@livestore/common 0.3.0-dev.12 → 0.3.0-dev.13

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 (239) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/__tests__/fixture.d.ts +21 -21
  3. package/dist/db-schema/ast/sqlite.d.ts +69 -0
  4. package/dist/db-schema/ast/sqlite.d.ts.map +1 -0
  5. package/dist/db-schema/ast/sqlite.js +71 -0
  6. package/dist/db-schema/ast/sqlite.js.map +1 -0
  7. package/dist/db-schema/ast/validate.d.ts +3 -0
  8. package/dist/db-schema/ast/validate.d.ts.map +1 -0
  9. package/dist/db-schema/ast/validate.js +12 -0
  10. package/dist/db-schema/ast/validate.js.map +1 -0
  11. package/dist/db-schema/dsl/field-defs.d.ts +90 -0
  12. package/dist/db-schema/dsl/field-defs.d.ts.map +1 -0
  13. package/dist/db-schema/dsl/field-defs.js +87 -0
  14. package/dist/db-schema/dsl/field-defs.js.map +1 -0
  15. package/dist/db-schema/dsl/field-defs.test.d.ts +2 -0
  16. package/dist/db-schema/dsl/field-defs.test.d.ts.map +1 -0
  17. package/dist/db-schema/dsl/field-defs.test.js +29 -0
  18. package/dist/db-schema/dsl/field-defs.test.js.map +1 -0
  19. package/dist/db-schema/dsl/index.d.ts +88 -0
  20. package/dist/db-schema/dsl/index.d.ts.map +1 -0
  21. package/dist/db-schema/dsl/index.js +35 -0
  22. package/dist/db-schema/dsl/index.js.map +1 -0
  23. package/dist/db-schema/dsl/mod.d.ts +90 -0
  24. package/dist/db-schema/dsl/mod.d.ts.map +1 -0
  25. package/dist/db-schema/dsl/mod.js +35 -0
  26. package/dist/db-schema/dsl/mod.js.map +1 -0
  27. package/dist/db-schema/dsl/sqlite/field-defs.d.ts +90 -0
  28. package/dist/db-schema/dsl/sqlite/field-defs.d.ts.map +1 -0
  29. package/dist/db-schema/dsl/sqlite/field-defs.js +86 -0
  30. package/dist/db-schema/dsl/sqlite/field-defs.js.map +1 -0
  31. package/dist/db-schema/dsl/sqlite/field-defs.test.d.ts +2 -0
  32. package/dist/db-schema/dsl/sqlite/field-defs.test.d.ts.map +1 -0
  33. package/dist/db-schema/dsl/sqlite/field-defs.test.js +29 -0
  34. package/dist/db-schema/dsl/sqlite/field-defs.test.js.map +1 -0
  35. package/dist/db-schema/dsl/sqlite/index.d.ts +88 -0
  36. package/dist/db-schema/dsl/sqlite/index.d.ts.map +1 -0
  37. package/dist/db-schema/dsl/sqlite/index.js +35 -0
  38. package/dist/db-schema/dsl/sqlite/index.js.map +1 -0
  39. package/dist/db-schema/hash.d.ts +2 -0
  40. package/dist/db-schema/hash.d.ts.map +1 -0
  41. package/dist/db-schema/hash.js +14 -0
  42. package/dist/db-schema/hash.js.map +1 -0
  43. package/dist/db-schema/index.d.ts +4 -0
  44. package/dist/db-schema/index.d.ts.map +1 -0
  45. package/dist/db-schema/index.js +6 -0
  46. package/dist/db-schema/index.js.map +1 -0
  47. package/dist/db-schema/mod.d.ts +3 -0
  48. package/dist/db-schema/mod.d.ts.map +1 -0
  49. package/dist/db-schema/mod.js +3 -0
  50. package/dist/db-schema/mod.js.map +1 -0
  51. package/dist/derived-mutations.d.ts +1 -1
  52. package/dist/derived-mutations.d.ts.map +1 -1
  53. package/dist/derived-mutations.js +3 -3
  54. package/dist/derived-mutations.js.map +1 -1
  55. package/dist/devtools/devtools-messages-client-session.d.ts +23 -23
  56. package/dist/devtools/devtools-messages-common.d.ts +6 -6
  57. package/dist/devtools/devtools-messages-leader.d.ts +41 -53
  58. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  59. package/dist/devtools/devtools-messages-leader.js +5 -4
  60. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  61. package/dist/index.d.ts +1 -1
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +1 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  66. package/dist/leader-thread/LeaderSyncProcessor.js +24 -22
  67. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  68. package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
  69. package/dist/leader-thread/apply-mutation.js +8 -6
  70. package/dist/leader-thread/apply-mutation.js.map +1 -1
  71. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  72. package/dist/leader-thread/leader-worker-devtools.js +6 -12
  73. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  74. package/dist/leader-thread/make-leader-thread-layer.js +6 -1
  75. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  76. package/dist/leader-thread/mutationlog.d.ts +1 -1
  77. package/dist/leader-thread/mutationlog.d.ts.map +1 -1
  78. package/dist/leader-thread/mutationlog.js +7 -5
  79. package/dist/leader-thread/mutationlog.js.map +1 -1
  80. package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
  81. package/dist/leader-thread/types.d.ts +7 -3
  82. package/dist/leader-thread/types.d.ts.map +1 -1
  83. package/dist/leader-thread/types.js +1 -1
  84. package/dist/leader-thread/types.js.map +1 -1
  85. package/dist/query-builder/api.d.ts +1 -1
  86. package/dist/query-builder/api.d.ts.map +1 -1
  87. package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
  88. package/dist/rehydrate-from-mutationlog.js +8 -6
  89. package/dist/rehydrate-from-mutationlog.js.map +1 -1
  90. package/dist/schema/EventId.d.ts +9 -9
  91. package/dist/schema/EventId.d.ts.map +1 -1
  92. package/dist/schema/EventId.js +12 -12
  93. package/dist/schema/EventId.js.map +1 -1
  94. package/dist/schema/EventId.test.js +3 -3
  95. package/dist/schema/EventId.test.js.map +1 -1
  96. package/dist/schema/MutationEvent.d.ts +37 -12
  97. package/dist/schema/MutationEvent.d.ts.map +1 -1
  98. package/dist/schema/MutationEvent.js +20 -4
  99. package/dist/schema/MutationEvent.js.map +1 -1
  100. package/dist/schema/db-schema/ast/sqlite.d.ts +69 -0
  101. package/dist/schema/db-schema/ast/sqlite.d.ts.map +1 -0
  102. package/dist/schema/db-schema/ast/sqlite.js +71 -0
  103. package/dist/schema/db-schema/ast/sqlite.js.map +1 -0
  104. package/dist/schema/db-schema/ast/validate.d.ts +3 -0
  105. package/dist/schema/db-schema/ast/validate.d.ts.map +1 -0
  106. package/dist/schema/db-schema/ast/validate.js +12 -0
  107. package/dist/schema/db-schema/ast/validate.js.map +1 -0
  108. package/dist/schema/db-schema/dsl/field-defs.d.ts +90 -0
  109. package/dist/schema/db-schema/dsl/field-defs.d.ts.map +1 -0
  110. package/dist/schema/db-schema/dsl/field-defs.js +87 -0
  111. package/dist/schema/db-schema/dsl/field-defs.js.map +1 -0
  112. package/dist/schema/db-schema/dsl/field-defs.test.d.ts +2 -0
  113. package/dist/schema/db-schema/dsl/field-defs.test.d.ts.map +1 -0
  114. package/dist/schema/db-schema/dsl/field-defs.test.js +29 -0
  115. package/dist/schema/db-schema/dsl/field-defs.test.js.map +1 -0
  116. package/dist/schema/db-schema/dsl/mod.d.ts +88 -0
  117. package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -0
  118. package/dist/schema/db-schema/dsl/mod.js +35 -0
  119. package/dist/schema/db-schema/dsl/mod.js.map +1 -0
  120. package/dist/schema/db-schema/hash.d.ts +2 -0
  121. package/dist/schema/db-schema/hash.d.ts.map +1 -0
  122. package/dist/schema/db-schema/hash.js +14 -0
  123. package/dist/schema/db-schema/hash.js.map +1 -0
  124. package/dist/schema/db-schema/mod.d.ts +3 -0
  125. package/dist/schema/db-schema/mod.d.ts.map +1 -0
  126. package/dist/schema/db-schema/mod.js +3 -0
  127. package/dist/schema/db-schema/mod.js.map +1 -0
  128. package/dist/schema/mod.d.ts +1 -0
  129. package/dist/schema/mod.d.ts.map +1 -1
  130. package/dist/schema/mod.js +1 -0
  131. package/dist/schema/mod.js.map +1 -1
  132. package/dist/schema/mutations.d.ts +5 -9
  133. package/dist/schema/mutations.d.ts.map +1 -1
  134. package/dist/schema/mutations.js +2 -2
  135. package/dist/schema/mutations.js.map +1 -1
  136. package/dist/schema/schema-helpers.js +1 -1
  137. package/dist/schema/schema-helpers.js.map +1 -1
  138. package/dist/schema/schema.d.ts +1 -1
  139. package/dist/schema/schema.d.ts.map +1 -1
  140. package/dist/schema/schema.js +1 -1
  141. package/dist/schema/schema.js.map +1 -1
  142. package/dist/schema/system-tables.d.ts +47 -29
  143. package/dist/schema/system-tables.d.ts.map +1 -1
  144. package/dist/schema/system-tables.js +10 -7
  145. package/dist/schema/system-tables.js.map +1 -1
  146. package/dist/schema/table-def.d.ts +18 -14
  147. package/dist/schema/table-def.d.ts.map +1 -1
  148. package/dist/schema/table-def.js +3 -4
  149. package/dist/schema/table-def.js.map +1 -1
  150. package/dist/schema-management/migrations.d.ts +1 -1
  151. package/dist/schema-management/migrations.d.ts.map +1 -1
  152. package/dist/schema-management/migrations.js +1 -1
  153. package/dist/schema-management/migrations.js.map +1 -1
  154. package/dist/sql-queries/sql-queries.d.ts +1 -1
  155. package/dist/sql-queries/sql-queries.d.ts.map +1 -1
  156. package/dist/sql-queries/sql-queries.js.map +1 -1
  157. package/dist/sql-queries/sql-query-builder.d.ts +1 -1
  158. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  159. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  160. package/dist/sql-queries/types.d.ts +2 -1
  161. package/dist/sql-queries/types.d.ts.map +1 -1
  162. package/dist/sql-queries/types.js.map +1 -1
  163. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  164. package/dist/sync/ClientSessionSyncProcessor.js +18 -3
  165. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  166. package/dist/sync/next/facts.js +1 -1
  167. package/dist/sync/next/facts.js.map +1 -1
  168. package/dist/sync/next/history-dag-common.d.ts +2 -0
  169. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  170. package/dist/sync/next/history-dag-common.js +3 -1
  171. package/dist/sync/next/history-dag-common.js.map +1 -1
  172. package/dist/sync/next/history-dag.d.ts.map +1 -1
  173. package/dist/sync/next/history-dag.js +1 -1
  174. package/dist/sync/next/history-dag.js.map +1 -1
  175. package/dist/sync/next/rebase-events.d.ts +3 -1
  176. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  177. package/dist/sync/next/rebase-events.js +5 -3
  178. package/dist/sync/next/rebase-events.js.map +1 -1
  179. package/dist/sync/next/test/compact-events.calculator.test.js +12 -12
  180. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  181. package/dist/sync/next/test/compact-events.test.js +43 -43
  182. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  183. package/dist/sync/next/test/mutation-fixtures.d.ts +11 -11
  184. package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
  185. package/dist/sync/next/test/mutation-fixtures.js +12 -10
  186. package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
  187. package/dist/sync/sync.d.ts +2 -2
  188. package/dist/sync/syncstate.d.ts +9 -9
  189. package/dist/sync/syncstate.js +6 -6
  190. package/dist/sync/syncstate.js.map +1 -1
  191. package/dist/sync/syncstate.test.js +18 -16
  192. package/dist/sync/syncstate.test.js.map +1 -1
  193. package/dist/version.d.ts +1 -1
  194. package/dist/version.js +1 -1
  195. package/package.json +2 -3
  196. package/src/derived-mutations.ts +4 -4
  197. package/src/devtools/devtools-messages-leader.ts +5 -4
  198. package/src/index.ts +1 -1
  199. package/src/leader-thread/LeaderSyncProcessor.ts +28 -22
  200. package/src/leader-thread/apply-mutation.ts +15 -5
  201. package/src/leader-thread/leader-worker-devtools.ts +6 -13
  202. package/src/leader-thread/make-leader-thread-layer.ts +9 -1
  203. package/src/leader-thread/mutationlog.ts +8 -6
  204. package/src/leader-thread/types.ts +6 -2
  205. package/src/query-builder/api.ts +1 -1
  206. package/src/rehydrate-from-mutationlog.ts +8 -6
  207. package/src/schema/EventId.test.ts +3 -3
  208. package/src/schema/EventId.ts +17 -17
  209. package/src/schema/MutationEvent.ts +31 -6
  210. package/src/schema/db-schema/ast/sqlite.ts +142 -0
  211. package/src/schema/db-schema/ast/validate.ts +13 -0
  212. package/src/schema/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +206 -0
  213. package/src/schema/db-schema/dsl/field-defs.test.ts +35 -0
  214. package/src/schema/db-schema/dsl/field-defs.ts +242 -0
  215. package/src/schema/db-schema/dsl/mod.ts +195 -0
  216. package/src/schema/db-schema/hash.ts +14 -0
  217. package/src/schema/db-schema/mod.ts +2 -0
  218. package/src/schema/mod.ts +1 -0
  219. package/src/schema/mutations.ts +6 -19
  220. package/src/schema/schema-helpers.ts +1 -1
  221. package/src/schema/schema.ts +2 -2
  222. package/src/schema/system-tables.ts +10 -7
  223. package/src/schema/table-def.ts +17 -16
  224. package/src/schema-management/migrations.ts +1 -1
  225. package/src/sql-queries/sql-queries.ts +1 -1
  226. package/src/sql-queries/sql-query-builder.ts +1 -2
  227. package/src/sql-queries/types.ts +3 -1
  228. package/src/sync/ClientSessionSyncProcessor.ts +23 -4
  229. package/src/sync/next/facts.ts +1 -1
  230. package/src/sync/next/history-dag-common.ts +5 -1
  231. package/src/sync/next/history-dag.ts +1 -1
  232. package/src/sync/next/rebase-events.ts +8 -2
  233. package/src/sync/next/test/compact-events.calculator.test.ts +12 -12
  234. package/src/sync/next/test/compact-events.test.ts +43 -43
  235. package/src/sync/next/test/mutation-fixtures.ts +16 -12
  236. package/src/sync/syncstate.test.ts +19 -17
  237. package/src/sync/syncstate.ts +6 -6
  238. package/src/version.ts +1 -1
  239. package/tsconfig.json +1 -1
