Skip to main content

@tenmol/stores

Client state for the PyMOL web client. ~2,950 lines of plain TypeScript, one dependency (@tenmol/protocol, types only), no framework and no state library.

Importing

The barrel (src/index.ts) exports createStore, bridgeBinding, poll, connection, feedback, objects, objectsSource and ui. It is frozenconsole.ts and settings.ts are deliberately not in it, and neither is anything you add. Reach a store by subpath:
package.json ("./*": "./src/*.ts") and tsconfig.base.json ("@tenmol/stores/*") already resolve that, so adding src/<yourStore>.ts is the entire installation step and no shared file is edited.

Three things to know before you change anything here

1. Nothing is optimistic except ui.ts. Every PyMOL mutation is round-tripped. A settings write can silently no-op at the wrong level, SettingGenerateSideEffects can invalidate geometry, and the object panel has no push feed at all — so the truth is always the next poll or the next topic event, never what the UI just asked for. ui.ts is exempt because none of it is PyMOL state. 2. Gap detection in bridgeBinding.ts is currently INERT, on purpose. EventMessage.seq is monotonic per topic per connection, but packages/client/src/connection.ts forwards message.payload and drops message.seq on the floor. So every binding runs with seq === undefined and reports seqAvailable: false rather than pretending everything is fine. The moment the client forwards seq, bind() starts working with no change here. 3. No React in this package. The binding is apps/web/src/app/hooks.ts. Everything here is therefore testable under vitest’s node environment with no DOM — which is the reason the split exists.

Tests

That covers the machinery and the stores the barrel exports. console.ts and settings.ts are tested from the app, in apps/web/src/features/console/** and apps/web/src/features/settings/** (214 tests between them), because their tests exercise the store together with the feature that wires it. Changing either of those two files and running only --filter @tenmol/stores will tell you nothing; run pnpm test.