@livestore/common 0.4.0-dev.2 → 0.4.0-dev.20
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 +17 -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 +36 -29
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +8 -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 +8 -4
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +156 -73
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts +15 -21
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +18 -18
- 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 +30 -42
- 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/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/types.d.ts +21 -19
- package/dist/leader-thread/types.d.ts.map +1 -1
- 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/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 +46 -7
- 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 +17 -10
- 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 +17 -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 +8 -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 +242 -103
- package/src/leader-thread/eventlog.ts +33 -34
- package/src/leader-thread/leader-worker-devtools.ts +50 -54
- 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/recreate-db.ts +15 -7
- package/src/leader-thread/shutdown-channel.ts +16 -2
- package/src/leader-thread/types.ts +21 -19
- package/src/logging.ts +62 -0
- package/src/make-client-session.ts +9 -3
- package/src/materializer-helper.ts +27 -10
- 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 +120 -8
- 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 +60 -7
- 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 +2 -1
- package/src/schema/state/sqlite/mod.ts +4 -3
- package/src/schema/state/sqlite/query-builder/api.ts +19 -10
- 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 +9 -8
- 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/dist/errors.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import { Effect, Schema, Stream } from '@livestore/utils/effect';
|
|
2
|
-
|
|
1
|
+
import { Cause, Effect, Layer, Schema, Stream } from '@livestore/utils/effect';
|
|
2
|
+
import * as LiveStoreEvent from "./schema/LiveStoreEvent/mod.js";
|
|
3
|
+
export class UnknownError extends Schema.TaggedError()('LiveStore.UnknownError', {
|
|
3
4
|
cause: Schema.Defect,
|
|
4
5
|
note: Schema.optional(Schema.String),
|
|
5
6
|
payload: Schema.optional(Schema.Any),
|
|
6
7
|
}) {
|
|
7
|
-
static
|
|
8
|
-
static
|
|
8
|
+
static mapToUnknownError = (effect) => effect.pipe(Effect.mapError((cause) => (Schema.is(UnknownError)(cause) ? cause : new UnknownError({ cause }))), Effect.catchAllDefect((cause) => new UnknownError({ cause })));
|
|
9
|
+
static mapToUnknownErrorLayer = (layer) => layer.pipe(Layer.catchAllCause((cause) => Cause.isFailType(cause) && Schema.is(UnknownError)(cause.error)
|
|
10
|
+
? Layer.fail(cause.error)
|
|
11
|
+
: Layer.fail(new UnknownError({ cause: cause }))));
|
|
12
|
+
static mapToUnknownErrorStream = (stream) => stream.pipe(Stream.mapError((cause) => (Schema.is(UnknownError)(cause) ? cause : new UnknownError({ cause }))));
|
|
9
13
|
}
|
|
10
|
-
export class
|
|
11
|
-
|
|
14
|
+
export class MaterializerHashMismatchError extends Schema.TaggedError()('LiveStore.MaterializerHashMismatchError', {
|
|
15
|
+
eventName: Schema.String,
|
|
16
|
+
note: Schema.optionalWith(Schema.String, {
|
|
17
|
+
default: () => 'Please make sure your event materializer is a pure function without side effects.',
|
|
18
|
+
}),
|
|
12
19
|
}) {
|
|
13
20
|
}
|
|
14
21
|
export class IntentionalShutdownCause extends Schema.TaggedError()('LiveStore.IntentionalShutdownCause', {
|
|
@@ -33,4 +40,16 @@ export class SqliteError extends Schema.TaggedError()('LiveStore.SqliteError', {
|
|
|
33
40
|
note: Schema.optional(Schema.String),
|
|
34
41
|
}) {
|
|
35
42
|
}
|
|
43
|
+
export class UnknownEventError extends Schema.TaggedError()('LiveStore.UnknownEventError', {
|
|
44
|
+
event: LiveStoreEvent.Client.Encoded.pipe(Schema.pick('name', 'args', 'seqNum', 'clientId', 'sessionId')),
|
|
45
|
+
reason: Schema.Literal('event-definition-missing', 'materializer-missing'),
|
|
46
|
+
operation: Schema.String,
|
|
47
|
+
note: Schema.optional(Schema.String),
|
|
48
|
+
}) {
|
|
49
|
+
}
|
|
50
|
+
export class MaterializeError extends Schema.TaggedError()('LiveStore.MaterializeError', {
|
|
51
|
+
cause: Schema.Union(MaterializerHashMismatchError, SqliteError, UnknownEventError),
|
|
52
|
+
note: Schema.optional(Schema.String),
|
|
53
|
+
}) {
|
|
54
|
+
}
|
|
36
55
|
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhE,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAE9E,OAAO,KAAK,cAAc,MAAM,gCAAgC,CAAA;AAEhE,MAAM,OAAO,YAAa,SAAQ,MAAM,CAAC,WAAW,EAAgB,CAAC,wBAAwB,EAAE;IAC7F,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC;CACrC,CAAC;IACA,MAAM,CAAC,iBAAiB,GAAG,CAAU,MAA8B,EAAE,EAAE,CACrE,MAAM,CAAC,IAAI,CACT,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAClG,MAAM,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAC9D,CAAA;IAEH,MAAM,CAAC,sBAAsB,GAAG,CAAU,KAA2B,EAAE,EAAE,CACvE,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,aAAa,CAAC,CAAC,KAAK,EAAE,EAAE,CAC5B,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;QAC7D,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACzB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CACnD,CACF,CAAA;IAEH,MAAM,CAAC,uBAAuB,GAAG,CAAU,MAA8B,EAAE,EAAE,CAC3E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;;AAGnH,MAAM,OAAO,6BAA8B,SAAQ,MAAM,CAAC,WAAW,EAAiC,CACpG,yCAAyC,EACzC;IACE,SAAS,EAAE,MAAM,CAAC,MAAM;IACxB,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE;QACvC,OAAO,EAAE,GAAG,EAAE,CAAC,mFAAmF;KACnG,CAAC;CACH,CACF;CAAG;AAEJ,MAAM,OAAO,wBAAyB,SAAQ,MAAM,CAAC,WAAW,EAA4B,CAC1F,oCAAoC,EACpC;IACE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAE,QAAQ,CAAC;CACvF,CACF;CAAG;AAEJ,MAAM,OAAO,gBAAiB,SAAQ,MAAM,CAAC,WAAW,EAAoB,CAAC,4BAA4B,EAAE;IACzG,MAAM,EAAE,MAAM,CAAC,MAAM;CACtB,CAAC;CAAG;AAEL,MAAM,OAAO,WAAY,SAAQ,MAAM,CAAC,WAAW,EAAe,CAAC,uBAAuB,EAAE;IAC1F,KAAK,EAAE,MAAM,CAAC,QAAQ,CACpB,MAAM,CAAC,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC,MAAM;QAClB,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KAC7G,CAAC,CACH;IACD,6BAA6B;IAC7B,wCAAwC;IACxC,8FAA8F;IAC9F,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACjE,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;CACrC,CAAC;CAAG;AAEL,MAAM,OAAO,iBAAkB,SAAQ,MAAM,CAAC,WAAW,EAAqB,CAAC,6BAA6B,EAAE;IAC5G,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IACzG,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,0BAA0B,EAAE,sBAAsB,CAAC;IAC1E,SAAS,EAAE,MAAM,CAAC,MAAM;IACxB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;CACrC,CAAC;CAAG;AAEL,MAAM,OAAO,gBAAiB,SAAQ,MAAM,CAAC,WAAW,EAAoB,CAAC,4BAA4B,EAAE;IACzG,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,WAAW,EAAE,iBAAiB,CAAC;IAClF,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;CACrC,CAAC;CAAG"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,12 +2,13 @@ export * from './adapter-types.ts';
|
|
|
2
2
|
export * from './bounded-collections.ts';
|
|
3
3
|
export * from './debug-info.ts';
|
|
4
4
|
export * as Devtools from './devtools/mod.ts';
|
|
5
|
+
export * as LogConfig from './logging.ts';
|
|
5
6
|
export * from './make-client-session.ts';
|
|
6
7
|
export * from './materializer-helper.ts';
|
|
7
8
|
export * from './otel.ts';
|
|
8
9
|
export * from './rematerialize-from-eventlog.ts';
|
|
9
10
|
export * from './schema/state/sqlite/query-builder/mod.ts';
|
|
10
|
-
export * from './schema/state/sqlite/system-tables.ts';
|
|
11
|
+
export * from './schema/state/sqlite/system-tables/mod.ts';
|
|
11
12
|
export * from './schema-management/migrations.ts';
|
|
12
13
|
export * as SqliteDbHelper from './sqlite-db-helper.ts';
|
|
13
14
|
export * from './sync/index.ts';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,WAAW,CAAA;AACzB,cAAc,kCAAkC,CAAA;AAChD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,SAAS,MAAM,cAAc,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,WAAW,CAAA;AACzB,cAAc,kCAAkC,CAAA;AAChD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,4CAA4C,CAAA;AAC1D,cAAc,mCAAmC,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AACvD,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,SAAS,MAAM,qBAAqB,CAAA;AAChD,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -2,12 +2,13 @@ export * from "./adapter-types.js";
|
|
|
2
2
|
export * from "./bounded-collections.js";
|
|
3
3
|
export * from "./debug-info.js";
|
|
4
4
|
export * as Devtools from "./devtools/mod.js";
|
|
5
|
+
export * as LogConfig from "./logging.js";
|
|
5
6
|
export * from "./make-client-session.js";
|
|
6
7
|
export * from "./materializer-helper.js";
|
|
7
8
|
export * from "./otel.js";
|
|
8
9
|
export * from "./rematerialize-from-eventlog.js";
|
|
9
10
|
export * from "./schema/state/sqlite/query-builder/mod.js";
|
|
10
|
-
export * from "./schema/state/sqlite/system-tables.js";
|
|
11
|
+
export * from "./schema/state/sqlite/system-tables/mod.js";
|
|
11
12
|
export * from "./schema-management/migrations.js";
|
|
12
13
|
export * as SqliteDbHelper from "./sqlite-db-helper.js";
|
|
13
14
|
export * from "./sync/index.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,WAAW,CAAA;AACzB,cAAc,kCAAkC,CAAA;AAChD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,SAAS,MAAM,cAAc,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,WAAW,CAAA;AACzB,cAAc,kCAAkC,CAAA;AAChD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,4CAA4C,CAAA;AAC1D,cAAc,mCAAmC,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AACvD,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,SAAS,MAAM,qBAAqB,CAAA;AAChD,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Scope } from '@livestore/utils/effect';
|
|
2
2
|
import { Effect } from '@livestore/utils/effect';
|
|
3
|
-
import type
|
|
4
|
-
import { UnexpectedError } from '../adapter-types.ts';
|
|
3
|
+
import { type SqliteDb, UnknownError } from '../adapter-types.ts';
|
|
5
4
|
import type { LiveStoreSchema } from '../schema/mod.ts';
|
|
6
5
|
import * as SyncState from '../sync/syncstate.ts';
|
|
7
6
|
import type { InitialBlockingSyncContext, LeaderSyncProcessor } from './types.ts';
|
|
@@ -35,7 +34,7 @@ import type { InitialBlockingSyncContext, LeaderSyncProcessor } from './types.ts
|
|
|
35
34
|
*
|
|
36
35
|
* See ClientSessionSyncProcessor for how the leader and session sync processors are similar/different.
|
|
37
36
|
*/
|
|
38
|
-
export declare const makeLeaderSyncProcessor: ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, params, testing, }: {
|
|
37
|
+
export declare const makeLeaderSyncProcessor: ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, livePull, params, testing, }: {
|
|
39
38
|
schema: LiveStoreSchema;
|
|
40
39
|
dbState: SqliteDb;
|
|
41
40
|
initialBlockingSyncContext: InitialBlockingSyncContext;
|
|
@@ -52,10 +51,15 @@ export declare const makeLeaderSyncProcessor: ({ schema, dbState, initialBlockin
|
|
|
52
51
|
*/
|
|
53
52
|
backendPushBatchSize?: number;
|
|
54
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* Whether the sync backend should reactively pull new events from the sync backend
|
|
56
|
+
* When `false`, the sync processor will only do an initial pull
|
|
57
|
+
*/
|
|
58
|
+
livePull: boolean;
|
|
55
59
|
testing: {
|
|
56
60
|
delays?: {
|
|
57
61
|
localPushProcessing?: Effect.Effect<void>;
|
|
58
62
|
};
|
|
59
63
|
};
|
|
60
|
-
}) => Effect.Effect<LeaderSyncProcessor,
|
|
64
|
+
}) => Effect.Effect<LeaderSyncProcessor, UnknownError, Scope.Scope>;
|
|
61
65
|
//# sourceMappingURL=LeaderSyncProcessor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LeaderSyncProcessor.d.ts","sourceRoot":"","sources":["../../src/leader-thread/LeaderSyncProcessor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuB,KAAK,EAAU,MAAM,yBAAyB,CAAA;AACjF,OAAO,
|
|
1
|
+
{"version":3,"file":"LeaderSyncProcessor.d.ts","sourceRoot":"","sources":["../../src/leader-thread/LeaderSyncProcessor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuB,KAAK,EAAU,MAAM,yBAAyB,CAAA;AACjF,OAAO,EAKL,MAAM,EAYP,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAwD,KAAK,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEvH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AASvD,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAIjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAQjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,uBAAuB,GAAI,wGASrC;IACD,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,QAAQ,CAAA;IACjB,0BAA0B,EAAE,0BAA0B,CAAA;IACtD,sFAAsF;IACtF,gBAAgB,EAAE,SAAS,CAAC,SAAS,CAAA;IACrC,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAA;IAC9B,MAAM,EAAE;QACN;;WAEG;QACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B;;WAEG;QACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAC9B,CAAA;IACD;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE;QACP,MAAM,CAAC,EAAE;YACP,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;SAC1C,CAAA;KACF,CAAA;CACF,KAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,YAAY,EAAE,KAAK,CAAC,KAAK,CAuR5D,CAAA"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { casesHandled, isNotUndefined, LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils';
|
|
2
|
-
import { BucketQueue, Deferred, Effect, Exit, FiberHandle, Option, OtelTracer,
|
|
3
|
-
import {
|
|
2
|
+
import { BucketQueue, Cause, Deferred, Duration, Effect, Exit, FiberHandle, Layer, Option, OtelTracer, Queue, ReadonlyArray, Schedule, Stream, Subscribable, SubscriptionRef, } from '@livestore/utils/effect';
|
|
3
|
+
import { UnknownError } from "../adapter-types.js";
|
|
4
4
|
import { makeMaterializerHash } from "../materializer-helper.js";
|
|
5
|
-
import { EventSequenceNumber,
|
|
6
|
-
import { LeaderAheadError } from "../sync/sync.js";
|
|
5
|
+
import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } from "../schema/mod.js";
|
|
6
|
+
import { LeaderAheadError, } from "../sync/sync.js";
|
|
7
7
|
import * as SyncState from "../sync/syncstate.js";
|
|
8
8
|
import { sql } from "../util.js";
|
|
9
9
|
import * as Eventlog from "./eventlog.js";
|
|
@@ -39,15 +39,12 @@ import { LeaderThreadCtx } from "./types.js";
|
|
|
39
39
|
*
|
|
40
40
|
* See ClientSessionSyncProcessor for how the leader and session sync processors are similar/different.
|
|
41
41
|
*/
|
|
42
|
-
export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, params, testing, }) => Effect.gen(function* () {
|
|
42
|
+
export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, livePull, params, testing, }) => Effect.gen(function* () {
|
|
43
43
|
const syncBackendPushQueue = yield* BucketQueue.make();
|
|
44
44
|
const localPushBatchSize = params.localPushBatchSize ?? 1;
|
|
45
45
|
const backendPushBatchSize = params.backendPushBatchSize ?? 2;
|
|
46
46
|
const syncStateSref = yield* SubscriptionRef.make(undefined);
|
|
47
|
-
const isClientEvent = (eventEncoded) =>
|
|
48
|
-
const { eventDef } = getEventDef(schema, eventEncoded.name);
|
|
49
|
-
return eventDef.options.clientOnly;
|
|
50
|
-
};
|
|
47
|
+
const isClientEvent = (eventEncoded) => schema.eventsDefsMap.get(eventEncoded.name)?.options.clientOnly ?? false;
|
|
51
48
|
const connectedClientSessionPullQueues = yield* makePullQueueSet;
|
|
52
49
|
// This context depends on data from `boot`, we should find a better implementation to avoid this ref indirection.
|
|
53
50
|
const ctxRef = {
|
|
@@ -65,9 +62,9 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
|
|
|
65
62
|
*
|
|
66
63
|
* Thus the purpose of the pushHeadRef is the guard the integrity of the local push queue
|
|
67
64
|
*/
|
|
68
|
-
const pushHeadRef = { current: EventSequenceNumber.ROOT };
|
|
65
|
+
const pushHeadRef = { current: EventSequenceNumber.Client.ROOT };
|
|
69
66
|
const advancePushHead = (eventNum) => {
|
|
70
|
-
pushHeadRef.current = EventSequenceNumber.max(pushHeadRef.current, eventNum);
|
|
67
|
+
pushHeadRef.current = EventSequenceNumber.Client.max(pushHeadRef.current, eventNum);
|
|
71
68
|
};
|
|
72
69
|
// NOTE: New events are only pushed to sync backend after successful local push processing
|
|
73
70
|
const push = (newEvents, options) => Effect.gen(function* () {
|
|
@@ -98,13 +95,30 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
|
|
|
98
95
|
const syncState = yield* syncStateSref;
|
|
99
96
|
if (syncState === undefined)
|
|
100
97
|
return shouldNeverHappen('Not initialized');
|
|
101
|
-
const
|
|
102
|
-
|
|
98
|
+
const resolution = yield* resolveEventDef(schema, {
|
|
99
|
+
operation: '@livestore/common:LeaderSyncProcessor:pushPartial',
|
|
100
|
+
event: {
|
|
101
|
+
name,
|
|
102
|
+
args,
|
|
103
|
+
clientId,
|
|
104
|
+
sessionId,
|
|
105
|
+
seqNum: syncState.localHead,
|
|
106
|
+
},
|
|
107
|
+
}).pipe(UnknownError.mapToUnknownError);
|
|
108
|
+
if (resolution._tag === 'unknown') {
|
|
109
|
+
// Ignore partial pushes for unrecognised events – they are still
|
|
110
|
+
// persisted server-side once a schema update ships.
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const eventEncoded = new LiveStoreEvent.Client.EncodedWithMeta({
|
|
103
114
|
name,
|
|
104
115
|
args,
|
|
105
116
|
clientId,
|
|
106
117
|
sessionId,
|
|
107
|
-
...EventSequenceNumber.nextPair({
|
|
118
|
+
...EventSequenceNumber.Client.nextPair({
|
|
119
|
+
seqNum: syncState.localHead,
|
|
120
|
+
isClient: resolution.eventDef.options.clientOnly,
|
|
121
|
+
}),
|
|
108
122
|
});
|
|
109
123
|
yield* push([eventEncoded]);
|
|
110
124
|
}).pipe(Effect.catchTag('LeaderAheadError', Effect.orDie));
|
|
@@ -125,20 +139,25 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
|
|
|
125
139
|
// Rehydrate sync queue
|
|
126
140
|
if (initialSyncState.pending.length > 0) {
|
|
127
141
|
const globalPendingEvents = initialSyncState.pending
|
|
128
|
-
// Don't sync
|
|
142
|
+
// Don't sync client-local events
|
|
129
143
|
.filter((eventEncoded) => {
|
|
130
|
-
const
|
|
131
|
-
return eventDef.options.clientOnly === false;
|
|
144
|
+
const eventDef = schema.eventsDefsMap.get(eventEncoded.name);
|
|
145
|
+
return eventDef === undefined ? true : eventDef.options.clientOnly === false;
|
|
132
146
|
});
|
|
133
147
|
if (globalPendingEvents.length > 0) {
|
|
134
148
|
yield* BucketQueue.offerAll(syncBackendPushQueue, globalPendingEvents);
|
|
135
149
|
}
|
|
136
150
|
}
|
|
137
|
-
const
|
|
138
|
-
if (onError === '
|
|
139
|
-
|
|
140
|
-
|
|
151
|
+
const maybeShutdownOnError = (cause) => Effect.gen(function* () {
|
|
152
|
+
if (onError === 'ignore') {
|
|
153
|
+
if (LS_DEV) {
|
|
154
|
+
yield* Effect.logDebug(`Ignoring sync error (${cause._tag === 'Fail' ? cause.error._tag : cause._tag})`, Cause.pretty(cause));
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
141
157
|
}
|
|
158
|
+
const errorToSend = Cause.isFailType(cause) ? cause.error : UnknownError.make({ cause });
|
|
159
|
+
yield* shutdownChannel.send(errorToSend).pipe(Effect.orDie);
|
|
160
|
+
return yield* Effect.die(cause);
|
|
142
161
|
});
|
|
143
162
|
yield* backgroundApplyLocalPushes({
|
|
144
163
|
localPushesLatch,
|
|
@@ -154,17 +173,16 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
|
|
|
154
173
|
testing: {
|
|
155
174
|
delay: testing?.delays?.localPushProcessing,
|
|
156
175
|
},
|
|
157
|
-
}).pipe(Effect.
|
|
176
|
+
}).pipe(Effect.catchAllCause(maybeShutdownOnError), Effect.forkScoped);
|
|
158
177
|
const backendPushingFiberHandle = yield* FiberHandle.make();
|
|
159
178
|
const backendPushingEffect = backgroundBackendPushing({
|
|
160
179
|
syncBackendPushQueue,
|
|
161
180
|
otelSpan,
|
|
162
181
|
devtoolsLatch: ctxRef.current?.devtoolsLatch,
|
|
163
182
|
backendPushBatchSize,
|
|
164
|
-
}).pipe(Effect.
|
|
183
|
+
}).pipe(Effect.catchAllCause(maybeShutdownOnError));
|
|
165
184
|
yield* FiberHandle.run(backendPushingFiberHandle, backendPushingEffect);
|
|
166
185
|
yield* backgroundBackendPulling({
|
|
167
|
-
initialBackendHead: initialSyncState.upstreamHead.global,
|
|
168
186
|
isClientEvent,
|
|
169
187
|
restartBackendPushing: (filteredRebasedPending) => Effect.gen(function* () {
|
|
170
188
|
// Stop current pushing fiber
|
|
@@ -178,13 +196,20 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
|
|
|
178
196
|
syncStateSref,
|
|
179
197
|
localPushesLatch,
|
|
180
198
|
pullLatch,
|
|
199
|
+
livePull,
|
|
181
200
|
dbState,
|
|
182
201
|
otelSpan,
|
|
183
202
|
initialBlockingSyncContext,
|
|
184
203
|
devtoolsLatch: ctxRef.current?.devtoolsLatch,
|
|
185
204
|
connectedClientSessionPullQueues,
|
|
186
205
|
advancePushHead,
|
|
187
|
-
}).pipe(Effect.
|
|
206
|
+
}).pipe(Effect.retry({
|
|
207
|
+
// We want to retry pulling if we've lost connection to the sync backend
|
|
208
|
+
while: (cause) => cause._tag === 'IsOfflineError',
|
|
209
|
+
}), Effect.catchAllCause(maybeShutdownOnError),
|
|
210
|
+
// Needed to avoid `Fiber terminated with an unhandled error` logs which seem to happen because of the `Effect.retry` above.
|
|
211
|
+
// This might be a bug in Effect. Only seems to happen in the browser.
|
|
212
|
+
Effect.provide(Layer.setUnhandledErrorLogLevel(Option.none())), Effect.forkScoped);
|
|
188
213
|
return { initialLeaderHead: initialSyncState.localHead };
|
|
189
214
|
}).pipe(Effect.withSpanScoped('@livestore/common:LeaderSyncProcessor:boot'));
|
|
190
215
|
const pull = ({ cursor }) => Effect.gen(function* () {
|
|
@@ -243,26 +268,39 @@ const backgroundApplyLocalPushes = ({ localPushesLatch, localPushesQueue, pullLa
|
|
|
243
268
|
const currentRebaseGeneration = syncState.localHead.rebaseGeneration;
|
|
244
269
|
// Since the rebase generation might have changed since enqueuing, we need to filter out items with older generation
|
|
245
270
|
// It's important that we filter after we got localPushesLatch, otherwise we might filter with the old generation
|
|
246
|
-
const [
|
|
247
|
-
if (
|
|
248
|
-
|
|
249
|
-
|
|
271
|
+
const [droppedItems, filteredItems] = ReadonlyArray.partition(batchItems, ([eventEncoded]) => eventEncoded.seqNum.rebaseGeneration >= currentRebaseGeneration);
|
|
272
|
+
if (droppedItems.length > 0) {
|
|
273
|
+
otelSpan?.addEvent(`push:drop-old-generation`, {
|
|
274
|
+
droppedCount: droppedItems.length,
|
|
275
|
+
currentRebaseGeneration,
|
|
276
|
+
});
|
|
277
|
+
/**
|
|
278
|
+
* Dropped pushes may still have a deferred awaiting completion.
|
|
279
|
+
* Fail it so the caller learns the leader advanced and resubmits with the updated generation.
|
|
280
|
+
*/
|
|
281
|
+
yield* Effect.forEach(droppedItems.filter((item) => item[1] !== undefined), ([eventEncoded, deferred]) => Deferred.fail(deferred, LeaderAheadError.make({
|
|
282
|
+
minimumExpectedNum: syncState.localHead,
|
|
283
|
+
providedNum: eventEncoded.seqNum,
|
|
284
|
+
})));
|
|
285
|
+
}
|
|
286
|
+
if (filteredItems.length === 0) {
|
|
250
287
|
yield* pullLatch.open;
|
|
251
288
|
continue;
|
|
252
289
|
}
|
|
290
|
+
const [newEvents, deferreds] = ReadonlyArray.unzip(filteredItems);
|
|
253
291
|
const mergeResult = SyncState.merge({
|
|
254
292
|
syncState,
|
|
255
293
|
payload: { _tag: 'local-push', newEvents },
|
|
256
294
|
isClientEvent,
|
|
257
|
-
isEqualEvent: LiveStoreEvent.isEqualEncoded,
|
|
295
|
+
isEqualEvent: LiveStoreEvent.Client.isEqualEncoded,
|
|
258
296
|
});
|
|
259
297
|
switch (mergeResult._tag) {
|
|
260
|
-
case '
|
|
261
|
-
otelSpan?.addEvent(`push:
|
|
298
|
+
case 'unknown-error': {
|
|
299
|
+
otelSpan?.addEvent(`push:unknown-error`, {
|
|
262
300
|
batchSize: newEvents.length,
|
|
263
301
|
newEvents: TRACE_VERBOSE ? JSON.stringify(newEvents) : undefined,
|
|
264
302
|
});
|
|
265
|
-
return yield* new
|
|
303
|
+
return yield* new UnknownError({ cause: mergeResult.message });
|
|
266
304
|
}
|
|
267
305
|
case 'rebase': {
|
|
268
306
|
return shouldNeverHappen('The leader thread should never have to rebase due to a local push');
|
|
@@ -312,10 +350,10 @@ const backgroundApplyLocalPushes = ({ localPushesLatch, localPushesQueue, pullLa
|
|
|
312
350
|
batchSize: newEvents.length,
|
|
313
351
|
mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
|
314
352
|
});
|
|
315
|
-
// Don't sync
|
|
353
|
+
// Don't sync client-local events
|
|
316
354
|
const filteredBatch = mergeResult.newEvents.filter((eventEncoded) => {
|
|
317
|
-
const
|
|
318
|
-
return eventDef.options.clientOnly === false;
|
|
355
|
+
const eventDef = schema.eventsDefsMap.get(eventEncoded.name);
|
|
356
|
+
return eventDef === undefined ? true : eventDef.options.clientOnly === false;
|
|
319
357
|
});
|
|
320
358
|
yield* BucketQueue.offerAll(syncBackendPushQueue, filteredBatch);
|
|
321
359
|
yield* materializeEventsBatch({ batchItems: mergeResult.newEvents, deferreds });
|
|
@@ -348,12 +386,12 @@ const materializeEventsBatch = ({ batchItems, deferreds }) => Effect.gen(functio
|
|
|
348
386
|
dbEventlog.execute('COMMIT', undefined); // Commit the transaction
|
|
349
387
|
}).pipe(Effect.uninterruptible, Effect.scoped, Effect.withSpan('@livestore/common:LeaderSyncProcessor:materializeEventItems', {
|
|
350
388
|
attributes: { batchSize: batchItems.length },
|
|
351
|
-
}), Effect.tapCauseLogPretty
|
|
352
|
-
const backgroundBackendPulling = ({
|
|
389
|
+
}), Effect.tapCauseLogPretty);
|
|
390
|
+
const backgroundBackendPulling = ({ isClientEvent, restartBackendPushing, otelSpan, dbState, syncStateSref, localPushesLatch, livePull, pullLatch, devtoolsLatch, initialBlockingSyncContext, connectedClientSessionPullQueues, advancePushHead, }) => Effect.gen(function* () {
|
|
353
391
|
const { syncBackend, dbState: db, dbEventlog, schema } = yield* LeaderThreadCtx;
|
|
354
392
|
if (syncBackend === undefined)
|
|
355
393
|
return;
|
|
356
|
-
const onNewPullChunk = (newEvents,
|
|
394
|
+
const onNewPullChunk = (newEvents, pageInfo) => Effect.gen(function* () {
|
|
357
395
|
if (newEvents.length === 0)
|
|
358
396
|
return;
|
|
359
397
|
if (devtoolsLatch !== undefined) {
|
|
@@ -370,18 +408,18 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
|
|
|
370
408
|
syncState,
|
|
371
409
|
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents }),
|
|
372
410
|
isClientEvent,
|
|
373
|
-
isEqualEvent: LiveStoreEvent.isEqualEncoded,
|
|
411
|
+
isEqualEvent: LiveStoreEvent.Client.isEqualEncoded,
|
|
374
412
|
ignoreClientEvents: true,
|
|
375
413
|
});
|
|
376
414
|
if (mergeResult._tag === 'reject') {
|
|
377
415
|
return shouldNeverHappen('The leader thread should never reject upstream advances');
|
|
378
416
|
}
|
|
379
|
-
else if (mergeResult._tag === '
|
|
380
|
-
otelSpan?.addEvent(`pull:
|
|
417
|
+
else if (mergeResult._tag === 'unknown-error') {
|
|
418
|
+
otelSpan?.addEvent(`pull:unknown-error`, {
|
|
381
419
|
newEventsCount: newEvents.length,
|
|
382
420
|
newEvents: TRACE_VERBOSE ? JSON.stringify(newEvents) : undefined,
|
|
383
421
|
});
|
|
384
|
-
return yield* new
|
|
422
|
+
return yield* new UnknownError({ cause: mergeResult.message });
|
|
385
423
|
}
|
|
386
424
|
const newBackendHead = newEvents.at(-1).seqNum;
|
|
387
425
|
Eventlog.updateBackendHead(dbEventlog, newBackendHead);
|
|
@@ -393,8 +431,8 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
|
|
|
393
431
|
mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
|
394
432
|
});
|
|
395
433
|
const globalRebasedPendingEvents = mergeResult.newSyncState.pending.filter((event) => {
|
|
396
|
-
const
|
|
397
|
-
return eventDef.options.clientOnly === false;
|
|
434
|
+
const eventDef = schema.eventsDefsMap.get(event.name);
|
|
435
|
+
return eventDef === undefined ? true : eventDef.options.clientOnly === false;
|
|
398
436
|
});
|
|
399
437
|
yield* restartBackendPushing(globalRebasedPendingEvents);
|
|
400
438
|
if (mergeResult.rollbackEvents.length > 0) {
|
|
@@ -414,6 +452,12 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
|
|
|
414
452
|
newEventsCount: newEvents.length,
|
|
415
453
|
mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
|
416
454
|
});
|
|
455
|
+
// Ensure push fiber is active after advance by restarting with current pending (non-client) events
|
|
456
|
+
const globalPendingEvents = mergeResult.newSyncState.pending.filter((event) => {
|
|
457
|
+
const eventDef = schema.eventsDefsMap.get(event.name);
|
|
458
|
+
return eventDef === undefined ? true : eventDef.options.clientOnly === false;
|
|
459
|
+
});
|
|
460
|
+
yield* restartBackendPushing(globalPendingEvents);
|
|
417
461
|
yield* connectedClientSessionPullQueues.offer({
|
|
418
462
|
payload: SyncState.payloadFromMergeResult(mergeResult),
|
|
419
463
|
leaderHead: mergeResult.newSyncState.localHead,
|
|
@@ -421,8 +465,8 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
|
|
|
421
465
|
if (mergeResult.confirmedEvents.length > 0) {
|
|
422
466
|
// `mergeResult.confirmedEvents` don't contain the correct sync metadata, so we need to use
|
|
423
467
|
// `newEvents` instead which we filter via `mergeResult.confirmedEvents`
|
|
424
|
-
const confirmedNewEvents = newEvents.filter((event) => mergeResult.confirmedEvents.some((confirmedEvent) => EventSequenceNumber.isEqual(event.seqNum, confirmedEvent.seqNum)));
|
|
425
|
-
yield* Eventlog.updateSyncMetadata(confirmedNewEvents);
|
|
468
|
+
const confirmedNewEvents = newEvents.filter((event) => mergeResult.confirmedEvents.some((confirmedEvent) => EventSequenceNumber.Client.isEqual(event.seqNum, confirmedEvent.seqNum)));
|
|
469
|
+
yield* Eventlog.updateSyncMetadata(confirmedNewEvents).pipe(UnknownError.mapToUnknownError);
|
|
426
470
|
}
|
|
427
471
|
}
|
|
428
472
|
// Removes the changeset rows which are no longer needed as we'll never have to rollback beyond this point
|
|
@@ -431,15 +475,18 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
|
|
|
431
475
|
yield* materializeEventsBatch({ batchItems: mergeResult.newEvents, deferreds: undefined });
|
|
432
476
|
yield* SubscriptionRef.set(syncStateSref, mergeResult.newSyncState);
|
|
433
477
|
// Allow local pushes to be processed again
|
|
434
|
-
if (
|
|
478
|
+
if (pageInfo._tag === 'NoMore') {
|
|
435
479
|
yield* localPushesLatch.open;
|
|
436
480
|
}
|
|
437
481
|
});
|
|
438
|
-
const
|
|
482
|
+
const syncState = yield* syncStateSref;
|
|
483
|
+
if (syncState === undefined)
|
|
484
|
+
return shouldNeverHappen('Not initialized');
|
|
485
|
+
const cursorInfo = yield* Eventlog.getSyncBackendCursorInfo({ remoteHead: syncState.upstreamHead.global });
|
|
439
486
|
const hashMaterializerResult = makeMaterializerHash({ schema, dbState });
|
|
440
|
-
yield* syncBackend.pull(cursorInfo).pipe(
|
|
487
|
+
yield* syncBackend.pull(cursorInfo, { live: livePull }).pipe(
|
|
441
488
|
// TODO only take from queue while connected
|
|
442
|
-
Stream.tap(({ batch,
|
|
489
|
+
Stream.tap(({ batch, pageInfo }) => Effect.gen(function* () {
|
|
443
490
|
// yield* Effect.spanEvent('batch', {
|
|
444
491
|
// attributes: {
|
|
445
492
|
// batchSize: batch.length,
|
|
@@ -450,15 +497,17 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
|
|
|
450
497
|
// (e.g. needed for simulating being offline)
|
|
451
498
|
// TODO remove when there's a better way to handle this in stream above
|
|
452
499
|
yield* SubscriptionRef.waitUntil(syncBackend.isConnected, (isConnected) => isConnected === true);
|
|
453
|
-
yield* onNewPullChunk(batch.map((_) => LiveStoreEvent.EncodedWithMeta.fromGlobal(_.eventEncoded, {
|
|
500
|
+
yield* onNewPullChunk(batch.map((_) => LiveStoreEvent.Client.EncodedWithMeta.fromGlobal(_.eventEncoded, {
|
|
454
501
|
syncMetadata: _.metadata,
|
|
455
502
|
// TODO we can't really know the materializer result here yet beyond the first event batch item as we need to materialize it one by one first
|
|
456
503
|
// This is a bug and needs to be fixed https://github.com/livestorejs/livestore/issues/503#issuecomment-3114533165
|
|
457
|
-
materializerHashLeader: hashMaterializerResult(LiveStoreEvent.
|
|
504
|
+
materializerHashLeader: hashMaterializerResult(LiveStoreEvent.Global.toClientEncoded(_.eventEncoded)),
|
|
458
505
|
materializerHashSession: Option.none(),
|
|
459
|
-
})),
|
|
460
|
-
yield* initialBlockingSyncContext.update({ processed: batch.length,
|
|
506
|
+
})), pageInfo);
|
|
507
|
+
yield* initialBlockingSyncContext.update({ processed: batch.length, pageInfo });
|
|
461
508
|
})), Stream.runDrain, Effect.interruptible);
|
|
509
|
+
// Should only ever happen when livePull is false
|
|
510
|
+
yield* Effect.logDebug('backend-pulling finished', { livePull });
|
|
462
511
|
}).pipe(Effect.withSpan('@livestore/common:LeaderSyncProcessor:backend-pulling'));
|
|
463
512
|
const backgroundBackendPushing = ({ syncBackendPushQueue, otelSpan, devtoolsLatch, backendPushBatchSize, }) => Effect.gen(function* () {
|
|
464
513
|
const { syncBackend } = yield* LeaderThreadCtx;
|
|
@@ -475,16 +524,39 @@ const backgroundBackendPushing = ({ syncBackendPushQueue, otelSpan, devtoolsLatc
|
|
|
475
524
|
batchSize: queueItems.length,
|
|
476
525
|
batch: TRACE_VERBOSE ? JSON.stringify(queueItems) : undefined,
|
|
477
526
|
});
|
|
478
|
-
//
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
527
|
+
// Push with declarative retry/backoff using Effect schedules
|
|
528
|
+
// - Exponential backoff starting at 1s and doubling (1s, 2s, 4s, 8s, 16s, 30s ...)
|
|
529
|
+
// - Delay clamped at 30s (continues retrying at 30s)
|
|
530
|
+
// - Resets automatically after successful push
|
|
531
|
+
// TODO(metrics): expose counters/gauges for retry attempts and queue health via devtools/metrics
|
|
532
|
+
// Only retry for transient UnknownError cases
|
|
533
|
+
const isRetryable = (err) => err._tag === 'InvalidPushError' && err.cause._tag === 'LiveStore.UnknownError';
|
|
534
|
+
// Input: InvalidPushError | IsOfflineError, Output: Duration
|
|
535
|
+
const retrySchedule = Schedule.exponential(Duration.seconds(1)).pipe(Schedule.andThenEither(Schedule.spaced(Duration.seconds(30))), // clamp at 30 second intervals
|
|
536
|
+
Schedule.compose(Schedule.elapsed), Schedule.whileInput(isRetryable));
|
|
537
|
+
yield* Effect.gen(function* () {
|
|
538
|
+
const iteration = yield* Schedule.CurrentIterationMetadata;
|
|
539
|
+
const pushResult = yield* syncBackend.push(queueItems.map((_) => _.toGlobal())).pipe(Effect.either);
|
|
540
|
+
const retries = iteration.recurrence;
|
|
541
|
+
if (retries > 0 && pushResult._tag === 'Right') {
|
|
542
|
+
otelSpan?.addEvent('backend-push-retry-success', { retries, batchSize: queueItems.length });
|
|
483
543
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
544
|
+
if (pushResult._tag === 'Left') {
|
|
545
|
+
otelSpan?.addEvent('backend-push-error', {
|
|
546
|
+
error: pushResult.left.toString(),
|
|
547
|
+
retries,
|
|
548
|
+
batchSize: queueItems.length,
|
|
549
|
+
});
|
|
550
|
+
const error = pushResult.left;
|
|
551
|
+
if (error._tag === 'IsOfflineError' ||
|
|
552
|
+
(error._tag === 'InvalidPushError' && error.cause._tag === 'ServerAheadError')) {
|
|
553
|
+
// It's a core part of the sync protocol that the sync backend will emit a new pull chunk alongside the ServerAheadError
|
|
554
|
+
yield* Effect.logDebug('handled backend-push-error (waiting for interupt caused by pull)', { error });
|
|
555
|
+
return yield* Effect.never;
|
|
556
|
+
}
|
|
557
|
+
return yield* error;
|
|
558
|
+
}
|
|
559
|
+
}).pipe(Effect.retry(retrySchedule));
|
|
488
560
|
}
|
|
489
561
|
}).pipe(Effect.interruptible, Effect.withSpan('@livestore/common:LeaderSyncProcessor:backend-pushing'));
|
|
490
562
|
const trimChangesetRows = (db, newHead) => {
|
|
@@ -506,15 +578,15 @@ const makePullQueueSet = Effect.gen(function* () {
|
|
|
506
578
|
const queue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
|
|
507
579
|
yield* Effect.addFinalizer(() => Effect.sync(() => set.delete(queue)));
|
|
508
580
|
const payloadsSinceCursor = Array.from(cachedPayloads.entries())
|
|
509
|
-
.flatMap(([seqNumStr, payloads]) => payloads.map((payload) => ({ payload, seqNum: EventSequenceNumber.fromString(seqNumStr) })))
|
|
510
|
-
.filter(({ seqNum }) => EventSequenceNumber.isGreaterThan(seqNum, cursor))
|
|
511
|
-
.toSorted((a, b) => EventSequenceNumber.compare(a.seqNum, b.seqNum))
|
|
581
|
+
.flatMap(([seqNumStr, payloads]) => payloads.map((payload) => ({ payload, seqNum: EventSequenceNumber.Client.fromString(seqNumStr) })))
|
|
582
|
+
.filter(({ seqNum }) => EventSequenceNumber.Client.isGreaterThan(seqNum, cursor))
|
|
583
|
+
.toSorted((a, b) => EventSequenceNumber.Client.compare(a.seqNum, b.seqNum))
|
|
512
584
|
.map(({ payload }) => {
|
|
513
585
|
if (payload._tag === 'upstream-advance') {
|
|
514
586
|
return {
|
|
515
587
|
payload: {
|
|
516
588
|
_tag: 'upstream-advance',
|
|
517
|
-
newEvents: ReadonlyArray.dropWhile(payload.newEvents, (eventEncoded) => EventSequenceNumber.isGreaterThanOrEqual(cursor, eventEncoded.seqNum)),
|
|
589
|
+
newEvents: ReadonlyArray.dropWhile(payload.newEvents, (eventEncoded) => EventSequenceNumber.Client.isGreaterThanOrEqual(cursor, eventEncoded.seqNum)),
|
|
518
590
|
},
|
|
519
591
|
};
|
|
520
592
|
}
|
|
@@ -554,7 +626,7 @@ const makePullQueueSet = Effect.gen(function* () {
|
|
|
554
626
|
return queue;
|
|
555
627
|
});
|
|
556
628
|
const offer = (item) => Effect.gen(function* () {
|
|
557
|
-
const seqNumStr = EventSequenceNumber.toString(item.leaderHead);
|
|
629
|
+
const seqNumStr = EventSequenceNumber.Client.toString(item.leaderHead);
|
|
558
630
|
if (cachedPayloads.has(seqNumStr)) {
|
|
559
631
|
cachedPayloads.get(seqNumStr).push(item.payload);
|
|
560
632
|
}
|
|
@@ -575,18 +647,29 @@ const makePullQueueSet = Effect.gen(function* () {
|
|
|
575
647
|
offer,
|
|
576
648
|
};
|
|
577
649
|
});
|
|
650
|
+
/**
|
|
651
|
+
* Validate a client-provided batch before it is admitted to the leader queue.
|
|
652
|
+
* Ensures the numbers form a strictly increasing chain and that the first
|
|
653
|
+
* event sits ahead of the current push head.
|
|
654
|
+
*/
|
|
578
655
|
const validatePushBatch = (batch, pushHead) => Effect.gen(function* () {
|
|
579
656
|
if (batch.length === 0) {
|
|
580
657
|
return;
|
|
581
658
|
}
|
|
582
|
-
//
|
|
659
|
+
// Example: session A already enqueued e1…e6 while session B (same client, different
|
|
660
|
+
// session) still believes the head is e1 and submits [e2, e7, e8]. The numbers look
|
|
661
|
+
// monotonic from B’s perspective, but we must reject and force B to rebase locally
|
|
662
|
+
// so the leader never regresses.
|
|
583
663
|
for (let i = 1; i < batch.length; i++) {
|
|
584
|
-
if (EventSequenceNumber.isGreaterThanOrEqual(batch[i - 1].seqNum, batch[i].seqNum)) {
|
|
585
|
-
|
|
664
|
+
if (EventSequenceNumber.Client.isGreaterThanOrEqual(batch[i - 1].seqNum, batch[i].seqNum)) {
|
|
665
|
+
return yield* LeaderAheadError.make({
|
|
666
|
+
minimumExpectedNum: batch[i - 1].seqNum,
|
|
667
|
+
providedNum: batch[i].seqNum,
|
|
668
|
+
});
|
|
586
669
|
}
|
|
587
670
|
}
|
|
588
671
|
// Make sure smallest sequence number is > pushHead
|
|
589
|
-
if (EventSequenceNumber.isGreaterThanOrEqual(pushHead, batch[0].seqNum)) {
|
|
672
|
+
if (EventSequenceNumber.Client.isGreaterThanOrEqual(pushHead, batch[0].seqNum)) {
|
|
590
673
|
return yield* LeaderAheadError.make({
|
|
591
674
|
minimumExpectedNum: pushHead,
|
|
592
675
|
providedNum: batch[0].seqNum,
|