@@ -225,7 +225,15 @@ const bootLeaderThread = ({
225
225
  yield* Deferred.succeed(dbReady, void 0)
226
226
 
227
227
  if (initialBlockingSyncContext.blockingDeferred !== undefined) {
228
- yield* initialBlockingSyncContext.blockingDeferred
228
+ // Provides a syncing status right away before the first pull response comes in
229
+ yield* Queue.offer(bootStatusQueue, {
230
+ stage: 'syncing',
231
+ progress: { done: 0, total: -1 },
232
+ })
233
+
234
+ yield* initialBlockingSyncContext.blockingDeferred.pipe(
235
+ Effect.withSpan('@livestore/common:leader-thread:initial-sync-blocking'),
236
+ )
229
237
  }
230
238
 
231
239
  yield* Queue.offer(bootStatusQueue, { stage: 'done' })
@@ -23,18 +23,20 @@ export const getMutationEventsSince = (
23
23
  .map((_) => ({
24
24
  mutation: _.mutation,
25
25
  args: _.argsJson,
26
- id: { global: _.idGlobal, local: _.idLocal },
27
- parentId: { global: _.parentIdGlobal, local: _.parentIdLocal },
26
+ id: { global: _.idGlobal, client: _.idClient },
27
+ parentId: { global: _.parentIdGlobal, client: _.parentIdClient },
28
+ clientId: _.clientId,
29
+ sessionId: _.sessionId ?? undefined,
28
30
  }))
29
31
  .filter((_) => EventId.compare(_.id, since) > 0)
30
32
  })
31
33
 
32
- export const getLocalHeadFromDb = (dbMutationLog: SqliteDb): EventId.EventId => {
33
- const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId; idLocal: EventId.LocalEventId }>(
34
- sql`select idGlobal, idLocal from ${MUTATION_LOG_META_TABLE} order by idGlobal DESC, idLocal DESC limit 1`,
34
+ export const getClientHeadFromDb = (dbMutationLog: SqliteDb): EventId.EventId => {
35
+ const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId; idClient: EventId.ClientEventId }>(
36
+ sql`select idGlobal, idClient from ${MUTATION_LOG_META_TABLE} order by idGlobal DESC, idClient DESC limit 1`,
35
37
  )[0]
36
38
 
37
- return res ? { global: res.idGlobal, local: res.idLocal } : EventId.ROOT
39
+ return res ? { global: res.idGlobal, client: res.idClient } : EventId.ROOT
38
40
  }
39
41
 
40
42
  export const getBackendHeadFromDb = (dbMutationLog: SqliteDb): EventId.GlobalEventId =>
@@ -32,7 +32,7 @@ export const InitialSyncOptionsSkip = Schema.TaggedStruct('Skip', {})
32
32
  export type InitialSyncOptionsSkip = typeof InitialSyncOptionsSkip.Type
33
33
 
34
34
  export const InitialSyncOptionsBlocking = Schema.TaggedStruct('Blocking', {
35
- timeout: Schema.DurationFromMillis,
35
+ timeout: Schema.Union(Schema.DurationFromMillis, Schema.Number),
36
36
  })
37
37
 
38
38
  export type InitialSyncOptionsBlocking = typeof InitialSyncOptionsBlocking.Type
@@ -134,7 +134,11 @@ export interface LeaderSyncProcessor {
134
134
  },
135
135
  ) => Effect.Effect<void, InvalidPushError>
