Skip to content

Releases: livestorejs/livestore

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 12:10
c80acb3

Installing v0.4.0: Make sure all LiveStore packages use the same version:

pnpm add @livestore/livestore @livestore/adapter-web @livestore/wa-sqlite @livestore/react
# Or for Cloudflare
pnpm add @livestore/livestore @livestore/adapter-cloudflare @livestore/sync-cf

Highlights

  • New Cloudflare adapter: Added the Workers/Durable Object adapter and rewrote the sync provider so LiveStore ships WebSocket, HTTP, and Durable Object RPC transports as first-party Cloudflare options (#528, #591).
  • S2 sync backend: Map LiveStore's event log onto S2's durable stream store via @livestore/sync-s2, unlocking scalable basins/streams, SSE live tails, and transport-safe batching for large sync workloads (#292, #709).
  • Schema-first tables: LiveStore now accepts Effect schema definitions as SQLite table definitions, removing duplicate column configuration in applications (#544).
  • Cloudflare sync provider storage: Default storage is now Durable Object (DO) SQLite, with an explicit option to use D1 via a named binding. Examples and docs updated to the DO‑by‑default posture (see issue #266, #693).
  • MCP support: LiveStore now ships a CLI with a first-class MCP server so automation flows can connect to instances, query data, and commit events using the bundled tools (#705).
  • React multi-store API: The multi-store API is now the primary React integration, replacing <LiveStoreProvider> with <StoreRegistryProvider> and useStore() with store options. The new API supports multiple stores, preloading, and caching out of the box. See the React integration docs (#841).

Breaking Changes

  • store.shutdown API: The shutdown method now returns an Effect instead of a Promise. Use yield* store.shutdown() inside Effects or await store.shutdownPromise() when a Promise is needed.

    // Before
    await store.shutdown()
    
    // After (Effect API)
    yield * store.shutdown()
    
    // Or use the Promise helper
    await store.shutdownPromise()
  • store.subscribe callback signature: The subscription callback is now passed as the second argument, with subscription options moved to an optional third argument object. Replace usages like store.subscribe(query$, { onUpdate }) with store.subscribe(query$, onUpdate, options).

  • QueryBuilder.first() behaviour: table.query.first() now returns undefined when no rows match. To keep the old behaviour, pass { behaviour: "error" }, or supply a fallback.

    // Before: threw an error when no rows matched
    const user = table.query.first() // throws
    
    // After: returns undefined when no rows match
    const user = table.query.first() // returns undefined
    
    // To preserve old behaviour
    const strictUser = table.query.first({ behaviour: 'error' })
    
    // Or provide a fallback value
    const fallbackUser = table.query.first({
      behaviour: 'fallback',
      fallback: () => ({ id: 'default', name: 'Guest' }),
    })
  • Raw SQL event availability: The livestore.RawSql event is no longer added automatically. Define it explicitly when needed (#469):

    import { Events, Schema } from '@livestore/livestore'
    
    const rawSqlEvent = Events.clientOnly({
      name: 'livestore.RawSql',
      schema: Schema.Struct({
        sql: Schema.String,
        bindValues: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
        writeTables: Schema.optional(Schema.ReadonlySet(Schema.String)),
      }),
    })
  • wa-sqlite version alignment: @livestore/wa-sqlite now follows LiveStore's versioning scheme to keep adapters on matching releases.

    # Before: wa-sqlite had independent versioning
    pnpm add wa-sqlite@1.0.5
    
    # After: wa-sqlite follows LiveStore versioning
    pnpm add @livestore/wa-sqlite@dev

    This change affects projects that directly depend on wa-sqlite. Most users rely on it indirectly through LiveStore adapters and don't need to change anything.

  • Cloudflare sync provider storage selection: Removed implicit D1 auto‑selection and env‑based fallbacks. D1 must be selected explicitly via storage: { _tag: 'd1', binding: 'DB' } on the sync Durable Object. The default is DO SQLite (see issue #266, #693).

    Before (implicit D1 when env.DB was present):

    export class SyncBackendDO extends makeDurableObject({
      // storage engine auto‑selected based on env
    }) {}

    After (explicit binding for D1):

    // wrangler.toml
    // [[d1_databases]]
    // binding = "DB"
    // database_name = "your-db"
    // database_id = "..."
    
    // code
    export class SyncBackendDO extends makeDurableObject({
      storage: { _tag: 'd1', binding: 'DB' },
    }) {}

    To use the default DO SQLite, omit the storage option or pass { _tag: 'do-sqlite' }.

  • Restructured LiveStoreEvent and EventSequenceNumber APIs: Types are now organized into symmetric Global, Client, and Input namespaces that clarify the distinction between sync backend format, client format, and events without sequence numbers (#855):

    Old Name New Name
    LiveStoreEvent.AnyEncodedGlobal LiveStoreEvent.Global.Encoded
    LiveStoreEvent.AnyEncoded LiveStoreEvent.Client.Encoded
    LiveStoreEvent.AnyDecoded LiveStoreEvent.Client.Decoded
    LiveStoreEvent.PartialAnyEncoded LiveStoreEvent.Input.Encoded
    LiveStoreEvent.PartialAnyDecoded LiveStoreEvent.Input.Decoded
    LiveStoreEvent.EncodedWithMeta LiveStoreEvent.Client.EncodedWithMeta
    EventSequenceNumber.GlobalEventSequenceNumber EventSequenceNumber.Global
    EventSequenceNumber.globalEventSequenceNumber EventSequenceNumber.Global.make
    EventSequenceNumber.localEventSequenceNumber EventSequenceNumber.Client.make
    EventSequenceNumber.clientDefault EventSequenceNumber.Client.DEFAULT
    EventSequenceNumber.rebaseGenerationDefault EventSequenceNumber.REBASE_GENERATION_DEFAULT
    LiveStoreEvent.EventDefPartialSchema LiveStoreEvent.EventDefInputSchema
    LiveStoreEvent.makeEventDefPartialSchema LiveStoreEvent.makeEventDefInputSchema
    // Before
    import { LiveStoreEvent, EventSequenceNumber } from '@livestore/livestore'
    const event: LiveStoreEvent.AnyEncoded = { ... }
    const globalSeq: EventSequenceNumber.GlobalEventSequenceNumber = 1
    
    // After
    import { LiveStoreEvent, EventSequenceNumber } from '@livestore/livestore'
    const event: LiveStoreEvent.Client.Encoded = { ... }
    const globalSeq: EventSequenceNumber.Global = 1
  • Error class rename: UnexpectedError has been renamed to UnknownError for better semantic clarity and consistency with Effect ecosystem naming conventions. The previous name conflicted with Effect's terminology where "unexpected errors" refer to defects, while this error type represents errors of unknown type from external libraries or infrastructure failures (See PR #823).

    Update all references:

    • Class name: UnexpectedErrorUnknownError
    • Error tag: 'LiveStore.UnexpectedError''UnknownError'
    • Static methods: mapToUnexpectedError*mapToUnknownError*
    • Related type: MergeResultUnexpectedErrorMergeResultUnknownError
    // Before
    import { UnexpectedError } from '@livestore/common'
    
    effect.pipe(UnexpectedError.mapToUnexpectedError)
    
    // After
    import { UnknownError } from '@livestore/common'
    
    effect.pipe(UnknownError.mapToUnknownError)
  • React integration API: The multi-store API is now the primary React integration, replacing <LiveStoreProvider> and the old useStore(). The new API uses StoreRegistry, <StoreRegistryProvider>, and useStore() with store options. See the React integration docs for full details (#841).

    Before After
    <LiveStoreProvider schema={...} adapter={...}> <StoreRegistryProvider storeRegistry={...}> + storeOptions({ ... })
    const { store } = useStore() const store = useStore({ ... })
    useQuery(query$) store.useQuery(query$)
    // Before
    import { LiveStoreProvider, useStore, useQuery } from '@livestore/react'
    
    const App = () => (
      <LiveStoreProvider schema={schema} adapter={adapter} batchUpdates={batchUpdates}>
        <MyComponent />
      </LiveStoreProvider>
    )
    
    const MyComponent = () => {
      const { store } = useStore()
      const todos = useQuery(visibleTodos$)
      // ...
    }
    
    // After
    import { StoreRegistry } from '@livestore/livestore'
    import { StoreRegistryProvider, useStore } from '@livestore/react'
    
    const useAppStore = () =>
      useStore({
        storeId: 'app-root',
        schema,
        adapter,
        batchUpdates,
      })
    
    const App = () => {
      const [storeRegistry] = useState(() => new StoreRegistry())
      return (
        <Suspense fallback={<div>Loading...</div>}>
          <StoreRegistryProvider storeRegis...
Read more

v0.4.0-dev.27

v0.4.0-dev.27 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 22 May 09:22
aa2e4a2

Release 0.4.0-dev.27

v0.4.0-dev.26

v0.4.0-dev.26 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 13 May 13:29
bfeaed0

Release 0.4.0-dev.26

v0.4.0-dev.25

v0.4.0-dev.25 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 12 May 08:53
4bb7f9a

Release 0.4.0-dev.25

v0.4.0-dev.24

v0.4.0-dev.24 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 08 May 01:28
5978abc

Release 0.4.0-dev.24

"v0.4.0-dev.23"

"v0.4.0-dev.23" Pre-release
Pre-release

Choose a tag to compare

@schickling-assistant schickling-assistant released this 29 Apr 23:45
39dc63d

Release 0.4.0-dev.23.

Posted on behalf of @schickling
field value
agent_name 🌱 co1-alder
agent_session_id 6c624c62-4e38-435e-b267-475ef99d9340
agent_tool Codex CLI
agent_tool_version codex-cli 0.124.0
agent_runtime Codex CLI codex-cli 0.124.0
agent_model unknown
worktree megarepo-all/schickling/2026-04-26-livestore-release
machine dev3
tooling_profile dotfiles@19cf6f4

"v0.4.0-dev.22"

"v0.4.0-dev.22" Pre-release
Pre-release

Choose a tag to compare

@schickling schickling released this 24 Dec 18:36
8bb0311

"Release 0.4.0-dev.22 including Chrome Extension"

"v0.4.0-dev.21"

"v0.4.0-dev.21" Pre-release
Pre-release

Choose a tag to compare

@schickling schickling released this 12 Dec 15:12
aadb5ea

"Release 0.4.0-dev.21 including Chrome Extension"

"v0.4.0-dev.20"

"v0.4.0-dev.20" Pre-release
Pre-release

Choose a tag to compare

@schickling schickling released this 04 Dec 20:01
4cf07ca

"Release 0.4.0-dev.20 including Chrome Extension"

"v0.4.0-dev.19"

"v0.4.0-dev.19" Pre-release
Pre-release

Choose a tag to compare

@schickling schickling released this 01 Dec 11:26
1f492cc

"Release 0.4.0-dev.19 including Chrome Extension"