@livestore/common 0.3.0-dev.9 → 0.3.1-dev.0
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/LICENSE +201 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/fixture.d.ts +83 -221
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/__tests__/fixture.js +33 -11
- package/dist/__tests__/fixture.js.map +1 -1
- package/dist/adapter-types.d.ts +120 -64
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +39 -8
- package/dist/adapter-types.js.map +1 -1
- package/dist/bounded-collections.d.ts.map +1 -1
- package/dist/debug-info.d.ts +1 -1
- package/dist/debug-info.d.ts.map +1 -1
- package/dist/debug-info.js +1 -0
- package/dist/debug-info.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +390 -0
- package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-client-session.js +97 -0
- package/dist/devtools/devtools-messages-client-session.js.map +1 -0
- package/dist/devtools/devtools-messages-common.d.ts +68 -0
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-common.js +60 -0
- package/dist/devtools/devtools-messages-common.js.map +1 -0
- package/dist/devtools/devtools-messages-leader.d.ts +394 -0
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-leader.js +147 -0
- package/dist/devtools/devtools-messages-leader.js.map +1 -0
- package/dist/devtools/devtools-messages.d.ts +3 -580
- package/dist/devtools/devtools-messages.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.js +3 -174
- package/dist/devtools/devtools-messages.js.map +1 -1
- package/dist/devtools/devtools-sessioninfo.d.ts +32 -0
- package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -0
- package/dist/devtools/devtools-sessioninfo.js +36 -0
- package/dist/devtools/devtools-sessioninfo.js.map +1 -0
- package/dist/devtools/mod.d.ts +55 -0
- package/dist/devtools/mod.d.ts.map +1 -0
- package/dist/devtools/mod.js +33 -0
- package/dist/devtools/mod.js.map +1 -0
- package/dist/index.d.ts +7 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -9
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +36 -11
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +426 -252
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/connection.d.ts +34 -6
- package/dist/leader-thread/connection.d.ts.map +1 -1
- package/dist/leader-thread/connection.js +22 -7
- package/dist/leader-thread/connection.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts +27 -0
- package/dist/leader-thread/eventlog.d.ts.map +1 -0
- package/dist/leader-thread/eventlog.js +119 -0
- package/dist/leader-thread/eventlog.js.map +1 -0
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +155 -80
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +22 -9
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +67 -45
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/materialize-event.d.ts +16 -0
- package/dist/leader-thread/materialize-event.d.ts.map +1 -0
- package/dist/leader-thread/materialize-event.js +109 -0
- package/dist/leader-thread/materialize-event.js.map +1 -0
- package/dist/leader-thread/mod.d.ts +1 -1
- package/dist/leader-thread/mod.d.ts.map +1 -1
- package/dist/leader-thread/mod.js +1 -1
- package/dist/leader-thread/mod.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts +4 -2
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +28 -32
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.d.ts +2 -5
- package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +2 -4
- package/dist/leader-thread/shutdown-channel.js.map +1 -1
- package/dist/leader-thread/types.d.ts +79 -38
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js +1 -3
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/make-client-session.d.ts +23 -0
- package/dist/make-client-session.d.ts.map +1 -0
- package/dist/make-client-session.js +57 -0
- package/dist/make-client-session.js.map +1 -0
- package/dist/materializer-helper.d.ts +23 -0
- package/dist/materializer-helper.d.ts.map +1 -0
- package/dist/materializer-helper.js +86 -0
- package/dist/materializer-helper.js.map +1 -0
- package/dist/otel.d.ts +2 -0
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +5 -0
- package/dist/otel.js.map +1 -1
- package/dist/rematerialize-from-eventlog.d.ts +14 -0
- package/dist/rematerialize-from-eventlog.d.ts.map +1 -0
- package/dist/rematerialize-from-eventlog.js +64 -0
- package/dist/rematerialize-from-eventlog.js.map +1 -0
- package/dist/schema/EventDef.d.ts +146 -0
- package/dist/schema/EventDef.d.ts.map +1 -0
- package/dist/schema/EventDef.js +58 -0
- package/dist/schema/EventDef.js.map +1 -0
- package/dist/schema/EventSequenceNumber.d.ts +57 -0
- package/dist/schema/EventSequenceNumber.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber.js +82 -0
- package/dist/schema/EventSequenceNumber.js.map +1 -0
- package/dist/schema/EventSequenceNumber.test.d.ts +2 -0
- package/dist/schema/EventSequenceNumber.test.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber.test.js +11 -0
- package/dist/schema/EventSequenceNumber.test.js.map +1 -0
- package/dist/schema/LiveStoreEvent.d.ts +257 -0
- package/dist/schema/LiveStoreEvent.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent.js +117 -0
- package/dist/schema/LiveStoreEvent.js.map +1 -0
- package/dist/schema/events.d.ts +2 -0
- package/dist/schema/events.d.ts.map +1 -0
- package/dist/schema/events.js +2 -0
- package/dist/schema/events.js.map +1 -0
- package/dist/schema/mod.d.ts +8 -6
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +8 -6
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/schema.d.ts +50 -32
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +36 -43
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/state/mod.d.ts +3 -0
- package/dist/schema/state/mod.d.ts.map +1 -0
- package/dist/schema/state/mod.js +3 -0
- package/dist/schema/state/mod.js.map +1 -0
- package/dist/schema/state/sqlite/client-document-def.d.ts +223 -0
- package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -0
- package/dist/schema/state/sqlite/client-document-def.js +170 -0
- package/dist/schema/state/sqlite/client-document-def.js.map +1 -0
- package/dist/schema/state/sqlite/client-document-def.test.d.ts +2 -0
- package/dist/schema/state/sqlite/client-document-def.test.d.ts.map +1 -0
- package/dist/schema/state/sqlite/client-document-def.test.js +201 -0
- package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +69 -0
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +71 -0
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/validate.d.ts +3 -0
- package/dist/schema/state/sqlite/db-schema/ast/validate.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/validate.js +12 -0
- package/dist/schema/state/sqlite/db-schema/ast/validate.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +90 -0
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +87 -0
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.d.ts +2 -0
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +29 -0
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +90 -0
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js +41 -0
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/hash.d.ts +2 -0
- package/dist/schema/state/sqlite/db-schema/hash.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/hash.js +14 -0
- package/dist/schema/state/sqlite/db-schema/hash.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/mod.d.ts +3 -0
- package/dist/schema/state/sqlite/db-schema/mod.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/mod.js +3 -0
- package/dist/schema/state/sqlite/db-schema/mod.js.map +1 -0
- package/dist/schema/state/sqlite/mod.d.ts +17 -0
- package/dist/schema/state/sqlite/mod.d.ts.map +1 -0
- package/dist/schema/state/sqlite/mod.js +41 -0
- package/dist/schema/state/sqlite/mod.js.map +1 -0
- package/dist/schema/state/sqlite/query-builder/api.d.ts +294 -0
- package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -0
- package/dist/schema/state/sqlite/query-builder/api.js +6 -0
- package/dist/schema/state/sqlite/query-builder/api.js.map +1 -0
- package/dist/schema/state/sqlite/query-builder/astToSql.d.ts +7 -0
- package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -0
- package/dist/schema/state/sqlite/query-builder/astToSql.js +190 -0
- package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -0
- package/dist/schema/state/sqlite/query-builder/impl.d.ts +7 -0
- package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -0
- package/dist/schema/state/sqlite/query-builder/impl.js +286 -0
- package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -0
- package/dist/schema/state/sqlite/query-builder/impl.test.d.ts +87 -0
- package/dist/schema/state/sqlite/query-builder/impl.test.d.ts.map +1 -0
- package/dist/schema/state/sqlite/query-builder/impl.test.js +563 -0
- package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -0
- package/dist/{query-builder → schema/state/sqlite/query-builder}/mod.d.ts +7 -0
- package/dist/schema/state/sqlite/query-builder/mod.d.ts.map +1 -0
- package/dist/{query-builder → schema/state/sqlite/query-builder}/mod.js +7 -0
- package/dist/schema/state/sqlite/query-builder/mod.js.map +1 -0
- package/dist/schema/state/sqlite/schema-helpers.d.ts.map +1 -0
- package/dist/schema/{schema-helpers.js → state/sqlite/schema-helpers.js} +1 -1
- package/dist/schema/state/sqlite/schema-helpers.js.map +1 -0
- package/dist/schema/state/sqlite/system-tables.d.ts +574 -0
- package/dist/schema/state/sqlite/system-tables.d.ts.map +1 -0
- package/dist/schema/state/sqlite/system-tables.js +88 -0
- package/dist/schema/state/sqlite/system-tables.js.map +1 -0
- package/dist/schema/state/sqlite/table-def.d.ts +84 -0
- package/dist/schema/state/sqlite/table-def.d.ts.map +1 -0
- package/dist/schema/state/sqlite/table-def.js +36 -0
- package/dist/schema/state/sqlite/table-def.js.map +1 -0
- package/dist/schema-management/common.d.ts +7 -7
- package/dist/schema-management/common.d.ts.map +1 -1
- package/dist/schema-management/common.js.map +1 -1
- package/dist/schema-management/migrations.d.ts +6 -6
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +27 -18
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-schema.d.ts +8 -0
- package/dist/schema-management/validate-schema.d.ts.map +1 -0
- package/dist/schema-management/validate-schema.js +39 -0
- package/dist/schema-management/validate-schema.js.map +1 -0
- package/dist/sql-queries/misc.d.ts.map +1 -1
- package/dist/sql-queries/sql-queries.d.ts +1 -1
- package/dist/sql-queries/sql-queries.d.ts.map +1 -1
- package/dist/sql-queries/sql-queries.js.map +1 -1
- package/dist/sql-queries/sql-query-builder.d.ts +1 -1
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
- package/dist/sql-queries/sql-query-builder.js.map +1 -1
- package/dist/sql-queries/types.d.ts +2 -1
- package/dist/sql-queries/types.d.ts.map +1 -1
- package/dist/sql-queries/types.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +40 -19
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +149 -73
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/next/compact-events.d.ts.map +1 -1
- package/dist/sync/next/compact-events.js +38 -35
- package/dist/sync/next/compact-events.js.map +1 -1
- package/dist/sync/next/facts.d.ts +21 -21
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +11 -11
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +9 -7
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +10 -5
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/history-dag.d.ts +0 -2
- package/dist/sync/next/history-dag.d.ts.map +1 -1
- package/dist/sync/next/history-dag.js +16 -14
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +10 -8
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +18 -10
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/compact-events.calculator.test.js +39 -34
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
- package/dist/sync/next/test/compact-events.test.js +77 -77
- package/dist/sync/next/test/compact-events.test.js.map +1 -1
- package/dist/sync/next/test/{mutation-fixtures.d.ts → event-fixtures.d.ts} +35 -25
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -0
- package/dist/sync/next/test/{mutation-fixtures.js → event-fixtures.js} +83 -38
- package/dist/sync/next/test/event-fixtures.js.map +1 -0
- package/dist/sync/next/test/mod.d.ts +1 -1
- package/dist/sync/next/test/mod.d.ts.map +1 -1
- package/dist/sync/next/test/mod.js +1 -1
- package/dist/sync/next/test/mod.js.map +1 -1
- package/dist/sync/sync.d.ts +46 -21
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js +10 -6
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/syncstate.d.ts +193 -84
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +305 -151
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +267 -303
- package/dist/sync/syncstate.test.js.map +1 -1
- 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 +4 -4
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/util.d.ts +2 -2
- package/dist/util.d.ts.map +1 -1
- package/dist/version.d.ts +3 -3
- package/dist/version.js +3 -3
- package/package.json +11 -4
- package/src/__tests__/fixture.ts +36 -15
- package/src/adapter-types.ts +107 -68
- package/src/debug-info.ts +1 -0
- package/src/devtools/devtools-messages-client-session.ts +142 -0
- package/src/devtools/devtools-messages-common.ts +115 -0
- package/src/devtools/devtools-messages-leader.ts +191 -0
- package/src/devtools/devtools-messages.ts +3 -246
- package/src/devtools/devtools-sessioninfo.ts +101 -0
- package/src/devtools/mod.ts +59 -0
- package/src/index.ts +7 -9
- package/src/leader-thread/LeaderSyncProcessor.ts +664 -394
- package/src/leader-thread/connection.ts +54 -9
- package/src/leader-thread/eventlog.ts +199 -0
- package/src/leader-thread/leader-worker-devtools.ts +227 -104
- package/src/leader-thread/make-leader-thread-layer.ts +121 -72
- package/src/leader-thread/materialize-event.ts +173 -0
- package/src/leader-thread/mod.ts +1 -1
- package/src/leader-thread/recreate-db.ts +33 -38
- package/src/leader-thread/shutdown-channel.ts +2 -4
- package/src/leader-thread/types.ts +84 -46
- package/src/make-client-session.ts +136 -0
- package/src/materializer-helper.ts +138 -0
- package/src/otel.ts +8 -0
- package/src/rematerialize-from-eventlog.ts +117 -0
- package/src/schema/EventDef.ts +227 -0
- package/src/schema/EventSequenceNumber.test.ts +12 -0
- package/src/schema/EventSequenceNumber.ts +121 -0
- package/src/schema/LiveStoreEvent.ts +240 -0
- package/src/schema/events.ts +1 -0
- package/src/schema/mod.ts +8 -6
- package/src/schema/schema.ts +88 -84
- package/src/schema/state/mod.ts +2 -0
- package/src/schema/state/sqlite/client-document-def.test.ts +238 -0
- package/src/schema/state/sqlite/client-document-def.ts +444 -0
- package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +142 -0
- package/src/schema/state/sqlite/db-schema/ast/validate.ts +13 -0
- package/src/schema/state/sqlite/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +206 -0
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +35 -0
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +242 -0
- package/src/schema/state/sqlite/db-schema/dsl/mod.ts +222 -0
- package/src/schema/state/sqlite/db-schema/hash.ts +14 -0
- package/src/schema/state/sqlite/db-schema/mod.ts +2 -0
- package/src/schema/state/sqlite/mod.ts +73 -0
- package/src/schema/state/sqlite/query-builder/api.ts +440 -0
- package/src/schema/state/sqlite/query-builder/astToSql.ts +232 -0
- package/src/schema/state/sqlite/query-builder/impl.test.ts +617 -0
- package/src/schema/state/sqlite/query-builder/impl.ts +351 -0
- package/src/{query-builder → schema/state/sqlite/query-builder}/mod.ts +7 -0
- package/src/schema/{schema-helpers.ts → state/sqlite/schema-helpers.ts} +1 -1
- package/src/schema/state/sqlite/system-tables.ts +117 -0
- package/src/schema/state/sqlite/table-def.ts +197 -0
- package/src/schema-management/common.ts +7 -7
- package/src/schema-management/migrations.ts +37 -31
- package/src/schema-management/validate-schema.ts +61 -0
- package/src/sql-queries/sql-queries.ts +1 -1
- package/src/sql-queries/sql-query-builder.ts +1 -2
- package/src/sql-queries/types.ts +3 -1
- package/src/sync/ClientSessionSyncProcessor.ts +218 -94
- package/src/sync/next/compact-events.ts +38 -35
- package/src/sync/next/facts.ts +43 -41
- package/src/sync/next/history-dag-common.ts +17 -10
- package/src/sync/next/history-dag.ts +16 -17
- package/src/sync/next/rebase-events.ts +29 -17
- package/src/sync/next/test/compact-events.calculator.test.ts +46 -46
- package/src/sync/next/test/compact-events.test.ts +79 -79
- package/src/sync/next/test/event-fixtures.ts +228 -0
- package/src/sync/next/test/mod.ts +1 -1
- package/src/sync/sync.ts +46 -21
- package/src/sync/syncstate.test.ts +312 -345
- package/src/sync/syncstate.ts +414 -224
- package/src/sync/validate-push-payload.ts +6 -6
- package/src/version.ts +3 -3
- package/dist/derived-mutations.d.ts +0 -109
- package/dist/derived-mutations.d.ts.map +0 -1
- package/dist/derived-mutations.js +0 -54
- package/dist/derived-mutations.js.map +0 -1
- package/dist/derived-mutations.test.d.ts +0 -2
- package/dist/derived-mutations.test.d.ts.map +0 -1
- package/dist/derived-mutations.test.js +0 -93
- package/dist/derived-mutations.test.js.map +0 -1
- package/dist/devtools/devtools-bridge.d.ts +0 -13
- package/dist/devtools/devtools-bridge.d.ts.map +0 -1
- package/dist/devtools/devtools-bridge.js +0 -2
- package/dist/devtools/devtools-bridge.js.map +0 -1
- package/dist/devtools/devtools-window-message.d.ts +0 -29
- package/dist/devtools/devtools-window-message.d.ts.map +0 -1
- package/dist/devtools/devtools-window-message.js +0 -33
- package/dist/devtools/devtools-window-message.js.map +0 -1
- package/dist/devtools/index.d.ts +0 -42
- package/dist/devtools/index.d.ts.map +0 -1
- package/dist/devtools/index.js +0 -48
- package/dist/devtools/index.js.map +0 -1
- package/dist/init-singleton-tables.d.ts +0 -4
- package/dist/init-singleton-tables.d.ts.map +0 -1
- package/dist/init-singleton-tables.js +0 -16
- package/dist/init-singleton-tables.js.map +0 -1
- package/dist/leader-thread/apply-mutation.d.ts +0 -11
- package/dist/leader-thread/apply-mutation.d.ts.map +0 -1
- package/dist/leader-thread/apply-mutation.js +0 -107
- package/dist/leader-thread/apply-mutation.js.map +0 -1
- package/dist/leader-thread/leader-sync-processor.d.ts +0 -47
- package/dist/leader-thread/leader-sync-processor.d.ts.map +0 -1
- package/dist/leader-thread/leader-sync-processor.js +0 -430
- package/dist/leader-thread/leader-sync-processor.js.map +0 -1
- package/dist/leader-thread/mutationlog.d.ts +0 -10
- package/dist/leader-thread/mutationlog.d.ts.map +0 -1
- package/dist/leader-thread/mutationlog.js +0 -28
- package/dist/leader-thread/mutationlog.js.map +0 -1
- package/dist/leader-thread/pull-queue-set.d.ts +0 -7
- package/dist/leader-thread/pull-queue-set.d.ts.map +0 -1
- package/dist/leader-thread/pull-queue-set.js +0 -39
- package/dist/leader-thread/pull-queue-set.js.map +0 -1
- package/dist/mutation.d.ts +0 -20
- package/dist/mutation.d.ts.map +0 -1
- package/dist/mutation.js +0 -57
- package/dist/mutation.js.map +0 -1
- package/dist/query-builder/api.d.ts +0 -190
- package/dist/query-builder/api.d.ts.map +0 -1
- package/dist/query-builder/api.js +0 -8
- package/dist/query-builder/api.js.map +0 -1
- package/dist/query-builder/impl.d.ts +0 -12
- package/dist/query-builder/impl.d.ts.map +0 -1
- package/dist/query-builder/impl.js +0 -244
- package/dist/query-builder/impl.js.map +0 -1
- package/dist/query-builder/impl.test.d.ts +0 -2
- package/dist/query-builder/impl.test.d.ts.map +0 -1
- package/dist/query-builder/impl.test.js +0 -212
- package/dist/query-builder/impl.test.js.map +0 -1
- package/dist/query-builder/mod.d.ts.map +0 -1
- package/dist/query-builder/mod.js.map +0 -1
- package/dist/query-info.d.ts +0 -38
- package/dist/query-info.d.ts.map +0 -1
- package/dist/query-info.js +0 -7
- package/dist/query-info.js.map +0 -1
- package/dist/rehydrate-from-mutationlog.d.ts +0 -14
- package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
- package/dist/rehydrate-from-mutationlog.js +0 -66
- package/dist/rehydrate-from-mutationlog.js.map +0 -1
- package/dist/schema/EventId.d.ts +0 -39
- package/dist/schema/EventId.d.ts.map +0 -1
- package/dist/schema/EventId.js +0 -38
- package/dist/schema/EventId.js.map +0 -1
- package/dist/schema/EventId.test.d.ts +0 -2
- package/dist/schema/EventId.test.d.ts.map +0 -1
- package/dist/schema/EventId.test.js +0 -11
- package/dist/schema/EventId.test.js.map +0 -1
- package/dist/schema/MutationEvent.d.ts +0 -167
- package/dist/schema/MutationEvent.d.ts.map +0 -1
- package/dist/schema/MutationEvent.js +0 -72
- package/dist/schema/MutationEvent.js.map +0 -1
- package/dist/schema/MutationEvent.test.d.ts +0 -2
- package/dist/schema/MutationEvent.test.d.ts.map +0 -1
- package/dist/schema/MutationEvent.test.js +0 -2
- package/dist/schema/MutationEvent.test.js.map +0 -1
- package/dist/schema/mutations.d.ts +0 -107
- package/dist/schema/mutations.d.ts.map +0 -1
- package/dist/schema/mutations.js +0 -42
- package/dist/schema/mutations.js.map +0 -1
- package/dist/schema/schema-helpers.d.ts.map +0 -1
- package/dist/schema/schema-helpers.js.map +0 -1
- package/dist/schema/system-tables.d.ts +0 -399
- package/dist/schema/system-tables.d.ts.map +0 -1
- package/dist/schema/system-tables.js +0 -59
- package/dist/schema/system-tables.js.map +0 -1
- package/dist/schema/table-def.d.ts +0 -156
- package/dist/schema/table-def.d.ts.map +0 -1
- package/dist/schema/table-def.js +0 -79
- package/dist/schema/table-def.js.map +0 -1
- package/dist/schema-management/validate-mutation-defs.d.ts +0 -8
- package/dist/schema-management/validate-mutation-defs.d.ts.map +0 -1
- package/dist/schema-management/validate-mutation-defs.js +0 -39
- package/dist/schema-management/validate-mutation-defs.js.map +0 -1
- package/dist/sync/client-session-sync-processor.d.ts +0 -45
- package/dist/sync/client-session-sync-processor.d.ts.map +0 -1
- package/dist/sync/client-session-sync-processor.js +0 -131
- package/dist/sync/client-session-sync-processor.js.map +0 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
- package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
- package/src/derived-mutations.test.ts +0 -101
- package/src/derived-mutations.ts +0 -170
- package/src/devtools/devtools-bridge.ts +0 -14
- package/src/devtools/devtools-window-message.ts +0 -27
- package/src/devtools/index.ts +0 -48
- package/src/init-singleton-tables.ts +0 -24
- package/src/leader-thread/apply-mutation.ts +0 -161
- package/src/leader-thread/mutationlog.ts +0 -46
- package/src/leader-thread/pull-queue-set.ts +0 -58
- package/src/mutation.ts +0 -91
- package/src/query-builder/api.ts +0 -289
- package/src/query-builder/impl.test.ts +0 -239
- package/src/query-builder/impl.ts +0 -285
- package/src/query-info.ts +0 -78
- package/src/rehydrate-from-mutationlog.ts +0 -119
- package/src/schema/EventId.test.ts +0 -12
- package/src/schema/EventId.ts +0 -60
- package/src/schema/MutationEvent.ts +0 -185
- package/src/schema/mutations.ts +0 -192
- package/src/schema/system-tables.ts +0 -105
- package/src/schema/table-def.ts +0 -343
- package/src/schema-management/validate-mutation-defs.ts +0 -63
- package/src/sync/next/test/mutation-fixtures.ts +0 -224
- package/tsconfig.json +0 -11
- /package/dist/schema/{schema-helpers.d.ts → state/sqlite/schema-helpers.d.ts} +0 -0
package/dist/sync/syncstate.js
CHANGED
@@ -1,278 +1,357 @@
|
|
1
|
-
import { shouldNeverHappen } from '@livestore/utils';
|
2
|
-
import { ReadonlyArray, Schema } from '@livestore/utils/effect';
|
3
|
-
import
|
4
|
-
import * as
|
1
|
+
import { casesHandled, LS_DEV, shouldNeverHappen } from '@livestore/utils';
|
2
|
+
import { Match, ReadonlyArray, Schema } from '@livestore/utils/effect';
|
3
|
+
import { UnexpectedError } from '../adapter-types.js';
|
4
|
+
import * as EventSequenceNumber from '../schema/EventSequenceNumber.js';
|
5
|
+
import * as LiveStoreEvent from '../schema/LiveStoreEvent.js';
|
5
6
|
/**
|
6
7
|
* SyncState represents the current sync state of a sync node relative to an upstream node.
|
7
8
|
* Events flow from local to upstream, with each state maintaining its own event head.
|
8
9
|
*
|
9
|
-
*
|
10
|
+
* Example:
|
10
11
|
* ```
|
11
|
-
*
|
12
|
-
* |
|
13
|
-
*
|
14
|
-
*
|
15
|
-
*
|
16
|
-
*
|
12
|
+
* +------------------------+
|
13
|
+
* | PENDING EVENTS |
|
14
|
+
* +------------------------+
|
15
|
+
* ▼ ▼
|
16
|
+
* Upstream Head Local Head
|
17
|
+
* (1,0) (1,1), (1,2), (2,0)
|
17
18
|
* ```
|
18
19
|
*
|
19
|
-
*
|
20
|
-
* -
|
21
|
-
*
|
22
|
-
* - Subject to rebase if rejected.
|
23
|
-
* - **Rollback Tail**: Events that are kept around temporarily for potential rollback until confirmed by upstream.
|
20
|
+
* **Pending Events**: Events awaiting acknowledgment from the upstream.
|
21
|
+
* - Can be confirmed or rejected by the upstream.
|
22
|
+
* - Subject to rebase if rejected.
|
24
23
|
*
|
25
24
|
* Payloads:
|
26
25
|
* - `PayloadUpstreamRebase`: Upstream has performed a rebase, so downstream must roll back to the specified event
|
27
26
|
* and rebase the pending events on top of the new events.
|
28
27
|
* - `PayloadUpstreamAdvance`: Upstream has advanced, so downstream must rebase the pending events on top of the new events.
|
29
|
-
* - `PayloadUpstreamTrimRollbackTail`: Upstream has advanced, so downstream can trim the rollback tail.
|
30
28
|
* - `PayloadLocalPush`: Local push payload
|
31
29
|
*
|
32
30
|
* Invariants:
|
33
31
|
* 1. **Chain Continuity**: Each event must reference its immediate parent.
|
34
32
|
* 2. **Head Ordering**: Upstream Head ≤ Local Head.
|
35
|
-
* 3. **
|
33
|
+
* 3. **Event number sequence**: Must follow the pattern (1,0)→(1,1)→(1,2)→(2,0).
|
36
34
|
*
|
37
|
-
*
|
38
|
-
*
|
35
|
+
* A few further notes to help form an intuition:
|
36
|
+
* - The goal is to keep the pending events as small as possible (i.e. to have synced with the next upstream node)
|
37
|
+
* - There are 2 cases for rebasing:
|
38
|
+
* - The conflicting event only conflicts with the pending events -> only (some of) the pending events need to be rolled back
|
39
|
+
*
|
40
|
+
* The `merge` function processes updates to the sync state based on incoming payloads,
|
41
|
+
* handling cases such as upstream rebase, advance and local push.
|
39
42
|
*/
|
40
43
|
export class SyncState extends Schema.Class('SyncState')({
|
41
|
-
pending: Schema.Array(
|
42
|
-
|
43
|
-
upstreamHead:
|
44
|
-
|
44
|
+
pending: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
45
|
+
/** What this node expects the next upstream node to have as its own local head */
|
46
|
+
upstreamHead: EventSequenceNumber.EventSequenceNumber,
|
47
|
+
/** Equivalent to `pending.at(-1)?.id` if there are pending events */
|
48
|
+
localHead: EventSequenceNumber.EventSequenceNumber,
|
45
49
|
}) {
|
46
|
-
toJSON = () => {
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
localHead: `(${this.localHead.global},${this.localHead.local})`,
|
52
|
-
};
|
53
|
-
};
|
50
|
+
toJSON = () => ({
|
51
|
+
pending: this.pending.map((e) => e.toJSON()),
|
52
|
+
upstreamHead: EventSequenceNumber.toString(this.upstreamHead),
|
53
|
+
localHead: EventSequenceNumber.toString(this.localHead),
|
54
|
+
});
|
54
55
|
}
|
56
|
+
/**
|
57
|
+
* This payload propagates a rebase from the upstream node
|
58
|
+
*/
|
55
59
|
export class PayloadUpstreamRebase extends Schema.TaggedStruct('upstream-rebase', {
|
56
|
-
/**
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
trimRollbackUntil: Schema.optional(EventId.EventId),
|
60
|
+
/** Events which need to be rolled back */
|
61
|
+
rollbackEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
62
|
+
/** Events which need to be applied after the rollback (already rebased by the upstream node) */
|
63
|
+
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
61
64
|
}) {
|
62
65
|
}
|
63
66
|
export class PayloadUpstreamAdvance extends Schema.TaggedStruct('upstream-advance', {
|
64
|
-
newEvents: Schema.Array(
|
65
|
-
/** Trim rollback tail up to this event (inclusive). */
|
66
|
-
trimRollbackUntil: Schema.optional(EventId.EventId),
|
67
|
+
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
67
68
|
}) {
|
68
69
|
}
|
69
70
|
export class PayloadLocalPush extends Schema.TaggedStruct('local-push', {
|
70
|
-
newEvents: Schema.Array(
|
71
|
+
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
71
72
|
}) {
|
72
73
|
}
|
73
74
|
export class Payload extends Schema.Union(PayloadUpstreamRebase, PayloadUpstreamAdvance, PayloadLocalPush) {
|
74
75
|
}
|
75
|
-
export
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
76
|
+
export class PayloadUpstream extends Schema.Union(PayloadUpstreamRebase, PayloadUpstreamAdvance) {
|
77
|
+
}
|
78
|
+
/** Only used for debugging purposes */
|
79
|
+
export class MergeContext extends Schema.Class('MergeContext')({
|
80
|
+
payload: Payload,
|
81
|
+
syncState: SyncState,
|
82
|
+
}) {
|
83
|
+
toJSON = () => {
|
84
|
+
const payload = Match.value(this.payload).pipe(Match.tag('local-push', () => ({
|
85
|
+
_tag: 'local-push',
|
86
|
+
newEvents: this.payload.newEvents.map((e) => e.toJSON()),
|
87
|
+
})), Match.tag('upstream-advance', () => ({
|
88
|
+
_tag: 'upstream-advance',
|
89
|
+
newEvents: this.payload.newEvents.map((e) => e.toJSON()),
|
90
|
+
})), Match.tag('upstream-rebase', (payload) => ({
|
91
|
+
_tag: 'upstream-rebase',
|
92
|
+
newEvents: payload.newEvents.map((e) => e.toJSON()),
|
93
|
+
rollbackEvents: payload.rollbackEvents.map((e) => e.toJSON()),
|
94
|
+
})), Match.exhaustive);
|
95
|
+
return {
|
96
|
+
payload,
|
97
|
+
syncState: this.syncState.toJSON(),
|
98
|
+
};
|
85
99
|
};
|
100
|
+
}
|
101
|
+
export class MergeResultAdvance extends Schema.Class('MergeResultAdvance')({
|
102
|
+
_tag: Schema.Literal('advance'),
|
103
|
+
newSyncState: SyncState,
|
104
|
+
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
105
|
+
/** Events which were previously pending but are now confirmed */
|
106
|
+
confirmedEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
107
|
+
mergeContext: MergeContext,
|
108
|
+
}) {
|
109
|
+
toJSON = () => {
|
110
|
+
return {
|
111
|
+
_tag: this._tag,
|
112
|
+
newSyncState: this.newSyncState.toJSON(),
|
113
|
+
newEvents: this.newEvents.map((e) => e.toJSON()),
|
114
|
+
confirmedEvents: this.confirmedEvents.map((e) => e.toJSON()),
|
115
|
+
mergeContext: this.mergeContext.toJSON(),
|
116
|
+
};
|
117
|
+
};
|
118
|
+
}
|
119
|
+
export class MergeResultRebase extends Schema.Class('MergeResultRebase')({
|
120
|
+
_tag: Schema.Literal('rebase'),
|
121
|
+
newSyncState: SyncState,
|
122
|
+
newEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
123
|
+
/** Events which need to be rolled back */
|
124
|
+
rollbackEvents: Schema.Array(LiveStoreEvent.EncodedWithMeta),
|
125
|
+
mergeContext: MergeContext,
|
126
|
+
}) {
|
127
|
+
toJSON = () => {
|
128
|
+
return {
|
129
|
+
_tag: this._tag,
|
130
|
+
newSyncState: this.newSyncState.toJSON(),
|
131
|
+
newEvents: this.newEvents.map((e) => e.toJSON()),
|
132
|
+
rollbackEvents: this.rollbackEvents.map((e) => e.toJSON()),
|
133
|
+
mergeContext: this.mergeContext.toJSON(),
|
134
|
+
};
|
135
|
+
};
|
136
|
+
}
|
137
|
+
export class MergeResultReject extends Schema.Class('MergeResultReject')({
|
138
|
+
_tag: Schema.Literal('reject'),
|
139
|
+
/** The minimum id that the new events must have */
|
140
|
+
expectedMinimumId: EventSequenceNumber.EventSequenceNumber,
|
141
|
+
mergeContext: MergeContext,
|
142
|
+
}) {
|
143
|
+
toJSON = () => {
|
144
|
+
return {
|
145
|
+
_tag: this._tag,
|
146
|
+
expectedMinimumId: EventSequenceNumber.toString(this.expectedMinimumId),
|
147
|
+
mergeContext: this.mergeContext.toJSON(),
|
148
|
+
};
|
149
|
+
};
|
150
|
+
}
|
151
|
+
export class MergeResultUnexpectedError extends Schema.Class('MergeResultUnexpectedError')({
|
152
|
+
_tag: Schema.Literal('unexpected-error'),
|
153
|
+
cause: UnexpectedError,
|
154
|
+
}) {
|
155
|
+
}
|
156
|
+
export class MergeResult extends Schema.Union(MergeResultAdvance, MergeResultRebase, MergeResultReject, MergeResultUnexpectedError) {
|
157
|
+
}
|
158
|
+
const unexpectedError = (cause) => {
|
159
|
+
if (LS_DEV) {
|
160
|
+
debugger;
|
161
|
+
}
|
162
|
+
return MergeResultUnexpectedError.make({
|
163
|
+
_tag: 'unexpected-error',
|
164
|
+
cause: new UnexpectedError({ cause }),
|
165
|
+
});
|
166
|
+
};
|
167
|
+
// TODO Idea: call merge recursively through hierarchy levels
|
168
|
+
/*
|
169
|
+
Idea: have a map that maps from `globalEventSequenceNumber` to Array<ClientEvents>
|
170
|
+
The same applies to even further hierarchy levels
|
171
|
+
|
172
|
+
TODO: possibly even keep the client events in a separate table in the client leader
|
173
|
+
*/
|
174
|
+
export const merge = ({ syncState, payload, isClientEvent, isEqualEvent, ignoreClientEvents = false, }) => {
|
175
|
+
validateSyncState(syncState);
|
176
|
+
validatePayload(payload);
|
177
|
+
const mergeContext = MergeContext.make({ payload, syncState });
|
86
178
|
switch (payload._tag) {
|
87
179
|
case 'upstream-rebase': {
|
88
|
-
|
89
|
-
const rollbackIndex = syncState.rollbackTail.findIndex((event) => EventId.isEqual(event.id, payload.rollbackUntil));
|
90
|
-
if (rollbackIndex === -1) {
|
91
|
-
return shouldNeverHappen(`Rollback event not found in rollback tail. Rollback until: [${payload.rollbackUntil.global},${payload.rollbackUntil.local}]. Rollback tail: [${syncState.rollbackTail.map((e) => e.toString()).join(', ')}]`);
|
92
|
-
}
|
93
|
-
const eventsToRollback = [...syncState.rollbackTail.slice(rollbackIndex), ...syncState.pending];
|
180
|
+
const rollbackEvents = [...payload.rollbackEvents, ...syncState.pending];
|
94
181
|
// Get the last new event's ID as the new upstream head
|
95
|
-
const newUpstreamHead = payload.newEvents.at(-1)?.
|
182
|
+
const newUpstreamHead = payload.newEvents.at(-1)?.seqNum ?? syncState.upstreamHead;
|
96
183
|
// Rebase pending events on top of the new events
|
97
184
|
const rebasedPending = rebaseEvents({
|
98
185
|
events: syncState.pending,
|
99
|
-
|
100
|
-
|
186
|
+
baseEventSequenceNumber: newUpstreamHead,
|
187
|
+
isClientEvent,
|
101
188
|
});
|
102
|
-
return {
|
189
|
+
return validateMergeResult(MergeResultRebase.make({
|
103
190
|
_tag: 'rebase',
|
104
191
|
newSyncState: new SyncState({
|
105
192
|
pending: rebasedPending,
|
106
|
-
rollbackTail: trimRollbackTail([...syncState.rollbackTail.slice(0, rollbackIndex), ...payload.newEvents]),
|
107
193
|
upstreamHead: newUpstreamHead,
|
108
|
-
localHead: rebasedPending.at(-1)?.
|
194
|
+
localHead: rebasedPending.at(-1)?.seqNum ?? newUpstreamHead,
|
109
195
|
}),
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
};
|
196
|
+
newEvents: [...payload.newEvents, ...rebasedPending],
|
197
|
+
rollbackEvents,
|
198
|
+
mergeContext,
|
199
|
+
}));
|
114
200
|
}
|
201
|
+
// #region upstream-advance
|
115
202
|
case 'upstream-advance': {
|
116
203
|
if (payload.newEvents.length === 0) {
|
117
|
-
return {
|
204
|
+
return validateMergeResult(MergeResultAdvance.make({
|
118
205
|
_tag: 'advance',
|
119
206
|
newSyncState: new SyncState({
|
120
207
|
pending: syncState.pending,
|
121
|
-
rollbackTail: trimRollbackTail(syncState.rollbackTail),
|
122
208
|
upstreamHead: syncState.upstreamHead,
|
123
209
|
localHead: syncState.localHead,
|
124
210
|
}),
|
125
|
-
previousSyncState: syncState,
|
126
211
|
newEvents: [],
|
127
|
-
|
212
|
+
confirmedEvents: [],
|
213
|
+
mergeContext: mergeContext,
|
214
|
+
}));
|
128
215
|
}
|
129
|
-
// Validate that newEvents are sorted in ascending order by
|
216
|
+
// Validate that newEvents are sorted in ascending order by eventNum
|
130
217
|
for (let i = 1; i < payload.newEvents.length; i++) {
|
131
|
-
if (
|
132
|
-
return
|
218
|
+
if (EventSequenceNumber.isGreaterThan(payload.newEvents[i - 1].seqNum, payload.newEvents[i].seqNum)) {
|
219
|
+
return unexpectedError(`Events must be sorted in ascending order by event number. Received: [${payload.newEvents.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`);
|
133
220
|
}
|
134
221
|
}
|
135
|
-
|
222
|
+
// Validate that incoming events are larger than upstream head
|
223
|
+
if (EventSequenceNumber.isGreaterThan(syncState.upstreamHead, payload.newEvents[0].seqNum) ||
|
224
|
+
EventSequenceNumber.isEqual(syncState.upstreamHead, payload.newEvents[0].seqNum)) {
|
225
|
+
return unexpectedError(`Incoming events must be greater than upstream head. Expected greater than: ${EventSequenceNumber.toString(syncState.upstreamHead)}. Received: [${payload.newEvents.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`);
|
226
|
+
}
|
227
|
+
const newUpstreamHead = payload.newEvents.at(-1).seqNum;
|
136
228
|
const divergentPendingIndex = findDivergencePoint({
|
137
229
|
existingEvents: syncState.pending,
|
138
230
|
incomingEvents: payload.newEvents,
|
139
231
|
isEqualEvent,
|
140
|
-
|
141
|
-
|
232
|
+
isClientEvent,
|
233
|
+
ignoreClientEvents,
|
142
234
|
});
|
235
|
+
// No divergent pending events, thus we can just advance (some of) the pending events
|
143
236
|
if (divergentPendingIndex === -1) {
|
144
|
-
const
|
145
|
-
const newEvents = payload.newEvents.filter((e) => !
|
237
|
+
const pendingEventSequenceNumbers = new Set(syncState.pending.map((e) => `${e.seqNum.global},${e.seqNum.client}`));
|
238
|
+
const newEvents = payload.newEvents.filter((e) => !pendingEventSequenceNumbers.has(`${e.seqNum.global},${e.seqNum.client}`));
|
146
239
|
// In the case where the incoming events are a subset of the pending events,
|
147
240
|
// we need to split the pending events into two groups:
|
148
241
|
// - pendingMatching: The pending events up to point where they match the incoming events
|
149
242
|
// - pendingRemaining: The pending events after the point where they match the incoming events
|
150
|
-
// The `
|
151
|
-
let
|
243
|
+
// The `clientIndexOffset` is used to account for the client events that are being ignored
|
244
|
+
let clientIndexOffset = 0;
|
152
245
|
const [pendingMatching, pendingRemaining] = ReadonlyArray.splitWhere(syncState.pending, (pendingEvent, index) => {
|
153
|
-
if (
|
154
|
-
|
246
|
+
if (ignoreClientEvents && isClientEvent(pendingEvent)) {
|
247
|
+
clientIndexOffset++;
|
155
248
|
return false;
|
156
249
|
}
|
157
|
-
const newEvent = payload.newEvents.at(index -
|
250
|
+
const newEvent = payload.newEvents.at(index - clientIndexOffset);
|
158
251
|
if (!newEvent) {
|
159
252
|
return true;
|
160
253
|
}
|
161
254
|
return isEqualEvent(pendingEvent, newEvent) === false;
|
162
255
|
});
|
163
|
-
|
164
|
-
const pendingAndNewEvents = [...pendingMatching, ...payload.newEvents].filter((event) => {
|
165
|
-
const eventIdStr = `${event.id.global},${event.id.local}`;
|
166
|
-
if (seenEventIds.has(eventIdStr)) {
|
167
|
-
return false;
|
168
|
-
}
|
169
|
-
seenEventIds.add(eventIdStr);
|
170
|
-
return true;
|
171
|
-
});
|
172
|
-
return {
|
256
|
+
return validateMergeResult(MergeResultAdvance.make({
|
173
257
|
_tag: 'advance',
|
174
258
|
newSyncState: new SyncState({
|
175
259
|
pending: pendingRemaining,
|
176
|
-
rollbackTail: trimRollbackTail([...syncState.rollbackTail, ...pendingAndNewEvents]),
|
177
260
|
upstreamHead: newUpstreamHead,
|
178
|
-
localHead: pendingRemaining.at(-1)?.
|
261
|
+
localHead: pendingRemaining.at(-1)?.seqNum ?? EventSequenceNumber.max(syncState.localHead, newUpstreamHead),
|
179
262
|
}),
|
180
|
-
previousSyncState: syncState,
|
181
263
|
newEvents,
|
182
|
-
|
264
|
+
confirmedEvents: pendingMatching,
|
265
|
+
mergeContext: mergeContext,
|
266
|
+
}));
|
183
267
|
}
|
184
268
|
else {
|
185
269
|
const divergentPending = syncState.pending.slice(divergentPendingIndex);
|
186
270
|
const rebasedPending = rebaseEvents({
|
187
271
|
events: divergentPending,
|
188
|
-
|
189
|
-
|
272
|
+
baseEventSequenceNumber: newUpstreamHead,
|
273
|
+
isClientEvent,
|
190
274
|
});
|
191
275
|
const divergentNewEventsIndex = findDivergencePoint({
|
192
276
|
existingEvents: payload.newEvents,
|
193
277
|
incomingEvents: syncState.pending,
|
194
278
|
isEqualEvent,
|
195
|
-
|
196
|
-
|
279
|
+
isClientEvent,
|
280
|
+
ignoreClientEvents,
|
197
281
|
});
|
198
|
-
return {
|
282
|
+
return validateMergeResult(MergeResultRebase.make({
|
199
283
|
_tag: 'rebase',
|
200
284
|
newSyncState: new SyncState({
|
201
285
|
pending: rebasedPending,
|
202
|
-
rollbackTail: trimRollbackTail([...syncState.rollbackTail, ...payload.newEvents]),
|
203
286
|
upstreamHead: newUpstreamHead,
|
204
|
-
localHead: rebasedPending.at(-1).
|
287
|
+
localHead: rebasedPending.at(-1).seqNum,
|
205
288
|
}),
|
206
|
-
previousSyncState: syncState,
|
207
289
|
newEvents: [...payload.newEvents.slice(divergentNewEventsIndex), ...rebasedPending],
|
208
|
-
|
209
|
-
|
290
|
+
rollbackEvents: divergentPending,
|
291
|
+
mergeContext,
|
292
|
+
}));
|
210
293
|
}
|
211
294
|
}
|
295
|
+
// #endregion
|
296
|
+
// This is the same as what's running in the sync backend
|
212
297
|
case 'local-push': {
|
213
298
|
if (payload.newEvents.length === 0) {
|
214
|
-
return {
|
299
|
+
return validateMergeResult(MergeResultAdvance.make({
|
300
|
+
_tag: 'advance',
|
301
|
+
newSyncState: syncState,
|
302
|
+
newEvents: [],
|
303
|
+
confirmedEvents: [],
|
304
|
+
mergeContext: mergeContext,
|
305
|
+
}));
|
215
306
|
}
|
216
307
|
const newEventsFirst = payload.newEvents.at(0);
|
217
|
-
const
|
218
|
-
if (
|
219
|
-
const expectedMinimumId =
|
220
|
-
return {
|
308
|
+
const invalidEventSequenceNumber = EventSequenceNumber.isGreaterThan(newEventsFirst.seqNum, syncState.localHead) === false;
|
309
|
+
if (invalidEventSequenceNumber) {
|
310
|
+
const expectedMinimumId = EventSequenceNumber.nextPair(syncState.localHead, true).seqNum;
|
311
|
+
return validateMergeResult(MergeResultReject.make({
|
312
|
+
_tag: 'reject',
|
313
|
+
expectedMinimumId,
|
314
|
+
mergeContext,
|
315
|
+
}));
|
221
316
|
}
|
222
317
|
else {
|
223
|
-
return {
|
318
|
+
return validateMergeResult(MergeResultAdvance.make({
|
224
319
|
_tag: 'advance',
|
225
320
|
newSyncState: new SyncState({
|
226
321
|
pending: [...syncState.pending, ...payload.newEvents],
|
227
|
-
rollbackTail: syncState.rollbackTail,
|
228
322
|
upstreamHead: syncState.upstreamHead,
|
229
|
-
localHead: payload.newEvents.at(-1).
|
323
|
+
localHead: payload.newEvents.at(-1).seqNum,
|
230
324
|
}),
|
231
|
-
previousSyncState: syncState,
|
232
325
|
newEvents: payload.newEvents,
|
233
|
-
|
326
|
+
confirmedEvents: [],
|
327
|
+
mergeContext: mergeContext,
|
328
|
+
}));
|
234
329
|
}
|
235
330
|
}
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
// if (startIndex === -1) {
|
240
|
-
// return shouldNeverHappen('New rollback start event not found in rollback tail')
|
241
|
-
// }
|
242
|
-
// // Keep only the events from the start index onwards
|
243
|
-
// const newRollbackTail = syncState.rollbackTail.slice(startIndex)
|
244
|
-
// return {
|
245
|
-
// _tag: 'advance',
|
246
|
-
// syncState: {
|
247
|
-
// pending: syncState.pending,
|
248
|
-
// rollbackTail: newRollbackTail,
|
249
|
-
// upstreamHead: syncState.upstreamHead,
|
250
|
-
// localHead: syncState.localHead,
|
251
|
-
// },
|
252
|
-
// newEvents: [],
|
253
|
-
// }
|
254
|
-
// }
|
331
|
+
default: {
|
332
|
+
casesHandled(payload);
|
333
|
+
}
|
255
334
|
}
|
256
335
|
};
|
257
336
|
/**
|
258
337
|
* Gets the index relative to `existingEvents` where the divergence point is
|
259
338
|
* by comparing each event in `existingEvents` to the corresponding event in `incomingEvents`
|
260
339
|
*/
|
261
|
-
const findDivergencePoint = ({ existingEvents, incomingEvents, isEqualEvent,
|
262
|
-
if (
|
263
|
-
const filteredExistingEvents = existingEvents.filter((event) => !
|
264
|
-
const
|
340
|
+
export const findDivergencePoint = ({ existingEvents, incomingEvents, isEqualEvent, isClientEvent, ignoreClientEvents, }) => {
|
341
|
+
if (ignoreClientEvents) {
|
342
|
+
const filteredExistingEvents = existingEvents.filter((event) => !isClientEvent(event));
|
343
|
+
const divergencePointWithoutClientEvents = findDivergencePoint({
|
265
344
|
existingEvents: filteredExistingEvents,
|
266
345
|
incomingEvents,
|
267
346
|
isEqualEvent,
|
268
|
-
|
269
|
-
|
347
|
+
isClientEvent,
|
348
|
+
ignoreClientEvents: false,
|
270
349
|
});
|
271
|
-
if (
|
350
|
+
if (divergencePointWithoutClientEvents === -1)
|
272
351
|
return -1;
|
273
|
-
const
|
352
|
+
const divergencePointEventSequenceNumber = existingEvents[divergencePointWithoutClientEvents].seqNum;
|
274
353
|
// Now find the divergence point in the original array
|
275
|
-
return existingEvents.findIndex((event) =>
|
354
|
+
return existingEvents.findIndex((event) => EventSequenceNumber.isEqual(event.seqNum, divergencePointEventSequenceNumber));
|
276
355
|
}
|
277
356
|
return existingEvents.findIndex((existingEvent, index) => {
|
278
357
|
const incomingEvent = incomingEvents[index];
|
@@ -280,13 +359,88 @@ const findDivergencePoint = ({ existingEvents, incomingEvents, isEqualEvent, isL
|
|
280
359
|
return incomingEvent && !isEqualEvent(existingEvent, incomingEvent);
|
281
360
|
});
|
282
361
|
};
|
283
|
-
const rebaseEvents = ({ events,
|
284
|
-
let
|
362
|
+
const rebaseEvents = ({ events, baseEventSequenceNumber, isClientEvent, }) => {
|
363
|
+
let prevEventSequenceNumber = baseEventSequenceNumber;
|
285
364
|
return events.map((event) => {
|
286
|
-
const isLocal =
|
287
|
-
const newEvent = event.rebase(
|
288
|
-
|
365
|
+
const isLocal = isClientEvent(event);
|
366
|
+
const newEvent = event.rebase(prevEventSequenceNumber, isLocal);
|
367
|
+
prevEventSequenceNumber = newEvent.seqNum;
|
289
368
|
return newEvent;
|
290
369
|
});
|
291
370
|
};
|
371
|
+
/**
|
372
|
+
* TODO: Implement this
|
373
|
+
*
|
374
|
+
* In certain scenarios e.g. when the client session has a queue of upstream update results,
|
375
|
+
* it could make sense to "flatten" update results into a single update result which the client session
|
376
|
+
* can process more efficiently which avoids push-threshing
|
377
|
+
*/
|
378
|
+
const _flattenMergeResults = (_updateResults) => { };
|
379
|
+
const validatePayload = (payload) => {
|
380
|
+
for (let i = 1; i < payload.newEvents.length; i++) {
|
381
|
+
if (EventSequenceNumber.isGreaterThanOrEqual(payload.newEvents[i - 1].seqNum, payload.newEvents[i].seqNum)) {
|
382
|
+
return unexpectedError(`Events must be ordered in monotonically ascending order by eventNum. Received: [${payload.newEvents.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`);
|
383
|
+
}
|
384
|
+
}
|
385
|
+
};
|
386
|
+
const validateSyncState = (syncState) => {
|
387
|
+
for (let i = 0; i < syncState.pending.length; i++) {
|
388
|
+
const event = syncState.pending[i];
|
389
|
+
const nextEvent = syncState.pending[i + 1];
|
390
|
+
if (nextEvent === undefined)
|
391
|
+
break; // Reached end of chain
|
392
|
+
if (EventSequenceNumber.isGreaterThanOrEqual(event.seqNum, nextEvent.seqNum)) {
|
393
|
+
shouldNeverHappen(`Events must be ordered in monotonically ascending order by eventNum. Received: [${syncState.pending.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`, {
|
394
|
+
event,
|
395
|
+
nextEvent,
|
396
|
+
});
|
397
|
+
}
|
398
|
+
// If the global id has increased, then the client id must be 0
|
399
|
+
const globalIdHasIncreased = nextEvent.seqNum.global > event.seqNum.global;
|
400
|
+
if (globalIdHasIncreased) {
|
401
|
+
if (nextEvent.seqNum.client !== 0) {
|
402
|
+
shouldNeverHappen(`New global events must point to clientId 0 in the parentSeqNum. Received: (${EventSequenceNumber.toString(nextEvent.seqNum)})`, syncState.pending, {
|
403
|
+
event,
|
404
|
+
nextEvent,
|
405
|
+
});
|
406
|
+
}
|
407
|
+
}
|
408
|
+
else {
|
409
|
+
// Otherwise, the parentSeqNum must be the same as the previous event's id
|
410
|
+
if (EventSequenceNumber.isEqual(nextEvent.parentSeqNum, event.seqNum) === false) {
|
411
|
+
shouldNeverHappen('Events must be linked in a continuous chain via the parentSeqNum', syncState.pending, {
|
412
|
+
event,
|
413
|
+
nextEvent,
|
414
|
+
});
|
415
|
+
}
|
416
|
+
}
|
417
|
+
}
|
418
|
+
};
|
419
|
+
const validateMergeResult = (mergeResult) => {
|
420
|
+
if (mergeResult._tag === 'unexpected-error' || mergeResult._tag === 'reject')
|
421
|
+
return mergeResult;
|
422
|
+
validateSyncState(mergeResult.newSyncState);
|
423
|
+
// Ensure local head is always greater than or equal to upstream head
|
424
|
+
if (EventSequenceNumber.isGreaterThan(mergeResult.newSyncState.upstreamHead, mergeResult.newSyncState.localHead)) {
|
425
|
+
shouldNeverHappen('Local head must be greater than or equal to upstream head', {
|
426
|
+
localHead: mergeResult.newSyncState.localHead,
|
427
|
+
upstreamHead: mergeResult.newSyncState.upstreamHead,
|
428
|
+
});
|
429
|
+
}
|
430
|
+
// Ensure new local head is greater than or equal to the previous local head
|
431
|
+
if (EventSequenceNumber.isGreaterThanOrEqual(mergeResult.newSyncState.localHead, mergeResult.mergeContext.syncState.localHead) === false) {
|
432
|
+
shouldNeverHappen('New local head must be greater than or equal to the previous local head', {
|
433
|
+
localHead: mergeResult.newSyncState.localHead,
|
434
|
+
previousLocalHead: mergeResult.mergeContext.syncState.localHead,
|
435
|
+
});
|
436
|
+
}
|
437
|
+
// Ensure new upstream head is greater than or equal to the previous upstream head
|
438
|
+
if (EventSequenceNumber.isGreaterThanOrEqual(mergeResult.newSyncState.upstreamHead, mergeResult.mergeContext.syncState.upstreamHead) === false) {
|
439
|
+
shouldNeverHappen('New upstream head must be greater than or equal to the previous upstream head', {
|
440
|
+
upstreamHead: mergeResult.newSyncState.upstreamHead,
|
441
|
+
previousUpstreamHead: mergeResult.mergeContext.syncState.upstreamHead,
|
442
|
+
});
|
443
|
+
}
|
444
|
+
return mergeResult;
|
445
|
+
};
|
292
446
|
//# sourceMappingURL=syncstate.js.map
|