@livestore/common 0.4.0-dev.0 → 0.4.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/ClientSessionLeaderThreadProxy.d.ts +7 -2
- package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
- package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
- package/dist/adapter-types.d.ts +9 -3
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
- package/dist/devtools/devtools-messages-common.d.ts +7 -14
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-common.js +1 -6
- package/dist/devtools/devtools-messages-common.js.map +1 -1
- package/dist/devtools/devtools-messages-leader.d.ts +27 -25
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/errors.d.ts +47 -5
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +22 -3
- package/dist/errors.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +7 -3
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +122 -49
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts +4 -10
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +4 -6
- package/dist/leader-thread/eventlog.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +6 -2
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +1 -2
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +68 -19
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.test.d.ts +2 -0
- package/dist/leader-thread/make-leader-thread-layer.test.d.ts.map +1 -0
- package/dist/leader-thread/make-leader-thread-layer.test.js +32 -0
- package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -0
- package/dist/leader-thread/materialize-event.d.ts +2 -2
- package/dist/leader-thread/materialize-event.d.ts.map +1 -1
- package/dist/leader-thread/materialize-event.js +23 -9
- package/dist/leader-thread/materialize-event.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts +2 -3
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +1 -1
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.d.ts +2 -2
- package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +2 -2
- package/dist/leader-thread/shutdown-channel.js.map +1 -1
- package/dist/leader-thread/types.d.ts +7 -5
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/materializer-helper.d.ts +1 -1
- package/dist/materializer-helper.d.ts.map +1 -1
- package/dist/materializer-helper.js +20 -4
- package/dist/materializer-helper.js.map +1 -1
- package/dist/rematerialize-from-eventlog.d.ts +1 -1
- package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
- package/dist/rematerialize-from-eventlog.js +25 -16
- package/dist/rematerialize-from-eventlog.js.map +1 -1
- package/dist/schema/EventDef.d.ts +3 -0
- package/dist/schema/EventDef.d.ts.map +1 -1
- package/dist/schema/EventDef.js.map +1 -1
- package/dist/schema/LiveStoreEvent.d.ts +1 -1
- package/dist/schema/LiveStoreEvent.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent.js +1 -2
- package/dist/schema/LiveStoreEvent.js.map +1 -1
- package/dist/schema/mod.d.ts +2 -0
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +1 -0
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/schema.d.ts +15 -0
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +26 -1
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.d.ts +35 -5
- package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.js +95 -4
- package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.test.js +16 -0
- package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.js +14 -6
- package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.d.ts +19 -0
- package/dist/schema/state/sqlite/column-def.d.ts.map +1 -0
- package/dist/schema/state/sqlite/column-def.js +179 -0
- package/dist/schema/state/sqlite/column-def.js.map +1 -0
- package/dist/schema/state/sqlite/column-def.test.d.ts +2 -0
- package/dist/schema/state/sqlite/column-def.test.d.ts.map +1 -0
- package/dist/schema/state/sqlite/column-def.test.js +572 -0
- package/dist/schema/state/sqlite/column-def.test.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +2 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +23 -6
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js +2 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
- package/dist/schema/state/sqlite/mod.d.ts +1 -1
- package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/mod.js +1 -1
- package/dist/schema/state/sqlite/mod.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/api.d.ts +5 -2
- package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.js +6 -2
- package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.test.js +137 -2
- package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
- package/dist/schema/state/sqlite/system-tables.d.ts +42 -6
- package/dist/schema/state/sqlite/system-tables.d.ts.map +1 -1
- package/dist/schema/state/sqlite/system-tables.js +2 -0
- package/dist/schema/state/sqlite/system-tables.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.d.ts +6 -8
- package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/table-def.js +4 -211
- package/dist/schema/state/sqlite/table-def.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.test.js +59 -453
- package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
- package/dist/schema/unknown-events.d.ts +47 -0
- package/dist/schema/unknown-events.d.ts.map +1 -0
- package/dist/schema/unknown-events.js +69 -0
- package/dist/schema/unknown-events.js.map +1 -0
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
- package/dist/sql-queries/sql-query-builder.js +2 -1
- package/dist/sql-queries/sql-query-builder.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +9 -11
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +35 -33
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/errors.d.ts +61 -0
- package/dist/sync/errors.d.ts.map +1 -0
- package/dist/sync/errors.js +36 -0
- package/dist/sync/errors.js.map +1 -0
- package/dist/sync/index.d.ts +3 -0
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +3 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/mock-sync-backend.d.ts +23 -0
- package/dist/sync/mock-sync-backend.d.ts.map +1 -0
- package/dist/sync/mock-sync-backend.js +114 -0
- package/dist/sync/mock-sync-backend.js.map +1 -0
- package/dist/sync/next/compact-events.d.ts.map +1 -1
- package/dist/sync/next/compact-events.js +4 -5
- package/dist/sync/next/compact-events.js.map +1 -1
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +1 -2
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +50 -11
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +193 -4
- 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 +3 -1
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/sync-backend-kv.d.ts +7 -0
- package/dist/sync/sync-backend-kv.d.ts.map +1 -0
- package/dist/sync/sync-backend-kv.js +18 -0
- package/dist/sync/sync-backend-kv.js.map +1 -0
- package/dist/sync/sync-backend.d.ts +105 -0
- package/dist/sync/sync-backend.d.ts.map +1 -0
- package/dist/sync/sync-backend.js +61 -0
- package/dist/sync/sync-backend.js.map +1 -0
- package/dist/sync/sync.d.ts +6 -84
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js +2 -27
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/transport-chunking.d.ts +36 -0
- package/dist/sync/transport-chunking.d.ts.map +1 -0
- package/dist/sync/transport-chunking.js +56 -0
- package/dist/sync/transport-chunking.js.map +1 -0
- package/dist/sync/validate-push-payload.d.ts +1 -1
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js +6 -6
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/testing/event-factory.d.ts +68 -0
- package/dist/testing/event-factory.d.ts.map +1 -0
- package/dist/testing/event-factory.js +80 -0
- package/dist/testing/event-factory.js.map +1 -0
- package/dist/testing/mod.d.ts +2 -0
- package/dist/testing/mod.d.ts.map +1 -0
- package/dist/testing/mod.js +2 -0
- package/dist/testing/mod.js.map +1 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +7 -8
- package/src/ClientSessionLeaderThreadProxy.ts +7 -2
- package/src/adapter-types.ts +13 -3
- package/src/devtools/devtools-messages-common.ts +1 -8
- package/src/errors.ts +33 -4
- package/src/leader-thread/LeaderSyncProcessor.ts +179 -57
- package/src/leader-thread/eventlog.ts +10 -6
- package/src/leader-thread/leader-worker-devtools.ts +6 -2
- package/src/leader-thread/make-leader-thread-layer.test.ts +44 -0
- package/src/leader-thread/make-leader-thread-layer.ts +137 -26
- package/src/leader-thread/materialize-event.ts +34 -9
- package/src/leader-thread/recreate-db.ts +11 -3
- package/src/leader-thread/shutdown-channel.ts +16 -2
- package/src/leader-thread/types.ts +7 -5
- package/src/materializer-helper.ts +22 -5
- package/src/rematerialize-from-eventlog.ts +33 -23
- package/src/schema/EventDef.ts +3 -0
- package/src/schema/LiveStoreEvent.ts +1 -2
- package/src/schema/mod.ts +2 -0
- package/src/schema/schema.ts +37 -1
- package/src/schema/state/sqlite/client-document-def.test.ts +17 -0
- package/src/schema/state/sqlite/client-document-def.ts +117 -5
- package/src/schema/state/sqlite/column-annotations.ts +16 -6
- package/src/schema/state/sqlite/column-def.test.ts +722 -0
- package/src/schema/state/sqlite/column-def.ts +215 -0
- package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +26 -6
- package/src/schema/state/sqlite/db-schema/dsl/mod.ts +2 -1
- package/src/schema/state/sqlite/mod.ts +1 -0
- package/src/schema/state/sqlite/query-builder/api.ts +7 -2
- package/src/schema/state/sqlite/query-builder/impl.test.ts +187 -6
- package/src/schema/state/sqlite/query-builder/impl.ts +8 -2
- package/src/schema/state/sqlite/system-tables.ts +2 -0
- package/src/schema/state/sqlite/table-def.test.ts +74 -569
- package/src/schema/state/sqlite/table-def.ts +13 -262
- package/src/schema/unknown-events.ts +131 -0
- package/src/sql-queries/sql-query-builder.ts +2 -1
- package/src/sync/ClientSessionSyncProcessor.ts +55 -49
- package/src/sync/errors.ts +38 -0
- package/src/sync/index.ts +3 -0
- package/src/sync/mock-sync-backend.ts +184 -0
- package/src/sync/next/compact-events.ts +4 -5
- package/src/sync/next/facts.ts +1 -3
- package/src/sync/next/history-dag-common.ts +272 -21
- package/src/sync/next/history-dag.ts +3 -1
- package/src/sync/sync-backend-kv.ts +22 -0
- package/src/sync/sync-backend.ts +185 -0
- package/src/sync/sync.ts +6 -89
- package/src/sync/transport-chunking.ts +90 -0
- package/src/sync/validate-push-payload.ts +6 -7
- package/src/testing/event-factory.ts +133 -0
- package/src/testing/mod.ts +1 -0
- package/src/version.ts +2 -2
- package/dist/schema-management/migrations.test.d.ts +0 -2
- package/dist/schema-management/migrations.test.d.ts.map +0 -1
- package/dist/schema-management/migrations.test.js +0 -52
- package/dist/schema-management/migrations.test.js.map +0 -1
- package/dist/sync/next/graphology.d.ts +0 -8
- package/dist/sync/next/graphology.d.ts.map +0 -1
- package/dist/sync/next/graphology.js +0 -30
- package/dist/sync/next/graphology.js.map +0 -1
- package/dist/sync/next/graphology_.d.ts +0 -3
- package/dist/sync/next/graphology_.d.ts.map +0 -1
- package/dist/sync/next/graphology_.js +0 -3
- package/dist/sync/next/graphology_.js.map +0 -1
- package/src/sync/next/ambient.d.ts +0 -3
- package/src/sync/next/graphology.ts +0 -41
- package/src/sync/next/graphology_.ts +0 -2
@@ -1,13 +1,29 @@
|
|
1
|
-
import { shouldNeverHappen } from '@livestore/utils'
|
1
|
+
import { omitUndefineds, shouldNeverHappen } from '@livestore/utils'
|
2
2
|
import type { HttpClient, Schema, Scope } from '@livestore/utils/effect'
|
3
|
-
import {
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
import {
|
4
|
+
Deferred,
|
5
|
+
Effect,
|
6
|
+
KeyValueStore,
|
7
|
+
Layer,
|
8
|
+
PlatformError,
|
9
|
+
Queue,
|
10
|
+
Stream,
|
11
|
+
Subscribable,
|
12
|
+
SubscriptionRef,
|
13
|
+
} from '@livestore/utils/effect'
|
14
|
+
import {
|
15
|
+
type BootStatus,
|
16
|
+
type MakeSqliteDb,
|
17
|
+
type MaterializerHashMismatchError,
|
18
|
+
type SqliteDb,
|
19
|
+
type SqliteError,
|
20
|
+
UnexpectedError,
|
21
|
+
} from '../adapter-types.ts'
|
22
|
+
import type { MigrationsReport } from '../defs.ts'
|
7
23
|
import type * as Devtools from '../devtools/mod.ts'
|
8
24
|
import type { LiveStoreSchema } from '../schema/mod.ts'
|
9
25
|
import { EventSequenceNumber, LiveStoreEvent, SystemTables } from '../schema/mod.ts'
|
10
|
-
import type { InvalidPullError, IsOfflineError, SyncOptions } from '../sync/sync.ts'
|
26
|
+
import type { InvalidPullError, IsOfflineError, SyncBackend, SyncOptions } from '../sync/sync.ts'
|
11
27
|
import { SyncState } from '../sync/syncstate.ts'
|
12
28
|
import { sql } from '../util.ts'
|
13
29
|
import * as Eventlog from './eventlog.ts'
|
@@ -17,6 +33,7 @@ import { makeMaterializeEvent } from './materialize-event.ts'
|
|
17
33
|
import { recreateDb } from './recreate-db.ts'
|
18
34
|
import type { ShutdownChannel } from './shutdown-channel.ts'
|
19
35
|
import type {
|
36
|
+
DevtoolsContext,
|
20
37
|
DevtoolsOptions,
|
21
38
|
InitialBlockingSyncContext,
|
22
39
|
InitialSyncOptions,
|
@@ -71,10 +88,45 @@ export const makeLeaderThreadLayer = ({
|
|
71
88
|
// Either happens on initial boot or if schema changes
|
72
89
|
const dbStateMissing = !hasStateTables(dbState)
|
73
90
|
|
91
|
+
yield* Eventlog.initEventlogDb(dbEventlog)
|
92
|
+
|
74
93
|
const syncBackend =
|
75
94
|
syncOptions?.backend === undefined
|
76
95
|
? undefined
|
77
|
-
: yield* syncOptions.backend({ storeId, clientId, payload: syncPayload })
|
96
|
+
: yield* syncOptions.backend({ storeId, clientId, payload: syncPayload }).pipe(
|
97
|
+
Effect.provide(
|
98
|
+
Layer.succeed(
|
99
|
+
KeyValueStore.KeyValueStore,
|
100
|
+
KeyValueStore.makeStringOnly({
|
101
|
+
get: (_key) =>
|
102
|
+
Effect.sync(() => Eventlog.getBackendIdFromDb(dbEventlog)).pipe(
|
103
|
+
Effect.catchAllDefect((cause) =>
|
104
|
+
PlatformError.BadArgument.make({
|
105
|
+
method: 'getBackendIdFromDb',
|
106
|
+
description: 'Failed to get backendId',
|
107
|
+
module: 'KeyValueStore',
|
108
|
+
cause,
|
109
|
+
}),
|
110
|
+
),
|
111
|
+
),
|
112
|
+
set: (_key, value) =>
|
113
|
+
Effect.sync(() => Eventlog.updateBackendId(dbEventlog, value)).pipe(
|
114
|
+
Effect.catchAllDefect((cause) =>
|
115
|
+
PlatformError.BadArgument.make({
|
116
|
+
method: 'updateBackendId',
|
117
|
+
module: 'KeyValueStore',
|
118
|
+
description: 'Failed to update backendId',
|
119
|
+
cause,
|
120
|
+
}),
|
121
|
+
),
|
122
|
+
),
|
123
|
+
clear: Effect.dieMessage(`Not implemented. Should never be used.`),
|
124
|
+
remove: () => Effect.dieMessage(`Not implemented. Should never be used.`),
|
125
|
+
size: Effect.dieMessage(`Not implemented. Should never be used.`),
|
126
|
+
}),
|
127
|
+
),
|
128
|
+
),
|
129
|
+
)
|
78
130
|
|
79
131
|
if (syncBackend !== undefined) {
|
80
132
|
// We're already connecting to the sync backend concurrently
|
@@ -86,18 +138,29 @@ export const makeLeaderThreadLayer = ({
|
|
86
138
|
bootStatusQueue,
|
87
139
|
})
|
88
140
|
|
141
|
+
const materializeEvent = yield* makeMaterializeEvent({ schema, dbState, dbEventlog })
|
142
|
+
|
143
|
+
// Recreate state database if needed BEFORE creating sync processor
|
144
|
+
// This ensures all system tables exist before any queries are made
|
145
|
+
const { migrationsReport } = dbStateMissing
|
146
|
+
? yield* recreateDb({ dbState, dbEventlog, schema, bootStatusQueue, materializeEvent })
|
147
|
+
: { migrationsReport: { migrations: [] } }
|
148
|
+
|
89
149
|
const syncProcessor = yield* makeLeaderSyncProcessor({
|
90
150
|
schema,
|
91
151
|
dbState,
|
92
152
|
initialSyncState: getInitialSyncState({ dbEventlog, dbState, dbEventlogMissing }),
|
93
153
|
initialBlockingSyncContext,
|
94
154
|
onError: syncOptions?.onSyncError ?? 'ignore',
|
155
|
+
livePull: syncOptions?.livePull ?? true,
|
95
156
|
params: {
|
96
|
-
|
97
|
-
|
157
|
+
...omitUndefineds({
|
158
|
+
localPushBatchSize: params?.localPushBatchSize,
|
159
|
+
backendPushBatchSize: params?.backendPushBatchSize,
|
160
|
+
}),
|
98
161
|
},
|
99
162
|
testing: {
|
100
|
-
delays: testing?.syncProcessor?.delays,
|
163
|
+
...omitUndefineds({ delays: testing?.syncProcessor?.delays }),
|
101
164
|
},
|
102
165
|
})
|
103
166
|
|
@@ -113,7 +176,7 @@ export const makeLeaderThreadLayer = ({
|
|
113
176
|
}
|
114
177
|
: { enabled: false as const }
|
115
178
|
|
116
|
-
const
|
179
|
+
const networkStatus = yield* makeNetworkStatusSubscribable({ syncBackend, devtoolsContext })
|
117
180
|
|
118
181
|
const ctx = {
|
119
182
|
schema,
|
@@ -131,6 +194,7 @@ export const makeLeaderThreadLayer = ({
|
|
131
194
|
materializeEvent,
|
132
195
|
extraIncomingMessagesQueue,
|
133
196
|
devtools: devtoolsContext,
|
197
|
+
networkStatus,
|
134
198
|
// State will be set during `bootLeaderThread`
|
135
199
|
initialState: {} as any as LeaderThreadCtx['Type']['initialState'],
|
136
200
|
} satisfies typeof LeaderThreadCtx.Service
|
@@ -141,7 +205,7 @@ export const makeLeaderThreadLayer = ({
|
|
141
205
|
const layer = Layer.succeed(LeaderThreadCtx, ctx)
|
142
206
|
|
143
207
|
ctx.initialState = yield* bootLeaderThread({
|
144
|
-
|
208
|
+
migrationsReport,
|
145
209
|
initialBlockingSyncContext,
|
146
210
|
devtoolsOptions,
|
147
211
|
}).pipe(Effect.provide(layer))
|
@@ -244,12 +308,12 @@ const makeInitialBlockingSyncContext = ({
|
|
244
308
|
|
245
309
|
return {
|
246
310
|
blockingDeferred,
|
247
|
-
update: ({ processed,
|
311
|
+
update: ({ processed, pageInfo }) =>
|
248
312
|
Effect.gen(function* () {
|
249
313
|
if (ctx.isDone === true) return
|
250
314
|
|
251
|
-
if (ctx.total === -1) {
|
252
|
-
ctx.total = remaining + processed
|
315
|
+
if (ctx.total === -1 && pageInfo._tag === 'MoreKnown') {
|
316
|
+
ctx.total = pageInfo.remaining + processed
|
253
317
|
}
|
254
318
|
|
255
319
|
ctx.processedEvents += processed
|
@@ -258,7 +322,7 @@ const makeInitialBlockingSyncContext = ({
|
|
258
322
|
progress: { done: ctx.processedEvents, total: ctx.total },
|
259
323
|
})
|
260
324
|
|
261
|
-
if (
|
325
|
+
if (pageInfo._tag === 'NoMore' && blockingDeferred !== undefined) {
|
262
326
|
yield* Deferred.succeed(blockingDeferred, void 0)
|
263
327
|
ctx.isDone = true
|
264
328
|
}
|
@@ -271,26 +335,20 @@ const makeInitialBlockingSyncContext = ({
|
|
271
335
|
* It also starts various background processes (e.g. syncing)
|
272
336
|
*/
|
273
337
|
const bootLeaderThread = ({
|
274
|
-
|
338
|
+
migrationsReport,
|
275
339
|
initialBlockingSyncContext,
|
276
340
|
devtoolsOptions,
|
277
341
|
}: {
|
278
|
-
|
342
|
+
migrationsReport: MigrationsReport
|
279
343
|
initialBlockingSyncContext: InitialBlockingSyncContext
|
280
344
|
devtoolsOptions: DevtoolsOptions
|
281
345
|
}): Effect.Effect<
|
282
346
|
LeaderThreadCtx['Type']['initialState'],
|
283
|
-
UnexpectedError | SqliteError | IsOfflineError | InvalidPullError,
|
347
|
+
UnexpectedError | SqliteError | IsOfflineError | InvalidPullError | MaterializerHashMismatchError,
|
284
348
|
LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
|
285
349
|
> =>
|
286
350
|
Effect.gen(function* () {
|
287
|
-
const {
|
288
|
-
|
289
|
-
yield* Eventlog.initEventlogDb(dbEventlog)
|
290
|
-
|
291
|
-
const { migrationsReport } = dbStateMissing
|
292
|
-
? yield* recreateDb({ dbState, dbEventlog, schema, bootStatusQueue, materializeEvent })
|
293
|
-
: { migrationsReport: { migrations: [] } }
|
351
|
+
const { bootStatusQueue, syncProcessor } = yield* LeaderThreadCtx
|
294
352
|
|
295
353
|
// NOTE the sync processor depends on the dbs being initialized properly
|
296
354
|
const { initialLeaderHead } = yield* syncProcessor.boot
|
@@ -313,3 +371,56 @@ const bootLeaderThread = ({
|
|
313
371
|
|
314
372
|
return { migrationsReport, leaderHead: initialLeaderHead }
|
315
373
|
})
|
374
|
+
|
375
|
+
/** @internal */
|
376
|
+
export const makeNetworkStatusSubscribable = ({
|
377
|
+
syncBackend,
|
378
|
+
devtoolsContext,
|
379
|
+
}: {
|
380
|
+
syncBackend: SyncBackend.SyncBackend | undefined
|
381
|
+
devtoolsContext: DevtoolsContext
|
382
|
+
}): Effect.Effect<Subscribable.Subscribable<SyncBackend.NetworkStatus>, never, Scope.Scope> =>
|
383
|
+
Effect.gen(function* () {
|
384
|
+
const initialIsConnected = syncBackend !== undefined ? yield* SubscriptionRef.get(syncBackend.isConnected) : false
|
385
|
+
const initialLatchClosed =
|
386
|
+
devtoolsContext.enabled === true
|
387
|
+
? (yield* SubscriptionRef.get(devtoolsContext.syncBackendLatchState)).latchClosed
|
388
|
+
: false
|
389
|
+
|
390
|
+
const networkStatusRef = yield* SubscriptionRef.make<SyncBackend.NetworkStatus>({
|
391
|
+
isConnected: initialIsConnected,
|
392
|
+
timestampMs: Date.now(),
|
393
|
+
devtools: { latchClosed: initialLatchClosed },
|
394
|
+
})
|
395
|
+
|
396
|
+
const updateNetworkStatus = (patch: { isConnected?: boolean; latchClosed?: boolean }) =>
|
397
|
+
SubscriptionRef.update(networkStatusRef, (previous) => ({
|
398
|
+
isConnected: patch.isConnected ?? previous.isConnected,
|
399
|
+
timestampMs: Date.now(),
|
400
|
+
devtools: {
|
401
|
+
latchClosed: patch.latchClosed ?? previous.devtools.latchClosed,
|
402
|
+
},
|
403
|
+
}))
|
404
|
+
|
405
|
+
if (syncBackend !== undefined) {
|
406
|
+
yield* syncBackend.isConnected.changes.pipe(
|
407
|
+
Stream.tap((isConnected) => updateNetworkStatus({ isConnected })),
|
408
|
+
Stream.runDrain,
|
409
|
+
Effect.interruptible,
|
410
|
+
Effect.tapCauseLogPretty,
|
411
|
+
Effect.forkScoped,
|
412
|
+
)
|
413
|
+
}
|
414
|
+
|
415
|
+
if (devtoolsContext.enabled === true) {
|
416
|
+
yield* devtoolsContext.syncBackendLatchState.changes.pipe(
|
417
|
+
Stream.tap(({ latchClosed }) => updateNetworkStatus({ latchClosed })),
|
418
|
+
Stream.runDrain,
|
419
|
+
Effect.interruptible,
|
420
|
+
Effect.tapCauseLogPretty,
|
421
|
+
Effect.forkScoped,
|
422
|
+
)
|
423
|
+
}
|
424
|
+
|
425
|
+
return Subscribable.fromSubscriptionRef(networkStatusRef)
|
426
|
+
})
|
@@ -1,16 +1,17 @@
|
|
1
1
|
import { isDevEnv, LS_DEV, shouldNeverHappen } from '@livestore/utils'
|
2
2
|
import { Effect, Option, ReadonlyArray, Schema } from '@livestore/utils/effect'
|
3
3
|
|
4
|
-
import { type SqliteDb
|
4
|
+
import { MaterializeError, MaterializerHashMismatchError, type SqliteDb } from '../adapter-types.ts'
|
5
5
|
import { getExecStatementsFromMaterializer, hashMaterializerResults } from '../materializer-helper.ts'
|
6
6
|
import type { LiveStoreSchema } from '../schema/mod.ts'
|
7
|
-
import { EventSequenceNumber,
|
7
|
+
import { EventSequenceNumber, resolveEventDef, SystemTables, UNKNOWN_EVENT_SCHEMA_HASH } from '../schema/mod.ts'
|
8
8
|
import { insertRow } from '../sql-queries/index.ts'
|
9
9
|
import { sql } from '../util.ts'
|
10
10
|
import { execSql, execSqlPrepared } from './connection.ts'
|
11
11
|
import * as Eventlog from './eventlog.ts'
|
12
12
|
import type { MaterializeEvent } from './types.ts'
|
13
13
|
|
14
|
+
// TODO refactor `makeMaterializeEvent` to not return an Effect for the constructor as it's not needed
|
14
15
|
export const makeMaterializeEvent = ({
|
15
16
|
schema,
|
16
17
|
dbState,
|
@@ -19,7 +20,7 @@ export const makeMaterializeEvent = ({
|
|
19
20
|
schema: LiveStoreSchema
|
20
21
|
dbState: SqliteDb
|
21
22
|
dbEventlog: SqliteDb
|
22
|
-
}): Effect.Effect<MaterializeEvent
|
23
|
+
}): Effect.Effect<MaterializeEvent> =>
|
23
24
|
Effect.gen(function* () {
|
24
25
|
const eventDefSchemaHashMap = new Map(
|
25
26
|
// TODO Running `Schema.hash` can be a bottleneck for larger schemas. There is an opportunity to run this
|
@@ -32,8 +33,34 @@ export const makeMaterializeEvent = ({
|
|
32
33
|
Effect.gen(function* () {
|
33
34
|
const skipEventlog = options?.skipEventlog ?? false
|
34
35
|
|
35
|
-
const
|
36
|
-
|
36
|
+
const resolution = yield* resolveEventDef(schema, {
|
37
|
+
operation: '@livestore/common:leader-thread:materializeEvent',
|
38
|
+
event: eventEncoded,
|
39
|
+
})
|
40
|
+
|
41
|
+
if (resolution._tag === 'unknown') {
|
42
|
+
// Unknown events still enter the eventlog so newer clients can replay
|
43
|
+
// them once they learn the schema. We skip materialization to keep the
|
44
|
+
// local state consistent with the knowledge of the current client.
|
45
|
+
if (skipEventlog === false) {
|
46
|
+
yield* Eventlog.insertIntoEventlog(
|
47
|
+
eventEncoded,
|
48
|
+
dbEventlog,
|
49
|
+
UNKNOWN_EVENT_SCHEMA_HASH,
|
50
|
+
eventEncoded.clientId,
|
51
|
+
eventEncoded.sessionId,
|
52
|
+
)
|
53
|
+
}
|
54
|
+
|
55
|
+
dbState.debug.head = eventEncoded.seqNum
|
56
|
+
|
57
|
+
return {
|
58
|
+
sessionChangeset: { _tag: 'no-op' as const },
|
59
|
+
hash: Option.none(),
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
const { eventDef, materializer } = resolution
|
37
64
|
|
38
65
|
const execArgsArr = getExecStatementsFromMaterializer({
|
39
66
|
eventDef,
|
@@ -49,10 +76,7 @@ export const makeMaterializeEvent = ({
|
|
49
76
|
eventEncoded.meta.materializerHashSession._tag === 'Some' &&
|
50
77
|
eventEncoded.meta.materializerHashSession.value !== materializerHash.value
|
51
78
|
) {
|
52
|
-
yield*
|
53
|
-
cause: `Materializer hash mismatch detected for event "${eventEncoded.name}".`,
|
54
|
-
note: `Please make sure your event materializer is a pure function without side effects.`,
|
55
|
-
})
|
79
|
+
return yield* MaterializerHashMismatchError.make({ eventName: eventEncoded.name })
|
56
80
|
}
|
57
81
|
|
58
82
|
// NOTE we might want to bring this back if we want to debug no-op events
|
@@ -126,6 +150,7 @@ export const makeMaterializeEvent = ({
|
|
126
150
|
hash: materializerHash,
|
127
151
|
}
|
128
152
|
}).pipe(
|
153
|
+
Effect.mapError((cause) => MaterializeError.make({ cause })),
|
129
154
|
Effect.withSpan(`@livestore/common:leader-thread:materializeEvent`, {
|
130
155
|
attributes: {
|
131
156
|
eventName: eventEncoded.name,
|
@@ -2,8 +2,16 @@ import { casesHandled } from '@livestore/utils'
|
|
2
2
|
import { Effect, Queue } from '@livestore/utils/effect'
|
3
3
|
|
4
4
|
import type { MigrationsReport } from '../defs.ts'
|
5
|
-
import
|
6
|
-
|
5
|
+
import {
|
6
|
+
type BootStatus,
|
7
|
+
type MaterializeError,
|
8
|
+
type MigrationHooks,
|
9
|
+
migrateDb,
|
10
|
+
rematerializeFromEventlog,
|
11
|
+
type SqliteDb,
|
12
|
+
type SqliteError,
|
13
|
+
UnexpectedError,
|
14
|
+
} from '../index.ts'
|
7
15
|
import type { LiveStoreSchema } from '../schema/mod.ts'
|
8
16
|
import { configureConnection } from './connection.ts'
|
9
17
|
import type { MaterializeEvent } from './types.ts'
|
@@ -20,7 +28,7 @@ export const recreateDb = ({
|
|
20
28
|
schema: LiveStoreSchema
|
21
29
|
bootStatusQueue: Queue.Queue<BootStatus>
|
22
30
|
materializeEvent: MaterializeEvent
|
23
|
-
}): Effect.Effect<{ migrationsReport: MigrationsReport }, UnexpectedError | SqliteError> =>
|
31
|
+
}): Effect.Effect<{ migrationsReport: MigrationsReport }, UnexpectedError | MaterializeError | SqliteError> =>
|
24
32
|
Effect.gen(function* () {
|
25
33
|
const migrationOptions = schema.state.sqlite.migrations
|
26
34
|
let migrationsReport: MigrationsReport
|
@@ -1,9 +1,23 @@
|
|
1
1
|
import type { WebChannel } from '@livestore/utils/effect'
|
2
2
|
import { Schema } from '@livestore/utils/effect'
|
3
3
|
|
4
|
-
import {
|
4
|
+
import {
|
5
|
+
IntentionalShutdownCause,
|
6
|
+
InvalidPullError,
|
7
|
+
InvalidPushError,
|
8
|
+
IsOfflineError,
|
9
|
+
MaterializeError,
|
10
|
+
UnexpectedError,
|
11
|
+
} from '../index.ts'
|
5
12
|
|
6
|
-
export class All extends Schema.Union(
|
13
|
+
export class All extends Schema.Union(
|
14
|
+
IntentionalShutdownCause,
|
15
|
+
UnexpectedError,
|
16
|
+
IsOfflineError,
|
17
|
+
InvalidPushError,
|
18
|
+
InvalidPullError,
|
19
|
+
MaterializeError,
|
20
|
+
) {}
|
7
21
|
|
8
22
|
/**
|
9
23
|
* Used internally by an adapter to shutdown gracefully.
|
@@ -13,7 +13,7 @@ import { Context, Schema } from '@livestore/utils/effect'
|
|
13
13
|
import type { MeshNode } from '@livestore/webmesh'
|
14
14
|
|
15
15
|
import type { MigrationsReport } from '../defs.ts'
|
16
|
-
import type {
|
16
|
+
import type { MaterializeError } from '../errors.ts'
|
17
17
|
import type {
|
18
18
|
BootStatus,
|
19
19
|
Devtools,
|
@@ -43,7 +43,7 @@ export const InitialSyncOptions = Schema.Union(InitialSyncOptionsSkip, InitialSy
|
|
43
43
|
export type InitialSyncOptions = typeof InitialSyncOptions.Type
|
44
44
|
|
45
45
|
export type InitialSyncInfo = Option.Option<{
|
46
|
-
|
46
|
+
eventSequenceNumber: EventSequenceNumber.GlobalEventSequenceNumber
|
47
47
|
metadata: Option.Option<Schema.JsonValue>
|
48
48
|
}>
|
49
49
|
|
@@ -98,7 +98,7 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
|
|
98
98
|
shutdownChannel: ShutdownChannel
|
99
99
|
eventSchema: LiveStoreEvent.ForEventDefRecord<any>
|
100
100
|
devtools: DevtoolsContext
|
101
|
-
syncBackend: SyncBackend | undefined
|
101
|
+
syncBackend: SyncBackend.SyncBackend | undefined
|
102
102
|
syncProcessor: LeaderSyncProcessor
|
103
103
|
materializeEvent: MaterializeEvent
|
104
104
|
initialState: {
|
@@ -111,6 +111,7 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
|
|
111
111
|
* This is currently separated from `.devtools` as it also needs to work when devtools are disabled
|
112
112
|
*/
|
113
113
|
extraIncomingMessagesQueue: Queue.Queue<Devtools.Leader.MessageToApp>
|
114
|
+
networkStatus: Subscribable.Subscribable<SyncBackend.NetworkStatus>
|
114
115
|
}
|
115
116
|
>() {}
|
116
117
|
|
@@ -125,12 +126,12 @@ export type MaterializeEvent = (
|
|
125
126
|
sessionChangeset: { _tag: 'sessionChangeset'; data: Uint8Array<ArrayBuffer>; debug: any } | { _tag: 'no-op' }
|
126
127
|
hash: Option.Option<number>
|
127
128
|
},
|
128
|
-
|
129
|
+
MaterializeError
|
129
130
|
>
|
130
131
|
|
131
132
|
export type InitialBlockingSyncContext = {
|
132
133
|
blockingDeferred: Deferred.Deferred<void> | undefined
|
133
|
-
update: (_: {
|
134
|
+
update: (_: { pageInfo: SyncBackend.PullResPageInfo; processed: number }) => Effect.Effect<void>
|
134
135
|
}
|
135
136
|
|
136
137
|
export interface LeaderSyncProcessor {
|
@@ -150,6 +151,7 @@ export interface LeaderSyncProcessor {
|
|
150
151
|
options?: {
|
151
152
|
/**
|
152
153
|
* If true, the effect will only finish when the local push has been processed (i.e. succeeded or was rejected).
|
154
|
+
* `true` doesn't mean the events have been pushed to the sync backend.
|
153
155
|
* @default false
|
154
156
|
*/
|
155
157
|
waitForProcessing?: boolean
|
@@ -5,7 +5,7 @@ import type { SqliteDb } from './adapter-types.ts'
|
|
5
5
|
import { SessionIdSymbol } from './adapter-types.ts'
|
6
6
|
import type { EventDef, Materializer, MaterializerContextQuery, MaterializerResult } from './schema/EventDef.ts'
|
7
7
|
import type * as LiveStoreEvent from './schema/LiveStoreEvent.ts'
|
8
|
-
import {
|
8
|
+
import type { LiveStoreSchema } from './schema/schema.ts'
|
9
9
|
import type { QueryBuilder } from './schema/state/sqlite/query-builder/api.ts'
|
10
10
|
import { isQueryBuilder } from './schema/state/sqlite/query-builder/api.ts'
|
11
11
|
import { getResultSchema } from './schema/state/sqlite/query-builder/impl.ts'
|
@@ -31,8 +31,13 @@ export const getExecStatementsFromMaterializer = ({
|
|
31
31
|
bindValues: PreparedBindValues
|
32
32
|
writeTables: ReadonlySet<string> | undefined
|
33
33
|
}> => {
|
34
|
-
const
|
35
|
-
event.decoded === undefined
|
34
|
+
const eventDecoded =
|
35
|
+
event.decoded === undefined
|
36
|
+
? {
|
37
|
+
...event.encoded!,
|
38
|
+
args: Schema.decodeUnknownSync(eventDef.schema)(event.encoded!.args),
|
39
|
+
}
|
40
|
+
: event.decoded
|
36
41
|
|
37
42
|
const eventArgsEncoded = isNil(event.decoded?.args)
|
38
43
|
? undefined
|
@@ -58,11 +63,12 @@ export const getExecStatementsFromMaterializer = ({
|
|
58
63
|
}
|
59
64
|
|
60
65
|
const statementResults = fromMaterializerResult(
|
61
|
-
materializer(
|
66
|
+
materializer(eventDecoded.args, {
|
62
67
|
eventDef,
|
63
68
|
query,
|
64
69
|
// TODO properly implement this
|
65
70
|
currentFacts: new Map(),
|
71
|
+
event: eventDecoded,
|
66
72
|
}),
|
67
73
|
)
|
68
74
|
|
@@ -81,7 +87,18 @@ export const makeMaterializerHash =
|
|
81
87
|
({ schema, dbState }: { schema: LiveStoreSchema; dbState: SqliteDb }) =>
|
82
88
|
(event: LiveStoreEvent.AnyEncoded): Option.Option<number> => {
|
83
89
|
if (isDevEnv()) {
|
84
|
-
|
90
|
+
// Hashing is only needed during dev-mode diagnostics. Skip work entirely for
|
91
|
+
// unknown events (no definition/materializer) so we do not introduce noisy
|
92
|
+
// warnings while still returning `Option.none()` to disable hash checks.
|
93
|
+
const eventDef = schema.eventsDefsMap.get(event.name)
|
94
|
+
const materializer = schema.state.materializers.get(event.name)
|
95
|
+
if (eventDef === undefined || materializer === undefined) {
|
96
|
+
return Option.none()
|
97
|
+
}
|
98
|
+
// For known events we replay the materializer with the encoded payload and
|
99
|
+
// hash the resulting SQL statements. This lets us cheaply detect
|
100
|
+
// side-effects or logic drift between leader/client materializers without
|
101
|
+
// mutating the underlying state.
|
85
102
|
const materializerResults = getExecStatementsFromMaterializer({
|
86
103
|
eventDef,
|
87
104
|
materializer,
|
@@ -4,7 +4,7 @@ import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
|
|
4
4
|
import { type SqliteDb, UnexpectedError } from './adapter-types.ts'
|
5
5
|
import type { MaterializeEvent } from './leader-thread/mod.ts'
|
6
6
|
import type { EventDef, LiveStoreSchema } from './schema/mod.ts'
|
7
|
-
import { EventSequenceNumber,
|
7
|
+
import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } from './schema/mod.ts'
|
8
8
|
import type { PreparedBindValues } from './util.ts'
|
9
9
|
import { sql } from './util.ts'
|
10
10
|
|
@@ -31,18 +31,45 @@ export const rematerializeFromEventlog = ({
|
|
31
31
|
|
32
32
|
const processEvent = (row: SystemTables.EventlogMetaRow) =>
|
33
33
|
Effect.gen(function* () {
|
34
|
-
const
|
34
|
+
const args = JSON.parse(row.argsJson)
|
35
|
+
const eventEncoded = LiveStoreEvent.EncodedWithMeta.make({
|
36
|
+
name: row.name,
|
37
|
+
args,
|
38
|
+
seqNum: {
|
39
|
+
global: row.seqNumGlobal,
|
40
|
+
client: row.seqNumClient,
|
41
|
+
rebaseGeneration: row.seqNumRebaseGeneration,
|
42
|
+
},
|
43
|
+
parentSeqNum: {
|
44
|
+
global: row.parentSeqNumGlobal,
|
45
|
+
client: row.parentSeqNumClient,
|
46
|
+
rebaseGeneration: row.parentSeqNumRebaseGeneration,
|
47
|
+
},
|
48
|
+
clientId: row.clientId,
|
49
|
+
sessionId: row.sessionId,
|
50
|
+
})
|
51
|
+
|
52
|
+
const resolution = yield* resolveEventDef(schema, {
|
53
|
+
operation: '@livestore/common:rematerializeFromEventlog:processEvent',
|
54
|
+
event: eventEncoded,
|
55
|
+
}).pipe(UnexpectedError.mapToUnexpectedError)
|
56
|
+
|
57
|
+
if (resolution._tag === 'unknown') {
|
58
|
+
// Old snapshots can contain newer events. Skip until the runtime has
|
59
|
+
// been updated; the event stays in the log for future replays.
|
60
|
+
return
|
61
|
+
}
|
35
62
|
|
36
|
-
|
63
|
+
const { eventDef } = resolution
|
64
|
+
|
65
|
+
if (hashEventDef(eventDef) !== row.schemaHash) {
|
37
66
|
yield* Effect.logWarning(
|
38
67
|
`Schema hash mismatch for event definition ${row.name}. Trying to materialize event anyway.`,
|
39
68
|
)
|
40
69
|
}
|
41
70
|
|
42
|
-
const args = JSON.parse(row.argsJson)
|
43
|
-
|
44
71
|
// Checking whether the schema has changed in an incompatible way
|
45
|
-
yield* Schema.decodeUnknown(eventDef.
|
72
|
+
yield* Schema.decodeUnknown(eventDef.schema)(args).pipe(
|
46
73
|
Effect.mapError((cause) =>
|
47
74
|
UnexpectedError.make({
|
48
75
|
cause,
|
@@ -55,23 +82,6 @@ This likely means the schema has changed in an incompatible way.
|
|
55
82
|
),
|
56
83
|
)
|
57
84
|
|
58
|
-
const eventEncoded = LiveStoreEvent.EncodedWithMeta.make({
|
59
|
-
seqNum: {
|
60
|
-
global: row.seqNumGlobal,
|
61
|
-
client: row.seqNumClient,
|
62
|
-
rebaseGeneration: row.seqNumRebaseGeneration,
|
63
|
-
},
|
64
|
-
parentSeqNum: {
|
65
|
-
global: row.parentSeqNumGlobal,
|
66
|
-
client: row.parentSeqNumClient,
|
67
|
-
rebaseGeneration: row.parentSeqNumRebaseGeneration,
|
68
|
-
},
|
69
|
-
name: row.name,
|
70
|
-
args,
|
71
|
-
clientId: row.clientId,
|
72
|
-
sessionId: row.sessionId,
|
73
|
-
})
|
74
|
-
|
75
85
|
yield* materializeEvent(eventEncoded, { skipEventlog: true })
|
76
86
|
}).pipe(Effect.withSpan(`@livestore/common:rematerializeFromEventlog:processEvent`))
|
77
87
|
|
package/src/schema/EventDef.ts
CHANGED
@@ -4,6 +4,7 @@ import { Schema } from '@livestore/utils/effect'
|
|
4
4
|
|
5
5
|
import type { BindValues } from '../sql-queries/sql-queries.ts'
|
6
6
|
import type { ParamsObject } from '../util.ts'
|
7
|
+
import type * as LiveStoreEvent from './LiveStoreEvent.ts'
|
7
8
|
import type { QueryBuilder } from './state/sqlite/query-builder/mod.ts'
|
8
9
|
|
9
10
|
export type EventDefMap = {
|
@@ -191,6 +192,8 @@ export type Materializer<TEventDef extends EventDef.AnyWithoutFn = EventDef.AnyW
|
|
191
192
|
eventDef: TEventDef
|
192
193
|
/** Can be used to query the current state */
|
193
194
|
query: MaterializerContextQuery
|
195
|
+
/** The full LiveStore event with clientId, sessionId, etc. */
|
196
|
+
event: LiveStoreEvent.AnyDecoded
|
194
197
|
},
|
195
198
|
) => SingleOrReadonlyArray<MaterializerResult>
|
196
199
|
|
@@ -283,5 +283,4 @@ export const isEqualEncoded = (a: AnyEncoded, b: AnyEncoded) =>
|
|
283
283
|
a.name === b.name &&
|
284
284
|
a.clientId === b.clientId &&
|
285
285
|
a.sessionId === b.sessionId &&
|
286
|
-
// TODO use schema equality here
|
287
|
-
JSON.stringify(a.args) === JSON.stringify(b.args)
|
286
|
+
JSON.stringify(a.args) === JSON.stringify(b.args) // TODO use schema equality here
|
package/src/schema/mod.ts
CHANGED
@@ -7,3 +7,5 @@ export * as State from './state/mod.ts'
|
|
7
7
|
export { SqliteAst, SqliteDsl } from './state/sqlite/db-schema/mod.ts'
|
8
8
|
export * from './state/sqlite/schema-helpers.ts'
|
9
9
|
export * as SystemTables from './state/sqlite/system-tables.ts'
|
10
|
+
export type { UnknownEvents } from './unknown-events.ts'
|
11
|
+
export { normalizeUnknownEventHandling, resolveEventDef } from './unknown-events.ts'
|