ResourceState:
    | { state: "idle" }
    | { origin: GraphTime; promise: Promise<unknown>; state: "loading" }
    | { loadedAt: GraphTime; origin: GraphTime; state: "loaded"; value: T }
    | { loadedAt: GraphTime; origin: GraphTime; state: "stale"; value: T }
    | {
        error: unknown;
        erroredAt: GraphTime;
        origin: GraphTime;
        state: "errored";
    }

Tagged-union state carried by a ResourceHandle.node.

Type Parameters

  • T

    Resolved value type produced by the loader.

Each tag corresponds to a state in the ResourceFleet sub-statechart. Accessing .value requires a tag check first; the type system forbids reading a not-yet-loaded value, so the "reading a not-yet-loaded resource" race is caught at compile time by tsc rather than left to runtime. Every "X may or may not have Y" optional field gets surfaced as a tag instead of being hidden as an optional.

  • idle: registered, never fetched.
  • loading: fetch in flight; origin is the GraphTime at which the fetch was issued. promise is the in-flight Promise for this loading episode — identity-stable across renders for the same key and origin (SPEC §9.1: "Suspense fresh-Promise-per-render breaks SuspenseList / startTransition … the in-flight Promise lives on ResourceState.loading itself"). Always resolves (never rejects): it is the Promise React's renderer awaits when the Suspense hook throws on this state, and a rejection there would surface as an unhandled-rejection warning. The loader's rejection still drives the resource to errored; the next render reads that tag and the error boundary catches it.
  • loaded: fetch resolved while still authoritative for origin.
  • stale: a previously-loaded value whose dependencies advanced past origin, or whose fetch resolved after a later commit.
  • errored: the loader rejected (the Loading → Errored fetch-reject edge), or ResourceHandle.fail was invoked from loading/loaded (the chart-named host-side trigger for the same two edges into Errored).