136
136
 
137
- pushPartial: (mutationEvent: MutationEvent.PartialAnyEncoded) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx>
137
+ pushPartial: (args: {
138
+ mutationEvent: MutationEvent.PartialAnyEncoded
139
+ clientId: string
140
+ sessionId: string | undefined
141
+ }) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx>
138
142
  boot: (args: {
139
143
  dbReady: Deferred.Deferred<void>
140
144
  }) => Effect.Effect<
@@ -3,8 +3,8 @@ import { type Option, Predicate, type Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import type { SessionIdSymbol } from '../adapter-types.js'
5
5
  import type { QueryInfo } from '../query-info.js'
6
+ import type { SqliteDsl } from '../schema/db-schema/mod.js'
6
7
  import type { DbSchema } from '../schema/mod.js'
7
- import type { SqliteDsl } from '../schema/table-def.js'
8
8
  import type { SqlValue } from '../util.js'
9
9
 
10
10
  export type QueryBuilderAst = QueryBuilderAst.SelectQuery | QueryBuilderAst.CountQuery | QueryBuilderAst.RowQuery
@@ -60,10 +60,12 @@ This likely means the schema has changed in an incompatible way.
60
60
  )
61
61
 
62
62
  const mutationEventEncoded = {
63
- id: { global: row.idGlobal, local: row.idLocal },
64
- parentId: { global: row.parentIdGlobal, local: row.parentIdLocal },
63
+ id: { global: row.idGlobal, client: row.idClient },
64
+ parentId: { global: row.parentIdGlobal, client: row.parentIdClient },
65
65
  mutation: row.mutation,
66
66
  args,
67
+ clientId: row.clientId,
68
+ sessionId: row.sessionId ?? undefined,
67
69
  } satisfies MutationEvent.AnyEncoded
