@livestore/common 0.3.0-dev.4 → 0.3.0-dev.41
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
@@ -1,4 +1,4 @@
|
|
1
|
-
import type {
|
1
|
+
import type { SqliteDb } from '../adapter-types.js'
|
2
2
|
import type { ParamsObject } from '../util.js'
|
3
3
|
import { prepareBindValues } from '../util.js'
|
4
4
|
|
@@ -6,7 +6,7 @@ import { prepareBindValues } from '../util.js'
|
|
6
6
|
// will require proper scope-aware cleanup etc (for testing and apps with multiple LiveStore instances)
|
7
7
|
// const cachedStmts = new Map<string, PreparedStatement>()
|
8
8
|
|
9
|
-
export const dbExecute = (db:
|
9
|
+
export const dbExecute = (db: SqliteDb, queryStr: string, bindValues?: ParamsObject) => {
|
10
10
|
// let stmt = cachedStmts.get(queryStr)
|
11
11
|
// if (!stmt) {
|
12
12
|
const stmt = db.prepare(queryStr)
|
@@ -20,7 +20,7 @@ export const dbExecute = (db: SynchronousDatabase, queryStr: string, bindValues?
|
|
20
20
|
stmt.finalize()
|
21
21
|
}
|
22
22
|
|
23
|
-
export const dbSelect = <T>(db:
|
23
|
+
export const dbSelect = <T>(db: SqliteDb, queryStr: string, bindValues?: ParamsObject) => {
|
24
24
|
// let stmt = cachedStmts.get(queryStr)
|
25
25
|
// if (!stmt) {
|
26
26
|
const stmt = db.prepare(queryStr)
|
@@ -33,12 +33,12 @@ export const dbSelect = <T>(db: SynchronousDatabase, queryStr: string, bindValue
|
|
33
33
|
}
|
34
34
|
|
35
35
|
export interface SchemaManager {
|
36
|
-
|
36
|
+
getEventDefInfos: () => ReadonlyArray<EventDefInfo>
|
37
37
|
|
38
|
-
|
38
|
+
setEventDefInfo: (eventDefInfo: EventDefInfo) => void
|
39
39
|
}
|
40
40
|
|
41
|
-
export type
|
42
|
-
|
41
|
+
export type EventDefInfo = {
|
42
|
+
eventName: string
|
43
43
|
schemaHash: number
|
44
44
|
}
|
@@ -1,42 +1,41 @@
|
|
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'
|
6
5
|
import type { LiveStoreSchema } from '../schema/mod.js'
|
7
|
-
import
|
6
|
+
import { SqliteAst, SqliteDsl } from '../schema/state/sqlite/db-schema/mod.js'
|
7
|
+
import type { SchemaEventDefsMetaRow, SchemaMetaRow } from '../schema/state/sqlite/system-tables.js'
|
8
8
|
import {
|
9
|
+
isStateSystemTable,
|
10
|
+
SCHEMA_EVENT_DEFS_META_TABLE,
|
9
11
|
SCHEMA_META_TABLE,
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
systemTables,
|
14
|
-
} from '../schema/system-tables.js'
|
12
|
+
schemaEventDefsMetaTable,
|
13
|
+
stateSystemTables,
|
14
|
+
} from '../schema/state/sqlite/system-tables.js'
|
15
15
|
import { sql } from '../util.js'
|
16
16
|
import type { SchemaManager } from './common.js'
|
17
17
|
import { dbExecute, dbSelect } from './common.js'
|
18
|
-
import { validateSchema } from './validate-
|
18
|
+
import { validateSchema } from './validate-schema.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,16 +50,18 @@ 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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
for (const tableDef of stateSystemTables) {
|
59
|
+
yield* migrateTable({
|
60
|
+
db,
|
61
|
+
tableAst: tableDef.sqliteDef.ast,
|
62
|
+
behaviour: 'create-if-not-exists',
|
63
|
+
})
|
64
|
+
}
|
64
65
|
|
65
66
|
// TODO enforce that migrating tables isn't allowed once the store is running
|
66
67
|
|
@@ -73,14 +74,15 @@ export const migrateDb = ({
|
|
73
74
|
schemaMetaRows.map(({ tableName, schemaHash }) => [tableName, schemaHash]),
|
74
75
|
)
|
75
76
|
|
76
|
-
const tableDefs =
|
77
|
+
const tableDefs = [
|
77
78
|
// NOTE it's important the `SCHEMA_META_TABLE` comes first since we're writing to it below
|
78
|
-
...
|
79
|
-
...Array.from(schema.tables.values()).filter((_) => _.sqliteDef.name
|
80
|
-
]
|
79
|
+
...stateSystemTables,
|
80
|
+
...Array.from(schema.state.sqlite.tables.values()).filter((_) => !isStateSystemTable(_.sqliteDef.name)),
|
81
|
+
]
|
81
82
|
|
82
83
|
const tablesToMigrate = new Set<{ tableAst: SqliteAst.Table; schemaHash: number }>()
|
83
84
|
|
85
|
+
const migrationsReportEntries: MigrationsReportEntry[] = []
|
84
86
|
for (const tableDef of tableDefs) {
|
85
87
|
const tableAst = tableDef.sqliteDef.ast
|
86
88
|
const tableName = tableAst.name
|
@@ -90,9 +92,10 @@ export const migrateDb = ({
|
|
90
92
|
if (schemaHash !== dbSchemaHash) {
|
91
93
|
tablesToMigrate.add({ tableAst, schemaHash })
|
92
94
|
|
93
|
-
|
94
|
-
|
95
|
-
|
95
|
+
migrationsReportEntries.push({
|
96
|
+
tableName,
|
97
|
+
hashes: { expected: schemaHash, actual: dbSchemaHash },
|
98
|
+
})
|
96
99
|
}
|
97
100
|
}
|
98
101
|
|
@@ -107,6 +110,8 @@ export const migrateDb = ({
|
|
107
110
|
yield* onProgress({ done: processedTables, total: tablesCount })
|
108
111
|
}
|
109
112
|
}
|
113
|
+
|
114
|
+
return { migrations: migrationsReportEntries }
|
110
115
|
})
|
111
116
|
|
112
117
|
export const migrateTable = ({
|
@@ -116,7 +121,7 @@ export const migrateTable = ({
|
|
116
121
|
behaviour,
|
117
122
|
skipMetaTable = false,
|
118
123
|
}: {
|
119
|
-
db:
|
124
|
+
db: SqliteDb
|
120
125
|
tableAst: SqliteAst.Table
|
121
126
|
schemaHash?: number
|
122
127
|
behaviour: 'drop-and-recreate' | 'create-if-not-exists'
|
@@ -129,10 +134,10 @@ export const migrateTable = ({
|
|
129
134
|
|
130
135
|
if (behaviour === 'drop-and-recreate') {
|
131
136
|
// 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`)
|
137
|
+
dbExecute(db, sql`drop table if exists '${tableName}'`)
|
138
|
+
dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
|
134
139
|
} else if (behaviour === 'create-if-not-exists') {
|
135
|
-
dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
|
140
|
+
dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
|
136
141
|
}
|
137
142
|
|
138
143
|
for (const index of tableAst.indexes) {
|
@@ -162,11 +167,11 @@ export const migrateTable = ({
|
|
162
167
|
|
163
168
|
const createIndexFromDefinition = (tableName: string, index: SqliteAst.Index) => {
|
164
169
|
const uniqueStr = index.unique ? 'UNIQUE' : ''
|
165
|
-
return sql`create ${uniqueStr} index if not exists ${index.name} on ${tableName} (${index.columns.join(', ')})`
|
170
|
+
return sql`create ${uniqueStr} index if not exists '${index.name}' on '${tableName}' (${index.columns.join(', ')})`
|
166
171
|
}
|
167
172
|
|
168
173
|
export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
|
169
|
-
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name)
|
174
|
+
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => `'${_.name}'`)
|
170
175
|
const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
|
171
176
|
if (primaryKeys.length > 0) {
|
172
177
|
columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
|
@@ -182,6 +187,7 @@ const toSqliteColumnSpec = (column: SqliteAst.Column) => {
|
|
182
187
|
const defaultValueStr = (() => {
|
183
188
|
if (column.default._tag === 'None') return ''
|
184
189
|
|
190
|
+
if (column.default.value === null) return 'default null'
|
185
191
|
if (SqliteDsl.isSqlDefaultValue(column.default.value)) return `default ${column.default.value.sql}`
|
186
192
|
|
187
193
|
const encodeValue = EffectSchema.encodeSync(column.schema)
|
@@ -191,5 +197,5 @@ const toSqliteColumnSpec = (column: SqliteAst.Column) => {
|
|
191
197
|
return `default ${encodedDefaultValue}`
|
192
198
|
})()
|
193
199
|
|
194
|
-
return
|
200
|
+
return `'${column.name}' ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
|
195
201
|
}
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import { Effect, Schema } from '@livestore/utils/effect'
|
2
|
+
|
3
|
+
import { UnexpectedError } from '../adapter-types.js'
|
4
|
+
import type { EventDef } from '../schema/EventDef.js'
|
5
|
+
import type { LiveStoreSchema } from '../schema/mod.js'
|
6
|
+
import type { EventDefInfo, SchemaManager } from './common.js'
|
7
|
+
|
8
|
+
export const validateSchema = (schema: LiveStoreSchema, schemaManager: SchemaManager) =>
|
9
|
+
Effect.gen(function* () {
|
10
|
+
// Validate mutation definitions
|
11
|
+
const registeredEventDefInfos = schemaManager.getEventDefInfos()
|
12
|
+
|
13
|
+
const missingEventDefs = registeredEventDefInfos.filter(
|
14
|
+
(registeredEventDefInfo) => !schema.eventsDefsMap.has(registeredEventDefInfo.eventName),
|
15
|
+
)
|
16
|
+
|
17
|
+
if (missingEventDefs.length > 0) {
|
18
|
+
yield* new UnexpectedError({
|
19
|
+
cause: `Missing mutation definitions: ${missingEventDefs.map((info) => info.eventName).join(', ')}`,
|
20
|
+
})
|
21
|
+
}
|
22
|
+
|
23
|
+
for (const [, eventDef] of schema.eventsDefsMap) {
|
24
|
+
const registeredEventDefInfo = registeredEventDefInfos.find((info) => info.eventName === eventDef.name)
|
25
|
+
|
26
|
+
validateEventDef(eventDef, schemaManager, registeredEventDefInfo)
|
27
|
+
}
|
28
|
+
|
29
|
+
// Validate table schemas
|
30
|
+
})
|
31
|
+
|
32
|
+
export const validateEventDef = (
|
33
|
+
eventDef: EventDef.AnyWithoutFn,
|
34
|
+
schemaManager: SchemaManager,
|
35
|
+
registeredEventDefInfo: EventDefInfo | undefined,
|
36
|
+
) => {
|
37
|
+
const schemaHash = Schema.hash(eventDef.schema)
|
38
|
+
|
39
|
+
if (registeredEventDefInfo === undefined) {
|
40
|
+
schemaManager.setEventDefInfo({
|
41
|
+
schemaHash,
|
42
|
+
eventName: eventDef.name,
|
43
|
+
})
|
44
|
+
|
45
|
+
return
|
46
|
+
}
|
47
|
+
|
48
|
+
if (schemaHash === registeredEventDefInfo.schemaHash) return
|
49
|
+
|
50
|
+
// TODO bring back some form of schema compatibility check (see https://github.com/livestorejs/livestore/issues/69)
|
51
|
+
// const newSchemaIsCompatibleWithOldSchema = Schema.isSubType(jsonSchemaDefFromMgmtStore, eventDef.schema)
|
52
|
+
|
53
|
+
// if (!newSchemaIsCompatibleWithOldSchema) {
|
54
|
+
// shouldNeverHappen(`Schema for mutation ${eventDef.name} has changed in an incompatible way`)
|
55
|
+
// }
|
56
|
+
|
57
|
+
schemaManager.setEventDefInfo({
|
58
|
+
schemaHash,
|
59
|
+
eventName: eventDef.name,
|
60
|
+
})
|
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/state/sqlite/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'
|
@@ -1,5 +1,4 @@
|
|
1
|
-
import type { SqliteDsl } from '
|
2
|
-
|
1
|
+
import type { SqliteDsl } from '../schema/state/sqlite/db-schema/mod.js'
|
3
2
|
import type { BindValues } from './sql-queries.js'
|
4
3
|
import * as SqlQueries from './sql-queries.js'
|
5
4
|
import type * 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/state/sqlite/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, type LiveStoreSchema, SystemTables } 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 state 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
|
+
materializeEvent,
|
30
|
+
rollback,
|
31
|
+
refreshTables,
|
32
|
+
span,
|
33
|
+
params,
|
34
|
+
confirmUnsavedChanges,
|
35
|
+
}: {
|
36
|
+
schema: LiveStoreSchema
|
37
|
+
clientSession: ClientSession
|
38
|
+
runtime: Runtime.Runtime<Scope.Scope>
|
39
|
+
materializeEvent: (
|
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 = materializeEvent(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 ${SystemTables.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 = materializeEvent(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