@playfast/reform-resource
v1.0.1
Published
Async resources for Reform — a layer that builds synchronously, loads in the background, and flips a reactive store from pending to ready/failed. The sanctioned home for async work that would otherwise break reform's synchronous scene build.
Maintainers
Readme
@playfast/reform-resource
Async resources for Reform.
Reform renders synchronously, so it builds a scene's whole layer graph with
runSync. A layer whose acquire does async work (open a connection, fetch config,
Effect.sleep) breaks that build — reform now reports it as AsyncSceneLayer and
points you here.
A Resource is the sanctioned home for that async work:
- its
livelayer builds synchronously, seeding apendingvalue; - it forks the load under the scene scope (so
acquireReleasefinalizers release when the scene unmounts); - when the load settles it flips a reactive store to
ready(orfailed), which re-renders any composition that read the resource — exactly like a state/calc.
Unlike AsyncCalc, a Resource has no reactive inputs and no query driver: it is
a one-shot, scoped load.
Usage
import { Resource } from '@playfast/reform-resource'
import { Effect, Option, Schema as S } from 'effect'
// Define — `output` shapes the ready value; `error` is required (`Option.none()`
// for an infallible load, `Option.some(schema)` to add a `failed` arm).
class Config extends Resource.make('Config', {
output: S.Struct({ url: S.String }),
error: Option.none(),
}) {}
// Wire — `acquire` may be scoped (acquire/release tied to the scene scope).
const ConfigLive = Resource.live(
Config,
Effect.acquireRelease(openConfig, closeConfig),
)
// Read inside a composition.
const view = Effect.gen(function* () {
const config = yield* Config
return config.isReady ? render(config.value) : spinner()
})The value is a union discriminated by isReady (pending | ready, plus a failed
arm only when an error schema is declared).
See the playbook for the full API and AsyncResource type.
