Licence
MIT
Version
0.0.5
Deps
0
Size
14 kB
Vulns
0
Weekly
357
@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, Schema as S } from 'effect'
// Define — output schema shapes the ready value; add `error` for a failed arm.
class Config extends Resource.make('Config', { output: S.Struct({ url: S.String }) }) {}
// 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:
type AsyncResource<A, E = never> =
| { _tag: 'AsyncResource'; isReady: false; failed: false } // pending
| { _tag: 'AsyncResource'; isReady: true; value: A } // ready
| { _tag: 'AsyncResource'; isReady: false; failed: true; error: E } // only when E ≠ neverThe public API is re-exported from the package index.