68
70
 
69
71
  yield* applyMutation(mutationEventEncoded, { skipMutationLog: true })
@@ -73,8 +75,8 @@ This likely means the schema has changed in an incompatible way.
73
75
 
74
76
  const stmt = logDb.prepare(sql`\
75
77
  SELECT * FROM ${MUTATION_LOG_META_TABLE}
76
- WHERE idGlobal > $idGlobal OR (idGlobal = $idGlobal AND idLocal > $idLocal)
77
- ORDER BY idGlobal ASC, idLocal ASC
78
+ WHERE idGlobal > $idGlobal OR (idGlobal = $idGlobal AND idClient > $idClient)
79
+ ORDER BY idGlobal ASC, idClient ASC
78
80
  LIMIT ${CHUNK_SIZE}
79
81
  `)
80
82
 
@@ -88,14 +90,14 @@ LIMIT ${CHUNK_SIZE}
88
90
 
89
91
  const lastId = Chunk.isChunk(item)
90
92
  ? Chunk.last(item).pipe(
91
- Option.map((_) => ({ global: _.idGlobal, local: _.idLocal })),
93
+ Option.map((_) => ({ global: _.idGlobal, client: _.idClient })),
92
94
  Option.getOrElse(() => EventId.ROOT),
93
95
  )
