{"version":3,"file":"use-lazy-DgUHsfq4.mjs","names":[],"sources":["../src/lazy/lazy.ts","../src/lazy/use-lazy.ts"],"sourcesContent":["import {\n  comparer,\n  reaction,\n  runInAction,\n  type IObservableArray,\n  type IReactionDisposer,\n  observable,\n  onBecomeObserved,\n  onBecomeUnobserved,\n} from \"mobx\";\n\n/** Options for `invalidate()`. */\nexport interface LazyInvalidateOptions {\n  /**\n   * Drop the current value instead of keeping it readable until the refetch lands.\n   * Default `false`: a refresh keeps showing what it already has.\n   */\n  discard?: boolean;\n}\n\n/**\n * Everything about a lazy that does not depend on whether it holds a value.\n *\n * Three facts vary independently here, and none of them is derivable from the others — which is why\n * there is no single `status` enum. `loaded` (below) says whether there is a value; `fetching` says\n * whether a request is running; `error` says how the last request ended. A refresh that fails while\n * a value is on screen is `loaded: true` *and* has an `error`, and both are true statements.\n */\n/**\n * How many times a lazy may go from unobserved to observed inside {@link THRASH_WINDOW_MS} before\n * the dev-only warning fires. Well above ordinary churn — a StrictMode double-mount is two, and a\n * list remounting on every keystroke is still single digits per second — and well below the\n * hundreds a runaway produces.\n */\nconst THRASH_LIMIT = 20;\nconst THRASH_WINDOW_MS = 1000;\n\nexport interface LazyApi<T> {\n  /**\n   * How the last request ended, or `undefined` if it succeeded (or none has run). Cleared when a\n   * new request starts and on every success.\n   *\n   * An error does **not** clear the value: a failed refresh keeps showing what it had, so `error`\n   * and a readable `value` coexist. Check `loaded` to decide whether there is anything to render;\n   * `error` only tells you what happened last.\n   */\n  error: unknown;\n  /**\n   * `true` whenever a request is in flight, including a background refresh that is still showing\n   * its previous value.\n   *\n   * Orthogonal to `loaded`, deliberately: the two together describe every state without overlapping.\n   * A first load is `!loaded && fetching`; a refresh is {@link LazyApi.refreshing}.\n   *\n   * ⚠️ **Reading this does not observe the lazy.** It is not one of the observation sources, so a\n   * render that decides what to show from `fetching` alone subscribes to nothing — see\n   * {@link LazyApi.refreshing}, which is the safe way to ask the same question.\n   */\n  fetching: boolean;\n  /**\n   * A request is in flight behind a value that is already there — a refresh, as opposed to a first\n   * load. Exactly `loaded && fetching`.\n   *\n   * **Prefer this to a bare `fetching` for anything that decides what to render.** Reading it\n   * touches whether there *is* a value, which is one of the reads that marks a lazy observed, so a\n   * placeholder branch gated on it keeps the lazy alive. A branch gated on `fetching` alone\n   * observes nothing: the lazy is dropped, its load aborted, `fetching` cleared — and the branch\n   * renders itself away again, as fast as the event loop allows. Development warns once when it\n   * sees that happening.\n   *\n   * (The `loading` property this resembles was removed for a different reason: it read as the\n   * opposite of `loaded` while actually meaning \"a request is in flight\", and mishandled a failed\n   * first load. This one is a conjunction of the two facts rather than a substitute for either.)\n   */\n  refreshing: boolean;\n  /**\n   * When a request last succeeded, as epoch milliseconds, or `undefined` if none ever has.\n   *\n   * Named for the fetch rather than the value, because the two differ: a lazy seeded with\n   * `initialValue` is `loaded` with no `fetchedAt` (hydrated, never been to the network), and a\n   * failed refresh leaves the previous timestamp in place (still showing data from then).\n   */\n  fetchedAt: number | undefined;\n  /**\n   * `true` while at least one reaction is observing `value`, `loaded` or `error`.\n   * Observable, so it can be read reactively — reading it does not itself count as observing the\n   * value, so it never triggers a load.\n   */\n  observed: boolean;\n  /**\n   * Resolve with the current value, loading first if there isn't one *or* the one held is stale.\n   * Joins a load already in flight rather than starting a second.\n   *\n   * Staleness counts, so `invalidate()` followed by `getOrLoad()` fetches rather than handing back\n   * the value being replaced — whether or not anything happens to be observing.\n   */\n  getOrLoad(): Promise<T>;\n  /** Always start a fresh load, abandoning any result already in flight. */\n  reload(): Promise<T>;\n  /**\n   * Write the value directly and mark it loaded and fresh, without fetching — the value is treated\n   * as authoritative, so no load is owed. Abandons any load in flight (so it cannot clobber this\n   * write) and detaches from dependency-driven refetching until the next load.\n   *\n   * Contrast `initialValue`, which is loaded but still *stale*: a starting point that gets\n   * revalidated on first observation.\n   */\n  set(value: T): void;\n  /**\n   * Mark the value stale and load again *if anyone is watching*. If nothing is observing, the load\n   * happens on next observation — or on the next `getOrLoad()`, which counts staleness.\n   *\n   * The current value stays readable while the refetch runs (`loaded` remains `true`, `fetching`\n   * becomes `true`), so a list doesn't blank out between a mutation and its refresh. Pass\n   * `{ discard: true }` to drop it first and show a fresh load instead.\n   */\n  invalidate(options?: LazyInvalidateOptions): void;\n}\n\n/**\n * A lazy observable.\n *\n * `loaded` is a discriminant, so checking it narrows `value` — no separate `!== undefined` guard:\n *\n * ```ts\n * if (list.loaded) list.value.map(render);   // value is T here\n * ```\n *\n * Written as a union of two complete members rather than `Api & (A | B)`. Both narrow — TypeScript\n * distributes the intersection — but `LazyArray` cannot be: it has to `Omit` `set` from\n * the API and replace it, and `Omit` over a union collapses it into one object, taking the\n * discriminant with it. The two types are spelled the same way so they stay comparable.\n */\nexport type Lazy<T = any> =\n  | (LazyApi<T> & { loaded: true; value: T })\n  | (LazyApi<T> & { loaded: false; value: undefined });\n\n/**\n * The `loaded: true` arm of {@link Lazy} — a lazy that is known to hold a value, so\n * `value` reads as `T` with no check. What a seeded `lazy` hands back, and what a\n * `loaded` check narrows an ordinary one to.\n */\nexport type LoadedLazy<T = any> = Extract<Lazy<T>, { loaded: true }>;\n\nexport interface LazyOptions {\n  /**\n   * Whether the value's contents are made observable recursively, as in mobx's own `deep` option.\n   * Defaults to `true`. Pass `false` for values that manage their own observability — model\n   * instances, for one — so nothing is converted on the way in.\n   */\n  deep?: boolean;\n  /**\n   * How long a loaded value outlives its last observer. `false` (the default) drops it as soon\n   * as nothing is watching, `true` keeps it forever, and `{ for: ms }` keeps it that long before\n   * dropping it — useful to survive a quick unmount/remount without refetching.\n   *\n   * Errors are never kept, regardless of this setting.\n   */\n  keepOnUnobserved?: boolean | { for: number };\n  /**\n   * Re-run `fetch` when observables it read while running change — a filter, a session field,\n   * a parent model's id.\n   *\n   * `false` (the default) calls `fetch` exactly once per load, so an observable it happens to\n   * touch can never trigger a request you didn't ask for. `true` tracks its reads and refetches\n   * on change. `{ throttle: ms }` tracks and allows at most one refetch per window, so a burst of\n   * changes (a filter bound to a text input) costs one request rather than one per keystroke.\n   * The first load is never throttled.\n   *\n   * Note this throttles rather than debounces: the window opens at the first change and is not\n   * pushed back by later ones, so sustained changes still refresh once per window instead of\n   * waiting for them to stop.\n   *\n   * Each re-run supersedes the previous request and aborts its signal.\n   */\n  trackDependencies?: boolean | { throttle: number };\n  /**\n   * Refresh the value automatically this often, in milliseconds — for data that should not go\n   * stale on screen (a dashboard, a queue, a status board).\n   *\n   * Only runs while something is observing: an unobserved lazy has nobody to refresh for. The\n   * interval is measured from the last completed request rather than a fixed clock, so a slow\n   * response pushes the next reload out instead of stacking requests. Coming back into\n   * observation after longer than the interval refreshes immediately.\n   *\n   * The current value stays readable throughout, exactly as with `invalidate()`. A failed\n   * reload reports its error and is retried on the next interval.\n   */\n  reloadEvery?: number;\n  debugName?: string;\n}\n\nexport interface LazyOptionsWithInitialValue<T> extends LazyOptions {\n  /**\n   * A value to start with, before anything is fetched. The lazy reports `loaded` immediately and\n   * still counts as stale, so the first observation revalidates it — which is what makes this the\n   * right shape for hydration from SSR, storage, or a cache you already trust.\n   *\n   * Without it a lazy holds nothing (`loaded: false`, `value: undefined`) until a load lands. That\n   * distinction is the point: an empty array means \"there are none\", not \"not known yet\".\n   *\n   * Passing this narrows the result to {@link LoadedLazy}, so `value` reads as `T`\n   * without a `loaded` check — the seed is restored by a discard, so a seeded lazy can never go\n   * back to holding nothing.\n   *\n   * Presence is what counts, not the value: for a `T` that includes `undefined`, seeding with\n   * `undefined` is a real value and reports `loaded`, matching a fetch that resolves `undefined`.\n   * That is why the unseeded overload has no `initialValue` at all — `{ initialValue: maybe }`\n   * where `maybe` might be `undefined` is the one state that cannot be represented, so it is\n   * rejected at the call site rather than guessed at.\n   */\n  initialValue?: T;\n}\n\nconst noop = (): void => {};\n\n/**\n * Which of the two things a request is doing. `\"load\"` produces the value from scratch — a first\n * load, a reload, a dependency change — and `\"more\"` adds to what is already held.\n *\n * Only a pager ever asks for `\"more\"`; without one every request is a `\"load\"`, which is why\n * nothing above this line has ever needed to say so.\n */\ntype RequestKind = \"load\" | \"more\";\n\n/**\n * The seam `lazyPages` extends the engine through.\n *\n * Paging lives entirely behind these five members, so every rule in `createLazy` — staleness,\n * observation, abort, generations, `keepOnUnobserved` — is written once and knows nothing about\n * cursors, page sizes or envelopes. The engine calls the first four at four exact points and\n * hands over the fifth so a pager can drive requests of its own.\n */\ninterface Pager {\n  /**\n   * Whether the request in flight is adding a page rather than replacing the list. Read by\n   * `refreshing`, which must not report an append as a refresh.\n   */\n  readonly appending: boolean;\n  /**\n   * Extra properties merged into what `fetch` is handed — the cursor, offset, limit and query for\n   * this particular request. Called at the moment a request starts, inside that batch, so a pager\n   * can record the kind at the same time.\n   */\n  request(kind: RequestKind): object;\n  /**\n   * Apply a settled payload. The pager owns the write rather than returning a value, because an\n   * append has to reach the owned array directly: handing back `[...held, ...page]` for the engine\n   * to `replace` would copy and re-notify the whole list on every page.\n   */\n  apply(payload: unknown, kind: RequestKind): void;\n  /** Forget paging state. Called wherever the engine clears the value. */\n  reset(): void;\n  /**\n   * A value was written directly with `set` rather than fetched. On the seam rather than as an\n   * override on the returned object, because `lazyPages` mutates that object in place — a `set`\n   * defined over the engine's would be reached by its own call through the property.\n   */\n  wrote(value: unknown): void;\n  /**\n   * Receives the engine's request function, once it exists. `\"load\"` supersedes anything in\n   * flight; `\"more\"` joins it, because two page requests at once would append the same page twice.\n   */\n  attach(request: (kind: RequestKind) => Promise<unknown>): void;\n}\n\ninterface Deferred<T> {\n  promise: Promise<T>;\n  resolve: (value: T) => void;\n  reject: (error: unknown) => void;\n}\n\n/**\n * What a fetch is handed. An object rather than a bare signal so more can be added later without\n * breaking every fetcher — and so a client whose own first parameter is an options bag can be\n * attached directly.\n */\nexport interface LazyFetchOptions {\n  /**\n   * Aborts as soon as the request is superseded — by `reload`, `set`, `invalidate`, going\n   * unobserved, or a dependency change.\n   */\n  signal: AbortSignal;\n}\n\n/** Taking the argument is optional; zero-argument fetchers remain valid. */\nexport type LazyFetch<T> = (options: LazyFetchOptions) => Promise<T>;\n\nexport function lazy<T>(\n  fetch: LazyFetch<T>,\n  options: LazyOptionsWithInitialValue<T> & { initialValue: T },\n): LoadedLazy<T>;\nexport function lazy<T>(fetch: LazyFetch<T>, options?: LazyOptions): Lazy<T>;\nexport function lazy<T>(fetch: LazyFetch<T>, options?: LazyOptionsWithInitialValue<T>): Lazy<T> {\n  // Presence, not value: `undefined` is a legitimate seed when `T` admits it, and the overloads\n  // above are what stop an ambiguous `T | undefined` from reaching here in the first place.\n  return createLazy(fetch, options, !!options && \"initialValue\" in options);\n}\n\n/**\n * The shared implementation behind `lazy` and `lazyArray`. The only difference\n * between them is where the value lives — a box, or an observable array the lazy owns — so that is\n * the one thing passed in, and every rule about loading, staleness, errors and observation is\n * written once here.\n */\nfunction createLazy<T>(\n  fetch: LazyFetch<T>,\n  options: LazyOptionsWithInitialValue<T> | undefined,\n  /**\n   * Whether `options` carried a seed. Passed in rather than derived here, because the two callers\n   * decide it differently and only they can: a scalar seed of `undefined` is a real value, while\n   * for a list `undefined` is never one — and `lazyArray` rebuilds the options bag on\n   * the way through, so an `in` test here would read its own reconstruction rather than what the\n   * caller wrote.\n   */\n  seeded: boolean,\n  ownedArray?: IObservableArray<unknown>,\n  /**\n   * Present only for `lazyPages`. Everything paging-shaped is behind it — see {@link Pager} — so\n   * the rules below stay written once for all three factories.\n   */\n  pager?: Pager,\n): Lazy<T> {\n  /**\n   * Where the value lives. `lazyArray` passes an observable array it owns, which is\n   * already an observable container, so it is used directly rather than wrapped in a box. Wrapping\n   * it would create two layers with only the outer one deciding when loading starts, so iterating\n   * the array would track its contents without ever triggering a fetch; owning it means any read of\n   * the contents both tracks *and* loads.\n   *\n   * Updates then replace the array's contents in place, so `value` keeps its identity for the\n   * lifetime of the lazy: a reference you hold stays valid. The trade is that the identity is no\n   * longer a signal — observe the contents, or `fetchedAt`.\n   */\n  const box = ownedArray\n    ? undefined\n    : observable.box<T | undefined>(options?.initialValue, { deep: options?.deep ?? true });\n\n  /**\n   * What a discard returns to. Arrays are snapshotted at construction, because the caller keeps a\n   * reference to the array they passed and mutating it must not change what a discard restores.\n   * Scalars are held as given, matching how the box would have stored them anyway. Whether there\n   * *is* a seed is `seeded`, not `seed !== undefined` — see above.\n   */\n  const seed = (\n    Array.isArray(options?.initialValue) ? [...options.initialValue] : options?.initialValue\n  ) as T | undefined;\n\n  /**\n   * Whether there is a value at all — the authority behind `loaded`, rather than testing `value`\n   * for `undefined`.\n   *\n   * It has to be its own box for two reasons. The owned array always exists (identity must be\n   * stable from construction) so its emptiness says nothing about whether it has been filled; and\n   * `undefined` is a legitimate value for a scalar lazy, which a `value !== undefined` test would\n   * misread as \"nothing here\" — and then refetch forever, since `getOrLoad` would never see it as\n   * loaded.\n   *\n   * Only `applyValue` and `clearValue` below write to it, which is what keeps it in step with\n   * whichever container is holding the value.\n   */\n  const hasValue = observable.box(seeded);\n\n  /** The observable that observation hooks attach to: the array itself, or the box. */\n  const valueSource = (ownedArray ?? box) as IObservableArray<unknown>;\n\n  /**\n   * Reads a value if there is one, and *always* touches an observable on the way — otherwise a read\n   * that lands before the first load would return `undefined` without registering anything, and a\n   * lazy nothing observes never loads. That is the whole mechanism, so it is deliberately\n   * unconditional rather than short-circuiting on `hasValue`.\n   */\n  const readValue = (): T | undefined => {\n    const has = hasValue.get();\n    // Touch the container itself, not just the flag: for the array case this is what makes a\n    // contents read both track and load, and it must happen whether or not there is a value yet.\n    if (ownedArray) void ownedArray.length;\n    else void box!.get();\n    return has ? ((ownedArray ?? box!.get()) as T) : undefined;\n  };\n\n  const applyValue = (next: T): void => {\n    if (ownedArray) ownedArray.replace(next as unknown[]);\n    else box!.set(next);\n    hasValue.set(true);\n  };\n\n  /**\n   * Back to where the lazy started: the seed if there was one, otherwise holding nothing. The owned\n   * array is emptied rather than replaced, so a reference taken earlier stays valid.\n   */\n  const clearValue = (): void => {\n    // Paging state describes the value, so it goes back with it: a discarded list must not keep a\n    // cursor pointing into the run that produced the rows it just dropped.\n    pager?.reset();\n    if (seeded) {\n      // `seed` is `T` whenever `seeded` — including a deliberate `undefined` for a `T` that\n      // admits one. A list can never reach here with an undefined seed: see `seeded` above.\n      applyValue(seed as T);\n      return;\n    }\n    if (ownedArray) ownedArray.clear();\n    else box!.set(undefined);\n    hasValue.set(false);\n  };\n\n  const error = observable.box<unknown>(undefined);\n\n  /**\n   * Observation is *derived*, never counted: this holds whichever of the public boxes are\n   * currently observed, and `observed` is simply whether that set is non-empty. A single\n   * shared counter miscounts any mix of consumers — a spinner reading `loaded` alongside a\n   * list reading `value` drove it to zero while the list was still mounted, silently\n   * blanking it forever.\n   */\n  const observedBoxes = new Set<unknown>();\n  const observed = observable.box(false);\n\n  /**\n   * Staleness is its own box, deliberately not derived from anything public: the gate reaction\n   * below reads it, and reading a *public* box there would register the lazy's own reaction\n   * as an observer of itself — it would report as permanently observed and never be lazy.\n   */\n  const stale = observable.box(true);\n\n  /** Whether a request is in flight. Independent of whether a value is held. */\n  const fetching = observable.box(false);\n\n  /**\n   * When a request last succeeded. Tracks the *fetch*, not the value: a seeded lazy holds a value\n   * with no `fetchedAt`, and a failed refresh keeps the previous one.\n   */\n  const fetchedAt = observable.box<number | undefined>(undefined);\n\n  /**\n   * When the last request finished, successfully or not. `reloadEvery` measures from here rather\n   * than from `fetchedAt` so a failed reload waits a full interval instead of retrying instantly\n   * off an old value's timestamp.\n   */\n  const settledAt = observable.box<number | undefined>(undefined);\n\n  let pollTimer: ReturnType<typeof setTimeout> | undefined;\n\n  const track = options?.trackDependencies ?? false;\n  const trackThrottle = typeof track === \"object\" ? track.throttle : 0;\n\n  /**\n   * Identifies the load whose result is still wanted. Every request captures the value at\n   * its start and only applies its result if it still matches, so a superseded fetch — one\n   * abandoned by `reload`, `set`, `invalidate`, or a dependency change — can never write\n   * back over newer state.\n   */\n  let generation = 0;\n\n  let keepTimer: ReturnType<typeof setTimeout> | undefined;\n  let fetchDisposer: IReactionDisposer | undefined;\n  let loadScheduled = false;\n  let controller: AbortController | undefined;\n\n  /**\n   * Created only by `getOrLoad`/`reload`, i.e. only when a caller is actually awaiting a\n   * value. Loads triggered by observation have no deferred — there is no call stack to throw\n   * into — so a failed background fetch surfaces through `error` instead of becoming an\n   * unhandled rejection.\n   */\n  let pending: Deferred<T> | undefined;\n\n  const log = (message: string) => {\n    if (options?.debugName) console.log(`lazy ${options.debugName}`, message);\n  };\n\n  /**\n   * Every mutation goes through here, for two reasons. Writes can originate inside a\n   * derivation — `onBecomeObserved` fires during an `observer()` render — which mobx permits\n   * inside an action and rejects outside one. And they always come in related groups, so\n   * batching them means observers never see a half-applied state such as `loaded` with the\n   * value already cleared.\n   */\n  const write = (fn: () => void): void => {\n    runInAction(fn);\n  };\n\n  /**\n   * Supersede the request in flight: its result will be discarded, and its signal aborts so\n   * the work actually stops rather than merely being ignored.\n   */\n  const abandon = (): void => {\n    clearTimeout(pollTimer);\n    generation++;\n    controller?.abort();\n    controller = undefined;\n  };\n\n  const ensurePending = (): Deferred<T> => {\n    if (pending) return pending;\n    let resolve!: (value: T) => void;\n    let reject!: (error: unknown) => void;\n    const promise = new Promise<T>((res, rej) => {\n      resolve = res;\n      reject = rej;\n    });\n    pending = { promise, resolve, reject };\n    return pending;\n  };\n\n  const settle = (\n    requestGeneration: number,\n    result: { value: T } | { error: unknown },\n    kind: RequestKind,\n  ): void => {\n    // A newer request has superseded this one — drop the result entirely.\n    if (requestGeneration !== generation) return;\n\n    controller = undefined; // this request has landed; there is nothing left to abort\n\n    const deferred = pending;\n    pending = undefined;\n\n    if (\"error\" in result) {\n      // The value is deliberately left alone: a refresh that fails keeps showing what it had, so\n      // `error` and a readable `value` coexist. Consumers decide from `loaded` whether there is\n      // anything to render, and from `error` what happened last.\n      write(() => {\n        error.set(result.error);\n        settledAt.set(Date.now());\n        fetching.set(false);\n      });\n      deferred?.reject(result.error);\n    } else {\n      write(() => {\n        if (pager) {\n          // The pager writes the value itself, so `hasValue` is set here rather than inside\n          // `applyValue` — an append never goes through it.\n          pager.apply(result.value, kind);\n          hasValue.set(true);\n        } else {\n          applyValue(result.value);\n        }\n        error.set(undefined);\n        fetchedAt.set(Date.now());\n        settledAt.set(Date.now());\n        fetching.set(false);\n      });\n      // Resolve with what `value` now holds, not with the raw payload. For a list lazy those are\n      // different objects — the payload is a plain array, `value` is the observable one the lazy\n      // owns — and handing back the payload would give an awaiting caller a detached snapshot that\n      // never updates and isn't the array everything else is looking at.\n      deferred?.resolve(readValue() as T);\n    }\n  };\n\n  /** One request: supersedes whatever came before it and applies its own result, or nothing. */\n  const runRequest = (kind: RequestKind = \"load\"): void => {\n    abandon();\n    const requestGeneration = generation;\n    const requestController = new AbortController();\n    controller = requestController;\n\n    let paging: object | undefined;\n    write(() => {\n      // Only a `\"load\"` settles the staleness question. An append adds a page to rows that may\n      // already be stale, and clearing the flag here would let a `loadMore` swallow an\n      // `invalidate()` issued in the same tick: the gate reaction has queued a reload, and the\n      // microtask re-checks `stale` before running it.\n      if (kind === \"load\") stale.set(false);\n      fetching.set(true);\n      // Whatever value is held stays held — a refresh never blanks what is on screen; `loading`\n      // derives from `!loaded && fetching`, so a first load reports it and a refresh does not.\n      // The previous failure is cleared here: a request is running, so it is no longer the\n      // current state of affairs.\n      error.set(undefined);\n      // Inside the batch for two reasons, and the second one is easy to lose in a refactor.\n      //\n      // Recording the kind and reading the cursor happen with everything else this request changes,\n      // so `refreshing` and `loadingMore` can never disagree with `fetching` for even one\n      // derivation. *And* a mobx action runs untracked — which is what keeps every paging box the\n      // pager touches here out of the dependency set when `trackDependencies` is on. Hoist this\n      // call out of the batch and the tracking reaction starts observing `cursor`, `pages` and\n      // `hasMore`, so every landed page invalidates it and refetches: an unbounded loop with no\n      // obvious cause. `lazy-pages.test.ts` pins it.\n      paging = pager?.request(kind);\n    });\n\n    let fetchPromise: Promise<T>;\n    try {\n      fetchPromise = fetch({ signal: requestController.signal, ...paging });\n    } catch (e) {\n      settle(requestGeneration, { error: e }, kind);\n      return;\n    }\n\n    fetchPromise.then(\n      (newValue) => settle(requestGeneration, { value: newValue }, kind),\n      (e) => settle(requestGeneration, { error: e }, kind),\n    );\n  };\n\n  const startLoad = (kind: RequestKind = \"load\"): void => {\n    clearTimeout(keepTimer);\n\n    // A `\"more\"` request adds a page to what is already held, which makes it wrong on both counts\n    // here: it must not *become* the tracked expression (a dependency change would then re-run an\n    // append rather than starting the list over), and it must not tear down the tracking reaction\n    // an earlier load installed.\n    if (kind === \"more\") {\n      runRequest(\"more\");\n      return;\n    }\n\n    fetchDisposer?.();\n    fetchDisposer = undefined;\n\n    if (!track) {\n      runRequest();\n      return;\n    }\n\n    /**\n     * The request *is* the tracked expression — that is what has to re-run to pick up new\n     * dependencies — so the effect has nothing left to do. `reaction` is used rather than\n     * `autorun` because it always runs that first pass synchronously (mobx routes an autorun's\n     * initial pass through the scheduler too, which would postpone the very first load); with\n     * `delay` only the re-runs wait. A delay of 0 makes mobx run everything synchronously, so\n     * this one call covers both the tracked and the throttled cases.\n     */\n    fetchDisposer = reaction(() => runRequest(\"load\"), noop, { delay: trackThrottle });\n  };\n\n  /**\n   * Abandon whatever is in flight and mark the value stale. The value itself is kept unless\n   * `discard` is set — or unless there is no loaded value to keep, in which case there is\n   * nothing to preserve and the state resets either way. Loads again only if someone is\n   * awaiting a value; otherwise the gate reaction decides.\n   */\n  const drop = (discard: boolean): void => {\n    abandon();\n    clearTimeout(keepTimer);\n    fetchDisposer?.();\n    fetchDisposer = undefined;\n    write(() => {\n      stale.set(true);\n      fetching.set(false);\n      if (discard || !hasValue.get()) {\n        // Back to `initialValue` — which for most lazies means holding nothing again, so a\n        // discarded list reads `undefined` rather than an empty array it could be mistaken for.\n        clearValue();\n        error.set(undefined);\n        fetchedAt.set(undefined);\n      }\n    });\n\n    // A caller awaiting a value is demand, not staleness: never leave them hanging on a\n    // request we just abandoned. Otherwise the gate reaction loads now if observed, or on\n    // next observation if not.\n    if (pending) startLoad();\n  };\n\n  /**\n   * MobX fires `onBecomeObserved` synchronously, which for an `observer()` component means *during\n   * its render*. Calling `startLoad()` there writes observable state mid-render, and if another\n   * component already observes this lazy, mobx-react-lite force-updates it while React is rendering\n   * something else — which React rejects (\"Cannot update a component while rendering a different\n   * component\").\n   *\n   * Deferring to a microtask moves the write just past the render pass. It still runs in the same\n   * task, well before any fetch could resolve, so the only observable difference is that `fetching`\n   * reads `false` during that first render.\n   */\n  const scheduleLoad = (): void => {\n    if (loadScheduled) return;\n    loadScheduled = true;\n    queueMicrotask(() => {\n      loadScheduled = false;\n      // Conditions are re-checked: the lazy may have been unobserved again before this ran\n      // (a component that mounted and immediately unmounted), or already loaded explicitly.\n      if (observed.get() && stale.get()) startLoad();\n    });\n  };\n\n  /**\n   * The single rule that decides when to load: something is watching, and what we hold is\n   * stale. Every state-changing operation just moves those two inputs and lets this derive\n   * the consequence, rather than each one re-deciding for itself.\n   */\n  reaction(\n    () => observed.get() && stale.get(),\n    (shouldLoad) => {\n      if (shouldLoad) scheduleLoad();\n    },\n    // Fired immediately so the dependency on `observed` is registered here rather than at the end\n    // of the enclosing batch. Constructing a lazy during an `observer()` render puts that batch\n    // around the render, so a deferred first evaluation would not read `observed` until *after*\n    // the render had already set it — leaving the reaction to treat `true` as its initial value\n    // and never fire. The immediate run itself is always a no-op: nothing can observe a lazy that\n    // does not exist yet.\n    { fireImmediately: true },\n  );\n\n  /**\n   * Auto-reload is derived the same way loading is: rather than sprinkling timer bookkeeping\n   * across settle/observe/set, one reaction watches the conditions that make a reload due and\n   * (re)schedules or cancels accordingly. Every input here is an internal box — reading a public\n   * one would register this reaction as an observer of the lazy itself, and it would never be\n   * lazy again.\n   */\n  if (options?.reloadEvery !== undefined) {\n    const interval = options.reloadEvery;\n    reaction(\n      () =>\n        observed.get() && !fetching.get() && !stale.get() && fetchedAt.get() !== undefined\n          ? settledAt.get()\n          : undefined,\n      (anchor) => {\n        clearTimeout(pollTimer);\n        if (anchor === undefined) return;\n        // Overdue (came back into observation late) schedules at 0 and refreshes right away.\n        // Wrapped rather than passed bare: `startLoad` now takes a kind, and a timer handing\n        // it an argument would be a silent mode change.\n        pollTimer = setTimeout(\n          () => startLoad(\"load\"),\n          Math.max(0, interval - (Date.now() - anchor)),\n        );\n      },\n      { fireImmediately: true },\n    );\n  }\n\n  /** Dev-only; see `warnOnThrash`. */\n  let observeTimes: number[] = [];\n  let thrashWarned = false;\n\n  /**\n   * A lazy that keeps being observed, dropped, and observed again is almost always a render gating\n   * on `fetching` without reading anything that observes. The cycle is self-sustaining and silent —\n   * no error, no failed request, just a component that renders forever and a server that gets hit\n   * forever — so it is worth spending a timestamp per transition to name it. Fires once per lazy,\n   * and only in development.\n   *\n   * Counted on the transition *into* observation, which is the edge that starts a load.\n   */\n  const warnOnThrash = (): void => {\n    if (thrashWarned) return;\n    const now = Date.now();\n    observeTimes = observeTimes.filter((t) => now - t < THRASH_WINDOW_MS);\n    observeTimes.push(now);\n    if (observeTimes.length <= THRASH_LIMIT) return;\n\n    thrashWarned = true;\n    const name = options?.debugName ? ` \"${options.debugName}\"` : \"\";\n    console.warn(\n      `[mobx-toolbox] lazy${name} was observed ${observeTimes.length} times in ` +\n        `under ${THRASH_WINDOW_MS}ms, and is probably in a reload loop.\\n\\n` +\n        \"This happens when a render decides what to show from `fetching` or `fetchedAt` alone. \" +\n        \"Neither one observes the lazy, so the branch that shows a placeholder drops it — which \" +\n        \"aborts the load, clears `fetching`, and renders the other branch again, forever.\\n\\n\" +\n        \"Gate on `refreshing` (a request behind an existing value) or `!loaded && fetching` (a \" +\n        \"first load) instead. Both read whether there is a value, which is what keeps the lazy \" +\n        \"observed while the placeholder is up.\",\n    );\n  };\n\n  const syncObserved = (): void => {\n    const next = observedBoxes.size > 0;\n    if (next === observed.get()) return;\n\n    log(next ? \"observed\" : \"unobserved\");\n    write(() => observed.set(next));\n\n    // Development only, and the spelling is load-bearing: `process.env.NODE_ENV` is what mobx\n    // uses, so a consumer already has it defined, and keeping the comparison inline and literal\n    // is what lets their bundler drop `warnOnThrash` and its bookkeeping entirely. This survives\n    // into the published chunk only because `pack` builds with `platform: \"neutral\"` — under\n    // `\"browser\"`, rolldown rewrites `process.env` in shared chunks and the guard folds to `true`.\n    if (process.env.NODE_ENV !== \"production\") {\n      if (next) warnOnThrash();\n    }\n\n    if (next) {\n      clearTimeout(keepTimer);\n      return;\n    }\n\n    // Errors are never kept regardless of keepOnUnobserved — failure state shouldn't persist\n    // across mounts, only successfully loaded values should.\n    const keep = options?.keepOnUnobserved ?? false;\n    // Unobserved data is dropped outright: nothing can be showing it, so there is nothing to keep.\n    if (error.get() !== undefined || keep === false) {\n      drop(true);\n    } else if (typeof keep === \"object\") {\n      keepTimer = setTimeout(() => drop(true), keep.for);\n    }\n    // keep === true: hold the loaded value indefinitely.\n  };\n\n  // What counts as \"observing\": the value itself, whether there is one, and how the last request\n  // ended. `fetching` is deliberately not here — it would let a header \"syncing…\" indicator both\n  // pin a value in memory and *start* a fetch merely by rendering, since becoming observed is what\n  // triggers a load. The cost of that exclusion is that `fetching` cannot safely gate a render on\n  // its own, which is what `refreshing` and the thrash warning above exist to handle.\n  for (const source of [valueSource, hasValue, error]) {\n    onBecomeObserved(source, () => {\n      observedBoxes.add(source);\n      syncObserved();\n    });\n    onBecomeUnobserved(source, () => {\n      observedBoxes.delete(source);\n      syncObserved();\n    });\n  }\n\n  /**\n   * `\"load\"` supersedes anything in flight, exactly as `reload()` does. `\"more\"` joins it instead\n   * and resolves with whatever that request produces: two page requests running at once would\n   * append the same page twice, or land page 3 ahead of page 2.\n   */\n  pager?.attach((kind) => {\n    if (kind === \"more\" && fetching.get()) return ensurePending().promise;\n    const deferred = ensurePending();\n    startLoad(kind);\n    return deferred.promise;\n  });\n\n  return {\n    get value() {\n      return readValue();\n    },\n    get error() {\n      return error.get();\n    },\n    get loaded() {\n      return hasValue.get();\n    },\n    get fetching() {\n      return fetching.get();\n    },\n    get refreshing() {\n      // `hasValue` is an observation source and `fetching` is not, which is what makes this safe\n      // to gate a render on where a bare `fetching` is not.\n      //\n      // The operand order matters, and only in one case: reading this when it is *false* because\n      // nothing is in flight. Written the other way round, `fetching` short-circuits and nothing\n      // is read at all — so a component whose only read is `refreshing` would observe nothing and\n      // never load. Leading with `hasValue` means every path through this getter observes.\n      //\n      // A pager's append is deliberately not this: it is adding to what is held rather than\n      // replacing it, and `loadingMore` is what reports it.\n      return hasValue.get() && fetching.get() && !pager?.appending;\n    },\n    get fetchedAt() {\n      return fetchedAt.get();\n    },\n    get observed() {\n      return observed.get();\n    },\n    getOrLoad() {\n      // Staleness counts, not just presence: an invalidated lazy holds a value it has been told to\n      // replace, and a seeded one holds a value it has never verified. Both owe a fetch, and a\n      // caller who awaited deserves the result of it rather than the thing being superseded.\n      if (hasValue.get() && !stale.get()) return Promise.resolve(readValue() as T);\n      const deferred = ensurePending();\n      // Join a load already in flight rather than starting a second one.\n      if (!fetching.get()) startLoad();\n      return deferred.promise;\n    },\n    reload() {\n      const deferred = ensurePending();\n      startLoad();\n      return deferred.promise;\n    },\n    set(newValue: T) {\n      abandon();\n      clearTimeout(keepTimer);\n      fetchDisposer?.();\n      fetchDisposer = undefined;\n\n      const deferred = pending;\n      pending = undefined;\n\n      write(() => {\n        applyValue(newValue);\n        pager?.wrote(newValue);\n        error.set(undefined);\n        // A written value is authoritative, so it is fresh rather than merely present: no fetch is\n        // owed, and it is stamped as though a request had just produced it.\n        fetchedAt.set(Date.now());\n        settledAt.set(Date.now());\n        stale.set(false);\n        fetching.set(false);\n      });\n\n      // Same as in `settle`: hand back what is held, which for a list is the owned array.\n      deferred?.resolve(readValue() as T);\n    },\n    invalidate(invalidateOptions?: LazyInvalidateOptions) {\n      drop(invalidateOptions?.discard ?? false);\n    },\n    // `loaded` and `value` are getters over the same pair of boxes, so they always agree — but the\n    // compiler can only see two independent properties, not the union's guarantee.\n  } as Lazy<T>;\n}\n\n/**\n * The API of a list lazy: everything a scalar one has, except that `set` takes a plain array —\n * callers hand over data, not an observable container.\n */\nexport type LazyArrayApi<T> = Omit<LazyApi<IObservableArray<T>>, \"set\"> & {\n  set(value: T[]): void;\n};\n\n/**\n * A lazy over a list. `value` is the *same* observable array for the lifetime of the lazy once\n * there is one — loads replace its contents rather than the array — so a reference you hold stays\n * valid. The trade is that the identity is no longer a change signal: observe the contents, or\n * `fetchedAt`.\n *\n * `value` is `undefined` until the first load (or an explicit `initialValue`), because \"no rows\n * yet\" and \"zero rows\" are different answers and only one of them is a fact. `loaded` narrows it,\n * exactly as it does for a scalar lazy.\n */\nexport type LazyArray<T = any> =\n  | (LazyArrayApi<T> & { loaded: true; value: IObservableArray<T> })\n  | (LazyArrayApi<T> & { loaded: false; value: undefined });\n\n/**\n * The `loaded: true` arm of {@link LazyArray} — the list counterpart of\n * {@link LoadedLazy}. What a seeded `lazyArray` hands back, including one\n * seeded with `[]`: \"there are none\" is a fact, and a fact is loaded.\n */\nexport type LoadedLazyArray<T = any> = Extract<LazyArray<T>, { loaded: true }>;\n\nexport interface LazyArrayOptions<T> extends LazyOptions {\n  /**\n   * Rows to start with — see {@link LazyOptionsWithInitialValue.initialValue}, of which\n   * this is the list form. Passing it narrows the result to {@link LoadedLazyArray}.\n   *\n   * Unlike the scalar case there is nothing ambiguous to guard against, because `undefined` is\n   * never a list: `{ initialValue: maybeRows }` is accepted and simply does not narrow, since a\n   * seed that might not be there cannot promise a value.\n   */\n  initialValue?: T[];\n}\n\nexport function lazyArray<T>(\n  fetch: LazyFetch<T[]>,\n  options: LazyArrayOptions<T> & { initialValue: T[] },\n): LoadedLazyArray<T>;\nexport function lazyArray<T>(fetch: LazyFetch<T[]>, options?: LazyArrayOptions<T>): LazyArray<T>;\nexport function lazyArray<T>(fetch: LazyFetch<T[]>, options?: LazyArrayOptions<T>): LazyArray<T> {\n  // Created here and owned for the lifetime of the lazy, so `value` is the same array every time\n  // there is one and loads replace its contents. `deep` applies to the array's *items*.\n  //\n  // It is created even when nothing seeds it — identity has to be stable from the start — but it is\n  // not *exposed* until there is a value, so an unloaded lazy reads `undefined` rather than `[]`.\n  const { deep, ...rest } = options ?? {};\n  const items = observable.array<T>(options?.initialValue ?? [], { deep: deep ?? true });\n  // The internal generic is what `fetch` returns — a plain array — while the public type says\n  // `IObservableArray`, which is what `value` actually hands back. `applyValue` bridges them by\n  // replacing contents rather than assigning.\n  return createLazy<T[]>(\n    fetch,\n    { ...rest, initialValue: options?.initialValue },\n    // A list is seeded by *having* rows, never by the key being present: `undefined` is not a\n    // list, so an explicit `initialValue: undefined` means the same as omitting it.\n    options?.initialValue !== undefined,\n    items as unknown as IObservableArray<unknown>,\n  ) as unknown as LazyArray<T>;\n}\n\n/** Rows per request when `pageSize` is not given. What most list endpoints default to anyway. */\nconst DEFAULT_PAGE_SIZE = 50;\n\n/**\n * What a page fetch is handed: the lazy's own options, plus where in the list this request is.\n *\n * Both `cursor` and `offset` are supplied on every request, so the same shape serves a\n * cursor-paginated endpoint and an offset-paginated one and you use whichever your API speaks.\n */\nexport interface LazyPageRequest<Q = undefined> extends LazyFetchOptions {\n  /** The cursor the previous page reported, or `undefined` for the first page of a run. */\n  cursor: string | undefined;\n  /** How many rows are already held — the offset an offset-paginated endpoint wants. `0` on a first page. */\n  offset: number;\n  /** How many rows to ask for: whatever `pageSize` is set to. */\n  limit: number;\n  /** Zero-based index of the page being fetched. `0` for a first load, a reload, or a query change. */\n  page: number;\n  /** Whatever `setQuery` was last given — the filters and sorts, for a table-driven list. */\n  query: Q;\n}\n\n/**\n * What a page fetch resolves to.\n *\n * A bare array is the whole answer for an endpoint that returns rows and nothing else. The\n * envelope carries whatever else it knows, and every field is optional because most endpoints\n * report one or two of them rather than all three — see {@link LazyPagesApi.hasMore} for how they\n * combine.\n */\nexport type LazyPageResult<T> =\n  | T[]\n  | {\n      items: T[];\n      /**\n       * Cursor for the *next* page. `null` means this page was the last, which is why the field\n       * being **present** is what makes it authoritative: an absent `cursor` says nothing.\n       */\n      cursor?: string | null;\n      /** Total rows matching the query across every page — the \"of 4,382\" in a row count. */\n      total?: number;\n      /** Whether another page exists, for an endpoint that says so outright. Outranks the rest. */\n      hasMore?: boolean;\n    };\n\nexport type LazyPagesFetch<T, Q = undefined> = (\n  request: LazyPageRequest<Q>,\n) => Promise<LazyPageResult<T>>;\n\n/**\n * Options for `lazyPages`. A deliberate subset of {@link LazyOptions}, and the two that are\n * missing are missing for reasons rather than oversight:\n *\n * - **`initialValue`** — a seed cannot say which cursor follows it, so it could be listed but\n *   never continued. Hydrating the first page is `set(rows)`, which says the same thing honestly:\n *   these rows, and nothing after them.\n * - **`reloadEvery`** — a reload starts the list over at page one, so polling would yank a user\n *   who had scrolled to page eight back to the top on a timer. Refresh a paged list on an event\n *   (`invalidate()`), not on a clock.\n */\nexport interface LazyPagesOptions<T, Q = undefined> extends Pick<\n  LazyOptions,\n  \"deep\" | \"keepOnUnobserved\" | \"trackDependencies\" | \"debugName\"\n> {\n  /**\n   * Rows per request, sent to the fetch as `limit`. Default 50.\n   *\n   * It doubles as the fallback for `hasMore` when an endpoint reports nothing else — a page\n   * shorter than this is the last one — so it should match what the server actually returns.\n   */\n  pageSize?: number;\n  /** The query the first page is fetched with, before any {@link LazyPagesApi.setQuery}. */\n  query?: Q;\n  /**\n   * A row's identity, used to drop a record that a later page repeats.\n   *\n   * Worth setting for anything served by cursor over a non-unique sort key, or by offset while\n   * rows are being inserted: both hand back a record already held, and the duplicate is not\n   * harmless — a table keys its rows by identity, so two entries for one record produce two rows\n   * that share a React key and a single selection toggle that hits both.\n   *\n   * For a model-backed list, `dedupeBy: SurveyModel.identityKey` is exactly this.\n   */\n  dedupeBy?: (item: T) => unknown;\n}\n\n/**\n * Everything a {@link LazyArray} has, plus what only an accumulating list can answer.\n *\n * Note which of these observe the list and which do not. `value`, `loaded`, `error` and\n * `loadingMore` do, so a render gated on any of them keeps the list alive and triggers its first\n * load. `hasMore`, `total`, `pages` and `fetching` do **not** — they describe the requests rather\n * than the rows, so a footer that renders \"1–100 of 4,382\" can't pin a list in memory or start a\n * fetch just by being on screen. It is the same split, and the same reasoning, as\n * {@link LazyApi.fetching} versus {@link LazyApi.refreshing}.\n */\nexport interface LazyPagesApi<T, Q = undefined> extends LazyArrayApi<T> {\n  /**\n   * Append the next page, resolving with the list once it lands.\n   *\n   * Safe to call speculatively, which is what makes it usable as a scroll handler: it resolves\n   * immediately when there is nothing more, and **joins** a request already in flight rather than\n   * starting a second one — so a burst of scroll events costs one page, not one each.\n   *\n   * On a list that holds nothing yet this fetches the first page, which is the same thing it\n   * always is: the page after the ones held.\n   */\n  loadMore(): Promise<IObservableArray<T>>;\n  /**\n   * Fetch every remaining page, one after another, and resolve with the whole list.\n   *\n   * For \"Load all 2,000\" rather than \"load more\" — a bar that offers the rest of the dataset in one\n   * click, or an export that needs it in memory. Pages arrive as they land, so a row count bound to\n   * `value.length` and `total` counts up throughout, and `loadingMore` stays `true` for the\n   * duration.\n   *\n   * A hand-written `while (list.hasMore) await list.loadMore()` does the same thing in the happy\n   * path. What this adds is **stopping**, in the two cases that loop cannot see:\n   *\n   * - **The list restarted underneath it.** A `setQuery`, a `reload`, a `created` event: the loop\n   *   would carry on and walk the *new* query to its end, which nobody asked for. This stops as\n   *   soon as a page fails to extend the list.\n   * - **Nothing is watching any more.** If something was observing when the walk began — a mounted\n   *   table — and has stopped by the time a page lands, the view it was for is gone and the rest of\n   *   the walk is pure waste. A walk that began with nothing observing keeps going, because that is\n   *   a script asking on its own behalf, exactly as `getOrLoad()` fetches for one.\n   *\n   * Rejects if a page does, leaving the pages already loaded in place — so a retry continues from\n   * where it stopped rather than starting over.\n   */\n  loadAll(): Promise<IObservableArray<T>>;\n  /**\n   * A page request is in flight *behind rows already held* — the append counterpart of\n   * {@link LazyApi.refreshing}, and mutually exclusive with it.\n   *\n   * Reading it observes the list, so this is the one to gate a footer spinner on. The two never\n   * overlap: a reload replaces the list and reports `refreshing`, a `loadMore` extends it and\n   * reports this.\n   */\n  readonly loadingMore: boolean;\n  /**\n   * Whether another page exists. `true` before anything has loaded — the first page is a page.\n   *\n   * Resolved from what the last page reported, in this order:\n   *\n   * 1. An empty page ends the list, whatever else it says. Trusting `hasMore: true` alongside zero\n   *    rows is what turns a server bug into a request loop, and anything driving `loadMore()` off\n   *    a scroll position would spin it as fast as the event loop allows.\n   * 2. An explicit `hasMore`.\n   * 3. A `cursor` field, if the envelope carried one: `null` means the end.\n   * 4. A `total`, if one has been reported: whether the rows held reach it.\n   * 5. Otherwise a short page is the last page. An endpoint whose final page happens to be exactly\n   *    `pageSize` long therefore costs one extra request, which comes back empty and ends it.\n   */\n  readonly hasMore: boolean;\n  /** Total rows matching the query, if a page reported one. Survives appends; cleared by a query change. */\n  readonly total: number | undefined;\n  /**\n   * How many pages are held. `0` before the first lands, and back to `0` on anything that starts\n   * the list over — a reload, a query change, a discard.\n   *\n   * That makes it the signal for \"this list restarted\" as opposed to \"this list grew\", which\n   * nothing else here provides: the array identity is stable by design, so it cannot say.\n   */\n  readonly pages: number;\n  /** Whatever `setQuery` was last given, or the `query` option. */\n  readonly query: Q;\n  /**\n   * Point the list at a different query — filters, sorts, a search term.\n   *\n   * The query decides which rows exist, so this is not a refresh of the rows held: the list goes\n   * stale from page one and reloads now if anything is watching, or on the next observation if\n   * not. The rows stay readable throughout, so a table keeps showing the previous results until\n   * the new first page lands rather than blanking.\n   *\n   * A structurally equal query is a no-op, so this is safe to call from an effect that runs more\n   * often than the query changes.\n   */\n  setQuery(query: Q): void;\n}\n\n/**\n * A lazy over a list that grows a page at a time.\n *\n * It is a {@link LazyArray} in every respect that matters to something reading rows — one stable\n * observable array, `undefined` until the first page lands, `loaded` narrowing it, loading on\n * first observation and dropping when nothing watches — so anything that accepts a `LazyArray`\n * accepts one of these, the table's `data` included.\n *\n * What it adds is the distinction a single-fetch lazy structurally cannot draw: `reload()` starts\n * the list over, `loadMore()` extends it, and `refreshing` / `loadingMore` say which is running.\n */\nexport type LazyPages<T = any, Q = undefined> =\n  | (LazyPagesApi<T, Q> & { loaded: true; value: IObservableArray<T> })\n  | (LazyPagesApi<T, Q> & { loaded: false; value: undefined });\n\n/** The envelope form of {@link LazyPageResult}, after a bare array has been wrapped into one. */\ntype PageEnvelope<T> = Exclude<LazyPageResult<T>, T[]>;\n\n/**\n * An accumulating list: one lazy, fetched a page at a time, for a dataset too large to hand over\n * whole.\n *\n * ```ts\n * const feed = lazyPages(({ cursor, limit, signal }) =>\n *   api.listSurveys({ cursor, limit, signal }),\n * );\n *\n * feed.value;        // undefined until the first page lands, then the accumulated rows\n * feed.loadMore();   // append the next page\n * feed.hasMore;      // whether there is one\n * ```\n *\n * Everything about *when* it loads is `lazy`'s: the first page is fetched when something observes\n * the list, requests abort when superseded, `keepOnUnobserved` decides how long the pages outlive\n * their last observer, and `trackDependencies` makes an observable the fetch reads a reason to\n * start the list over. Only the accumulation is new.\n *\n * **Three operations, deliberately distinct**, where a single-fetch lazy only has room for two:\n *\n * | | |\n * | --- | --- |\n * | `loadMore()` | the page after the ones held, appended |\n * | `reload()` | the first page again, replacing everything — the whole list, refetched |\n * | `setQuery(q)` | a different list; page one of it, rows held until it lands |\n */\nexport function lazyPages<T, Q = undefined>(\n  fetch: LazyPagesFetch<T, Q>,\n  options?: LazyPagesOptions<T, Q>,\n): LazyPages<T, Q> {\n  const {\n    deep,\n    pageSize = DEFAULT_PAGE_SIZE,\n    dedupeBy,\n    query: initialQuery,\n    ...rest\n  } = options ?? {};\n\n  // Owned for the lifetime of the lazy, exactly as `lazyArray`'s is, so `value` keeps its identity\n  // as pages accumulate. That is what lets a table bind once and let MobX carry every later page\n  // through its own computeds, rather than re-applying a dataset per page.\n  const items = observable.array<T>([], { deep: deep ?? true });\n\n  /**\n   * Paging state, in its own observable and deliberately *not* wired into the observation hooks:\n   * see the note on {@link LazyPagesApi} for why reading `hasMore` must not start a fetch.\n   *\n   * `deep: false` because every field is a primitive or an opaque query object the consumer owns.\n   */\n  const state = observable(\n    {\n      cursor: undefined as string | undefined,\n      hasMore: true,\n      total: undefined as number | undefined,\n      pages: 0,\n      appending: false,\n      query: initialQuery as Q,\n    },\n    {},\n    { deep: false },\n  );\n\n  /** Identities already held, for `dedupeBy`. Absent when nothing asked for deduplication. */\n  const seen = dedupeBy ? new Set<unknown>() : undefined;\n\n  /** Back to knowing nothing about the run: no cursor, no pages, no total, more presumed. */\n  const forgetPaging = (): void => {\n    state.cursor = undefined;\n    state.hasMore = true;\n    state.total = undefined;\n    state.pages = 0;\n    state.appending = false;\n    seen?.clear();\n  };\n\n  /** Assigned by `createLazy` through {@link Pager.attach}, before anything can call `loadMore`. */\n  let request!: (kind: RequestKind) => Promise<unknown>;\n\n  /**\n   * Whether a request of this kind extends the list or starts it. Keyed off `pages` rather than\n   * the array's length, because the two disagree in exactly the case that matters: a query change\n   * leaves the previous rows readable while resetting `pages` to zero, and a `loadMore` arriving\n   * in that window has to fetch page one rather than asking for the page after rows it is about\n   * to replace.\n   */\n  const appends = (kind: RequestKind): boolean => kind === \"more\" && state.pages > 0;\n\n  const resolveHasMore = (page: PageEnvelope<T>, received: number): boolean => {\n    if (received === 0) return false;\n    if (page.hasMore !== undefined) return page.hasMore;\n    if (\"cursor\" in page) return page.cursor != null;\n    if (state.total !== undefined) return items.length < state.total;\n    return received >= pageSize;\n  };\n\n  const pager: Pager = {\n    get appending() {\n      return state.appending;\n    },\n\n    request(kind) {\n      const appending = appends(kind);\n      state.appending = appending;\n      if (!appending) {\n        // A fresh first page: forget where the last run got to, so a reload starts from the top\n        // and a retry after a failure doesn't resume mid-list against a cursor from before it.\n        state.cursor = undefined;\n        state.pages = 0;\n        seen?.clear();\n      }\n      return {\n        cursor: appending ? state.cursor : undefined,\n        offset: appending ? items.length : 0,\n        limit: pageSize,\n        page: state.pages,\n        query: state.query,\n      } satisfies Omit<LazyPageRequest<Q>, \"signal\">;\n    },\n\n    apply(payload, kind) {\n      const page = (Array.isArray(payload) ? { items: payload } : payload) as PageEnvelope<T>;\n      const received = page.items ?? [];\n\n      // Filtered before the push, so `dedupeBy` sees the payload's own rows rather than whatever\n      // `deep` converted them into on the way in.\n      const rows = seen\n        ? received.filter((row) => {\n            const id = dedupeBy!(row);\n            if (seen.has(id)) return false;\n            seen.add(id);\n            return true;\n          })\n        : received;\n\n      if (appends(kind)) items.push(...rows);\n      else items.replace(rows);\n\n      state.pages++;\n      if (page.total !== undefined) state.total = page.total;\n      state.cursor = page.cursor ?? undefined;\n      // Off the payload's own row count, not the deduplicated one: a page entirely made of\n      // records already held is still a page the server had, and treating it as empty would end\n      // the list one page early.\n      state.hasMore = resolveHasMore(page, received.length);\n    },\n\n    reset: forgetPaging,\n\n    wrote(value) {\n      const written = value as T[];\n      forgetPaging();\n      // `set` is authoritative — the same promise it makes on any lazy — so it says these are the\n      // rows, all of them, and there is no page after them.\n      state.hasMore = false;\n      state.pages = 1;\n      state.total = written.length;\n      if (seen) for (const row of written) seen.add(dedupeBy!(row));\n    },\n\n    attach(run) {\n      request = run;\n    },\n  };\n\n  const base = createLazy<T[]>(\n    fetch as unknown as LazyFetch<T[]>,\n    rest,\n    // Never seeded: `initialValue` is not among the options, and `set` is the honest way in.\n    false,\n    items as unknown as IObservableArray<unknown>,\n    pager,\n  );\n\n  const api = base as unknown as LazyPages<T, Q>;\n\n  // Defined onto the engine's object rather than delegated through a second one: these are\n  // accessors, so a wrapper would mean a hand-written passthrough for every member of `LazyApi`\n  // and one more thing to keep in step with it.\n  Object.defineProperties(api, {\n    loadingMore: {\n      enumerable: true,\n      // `loaded` leads, deliberately: it is an observation source and `fetching` is not, so\n      // reading this observes the list on every path through it. Written the other way round,\n      // `fetching` would short-circuit and a footer whose only read is this one would observe\n      // nothing — the same trap `refreshing` is written to avoid.\n      get: () => base.loaded && base.fetching && state.appending,\n    },\n    hasMore: { enumerable: true, get: () => state.hasMore },\n    total: { enumerable: true, get: () => state.total },\n    pages: { enumerable: true, get: () => state.pages },\n    query: { enumerable: true, get: () => state.query },\n\n    loadMore: {\n      enumerable: true,\n      value: (): Promise<IObservableArray<T>> =>\n        state.hasMore ? request(\"more\").then(() => items) : Promise.resolve(items),\n    },\n\n    loadAll: {\n      enumerable: true,\n      value: async (): Promise<IObservableArray<T>> => {\n        // Whether this walk is serving something on screen. Captured once: a walk that began\n        // unobserved is a caller asking on its own behalf and runs to the end, the same way\n        // `getOrLoad()` fetches for one.\n        const startedObserved = base.observed;\n\n        while (state.hasMore) {\n          const before = state.pages;\n          await request(\"more\");\n\n          // Nothing was added. Either the list restarted under us — a `setQuery`, a `reload`, a\n          // discard, whose reset put `pages` back and whose generation bump discarded this page —\n          // or the page was empty. Both mean this walk is finished; carrying on would work through\n          // a list nobody asked about.\n          if (state.pages <= before) break;\n\n          // The view this was for has gone. Everything still held stays held; only the rest of the\n          // walk is abandoned.\n          if (startedObserved && !base.observed) break;\n        }\n\n        return items;\n      },\n    },\n\n    setQuery: {\n      enumerable: true,\n      value: (next: Q): void => {\n        if (comparer.structural(state.query, next)) return;\n        runInAction(() => {\n          // Before `invalidate`, so the reload this may trigger already reads the new query — and\n          // `pages` drops to 0 now rather than when the page lands, which is what tells a view\n          // this is a different list and not a longer one.\n          forgetPaging();\n          state.query = next;\n        });\n        api.invalidate();\n      },\n    },\n  });\n\n  return api;\n}\n\n/**\n * The value type a lazy resolves to. Inferred off `getOrLoad` rather than the type itself, so it\n * reads through the `loaded` union without needing to match either member.\n */\nexport type InferLazy<O> = O extends { getOrLoad(): Promise<infer T> } ? T : never;\n","import { useStable } from \"../react-util/useStable\";\nimport {\n  lazy,\n  lazyArray,\n  lazyPages,\n  type LazyFetch,\n  type Lazy,\n  type LazyArray,\n  type LazyArrayOptions,\n  type LazyOptions,\n  type LazyOptionsWithInitialValue,\n  type LazyPages,\n  type LazyPagesFetch,\n  type LazyPagesOptions,\n  type LoadedLazy,\n  type LoadedLazyArray,\n} from \"./lazy\";\n\n/**\n * A lazy observable that belongs to one component, for an async read whose inputs are the\n * component's own — a route param, a prop, a piece of local state.\n *\n * ```tsx\n * const study = useLazy((options) => StudyModel.get({ id: studyId }, options), [studyId]);\n * ```\n *\n * What comes back is an ordinary `lazy`: it loads when something observes it, keeps its\n * value while it reloads, and aborts a request it supersedes. Nothing reading one can tell whether\n * it came from a hook, a store, or a hand-rolled construction — which is the point.\n *\n * `deps` say *which* lazy this is, so changing them builds a new one, exactly as constructing a\n * second lazy by hand would: the value starts empty and loads again. That is what you want for a\n * record — showing the study you navigated away from while the next one loads would be a lie. When\n * the inputs are filters over a single list rather than a different list, `useCollection`'s `params`\n * are the other shape: same lazy, refetched, rows readable throughout.\n *\n * Held through {@link useStable} rather than `useMemo`, which React may discard — that would rebuild\n * the lazy and silently drop what it had loaded.\n *\n * An `initialValue` seeds it, exactly as it does for a hand-built lazy, and narrows the result so\n * `value` reads without a `loaded` check. The seed belongs to *this* lazy, so changing `deps`\n * builds a new one starting from the seed again — which is what you want, since the seed describes\n * the inputs it was written for.\n */\nexport function useLazy<T>(\n  fetch: LazyFetch<T>,\n  deps: React.DependencyList,\n  options: LazyOptionsWithInitialValue<T> & { initialValue: T },\n): LoadedLazy<T>;\nexport function useLazy<T>(\n  fetch: LazyFetch<T>,\n  deps: React.DependencyList,\n  options?: LazyOptions,\n): Lazy<T>;\nexport function useLazy<T>(\n  fetch: LazyFetch<T>,\n  deps: React.DependencyList,\n  options?: LazyOptionsWithInitialValue<T>,\n): Lazy<T> {\n  // `?? {}` rather than passing `options` straight through: the seed is read off the presence of\n  // the key, which an absent bag and an empty one answer the same way.\n  return useStable(() => lazy(fetch, options ?? {}), deps);\n}\n\n/**\n * {@link useLazy} for a value that is a list.\n *\n * ```tsx\n * const rows = useLazyArray((options) => api.listSections({ studyId }, options), [studyId]);\n * ```\n *\n * The lazy owns one observable array for its lifetime, so loads replace its *contents* — but `deps`\n * changing ends that lifetime and builds a new lazy with a new array, just as constructing one by\n * hand would. Anything watching array identity should watch the lazy's `loadedAt` instead.\n *\n * An `initialValue` seeds the list and narrows the result, so `value` reads without a `loaded`\n * check — `initialValue: []` included, which is how you say \"there are none yet, and that is a\n * fact\" rather than \"not known yet\".\n */\nexport function useLazyArray<T>(\n  fetch: LazyFetch<T[]>,\n  deps: React.DependencyList,\n  options: LazyArrayOptions<T> & { initialValue: T[] },\n): LoadedLazyArray<T>;\nexport function useLazyArray<T>(\n  fetch: LazyFetch<T[]>,\n  deps: React.DependencyList,\n  options?: LazyArrayOptions<T>,\n): LazyArray<T>;\nexport function useLazyArray<T>(\n  fetch: LazyFetch<T[]>,\n  deps: React.DependencyList,\n  options?: LazyArrayOptions<T>,\n): LazyArray<T> {\n  return useStable(() => lazyArray(fetch, options), deps);\n}\n\n/**\n * {@link useLazyArray} for a list that grows a page at a time — an infinite feed or a load-more\n * list whose inputs are the component's own.\n *\n * ```tsx\n * const feed = useLazyPages(\n *   ({ cursor, limit, signal }) => api.listComments({ postId, cursor, limit, signal }),\n *   [postId],\n * );\n * ```\n *\n * `deps` say *which* list this is, so changing them builds a new one from page one — the right\n * answer for a different post, where continuing to show the previous one's comments while the next\n * arrive would be a lie.\n *\n * For inputs that select *within* one list — a filter, a sort, a search box — reach for\n * `setQuery` instead and leave `deps` alone. That keeps the same list and requeries it, so the rows\n * stay readable while page one of the new query loads:\n *\n * ```tsx\n * const feed = useLazyPages(fetchPage, [postId]);\n * useEffect(() => feed.setQuery({ sort }), [feed, sort]);\n * ```\n *\n * A structurally equal query is a no-op, which is what makes that effect safe to run every render.\n */\nexport function useLazyPages<T, Q = undefined>(\n  fetch: LazyPagesFetch<T, Q>,\n  deps: React.DependencyList,\n  options?: LazyPagesOptions<T, Q>,\n): LazyPages<T, Q> {\n  return useStable(() => lazyPages(fetch, options), deps);\n}\n"],"mappings":"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"}