@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
|
@@ -2,27 +2,34 @@ import { casesHandled, isNotUndefined, LS_DEV, shouldNeverHappen, TRACE_VERBOSE
|
|
|
2
2
|
import type { HttpClient, Runtime, Scope, Tracer } from '@livestore/utils/effect'
|
|
3
3
|
import {
|
|
4
4
|
BucketQueue,
|
|
5
|
+
Cause,
|
|
5
6
|
Deferred,
|
|
7
|
+
Duration,
|
|
6
8
|
Effect,
|
|
7
9
|
Exit,
|
|
8
10
|
FiberHandle,
|
|
11
|
+
Layer,
|
|
9
12
|
Option,
|
|
10
13
|
OtelTracer,
|
|
11
|
-
pipe,
|
|
12
14
|
Queue,
|
|
13
15
|
ReadonlyArray,
|
|
16
|
+
Schedule,
|
|
14
17
|
Stream,
|
|
15
18
|
Subscribable,
|
|
16
19
|
SubscriptionRef,
|
|
17
20
|
} from '@livestore/utils/effect'
|
|
18
21
|
import type * as otel from '@opentelemetry/api'
|
|
19
|
-
|
|
20
|
-
import type { SqliteDb } from '../adapter-types.ts'
|
|
21
|
-
import { SyncError, UnexpectedError } from '../adapter-types.ts'
|
|
22
|
+
import { type IntentionalShutdownCause, type MaterializeError, type SqliteDb, UnknownError } from '../adapter-types.ts'
|
|
22
23
|
import { makeMaterializerHash } from '../materializer-helper.ts'
|
|
23
24
|
import type { LiveStoreSchema } from '../schema/mod.ts'
|
|
24
|
-
import { EventSequenceNumber,
|
|
25
|
-
import {
|
|
25
|
+
import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } from '../schema/mod.ts'
|
|
26
|
+
import {
|
|
27
|
+
type InvalidPullError,
|
|
28
|
+
type InvalidPushError,
|
|
29
|
+
type IsOfflineError,
|
|
30
|
+
LeaderAheadError,
|
|
31
|
+
type SyncBackend,
|
|
32
|
+
} from '../sync/sync.ts'
|
|
26
33
|
import * as SyncState from '../sync/syncstate.ts'
|
|
27
34
|
import { sql } from '../util.ts'
|
|
28
35
|
import * as Eventlog from './eventlog.ts'
|
|
@@ -31,7 +38,7 @@ import type { InitialBlockingSyncContext, LeaderSyncProcessor } from './types.ts
|
|
|
31
38
|
import { LeaderThreadCtx } from './types.ts'
|
|
32
39
|
|
|
33
40
|
type LocalPushQueueItem = [
|
|
34
|
-
event: LiveStoreEvent.EncodedWithMeta,
|
|
41
|
+
event: LiveStoreEvent.Client.EncodedWithMeta,
|
|
35
42
|
deferred: Deferred.Deferred<void, LeaderAheadError> | undefined,
|
|
36
43
|
]
|
|
37
44
|
|
|
@@ -71,6 +78,7 @@ export const makeLeaderSyncProcessor = ({
|
|
|
71
78
|
initialBlockingSyncContext,
|
|
72
79
|
initialSyncState,
|
|
73
80
|
onError,
|
|
81
|
+
livePull,
|
|
74
82
|
params,
|
|
75
83
|
testing,
|
|
76
84
|
}: {
|
|
@@ -90,23 +98,26 @@ export const makeLeaderSyncProcessor = ({
|
|
|
90
98
|
*/
|
|
91
99
|
backendPushBatchSize?: number
|
|
92
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Whether the sync backend should reactively pull new events from the sync backend
|
|
103
|
+
* When `false`, the sync processor will only do an initial pull
|
|
104
|
+
*/
|
|
105
|
+
livePull: boolean
|
|
93
106
|
testing: {
|
|
94
107
|
delays?: {
|
|
95
108
|
localPushProcessing?: Effect.Effect<void>
|
|
96
109
|
}
|
|
97
110
|
}
|
|
98
|
-
}): Effect.Effect<LeaderSyncProcessor,
|
|
111
|
+
}): Effect.Effect<LeaderSyncProcessor, UnknownError, Scope.Scope> =>
|
|
99
112
|
Effect.gen(function* () {
|
|
100
|
-
const syncBackendPushQueue = yield* BucketQueue.make<LiveStoreEvent.EncodedWithMeta>()
|
|
113
|
+
const syncBackendPushQueue = yield* BucketQueue.make<LiveStoreEvent.Client.EncodedWithMeta>()
|
|
101
114
|
const localPushBatchSize = params.localPushBatchSize ?? 1
|
|
102
115
|
const backendPushBatchSize = params.backendPushBatchSize ?? 2
|
|
103
116
|
|
|
104
117
|
const syncStateSref = yield* SubscriptionRef.make<SyncState.SyncState | undefined>(undefined)
|
|
105
118
|
|
|
106
|
-
const isClientEvent = (eventEncoded: LiveStoreEvent.EncodedWithMeta) =>
|
|
107
|
-
|
|
108
|
-
return eventDef.options.clientOnly
|
|
109
|
-
}
|
|
119
|
+
const isClientEvent = (eventEncoded: LiveStoreEvent.Client.EncodedWithMeta) =>
|
|
120
|
+
schema.eventsDefsMap.get(eventEncoded.name)?.options.clientOnly ?? false
|
|
110
121
|
|
|
111
122
|
const connectedClientSessionPullQueues = yield* makePullQueueSet
|
|
112
123
|
|
|
@@ -135,9 +146,9 @@ export const makeLeaderSyncProcessor = ({
|
|
|
135
146
|
*
|
|
136
147
|
* Thus the purpose of the pushHeadRef is the guard the integrity of the local push queue
|
|
137
148
|
*/
|
|
138
|
-
const pushHeadRef = { current: EventSequenceNumber.ROOT }
|
|
139
|
-
const advancePushHead = (eventNum: EventSequenceNumber.
|
|
140
|
-
pushHeadRef.current = EventSequenceNumber.max(pushHeadRef.current, eventNum)
|
|
149
|
+
const pushHeadRef = { current: EventSequenceNumber.Client.ROOT }
|
|
150
|
+
const advancePushHead = (eventNum: EventSequenceNumber.Client.Composite) => {
|
|
151
|
+
pushHeadRef.current = EventSequenceNumber.Client.max(pushHeadRef.current, eventNum)
|
|
141
152
|
}
|
|
142
153
|
|
|
143
154
|
// NOTE: New events are only pushed to sync backend after successful local push processing
|
|
@@ -180,14 +191,32 @@ export const makeLeaderSyncProcessor = ({
|
|
|
180
191
|
const syncState = yield* syncStateSref
|
|
181
192
|
if (syncState === undefined) return shouldNeverHappen('Not initialized')
|
|
182
193
|
|
|
183
|
-
const
|
|
194
|
+
const resolution = yield* resolveEventDef(schema, {
|
|
195
|
+
operation: '@livestore/common:LeaderSyncProcessor:pushPartial',
|
|
196
|
+
event: {
|
|
197
|
+
name,
|
|
198
|
+
args,
|
|
199
|
+
clientId,
|
|
200
|
+
sessionId,
|
|
201
|
+
seqNum: syncState.localHead,
|
|
202
|
+
},
|
|
203
|
+
}).pipe(UnknownError.mapToUnknownError)
|
|
184
204
|
|
|
185
|
-
|
|
205
|
+
if (resolution._tag === 'unknown') {
|
|
206
|
+
// Ignore partial pushes for unrecognised events – they are still
|
|
207
|
+
// persisted server-side once a schema update ships.
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const eventEncoded = new LiveStoreEvent.Client.EncodedWithMeta({
|
|
186
212
|
name,
|
|
187
213
|
args,
|
|
188
214
|
clientId,
|
|
189
215
|
sessionId,
|
|
190
|
-
...EventSequenceNumber.nextPair({
|
|
216
|
+
...EventSequenceNumber.Client.nextPair({
|
|
217
|
+
seqNum: syncState.localHead,
|
|
218
|
+
isClient: resolution.eventDef.options.clientOnly,
|
|
219
|
+
}),
|
|
191
220
|
})
|
|
192
221
|
|
|
193
222
|
yield* push([eventEncoded])
|
|
@@ -213,10 +242,10 @@ export const makeLeaderSyncProcessor = ({
|
|
|
213
242
|
// Rehydrate sync queue
|
|
214
243
|
if (initialSyncState.pending.length > 0) {
|
|
215
244
|
const globalPendingEvents = initialSyncState.pending
|
|
216
|
-
// Don't sync
|
|
245
|
+
// Don't sync client-local events
|
|
217
246
|
.filter((eventEncoded) => {
|
|
218
|
-
const
|
|
219
|
-
return eventDef.options.clientOnly === false
|
|
247
|
+
const eventDef = schema.eventsDefsMap.get(eventEncoded.name)
|
|
248
|
+
return eventDef === undefined ? true : eventDef.options.clientOnly === false
|
|
220
249
|
})
|
|
221
250
|
|
|
222
251
|
if (globalPendingEvents.length > 0) {
|
|
@@ -224,12 +253,31 @@ export const makeLeaderSyncProcessor = ({
|
|
|
224
253
|
}
|
|
225
254
|
}
|
|
226
255
|
|
|
227
|
-
const
|
|
256
|
+
const maybeShutdownOnError = (
|
|
257
|
+
cause: Cause.Cause<
|
|
258
|
+
| UnknownError
|
|
259
|
+
| IntentionalShutdownCause
|
|
260
|
+
| IsOfflineError
|
|
261
|
+
| InvalidPushError
|
|
262
|
+
| InvalidPullError
|
|
263
|
+
| MaterializeError
|
|
264
|
+
>,
|
|
265
|
+
) =>
|
|
228
266
|
Effect.gen(function* () {
|
|
229
|
-
if (onError === '
|
|
230
|
-
|
|
231
|
-
|
|
267
|
+
if (onError === 'ignore') {
|
|
268
|
+
if (LS_DEV) {
|
|
269
|
+
yield* Effect.logDebug(
|
|
270
|
+
`Ignoring sync error (${cause._tag === 'Fail' ? cause.error._tag : cause._tag})`,
|
|
271
|
+
Cause.pretty(cause),
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
return
|
|
232
275
|
}
|
|
276
|
+
|
|
277
|
+
const errorToSend = Cause.isFailType(cause) ? cause.error : UnknownError.make({ cause })
|
|
278
|
+
yield* shutdownChannel.send(errorToSend).pipe(Effect.orDie)
|
|
279
|
+
|
|
280
|
+
return yield* Effect.die(cause)
|
|
233
281
|
})
|
|
234
282
|
|
|
235
283
|
yield* backgroundApplyLocalPushes({
|
|
@@ -246,20 +294,19 @@ export const makeLeaderSyncProcessor = ({
|
|
|
246
294
|
testing: {
|
|
247
295
|
delay: testing?.delays?.localPushProcessing,
|
|
248
296
|
},
|
|
249
|
-
}).pipe(Effect.
|
|
297
|
+
}).pipe(Effect.catchAllCause(maybeShutdownOnError), Effect.forkScoped)
|
|
250
298
|
|
|
251
|
-
const backendPushingFiberHandle = yield* FiberHandle.make()
|
|
299
|
+
const backendPushingFiberHandle = yield* FiberHandle.make<void, never>()
|
|
252
300
|
const backendPushingEffect = backgroundBackendPushing({
|
|
253
301
|
syncBackendPushQueue,
|
|
254
302
|
otelSpan,
|
|
255
303
|
devtoolsLatch: ctxRef.current?.devtoolsLatch,
|
|
256
304
|
backendPushBatchSize,
|
|
257
|
-
}).pipe(Effect.
|
|
305
|
+
}).pipe(Effect.catchAllCause(maybeShutdownOnError))
|
|
258
306
|
|
|
259
307
|
yield* FiberHandle.run(backendPushingFiberHandle, backendPushingEffect)
|
|
260
308
|
|
|
261
309
|
yield* backgroundBackendPulling({
|
|
262
|
-
initialBackendHead: initialSyncState.upstreamHead.global,
|
|
263
310
|
isClientEvent,
|
|
264
311
|
restartBackendPushing: (filteredRebasedPending) =>
|
|
265
312
|
Effect.gen(function* () {
|
|
@@ -276,13 +323,24 @@ export const makeLeaderSyncProcessor = ({
|
|
|
276
323
|
syncStateSref,
|
|
277
324
|
localPushesLatch,
|
|
278
325
|
pullLatch,
|
|
326
|
+
livePull,
|
|
279
327
|
dbState,
|
|
280
328
|
otelSpan,
|
|
281
329
|
initialBlockingSyncContext,
|
|
282
330
|
devtoolsLatch: ctxRef.current?.devtoolsLatch,
|
|
283
331
|
connectedClientSessionPullQueues,
|
|
284
332
|
advancePushHead,
|
|
285
|
-
}).pipe(
|
|
333
|
+
}).pipe(
|
|
334
|
+
Effect.retry({
|
|
335
|
+
// We want to retry pulling if we've lost connection to the sync backend
|
|
336
|
+
while: (cause) => cause._tag === 'IsOfflineError',
|
|
337
|
+
}),
|
|
338
|
+
Effect.catchAllCause(maybeShutdownOnError),
|
|
339
|
+
// Needed to avoid `Fiber terminated with an unhandled error` logs which seem to happen because of the `Effect.retry` above.
|
|
340
|
+
// This might be a bug in Effect. Only seems to happen in the browser.
|
|
341
|
+
Effect.provide(Layer.setUnhandledErrorLogLevel(Option.none())),
|
|
342
|
+
Effect.forkScoped,
|
|
343
|
+
)
|
|
286
344
|
|
|
287
345
|
return { initialLeaderHead: initialSyncState.localHead }
|
|
288
346
|
}).pipe(Effect.withSpanScoped('@livestore/common:LeaderSyncProcessor:boot'))
|
|
@@ -348,9 +406,9 @@ const backgroundApplyLocalPushes = ({
|
|
|
348
406
|
localPushesLatch: Effect.Latch
|
|
349
407
|
localPushesQueue: BucketQueue.BucketQueue<LocalPushQueueItem>
|
|
350
408
|
syncStateSref: SubscriptionRef.SubscriptionRef<SyncState.SyncState | undefined>
|
|
351
|
-
syncBackendPushQueue: BucketQueue.BucketQueue<LiveStoreEvent.EncodedWithMeta>
|
|
409
|
+
syncBackendPushQueue: BucketQueue.BucketQueue<LiveStoreEvent.Client.EncodedWithMeta>
|
|
352
410
|
schema: LiveStoreSchema
|
|
353
|
-
isClientEvent: (eventEncoded: LiveStoreEvent.EncodedWithMeta) => boolean
|
|
411
|
+
isClientEvent: (eventEncoded: LiveStoreEvent.Client.EncodedWithMeta) => boolean
|
|
354
412
|
otelSpan: otel.Span | undefined
|
|
355
413
|
connectedClientSessionPullQueues: PullQueueSet
|
|
356
414
|
localPushBatchSize: number
|
|
@@ -379,33 +437,58 @@ const backgroundApplyLocalPushes = ({
|
|
|
379
437
|
|
|
380
438
|
// Since the rebase generation might have changed since enqueuing, we need to filter out items with older generation
|
|
381
439
|
// It's important that we filter after we got localPushesLatch, otherwise we might filter with the old generation
|
|
382
|
-
const [
|
|
440
|
+
const [droppedItems, filteredItems] = ReadonlyArray.partition(
|
|
383
441
|
batchItems,
|
|
384
|
-
|
|
385
|
-
ReadonlyArray.unzip,
|
|
442
|
+
([eventEncoded]) => eventEncoded.seqNum.rebaseGeneration >= currentRebaseGeneration,
|
|
386
443
|
)
|
|
387
444
|
|
|
388
|
-
if (
|
|
389
|
-
|
|
390
|
-
|
|
445
|
+
if (droppedItems.length > 0) {
|
|
446
|
+
otelSpan?.addEvent(`push:drop-old-generation`, {
|
|
447
|
+
droppedCount: droppedItems.length,
|
|
448
|
+
currentRebaseGeneration,
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Dropped pushes may still have a deferred awaiting completion.
|
|
453
|
+
* Fail it so the caller learns the leader advanced and resubmits with the updated generation.
|
|
454
|
+
*/
|
|
455
|
+
yield* Effect.forEach(
|
|
456
|
+
droppedItems.filter(
|
|
457
|
+
(item): item is [LiveStoreEvent.Client.EncodedWithMeta, Deferred.Deferred<void, LeaderAheadError>] =>
|
|
458
|
+
item[1] !== undefined,
|
|
459
|
+
),
|
|
460
|
+
([eventEncoded, deferred]) =>
|
|
461
|
+
Deferred.fail(
|
|
462
|
+
deferred,
|
|
463
|
+
LeaderAheadError.make({
|
|
464
|
+
minimumExpectedNum: syncState.localHead,
|
|
465
|
+
providedNum: eventEncoded.seqNum,
|
|
466
|
+
}),
|
|
467
|
+
),
|
|
468
|
+
)
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (filteredItems.length === 0) {
|
|
391
472
|
yield* pullLatch.open
|
|
392
473
|
continue
|
|
393
474
|
}
|
|
394
475
|
|
|
476
|
+
const [newEvents, deferreds] = ReadonlyArray.unzip(filteredItems)
|
|
477
|
+
|
|
395
478
|
const mergeResult = SyncState.merge({
|
|
396
479
|
syncState,
|
|
397
480
|
payload: { _tag: 'local-push', newEvents },
|
|
398
481
|
isClientEvent,
|
|
399
|
-
isEqualEvent: LiveStoreEvent.isEqualEncoded,
|
|
482
|
+
isEqualEvent: LiveStoreEvent.Client.isEqualEncoded,
|
|
400
483
|
})
|
|
401
484
|
|
|
402
485
|
switch (mergeResult._tag) {
|
|
403
|
-
case '
|
|
404
|
-
otelSpan?.addEvent(`push:
|
|
486
|
+
case 'unknown-error': {
|
|
487
|
+
otelSpan?.addEvent(`push:unknown-error`, {
|
|
405
488
|
batchSize: newEvents.length,
|
|
406
489
|
newEvents: TRACE_VERBOSE ? JSON.stringify(newEvents) : undefined,
|
|
407
490
|
})
|
|
408
|
-
return yield* new
|
|
491
|
+
return yield* new UnknownError({ cause: mergeResult.message })
|
|
409
492
|
}
|
|
410
493
|
case 'rebase': {
|
|
411
494
|
return shouldNeverHappen('The leader thread should never have to rebase due to a local push')
|
|
@@ -474,10 +557,10 @@ const backgroundApplyLocalPushes = ({
|
|
|
474
557
|
mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
|
475
558
|
})
|
|
476
559
|
|
|
477
|
-
// Don't sync
|
|
560
|
+
// Don't sync client-local events
|
|
478
561
|
const filteredBatch = mergeResult.newEvents.filter((eventEncoded) => {
|
|
479
|
-
const
|
|
480
|
-
return eventDef.options.clientOnly === false
|
|
562
|
+
const eventDef = schema.eventsDefsMap.get(eventEncoded.name)
|
|
563
|
+
return eventDef === undefined ? true : eventDef.options.clientOnly === false
|
|
481
564
|
})
|
|
482
565
|
|
|
483
566
|
yield* BucketQueue.offerAll(syncBackendPushQueue, filteredBatch)
|
|
@@ -490,13 +573,13 @@ const backgroundApplyLocalPushes = ({
|
|
|
490
573
|
})
|
|
491
574
|
|
|
492
575
|
type MaterializeEventsBatch = (_: {
|
|
493
|
-
batchItems: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>
|
|
576
|
+
batchItems: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>
|
|
494
577
|
/**
|
|
495
578
|
* The deferreds are used by the caller to know when the mutation has been processed.
|
|
496
579
|
* Indexes are aligned with `batchItems`
|
|
497
580
|
*/
|
|
498
581
|
deferreds: ReadonlyArray<Deferred.Deferred<void, LeaderAheadError> | undefined> | undefined
|
|
499
|
-
}) => Effect.Effect<void,
|
|
582
|
+
}) => Effect.Effect<void, MaterializeError, LeaderThreadCtx>
|
|
500
583
|
|
|
501
584
|
// TODO how to handle errors gracefully
|
|
502
585
|
const materializeEventsBatch: MaterializeEventsBatch = ({ batchItems, deferreds }) =>
|
|
@@ -536,44 +619,46 @@ const materializeEventsBatch: MaterializeEventsBatch = ({ batchItems, deferreds
|
|
|
536
619
|
attributes: { batchSize: batchItems.length },
|
|
537
620
|
}),
|
|
538
621
|
Effect.tapCauseLogPretty,
|
|
539
|
-
UnexpectedError.mapToUnexpectedError,
|
|
540
622
|
)
|
|
541
623
|
|
|
542
624
|
const backgroundBackendPulling = ({
|
|
543
|
-
initialBackendHead,
|
|
544
625
|
isClientEvent,
|
|
545
626
|
restartBackendPushing,
|
|
546
627
|
otelSpan,
|
|
547
628
|
dbState,
|
|
548
629
|
syncStateSref,
|
|
549
630
|
localPushesLatch,
|
|
631
|
+
livePull,
|
|
550
632
|
pullLatch,
|
|
551
633
|
devtoolsLatch,
|
|
552
634
|
initialBlockingSyncContext,
|
|
553
635
|
connectedClientSessionPullQueues,
|
|
554
636
|
advancePushHead,
|
|
555
637
|
}: {
|
|
556
|
-
|
|
557
|
-
isClientEvent: (eventEncoded: LiveStoreEvent.EncodedWithMeta) => boolean
|
|
638
|
+
isClientEvent: (eventEncoded: LiveStoreEvent.Client.EncodedWithMeta) => boolean
|
|
558
639
|
restartBackendPushing: (
|
|
559
|
-
filteredRebasedPending: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>,
|
|
560
|
-
) => Effect.Effect<void,
|
|
640
|
+
filteredRebasedPending: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>,
|
|
641
|
+
) => Effect.Effect<void, UnknownError, LeaderThreadCtx | HttpClient.HttpClient>
|
|
561
642
|
otelSpan: otel.Span | undefined
|
|
562
643
|
syncStateSref: SubscriptionRef.SubscriptionRef<SyncState.SyncState | undefined>
|
|
563
644
|
dbState: SqliteDb
|
|
564
645
|
localPushesLatch: Effect.Latch
|
|
565
646
|
pullLatch: Effect.Latch
|
|
647
|
+
livePull: boolean
|
|
566
648
|
devtoolsLatch: Effect.Latch | undefined
|
|
567
649
|
initialBlockingSyncContext: InitialBlockingSyncContext
|
|
568
650
|
connectedClientSessionPullQueues: PullQueueSet
|
|
569
|
-
advancePushHead: (eventNum: EventSequenceNumber.
|
|
651
|
+
advancePushHead: (eventNum: EventSequenceNumber.Client.Composite) => void
|
|
570
652
|
}) =>
|
|
571
653
|
Effect.gen(function* () {
|
|
572
654
|
const { syncBackend, dbState: db, dbEventlog, schema } = yield* LeaderThreadCtx
|
|
573
655
|
|
|
574
656
|
if (syncBackend === undefined) return
|
|
575
657
|
|
|
576
|
-
const onNewPullChunk = (
|
|
658
|
+
const onNewPullChunk = (
|
|
659
|
+
newEvents: LiveStoreEvent.Client.EncodedWithMeta[],
|
|
660
|
+
pageInfo: SyncBackend.PullResPageInfo,
|
|
661
|
+
) =>
|
|
577
662
|
Effect.gen(function* () {
|
|
578
663
|
if (newEvents.length === 0) return
|
|
579
664
|
|
|
@@ -594,18 +679,18 @@ const backgroundBackendPulling = ({
|
|
|
594
679
|
syncState,
|
|
595
680
|
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents }),
|
|
596
681
|
isClientEvent,
|
|
597
|
-
isEqualEvent: LiveStoreEvent.isEqualEncoded,
|
|
682
|
+
isEqualEvent: LiveStoreEvent.Client.isEqualEncoded,
|
|
598
683
|
ignoreClientEvents: true,
|
|
599
684
|
})
|
|
600
685
|
|
|
601
686
|
if (mergeResult._tag === 'reject') {
|
|
602
687
|
return shouldNeverHappen('The leader thread should never reject upstream advances')
|
|
603
|
-
} else if (mergeResult._tag === '
|
|
604
|
-
otelSpan?.addEvent(`pull:
|
|
688
|
+
} else if (mergeResult._tag === 'unknown-error') {
|
|
689
|
+
otelSpan?.addEvent(`pull:unknown-error`, {
|
|
605
690
|
newEventsCount: newEvents.length,
|
|
606
691
|
newEvents: TRACE_VERBOSE ? JSON.stringify(newEvents) : undefined,
|
|
607
692
|
})
|
|
608
|
-
return yield* new
|
|
693
|
+
return yield* new UnknownError({ cause: mergeResult.message })
|
|
609
694
|
}
|
|
610
695
|
|
|
611
696
|
const newBackendHead = newEvents.at(-1)!.seqNum
|
|
@@ -621,8 +706,8 @@ const backgroundBackendPulling = ({
|
|
|
621
706
|
})
|
|
622
707
|
|
|
623
708
|
const globalRebasedPendingEvents = mergeResult.newSyncState.pending.filter((event) => {
|
|
624
|
-
const
|
|
625
|
-
return eventDef.options.clientOnly === false
|
|
709
|
+
const eventDef = schema.eventsDefsMap.get(event.name)
|
|
710
|
+
return eventDef === undefined ? true : eventDef.options.clientOnly === false
|
|
626
711
|
})
|
|
627
712
|
yield* restartBackendPushing(globalRebasedPendingEvents)
|
|
628
713
|
|
|
@@ -644,6 +729,13 @@ const backgroundBackendPulling = ({
|
|
|
644
729
|
mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
|
645
730
|
})
|
|
646
731
|
|
|
732
|
+
// Ensure push fiber is active after advance by restarting with current pending (non-client) events
|
|
733
|
+
const globalPendingEvents = mergeResult.newSyncState.pending.filter((event) => {
|
|
734
|
+
const eventDef = schema.eventsDefsMap.get(event.name)
|
|
735
|
+
return eventDef === undefined ? true : eventDef.options.clientOnly === false
|
|
736
|
+
})
|
|
737
|
+
yield* restartBackendPushing(globalPendingEvents)
|
|
738
|
+
|
|
647
739
|
yield* connectedClientSessionPullQueues.offer({
|
|
648
740
|
payload: SyncState.payloadFromMergeResult(mergeResult),
|
|
649
741
|
leaderHead: mergeResult.newSyncState.localHead,
|
|
@@ -654,10 +746,10 @@ const backgroundBackendPulling = ({
|
|
|
654
746
|
// `newEvents` instead which we filter via `mergeResult.confirmedEvents`
|
|
655
747
|
const confirmedNewEvents = newEvents.filter((event) =>
|
|
656
748
|
mergeResult.confirmedEvents.some((confirmedEvent) =>
|
|
657
|
-
EventSequenceNumber.isEqual(event.seqNum, confirmedEvent.seqNum),
|
|
749
|
+
EventSequenceNumber.Client.isEqual(event.seqNum, confirmedEvent.seqNum),
|
|
658
750
|
),
|
|
659
751
|
)
|
|
660
|
-
yield* Eventlog.updateSyncMetadata(confirmedNewEvents)
|
|
752
|
+
yield* Eventlog.updateSyncMetadata(confirmedNewEvents).pipe(UnknownError.mapToUnknownError)
|
|
661
753
|
}
|
|
662
754
|
}
|
|
663
755
|
|
|
@@ -671,18 +763,20 @@ const backgroundBackendPulling = ({
|
|
|
671
763
|
yield* SubscriptionRef.set(syncStateSref, mergeResult.newSyncState)
|
|
672
764
|
|
|
673
765
|
// Allow local pushes to be processed again
|
|
674
|
-
if (
|
|
766
|
+
if (pageInfo._tag === 'NoMore') {
|
|
675
767
|
yield* localPushesLatch.open
|
|
676
768
|
}
|
|
677
769
|
})
|
|
678
770
|
|
|
679
|
-
const
|
|
771
|
+
const syncState = yield* syncStateSref
|
|
772
|
+
if (syncState === undefined) return shouldNeverHappen('Not initialized')
|
|
773
|
+
const cursorInfo = yield* Eventlog.getSyncBackendCursorInfo({ remoteHead: syncState.upstreamHead.global })
|
|
680
774
|
|
|
681
775
|
const hashMaterializerResult = makeMaterializerHash({ schema, dbState })
|
|
682
776
|
|
|
683
|
-
yield* syncBackend.pull(cursorInfo).pipe(
|
|
777
|
+
yield* syncBackend.pull(cursorInfo, { live: livePull }).pipe(
|
|
684
778
|
// TODO only take from queue while connected
|
|
685
|
-
Stream.tap(({ batch,
|
|
779
|
+
Stream.tap(({ batch, pageInfo }) =>
|
|
686
780
|
Effect.gen(function* () {
|
|
687
781
|
// yield* Effect.spanEvent('batch', {
|
|
688
782
|
// attributes: {
|
|
@@ -690,31 +784,31 @@ const backgroundBackendPulling = ({
|
|
|
690
784
|
// batch: TRACE_VERBOSE ? batch : undefined,
|
|
691
785
|
// },
|
|
692
786
|
// })
|
|
693
|
-
|
|
694
787
|
// NOTE we only want to take process events when the sync backend is connected
|
|
695
788
|
// (e.g. needed for simulating being offline)
|
|
696
789
|
// TODO remove when there's a better way to handle this in stream above
|
|
697
790
|
yield* SubscriptionRef.waitUntil(syncBackend.isConnected, (isConnected) => isConnected === true)
|
|
698
|
-
|
|
699
791
|
yield* onNewPullChunk(
|
|
700
792
|
batch.map((_) =>
|
|
701
|
-
LiveStoreEvent.EncodedWithMeta.fromGlobal(_.eventEncoded, {
|
|
793
|
+
LiveStoreEvent.Client.EncodedWithMeta.fromGlobal(_.eventEncoded, {
|
|
702
794
|
syncMetadata: _.metadata,
|
|
703
795
|
// 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
|
|
704
796
|
// This is a bug and needs to be fixed https://github.com/livestorejs/livestore/issues/503#issuecomment-3114533165
|
|
705
|
-
materializerHashLeader: hashMaterializerResult(LiveStoreEvent.
|
|
797
|
+
materializerHashLeader: hashMaterializerResult(LiveStoreEvent.Global.toClientEncoded(_.eventEncoded)),
|
|
706
798
|
materializerHashSession: Option.none(),
|
|
707
799
|
}),
|
|
708
800
|
),
|
|
709
|
-
|
|
801
|
+
pageInfo,
|
|
710
802
|
)
|
|
711
|
-
|
|
712
|
-
yield* initialBlockingSyncContext.update({ processed: batch.length, remaining })
|
|
803
|
+
yield* initialBlockingSyncContext.update({ processed: batch.length, pageInfo })
|
|
713
804
|
}),
|
|
714
805
|
),
|
|
715
806
|
Stream.runDrain,
|
|
716
807
|
Effect.interruptible,
|
|
717
808
|
)
|
|
809
|
+
|
|
810
|
+
// Should only ever happen when livePull is false
|
|
811
|
+
yield* Effect.logDebug('backend-pulling finished', { livePull })
|
|
718
812
|
}).pipe(Effect.withSpan('@livestore/common:LeaderSyncProcessor:backend-pulling'))
|
|
719
813
|
|
|
720
814
|
const backgroundBackendPushing = ({
|
|
@@ -723,7 +817,7 @@ const backgroundBackendPushing = ({
|
|
|
723
817
|
devtoolsLatch,
|
|
724
818
|
backendPushBatchSize,
|
|
725
819
|
}: {
|
|
726
|
-
syncBackendPushQueue: BucketQueue.BucketQueue<LiveStoreEvent.EncodedWithMeta>
|
|
820
|
+
syncBackendPushQueue: BucketQueue.BucketQueue<LiveStoreEvent.Client.EncodedWithMeta>
|
|
727
821
|
otelSpan: otel.Span | undefined
|
|
728
822
|
devtoolsLatch: Effect.Latch | undefined
|
|
729
823
|
backendPushBatchSize: number
|
|
@@ -748,21 +842,57 @@ const backgroundBackendPushing = ({
|
|
|
748
842
|
batch: TRACE_VERBOSE ? JSON.stringify(queueItems) : undefined,
|
|
749
843
|
})
|
|
750
844
|
|
|
751
|
-
//
|
|
752
|
-
|
|
845
|
+
// Push with declarative retry/backoff using Effect schedules
|
|
846
|
+
// - Exponential backoff starting at 1s and doubling (1s, 2s, 4s, 8s, 16s, 30s ...)
|
|
847
|
+
// - Delay clamped at 30s (continues retrying at 30s)
|
|
848
|
+
// - Resets automatically after successful push
|
|
849
|
+
// TODO(metrics): expose counters/gauges for retry attempts and queue health via devtools/metrics
|
|
850
|
+
|
|
851
|
+
// Only retry for transient UnknownError cases
|
|
852
|
+
const isRetryable = (err: InvalidPushError | IsOfflineError) =>
|
|
853
|
+
err._tag === 'InvalidPushError' && err.cause._tag === 'LiveStore.UnknownError'
|
|
854
|
+
|
|
855
|
+
// Input: InvalidPushError | IsOfflineError, Output: Duration
|
|
856
|
+
const retrySchedule: Schedule.Schedule<Duration.DurationInput, InvalidPushError | IsOfflineError> =
|
|
857
|
+
Schedule.exponential(Duration.seconds(1)).pipe(
|
|
858
|
+
Schedule.andThenEither(Schedule.spaced(Duration.seconds(30))), // clamp at 30 second intervals
|
|
859
|
+
Schedule.compose(Schedule.elapsed),
|
|
860
|
+
Schedule.whileInput(isRetryable),
|
|
861
|
+
)
|
|
862
|
+
|
|
863
|
+
yield* Effect.gen(function* () {
|
|
864
|
+
const iteration = yield* Schedule.CurrentIterationMetadata
|
|
753
865
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
866
|
+
const pushResult = yield* syncBackend.push(queueItems.map((_) => _.toGlobal())).pipe(Effect.either)
|
|
867
|
+
|
|
868
|
+
const retries = iteration.recurrence
|
|
869
|
+
if (retries > 0 && pushResult._tag === 'Right') {
|
|
870
|
+
otelSpan?.addEvent('backend-push-retry-success', { retries, batchSize: queueItems.length })
|
|
757
871
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
872
|
+
|
|
873
|
+
if (pushResult._tag === 'Left') {
|
|
874
|
+
otelSpan?.addEvent('backend-push-error', {
|
|
875
|
+
error: pushResult.left.toString(),
|
|
876
|
+
retries,
|
|
877
|
+
batchSize: queueItems.length,
|
|
878
|
+
})
|
|
879
|
+
const error = pushResult.left
|
|
880
|
+
if (
|
|
881
|
+
error._tag === 'IsOfflineError' ||
|
|
882
|
+
(error._tag === 'InvalidPushError' && error.cause._tag === 'ServerAheadError')
|
|
883
|
+
) {
|
|
884
|
+
// It's a core part of the sync protocol that the sync backend will emit a new pull chunk alongside the ServerAheadError
|
|
885
|
+
yield* Effect.logDebug('handled backend-push-error (waiting for interupt caused by pull)', { error })
|
|
886
|
+
return yield* Effect.never
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
return yield* error
|
|
890
|
+
}
|
|
891
|
+
}).pipe(Effect.retry(retrySchedule))
|
|
762
892
|
}
|
|
763
893
|
}).pipe(Effect.interruptible, Effect.withSpan('@livestore/common:LeaderSyncProcessor:backend-pushing'))
|
|
764
894
|
|
|
765
|
-
const trimChangesetRows = (db: SqliteDb, newHead: EventSequenceNumber.
|
|
895
|
+
const trimChangesetRows = (db: SqliteDb, newHead: EventSequenceNumber.Client.Composite) => {
|
|
766
896
|
// Since we're using the session changeset rows to query for the current head,
|
|
767
897
|
// we're keeping at least one row for the current head, and thus are using `<` instead of `<=`
|
|
768
898
|
db.execute(sql`DELETE FROM ${SystemTables.SESSION_CHANGESET_META_TABLE} WHERE seqNumGlobal < ${newHead.global}`)
|
|
@@ -770,16 +900,16 @@ const trimChangesetRows = (db: SqliteDb, newHead: EventSequenceNumber.EventSeque
|
|
|
770
900
|
|
|
771
901
|
interface PullQueueSet {
|
|
772
902
|
makeQueue: (
|
|
773
|
-
cursor: EventSequenceNumber.
|
|
903
|
+
cursor: EventSequenceNumber.Client.Composite,
|
|
774
904
|
) => Effect.Effect<
|
|
775
905
|
Queue.Queue<{ payload: typeof SyncState.PayloadUpstream.Type }>,
|
|
776
|
-
|
|
906
|
+
UnknownError,
|
|
777
907
|
Scope.Scope | LeaderThreadCtx
|
|
778
908
|
>
|
|
779
909
|
offer: (item: {
|
|
780
910
|
payload: typeof SyncState.PayloadUpstream.Type
|
|
781
|
-
leaderHead: EventSequenceNumber.
|
|
782
|
-
}) => Effect.Effect<void,
|
|
911
|
+
leaderHead: EventSequenceNumber.Client.Composite
|
|
912
|
+
}) => Effect.Effect<void, UnknownError>
|
|
783
913
|
}
|
|
784
914
|
|
|
785
915
|
const makePullQueueSet = Effect.gen(function* () {
|
|
@@ -809,17 +939,17 @@ const makePullQueueSet = Effect.gen(function* () {
|
|
|
809
939
|
|
|
810
940
|
const payloadsSinceCursor = Array.from(cachedPayloads.entries())
|
|
811
941
|
.flatMap(([seqNumStr, payloads]) =>
|
|
812
|
-
payloads.map((payload) => ({ payload, seqNum: EventSequenceNumber.fromString(seqNumStr) })),
|
|
942
|
+
payloads.map((payload) => ({ payload, seqNum: EventSequenceNumber.Client.fromString(seqNumStr) })),
|
|
813
943
|
)
|
|
814
|
-
.filter(({ seqNum }) => EventSequenceNumber.isGreaterThan(seqNum, cursor))
|
|
815
|
-
.toSorted((a, b) => EventSequenceNumber.compare(a.seqNum, b.seqNum))
|
|
944
|
+
.filter(({ seqNum }) => EventSequenceNumber.Client.isGreaterThan(seqNum, cursor))
|
|
945
|
+
.toSorted((a, b) => EventSequenceNumber.Client.compare(a.seqNum, b.seqNum))
|
|
816
946
|
.map(({ payload }) => {
|
|
817
947
|
if (payload._tag === 'upstream-advance') {
|
|
818
948
|
return {
|
|
819
949
|
payload: {
|
|
820
950
|
_tag: 'upstream-advance' as const,
|
|
821
951
|
newEvents: ReadonlyArray.dropWhile(payload.newEvents, (eventEncoded) =>
|
|
822
|
-
EventSequenceNumber.isGreaterThanOrEqual(cursor, eventEncoded.seqNum),
|
|
952
|
+
EventSequenceNumber.Client.isGreaterThanOrEqual(cursor, eventEncoded.seqNum),
|
|
823
953
|
),
|
|
824
954
|
},
|
|
825
955
|
}
|
|
@@ -865,7 +995,7 @@ const makePullQueueSet = Effect.gen(function* () {
|
|
|
865
995
|
|
|
866
996
|
const offer: PullQueueSet['offer'] = (item) =>
|
|
867
997
|
Effect.gen(function* () {
|
|
868
|
-
const seqNumStr = EventSequenceNumber.toString(item.leaderHead)
|
|
998
|
+
const seqNumStr = EventSequenceNumber.Client.toString(item.leaderHead)
|
|
869
999
|
if (cachedPayloads.has(seqNumStr)) {
|
|
870
1000
|
cachedPayloads.get(seqNumStr)!.push(item.payload)
|
|
871
1001
|
} else {
|
|
@@ -890,26 +1020,35 @@ const makePullQueueSet = Effect.gen(function* () {
|
|
|
890
1020
|
}
|
|
891
1021
|
})
|
|
892
1022
|
|
|
1023
|
+
/**
|
|
1024
|
+
* Validate a client-provided batch before it is admitted to the leader queue.
|
|
1025
|
+
* Ensures the numbers form a strictly increasing chain and that the first
|
|
1026
|
+
* event sits ahead of the current push head.
|
|
1027
|
+
*/
|
|
893
1028
|
const validatePushBatch = (
|
|
894
|
-
batch: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>,
|
|
895
|
-
pushHead: EventSequenceNumber.
|
|
1029
|
+
batch: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>,
|
|
1030
|
+
pushHead: EventSequenceNumber.Client.Composite,
|
|
896
1031
|
) =>
|
|
897
1032
|
Effect.gen(function* () {
|
|
898
1033
|
if (batch.length === 0) {
|
|
899
1034
|
return
|
|
900
1035
|
}
|
|
901
1036
|
|
|
902
|
-
//
|
|
1037
|
+
// Example: session A already enqueued e1…e6 while session B (same client, different
|
|
1038
|
+
// session) still believes the head is e1 and submits [e2, e7, e8]. The numbers look
|
|
1039
|
+
// monotonic from B’s perspective, but we must reject and force B to rebase locally
|
|
1040
|
+
// so the leader never regresses.
|
|
903
1041
|
for (let i = 1; i < batch.length; i++) {
|
|
904
|
-
if (EventSequenceNumber.isGreaterThanOrEqual(batch[i - 1]!.seqNum, batch[i]!.seqNum)) {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1042
|
+
if (EventSequenceNumber.Client.isGreaterThanOrEqual(batch[i - 1]!.seqNum, batch[i]!.seqNum)) {
|
|
1043
|
+
return yield* LeaderAheadError.make({
|
|
1044
|
+
minimumExpectedNum: batch[i - 1]!.seqNum,
|
|
1045
|
+
providedNum: batch[i]!.seqNum,
|
|
1046
|
+
})
|
|
908
1047
|
}
|
|
909
1048
|
}
|
|
910
1049
|
|
|
911
1050
|
// Make sure smallest sequence number is > pushHead
|
|
912
|
-
if (EventSequenceNumber.isGreaterThanOrEqual(pushHead, batch[0]!.seqNum)) {
|
|
1051
|
+
if (EventSequenceNumber.Client.isGreaterThanOrEqual(pushHead, batch[0]!.seqNum)) {
|
|
913
1052
|
return yield* LeaderAheadError.make({
|
|
914
1053
|
minimumExpectedNum: pushHead,
|
|
915
1054
|
providedNum: batch[0]!.seqNum,
|