94
96
  : EventId.ROOT
95
97
  const nextItem = Chunk.fromIterable(
96
98
  stmt.select<MutationLogMetaRow>({
97
99
  $idGlobal: lastId?.global,
98
- $idLocal: lastId?.local,
100
+ $idClient: lastId?.client,
99
101
  } as any as PreparedBindValues),
100
102
  )
101
103
  const prevItem = Chunk.isChunk(item) ? item : Chunk.empty()
@@ -5,8 +5,8 @@ import { EventId } from './mod.js'
5
5
 
6
6
  Vitest.describe('EventId', () => {
7
7
  Vitest.test('nextPair', () => {
8
- const e_0_0 = EventId.make({ global: 0, local: 0 })
9
- expect(EventId.nextPair(e_0_0, false).id).toStrictEqual({ global: 1, local: 0 })
10
- expect(EventId.nextPair(e_0_0, true).id).toStrictEqual({ global: 0, local: 1 })
8
+ const e_0_0 = EventId.make({ global: 0, client: 0 })
9
+ expect(EventId.nextPair(e_0_0, false).id).toStrictEqual({ global: 1, client: 0 })
10
+ expect(EventId.nextPair(e_0_0, true).id).toStrictEqual({ global: 0, client: 1 })
11
11
  })
12
12
  })
@@ -1,26 +1,26 @@
1
1
  import { Brand, Schema } from '@livestore/utils/effect'
2
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)
3
+ export type ClientEventId = Brand.Branded<number, 'ClientEventId'>
4
+ export const localEventId = Brand.nominal<ClientEventId>()
5
+ export const ClientEventId = Schema.fromBrand(localEventId)(Schema.Int)
6
6
 
7
7
  export type GlobalEventId = Brand.Branded<number, 'GlobalEventId'>
8
8
  export const globalEventId = Brand.nominal<GlobalEventId>()
9
9
  export const GlobalEventId = Schema.fromBrand(globalEventId)(Schema.Int)
10
10
 
11
- export const localDefault = 0 as any as LocalEventId
11
+ export const clientDefault = 0 as any as ClientEventId
12
12
 
13
13
  /**
14
14
  * LiveStore event id value consisting of a globally unique event sequence number
15
- * and a local sequence number.
15
+ * and a client sequence number.
16
16
  *
17
- * The local sequence number is only used for localOnly mutations and starts from 0 for each global sequence number.
17
+ * The client sequence number is only used for clientOnly mutations and starts from 0 for each global sequence number.
18
18
  */
19
- export type EventId = { global: GlobalEventId; local: LocalEventId }
19
+ export type EventId = { global: GlobalEventId; client: ClientEventId }
20
20
 
21
21
  export const EventId = Schema.Struct({
22
22
  global: GlobalEventId,
23
- local: LocalEventId,
23
+ client: ClientEventId,
24
24
  }).annotations({ title: 'LiveStore.EventId' })
