Documentation / @etherfold/processor-entities / stateFactoriesFrom
Function: stateFactoriesFrom() ​
stateFactoriesFrom(
options):StateFactories
Defined in: packages/processor-entities/src/stateFactories.ts:157
ONE STORE CONSTRUCTOR, BOTH SEATS OF THE TAB ELECTION (ADR-0097): the writer factory and the reader factory, derived from one open, so the two can never name different databases.
hostIndexerInThisWorker({
...stateFactoriesFrom({
open: (context, entities) => createBrowserStateStore(entities, {databaseName: `app-${context.stream}`}),
entities: processor.entities,
}),
createProcessor: (state) => fromEntityProcessor(processor)(state),
tabElection: {name: 'my-app'},
});Two hand-written factories are a correctness hazard and not only repetition: the election is correct only while the reader opens the SAME database the leader writes, and a databaseName changed in one of them leaves a reader answering from an empty store while looking healthy.
It changes nothing about either factory's contract, which is why it is a helper and not a host change: the writer returns the WritableStateStoreopenForWriting gives (ADR-0077) and the reader the read-only StateStoreopenForReading gives, so a reader built this way cannot write, by type. The install stays the app's (ADR-0096): the writer runs openAndBootstrap with the published snapshot the host hands it, and the reader never downloads or installs one. The claim signal bounds the CLAIM alone, never the download.
The reader is opened SNAPSHOT-AWARE before it is opened for reading, so a reader of a snapshot-seeded store keeps the floor the leader's install recorded and refuses an as-of read below it, as the writer does. Opening snapshot-aware MIGRATES the store (openSnapshotAware calls migrate()), so a reader runs the backend's idempotent migration too: nothing for the browser store, whose constructor already migrated, and CREATE ... IF NOT EXISTS DDL on a SQLite one, which a read-only connection would refuse. Give a reader a connection that may run it, or open it by hand (openForReading over the raw backend), accepting that it then reads without the snapshot floor.