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