@livestore/common 0.3.0-dev.3 → 0.3.0-dev.30
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 +128 -68
- 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 +389 -0
- package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-client-session.js +96 -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 +28 -0
- package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -0
- package/dist/devtools/devtools-sessioninfo.js +34 -0
- package/dist/devtools/devtools-sessioninfo.js.map +1 -0
- package/dist/devtools/mod.d.ts +39 -0
- package/dist/devtools/mod.d.ts.map +1 -0
- package/dist/devtools/mod.js +27 -0
- package/dist/devtools/mod.js.map +1 -0
- package/dist/index.d.ts +4 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -7
- 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 +589 -0
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -0
- package/dist/leader-thread/apply-event.d.ts +16 -0
- package/dist/leader-thread/apply-event.d.ts.map +1 -0
- package/dist/leader-thread/apply-event.js +103 -0
- package/dist/leader-thread/apply-event.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 +123 -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 +154 -132
- 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 +82 -47
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- 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 +35 -25
- 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 +86 -39
- 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/materializer-helper.d.ts +23 -0
- package/dist/materializer-helper.d.ts.map +1 -0
- package/dist/materializer-helper.js +70 -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/query-builder/api.d.ts +158 -55
- package/dist/query-builder/api.d.ts.map +1 -1
- package/dist/query-builder/api.js +3 -5
- package/dist/query-builder/api.js.map +1 -1
- package/dist/query-builder/astToSql.d.ts +7 -0
- package/dist/query-builder/astToSql.d.ts.map +1 -0
- package/dist/query-builder/astToSql.js +190 -0
- package/dist/query-builder/astToSql.js.map +1 -0
- package/dist/query-builder/impl.d.ts +3 -8
- package/dist/query-builder/impl.d.ts.map +1 -1
- package/dist/query-builder/impl.js +166 -124
- package/dist/query-builder/impl.js.map +1 -1
- package/dist/query-builder/impl.test.d.ts +86 -1
- package/dist/query-builder/impl.test.d.ts.map +1 -1
- package/dist/query-builder/impl.test.js +411 -69
- package/dist/query-builder/impl.test.js.map +1 -1
- package/dist/query-builder/mod.d.ts +7 -0
- package/dist/query-builder/mod.d.ts.map +1 -1
- package/dist/query-builder/mod.js +7 -0
- package/dist/query-builder/mod.js.map +1 -1
- package/dist/rehydrate-from-eventlog.d.ts +14 -0
- package/dist/rehydrate-from-eventlog.d.ts.map +1 -0
- package/dist/rehydrate-from-eventlog.js +65 -0
- package/dist/rehydrate-from-eventlog.js.map +1 -0
- package/dist/schema/EventDef.d.ts +136 -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/client-document-def.d.ts +223 -0
- package/dist/schema/client-document-def.d.ts.map +1 -0
- package/dist/schema/client-document-def.js +170 -0
- package/dist/schema/client-document-def.js.map +1 -0
- package/dist/schema/client-document-def.test.d.ts +2 -0
- package/dist/schema/client-document-def.test.d.ts.map +1 -0
- package/dist/schema/client-document-def.test.js +201 -0
- package/dist/schema/client-document-def.test.js.map +1 -0
- package/dist/schema/db-schema/ast/sqlite.d.ts +69 -0
- package/dist/schema/db-schema/ast/sqlite.d.ts.map +1 -0
- package/dist/schema/db-schema/ast/sqlite.js +71 -0
- package/dist/schema/db-schema/ast/sqlite.js.map +1 -0
- package/dist/schema/db-schema/ast/validate.d.ts +3 -0
- package/dist/schema/db-schema/ast/validate.d.ts.map +1 -0
- package/dist/schema/db-schema/ast/validate.js +12 -0
- package/dist/schema/db-schema/ast/validate.js.map +1 -0
- package/dist/schema/db-schema/dsl/field-defs.d.ts +90 -0
- package/dist/schema/db-schema/dsl/field-defs.d.ts.map +1 -0
- package/dist/schema/db-schema/dsl/field-defs.js +87 -0
- package/dist/schema/db-schema/dsl/field-defs.js.map +1 -0
- package/dist/schema/db-schema/dsl/field-defs.test.d.ts +2 -0
- package/dist/schema/db-schema/dsl/field-defs.test.d.ts.map +1 -0
- package/dist/schema/db-schema/dsl/field-defs.test.js +29 -0
- package/dist/schema/db-schema/dsl/field-defs.test.js.map +1 -0
- package/dist/schema/db-schema/dsl/mod.d.ts +90 -0
- package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -0
- package/dist/schema/db-schema/dsl/mod.js +41 -0
- package/dist/schema/db-schema/dsl/mod.js.map +1 -0
- package/dist/schema/db-schema/hash.d.ts +2 -0
- package/dist/schema/db-schema/hash.d.ts.map +1 -0
- package/dist/schema/db-schema/hash.js +14 -0
- package/dist/schema/db-schema/hash.js.map +1 -0
- package/dist/schema/db-schema/mod.d.ts +3 -0
- package/dist/schema/db-schema/mod.d.ts.map +1 -0
- package/dist/schema/db-schema/mod.js +3 -0
- package/dist/schema/db-schema/mod.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 +5 -3
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +5 -3
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/schema-helpers.d.ts.map +1 -1
- package/dist/schema/schema-helpers.js +1 -1
- package/dist/schema/schema-helpers.js.map +1 -1
- package/dist/schema/schema.d.ts +30 -23
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +48 -35
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/sqlite-state.d.ts +12 -0
- package/dist/schema/sqlite-state.d.ts.map +1 -0
- package/dist/schema/sqlite-state.js +36 -0
- package/dist/schema/sqlite-state.js.map +1 -0
- package/dist/schema/system-tables.d.ts +179 -125
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +76 -41
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema/table-def.d.ts +37 -109
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +23 -66
- package/dist/schema/table-def.js.map +1 -1
- package/dist/schema/view.d.ts +3 -0
- package/dist/schema/view.d.ts.map +1 -0
- package/dist/schema/view.js +3 -0
- package/dist/schema/view.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 +19 -14
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-mutation-defs.d.ts +3 -3
- package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
- package/dist/schema-management/validate-mutation-defs.js +17 -17
- package/dist/schema-management/validate-mutation-defs.js.map +1 -1
- 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} +29 -29
- 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 +6 -6
- package/src/__tests__/fixture.ts +36 -15
- package/src/adapter-types.ts +111 -74
- package/src/debug-info.ts +1 -0
- package/src/devtools/devtools-messages-client-session.ts +141 -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 +99 -0
- package/src/devtools/mod.ts +36 -0
- package/src/index.ts +4 -13
- package/src/leader-thread/LeaderSyncProcessor.ts +935 -0
- package/src/leader-thread/apply-event.ts +173 -0
- package/src/leader-thread/connection.ts +54 -9
- package/src/leader-thread/eventlog.ts +199 -0
- package/src/leader-thread/leader-worker-devtools.ts +212 -189
- package/src/leader-thread/make-leader-thread-layer.ts +143 -77
- package/src/leader-thread/mod.ts +1 -1
- package/src/leader-thread/recreate-db.ts +41 -30
- package/src/leader-thread/shutdown-channel.ts +2 -4
- package/src/leader-thread/types.ts +95 -51
- package/src/materializer-helper.ts +110 -0
- package/src/otel.ts +8 -0
- package/src/query-builder/api.ts +236 -85
- package/src/query-builder/astToSql.ts +232 -0
- package/src/query-builder/impl.test.ts +447 -78
- package/src/query-builder/impl.ts +209 -144
- package/src/query-builder/mod.ts +7 -0
- package/src/rehydrate-from-eventlog.ts +114 -0
- package/src/schema/EventDef.ts +216 -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/client-document-def.test.ts +239 -0
- package/src/schema/client-document-def.ts +444 -0
- package/src/schema/db-schema/ast/sqlite.ts +142 -0
- package/src/schema/db-schema/ast/validate.ts +13 -0
- package/src/schema/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +206 -0
- package/src/schema/db-schema/dsl/field-defs.test.ts +35 -0
- package/src/schema/db-schema/dsl/field-defs.ts +242 -0
- package/src/schema/db-schema/dsl/mod.ts +222 -0
- package/src/schema/db-schema/hash.ts +14 -0
- package/src/schema/db-schema/mod.ts +2 -0
- package/src/schema/events.ts +1 -0
- package/src/schema/mod.ts +5 -3
- package/src/schema/schema-helpers.ts +1 -1
- package/src/schema/schema.ts +84 -62
- package/src/schema/sqlite-state.ts +62 -0
- package/src/schema/system-tables.ts +68 -50
- package/src/schema/table-def.ts +68 -214
- package/src/schema/view.ts +2 -0
- package/src/schema-management/common.ts +7 -7
- package/src/schema-management/migrations.ts +27 -24
- package/src/schema-management/validate-mutation-defs.ts +22 -24
- 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/tmp/pack.tgz +0 -0
- package/tsconfig.json +2 -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/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-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/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/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-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/sync/client-session-sync-processor.ts +0 -207
- package/src/sync/next/test/mutation-fixtures.ts +0 -231
@@ -1,15 +1,15 @@
|
|
1
|
-
import { SqliteAst, SqliteDsl } from '@livestore/db-schema'
|
2
1
|
import { memoizeByStringifyArgs } from '@livestore/utils'
|
3
2
|
import { Effect, Schema as EffectSchema } from '@livestore/utils/effect'
|
4
3
|
|
5
|
-
import type {
|
4
|
+
import type { MigrationsReport, MigrationsReportEntry, SqliteDb, UnexpectedError } from '../adapter-types.js'
|
5
|
+
import { SqliteAst, SqliteDsl } from '../schema/db-schema/mod.js'
|
6
6
|
import type { LiveStoreSchema } from '../schema/mod.js'
|
7
|
-
import type {
|
7
|
+
import type { SchemaEventDefsMetaRow, SchemaMetaRow } from '../schema/system-tables.js'
|
8
8
|
import {
|
9
|
+
SCHEMA_EVENT_DEFS_META_TABLE,
|
9
10
|
SCHEMA_META_TABLE,
|
10
|
-
|
11
|
+
schemaEventDefsMetaTable,
|
11
12
|
schemaMetaTable,
|
12
|
-
schemaMutationsMetaTable,
|
13
13
|
systemTables,
|
14
14
|
} from '../schema/system-tables.js'
|
15
15
|
import { sql } from '../util.js'
|
@@ -19,24 +19,23 @@ import { validateSchema } from './validate-mutation-defs.js'
|
|
19
19
|
|
20
20
|
const getMemoizedTimestamp = memoizeByStringifyArgs(() => new Date().toISOString())
|
21
21
|
|
22
|
-
export const makeSchemaManager = (db:
|
22
|
+
export const makeSchemaManager = (db: SqliteDb): Effect.Effect<SchemaManager> =>
|
23
23
|
Effect.gen(function* () {
|
24
24
|
yield* migrateTable({
|
25
25
|
db,
|
26
|
-
tableAst:
|
26
|
+
tableAst: schemaEventDefsMetaTable.sqliteDef.ast,
|
27
27
|
behaviour: 'create-if-not-exists',
|
28
28
|
})
|
29
29
|
|
30
30
|
return {
|
31
|
-
|
32
|
-
dbSelect<SchemaMutationsMetaRow>(db, sql`SELECT * FROM ${SCHEMA_MUTATIONS_META_TABLE}`),
|
31
|
+
getEventDefInfos: () => dbSelect<SchemaEventDefsMetaRow>(db, sql`SELECT * FROM ${SCHEMA_EVENT_DEFS_META_TABLE}`),
|
33
32
|
|
34
|
-
|
33
|
+
setEventDefInfo: (info) => {
|
35
34
|
dbExecute(
|
36
35
|
db,
|
37
|
-
sql`INSERT OR REPLACE INTO ${
|
36
|
+
sql`INSERT OR REPLACE INTO ${SCHEMA_EVENT_DEFS_META_TABLE} (eventName, schemaHash, updatedAt) VALUES ($eventName, $schemaHash, $updatedAt)`,
|
38
37
|
{
|
39
|
-
|
38
|
+
eventName: info.eventName,
|
40
39
|
schemaHash: info.schemaHash,
|
41
40
|
updatedAt: new Date().toISOString(),
|
42
41
|
},
|
@@ -51,10 +50,10 @@ export const migrateDb = ({
|
|
51
50
|
schema,
|
52
51
|
onProgress,
|
53
52
|
}: {
|
54
|
-
db:
|
53
|
+
db: SqliteDb
|
55
54
|
schema: LiveStoreSchema
|
56
55
|
onProgress?: (opts: { done: number; total: number }) => Effect.Effect<void>
|
57
|
-
}) =>
|
56
|
+
}): Effect.Effect<MigrationsReport, UnexpectedError> =>
|
58
57
|
Effect.gen(function* () {
|
59
58
|
yield* migrateTable({
|
60
59
|
db,
|
@@ -81,6 +80,7 @@ export const migrateDb = ({
|
|
81
80
|
|
82
81
|
const tablesToMigrate = new Set<{ tableAst: SqliteAst.Table; schemaHash: number }>()
|
83
82
|
|
83
|
+
const migrationsReportEntries: MigrationsReportEntry[] = []
|
84
84
|
for (const tableDef of tableDefs) {
|
85
85
|
const tableAst = tableDef.sqliteDef.ast
|
86
86
|
const tableName = tableAst.name
|
@@ -90,9 +90,10 @@ export const migrateDb = ({
|
|
90
90
|
if (schemaHash !== dbSchemaHash) {
|
91
91
|
tablesToMigrate.add({ tableAst, schemaHash })
|
92
92
|
|
93
|
-
|
94
|
-
|
95
|
-
|
93
|
+
migrationsReportEntries.push({
|
94
|
+
tableName,
|
95
|
+
hashes: { expected: schemaHash, actual: dbSchemaHash },
|
96
|
+
})
|
96
97
|
}
|
97
98
|
}
|
98
99
|
|
@@ -107,6 +108,8 @@ export const migrateDb = ({
|
|
107
108
|
yield* onProgress({ done: processedTables, total: tablesCount })
|
108
109
|
}
|
109
110
|
}
|
111
|
+
|
112
|
+
return { migrations: migrationsReportEntries }
|
110
113
|
})
|
111
114
|
|
112
115
|
export const migrateTable = ({
|
@@ -116,7 +119,7 @@ export const migrateTable = ({
|
|
116
119
|
behaviour,
|
117
120
|
skipMetaTable = false,
|
118
121
|
}: {
|
119
|
-
db:
|
122
|
+
db: SqliteDb
|
120
123
|
tableAst: SqliteAst.Table
|
121
124
|
schemaHash?: number
|
122
125
|
behaviour: 'drop-and-recreate' | 'create-if-not-exists'
|
@@ -129,10 +132,10 @@ export const migrateTable = ({
|
|
129
132
|
|
130
133
|
if (behaviour === 'drop-and-recreate') {
|
131
134
|
// TODO need to possibly handle cascading deletes due to foreign keys
|
132
|
-
dbExecute(db, sql`drop table if exists ${tableName}`)
|
133
|
-
dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
|
135
|
+
dbExecute(db, sql`drop table if exists '${tableName}'`)
|
136
|
+
dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
|
134
137
|
} else if (behaviour === 'create-if-not-exists') {
|
135
|
-
dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
|
138
|
+
dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
|
136
139
|
}
|
137
140
|
|
138
141
|
for (const index of tableAst.indexes) {
|
@@ -162,11 +165,11 @@ export const migrateTable = ({
|
|
162
165
|
|
163
166
|
const createIndexFromDefinition = (tableName: string, index: SqliteAst.Index) => {
|
164
167
|
const uniqueStr = index.unique ? 'UNIQUE' : ''
|
165
|
-
return sql`create ${uniqueStr} index if not exists ${index.name} on ${tableName} (${index.columns.join(', ')})`
|
168
|
+
return sql`create ${uniqueStr} index if not exists '${index.name}' on '${tableName}' (${index.columns.join(', ')})`
|
166
169
|
}
|
167
170
|
|
168
171
|
export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
|
169
|
-
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name)
|
172
|
+
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => `'${_.name}'`)
|
170
173
|
const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
|
171
174
|
if (primaryKeys.length > 0) {
|
172
175
|
columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
|
@@ -191,5 +194,5 @@ const toSqliteColumnSpec = (column: SqliteAst.Column) => {
|
|
191
194
|
return `default ${encodedDefaultValue}`
|
192
195
|
})()
|
193
196
|
|
194
|
-
return
|
197
|
+
return `'${column.name}' ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
|
195
198
|
}
|
@@ -1,63 +1,61 @@
|
|
1
1
|
import { Effect, Schema } from '@livestore/utils/effect'
|
2
2
|
|
3
3
|
import { UnexpectedError } from '../adapter-types.js'
|
4
|
+
import type { EventDef } from '../schema/EventDef.js'
|
4
5
|
import type { LiveStoreSchema } from '../schema/mod.js'
|
5
|
-
import type {
|
6
|
-
import type { MutationDefInfo, SchemaManager } from './common.js'
|
6
|
+
import type { EventDefInfo, SchemaManager } from './common.js'
|
7
7
|
|
8
8
|
export const validateSchema = (schema: LiveStoreSchema, schemaManager: SchemaManager) =>
|
9
9
|
Effect.gen(function* () {
|
10
10
|
// Validate mutation definitions
|
11
|
-
const
|
11
|
+
const registeredEventDefInfos = schemaManager.getEventDefInfos()
|
12
12
|
|
13
|
-
const
|
14
|
-
(
|
13
|
+
const missingEventDefs = registeredEventDefInfos.filter(
|
14
|
+
(registeredEventDefInfo) => !schema.eventsDefsMap.has(registeredEventDefInfo.eventName),
|
15
15
|
)
|
16
16
|
|
17
|
-
if (
|
17
|
+
if (missingEventDefs.length > 0) {
|
18
18
|
yield* new UnexpectedError({
|
19
|
-
cause: `Missing mutation definitions: ${
|
19
|
+
cause: `Missing mutation definitions: ${missingEventDefs.map((info) => info.eventName).join(', ')}`,
|
20
20
|
})
|
21
21
|
}
|
22
22
|
|
23
|
-
for (const [,
|
24
|
-
const
|
25
|
-
(info) => info.mutationName === mutationDef.name,
|
26
|
-
)
|
23
|
+
for (const [, eventDef] of schema.eventsDefsMap) {
|
24
|
+
const registeredEventDefInfo = registeredEventDefInfos.find((info) => info.eventName === eventDef.name)
|
27
25
|
|
28
|
-
|
26
|
+
validateEventDef(eventDef, schemaManager, registeredEventDefInfo)
|
29
27
|
}
|
30
28
|
|
31
29
|
// Validate table schemas
|
32
30
|
})
|
33
31
|
|
34
|
-
export const
|
35
|
-
|
32
|
+
export const validateEventDef = (
|
33
|
+
eventDef: EventDef.AnyWithoutFn,
|
36
34
|
schemaManager: SchemaManager,
|
37
|
-
|
35
|
+
registeredEventDefInfo: EventDefInfo | undefined,
|
38
36
|
) => {
|
39
|
-
const schemaHash = Schema.hash(
|
37
|
+
const schemaHash = Schema.hash(eventDef.schema)
|
40
38
|
|
41
|
-
if (
|
42
|
-
schemaManager.
|
39
|
+
if (registeredEventDefInfo === undefined) {
|
40
|
+
schemaManager.setEventDefInfo({
|
43
41
|
schemaHash,
|
44
|
-
|
42
|
+
eventName: eventDef.name,
|
45
43
|
})
|
46
44
|
|
47
45
|
return
|
48
46
|
}
|
49
47
|
|
50
|
-
if (schemaHash ===
|
48
|
+
if (schemaHash === registeredEventDefInfo.schemaHash) return
|
51
49
|
|
52
50
|
// TODO bring back some form of schema compatibility check (see https://github.com/livestorejs/livestore/issues/69)
|
53
|
-
// const newSchemaIsCompatibleWithOldSchema = Schema.isSubType(jsonSchemaDefFromMgmtStore,
|
51
|
+
// const newSchemaIsCompatibleWithOldSchema = Schema.isSubType(jsonSchemaDefFromMgmtStore, eventDef.schema)
|
54
52
|
|
55
53
|
// if (!newSchemaIsCompatibleWithOldSchema) {
|
56
|
-
// shouldNeverHappen(`Schema for mutation ${
|
54
|
+
// shouldNeverHappen(`Schema for mutation ${eventDef.name} has changed in an incompatible way`)
|
57
55
|
// }
|
58
56
|
|
59
|
-
schemaManager.
|
57
|
+
schemaManager.setEventDefInfo({
|
60
58
|
schemaHash,
|
61
|
-
|
59
|
+
eventName: eventDef.name,
|
62
60
|
})
|
63
61
|
}
|
@@ -1,7 +1,7 @@
|
|
1
|
-
import type { SqliteDsl } from '@livestore/db-schema'
|
2
1
|
import { shouldNeverHappen } from '@livestore/utils'
|
3
2
|
import { pipe, ReadonlyArray, Schema, TreeFormatter } from '@livestore/utils/effect'
|
4
3
|
|
4
|
+
import type { SqliteDsl } from '../schema/db-schema/mod.js'
|
5
5
|
import { sql } from '../util.js'
|
6
6
|
import { objectEntries } from './misc.js'
|
7
7
|
import * as ClientTypes from './types.js'
|
package/src/sql-queries/types.ts
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
import type { Prettify
|
1
|
+
import type { Prettify } from '@livestore/utils'
|
2
2
|
import type { Schema } from '@livestore/utils/effect'
|
3
3
|
|
4
|
+
import type { SqliteDsl } from '../schema/db-schema/mod.js'
|
5
|
+
|
4
6
|
export type DecodedValuesForTableAll<TSchema extends SqliteDsl.DbSchema, TTableName extends keyof TSchema> = {
|
5
7
|
[K in keyof GetColumns<TSchema, TTableName>]: Schema.Schema.Type<GetColumn<TSchema, TTableName, K>['schema']>
|
6
8
|
}
|
@@ -0,0 +1,332 @@
|
|
1
|
+
/// <reference lib="dom" />
|
2
|
+
import { LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
|
3
|
+
import type { Runtime, Scope } from '@livestore/utils/effect'
|
4
|
+
import { BucketQueue, Effect, FiberHandle, Queue, Schema, Stream, Subscribable } from '@livestore/utils/effect'
|
5
|
+
import * as otel from '@opentelemetry/api'
|
6
|
+
|
7
|
+
import type { ClientSession, UnexpectedError } from '../adapter-types.js'
|
8
|
+
import * as EventId from '../schema/EventId.js'
|
9
|
+
import * as LiveStoreEvent from '../schema/LiveStoreEvent.js'
|
10
|
+
import { getEventDef, LEADER_MERGE_COUNTER_TABLE, type LiveStoreSchema } from '../schema/mod.js'
|
11
|
+
import { sql } from '../util.js'
|
12
|
+
import * as SyncState from './syncstate.js'
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Rebase behaviour:
|
16
|
+
* - We continously pull events from the leader and apply them to the local store.
|
17
|
+
* - If there was a race condition (i.e. the leader and client session have both advacned),
|
18
|
+
* we'll need to rebase the local pending events on top of the leader's head.
|
19
|
+
* - The goal is to never block the UI, so we'll interrupt rebasing if a new events is pushed by the client session.
|
20
|
+
* - We also want to avoid "backwards-jumping" in the UI, so we'll transactionally apply a read model changes during a rebase.
|
21
|
+
* - We might need to make the rebase behaviour configurable e.g. to let users manually trigger a rebase
|
22
|
+
*
|
23
|
+
* Longer term we should evalutate whether we can unify the ClientSessionSyncProcessor with the LeaderSyncProcessor.
|
24
|
+
*/
|
25
|
+
export const makeClientSessionSyncProcessor = ({
|
26
|
+
schema,
|
27
|
+
clientSession,
|
28
|
+
runtime,
|
29
|
+
applyEvent,
|
30
|
+
rollback,
|
31
|
+
refreshTables,
|
32
|
+
span,
|
33
|
+
params,
|
34
|
+
confirmUnsavedChanges,
|
35
|
+
}: {
|
36
|
+
schema: LiveStoreSchema
|
37
|
+
clientSession: ClientSession
|
38
|
+
runtime: Runtime.Runtime<Scope.Scope>
|
39
|
+
applyEvent: (
|
40
|
+
eventDecoded: LiveStoreEvent.PartialAnyDecoded,
|
41
|
+
options: { otelContext: otel.Context; withChangeset: boolean },
|
42
|
+
) => {
|
43
|
+
writeTables: Set<string>
|
44
|
+
sessionChangeset: { _tag: 'sessionChangeset'; data: Uint8Array; debug: any } | { _tag: 'no-op' } | { _tag: 'unset' }
|
45
|
+
}
|
46
|
+
rollback: (changeset: Uint8Array) => void
|
47
|
+
refreshTables: (tables: Set<string>) => void
|
48
|
+
span: otel.Span
|
49
|
+
params: {
|
50
|
+
leaderPushBatchSize: number
|
51
|
+
}
|
52
|
+
/**
|
53
|
+
* Currently only used in the web adapter:
|
54
|
+
* If true, registers a beforeunload event listener to confirm unsaved changes.
|
55
|
+
*/
|
56
|
+
confirmUnsavedChanges: boolean
|
57
|
+
}): ClientSessionSyncProcessor => {
|
58
|
+
const eventSchema = LiveStoreEvent.makeEventDefSchemaMemo(schema)
|
59
|
+
|
60
|
+
const syncStateRef = {
|
61
|
+
// The initial state is identical to the leader's initial state
|
62
|
+
current: new SyncState.SyncState({
|
63
|
+
localHead: clientSession.leaderThread.initialState.leaderHead,
|
64
|
+
upstreamHead: clientSession.leaderThread.initialState.leaderHead,
|
65
|
+
// Given we're starting with the leader's snapshot, we don't have any pending events intially
|
66
|
+
pending: [],
|
67
|
+
}),
|
68
|
+
}
|
69
|
+
|
70
|
+
const syncStateUpdateQueue = Queue.unbounded<SyncState.SyncState>().pipe(Effect.runSync)
|
71
|
+
const isClientEvent = (eventEncoded: LiveStoreEvent.EncodedWithMeta) =>
|
72
|
+
getEventDef(schema, eventEncoded.name).eventDef.options.clientOnly
|
73
|
+
|
74
|
+
/** We're queuing push requests to reduce the number of messages sent to the leader by batching them */
|
75
|
+
const leaderPushQueue = BucketQueue.make<LiveStoreEvent.EncodedWithMeta>().pipe(Effect.runSync)
|
76
|
+
|
77
|
+
const push: ClientSessionSyncProcessor['push'] = (batch, { otelContext }) => {
|
78
|
+
// TODO validate batch
|
79
|
+
|
80
|
+
let baseEventId = syncStateRef.current.localHead
|
81
|
+
const encodedEventDefs = batch.map(({ name, args }) => {
|
82
|
+
const eventDef = getEventDef(schema, name)
|
83
|
+
const nextIdPair = EventId.nextPair(baseEventId, eventDef.eventDef.options.clientOnly)
|
84
|
+
baseEventId = nextIdPair.id
|
85
|
+
return new LiveStoreEvent.EncodedWithMeta(
|
86
|
+
Schema.encodeUnknownSync(eventSchema)({
|
87
|
+
name,
|
88
|
+
args,
|
89
|
+
...nextIdPair,
|
90
|
+
clientId: clientSession.clientId,
|
91
|
+
sessionId: clientSession.sessionId,
|
92
|
+
}),
|
93
|
+
)
|
94
|
+
})
|
95
|
+
|
96
|
+
const mergeResult = SyncState.merge({
|
97
|
+
syncState: syncStateRef.current,
|
98
|
+
payload: { _tag: 'local-push', newEvents: encodedEventDefs },
|
99
|
+
isClientEvent,
|
100
|
+
isEqualEvent: LiveStoreEvent.isEqualEncoded,
|
101
|
+
})
|
102
|
+
|
103
|
+
if (mergeResult._tag === 'unexpected-error') {
|
104
|
+
return shouldNeverHappen('Unexpected error in client-session-sync-processor', mergeResult.cause)
|
105
|
+
}
|
106
|
+
|
107
|
+
span.addEvent('local-push', {
|
108
|
+
batchSize: encodedEventDefs.length,
|
109
|
+
mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
110
|
+
})
|
111
|
+
|
112
|
+
if (mergeResult._tag !== 'advance') {
|
113
|
+
return shouldNeverHappen(`Expected advance, got ${mergeResult._tag}`)
|
114
|
+
}
|
115
|
+
|
116
|
+
syncStateRef.current = mergeResult.newSyncState
|
117
|
+
syncStateUpdateQueue.offer(mergeResult.newSyncState).pipe(Effect.runSync)
|
118
|
+
|
119
|
+
const writeTables = new Set<string>()
|
120
|
+
for (const event of mergeResult.newEvents) {
|
121
|
+
// TODO avoid encoding and decoding here again
|
122
|
+
const decodedEventDef = Schema.decodeSync(eventSchema)(event)
|
123
|
+
const res = applyEvent(decodedEventDef, { otelContext, withChangeset: true })
|
124
|
+
for (const table of res.writeTables) {
|
125
|
+
writeTables.add(table)
|
126
|
+
}
|
127
|
+
event.meta.sessionChangeset = res.sessionChangeset
|
128
|
+
}
|
129
|
+
|
130
|
+
// console.debug('pushToLeader', encodedEventDefs.length, ...encodedEventDefs.map((_) => _.toJSON()))
|
131
|
+
BucketQueue.offerAll(leaderPushQueue, encodedEventDefs).pipe(Effect.runSync)
|
132
|
+
|
133
|
+
return { writeTables }
|
134
|
+
}
|
135
|
+
|
136
|
+
const debugInfo = {
|
137
|
+
rebaseCount: 0,
|
138
|
+
advanceCount: 0,
|
139
|
+
rejectCount: 0,
|
140
|
+
}
|
141
|
+
|
142
|
+
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
143
|
+
|
144
|
+
const boot: ClientSessionSyncProcessor['boot'] = Effect.gen(function* () {
|
145
|
+
// eslint-disable-next-line unicorn/prefer-global-this
|
146
|
+
if (confirmUnsavedChanges && typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
|
147
|
+
const onBeforeUnload = (event: BeforeUnloadEvent) => {
|
148
|
+
if (syncStateRef.current.pending.length > 0) {
|
149
|
+
// Trigger the default browser dialog
|
150
|
+
event.preventDefault()
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
yield* Effect.acquireRelease(
|
155
|
+
Effect.sync(() => window.addEventListener('beforeunload', onBeforeUnload)),
|
156
|
+
() => Effect.sync(() => window.removeEventListener('beforeunload', onBeforeUnload)),
|
157
|
+
)
|
158
|
+
}
|
159
|
+
|
160
|
+
const leaderPushingFiberHandle = yield* FiberHandle.make()
|
161
|
+
|
162
|
+
const backgroundLeaderPushing = Effect.gen(function* () {
|
163
|
+
const batch = yield* BucketQueue.takeBetween(leaderPushQueue, 1, params.leaderPushBatchSize)
|
164
|
+
yield* clientSession.leaderThread.events.push(batch).pipe(
|
165
|
+
Effect.catchTag('LeaderAheadError', () => {
|
166
|
+
debugInfo.rejectCount++
|
167
|
+
return BucketQueue.clear(leaderPushQueue)
|
168
|
+
}),
|
169
|
+
)
|
170
|
+
}).pipe(Effect.forever, Effect.interruptible, Effect.tapCauseLogPretty)
|
171
|
+
|
172
|
+
yield* FiberHandle.run(leaderPushingFiberHandle, backgroundLeaderPushing)
|
173
|
+
|
174
|
+
const getMergeCounter = () =>
|
175
|
+
clientSession.sqliteDb.select<{ mergeCounter: number }>(
|
176
|
+
sql`SELECT mergeCounter FROM ${LEADER_MERGE_COUNTER_TABLE} WHERE id = 0`,
|
177
|
+
)[0]?.mergeCounter ?? 0
|
178
|
+
|
179
|
+
// NOTE We need to lazily call `.pull` as we want the cursor to be updated
|
180
|
+
yield* Stream.suspend(() =>
|
181
|
+
clientSession.leaderThread.events.pull({
|
182
|
+
cursor: { mergeCounter: getMergeCounter(), eventId: syncStateRef.current.localHead },
|
183
|
+
}),
|
184
|
+
).pipe(
|
185
|
+
Stream.tap(({ payload, mergeCounter: leaderMergeCounter }) =>
|
186
|
+
Effect.gen(function* () {
|
187
|
+
// yield* Effect.logDebug('ClientSessionSyncProcessor:pull', payload)
|
188
|
+
|
189
|
+
if (clientSession.devtools.enabled) {
|
190
|
+
yield* clientSession.devtools.pullLatch.await
|
191
|
+
}
|
192
|
+
|
193
|
+
const mergeResult = SyncState.merge({
|
194
|
+
syncState: syncStateRef.current,
|
195
|
+
payload,
|
196
|
+
isClientEvent,
|
197
|
+
isEqualEvent: LiveStoreEvent.isEqualEncoded,
|
198
|
+
})
|
199
|
+
|
200
|
+
if (mergeResult._tag === 'unexpected-error') {
|
201
|
+
return yield* Effect.fail(mergeResult.cause)
|
202
|
+
} else if (mergeResult._tag === 'reject') {
|
203
|
+
return shouldNeverHappen('Unexpected reject in client-session-sync-processor', mergeResult)
|
204
|
+
}
|
205
|
+
|
206
|
+
syncStateRef.current = mergeResult.newSyncState
|
207
|
+
syncStateUpdateQueue.offer(mergeResult.newSyncState).pipe(Effect.runSync)
|
208
|
+
|
209
|
+
if (mergeResult._tag === 'rebase') {
|
210
|
+
span.addEvent('merge:pull:rebase', {
|
211
|
+
payloadTag: payload._tag,
|
212
|
+
payload: TRACE_VERBOSE ? JSON.stringify(payload) : undefined,
|
213
|
+
newEventsCount: mergeResult.newEvents.length,
|
214
|
+
rollbackCount: mergeResult.rollbackEvents.length,
|
215
|
+
res: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
216
|
+
leaderMergeCounter,
|
217
|
+
})
|
218
|
+
|
219
|
+
debugInfo.rebaseCount++
|
220
|
+
|
221
|
+
yield* FiberHandle.clear(leaderPushingFiberHandle)
|
222
|
+
|
223
|
+
// Reset the leader push queue since we're rebasing and will push again
|
224
|
+
yield* BucketQueue.clear(leaderPushQueue)
|
225
|
+
|
226
|
+
yield* FiberHandle.run(leaderPushingFiberHandle, backgroundLeaderPushing)
|
227
|
+
|
228
|
+
if (LS_DEV) {
|
229
|
+
Effect.logDebug(
|
230
|
+
'merge:pull:rebase: rollback',
|
231
|
+
mergeResult.rollbackEvents.length,
|
232
|
+
...mergeResult.rollbackEvents.slice(0, 10).map((_) => _.toJSON()),
|
233
|
+
{ leaderMergeCounter },
|
234
|
+
).pipe(Effect.provide(runtime), Effect.runSync)
|
235
|
+
}
|
236
|
+
|
237
|
+
for (let i = mergeResult.rollbackEvents.length - 1; i >= 0; i--) {
|
238
|
+
const event = mergeResult.rollbackEvents[i]!
|
239
|
+
if (event.meta.sessionChangeset._tag !== 'no-op' && event.meta.sessionChangeset._tag !== 'unset') {
|
240
|
+
rollback(event.meta.sessionChangeset.data)
|
241
|
+
event.meta.sessionChangeset = { _tag: 'unset' }
|
242
|
+
}
|
243
|
+
}
|
244
|
+
|
245
|
+
yield* BucketQueue.offerAll(leaderPushQueue, mergeResult.newSyncState.pending)
|
246
|
+
} else {
|
247
|
+
span.addEvent('merge:pull:advance', {
|
248
|
+
payloadTag: payload._tag,
|
249
|
+
payload: TRACE_VERBOSE ? JSON.stringify(payload) : undefined,
|
250
|
+
newEventsCount: mergeResult.newEvents.length,
|
251
|
+
res: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
252
|
+
leaderMergeCounter,
|
253
|
+
})
|
254
|
+
|
255
|
+
debugInfo.advanceCount++
|
256
|
+
}
|
257
|
+
|
258
|
+
if (mergeResult.newEvents.length === 0) return
|
259
|
+
|
260
|
+
const writeTables = new Set<string>()
|
261
|
+
for (const event of mergeResult.newEvents) {
|
262
|
+
// TODO apply changeset if available (will require tracking of write tables as well)
|
263
|
+
const decodedEventDef = Schema.decodeSync(eventSchema)(event)
|
264
|
+
const res = applyEvent(decodedEventDef, { otelContext, withChangeset: true })
|
265
|
+
for (const table of res.writeTables) {
|
266
|
+
writeTables.add(table)
|
267
|
+
}
|
268
|
+
|
269
|
+
event.meta.sessionChangeset = res.sessionChangeset
|
270
|
+
}
|
271
|
+
|
272
|
+
refreshTables(writeTables)
|
273
|
+
}).pipe(
|
274
|
+
Effect.tapCauseLogPretty,
|
275
|
+
Effect.catchAllCause((cause) => Effect.sync(() => clientSession.shutdown(cause))),
|
276
|
+
),
|
277
|
+
),
|
278
|
+
Stream.runDrain,
|
279
|
+
Effect.forever, // NOTE Whenever the leader changes, we need to re-start the stream
|
280
|
+
Effect.interruptible,
|
281
|
+
Effect.withSpan('client-session-sync-processor:pull'),
|
282
|
+
Effect.tapCauseLogPretty,
|
283
|
+
Effect.forkScoped,
|
284
|
+
)
|
285
|
+
})
|
286
|
+
|
287
|
+
return {
|
288
|
+
push,
|
289
|
+
boot,
|
290
|
+
syncState: Subscribable.make({
|
291
|
+
get: Effect.gen(function* () {
|
292
|
+
const syncState = syncStateRef.current
|
293
|
+
if (syncStateRef === undefined) return shouldNeverHappen('Not initialized')
|
294
|
+
return syncState
|
295
|
+
}),
|
296
|
+
changes: Stream.fromQueue(syncStateUpdateQueue),
|
297
|
+
}),
|
298
|
+
debug: {
|
299
|
+
print: () =>
|
300
|
+
Effect.gen(function* () {
|
301
|
+
console.log('debugInfo', debugInfo)
|
302
|
+
console.log('syncState', syncStateRef.current)
|
303
|
+
const pushQueueSize = yield* BucketQueue.size(leaderPushQueue)
|
304
|
+
console.log('pushQueueSize', pushQueueSize)
|
305
|
+
const pushQueueItems = yield* BucketQueue.peekAll(leaderPushQueue)
|
306
|
+
console.log(
|
307
|
+
'pushQueueItems',
|
308
|
+
pushQueueItems.map((_) => _.toJSON()),
|
309
|
+
)
|
310
|
+
}).pipe(Effect.provide(runtime), Effect.runSync),
|
311
|
+
debugInfo: () => debugInfo,
|
312
|
+
},
|
313
|
+
} satisfies ClientSessionSyncProcessor
|
314
|
+
}
|
315
|
+
|
316
|
+
export interface ClientSessionSyncProcessor {
|
317
|
+
push: (
|
318
|
+
batch: ReadonlyArray<LiveStoreEvent.PartialAnyDecoded>,
|
319
|
+
options: { otelContext: otel.Context },
|
320
|
+
) => {
|
321
|
+
writeTables: Set<string>
|
322
|
+
}
|
323
|
+
boot: Effect.Effect<void, UnexpectedError, Scope.Scope>
|
324
|
+
syncState: Subscribable.Subscribable<SyncState.SyncState>
|
325
|
+
debug: {
|
326
|
+
print: () => void
|
327
|
+
debugInfo: () => {
|
328
|
+
rebaseCount: number
|
329
|
+
advanceCount: number
|
330
|
+
}
|
331
|
+
}
|
332
|
+
}
|
package/src/sync/index.ts
CHANGED