Resources & suspense

Async data loading with declarative fallbacks.

Resource

Resource(T) wraps an async value: .loading.ready(T) or .err(anyerror). The fetcher runs off-thread; a signal updates when it resolves.

const res = try verve.resource.create(u32, io, owner, fetch_ctx, fetcherFn);

res.get();       // ?T — reactive read, subscribes the current effect
res.peek();      // untracked state snapshot
res.isLoading(); res.isReady(); res.isErr();
res.resolve(io); // await + apply staged result (main thread)

verve.resource.ready(T, owner, value) builds a pre-resolved resource — useful for tests and cache hits.

Suspense boundaries

A suspense boundary renders its child, or the fallback if anything inside marked itself suspended:

return verve.suspense(ctx, .{ .fallback = spinner }, data, renderChild);
  • A Resource in .loading calls markSuspended() internally — the nearest boundary swaps to its fallback.
  • verve.transition(...) is the same boundary under the view-transition name.

Streaming SSR

Suspended boundaries integrate with Renderer.streamRender: the shell flushes immediately with fallbacks in place, and resolved chunks stream in as they complete. Pair with the server's chunked response path; no client code changes needed — hydration picks up whichever HTML arrived.

Next: I18n.