Start here after you can run an Effect and observe an Fx. Your library should expose the capability a caller needs, together with its failures, services and lifetime. Start with an existing producer or consumer; implementing a renderer is an optional boundary.
Accept the narrow capability you need
A label needs to read the selected name, not change it. Accept a read-only capability so the caller can supply writable state without giving the library permission to replace it:
import { RefSubject } from "@typed/fx";
const selectedLabel = <E, R>(selectedName: RefSubject.Computed<string, E, R>) =>
RefSubject.map(selectedName, (name) => `Selected account: ${name}`);
This preserves the source’s errors and services. For a clearable selection, keep absence in an Option-valued source; conditional state explains why filtering absence does not emit a clear.
Keep asynchronous work visible to the caller
Preserve Fx<A, E, R> through your wrapper. Handle an expected failure only when your API defines the resulting behavior. Supply services at the consuming application’s boundary, so a test can replace the repository without a global runtime.
Next, write a consumer with Sink. That path then covers publication, scoped producers and resource ownership. Prefer existing operators before implementing a producer protocol.
Choose the boundary your caller needs
| Requirement | Focused extension |
|---|---|
| Share one current model | Shared state contracts |
| Render caller-owned state | Build a component |
| Retain an editable item across reorders | Keyed collections |
| Place an existing chart or editor | DOM output adapter |
| Accept already serialized HTML | HTML output contract |
| Interpret template syntax itself | Template compilation |
These are alternatives, not prerequisites for finishing a library.
Test the promises at the public boundary
Test the behavior your public contract promises, including cleanup for resources the library acquires. Testing techniques shows how to observe those boundaries.