Support Matrix

September 5, 2026 · View on GitHub

This document records the officially supported feature combinations for the current codebase.

Status Legend

  • Supported
    • covered by tests and intended as a maintained contract
  • Limited
    • works with a narrower guarantee than the surrounding feature might imply
  • Unsupported
    • not part of the maintained contract; may throw, diverge, or remain untested

When in doubt, prefer documenting a combination as Limited or Unsupported instead of implying a stronger guarantee than the test suite and runtime checks actually enforce.

Core Store Modes

CombinationStatusNotes
Native single store in local modeSupportedDefault synchronous store with local mutation authority.
Native slices store in local modeSupportedOfficial slices contract.
Native single store as shared main storeSupportedRequires patch generation in shared mode.
Native slices store as shared main storeSupportedSame authority model as single store.
Native single store as shared client storeSupportedMethods become async proxies to the main store.
Native slices store as shared client storeSupportedSame client authority rules as single store.
Direct setState() in client modeUnsupportedClient stores are mirrors and reject local authority writes.
Shared mode with enablePatches: falseUnsupportedShared synchronization depends on patch streams.

Binder-Backed Adapter Matrix

Binder-backed adapters are whole-store adapters. They are never supported as a slice nested inside a Coaction slices store.

AdapterLocal whole storeShared main/clientSlices modeNotes
@coaction/zustandSupportedSupportedUnsupportedShared contract covers remote method execution. Direct client-side Zustand writes are rejected.
@coaction/mobxSupportedSupportedUnsupportedShared contract covers remote method execution. Direct client-side MobX writes are integration-defined.
@coaction/piniaSupportedSupportedUnsupportedShared contract covers remote method execution. Direct client-side Pinia writes are integration-defined.
@coaction/jotaiSupportedSupportedUnsupportedShared contract covers remote method execution. Direct client-side atom writes are rejected.
@coaction/reduxSupportedUnsupportedUnsupportedOfficial contract is local whole-store binding only.
@coaction/valtioSupportedSupportedUnsupportedShared contract covers remote method execution. Direct client-side Valtio writes to mirrored fields are restored.
@coaction/xstateSupportedUnsupportedUnsupportedOfficial contract is local whole-store binding only.

Adapter Boundaries

  • Binder-backed adapters are whole-store bridges.
    • Do not mount them under a slice key inside a Coaction slices object.
  • Shared support means Coaction method execution is part of the contract.
    • It does not automatically mean every out-of-band write to the underlying external store is mirrored across a client/main topology.
  • Local external writes are part of the maintained contract for official binder-backed adapters.
  • Shared external writes to the underlying adapter store are not yet a uniform cross-adapter contract.
  • Client-bound external writes are only supported when the adapter explicitly says so.
    • @coaction/zustand rejects them at runtime.
    • @coaction/jotai rejects client-side atom writes at runtime.
    • @coaction/valtio restores client-side Valtio writes to mirrored schema fields back to the authoritative snapshot.
    • @coaction/mobx and @coaction/pinia currently leave them integration-defined and should not be treated as authoritative.

Middleware and Integration Matrix

IntegrationLocal storeShared main storeShared client storeNotes
@coaction/loggerSupportedSupportedLimitedClient-side logs reflect mirrored updates and proxied calls, not hidden authority-side work.
@coaction/persistSupportedSupportedUnsupportedRehydrate and writeback use store.setState(), which client stores reject. Install on the authority store.
@coaction/historySupportedSupportedUnsupportedUndo/redo mutates state through setState(). Install on the authority store.
@coaction/yjsSupportedSupportedUnsupportedBinding rejects store.share === 'client'. Use on the owning store only.
@coaction/syncSupportedSupportedUnsupportedsync() throws on store.share === 'client'. Attach it to the local or authoritative main store.

The @coaction/sync backend adapters — /crud, /supabase, /firestore, /query — and the /indexeddb storage carry the same boundary as sync() itself: they are attached through it, so a client mirror rejects them with it.

Combination Notes

Slices and Binder-Backed Adapters

Unsupported.

Reason:

  • defineExternalStoreAdapter() adapts an external whole-store runtime
  • Coaction slices are a native state-composition model
  • nesting one inside the other makes store ownership ambiguous

The runtime enforces this by throwing during initialization.

Client Store Restricted Operations

Client stores may:

  • read mirrored state
  • subscribe to mirrored updates
  • call store methods, which proxy execution to the main store

Client stores may not:

  • call setState() directly
  • become an independent mutation authority
  • assume local middleware can authoritatively persist, time-travel, or merge state

Middleware Guarantees in Worker/Client Topologies

logger

  • Install on the main store when you need authority-side logs.
  • Install on a client store only when mirror-side logging is acceptable.

persist

  • Persist the main/shared authority store.
  • Do not persist a client mirror.

history

  • Run undo/redo on the authority store.
  • Do not expose client-local undo/redo as if it were authoritative.

Framework Auto-Selector Boundaries

Framework packages that expose autoSelector or equivalent generated selector maps currently build those maps from the state descriptors available during initialization.

Implications:

  • known keys get stable generated selectors
  • dynamically added keys are not promoted into the generated selector map later
  • dynamic paths should use explicit selectors instead of relying on autoSelector

For React specifically, autoSelector returns a cached selector map rather than implicitly reading values. Call useStore(selectorMap.someKey) to subscribe to that field.

Yjs Data Model Constraints

@coaction/yjs synchronizes the store's pure data, not Coaction runtime behavior.

Constraints:

  • keep the synced state plain and serializable
  • methods and getters are excluded from the synchronized payload
  • nested data is stored as Y.Map and Y.Array
  • scalar conflict resolution follows Yjs semantics
  • commutative behavior should be modeled with CRDT-native Yjs structures when needed

Officially Supported vs Not Yet Supported

The test suite now distinguishes between:

  • officially maintained adapter contracts
  • combinations that may appear to work in isolated cases but are not yet a repository-level support promise

When extending support, update this matrix and add contract coverage in the same change.