@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.
Files changed (96) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/adapter-types.d.ts +26 -23
  3. package/dist/adapter-types.d.ts.map +1 -1
  4. package/dist/adapter-types.js.map +1 -1
  5. package/dist/devtools/devtools-bridge.d.ts +2 -1
  6. package/dist/devtools/devtools-bridge.d.ts.map +1 -1
  7. package/dist/devtools/devtools-messages.d.ts +90 -102
  8. package/dist/devtools/devtools-messages.d.ts.map +1 -1
  9. package/dist/devtools/devtools-messages.js +9 -6
  10. package/dist/devtools/devtools-messages.js.map +1 -1
  11. package/dist/leader-thread/apply-mutation.js.map +1 -1
  12. package/dist/leader-thread/leader-sync-processor.d.ts.map +1 -1
  13. package/dist/leader-thread/leader-sync-processor.js +10 -7
  14. package/dist/leader-thread/leader-sync-processor.js.map +1 -1
  15. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  16. package/dist/leader-thread/leader-worker-devtools.js +22 -66
  17. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  18. package/dist/leader-thread/make-leader-thread-layer.d.ts +4 -2
  19. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  20. package/dist/leader-thread/make-leader-thread-layer.js +5 -2
  21. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  22. package/dist/leader-thread/mutationlog.d.ts +4 -17
  23. package/dist/leader-thread/mutationlog.d.ts.map +1 -1
  24. package/dist/leader-thread/mutationlog.js +2 -1
  25. package/dist/leader-thread/mutationlog.js.map +1 -1
  26. package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
  27. package/dist/leader-thread/types.d.ts +7 -5
  28. package/dist/leader-thread/types.d.ts.map +1 -1
  29. package/dist/leader-thread/types.js.map +1 -1
  30. package/dist/mutation.d.ts +1 -1
  31. package/dist/mutation.d.ts.map +1 -1
  32. package/dist/rehydrate-from-mutationlog.js.map +1 -1
  33. package/dist/schema/EventId.d.ts +16 -14
  34. package/dist/schema/EventId.d.ts.map +1 -1
  35. package/dist/schema/EventId.js +15 -7
  36. package/dist/schema/EventId.js.map +1 -1
  37. package/dist/schema/MutationEvent.d.ts +51 -76
  38. package/dist/schema/MutationEvent.d.ts.map +1 -1
  39. package/dist/schema/MutationEvent.js +29 -13
  40. package/dist/schema/MutationEvent.js.map +1 -1
  41. package/dist/schema/system-tables.d.ts +17 -17
  42. package/dist/schema/system-tables.d.ts.map +1 -1
  43. package/dist/schema/system-tables.js +14 -7
  44. package/dist/schema/system-tables.js.map +1 -1
  45. package/dist/schema-management/migrations.js +6 -6
  46. package/dist/schema-management/migrations.js.map +1 -1
  47. package/dist/sync/client-session-sync-processor.d.ts +2 -2
  48. package/dist/sync/client-session-sync-processor.d.ts.map +1 -1
  49. package/dist/sync/next/history-dag-common.d.ts +1 -4
  50. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  51. package/dist/sync/next/history-dag-common.js +1 -1
  52. package/dist/sync/next/history-dag-common.js.map +1 -1
  53. package/dist/sync/next/rebase-events.d.ts +1 -1
  54. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  55. package/dist/sync/next/rebase-events.js +3 -2
  56. package/dist/sync/next/rebase-events.js.map +1 -1
  57. package/dist/sync/next/test/mutation-fixtures.d.ts +7 -7
  58. package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
  59. package/dist/sync/next/test/mutation-fixtures.js +3 -9
  60. package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
  61. package/dist/sync/sync.d.ts +6 -6
  62. package/dist/sync/sync.d.ts.map +1 -1
  63. package/dist/sync/sync.js.map +1 -1
  64. package/dist/sync/syncstate.d.ts +10 -10
  65. package/dist/sync/syncstate.test.js +2 -6
  66. package/dist/sync/syncstate.test.js.map +1 -1
  67. package/dist/sync/validate-push-payload.d.ts +2 -2
  68. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  69. package/dist/sync/validate-push-payload.js +2 -2
  70. package/dist/sync/validate-push-payload.js.map +1 -1
  71. package/dist/version.d.ts +1 -1
  72. package/dist/version.js +1 -1
  73. package/package.json +3 -3
  74. package/src/adapter-types.ts +22 -24
  75. package/src/devtools/devtools-bridge.ts +2 -1
  76. package/src/devtools/devtools-messages.ts +9 -6
  77. package/src/leader-thread/apply-mutation.ts +1 -1
  78. package/src/leader-thread/leader-sync-processor.ts +14 -10
  79. package/src/leader-thread/leader-worker-devtools.ts +30 -109
  80. package/src/leader-thread/make-leader-thread-layer.ts +15 -5
  81. package/src/leader-thread/mutationlog.ts +9 -5
  82. package/src/leader-thread/types.ts +7 -8
  83. package/src/mutation.ts +1 -1
  84. package/src/rehydrate-from-mutationlog.ts +1 -1
  85. package/src/schema/EventId.ts +23 -9
  86. package/src/schema/MutationEvent.ts +37 -18
  87. package/src/schema/system-tables.ts +14 -7
  88. package/src/schema-management/migrations.ts +6 -6
  89. package/src/sync/client-session-sync-processor.ts +2 -2
  90. package/src/sync/next/history-dag-common.ts +1 -1
  91. package/src/sync/next/rebase-events.ts +5 -5
  92. package/src/sync/next/test/mutation-fixtures.ts +3 -10
  93. package/src/sync/sync.ts +4 -2
  94. package/src/sync/syncstate.test.ts +4 -4
  95. package/src/sync/validate-push-payload.ts +7 -4
  96. 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 { PayloadUpstream, SyncState } from '../sync/syncstate.js'
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
- originId: string
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
- // mutationEvents: ReadonlyArray<MutationEvent.AnyEncoded>
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.Any | MutationEvent.PartialAny
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.Any
61
+ } satisfies MutationEvent.AnyDecoded
62
62
 
