@livestore/common 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapter-types.d.ts +5 -0
- 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 +6 -6
- package/dist/devtools/devtools-messages-leader.d.ts +24 -24
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +13 -4
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +2 -0
- package/dist/leader-thread/eventlog.js.map +1 -1
- package/dist/leader-thread/materialize-event.d.ts +3 -3
- package/dist/leader-thread/materialize-event.d.ts.map +1 -1
- package/dist/leader-thread/materialize-event.js +20 -9
- package/dist/leader-thread/materialize-event.js.map +1 -1
- package/dist/leader-thread/mod.d.ts +1 -0
- package/dist/leader-thread/mod.d.ts.map +1 -1
- package/dist/leader-thread/mod.js +1 -0
- package/dist/leader-thread/mod.js.map +1 -1
- package/dist/leader-thread/types.d.ts +1 -0
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/materializer-helper.d.ts +13 -2
- package/dist/materializer-helper.d.ts.map +1 -1
- package/dist/materializer-helper.js +25 -11
- package/dist/materializer-helper.js.map +1 -1
- package/dist/rematerialize-from-eventlog.js +2 -2
- package/dist/rematerialize-from-eventlog.js.map +1 -1
- package/dist/schema/EventDef.d.ts +6 -1
- package/dist/schema/EventDef.d.ts.map +1 -1
- package/dist/schema/EventDef.js +3 -0
- package/dist/schema/EventDef.js.map +1 -1
- package/dist/schema/LiveStoreEvent.d.ts +35 -1
- package/dist/schema/LiveStoreEvent.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent.js +22 -4
- package/dist/schema/LiveStoreEvent.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/api.d.ts +1 -1
- package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.test.d.ts +57 -62
- package/dist/schema/state/sqlite/query-builder/impl.test.d.ts.map +1 -1
- package/dist/schema/state/sqlite/system-tables.d.ts +350 -407
- package/dist/schema/state/sqlite/system-tables.d.ts.map +1 -1
- package/dist/schema/state/sqlite/table-def.d.ts +1 -1
- package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
- package/dist/sqlite-db-helper.d.ts +7 -0
- package/dist/sqlite-db-helper.d.ts.map +1 -0
- package/dist/sqlite-db-helper.js +29 -0
- package/dist/sqlite-db-helper.js.map +1 -0
- package/dist/sync/ClientSessionSyncProcessor.d.ts +6 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +21 -6
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/event-fixtures.js +2 -0
- package/dist/sync/next/test/event-fixtures.js.map +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/package.json +5 -4
- package/src/adapter-types.ts +5 -0
- package/src/index.ts +1 -0
- package/src/leader-thread/LeaderSyncProcessor.ts +17 -2
- package/src/leader-thread/eventlog.ts +2 -0
- package/src/leader-thread/materialize-event.ts +25 -11
- package/src/leader-thread/mod.ts +1 -0
- package/src/leader-thread/types.ts +4 -1
- package/src/materializer-helper.ts +45 -19
- package/src/rematerialize-from-eventlog.ts +2 -2
- package/src/schema/EventDef.ts +11 -1
- package/src/schema/LiveStoreEvent.ts +29 -4
- package/src/schema/state/sqlite/query-builder/api.ts +1 -1
- package/src/schema/state/sqlite/table-def.ts +1 -1
- package/src/sqlite-db-helper.ts +41 -0
- package/src/sync/ClientSessionSyncProcessor.ts +34 -8
- package/src/sync/next/test/event-fixtures.ts +2 -0
- package/src/version.ts +2 -2
@@ -1,26 +1,27 @@
|
|
1
|
-
import { isNil, isReadonlyArray } from '@livestore/utils'
|
2
|
-
import { Schema } from '@livestore/utils/effect'
|
1
|
+
import { isDevEnv, isNil, isReadonlyArray } from '@livestore/utils'
|
2
|
+
import { Hash, Option, Schema } from '@livestore/utils/effect'
|
3
3
|
|
4
4
|
import type { SqliteDb } from './adapter-types.js'
|
5
5
|
import { SessionIdSymbol } from './adapter-types.js'
|
6
6
|
import type { EventDef, Materializer, MaterializerContextQuery, MaterializerResult } from './schema/EventDef.js'
|
7
7
|
import type * as LiveStoreEvent from './schema/LiveStoreEvent.js'
|
8
|
+
import { getEventDef, type LiveStoreSchema } from './schema/schema.js'
|
8
9
|
import type { QueryBuilder } from './schema/state/sqlite/query-builder/api.js'
|
9
10
|
import { isQueryBuilder } from './schema/state/sqlite/query-builder/api.js'
|
10
11
|
import { getResultSchema } from './schema/state/sqlite/query-builder/impl.js'
|
11
|
-
import {
|
12
|
+
import type { BindValues } from './sql-queries/sql-queries.js'
|
12
13
|
import type { ParamsObject, PreparedBindValues } from './util.js'
|
13
14
|
import { prepareBindValues } from './util.js'
|
14
15
|
|
15
|
-
export const
|
16
|
+
export const getExecStatementsFromMaterializer = ({
|
16
17
|
eventDef,
|
17
18
|
materializer,
|
18
|
-
|
19
|
+
dbState,
|
19
20
|
event,
|
20
21
|
}: {
|
21
22
|
eventDef: EventDef.AnyWithoutFn
|
22
23
|
materializer: Materializer
|
23
|
-
|
24
|
+
dbState: SqliteDb
|
24
25
|
/** Both encoded and decoded events are supported to reduce the number of times we need to decode/encode */
|
25
26
|
event:
|
26
27
|
| {
|
@@ -53,25 +54,25 @@ export const getExecArgsFromEvent = ({
|
|
53
54
|
) => {
|
54
55
|
if (isQueryBuilder(rawQueryOrQueryBuilder)) {
|
55
56
|
const { query, bindValues } = rawQueryOrQueryBuilder.asSql()
|
56
|
-
const rawResults =
|
57
|
+
const rawResults = dbState.select(query, prepareBindValues(bindValues, query))
|
57
58
|
const resultSchema = getResultSchema(rawQueryOrQueryBuilder)
|
58
59
|
return Schema.decodeSync(resultSchema)(rawResults)
|
59
60
|
} else {
|
60
61
|
const { query, bindValues } = rawQueryOrQueryBuilder
|
61
|
-
return
|
62
|
+
return dbState.select(query, prepareBindValues(bindValues, query))
|
62
63
|
}
|
63
64
|
}
|
64
65
|
|
65
|
-
const
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
66
|
+
const statementResults = fromMaterializerResult(
|
67
|
+
materializer(eventArgsDecoded, {
|
68
|
+
eventDef,
|
69
|
+
query,
|
70
|
+
// TODO properly implement this
|
71
|
+
currentFacts: new Map(),
|
72
|
+
}),
|
73
|
+
)
|
73
74
|
|
74
|
-
return
|
75
|
+
return statementResults.map((statementRes) => {
|
75
76
|
const statementSql = statementRes.sql
|
76
77
|
|
77
78
|
const bindValues = typeof statementRes === 'string' ? eventArgsEncoded : statementRes.bindValues
|
@@ -82,7 +83,32 @@ export const getExecArgsFromEvent = ({
|
|
82
83
|
})
|
83
84
|
}
|
84
85
|
|
85
|
-
const
|
86
|
+
export const makeMaterializerHash =
|
87
|
+
({ schema, dbState }: { schema: LiveStoreSchema; dbState: SqliteDb }) =>
|
88
|
+
(event: LiveStoreEvent.AnyEncodedGlobal): Option.Option<number> => {
|
89
|
+
if (isDevEnv()) {
|
90
|
+
const { eventDef, materializer } = getEventDef(schema, event.name)
|
91
|
+
const materializerResults = getExecStatementsFromMaterializer({
|
92
|
+
eventDef,
|
93
|
+
materializer,
|
94
|
+
dbState,
|
95
|
+
event: { decoded: undefined, encoded: event },
|
96
|
+
})
|
97
|
+
return Option.some(Hash.string(JSON.stringify(materializerResults)))
|
98
|
+
}
|
99
|
+
|
100
|
+
return Option.none()
|
101
|
+
}
|
102
|
+
|
103
|
+
export const hashMaterializerResults = (
|
104
|
+
materializerResults: ReadonlyArray<{
|
105
|
+
statementSql: string
|
106
|
+
bindValues: PreparedBindValues
|
107
|
+
writeTables: ReadonlySet<string> | undefined
|
108
|
+
}>,
|
109
|
+
) => Hash.string(JSON.stringify(materializerResults))
|
110
|
+
|
111
|
+
const fromMaterializerResult = (
|
86
112
|
materializerResult: MaterializerResult | ReadonlyArray<MaterializerResult>,
|
87
113
|
): ReadonlyArray<{
|
88
114
|
sql: string
|
@@ -90,7 +116,7 @@ const mapMaterializerResult = (
|
|
90
116
|
writeTables: ReadonlySet<string> | undefined
|
91
117
|
}> => {
|
92
118
|
if (isReadonlyArray(materializerResult)) {
|
93
|
-
return materializerResult.flatMap(
|
119
|
+
return materializerResult.flatMap(fromMaterializerResult)
|
94
120
|
}
|
95
121
|
if (isQueryBuilder(materializerResult)) {
|
96
122
|
const { query, bindValues } = materializerResult.asSql()
|
@@ -27,13 +27,13 @@ export const rematerializeFromEventlog = ({
|
|
27
27
|
`SELECT COUNT(*) AS count FROM ${SystemTables.EVENTLOG_META_TABLE}`,
|
28
28
|
)[0]!.count
|
29
29
|
|
30
|
-
const
|
30
|
+
const hashEventDef = memoizeByRef((event: EventDef.AnyWithoutFn) => Schema.hash(event.schema))
|
31
31
|
|
32
32
|
const processEvent = (row: SystemTables.EventlogMetaRow) =>
|
33
33
|
Effect.gen(function* () {
|
34
34
|
const eventDef = getEventDef(schema, row.name)
|
35
35
|
|
36
|
-
if (
|
36
|
+
if (hashEventDef(eventDef.eventDef) !== row.schemaHash) {
|
37
37
|
yield* Effect.logWarning(
|
38
38
|
`Schema hash mismatch for event definition ${row.name}. Trying to materialize event anyway.`,
|
39
39
|
)
|
package/src/schema/EventDef.ts
CHANGED
@@ -27,12 +27,18 @@ export type EventDef<TName extends string, TType, TEncoded = TType, TDerived ext
|
|
27
27
|
derived: TDerived
|
28
28
|
}
|
29
29
|
|
30
|
-
/** Helper function to construct a partial
|
30
|
+
/** Helper function to construct a partial event */
|
31
31
|
(args: TType): {
|
32
32
|
name: TName
|
33
33
|
args: TType
|
34
34
|
}
|
35
35
|
|
36
|
+
/** Helper function to construct a partial encoded event */
|
37
|
+
encoded: (args: TEncoded) => {
|
38
|
+
name: TName
|
39
|
+
args: TEncoded
|
40
|
+
}
|
41
|
+
|
36
42
|
readonly Event: {
|
37
43
|
name: TName
|
38
44
|
args: TType
|
@@ -123,6 +129,10 @@ export const defineEvent = <TName extends string, TType, TEncoded = TType, TDeri
|
|
123
129
|
|
124
130
|
Object.defineProperty(makePartialEvent, 'name', { value: name })
|
125
131
|
Object.defineProperty(makePartialEvent, 'schema', { value: schema })
|
132
|
+
Object.defineProperty(makePartialEvent, 'encoded', {
|
133
|
+
value: (args: TEncoded) => ({ name: name, args }),
|
134
|
+
})
|
135
|
+
|
126
136
|
Object.defineProperty(makePartialEvent, 'options', {
|
127
137
|
value: {
|
128
138
|
clientOnly: options?.clientOnly ?? false,
|
@@ -171,12 +171,25 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('LiveStoreEve
|
|
171
171
|
Schema.TaggedStruct('unset', {}),
|
172
172
|
),
|
173
173
|
syncMetadata: Schema.Option(Schema.JsonValue),
|
174
|
+
/** Used to detect if the materializer is side effecting (during dev) */
|
175
|
+
materializerHashLeader: Schema.Option(Schema.Number),
|
176
|
+
materializerHashSession: Schema.Option(Schema.Number),
|
174
177
|
}).pipe(
|
175
178
|
Schema.mutable,
|
176
179
|
Schema.optional,
|
177
180
|
Schema.withDefaults({
|
178
|
-
constructor: () => ({
|
179
|
-
|
181
|
+
constructor: () => ({
|
182
|
+
sessionChangeset: { _tag: 'unset' as const },
|
183
|
+
syncMetadata: Option.none(),
|
184
|
+
materializerHashLeader: Option.none(),
|
185
|
+
materializerHashSession: Option.none(),
|
186
|
+
}),
|
187
|
+
decoding: () => ({
|
188
|
+
sessionChangeset: { _tag: 'unset' as const },
|
189
|
+
syncMetadata: Option.none(),
|
190
|
+
materializerHashLeader: Option.none(),
|
191
|
+
materializerHashSession: Option.none(),
|
192
|
+
}),
|
180
193
|
}),
|
181
194
|
),
|
182
195
|
}) {
|
@@ -214,12 +227,24 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('LiveStoreEve
|
|
214
227
|
...EventSequenceNumber.nextPair(parentSeqNum, isClient),
|
215
228
|
})
|
216
229
|
|
217
|
-
static fromGlobal = (
|
230
|
+
static fromGlobal = (
|
231
|
+
event: AnyEncodedGlobal,
|
232
|
+
meta: {
|
233
|
+
syncMetadata: Option.Option<Schema.JsonValue>
|
234
|
+
materializerHashLeader: Option.Option<number>
|
235
|
+
materializerHashSession: Option.Option<number>
|
236
|
+
},
|
237
|
+
) =>
|
218
238
|
new EncodedWithMeta({
|
219
239
|
...event,
|
220
240
|
seqNum: { global: event.seqNum, client: EventSequenceNumber.clientDefault },
|
221
241
|
parentSeqNum: { global: event.parentSeqNum, client: EventSequenceNumber.clientDefault },
|
222
|
-
meta: {
|
242
|
+
meta: {
|
243
|
+
sessionChangeset: { _tag: 'unset' as const },
|
244
|
+
syncMetadata: meta.syncMetadata,
|
245
|
+
materializerHashLeader: meta.materializerHashLeader,
|
246
|
+
materializerHashSession: meta.materializerHashSession,
|
247
|
+
},
|
223
248
|
})
|
224
249
|
|
225
250
|
toGlobal = (): AnyEncodedGlobal => ({
|
@@ -117,7 +117,7 @@ export type QueryBuilder<
|
|
117
117
|
> = {
|
118
118
|
readonly [QueryBuilderTypeId]: QueryBuilderTypeId
|
119
119
|
readonly [QueryBuilderAstSymbol]: QueryBuilderAst
|
120
|
-
readonly
|
120
|
+
readonly ResultType: TResult
|
121
121
|
readonly asSql: () => { query: string; bindValues: SqlValue[] }
|
122
122
|
readonly toString: () => string
|
123
123
|
} & Omit<QueryBuilder.ApiFull<TResult, TTableDef, TWithout>, TWithout>
|
@@ -177,7 +177,7 @@ export namespace FromColumns {
|
|
177
177
|
export type InsertRowDecoded<TColumns extends SqliteDsl.Columns> = SqliteDsl.FromColumns.InsertRowDecoded<TColumns>
|
178
178
|
}
|
179
179
|
|
180
|
-
type SqliteTableDefForInput<
|
180
|
+
export type SqliteTableDefForInput<
|
181
181
|
TName extends string,
|
182
182
|
TColumns extends SqliteDsl.Columns | SqliteDsl.ColumnDefinition<any, any>,
|
183
183
|
> = SqliteDsl.TableDefinition<TName, PrettifyFlat<ToColumns<TColumns>>>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import { Schema } from '@livestore/utils/effect'
|
2
|
+
|
3
|
+
import type { SqliteDb } from './adapter-types.js'
|
4
|
+
import { getResultSchema, isQueryBuilder } from './schema/state/sqlite/query-builder/mod.js'
|
5
|
+
import type { PreparedBindValues } from './util.js'
|
6
|
+
|
7
|
+
export const makeExecute = (
|
8
|
+
execute: (
|
9
|
+
queryStr: string,
|
10
|
+
bindValues: PreparedBindValues | undefined,
|
11
|
+
options?: { onRowsChanged?: (rowsChanged: number) => void },
|
12
|
+
) => void,
|
13
|
+
): SqliteDb['execute'] => {
|
14
|
+
return (...args: any[]) => {
|
15
|
+
const [queryStrOrQueryBuilder, bindValuesOrOptions, maybeOptions] = args
|
16
|
+
|
17
|
+
if (isQueryBuilder(queryStrOrQueryBuilder)) {
|
18
|
+
const { query, bindValues } = queryStrOrQueryBuilder.asSql()
|
19
|
+
return execute(query, bindValues as unknown as PreparedBindValues, bindValuesOrOptions)
|
20
|
+
} else {
|
21
|
+
return execute(queryStrOrQueryBuilder, bindValuesOrOptions, maybeOptions)
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
export const makeSelect = <T>(
|
27
|
+
select: (queryStr: string, bindValues: PreparedBindValues | undefined) => ReadonlyArray<T>,
|
28
|
+
): SqliteDb['select'] => {
|
29
|
+
return (...args: any[]) => {
|
30
|
+
const [queryStrOrQueryBuilder, maybeBindValues] = args
|
31
|
+
|
32
|
+
if (isQueryBuilder(queryStrOrQueryBuilder)) {
|
33
|
+
const { query, bindValues } = queryStrOrQueryBuilder.asSql()
|
34
|
+
const resultSchema = getResultSchema(queryStrOrQueryBuilder)
|
35
|
+
const results = select(query, bindValues as unknown as PreparedBindValues)
|
36
|
+
return Schema.decodeSync(resultSchema)(results)
|
37
|
+
} else {
|
38
|
+
return select(queryStrOrQueryBuilder, maybeBindValues)
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/// <reference lib="dom" />
|
2
2
|
import { LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
|
3
|
-
import type
|
3
|
+
import { Option, type Runtime, type Scope } from '@livestore/utils/effect'
|
4
4
|
import { BucketQueue, Effect, FiberHandle, Queue, Schema, Stream, Subscribable } from '@livestore/utils/effect'
|
5
5
|
import * as otel from '@opentelemetry/api'
|
6
6
|
|
@@ -38,10 +38,11 @@ export const makeClientSessionSyncProcessor = ({
|
|
38
38
|
runtime: Runtime.Runtime<Scope.Scope>
|
39
39
|
materializeEvent: (
|
40
40
|
eventDecoded: LiveStoreEvent.PartialAnyDecoded,
|
41
|
-
options: { otelContext: otel.Context; withChangeset: boolean },
|
41
|
+
options: { otelContext: otel.Context; withChangeset: boolean; materializerHashLeader: Option.Option<number> },
|
42
42
|
) => {
|
43
43
|
writeTables: Set<string>
|
44
44
|
sessionChangeset: { _tag: 'sessionChangeset'; data: Uint8Array; debug: any } | { _tag: 'no-op' } | { _tag: 'unset' }
|
45
|
+
materializerHash: Option.Option<number>
|
45
46
|
}
|
46
47
|
rollback: (changeset: Uint8Array) => void
|
47
48
|
refreshTables: (tables: Set<string>) => void
|
@@ -67,6 +68,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
67
68
|
}),
|
68
69
|
}
|
69
70
|
|
71
|
+
/** Only used for debugging / observability, it's not relied upon for correctness of the sync processor. */
|
70
72
|
const syncStateUpdateQueue = Queue.unbounded<SyncState.SyncState>().pipe(Effect.runSync)
|
71
73
|
const isClientEvent = (eventEncoded: LiveStoreEvent.EncodedWithMeta) =>
|
72
74
|
getEventDef(schema, eventEncoded.name).eventDef.options.clientOnly
|
@@ -116,17 +118,28 @@ export const makeClientSessionSyncProcessor = ({
|
|
116
118
|
syncStateRef.current = mergeResult.newSyncState
|
117
119
|
syncStateUpdateQueue.offer(mergeResult.newSyncState).pipe(Effect.runSync)
|
118
120
|
|
121
|
+
// Materialize events to state
|
119
122
|
const writeTables = new Set<string>()
|
120
123
|
for (const event of mergeResult.newEvents) {
|
121
124
|
// TODO avoid encoding and decoding here again
|
122
125
|
const decodedEventDef = Schema.decodeSync(eventSchema)(event)
|
123
|
-
const
|
124
|
-
|
126
|
+
const {
|
127
|
+
writeTables: newWriteTables,
|
128
|
+
sessionChangeset,
|
129
|
+
materializerHash,
|
130
|
+
} = materializeEvent(decodedEventDef, {
|
131
|
+
otelContext,
|
132
|
+
withChangeset: true,
|
133
|
+
materializerHashLeader: Option.none(),
|
134
|
+
})
|
135
|
+
for (const table of newWriteTables) {
|
125
136
|
writeTables.add(table)
|
126
137
|
}
|
127
|
-
event.meta.sessionChangeset =
|
138
|
+
event.meta.sessionChangeset = sessionChangeset
|
139
|
+
event.meta.materializerHashSession = materializerHash
|
128
140
|
}
|
129
141
|
|
142
|
+
// Trigger push to leader
|
130
143
|
// console.debug('pushToLeader', encodedEventDefs.length, ...encodedEventDefs.map((_) => _.toJSON()))
|
131
144
|
BucketQueue.offerAll(leaderPushQueue, encodedEventDefs).pipe(Effect.runSync)
|
132
145
|
|
@@ -242,6 +255,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
242
255
|
}
|
243
256
|
}
|
244
257
|
|
258
|
+
// Pushing rebased pending events to leader
|
245
259
|
yield* BucketQueue.offerAll(leaderPushQueue, mergeResult.newSyncState.pending)
|
246
260
|
} else {
|
247
261
|
span.addEvent('merge:pull:advance', {
|
@@ -261,12 +275,21 @@ export const makeClientSessionSyncProcessor = ({
|
|
261
275
|
for (const event of mergeResult.newEvents) {
|
262
276
|
// TODO apply changeset if available (will require tracking of write tables as well)
|
263
277
|
const decodedEventDef = Schema.decodeSync(eventSchema)(event)
|
264
|
-
const
|
265
|
-
|
278
|
+
const {
|
279
|
+
writeTables: newWriteTables,
|
280
|
+
sessionChangeset,
|
281
|
+
materializerHash,
|
282
|
+
} = materializeEvent(decodedEventDef, {
|
283
|
+
otelContext,
|
284
|
+
withChangeset: true,
|
285
|
+
materializerHashLeader: event.meta.materializerHashLeader,
|
286
|
+
})
|
287
|
+
for (const table of newWriteTables) {
|
266
288
|
writeTables.add(table)
|
267
289
|
}
|
268
290
|
|
269
|
-
event.meta.sessionChangeset =
|
291
|
+
event.meta.sessionChangeset = sessionChangeset
|
292
|
+
event.meta.materializerHashSession = materializerHash
|
270
293
|
}
|
271
294
|
|
272
295
|
refreshTables(writeTables)
|
@@ -321,6 +344,9 @@ export interface ClientSessionSyncProcessor {
|
|
321
344
|
writeTables: Set<string>
|
322
345
|
}
|
323
346
|
boot: Effect.Effect<void, UnexpectedError, Scope.Scope>
|
347
|
+
/**
|
348
|
+
* Only used for debugging / observability.
|
349
|
+
*/
|
324
350
|
syncState: Subscribable.Subscribable<SyncState.SyncState>
|
325
351
|
debug: {
|
326
352
|
print: () => void
|
@@ -24,6 +24,8 @@ export const facts = defineFacts({
|
|
24
24
|
inputValue: (id: string) => `input-value-${id}`,
|
25
25
|
})
|
26
26
|
|
27
|
+
// TODO also consider the case of "OR" in `require`
|
28
|
+
// TODO compaction strategy: "make more coarse" (one data point per hour)
|
27
29
|
export const events = {
|
28
30
|
createTodo: defineEvent({
|
29
31
|
name: 'createTodo',
|
package/src/version.ts
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
// import packageJson from '../package.json' with { type: 'json' }
|
3
3
|
// export const liveStoreVersion = packageJson.version
|
4
4
|
|
5
|
-
export const liveStoreVersion = '0.3.
|
5
|
+
export const liveStoreVersion = '0.3.1' as const
|
6
6
|
|
7
7
|
/**
|
8
8
|
* This version number is incremented whenever the internal storage format changes in a breaking way.
|
9
9
|
* Whenever this version changes, LiveStore will start with fresh database files. Old database files are not deleted.
|
10
10
|
*
|
11
|
-
* While LiveStore is in
|
11
|
+
* While LiveStore is in beta, this might happen more frequently.
|
12
12
|
* In the future, LiveStore will provide a migration path for older database files to avoid the impression of data loss.
|
13
13
|
*/
|
14
14
|
export const liveStoreStorageFormatVersion = 4
|