@livestore/common 0.4.0-dev.2 → 0.4.0-dev.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/ClientSessionLeaderThreadProxy.d.ts +20 -12
- package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
- package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
- package/dist/adapter-types.d.ts +14 -6
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js.map +1 -1
- package/dist/debug-info.d.ts.map +1 -1
- package/dist/debug-info.js +33 -6
- package/dist/debug-info.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +28 -23
- package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-client-session.js +2 -2
- package/dist/devtools/devtools-messages-client-session.js.map +1 -1
- package/dist/devtools/devtools-messages-common.d.ts +7 -14
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-common.js +1 -6
- package/dist/devtools/devtools-messages-common.js.map +1 -1
- package/dist/devtools/devtools-messages-leader.d.ts +38 -29
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +9 -8
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/devtools/devtools-sessioninfo.d.ts +14 -2
- package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -1
- package/dist/devtools/devtools-sessioninfo.js +7 -4
- package/dist/devtools/devtools-sessioninfo.js.map +1 -1
- package/dist/devtools/mod.d.ts +13 -2
- package/dist/devtools/mod.d.ts.map +1 -1
- package/dist/devtools/mod.js +10 -3
- package/dist/devtools/mod.js.map +1 -1
- package/dist/errors.d.ts +52 -10
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +25 -6
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +41 -4
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +158 -75
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts +21 -22
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +77 -20
- package/dist/leader-thread/eventlog.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +2 -2
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +56 -45
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +6 -6
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +79 -27
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.test.d.ts +2 -0
- package/dist/leader-thread/make-leader-thread-layer.test.d.ts.map +1 -0
- package/dist/leader-thread/make-leader-thread-layer.test.js +32 -0
- package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -0
- package/dist/leader-thread/materialize-event.d.ts +3 -3
- package/dist/leader-thread/materialize-event.d.ts.map +1 -1
- package/dist/leader-thread/materialize-event.js +25 -11
- package/dist/leader-thread/materialize-event.js.map +1 -1
- package/dist/leader-thread/mod.d.ts +1 -0
- package/dist/leader-thread/mod.d.ts.map +1 -1
- package/dist/leader-thread/mod.js +1 -0
- package/dist/leader-thread/mod.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts +2 -3
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +5 -5
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.d.ts +2 -2
- package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +2 -2
- package/dist/leader-thread/shutdown-channel.js.map +1 -1
- package/dist/leader-thread/stream-events.d.ts +56 -0
- package/dist/leader-thread/stream-events.d.ts.map +1 -0
- package/dist/leader-thread/stream-events.js +166 -0
- package/dist/leader-thread/stream-events.js.map +1 -0
- package/dist/leader-thread/types.d.ts +98 -20
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js +13 -0
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/logging.d.ts +40 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +33 -0
- package/dist/logging.js.map +1 -0
- package/dist/make-client-session.d.ts +5 -3
- package/dist/make-client-session.d.ts.map +1 -1
- package/dist/make-client-session.js +5 -2
- package/dist/make-client-session.js.map +1 -1
- package/dist/materializer-helper.d.ts +6 -6
- package/dist/materializer-helper.d.ts.map +1 -1
- package/dist/materializer-helper.js +20 -4
- package/dist/materializer-helper.js.map +1 -1
- package/dist/otel.d.ts +2 -1
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +5 -0
- package/dist/otel.js.map +1 -1
- package/dist/rematerialize-from-eventlog.d.ts +2 -2
- package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
- package/dist/rematerialize-from-eventlog.js +29 -20
- package/dist/rematerialize-from-eventlog.js.map +1 -1
- package/dist/schema/EventDef/define.d.ts +147 -0
- package/dist/schema/EventDef/define.d.ts.map +1 -0
- package/dist/schema/EventDef/define.js +139 -0
- package/dist/schema/EventDef/define.js.map +1 -0
- package/dist/schema/EventDef/event-def.d.ts +106 -0
- package/dist/schema/EventDef/event-def.d.ts.map +1 -0
- package/dist/schema/EventDef/event-def.js +2 -0
- package/dist/schema/EventDef/event-def.js.map +1 -0
- package/dist/schema/EventDef/facts.d.ts +118 -0
- package/dist/schema/EventDef/facts.d.ts.map +1 -0
- package/dist/schema/EventDef/facts.js +53 -0
- package/dist/schema/EventDef/facts.js.map +1 -0
- package/dist/schema/EventDef/materializer.d.ts +155 -0
- package/dist/schema/EventDef/materializer.d.ts.map +1 -0
- package/dist/schema/EventDef/materializer.js +83 -0
- package/dist/schema/EventDef/materializer.js.map +1 -0
- package/dist/schema/EventDef/mod.d.ts +5 -0
- package/dist/schema/EventDef/mod.d.ts.map +1 -0
- package/dist/schema/EventDef/mod.js +5 -0
- package/dist/schema/EventDef/mod.js.map +1 -0
- package/dist/schema/EventSequenceNumber/client.d.ts +136 -0
- package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber/client.js +193 -0
- package/dist/schema/EventSequenceNumber/client.js.map +1 -0
- package/dist/schema/EventSequenceNumber/global.d.ts +15 -0
- package/dist/schema/EventSequenceNumber/global.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber/global.js +14 -0
- package/dist/schema/EventSequenceNumber/global.js.map +1 -0
- package/dist/schema/EventSequenceNumber/mod.d.ts +37 -0
- package/dist/schema/EventSequenceNumber/mod.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber/mod.js +37 -0
- package/dist/schema/EventSequenceNumber/mod.js.map +1 -0
- package/dist/schema/EventSequenceNumber.test.js +43 -43
- package/dist/schema/EventSequenceNumber.test.js.map +1 -1
- package/dist/schema/{LiveStoreEvent.d.ts → LiveStoreEvent/client.d.ts} +89 -106
- package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -0
- package/dist/schema/{LiveStoreEvent.js → LiveStoreEvent/client.js} +74 -58
- package/dist/schema/LiveStoreEvent/client.js.map +1 -0
- package/dist/schema/LiveStoreEvent/for-event-def.d.ts +52 -0
- package/dist/schema/LiveStoreEvent/for-event-def.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/for-event-def.js +2 -0
- package/dist/schema/LiveStoreEvent/for-event-def.js.map +1 -0
- package/dist/schema/LiveStoreEvent/global.d.ts +36 -0
- package/dist/schema/LiveStoreEvent/global.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/global.js +31 -0
- package/dist/schema/LiveStoreEvent/global.js.map +1 -0
- package/dist/schema/LiveStoreEvent/input.d.ts +46 -0
- package/dist/schema/LiveStoreEvent/input.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/input.js +26 -0
- package/dist/schema/LiveStoreEvent/input.js.map +1 -0
- package/dist/schema/LiveStoreEvent/mod.d.ts +5 -0
- package/dist/schema/LiveStoreEvent/mod.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/mod.js +5 -0
- package/dist/schema/LiveStoreEvent/mod.js.map +1 -0
- package/dist/schema/events.d.ts +1 -1
- package/dist/schema/events.d.ts.map +1 -1
- package/dist/schema/events.js +1 -1
- package/dist/schema/events.js.map +1 -1
- package/dist/schema/mod.d.ts +6 -4
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +5 -4
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/schema.d.ts +16 -1
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +27 -2
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.d.ts +36 -6
- package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.js +97 -6
- package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.test.js +16 -0
- package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.js +14 -6
- package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.js +69 -22
- package/dist/schema/state/sqlite/column-def.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.test.js +48 -10
- package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-spec.js +30 -12
- package/dist/schema/state/sqlite/column-spec.js.map +1 -1
- package/dist/schema/state/sqlite/column-spec.test.js +23 -14
- package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +2 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +23 -6
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +14 -8
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +5 -3
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js +2 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
- package/dist/schema/state/sqlite/mod.d.ts +3 -3
- package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/mod.js +3 -3
- package/dist/schema/state/sqlite/mod.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/api.d.ts +19 -11
- package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.js +22 -15
- package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.js +6 -3
- package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.test.js +252 -88
- package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.d.ts +2 -2
- package/dist/schema/state/sqlite/schema-helpers.d.ts.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.js +22 -12
- package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.test.d.ts +2 -0
- package/dist/schema/state/sqlite/schema-helpers.test.d.ts.map +1 -0
- package/dist/schema/state/sqlite/schema-helpers.test.js +36 -0
- package/dist/schema/state/sqlite/schema-helpers.test.js.map +1 -0
- package/dist/schema/state/sqlite/{system-tables.d.ts → system-tables/eventlog-tables.d.ts} +63 -456
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.d.ts.map +1 -0
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.js +54 -0
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.js.map +1 -0
- package/dist/schema/state/sqlite/system-tables/mod.d.ts +3 -0
- package/dist/schema/state/sqlite/system-tables/mod.d.ts.map +1 -0
- package/dist/schema/state/sqlite/system-tables/mod.js +3 -0
- package/dist/schema/state/sqlite/system-tables/mod.js.map +1 -0
- package/dist/schema/state/sqlite/system-tables/state-tables.d.ts +456 -0
- package/dist/schema/state/sqlite/system-tables/state-tables.d.ts.map +1 -0
- package/dist/schema/state/sqlite/system-tables/state-tables.js +55 -0
- package/dist/schema/state/sqlite/system-tables/state-tables.js.map +1 -0
- package/dist/schema/state/sqlite/table-def.d.ts +4 -4
- package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/table-def.js +2 -2
- package/dist/schema/state/sqlite/table-def.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.test.js +80 -0
- package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
- package/dist/schema/unknown-events.d.ts +47 -0
- package/dist/schema/unknown-events.d.ts.map +1 -0
- package/dist/schema/unknown-events.js +69 -0
- package/dist/schema/unknown-events.js.map +1 -0
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts +2 -0
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts.map +1 -0
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +73 -0
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -0
- package/dist/schema-management/migrations.d.ts +32 -2
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +37 -5
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-schema.d.ts +3 -3
- package/dist/schema-management/validate-schema.d.ts.map +1 -1
- package/dist/schema-management/validate-schema.js +2 -2
- package/dist/schema-management/validate-schema.js.map +1 -1
- package/dist/sql-queries/sql-queries.d.ts.map +1 -1
- package/dist/sql-queries/sql-queries.js +11 -1
- package/dist/sql-queries/sql-queries.js.map +1 -1
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
- package/dist/sql-queries/sql-query-builder.js +2 -1
- package/dist/sql-queries/sql-query-builder.js.map +1 -1
- package/dist/sqlite-types.d.ts +3 -3
- package/dist/sqlite-types.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +11 -13
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +45 -42
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/errors.d.ts +66 -0
- package/dist/sync/errors.d.ts.map +1 -0
- package/dist/sync/errors.js +36 -0
- package/dist/sync/errors.js.map +1 -0
- package/dist/sync/index.d.ts +3 -0
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +3 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/mock-sync-backend.d.ts +23 -0
- package/dist/sync/mock-sync-backend.d.ts.map +1 -0
- package/dist/sync/mock-sync-backend.js +114 -0
- package/dist/sync/mock-sync-backend.js.map +1 -0
- package/dist/sync/next/compact-events.d.ts.map +1 -1
- package/dist/sync/next/compact-events.js +6 -7
- package/dist/sync/next/compact-events.js.map +1 -1
- package/dist/sync/next/facts.d.ts +5 -5
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +1 -2
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +54 -15
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +198 -9
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/history-dag.d.ts.map +1 -1
- package/dist/sync/next/history-dag.js +10 -8
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +5 -5
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +5 -5
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/event-fixtures.d.ts +2 -2
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/event-fixtures.js +9 -9
- package/dist/sync/next/test/event-fixtures.js.map +1 -1
- package/dist/sync/sync-backend-kv.d.ts +7 -0
- package/dist/sync/sync-backend-kv.d.ts.map +1 -0
- package/dist/sync/sync-backend-kv.js +18 -0
- package/dist/sync/sync-backend-kv.js.map +1 -0
- package/dist/sync/sync-backend.d.ts +105 -0
- package/dist/sync/sync-backend.d.ts.map +1 -0
- package/dist/sync/sync-backend.js +61 -0
- package/dist/sync/sync-backend.js.map +1 -0
- package/dist/sync/sync.d.ts +9 -86
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js +2 -27
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/syncstate.d.ts +57 -44
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +50 -45
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +83 -46
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/sync/transport-chunking.d.ts +36 -0
- package/dist/sync/transport-chunking.d.ts.map +1 -0
- package/dist/sync/transport-chunking.js +56 -0
- package/dist/sync/transport-chunking.js.map +1 -0
- package/dist/sync/validate-push-payload.d.ts +2 -2
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js +6 -6
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/testing/event-factory.d.ts +68 -0
- package/dist/testing/event-factory.d.ts.map +1 -0
- package/dist/testing/event-factory.js +78 -0
- package/dist/testing/event-factory.js.map +1 -0
- package/dist/testing/mod.d.ts +2 -0
- package/dist/testing/mod.d.ts.map +1 -0
- package/dist/testing/mod.js +2 -0
- package/dist/testing/mod.js.map +1 -0
- package/dist/version.d.ts +16 -6
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +16 -6
- package/dist/version.js.map +1 -1
- package/package.json +7 -8
- package/src/ClientSessionLeaderThreadProxy.ts +20 -12
- package/src/adapter-types.ts +18 -6
- package/src/debug-info.ts +37 -6
- package/src/devtools/devtools-messages-client-session.ts +2 -2
- package/src/devtools/devtools-messages-common.ts +1 -8
- package/src/devtools/devtools-messages-leader.ts +9 -8
- package/src/devtools/devtools-sessioninfo.ts +8 -5
- package/src/devtools/mod.ts +11 -2
- package/src/errors.ts +38 -11
- package/src/index.ts +2 -1
- package/src/leader-thread/LeaderSyncProcessor.ts +277 -105
- package/src/leader-thread/eventlog.ts +113 -38
- package/src/leader-thread/leader-worker-devtools.ts +86 -55
- package/src/leader-thread/make-leader-thread-layer.test.ts +44 -0
- package/src/leader-thread/make-leader-thread-layer.ts +156 -37
- package/src/leader-thread/materialize-event.ts +37 -12
- package/src/leader-thread/mod.ts +1 -0
- package/src/leader-thread/recreate-db.ts +15 -7
- package/src/leader-thread/shutdown-channel.ts +16 -2
- package/src/leader-thread/stream-events.ts +201 -0
- package/src/leader-thread/types.ts +70 -20
- package/src/logging.ts +62 -0
- package/src/make-client-session.ts +9 -3
- package/src/materializer-helper.ts +27 -10
- package/src/otel.ts +10 -0
- package/src/rematerialize-from-eventlog.ts +37 -27
- package/src/schema/EventDef/define.ts +201 -0
- package/src/schema/EventDef/event-def.ts +120 -0
- package/src/schema/EventDef/facts.ts +135 -0
- package/src/schema/EventDef/materializer.ts +172 -0
- package/src/schema/EventDef/mod.ts +4 -0
- package/src/schema/EventSequenceNumber/client.ts +257 -0
- package/src/schema/EventSequenceNumber/global.ts +19 -0
- package/src/schema/EventSequenceNumber/mod.ts +37 -0
- package/src/schema/EventSequenceNumber.test.ts +70 -52
- package/src/schema/LiveStoreEvent/client.ts +221 -0
- package/src/schema/LiveStoreEvent/for-event-def.ts +60 -0
- package/src/schema/LiveStoreEvent/global.ts +45 -0
- package/src/schema/LiveStoreEvent/input.ts +63 -0
- package/src/schema/LiveStoreEvent/mod.ts +4 -0
- package/src/schema/events.ts +1 -1
- package/src/schema/mod.ts +6 -4
- package/src/schema/schema.ts +39 -3
- package/src/schema/state/sqlite/client-document-def.test.ts +19 -2
- package/src/schema/state/sqlite/client-document-def.ts +127 -25
- package/src/schema/state/sqlite/column-annotations.test.ts +1 -1
- package/src/schema/state/sqlite/column-annotations.ts +16 -6
- package/src/schema/state/sqlite/column-def.test.ts +62 -10
- package/src/schema/state/sqlite/column-def.ts +88 -21
- package/src/schema/state/sqlite/column-spec.test.ts +29 -16
- package/src/schema/state/sqlite/column-spec.ts +36 -11
- package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +26 -6
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +29 -12
- package/src/schema/state/sqlite/db-schema/dsl/mod.ts +12 -17
- package/src/schema/state/sqlite/mod.ts +4 -3
- package/src/schema/state/sqlite/query-builder/api.ts +25 -11
- package/src/schema/state/sqlite/query-builder/astToSql.ts +23 -14
- package/src/schema/state/sqlite/query-builder/impl.test.ts +305 -92
- package/src/schema/state/sqlite/query-builder/impl.ts +8 -3
- package/src/schema/state/sqlite/schema-helpers.test.ts +44 -0
- package/src/schema/state/sqlite/schema-helpers.ts +28 -20
- package/src/schema/state/sqlite/system-tables/eventlog-tables.ts +64 -0
- package/src/schema/state/sqlite/system-tables/mod.ts +2 -0
- package/src/schema/state/sqlite/system-tables/state-tables.ts +69 -0
- package/src/schema/state/sqlite/table-def.test.ts +101 -0
- package/src/schema/state/sqlite/table-def.ts +8 -6
- package/src/schema/unknown-events.ts +131 -0
- package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +86 -0
- package/src/schema-management/migrations.ts +41 -8
- package/src/schema-management/validate-schema.ts +3 -3
- package/src/sql-queries/sql-queries.ts +9 -1
- package/src/sql-queries/sql-query-builder.ts +2 -1
- package/src/sqlite-types.ts +3 -3
- package/src/sync/ClientSessionSyncProcessor.ts +69 -62
- package/src/sync/errors.ts +38 -0
- package/src/sync/index.ts +3 -0
- package/src/sync/mock-sync-backend.ts +184 -0
- package/src/sync/next/compact-events.ts +6 -7
- package/src/sync/next/facts.ts +7 -9
- package/src/sync/next/history-dag-common.ts +277 -26
- package/src/sync/next/history-dag.ts +16 -10
- package/src/sync/next/rebase-events.ts +11 -11
- package/src/sync/next/test/event-fixtures.ts +11 -11
- package/src/sync/sync-backend-kv.ts +22 -0
- package/src/sync/sync-backend.ts +185 -0
- package/src/sync/sync.ts +9 -91
- package/src/sync/syncstate.test.ts +96 -52
- package/src/sync/syncstate.ts +69 -58
- package/src/sync/transport-chunking.ts +90 -0
- package/src/sync/validate-push-payload.ts +8 -9
- package/src/testing/event-factory.ts +131 -0
- package/src/testing/mod.ts +1 -0
- package/src/version.ts +16 -6
- package/dist/schema/EventDef.d.ts +0 -123
- package/dist/schema/EventDef.d.ts.map +0 -1
- package/dist/schema/EventDef.js +0 -46
- package/dist/schema/EventDef.js.map +0 -1
- package/dist/schema/EventSequenceNumber.d.ts +0 -80
- package/dist/schema/EventSequenceNumber.d.ts.map +0 -1
- package/dist/schema/EventSequenceNumber.js +0 -139
- package/dist/schema/EventSequenceNumber.js.map +0 -1
- package/dist/schema/LiveStoreEvent.d.ts.map +0 -1
- package/dist/schema/LiveStoreEvent.js.map +0 -1
- package/dist/schema/state/sqlite/system-tables.d.ts.map +0 -1
- package/dist/schema/state/sqlite/system-tables.js +0 -79
- package/dist/schema/state/sqlite/system-tables.js.map +0 -1
- package/dist/schema-management/migrations.test.d.ts +0 -2
- package/dist/schema-management/migrations.test.d.ts.map +0 -1
- package/dist/schema-management/migrations.test.js +0 -52
- package/dist/schema-management/migrations.test.js.map +0 -1
- package/dist/sync/next/graphology.d.ts +0 -8
- package/dist/sync/next/graphology.d.ts.map +0 -1
- package/dist/sync/next/graphology.js +0 -30
- package/dist/sync/next/graphology.js.map +0 -1
- package/dist/sync/next/graphology_.d.ts +0 -3
- package/dist/sync/next/graphology_.d.ts.map +0 -1
- package/dist/sync/next/graphology_.js +0 -3
- package/dist/sync/next/graphology_.js.map +0 -1
- package/src/schema/EventDef.ts +0 -219
- package/src/schema/EventSequenceNumber.ts +0 -199
- package/src/schema/LiveStoreEvent.ts +0 -287
- package/src/schema/state/sqlite/system-tables.ts +0 -104
- package/src/sync/next/ambient.d.ts +0 -3
- package/src/sync/next/graphology.ts +0 -41
- package/src/sync/next/graphology_.ts +0 -2
package/src/sync/syncstate.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { casesHandled, LS_DEV, shouldNeverHappen } from '@livestore/utils'
|
|
2
2
|
import { Match, ReadonlyArray, Schema } from '@livestore/utils/effect'
|
|
3
3
|
|
|
4
|
-
import * as EventSequenceNumber from '../schema/EventSequenceNumber.ts'
|
|
5
|
-
import * as LiveStoreEvent from '../schema/LiveStoreEvent.ts'
|
|
4
|
+
import * as EventSequenceNumber from '../schema/EventSequenceNumber/mod.ts'
|
|
5
|
+
import * as LiveStoreEvent from '../schema/LiveStoreEvent/mod.ts'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* SyncState represents the current sync state of a sync node relative to an upstream node.
|
|
@@ -15,7 +15,7 @@ import * as LiveStoreEvent from '../schema/LiveStoreEvent.ts'
|
|
|
15
15
|
* +------------------------+
|
|
16
16
|
* ▼ ▼
|
|
17
17
|
* Upstream Head Local Head
|
|
18
|
-
*
|
|
18
|
+
* e1 e1.1, e1.2, e2
|
|
19
19
|
* ```
|
|
20
20
|
*
|
|
21
21
|
* **Pending Events**: Events awaiting acknowledgment from the upstream.
|
|
@@ -31,7 +31,7 @@ import * as LiveStoreEvent from '../schema/LiveStoreEvent.ts'
|
|
|
31
31
|
* Invariants:
|
|
32
32
|
* 1. **Chain Continuity**: Each event must reference its immediate parent.
|
|
33
33
|
* 2. **Head Ordering**: Upstream Head ≤ Local Head.
|
|
34
|
-
* 3. **Event number sequence**: Must follow the pattern
|
|
34
|
+
* 3. **Event number sequence**: Must follow the pattern e1→e1.1→e1.2→e2.
|
|
35
35
|
*
|
|
36
36
|
* A few further notes to help form an intuition:
|
|
37
37
|
* - The goal is to keep the pending events as small as possible (i.e. to have synced with the next upstream node)
|
|
@@ -42,16 +42,16 @@ import * as LiveStoreEvent from '../schema/LiveStoreEvent.ts'
|
|
|
42
42
|
* handling cases such as upstream rebase, advance and local push.
|
|
43
43
|
*/
|
|
44
44
|
export class SyncState extends Schema.Class<SyncState>('SyncState')({
|
|
45
|
-
pending: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
|
45
|
+
pending: Schema.Array(LiveStoreEvent.Client.EncodedWithMeta),
|
|
46
46
|
/** What this node expects the next upstream node to have as its own local head */
|
|
47
|
-
upstreamHead: EventSequenceNumber.
|
|
47
|
+
upstreamHead: EventSequenceNumber.Client.Composite,
|
|
48
48
|
/** Equivalent to `pending.at(-1)?.id` if there are pending events */
|
|
49
|
-
localHead: EventSequenceNumber.
|
|
49
|
+
localHead: EventSequenceNumber.Client.Composite,
|
|
50
50
|
}) {
|
|
51
51
|
toJSON = (): any => ({
|
|
52
52
|
pending: this.pending.map((e) => e.toJSON()),
|
|
53
|
-
upstreamHead: EventSequenceNumber.toString(this.upstreamHead),
|
|
54
|
-
localHead: EventSequenceNumber.toString(this.localHead),
|
|
53
|
+
upstreamHead: EventSequenceNumber.Client.toString(this.upstreamHead),
|
|
54
|
+
localHead: EventSequenceNumber.Client.toString(this.localHead),
|
|
55
55
|
})
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -60,17 +60,17 @@ export class SyncState extends Schema.Class<SyncState>('SyncState')({
|
|
|
60
60
|
*/
|
|
61
61
|
export class PayloadUpstreamRebase extends Schema.TaggedStruct('upstream-rebase', {
|
|
62
62
|
/** Events which need to be rolled back */
|
|
63
|
-
rollbackEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
|
63
|
+
rollbackEvents: Schema.Array(LiveStoreEvent.Client.EncodedWithMeta),
|
|
64
64
|
/** Events which need to be applied after the rollback (already rebased by the upstream node) */
|
|
65
|
-
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
|
65
|
+
newEvents: Schema.Array(LiveStoreEvent.Client.EncodedWithMeta),
|
|
66
66
|
}) {}
|
|
67
67
|
|
|
68
68
|
export class PayloadUpstreamAdvance extends Schema.TaggedStruct('upstream-advance', {
|
|
69
|
-
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
|
69
|
+
newEvents: Schema.Array(LiveStoreEvent.Client.EncodedWithMeta),
|
|
70
70
|
}) {}
|
|
71
71
|
|
|
72
72
|
export class PayloadLocalPush extends Schema.TaggedStruct('local-push', {
|
|
73
|
-
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
|
73
|
+
newEvents: Schema.Array(LiveStoreEvent.Client.EncodedWithMeta),
|
|
74
74
|
}) {}
|
|
75
75
|
|
|
76
76
|
export class Payload extends Schema.Union(PayloadUpstreamRebase, PayloadUpstreamAdvance, PayloadLocalPush) {}
|
|
@@ -109,9 +109,9 @@ export class MergeContext extends Schema.Class<MergeContext>('MergeContext')({
|
|
|
109
109
|
export class MergeResultAdvance extends Schema.Class<MergeResultAdvance>('MergeResultAdvance')({
|
|
110
110
|
_tag: Schema.Literal('advance'),
|
|
111
111
|
newSyncState: SyncState,
|
|
112
|
-
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
|
112
|
+
newEvents: Schema.Array(LiveStoreEvent.Client.EncodedWithMeta),
|
|
113
113
|
/** Events which were previously pending but are now confirmed */
|
|
114
|
-
confirmedEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
|
114
|
+
confirmedEvents: Schema.Array(LiveStoreEvent.Client.EncodedWithMeta),
|
|
115
115
|
mergeContext: MergeContext,
|
|
116
116
|
}) {
|
|
117
117
|
toJSON = (): any => {
|
|
@@ -128,9 +128,9 @@ export class MergeResultAdvance extends Schema.Class<MergeResultAdvance>('MergeR
|
|
|
128
128
|
export class MergeResultRebase extends Schema.Class<MergeResultRebase>('MergeResultRebase')({
|
|
129
129
|
_tag: Schema.Literal('rebase'),
|
|
130
130
|
newSyncState: SyncState,
|
|
131
|
-
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
|
131
|
+
newEvents: Schema.Array(LiveStoreEvent.Client.EncodedWithMeta),
|
|
132
132
|
/** Events which need to be rolled back */
|
|
133
|
-
rollbackEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
|
133
|
+
rollbackEvents: Schema.Array(LiveStoreEvent.Client.EncodedWithMeta),
|
|
134
134
|
mergeContext: MergeContext,
|
|
135
135
|
}) {
|
|
136
136
|
toJSON = (): any => {
|
|
@@ -147,20 +147,20 @@ export class MergeResultRebase extends Schema.Class<MergeResultRebase>('MergeRes
|
|
|
147
147
|
export class MergeResultReject extends Schema.Class<MergeResultReject>('MergeResultReject')({
|
|
148
148
|
_tag: Schema.Literal('reject'),
|
|
149
149
|
/** The minimum id that the new events must have */
|
|
150
|
-
expectedMinimumId: EventSequenceNumber.
|
|
150
|
+
expectedMinimumId: EventSequenceNumber.Client.Composite,
|
|
151
151
|
mergeContext: MergeContext,
|
|
152
152
|
}) {
|
|
153
153
|
toJSON = (): any => {
|
|
154
154
|
return {
|
|
155
155
|
_tag: this._tag,
|
|
156
|
-
expectedMinimumId: EventSequenceNumber.toString(this.expectedMinimumId),
|
|
156
|
+
expectedMinimumId: EventSequenceNumber.Client.toString(this.expectedMinimumId),
|
|
157
157
|
mergeContext: this.mergeContext.toJSON(),
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
export class
|
|
163
|
-
_tag: Schema.Literal('
|
|
162
|
+
export class MergeResultUnknownError extends Schema.Class<MergeResultUnknownError>('MergeResultUnknownError')({
|
|
163
|
+
_tag: Schema.Literal('unknown-error'),
|
|
164
164
|
message: Schema.String,
|
|
165
165
|
}) {}
|
|
166
166
|
|
|
@@ -168,7 +168,7 @@ export class MergeResult extends Schema.Union(
|
|
|
168
168
|
MergeResultAdvance,
|
|
169
169
|
MergeResultRebase,
|
|
170
170
|
MergeResultReject,
|
|
171
|
-
|
|
171
|
+
MergeResultUnknownError,
|
|
172
172
|
) {}
|
|
173
173
|
|
|
174
174
|
export const payloadFromMergeResult = (
|
|
@@ -187,13 +187,13 @@ export const payloadFromMergeResult = (
|
|
|
187
187
|
Match.exhaustive,
|
|
188
188
|
)
|
|
189
189
|
|
|
190
|
-
const
|
|
190
|
+
const unknownError = (message: string): MergeResultUnknownError => {
|
|
191
191
|
if (LS_DEV) {
|
|
192
192
|
// biome-ignore lint/suspicious/noDebugger: debug
|
|
193
193
|
debugger
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
return
|
|
196
|
+
return MergeResultUnknownError.make({ _tag: 'unknown-error', message })
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
// TODO Idea: call merge recursively through hierarchy levels
|
|
@@ -212,8 +212,8 @@ export const merge = ({
|
|
|
212
212
|
}: {
|
|
213
213
|
syncState: SyncState
|
|
214
214
|
payload: typeof Payload.Type
|
|
215
|
-
isClientEvent: (event: LiveStoreEvent.EncodedWithMeta) => boolean
|
|
216
|
-
isEqualEvent: (a: LiveStoreEvent.EncodedWithMeta, b: LiveStoreEvent.EncodedWithMeta) => boolean
|
|
215
|
+
isClientEvent: (event: LiveStoreEvent.Client.EncodedWithMeta) => boolean
|
|
216
|
+
isEqualEvent: (a: LiveStoreEvent.Client.EncodedWithMeta, b: LiveStoreEvent.Client.EncodedWithMeta) => boolean
|
|
217
217
|
/** This is used in the leader which should ignore client events when receiving an upstream-advance payload */
|
|
218
218
|
ignoreClientEvents?: boolean
|
|
219
219
|
}): typeof MergeResult.Type => {
|
|
@@ -271,20 +271,20 @@ export const merge = ({
|
|
|
271
271
|
|
|
272
272
|
// Validate that newEvents are sorted in ascending order by eventNum
|
|
273
273
|
for (let i = 1; i < payload.newEvents.length; i++) {
|
|
274
|
-
if (EventSequenceNumber.isGreaterThan(payload.newEvents[i - 1]!.seqNum, payload.newEvents[i]!.seqNum)) {
|
|
275
|
-
return
|
|
276
|
-
`Events must be sorted in ascending order by event number. Received: [${payload.newEvents.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`,
|
|
274
|
+
if (EventSequenceNumber.Client.isGreaterThan(payload.newEvents[i - 1]!.seqNum, payload.newEvents[i]!.seqNum)) {
|
|
275
|
+
return unknownError(
|
|
276
|
+
`Events must be sorted in ascending order by event number. Received: [${payload.newEvents.map((e) => EventSequenceNumber.Client.toString(e.seqNum)).join(', ')}]`,
|
|
277
277
|
)
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
// Validate that incoming events are larger than upstream head
|
|
282
282
|
if (
|
|
283
|
-
EventSequenceNumber.isGreaterThan(syncState.upstreamHead, payload.newEvents[0]!.seqNum) ||
|
|
284
|
-
EventSequenceNumber.isEqual(syncState.upstreamHead, payload.newEvents[0]!.seqNum)
|
|
283
|
+
EventSequenceNumber.Client.isGreaterThan(syncState.upstreamHead, payload.newEvents[0]!.seqNum) ||
|
|
284
|
+
EventSequenceNumber.Client.isEqual(syncState.upstreamHead, payload.newEvents[0]!.seqNum)
|
|
285
285
|
) {
|
|
286
|
-
return
|
|
287
|
-
`Incoming events must be greater than upstream head. Expected greater than: ${EventSequenceNumber.toString(syncState.upstreamHead)}. Received: [${payload.newEvents.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`,
|
|
286
|
+
return unknownError(
|
|
287
|
+
`Incoming events must be greater than upstream head. Expected greater than: ${EventSequenceNumber.Client.toString(syncState.upstreamHead)}. Received: [${payload.newEvents.map((e) => EventSequenceNumber.Client.toString(e.seqNum)).join(', ')}]`,
|
|
288
288
|
)
|
|
289
289
|
}
|
|
290
290
|
|
|
@@ -336,7 +336,7 @@ export const merge = ({
|
|
|
336
336
|
pending: pendingRemaining,
|
|
337
337
|
upstreamHead: newUpstreamHead,
|
|
338
338
|
localHead:
|
|
339
|
-
pendingRemaining.at(-1)?.seqNum ?? EventSequenceNumber.max(syncState.localHead, newUpstreamHead),
|
|
339
|
+
pendingRemaining.at(-1)?.seqNum ?? EventSequenceNumber.Client.max(syncState.localHead, newUpstreamHead),
|
|
340
340
|
}),
|
|
341
341
|
newEvents,
|
|
342
342
|
confirmedEvents: pendingMatching,
|
|
@@ -392,10 +392,10 @@ export const merge = ({
|
|
|
392
392
|
|
|
393
393
|
const newEventsFirst = payload.newEvents.at(0)!
|
|
394
394
|
const invalidEventSequenceNumber =
|
|
395
|
-
EventSequenceNumber.isGreaterThan(newEventsFirst.seqNum, syncState.localHead) === false
|
|
395
|
+
EventSequenceNumber.Client.isGreaterThan(newEventsFirst.seqNum, syncState.localHead) === false
|
|
396
396
|
|
|
397
397
|
if (invalidEventSequenceNumber) {
|
|
398
|
-
const expectedMinimumId = EventSequenceNumber.nextPair({
|
|
398
|
+
const expectedMinimumId = EventSequenceNumber.Client.nextPair({
|
|
399
399
|
seqNum: syncState.localHead,
|
|
400
400
|
isClient: true,
|
|
401
401
|
}).seqNum
|
|
@@ -407,13 +407,20 @@ export const merge = ({
|
|
|
407
407
|
}),
|
|
408
408
|
)
|
|
409
409
|
} else {
|
|
410
|
+
const nonClientEvents = ignoreClientEvents
|
|
411
|
+
? payload.newEvents.filter((event) => !isClientEvent(event))
|
|
412
|
+
: payload.newEvents
|
|
413
|
+
const newPending = [...syncState.pending, ...nonClientEvents]
|
|
414
|
+
const newLocalHead =
|
|
415
|
+
newPending.at(-1)?.seqNum ?? EventSequenceNumber.Client.max(syncState.localHead, syncState.upstreamHead)
|
|
416
|
+
|
|
410
417
|
return validateMergeResult(
|
|
411
418
|
MergeResultAdvance.make({
|
|
412
419
|
_tag: 'advance',
|
|
413
420
|
newSyncState: new SyncState({
|
|
414
|
-
pending:
|
|
421
|
+
pending: newPending,
|
|
415
422
|
upstreamHead: syncState.upstreamHead,
|
|
416
|
-
localHead:
|
|
423
|
+
localHead: newLocalHead,
|
|
417
424
|
}),
|
|
418
425
|
newEvents: payload.newEvents,
|
|
419
426
|
confirmedEvents: [],
|
|
@@ -440,10 +447,10 @@ export const findDivergencePoint = ({
|
|
|
440
447
|
isClientEvent,
|
|
441
448
|
ignoreClientEvents,
|
|
442
449
|
}: {
|
|
443
|
-
existingEvents: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>
|
|
444
|
-
incomingEvents: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>
|
|
445
|
-
isEqualEvent: (a: LiveStoreEvent.EncodedWithMeta, b: LiveStoreEvent.EncodedWithMeta) => boolean
|
|
446
|
-
isClientEvent: (event: LiveStoreEvent.EncodedWithMeta) => boolean
|
|
450
|
+
existingEvents: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>
|
|
451
|
+
incomingEvents: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>
|
|
452
|
+
isEqualEvent: (a: LiveStoreEvent.Client.EncodedWithMeta, b: LiveStoreEvent.Client.EncodedWithMeta) => boolean
|
|
453
|
+
isClientEvent: (event: LiveStoreEvent.Client.EncodedWithMeta) => boolean
|
|
447
454
|
ignoreClientEvents: boolean
|
|
448
455
|
}): number => {
|
|
449
456
|
if (ignoreClientEvents) {
|
|
@@ -461,7 +468,7 @@ export const findDivergencePoint = ({
|
|
|
461
468
|
const divergencePointEventSequenceNumber = existingEvents[divergencePointWithoutClientEvents]!.seqNum
|
|
462
469
|
// Now find the divergence point in the original array
|
|
463
470
|
return existingEvents.findIndex((event) =>
|
|
464
|
-
EventSequenceNumber.isEqual(event.seqNum, divergencePointEventSequenceNumber),
|
|
471
|
+
EventSequenceNumber.Client.isEqual(event.seqNum, divergencePointEventSequenceNumber),
|
|
465
472
|
)
|
|
466
473
|
}
|
|
467
474
|
|
|
@@ -477,10 +484,10 @@ const rebaseEvents = ({
|
|
|
477
484
|
baseEventSequenceNumber,
|
|
478
485
|
isClientEvent,
|
|
479
486
|
}: {
|
|
480
|
-
events: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>
|
|
481
|
-
baseEventSequenceNumber: EventSequenceNumber.
|
|
482
|
-
isClientEvent: (event: LiveStoreEvent.EncodedWithMeta) => boolean
|
|
483
|
-
}): ReadonlyArray<LiveStoreEvent.EncodedWithMeta> => {
|
|
487
|
+
events: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>
|
|
488
|
+
baseEventSequenceNumber: EventSequenceNumber.Client.Composite
|
|
489
|
+
isClientEvent: (event: LiveStoreEvent.Client.EncodedWithMeta) => boolean
|
|
490
|
+
}): ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta> => {
|
|
484
491
|
let prevEventSequenceNumber = baseEventSequenceNumber
|
|
485
492
|
const rebaseGeneration = baseEventSequenceNumber.rebaseGeneration + 1
|
|
486
493
|
return events.map((event) => {
|
|
@@ -506,9 +513,11 @@ const _flattenMergeResults = (_updateResults: ReadonlyArray<MergeResult>) => {}
|
|
|
506
513
|
|
|
507
514
|
const validatePayload = (payload: typeof Payload.Type) => {
|
|
508
515
|
for (let i = 1; i < payload.newEvents.length; i++) {
|
|
509
|
-
if (
|
|
510
|
-
|
|
511
|
-
|
|
516
|
+
if (
|
|
517
|
+
EventSequenceNumber.Client.isGreaterThanOrEqual(payload.newEvents[i - 1]!.seqNum, payload.newEvents[i]!.seqNum)
|
|
518
|
+
) {
|
|
519
|
+
return unknownError(
|
|
520
|
+
`Events must be ordered in monotonically ascending order by eventNum. Received: [${payload.newEvents.map((e) => EventSequenceNumber.Client.toString(e.seqNum)).join(', ')}]`,
|
|
512
521
|
)
|
|
513
522
|
}
|
|
514
523
|
}
|
|
@@ -520,9 +529,9 @@ const validateSyncState = (syncState: SyncState) => {
|
|
|
520
529
|
const nextEvent = syncState.pending[i + 1]
|
|
521
530
|
if (nextEvent === undefined) break // Reached end of chain
|
|
522
531
|
|
|
523
|
-
if (EventSequenceNumber.isGreaterThanOrEqual(event.seqNum, nextEvent.seqNum)) {
|
|
532
|
+
if (EventSequenceNumber.Client.isGreaterThanOrEqual(event.seqNum, nextEvent.seqNum)) {
|
|
524
533
|
shouldNeverHappen(
|
|
525
|
-
`Events must be ordered in monotonically ascending order by eventNum. Received: [${syncState.pending.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`,
|
|
534
|
+
`Events must be ordered in monotonically ascending order by eventNum. Received: [${syncState.pending.map((e) => EventSequenceNumber.Client.toString(e.seqNum)).join(', ')}]`,
|
|
526
535
|
{
|
|
527
536
|
event,
|
|
528
537
|
nextEvent,
|
|
@@ -535,7 +544,7 @@ const validateSyncState = (syncState: SyncState) => {
|
|
|
535
544
|
if (globalIdHasIncreased) {
|
|
536
545
|
if (nextEvent.seqNum.client !== 0) {
|
|
537
546
|
shouldNeverHappen(
|
|
538
|
-
`New global events must point to clientId 0 in the parentSeqNum. Received: (${EventSequenceNumber.toString(nextEvent.seqNum)})`,
|
|
547
|
+
`New global events must point to clientId 0 in the parentSeqNum. Received: (${EventSequenceNumber.Client.toString(nextEvent.seqNum)})`,
|
|
539
548
|
syncState.pending,
|
|
540
549
|
{
|
|
541
550
|
event,
|
|
@@ -545,7 +554,7 @@ const validateSyncState = (syncState: SyncState) => {
|
|
|
545
554
|
}
|
|
546
555
|
} else {
|
|
547
556
|
// Otherwise, the parentSeqNum must be the same as the previous event's id
|
|
548
|
-
if (EventSequenceNumber.isEqual(nextEvent.parentSeqNum, event.seqNum) === false) {
|
|
557
|
+
if (EventSequenceNumber.Client.isEqual(nextEvent.parentSeqNum, event.seqNum) === false) {
|
|
549
558
|
shouldNeverHappen('Events must be linked in a continuous chain via the parentSeqNum', syncState.pending, {
|
|
550
559
|
event,
|
|
551
560
|
nextEvent,
|
|
@@ -556,12 +565,14 @@ const validateSyncState = (syncState: SyncState) => {
|
|
|
556
565
|
}
|
|
557
566
|
|
|
558
567
|
const validateMergeResult = (mergeResult: typeof MergeResult.Type) => {
|
|
559
|
-
if (mergeResult._tag === '
|
|
568
|
+
if (mergeResult._tag === 'unknown-error' || mergeResult._tag === 'reject') return mergeResult
|
|
560
569
|
|
|
561
570
|
validateSyncState(mergeResult.newSyncState)
|
|
562
571
|
|
|
563
572
|
// Ensure local head is always greater than or equal to upstream head
|
|
564
|
-
if (
|
|
573
|
+
if (
|
|
574
|
+
EventSequenceNumber.Client.isGreaterThan(mergeResult.newSyncState.upstreamHead, mergeResult.newSyncState.localHead)
|
|
575
|
+
) {
|
|
565
576
|
shouldNeverHappen('Local head must be greater than or equal to upstream head', {
|
|
566
577
|
localHead: mergeResult.newSyncState.localHead,
|
|
567
578
|
upstreamHead: mergeResult.newSyncState.upstreamHead,
|
|
@@ -570,7 +581,7 @@ const validateMergeResult = (mergeResult: typeof MergeResult.Type) => {
|
|
|
570
581
|
|
|
571
582
|
// Ensure new local head is greater than or equal to the previous local head
|
|
572
583
|
if (
|
|
573
|
-
EventSequenceNumber.isGreaterThanOrEqual(
|
|
584
|
+
EventSequenceNumber.Client.isGreaterThanOrEqual(
|
|
574
585
|
mergeResult.newSyncState.localHead,
|
|
575
586
|
mergeResult.mergeContext.syncState.localHead,
|
|
576
587
|
) === false
|
|
@@ -583,7 +594,7 @@ const validateMergeResult = (mergeResult: typeof MergeResult.Type) => {
|
|
|
583
594
|
|
|
584
595
|
// Ensure new upstream head is greater than or equal to the previous upstream head
|
|
585
596
|
if (
|
|
586
|
-
EventSequenceNumber.isGreaterThanOrEqual(
|
|
597
|
+
EventSequenceNumber.Client.isGreaterThanOrEqual(
|
|
587
598
|
mergeResult.newSyncState.upstreamHead,
|
|
588
599
|
mergeResult.mergeContext.syncState.upstreamHead,
|
|
589
600
|
) === false
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Chunk, Effect, Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
const textEncoder = new TextEncoder()
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Configuration describing how to break a chunk into smaller payload-safe chunks.
|
|
7
|
+
*/
|
|
8
|
+
export interface ChunkingOptions<A> {
|
|
9
|
+
/** Maximum number of items that may appear in any emitted chunk. */
|
|
10
|
+
readonly maxItems: number
|
|
11
|
+
/** Maximum encoded byte size allowed for any emitted chunk. */
|
|
12
|
+
readonly maxBytes: number
|
|
13
|
+
/**
|
|
14
|
+
* Callback that produces a JSON-serialisable structure whose byte size should
|
|
15
|
+
* fit within {@link maxBytes}. This lets callers control framing overhead.
|
|
16
|
+
*/
|
|
17
|
+
readonly encode: (items: ReadonlyArray<A>) => unknown
|
|
18
|
+
/**
|
|
19
|
+
* Optional custom measurement function. When provided it overrides the
|
|
20
|
+
* default {@link JSON.stringify}-based measurement logic.
|
|
21
|
+
*/
|
|
22
|
+
readonly measure?: (items: ReadonlyArray<A>) => number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Derives a function that splits an input chunk into sub-chunks confined by
|
|
27
|
+
* both item count and encoded byte size limits. Designed for transports with
|
|
28
|
+
* strict frame caps (e.g. Cloudflare hibernated WebSockets).
|
|
29
|
+
*/
|
|
30
|
+
export class OversizeChunkItemError extends Schema.TaggedError<OversizeChunkItemError>()('OversizeChunkItemError', {
|
|
31
|
+
size: Schema.Number,
|
|
32
|
+
maxBytes: Schema.Number,
|
|
33
|
+
}) {}
|
|
34
|
+
|
|
35
|
+
export const splitChunkBySize =
|
|
36
|
+
<A>(options: ChunkingOptions<A>) =>
|
|
37
|
+
(chunk: Chunk.Chunk<A>): Effect.Effect<Chunk.Chunk<Chunk.Chunk<A>>, OversizeChunkItemError> =>
|
|
38
|
+
Effect.gen(function* () {
|
|
39
|
+
const maxItems = Math.max(1, options.maxItems)
|
|
40
|
+
const maxBytes = Math.max(1, options.maxBytes)
|
|
41
|
+
const encode = options.encode
|
|
42
|
+
const measure = options.measure
|
|
43
|
+
|
|
44
|
+
const computeSize = (items: ReadonlyArray<A>) => {
|
|
45
|
+
if (measure !== undefined) {
|
|
46
|
+
return measure(items)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const encoded = encode(items)
|
|
50
|
+
return textEncoder.encode(JSON.stringify(encoded)).byteLength
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const items = Chunk.toReadonlyArray(chunk)
|
|
54
|
+
if (items.length === 0) {
|
|
55
|
+
return Chunk.fromIterable<Chunk.Chunk<A>>([])
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const result: Array<Chunk.Chunk<A>> = []
|
|
59
|
+
let current: Array<A> = []
|
|
60
|
+
|
|
61
|
+
const flushCurrent = () => {
|
|
62
|
+
if (current.length > 0) {
|
|
63
|
+
result.push(Chunk.fromIterable(current))
|
|
64
|
+
current = []
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (const item of items) {
|
|
69
|
+
current.push(item)
|
|
70
|
+
const exceedsLimit = current.length > maxItems || computeSize(current) > maxBytes
|
|
71
|
+
|
|
72
|
+
if (exceedsLimit) {
|
|
73
|
+
// remove the item we just added and emit the previous chunk if it exists
|
|
74
|
+
const last = current.pop()!
|
|
75
|
+
flushCurrent()
|
|
76
|
+
|
|
77
|
+
if (last !== undefined) {
|
|
78
|
+
current = [last]
|
|
79
|
+
const singleItemTooLarge = computeSize(current) > maxBytes
|
|
80
|
+
if (singleItemTooLarge || current.length > maxItems) {
|
|
81
|
+
return yield* new OversizeChunkItemError({ size: computeSize([last]), maxBytes })
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
flushCurrent()
|
|
88
|
+
|
|
89
|
+
return Chunk.fromIterable(result)
|
|
90
|
+
})
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { Effect } from '@livestore/utils/effect'
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import { InvalidPushError } from './sync.ts'
|
|
3
|
+
import { EventSequenceNumber, type LiveStoreEvent } from '../schema/mod.ts'
|
|
4
|
+
import { InvalidPushError, ServerAheadError } from './sync.ts'
|
|
5
5
|
|
|
6
6
|
// TODO proper batch validation
|
|
7
7
|
export const validatePushPayload = (
|
|
8
|
-
batch: ReadonlyArray<LiveStoreEvent.
|
|
9
|
-
currentEventSequenceNumber: EventSequenceNumber.
|
|
8
|
+
batch: ReadonlyArray<LiveStoreEvent.Global.Encoded>,
|
|
9
|
+
currentEventSequenceNumber: EventSequenceNumber.Global.Type,
|
|
10
10
|
) =>
|
|
11
11
|
Effect.gen(function* () {
|
|
12
12
|
if (batch[0]!.seqNum <= currentEventSequenceNumber) {
|
|
13
13
|
return yield* InvalidPushError.make({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
14
|
+
cause: new ServerAheadError({
|
|
15
|
+
minimumExpectedNum: EventSequenceNumber.Global.make(currentEventSequenceNumber + 1),
|
|
16
|
+
providedNum: EventSequenceNumber.Global.make(batch[0]!.seqNum),
|
|
17
|
+
}),
|
|
19
18
|
})
|
|
20
19
|
}
|
|
21
20
|
})
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for synthesizing LiveStore events in tests while keeping track of
|
|
3
|
+
* sequence numbers, parent pointers, and authoring client identity. Inspired
|
|
4
|
+
* by the effect-based schema utilities, the factory exposes a namespaced API
|
|
5
|
+
* where each event definition maps to a helper with `next`, `advanceTo`, and
|
|
6
|
+
* `setParent` functions that share a single sequence stream.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { EventFactory } from '@livestore/common/testing'
|
|
11
|
+
* import { events } from './schema'
|
|
12
|
+
*
|
|
13
|
+
* const eventFactory = EventFactory.makeFactory(events)({
|
|
14
|
+
* client: EventFactory.clientIdentity('test-client'),
|
|
15
|
+
* startSeq: 1,
|
|
16
|
+
* initialParent: 'root',
|
|
17
|
+
* })
|
|
18
|
+
*
|
|
19
|
+
* const bootstrap = eventFactory.todoCreated.next({
|
|
20
|
+
* id: 'todo-1',
|
|
21
|
+
* text: 'write tests',
|
|
22
|
+
* completed: false,
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* eventFactory.todoCreated.advanceTo(42)
|
|
26
|
+
* const branched = eventFactory.todoUpdated.next({
|
|
27
|
+
* id: 'todo-1',
|
|
28
|
+
* text: 'ship feature',
|
|
29
|
+
* completed: true,
|
|
30
|
+
* })
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { Schema } from '@livestore/utils/effect'
|
|
35
|
+
|
|
36
|
+
import type { EventDef } from '../schema/EventDef/mod.ts'
|
|
37
|
+
import * as EventSequenceNumber from '../schema/EventSequenceNumber/mod.ts'
|
|
38
|
+
import * as LiveStoreEvent from '../schema/LiveStoreEvent/mod.ts'
|
|
39
|
+
|
|
40
|
+
export interface ClientIdentity {
|
|
41
|
+
clientId: string
|
|
42
|
+
sessionId: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const clientIdentity = (label: string, session = `${label}-session`): ClientIdentity => ({
|
|
46
|
+
clientId: label,
|
|
47
|
+
sessionId: session,
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
export type SequenceValue = 'root' | number
|
|
51
|
+
|
|
52
|
+
type EventFactoriesArgs<TDefs extends Record<string, EventDef.Any>> = {
|
|
53
|
+
[K in keyof TDefs]: Parameters<TDefs[K]>[0]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
type EventFactories<TDefs extends Record<string, EventDef.Any>, TResult> = {
|
|
57
|
+
[K in keyof TDefs]: {
|
|
58
|
+
next: (args: EventFactoriesArgs<TDefs>[K]) => TResult
|
|
59
|
+
advanceTo: (seq: number, parent?: SequenceValue) => void
|
|
60
|
+
setParent: (parent: SequenceValue) => void
|
|
61
|
+
current: () => { seq: number; parent: SequenceValue }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface EventFactoriesConfig {
|
|
66
|
+
client: ClientIdentity
|
|
67
|
+
/**
|
|
68
|
+
* @default 1
|
|
69
|
+
*/
|
|
70
|
+
startSeq?: number
|
|
71
|
+
/**
|
|
72
|
+
* @default 0 (root)
|
|
73
|
+
*/
|
|
74
|
+
initialParent?: SequenceValue
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const makeFactory =
|
|
78
|
+
<TDefs extends Record<string, EventDef.Any>>(eventDefs: TDefs) =>
|
|
79
|
+
({
|
|
80
|
+
client,
|
|
81
|
+
startSeq = 1,
|
|
82
|
+
initialParent = 'root',
|
|
83
|
+
}: EventFactoriesConfig): EventFactories<TDefs, LiveStoreEvent.Global.Encoded> => {
|
|
84
|
+
let nextSeq = startSeq
|
|
85
|
+
let parentRef: SequenceValue = initialParent
|
|
86
|
+
|
|
87
|
+
const advanceTo = (seq: number, parent: SequenceValue = 'root') => {
|
|
88
|
+
nextSeq = seq
|
|
89
|
+
parentRef = parent
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const setParent = (parent: SequenceValue) => {
|
|
93
|
+
parentRef = parent
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const current = () => ({ seq: nextSeq, parent: parentRef })
|
|
97
|
+
|
|
98
|
+
const factories: Partial<EventFactories<TDefs, LiveStoreEvent.Global.Encoded>> = {}
|
|
99
|
+
|
|
100
|
+
for (const [name, eventDef] of Object.entries(eventDefs) as [keyof TDefs, TDefs[keyof TDefs]][]) {
|
|
101
|
+
const next = (args: EventFactoriesArgs<TDefs>[typeof name]) => {
|
|
102
|
+
const decoded = eventDef(args)
|
|
103
|
+
const encodedArgs = Schema.encodeSync(eventDef.schema)(decoded.args)
|
|
104
|
+
const encoded = eventDef.encoded(encodedArgs)
|
|
105
|
+
|
|
106
|
+
const event = LiveStoreEvent.Global.Encoded.make({
|
|
107
|
+
name: encoded.name,
|
|
108
|
+
args: encoded.args,
|
|
109
|
+
seqNum: EventSequenceNumber.Global.make(nextSeq),
|
|
110
|
+
parentSeqNum:
|
|
111
|
+
parentRef === 'root' ? EventSequenceNumber.Client.ROOT.global : EventSequenceNumber.Global.make(parentRef),
|
|
112
|
+
clientId: client.clientId,
|
|
113
|
+
sessionId: client.sessionId,
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
parentRef = nextSeq
|
|
117
|
+
nextSeq = nextSeq + 1
|
|
118
|
+
|
|
119
|
+
return event
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
factories[name] = {
|
|
123
|
+
next,
|
|
124
|
+
advanceTo,
|
|
125
|
+
setParent,
|
|
126
|
+
current,
|
|
127
|
+
} as EventFactories<TDefs, LiveStoreEvent.Global.Encoded>[typeof name]
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return factories as EventFactories<TDefs, LiveStoreEvent.Global.Encoded>
|
|
131
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as EventFactory from './event-factory.ts'
|
package/src/version.ts
CHANGED
|
@@ -2,13 +2,23 @@
|
|
|
2
2
|
// import packageJson from '../package.json' with { type: 'json' }
|
|
3
3
|
// export const liveStoreVersion = packageJson.version
|
|
4
4
|
|
|
5
|
-
export const liveStoreVersion = '0.4.0-dev.
|
|
5
|
+
export const liveStoreVersion = '0.4.0-dev.21' as const
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
* Whenever this version changes, LiveStore will start with fresh database files. Old database files are not deleted.
|
|
8
|
+
* CRITICAL: Increment this version whenever you modify client-side EVENTLOG table schemas.
|
|
10
9
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Used to generate database file names (e.g., `eventlog@6.db`, `state@6.db`) across all client adapters.
|
|
11
|
+
*
|
|
12
|
+
* Bump required when:
|
|
13
|
+
* - Modifying eventlog system tables (eventlogMetaTable, syncStatusTable) in schema/state/sqlite/system-tables/eventlog-tables.ts
|
|
14
|
+
* - Changing columns, types, constraints, or indexes in eventlog tables
|
|
15
|
+
*
|
|
16
|
+
* Bump NOT required when:
|
|
17
|
+
* - Modifying STATE table schemas (auto-migrated via hash-based detection and rebuilt from eventlog)
|
|
18
|
+
* - Changing query patterns or client-side implementation details
|
|
19
|
+
*
|
|
20
|
+
* ⚠️ CRITICAL: Eventlog changes without bumping this version cause permanent data loss!
|
|
21
|
+
*
|
|
22
|
+
* Impact: Version changes trigger a "soft reset" - old data becomes inaccessible but remains on disk.
|
|
13
23
|
*/
|
|
14
|
-
export const liveStoreStorageFormatVersion =
|
|
24
|
+
export const liveStoreStorageFormatVersion = 6
|