@livestore/common 0.3.0-dev.3 → 0.3.0-dev.5
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/adapter-types.d.ts +26 -23
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js.map +1 -1
- package/dist/devtools/devtools-bridge.d.ts +2 -1
- package/dist/devtools/devtools-bridge.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.d.ts +90 -102
- package/dist/devtools/devtools-messages.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.js +9 -6
- package/dist/devtools/devtools-messages.js.map +1 -1
- package/dist/leader-thread/apply-mutation.js.map +1 -1
- package/dist/leader-thread/leader-sync-processor.d.ts.map +1 -1
- package/dist/leader-thread/leader-sync-processor.js +10 -7
- package/dist/leader-thread/leader-sync-processor.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +22 -66
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +4 -2
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +5 -2
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mutationlog.d.ts +4 -17
- package/dist/leader-thread/mutationlog.d.ts.map +1 -1
- package/dist/leader-thread/mutationlog.js +2 -1
- package/dist/leader-thread/mutationlog.js.map +1 -1
- package/dist/leader-thread/pull-queue-set.d.ts.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/mutation.d.ts +1 -1
- package/dist/mutation.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.js.map +1 -1
- package/dist/schema/EventId.d.ts +16 -14
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +15 -7
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/MutationEvent.d.ts +51 -76
- package/dist/schema/MutationEvent.d.ts.map +1 -1
- package/dist/schema/MutationEvent.js +29 -13
- package/dist/schema/MutationEvent.js.map +1 -1
- package/dist/schema/system-tables.d.ts +17 -17
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +14 -7
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema-management/migrations.js +6 -6
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/sync/client-session-sync-processor.d.ts +2 -2
- package/dist/sync/client-session-sync-processor.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +1 -4
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +1 -1
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +1 -1
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +3 -2
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts +7 -7
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.js +3 -9
- package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
- package/dist/sync/sync.d.ts +6 -6
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/syncstate.d.ts +10 -10
- package/dist/sync/syncstate.test.js +2 -6
- 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/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/src/adapter-types.ts +22 -24
- package/src/devtools/devtools-bridge.ts +2 -1
- package/src/devtools/devtools-messages.ts +9 -6
- package/src/leader-thread/apply-mutation.ts +1 -1
- package/src/leader-thread/leader-sync-processor.ts +14 -10
- package/src/leader-thread/leader-worker-devtools.ts +30 -109
- package/src/leader-thread/make-leader-thread-layer.ts +15 -5
- package/src/leader-thread/mutationlog.ts +9 -5
- package/src/leader-thread/types.ts +7 -8
- package/src/mutation.ts +1 -1
- package/src/rehydrate-from-mutationlog.ts +1 -1
- package/src/schema/EventId.ts +23 -9
- package/src/schema/MutationEvent.ts +37 -18
- package/src/schema/system-tables.ts +14 -7
- package/src/schema-management/migrations.ts +6 -6
- package/src/sync/client-session-sync-processor.ts +2 -2
- package/src/sync/next/history-dag-common.ts +1 -1
- package/src/sync/next/rebase-events.ts +5 -5
- package/src/sync/next/test/mutation-fixtures.ts +3 -10
- package/src/sync/sync.ts +4 -2
- package/src/sync/syncstate.test.ts +4 -4
- package/src/sync/validate-push-payload.ts +7 -4
- package/src/version.ts +1 -1
@@ -22,7 +22,7 @@ import type {
|
|
22
22
|
UnexpectedError,
|
23
23
|
} from '../index.js'
|
24
24
|
import type { EventId, LiveStoreSchema, MutationEvent } from '../schema/mod.js'
|
25
|
-
import type
|
25
|
+
import type * as SyncState from '../sync/syncstate.js'
|
26
26
|
import type { ShutdownChannel } from './shutdown-channel.js'
|
27
27
|
|
28
28
|
export type ShutdownState = 'running' | 'shutting-down'
|
@@ -67,7 +67,6 @@ export type DevtoolsOptions =
|
|
67
67
|
makeContext: Effect.Effect<
|
68
68
|
{
|
69
69
|
devtoolsWebChannel: WebChannel.WebChannel<Devtools.MessageToAppLeader, Devtools.MessageFromAppLeader>
|
70
|
-
shutdownChannel: ShutdownChannel
|
71
70
|
persistenceInfo: PersistenceInfoPair
|
72
71
|
},
|
73
72
|
UnexpectedError,
|
@@ -80,18 +79,21 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
|
|
80
79
|
{
|
81
80
|
schema: LiveStoreSchema
|
82
81
|
storeId: string
|
83
|
-
|
82
|
+
clientId: string
|
84
83
|
makeSyncDb: MakeSynchronousDatabase
|
85
84
|
db: LeaderDatabase
|
86
85
|
dbLog: LeaderDatabase
|
87
86
|
bootStatusQueue: Queue.Queue<BootStatus>
|
88
87
|
// TODO we should find a more elegant way to handle cases which need this ref for their implementation
|
89
88
|
shutdownStateSubRef: SubscriptionRef.SubscriptionRef<ShutdownState>
|
89
|
+
shutdownChannel: ShutdownChannel
|
90
90
|
mutationEventSchema: MutationEvent.ForMutationDefRecord<any>
|
91
91
|
// devtools: DevtoolsContext
|
92
92
|
syncBackend: SyncBackend | undefined
|
93
93
|
syncProcessor: SyncProcessor
|
94
94
|
connectedClientSessionPullQueues: PullQueueSet
|
95
|
+
/** e.g. used for `store.__dev` APIs */
|
96
|
+
extraIncomingMessagesQueue: Queue.Queue<Devtools.MessageToAppLeader>
|
95
97
|
}
|
96
98
|
>() {}
|
97
99
|
|
@@ -101,10 +103,7 @@ export type InitialBlockingSyncContext = {
|
|
101
103
|
}
|
102
104
|
|
103
105
|
export type PullQueueItem = {
|
104
|
-
|
105
|
-
// backendHead: number
|
106
|
-
payload: PayloadUpstream
|
107
|
-
// TODO move `remaining` into `PayloadUpstream`
|
106
|
+
payload: SyncState.PayloadUpstream
|
108
107
|
remaining: number
|
109
108
|
}
|
110
109
|
|
@@ -118,7 +117,7 @@ export interface SyncProcessor {
|
|
118
117
|
boot: (args: {
|
119
118
|
dbReady: Deferred.Deferred<void>
|
120
119
|
}) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient>
|
121
|
-
syncState: Effect.Effect<SyncState, UnexpectedError>
|
120
|
+
syncState: Effect.Effect<SyncState.SyncState, UnexpectedError>
|
122
121
|
}
|
123
122
|
|
124
123
|
export interface PullQueueSet {
|
package/src/mutation.ts
CHANGED
@@ -11,7 +11,7 @@ export const getExecArgsFromMutation = ({
|
|
11
11
|
mutationEventDecoded,
|
12
12
|
}: {
|
13
13
|
mutationDef: MutationDef.Any
|
14
|
-
mutationEventDecoded: MutationEvent.
|
14
|
+
mutationEventDecoded: MutationEvent.AnyDecoded | MutationEvent.PartialAny
|
15
15
|
}): ReadonlyArray<{
|
16
16
|
statementSql: string
|
17
17
|
bindValues: PreparedBindValues
|
@@ -58,7 +58,7 @@ This likely means the schema has changed in an incompatible way.
|
|
58
58
|
parentId: { global: row.parentIdGlobal, local: row.parentIdLocal },
|
59
59
|
mutation: row.mutation,
|
60
60
|
args: argsDecoded,
|
61
|
-
} satisfies MutationEvent.
|
61
|
+
} satisfies MutationEvent.AnyDecoded
|
62
62
|
|
63
63
|
const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
|
64
64
|
|
package/src/schema/EventId.ts
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
import { Schema } from '@livestore/utils/effect'
|
1
|
+
import { Brand, Schema } from '@livestore/utils/effect'
|
2
|
+
|
3
|
+
export type LocalEventId = Brand.Branded<number, 'LocalEventId'>
|
4
|
+
export const localEventId = Brand.nominal<LocalEventId>()
|
5
|
+
export const LocalEventId = Schema.fromBrand(localEventId)(Schema.Int)
|
6
|
+
|
7
|
+
export type GlobalEventId = Brand.Branded<number, 'GlobalEventId'>
|
8
|
+
export const globalEventId = Brand.nominal<GlobalEventId>()
|
9
|
+
export const GlobalEventId = Schema.fromBrand(globalEventId)(Schema.Int)
|
10
|
+
|
11
|
+
export const localDefault = 0 as any as LocalEventId
|
2
12
|
|
3
13
|
/**
|
4
14
|
* LiveStore event id value consisting of a globally unique event sequence number
|
@@ -6,11 +16,11 @@ import { Schema } from '@livestore/utils/effect'
|
|
6
16
|
*
|
7
17
|
* The local sequence number is only used for localOnly mutations and starts from 0 for each global sequence number.
|
8
18
|
*/
|
9
|
-
export type EventId = { global:
|
19
|
+
export type EventId = { global: GlobalEventId; local: LocalEventId }
|
10
20
|
|
11
21
|
export const EventId = Schema.Struct({
|
12
|
-
global:
|
13
|
-
local:
|
22
|
+
global: GlobalEventId,
|
23
|
+
local: LocalEventId,
|
14
24
|
}).annotations({ title: 'LiveStore.EventId' })
|
15
25
|
|
16
26
|
/**
|
@@ -27,20 +37,24 @@ export const isEqual = (a: EventId, b: EventId) => a.global === b.global && a.lo
|
|
27
37
|
|
28
38
|
export type EventIdPair = { id: EventId; parentId: EventId }
|
29
39
|
|
30
|
-
export const ROOT = { global: -1, local:
|
40
|
+
export const ROOT = { global: -1 as any as GlobalEventId, local: localDefault } satisfies EventId
|
31
41
|
|
32
42
|
export const isGreaterThan = (a: EventId, b: EventId) => {
|
33
43
|
return a.global > b.global || (a.global === b.global && a.local > b.local)
|
34
44
|
}
|
35
45
|
|
36
|
-
export const
|
46
|
+
export const make = (id: EventId | typeof EventId.Encoded): EventId => {
|
47
|
+
return Schema.is(EventId)(id) ? id : Schema.decodeSync(EventId)(id)
|
48
|
+
}
|
49
|
+
|
50
|
+
export const nextPair = (id: EventId, isLocal: boolean): EventIdPair => {
|
37
51
|
if (isLocal) {
|
38
|
-
return { id: { global: id.global, local: id.local + 1 }, parentId: id }
|
52
|
+
return { id: { global: id.global, local: (id.local + 1) as any as LocalEventId }, parentId: id }
|
39
53
|
}
|
40
54
|
|
41
55
|
return {
|
42
|
-
id: { global: id.global + 1, local:
|
56
|
+
id: { global: (id.global + 1) as any as GlobalEventId, local: localDefault },
|
43
57
|
// NOTE we always point to `local: 0` for non-localOnly mutations
|
44
|
-
parentId: { global: id.global, local:
|
58
|
+
parentId: { global: id.global, local: localDefault },
|
45
59
|
}
|
46
60
|
}
|
@@ -30,8 +30,29 @@ export type MutationEventEncoded<TMutationsDef extends MutationDef.Any> = {
|
|
30
30
|
parentId: EventId.EventId
|
31
31
|
}
|
32
32
|
|
33
|
-
export type
|
33
|
+
export type AnyDecoded = MutationEvent<MutationDef.Any>
|
34
|
+
export const AnyDecoded = Schema.Struct({
|
35
|
+
mutation: Schema.String,
|
36
|
+
args: Schema.Any,
|
37
|
+
id: EventId.EventId,
|
38
|
+
parentId: EventId.EventId,
|
39
|
+
}).annotations({ title: 'MutationEvent.AnyDecoded' })
|
40
|
+
|
34
41
|
export type AnyEncoded = MutationEventEncoded<MutationDef.Any>
|
42
|
+
export const AnyEncoded = Schema.Struct({
|
43
|
+
mutation: Schema.String,
|
44
|
+
args: Schema.Any,
|
45
|
+
id: EventId.EventId,
|
46
|
+
parentId: EventId.EventId,
|
47
|
+
}).annotations({ title: 'MutationEvent.AnyEncoded' })
|
48
|
+
|
49
|
+
export const AnyEncodedGlobal = Schema.Struct({
|
50
|
+
mutation: Schema.String,
|
51
|
+
args: Schema.Any,
|
52
|
+
id: EventId.GlobalEventId,
|
53
|
+
parentId: EventId.GlobalEventId,
|
54
|
+
}).annotations({ title: 'MutationEvent.AnyEncodedGlobal' })
|
55
|
+
export type AnyEncodedGlobal = typeof AnyEncodedGlobal.Type
|
35
56
|
|
36
57
|
export type PartialAny = MutationEventPartial<MutationDef.Any>
|
37
58
|
export type PartialAnyEncoded = MutationEventPartialEncoded<MutationDef.Any>
|
@@ -44,7 +65,7 @@ export type ForSchema<TSchema extends LiveStoreSchema> = {
|
|
44
65
|
[K in keyof TSchema['_MutationDefMapType']]: MutationEvent<TSchema['_MutationDefMapType'][K]>
|
45
66
|
}[keyof TSchema['_MutationDefMapType']]
|
46
67
|
|
47
|
-
export const isPartialMutationEvent = (mutationEvent:
|
68
|
+
export const isPartialMutationEvent = (mutationEvent: AnyDecoded | PartialAny): mutationEvent is PartialAny =>
|
48
69
|
'id' in mutationEvent === false && 'parentId' in mutationEvent === false
|
49
70
|
|
50
71
|
export type ForMutationDefRecord<TMutationsDefRecord extends MutationDefRecord> = Schema.Schema<
|
@@ -109,22 +130,7 @@ export const makeMutationEventPartialSchema = <TSchema extends LiveStoreSchema>(
|
|
109
130
|
|
110
131
|
export const makeMutationEventSchemaMemo = memoizeByRef(makeMutationEventSchema)
|
111
132
|
|
112
|
-
|
113
|
-
mutation: Schema.String,
|
114
|
-
args: Schema.Any,
|
115
|
-
id: EventId.EventId,
|
116
|
-
parentId: EventId.EventId,
|
117
|
-
}).annotations({ title: 'MutationEvent.Any' })
|
118
|
-
|
119
|
-
export const DecodedAny = Schema.typeSchema(Any).annotations({
|
120
|
-
title: 'MutationEvent.DecodedAny',
|
121
|
-
})
|
122
|
-
|
123
|
-
export const EncodedAny = Schema.encodedSchema(Any).annotations({
|
124
|
-
title: 'MutationEvent.EncodedAny',
|
125
|
-
})
|
126
|
-
|
127
|
-
/** Equivalent to EncodedAny but with a meta field and some convenience methods */
|
133
|
+
/** Equivalent to AnyEncoded but with a meta field and some convenience methods */
|
128
134
|
export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEvent.EncodedWithMeta')({
|
129
135
|
mutation: Schema.String,
|
130
136
|
args: Schema.Any,
|
@@ -151,6 +157,19 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
|
|
151
157
|
...this,
|
152
158
|
...EventId.nextPair(this.id, isLocal),
|
153
159
|
})
|
160
|
+
|
161
|
+
static fromGlobal = (mutationEvent: AnyEncodedGlobal) =>
|
162
|
+
new EncodedWithMeta({
|
163
|
+
...mutationEvent,
|
164
|
+
id: { global: mutationEvent.id, local: EventId.localDefault },
|
165
|
+
parentId: { global: mutationEvent.parentId, local: EventId.localDefault },
|
166
|
+
})
|
167
|
+
|
168
|
+
toGlobal = (): AnyEncodedGlobal => ({
|
169
|
+
...this,
|
170
|
+
id: this.id.global,
|
171
|
+
parentId: this.parentId.global,
|
172
|
+
})
|
154
173
|
}
|
155
174
|
|
156
175
|
export const isEqualEncoded = (a: AnyEncoded, b: AnyEncoded) =>
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { type SqliteAst as __SqliteAst, SqliteDsl } from '@livestore/db-schema'
|
2
2
|
import { Schema } from '@livestore/utils/effect'
|
3
3
|
|
4
|
+
import * as EventId from './EventId.js'
|
4
5
|
import type { FromTable } from './table-def.js'
|
5
6
|
import { table } from './table-def.js'
|
6
7
|
|
@@ -46,8 +47,8 @@ export const sessionChangesetMetaTable = table(
|
|
46
47
|
SESSION_CHANGESET_META_TABLE,
|
47
48
|
{
|
48
49
|
// TODO bring back primary key
|
49
|
-
idGlobal: SqliteDsl.integer({}),
|
50
|
-
idLocal: SqliteDsl.integer({}),
|
50
|
+
idGlobal: SqliteDsl.integer({ schema: EventId.GlobalEventId }),
|
51
|
+
idLocal: SqliteDsl.integer({ schema: EventId.LocalEventId }),
|
51
52
|
// idGlobal: SqliteDsl.integer({ primaryKey: true }),
|
52
53
|
// idLocal: SqliteDsl.integer({ primaryKey: true }),
|
53
54
|
changeset: SqliteDsl.blob({}),
|
@@ -70,16 +71,22 @@ export const MUTATION_LOG_META_TABLE = 'mutation_log'
|
|
70
71
|
export const mutationLogMetaTable = table(
|
71
72
|
MUTATION_LOG_META_TABLE,
|
72
73
|
{
|
73
|
-
idGlobal: SqliteDsl.integer({ primaryKey: true }),
|
74
|
-
idLocal: SqliteDsl.integer({ primaryKey: true }),
|
75
|
-
parentIdGlobal: SqliteDsl.integer({}),
|
76
|
-
parentIdLocal: SqliteDsl.integer({}),
|
74
|
+
idGlobal: SqliteDsl.integer({ primaryKey: true, schema: EventId.GlobalEventId }),
|
75
|
+
idLocal: SqliteDsl.integer({ primaryKey: true, schema: EventId.LocalEventId }),
|
76
|
+
parentIdGlobal: SqliteDsl.integer({ schema: EventId.GlobalEventId }),
|
77
|
+
parentIdLocal: SqliteDsl.integer({ schema: EventId.LocalEventId }),
|
77
78
|
mutation: SqliteDsl.text({}),
|
78
79
|
argsJson: SqliteDsl.text({ schema: Schema.parseJson(Schema.Any) }),
|
79
80
|
schemaHash: SqliteDsl.integer({}),
|
80
81
|
syncMetadataJson: SqliteDsl.text({ schema: Schema.parseJson(Schema.Option(Schema.JsonValue)) }),
|
81
82
|
},
|
82
|
-
{
|
83
|
+
{
|
84
|
+
disableAutomaticIdColumn: true,
|
85
|
+
indexes: [
|
86
|
+
{ columns: ['idGlobal'], name: 'idx_idGlobal' },
|
87
|
+
{ columns: ['idGlobal', 'idLocal'], name: 'idx_idGlobal_idLocal' },
|
88
|
+
],
|
89
|
+
},
|
83
90
|
)
|
84
91
|
|
85
92
|
export type MutationLogMetaRow = FromTable.RowDecoded<typeof mutationLogMetaTable>
|
@@ -129,10 +129,10 @@ export const migrateTable = ({
|
|
129
129
|
|
130
130
|
if (behaviour === 'drop-and-recreate') {
|
131
131
|
// 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`)
|
132
|
+
dbExecute(db, sql`drop table if exists '${tableName}'`)
|
133
|
+
dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
|
134
134
|
} else if (behaviour === 'create-if-not-exists') {
|
135
|
-
dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
|
135
|
+
dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
|
136
136
|
}
|
137
137
|
|
138
138
|
for (const index of tableAst.indexes) {
|
@@ -162,11 +162,11 @@ export const migrateTable = ({
|
|
162
162
|
|
163
163
|
const createIndexFromDefinition = (tableName: string, index: SqliteAst.Index) => {
|
164
164
|
const uniqueStr = index.unique ? 'UNIQUE' : ''
|
165
|
-
return sql`create ${uniqueStr} index if not exists ${index.name} on ${tableName} (${index.columns.join(', ')})`
|
165
|
+
return sql`create ${uniqueStr} index if not exists '${index.name}' on '${tableName}' (${index.columns.join(', ')})`
|
166
166
|
}
|
167
167
|
|
168
168
|
export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
|
169
|
-
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name)
|
169
|
+
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => `'${_.name}'`)
|
170
170
|
const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
|
171
171
|
if (primaryKeys.length > 0) {
|
172
172
|
columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
|
@@ -191,5 +191,5 @@ const toSqliteColumnSpec = (column: SqliteAst.Column) => {
|
|
191
191
|
return `default ${encodedDefaultValue}`
|
192
192
|
})()
|
193
193
|
|
194
|
-
return
|
194
|
+
return `'${column.name}' ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
|
195
195
|
}
|
@@ -3,7 +3,7 @@ import type { Scope } from '@livestore/utils/effect'
|
|
3
3
|
import { Effect, Schema, Stream } from '@livestore/utils/effect'
|
4
4
|
import * as otel from '@opentelemetry/api'
|
5
5
|
|
6
|
-
import type {
|
6
|
+
import type { ClientSessionLeaderThreadProxy, UnexpectedError } from '../adapter-types.js'
|
7
7
|
import * as EventId from '../schema/EventId.js'
|
8
8
|
import { type LiveStoreSchema } from '../schema/mod.js'
|
9
9
|
import * as MutationEvent from '../schema/MutationEvent.js'
|
@@ -32,7 +32,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
32
32
|
schema: LiveStoreSchema
|
33
33
|
initialLeaderHead: EventId.EventId
|
34
34
|
pushToLeader: (batch: ReadonlyArray<MutationEvent.AnyEncoded>) => void
|
35
|
-
pullFromLeader:
|
35
|
+
pullFromLeader: ClientSessionLeaderThreadProxy['mutations']['pull']
|
36
36
|
applyMutation: (
|
37
37
|
mutationEventDecoded: MutationEvent.PartialAny,
|
38
38
|
options: { otelContext: otel.Context; withChangeset: boolean },
|
@@ -20,7 +20,7 @@ export const emptyHistoryDag = (): HistoryDag =>
|
|
20
20
|
})
|
21
21
|
|
22
22
|
// TODO consider making `ROOT_ID` parent to itself
|
23
|
-
export const rootParentId = { global: EventId.ROOT.global - 1, local:
|
23
|
+
export const rootParentId = EventId.make({ global: EventId.ROOT.global - 1, local: EventId.localDefault })
|
24
24
|
|
25
25
|
export type HistoryDagNode = {
|
26
26
|
id: EventId.EventId
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import
|
1
|
+
import * as EventId from '../../schema/EventId.js'
|
2
2
|
import type * as MutationEvent from '../../schema/MutationEvent.js'
|
3
3
|
import type { MutationDef, MutationEventFactsSnapshot } from '../../schema/mutations.js'
|
4
4
|
import {
|
@@ -48,7 +48,7 @@ export const rebaseEvents = ({
|
|
48
48
|
newRemoteEvents: HistoryDagNode[]
|
49
49
|
rebaseFn: RebaseFn
|
50
50
|
currentFactsSnapshot: MutationEventFactsSnapshot
|
51
|
-
}): MutationEvent.
|
51
|
+
}): ReadonlyArray<MutationEvent.AnyDecoded> => {
|
52
52
|
const initialSnapshot = new Map(currentFactsSnapshot)
|
53
53
|
applyFactGroups(
|
54
54
|
newRemoteEvents.map((event) => event.factsGroup),
|
@@ -89,10 +89,10 @@ export const rebaseEvents = ({
|
|
89
89
|
return rebasedLocalEvents.map(
|
90
90
|
(event, index) =>
|
91
91
|
({
|
92
|
-
id: { global: headGlobalId + index + 1, local:
|
93
|
-
parentId: { global: headGlobalId + index, local:
|
92
|
+
id: EventId.make({ global: headGlobalId + index + 1, local: EventId.localDefault }),
|
93
|
+
parentId: EventId.make({ global: headGlobalId + index, local: EventId.localDefault }),
|
94
94
|
mutation: event.mutation,
|
95
95
|
args: event.args,
|
96
|
-
}) satisfies MutationEvent.
|
96
|
+
}) satisfies MutationEvent.AnyDecoded,
|
97
97
|
)
|
98
98
|
}
|
@@ -140,16 +140,9 @@ export const toEventNodes = (
|
|
140
140
|
|
141
141
|
let currentEventId: EventId.EventId = EventId.ROOT
|
142
142
|
|
143
|
-
const getNextEventId = (mutationDef: MutationDef.Any): EventId.EventId => {
|
144
|
-
if (mutationDef.options.localOnly) {
|
145
|
-
return { global: currentEventId.global, local: currentEventId.local + 1 }
|
146
|
-
}
|
147
|
-
return { global: currentEventId.global + 1, local: 0 }
|
148
|
-
}
|
149
|
-
|
150
143
|
const eventNodes = partialEvents.map((partialEvent) => {
|
151
144
|
const mutationDef = mutationDefs[partialEvent.mutation]!
|
152
|
-
const eventId =
|
145
|
+
const eventId = EventId.nextPair(currentEventId, mutationDef.options.localOnly).id
|
153
146
|
currentEventId = eventId
|
154
147
|
|
155
148
|
const factsSnapshot = factsSnapshotForDag(historyDagFromNodes(nodesAcc, { skipFactsCheck: true }), undefined)
|
@@ -224,8 +217,8 @@ const getParentId = (eventId: EventId.EventId): EventId.EventId => {
|
|
224
217
|
const localParentId = eventId.local - 1
|
225
218
|
|
226
219
|
if (localParentId < 0) {
|
227
|
-
return { global: globalParentId - 1, local:
|
220
|
+
return EventId.make({ global: globalParentId - 1, local: EventId.localDefault })
|
228
221
|
}
|
229
222
|
|
230
|
-
return { global: globalParentId, local: localParentId }
|
223
|
+
return EventId.make({ global: globalParentId, local: localParentId })
|
231
224
|
}
|
package/src/sync/sync.ts
CHANGED
@@ -18,7 +18,7 @@ export type SyncBackend<TSyncMetadata = Schema.JsonValue> = {
|
|
18
18
|
) => Stream.Stream<
|
19
19
|
{
|
20
20
|
batch: ReadonlyArray<{
|
21
|
-
mutationEventEncoded: MutationEvent.
|
21
|
+
mutationEventEncoded: MutationEvent.AnyEncodedGlobal
|
22
22
|
metadata: Option.Option<TSyncMetadata>
|
23
23
|
}>
|
24
24
|
remaining: number
|
@@ -33,7 +33,7 @@ export type SyncBackend<TSyncMetadata = Schema.JsonValue> = {
|
|
33
33
|
* - Number of events: 1-100
|
34
34
|
* - event ids must be in ascending order
|
35
35
|
* */
|
36
|
-
batch: ReadonlyArray<MutationEvent.
|
36
|
+
batch: ReadonlyArray<MutationEvent.AnyEncodedGlobal>,
|
37
37
|
) => Effect.Effect<
|
38
38
|
{
|
39
39
|
/** Indexes are relative to `batch` */
|
@@ -46,6 +46,7 @@ export type SyncBackend<TSyncMetadata = Schema.JsonValue> = {
|
|
46
46
|
}
|
47
47
|
|
48
48
|
export class IsOfflineError extends Schema.TaggedError<IsOfflineError>()('IsOfflineError', {}) {}
|
49
|
+
|
49
50
|
export class InvalidPushError extends Schema.TaggedError<InvalidPushError>()('InvalidPushError', {
|
50
51
|
reason: Schema.Union(
|
51
52
|
Schema.TaggedStruct('Unexpected', {
|
@@ -61,6 +62,7 @@ export class InvalidPushError extends Schema.TaggedError<InvalidPushError>()('In
|
|
61
62
|
}),
|
62
63
|
),
|
63
64
|
}) {}
|
65
|
+
|
64
66
|
export class InvalidPullError extends Schema.TaggedError<InvalidPullError>()('InvalidPullError', {
|
65
67
|
message: Schema.String,
|
66
68
|
}) {}
|
@@ -7,14 +7,14 @@ import * as SyncState from './syncstate.js'
|
|
7
7
|
|
8
8
|
class TestEvent extends MutationEvent.EncodedWithMeta {
|
9
9
|
constructor(
|
10
|
-
|
11
|
-
|
10
|
+
id: EventId.EventId | typeof EventId.EventId.Encoded,
|
11
|
+
parentId: EventId.EventId,
|
12
12
|
public readonly payload: string,
|
13
13
|
public readonly isLocal: boolean,
|
14
14
|
) {
|
15
15
|
super({
|
16
|
-
id,
|
17
|
-
parentId,
|
16
|
+
id: EventId.make(id),
|
17
|
+
parentId: EventId.make(parentId),
|
18
18
|
mutation: 'a',
|
19
19
|
args: payload,
|
20
20
|
meta: {},
|
@@ -1,17 +1,20 @@
|
|
1
1
|
import { Effect } from '@livestore/utils/effect'
|
2
2
|
|
3
|
-
import type { MutationEvent } from '../schema/mod.js'
|
3
|
+
import type { EventId, MutationEvent } from '../schema/mod.js'
|
4
4
|
import { InvalidPushError } from './sync.js'
|
5
5
|
|
6
6
|
// TODO proper batch validation
|
7
|
-
export const validatePushPayload = (
|
7
|
+
export const validatePushPayload = (
|
8
|
+
batch: ReadonlyArray<MutationEvent.AnyEncodedGlobal>,
|
9
|
+
currentEventId: EventId.GlobalEventId,
|
10
|
+
) =>
|
8
11
|
Effect.gen(function* () {
|
9
|
-
if (batch[0]!.id
|
12
|
+
if (batch[0]!.id <= currentEventId) {
|
10
13
|
return yield* InvalidPushError.make({
|
11
14
|
reason: {
|
12
15
|
_tag: 'ServerAhead',
|
13
16
|
minimumExpectedId: currentEventId + 1,
|
14
|
-
providedId: batch[0]!.id
|
17
|
+
providedId: batch[0]!.id,
|
15
18
|
},
|
16
19
|
})
|
17
20
|
}
|
package/src/version.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
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.0-dev.
|
5
|
+
export const liveStoreVersion = '0.3.0-dev.4' as const
|
6
6
|
|
7
7
|
/**
|
8
8
|
* This version number is incremented whenever the internal storage format changes in a breaking way.
|