25
25
 
26
26
  /**
@@ -30,21 +30,21 @@ export const compare = (a: EventId, b: EventId) => {
30
30
  if (a.global !== b.global) {
31
31
  return a.global - b.global
32
32
  }
33
- return a.local - b.local
33
+ return a.client - b.client
34
34
  }
35
35
 
36
- export const isEqual = (a: EventId, b: EventId) => a.global === b.global && a.local === b.local
36
+ export const isEqual = (a: EventId, b: EventId) => a.global === b.global && a.client === b.client
37
37
 
38
38
  export type EventIdPair = { id: EventId; parentId: EventId }
39
39
 
40
- export const ROOT = { global: -1 as any as GlobalEventId, local: localDefault } satisfies EventId
40
+ export const ROOT = { global: -1 as any as GlobalEventId, client: clientDefault } satisfies EventId
41
41
 
42
42
  export const isGreaterThan = (a: EventId, b: EventId) => {
43
- return a.global > b.global || (a.global === b.global && a.local > b.local)
43
+ return a.global > b.global || (a.global === b.global && a.client > b.client)
44
44
  }
45
45
 
46
46
  export const isGreaterThanOrEqual = (a: EventId, b: EventId) => {
47
- return a.global > b.global || (a.global === b.global && a.local >= b.local)
47
+ return a.global > b.global || (a.global === b.global && a.client >= b.client)
48
48
  }
49
49
 
50
50
  export const make = (id: EventId | typeof EventId.Encoded): EventId => {
@@ -53,12 +53,12 @@ export const make = (id: EventId | typeof EventId.Encoded): EventId => {
53
53
 
54
54
  export const nextPair = (id: EventId, isLocal: boolean): EventIdPair => {
55
55
  if (isLocal) {
56
- return { id: { global: id.global, local: (id.local + 1) as any as LocalEventId }, parentId: id }
56
+ return { id: { global: id.global, client: (id.client + 1) as any as ClientEventId }, parentId: id }
57
57
  }
58
58
 
59
59
  return {
60
- id: { global: (id.global + 1) as any as GlobalEventId, local: localDefault },
61
- // NOTE we always point to `local: 0` for non-localOnly mutations
62
- parentId: { global: id.global, local: localDefault },
60
+ id: { global: (id.global + 1) as any as GlobalEventId, client: clientDefault },
61
+ // NOTE we always point to `client: 0` for non-clientOnly mutations
62
+ parentId: { global: id.global, client: clientDefault },
63
63
  }
64
64
  }
@@ -10,7 +10,7 @@ export type MutationEventPartial<TMutationsDef extends MutationDef.Any> = {
10
10
  args: Schema.Schema.Type<TMutationsDef['schema']>
11
11
  }
12
12
 
13
- export type MutationEventPartialEncoded<TMutationsDef extends MutationDef.Any> = {
13
+ export type PartialEncoded<TMutationsDef extends MutationDef.Any> = {
14
14
  mutation: TMutationsDef['name']
15
15
  args: Schema.Schema.Encoded<TMutationsDef['schema']>
16
16
  }
@@ -20,6 +20,8 @@ export type MutationEvent<TMutationsDef extends MutationDef.Any> = {
20
20
  args: Schema.Schema.Type<TMutationsDef['schema']>
21
21
  id: EventId.EventId
22
22
  parentId: EventId.EventId
23
+ clientId: string
24
+ sessionId: string | undefined
23
25
  }
24
26
 
25
27
  export type MutationEventEncoded<TMutationsDef extends MutationDef.Any> = {
@@ -27,6 +29,8 @@ export type MutationEventEncoded<TMutationsDef extends MutationDef.Any> = {
27
29
  args: Schema.Schema.Encoded<TMutationsDef['schema']>
28
30
  id: EventId.EventId
29
31
  parentId: EventId.EventId
32
+ clientId: string
33
+ sessionId: string | undefined
30
34
  }
31
35
 
32
36
  export type AnyDecoded = MutationEvent<MutationDef.Any>
@@ -35,6 +39,8 @@ export const AnyDecoded = Schema.Struct({
35
39
  args: Schema.Any,
36
40
  id: EventId.EventId,
37
41
  parentId: EventId.EventId,
42
+ clientId: Schema.String,
43
+ sessionId: Schema.UndefinedOr(Schema.String),
38
44
  }).annotations({ title: 'MutationEvent.AnyDecoded' })
39
45
 
40
46
  export type AnyEncoded = MutationEventEncoded<MutationDef.Any>
@@ -43,6 +49,8 @@ export const AnyEncoded = Schema.Struct({
43
49
  args: Schema.Any,
44
50
  id: EventId.EventId,
45
51
  parentId: EventId.EventId,
52
+ clientId: Schema.String,
53
+ sessionId: Schema.UndefinedOr(Schema.String),
46
54
  }).annotations({ title: 'MutationEvent.AnyEncoded' })
47
55
 
48
56
  export const AnyEncodedGlobal = Schema.Struct({
@@ -50,11 +58,17 @@ export const AnyEncodedGlobal = Schema.Struct({
50
58
  args: Schema.Any,
51
59
  id: EventId.GlobalEventId,
52
60
  parentId: EventId.GlobalEventId,
61
+ clientId: Schema.String,
53
62
  }).annotations({ title: 'MutationEvent.AnyEncodedGlobal' })
54
63
  export type AnyEncodedGlobal = typeof AnyEncodedGlobal.Type
55
64
 
56
65
  export type PartialAnyDecoded = MutationEventPartial<MutationDef.Any>
57
- export type PartialAnyEncoded = MutationEventPartialEncoded<MutationDef.Any>
66
+ export type PartialAnyEncoded = PartialEncoded<MutationDef.Any>
67
+
68
+ export const PartialAnyEncoded = Schema.Struct({
69
+ mutation: Schema.String,
70
+ args: Schema.Any,
71
+ })
58
72
 
59
73
  export type PartialForSchema<TSchema extends LiveStoreSchema> = {
60
74
  [K in keyof TSchema['_MutationDefMapType']]: MutationEventPartial<TSchema['_MutationDefMapType'][K]>
@@ -75,6 +89,8 @@ export type ForMutationDefRecord<TMutationsDefRecord extends MutationDefRecord>
75
89
  args: Schema.Schema.Type<TMutationsDefRecord[K]['schema']>
76
90
  id: EventId.EventId
77
91
  parentId: EventId.EventId
92
+ clientId: string
93
+ sessionId: string | undefined
78
94
  }
79
95
  }[keyof TMutationsDefRecord],
80
96
  {
@@ -83,6 +99,8 @@ export type ForMutationDefRecord<TMutationsDefRecord extends MutationDefRecord>
83
99
  args: Schema.Schema.Encoded<TMutationsDefRecord[K]['schema']>
84
100
  id: EventId.EventId
85
101
  parentId: EventId.EventId
102
+ clientId: string
103
+ sessionId: string | undefined
86
104
  }
87
105
  }[keyof TMutationsDefRecord]
88
106
  >
@@ -112,6 +130,8 @@ export const makeMutationEventSchema = <TSchema extends LiveStoreSchema>(
112
130
  args: def.schema,
113
131
  id: EventId.EventId,
114
132
  parentId: EventId.EventId,
133
+ clientId: Schema.String,
134
+ sessionId: Schema.UndefinedOr(Schema.String),
115
135
  }),
116
136
  ),
117
137
  ).annotations({ title: 'MutationEvent' }) as any
@@ -136,6 +156,8 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
136
156
  args: Schema.Any,
137
157
  id: EventId.EventId,
138
158
  parentId: EventId.EventId,
159
+ clientId: Schema.String,
160
+ sessionId: Schema.UndefinedOr(Schema.String),
139
161
  // TODO get rid of `meta` again by cleaning up the usage implementations
140
162
  meta: Schema.optionalWith(
141
163
  Schema.Any as Schema.Schema<{
@@ -149,7 +171,7 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
149
171
  // - More readable way to print the id + parentId
150
172
  // - not including `meta`
151
173
  return {
152
- id: `(${this.id.global},${this.id.local}) → (${this.parentId.global},${this.parentId.local})`,
174
+ id: `(${this.id.global},${this.id.client}) → (${this.parentId.global},${this.parentId.client})`,
153
175
  mutation: this.mutation,
154
176
  args: this.args,
155
177
  }
@@ -164,8 +186,9 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
164
186
  static fromGlobal = (mutationEvent: AnyEncodedGlobal) =>
165
187
  new EncodedWithMeta({
166
188
  ...mutationEvent,
167
- id: { global: mutationEvent.id, local: EventId.localDefault },
168
- parentId: { global: mutationEvent.parentId, local: EventId.localDefault },
189
+ id: { global: mutationEvent.id, client: EventId.clientDefault },
190
+ parentId: { global: mutationEvent.parentId, client: EventId.clientDefault },
191
+ sessionId: undefined,
169
192
  })
170
193
 
171
194
  toGlobal = (): AnyEncodedGlobal => ({
@@ -177,7 +200,9 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
177
200
 
178
201
  export const isEqualEncoded = (a: AnyEncoded, b: AnyEncoded) =>
179
202
  a.id.global === b.id.global &&
180
- a.id.local === b.id.local &&
203
+ a.id.client === b.id.client &&
181
204
  a.mutation === b.mutation &&
205
+ a.clientId === b.clientId &&
206
+ // a.sessionId === b.sessionId &&
182
207
  // TODO use schema equality here
183
208
  JSON.stringify(a.args) === JSON.stringify(b.args)
@@ -0,0 +1,142 @@
1
+ import { type Option, Schema } from '@livestore/utils/effect'
2
+
3
+ import { hashCode } from '../hash.js'
4
+
5
+ export namespace ColumnType {
6
+ export type ColumnType = Text | Null | Real | Integer | Blob
7
+
8
+ export type Text = { _tag: 'text' }
9
+
10
+ export type Null = { _tag: 'null' }
11
+
12
+ export type Real = { _tag: 'real' }
13
+
14
+ export type Integer = { _tag: 'integer' }
15
+
16
+ export type Blob = { _tag: 'blob' }
17
+ }
18
+
19
+ export type Column = {
20
+ _tag: 'column'
21
+ name: string
22
+ type: ColumnType.ColumnType
23
+ primaryKey: boolean
24
+ nullable: boolean
25
+ default: Option.Option<any>
26
+ schema: Schema.Schema<any>
27
+ }
28
+
29
+ export const column = (props: Omit<Column, '_tag'>): Column => ({ _tag: 'column', ...props })
30
+
31
+ export type Index = {
32
+ _tag: 'index'
33
+ columns: ReadonlyArray<string>
34
+ name?: string
35
+ unique?: boolean
36
+ primaryKey?: boolean
37
+ }
38
+
39
+ export const index = (
40
+ columns: ReadonlyArray<string>,
41
+ name?: string,
42
+ unique?: boolean,
43
+ primaryKey?: boolean,
44
+ ): Index => ({
45
+ _tag: 'index',
46
+ columns,
47
+ name,
48
+ unique,
49
+ primaryKey,
50
+ })
51
+
52
+ export type ForeignKey = {
53
+ _tag: 'foreignKey'
54
+ references: {
55
+ table: string
56
+ columns: ReadonlyArray<string>
57
+ }
58
+ key: {
59
+ table: string
60
+ columns: ReadonlyArray<string>
61
+ }
62
+ columns: ReadonlyArray<string>
63
+ }
64
+
65
+ export type Table = {
66
+ _tag: 'table'
67
+ name: string
68
+ columns: ReadonlyArray<Column>
69
+ indexes: ReadonlyArray<Index>
70
+ }
71
+
72
+ export const table = (name: string, columns: ReadonlyArray<Column>, indexes: ReadonlyArray<Index>): Table => ({
73
+ _tag: 'table',
74
+ name,
75
+ columns,
76
+ indexes,
77
+ })
78
+
79
+ export type DbSchema = {
80
+ _tag: 'dbSchema'
81
+ tables: Table[]
82
+ }
83
+
84
+ export const dbSchema = (tables: Table[]): DbSchema => ({ _tag: 'dbSchema', tables })
85
+
86
+ /**
87
+ * NOTE we're only including SQLite-relevant information in the hash (which excludes the schema mapping)
88
+ */
89
+ export const hash = (obj: Table | Column | Index | ForeignKey | DbSchema): number =>
90
+ hashCode(JSON.stringify(trimInfoForHasing(obj)))
91
+
92
+ const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema): Record<string, any> => {
93
+ switch (obj._tag) {
94
+ case 'table': {
95
+ return {
96
+ _tag: 'table',
97
+ name: obj.name,
98
+ columns: obj.columns.map((column) => trimInfoForHasing(column)),
99
+ indexes: obj.indexes.map((index) => trimInfoForHasing(index)),
100
+ }
101
+ }
102
+ case 'column': {
103
+ return {
104
+ _tag: 'column',
105
+ name: obj.name,
106
+ type: obj.type._tag,
107
+ primaryKey: obj.primaryKey,
108
+ nullable: obj.nullable,
109
+ default: obj.default,
110
+ }
111
+ }
112
+ case 'index': {
113
+ return {
114
+ _tag: 'index',
115
+ columns: obj.columns,
116
+ name: obj.name,
117
+ unique: obj.unique,
118
+ primaryKey: obj.primaryKey,
119
+ }
120
+ }
121
+ case 'foreignKey': {
122
+ return {
123
+ _tag: 'foreignKey',
124
+ references: obj.references,
125
+ key: obj.key,
126
+ columns: obj.columns,
127
+ }
128
+ }
129
+ case 'dbSchema': {
130
+ return {
131
+ _tag: 'dbSchema',
132
+ tables: obj.tables.map(trimInfoForHasing),
133
+ }
134
+ }
135
+ default: {
136
+ throw new Error(`Unreachable: ${obj}`)
137
+ }
138
+ }
139
+ }
140
+
141
+ export const structSchemaForTable = (tableDef: Table) =>
142
+ Schema.Struct(Object.fromEntries(tableDef.columns.map((column) => [column.name, column.schema])))
@@ -0,0 +1,13 @@
1
+ import type { DbSchema } from './sqlite.js'
2
+
3
+ // TODO
4
+ export const validate = (_dbSchema: DbSchema) => {
5
+ /*
6
+ TODO:
7
+
8
+ - ensure no duplicate table names
9
+ - ensure no duplicate column names within a table
10
+ - ensure no duplicate index names globally
11
+ - ...
12
+ */
13
+ }