63
63
  const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
64
64
 
@@ -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: number; local: number }
19
+ export type EventId = { global: GlobalEventId; local: LocalEventId }
10
20
 
11
21
  export const EventId = Schema.Struct({
12
- global: Schema.Number,
13
- local: Schema.Number,
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: 0 } satisfies EventId
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 nextPair = (id: EventId, isLocal: boolean) => {
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: 0 },
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: 0 },
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 Any = MutationEvent<MutationDef.Any>
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: Any | PartialAny): mutationEvent is PartialAny =>
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
- export const Any = Schema.Struct({
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
- { disableAutomaticIdColumn: true, indexes: [] },
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 `${column.name} ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
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 { Coordinator, UnexpectedError } from '../adapter-types.js'
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: Coordinator['mutations']['pull']
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: 0 } satisfies EventId.EventId
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 type * as EventId from '../../schema/EventId.js'
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.Any[] => {
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: 0 } satisfies EventId.EventId,
93
- parentId: { global: headGlobalId + index, local: 0 } satisfies EventId.EventId,
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.Any,
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 = getNextEventId(mutationDef)
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: 0 }
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.AnyEncoded
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.AnyEncoded>,
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
- public readonly id: EventId.EventId,
11
- public readonly parentId: EventId.EventId,
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 = (batch: ReadonlyArray<MutationEvent.AnyEncoded>, currentEventId: number) =>
7
+ export const validatePushPayload = (
8
+ batch: ReadonlyArray<MutationEvent.AnyEncodedGlobal>,
9
+ currentEventId: EventId.GlobalEventId,
10
+ ) =>
8
11
  Effect.gen(function* () {
9
- if (batch[0]!.id.global <= currentEventId) {
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.global,
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.2' as const
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.