@livestore/livestore 0.4.0-dev.21 → 0.4.0-dev.23

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 (216) hide show
  1. package/README.md +0 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/QueryCache.js +1 -1
  4. package/dist/QueryCache.js.map +1 -1
  5. package/dist/SqliteDbWrapper.d.ts +5 -5
  6. package/dist/SqliteDbWrapper.d.ts.map +1 -1
  7. package/dist/SqliteDbWrapper.js +8 -8
  8. package/dist/SqliteDbWrapper.js.map +1 -1
  9. package/dist/SqliteDbWrapper.test.js +2 -2
  10. package/dist/SqliteDbWrapper.test.js.map +1 -1
  11. package/dist/effect/LiveStore.d.ts +130 -2
  12. package/dist/effect/LiveStore.d.ts.map +1 -1
  13. package/dist/effect/LiveStore.js +185 -6
  14. package/dist/effect/LiveStore.js.map +1 -1
  15. package/dist/effect/LiveStore.test.d.ts +2 -0
  16. package/dist/effect/LiveStore.test.d.ts.map +1 -0
  17. package/dist/effect/LiveStore.test.js +42 -0
  18. package/dist/effect/LiveStore.test.js.map +1 -0
  19. package/dist/effect/mod.d.ts +1 -1
  20. package/dist/effect/mod.d.ts.map +1 -1
  21. package/dist/effect/mod.js +3 -1
  22. package/dist/effect/mod.js.map +1 -1
  23. package/dist/live-queries/base-class.d.ts +3 -3
  24. package/dist/live-queries/base-class.d.ts.map +1 -1
  25. package/dist/live-queries/base-class.js +2 -2
  26. package/dist/live-queries/base-class.js.map +1 -1
  27. package/dist/live-queries/client-document-get-query.d.ts +1 -1
  28. package/dist/live-queries/client-document-get-query.d.ts.map +1 -1
  29. package/dist/live-queries/client-document-get-query.js +1 -1
  30. package/dist/live-queries/client-document-get-query.js.map +1 -1
  31. package/dist/live-queries/computed.d.ts.map +1 -1
  32. package/dist/live-queries/computed.js +2 -2
  33. package/dist/live-queries/computed.js.map +1 -1
  34. package/dist/live-queries/db-query.js +14 -14
  35. package/dist/live-queries/db-query.js.map +1 -1
  36. package/dist/live-queries/db-query.test.js +2 -2
  37. package/dist/live-queries/db-query.test.js.map +1 -1
  38. package/dist/live-queries/signal.test.js +2 -2
  39. package/dist/live-queries/signal.test.js.map +1 -1
  40. package/dist/mod.d.ts +2 -1
  41. package/dist/mod.d.ts.map +1 -1
  42. package/dist/mod.js +1 -0
  43. package/dist/mod.js.map +1 -1
  44. package/dist/reactive.d.ts +9 -9
  45. package/dist/reactive.d.ts.map +1 -1
  46. package/dist/reactive.js +9 -26
  47. package/dist/reactive.js.map +1 -1
  48. package/dist/reactive.test.js +2 -2
  49. package/dist/reactive.test.js.map +1 -1
  50. package/dist/store/StoreRegistry.d.ts +215 -0
  51. package/dist/store/StoreRegistry.d.ts.map +1 -0
  52. package/dist/store/StoreRegistry.js +267 -0
  53. package/dist/store/StoreRegistry.js.map +1 -0
  54. package/dist/store/StoreRegistry.test.d.ts +2 -0
  55. package/dist/store/StoreRegistry.test.d.ts.map +1 -0
  56. package/dist/store/StoreRegistry.test.js +381 -0
  57. package/dist/store/StoreRegistry.test.js.map +1 -0
  58. package/dist/store/create-store.d.ts +56 -6
  59. package/dist/store/create-store.d.ts.map +1 -1
  60. package/dist/store/create-store.js +32 -7
  61. package/dist/store/create-store.js.map +1 -1
  62. package/dist/store/devtools.d.ts +1 -1
  63. package/dist/store/devtools.d.ts.map +1 -1
  64. package/dist/store/devtools.js +16 -3
  65. package/dist/store/devtools.js.map +1 -1
  66. package/dist/store/store-eventstream.test.js +2 -2
  67. package/dist/store/store-eventstream.test.js.map +1 -1
  68. package/dist/store/store-types.d.ts +59 -9
  69. package/dist/store/store-types.d.ts.map +1 -1
  70. package/dist/store/store-types.js.map +1 -1
  71. package/dist/store/store-types.test.js +1 -1
  72. package/dist/store/store-types.test.js.map +1 -1
  73. package/dist/store/store.d.ts +102 -6
  74. package/dist/store/store.d.ts.map +1 -1
  75. package/dist/store/store.js +148 -47
  76. package/dist/store/store.js.map +1 -1
  77. package/dist/utils/dev.js.map +1 -1
  78. package/dist/utils/stack-info.js +2 -2
  79. package/dist/utils/stack-info.js.map +1 -1
  80. package/dist/utils/tests/fixture.d.ts +1 -1
  81. package/dist/utils/tests/fixture.d.ts.map +1 -1
  82. package/dist/utils/tests/fixture.js.map +1 -1
  83. package/dist/utils/tests/otel.d.ts.map +1 -1
  84. package/dist/utils/tests/otel.js +5 -5
  85. package/dist/utils/tests/otel.js.map +1 -1
  86. package/package.json +59 -18
  87. package/src/QueryCache.ts +1 -1
  88. package/src/SqliteDbWrapper.test.ts +4 -2
  89. package/src/SqliteDbWrapper.ts +12 -11
  90. package/src/ambient.d.ts +0 -7
  91. package/src/effect/LiveStore.test.ts +61 -0
  92. package/src/effect/LiveStore.ts +381 -8
  93. package/src/effect/mod.ts +13 -1
  94. package/src/live-queries/__snapshots__/db-query.test.ts.snap +336 -231
  95. package/src/live-queries/base-class.ts +7 -6
  96. package/src/live-queries/client-document-get-query.ts +4 -2
  97. package/src/live-queries/computed.ts +3 -2
  98. package/src/live-queries/db-query.test.ts +3 -2
  99. package/src/live-queries/db-query.ts +15 -15
  100. package/src/live-queries/signal.test.ts +3 -2
  101. package/src/mod.ts +2 -0
  102. package/src/reactive.test.ts +3 -2
  103. package/src/reactive.ts +22 -23
  104. package/src/store/StoreRegistry.test.ts +540 -0
  105. package/src/store/StoreRegistry.ts +418 -0
  106. package/src/store/create-store.ts +76 -15
  107. package/src/store/devtools.ts +20 -6
  108. package/src/store/store-eventstream.test.ts +4 -2
  109. package/src/store/store-types.test.ts +3 -1
  110. package/src/store/store-types.ts +64 -13
  111. package/src/store/store.ts +197 -60
  112. package/src/utils/dev.ts +2 -2
  113. package/src/utils/stack-info.ts +2 -2
  114. package/src/utils/tests/fixture.ts +2 -1
  115. package/src/utils/tests/otel.ts +8 -7
  116. package/docs/api/index.md +0 -3
  117. package/docs/building-with-livestore/complex-ui-state/index.md +0 -5
  118. package/docs/building-with-livestore/crud/index.md +0 -5
  119. package/docs/building-with-livestore/data-modeling/index.md +0 -1
  120. package/docs/building-with-livestore/debugging/index.md +0 -17
  121. package/docs/building-with-livestore/devtools/index.md +0 -79
  122. package/docs/building-with-livestore/events/index.md +0 -355
  123. package/docs/building-with-livestore/examples/ai-agent/index.md +0 -5
  124. package/docs/building-with-livestore/examples/index.md +0 -30
  125. package/docs/building-with-livestore/examples/todo-workspaces/index.md +0 -891
  126. package/docs/building-with-livestore/examples/turnbased-game/index.md +0 -7
  127. package/docs/building-with-livestore/opentelemetry/index.md +0 -208
  128. package/docs/building-with-livestore/production-checklist/index.md +0 -5
  129. package/docs/building-with-livestore/reactivity-system/index.md +0 -202
  130. package/docs/building-with-livestore/rules-for-ai-agents/index.md +0 -9
  131. package/docs/building-with-livestore/state/materializers/index.md +0 -300
  132. package/docs/building-with-livestore/state/sql-queries/index.md +0 -72
  133. package/docs/building-with-livestore/state/sqlite/index.md +0 -45
  134. package/docs/building-with-livestore/state/sqlite-schema/index.md +0 -306
  135. package/docs/building-with-livestore/state/sqlite-schema-effect/index.md +0 -300
  136. package/docs/building-with-livestore/store/index.md +0 -281
  137. package/docs/building-with-livestore/syncing/index.md +0 -136
  138. package/docs/building-with-livestore/tools/cli/index.md +0 -177
  139. package/docs/building-with-livestore/tools/mcp/index.md +0 -187
  140. package/docs/examples/cloudflare-adapter/index.md +0 -44
  141. package/docs/examples/expo-adapter/index.md +0 -44
  142. package/docs/examples/index.md +0 -55
  143. package/docs/examples/node-adapter/index.md +0 -44
  144. package/docs/examples/web-adapter/index.md +0 -52
  145. package/docs/framework-integrations/custom-elements/index.md +0 -142
  146. package/docs/framework-integrations/react-integration/index.md +0 -918
  147. package/docs/framework-integrations/solid-integration/index.md +0 -293
  148. package/docs/framework-integrations/svelte-integration/index.md +0 -42
  149. package/docs/framework-integrations/vue-integration/index.md +0 -294
  150. package/docs/getting-started/expo/index.md +0 -736
  151. package/docs/getting-started/node/index.md +0 -115
  152. package/docs/getting-started/react-web/index.md +0 -573
  153. package/docs/getting-started/solid/index.md +0 -3
  154. package/docs/getting-started/vue/index.md +0 -471
  155. package/docs/index.md +0 -209
  156. package/docs/llms.txt +0 -147
  157. package/docs/misc/CODE_OF_CONDUCT/index.md +0 -133
  158. package/docs/misc/FAQ/index.md +0 -37
  159. package/docs/misc/community/index.md +0 -88
  160. package/docs/misc/credits/index.md +0 -14
  161. package/docs/misc/design-partners/index.md +0 -13
  162. package/docs/misc/package-management/index.md +0 -21
  163. package/docs/misc/performance/index.md +0 -25
  164. package/docs/misc/resources/index.md +0 -46
  165. package/docs/misc/state-of-the-project/index.md +0 -37
  166. package/docs/misc/troubleshooting/index.md +0 -82
  167. package/docs/overview/concepts/index.md +0 -78
  168. package/docs/overview/how-livestore-works/index.md +0 -56
  169. package/docs/overview/introduction/index.md +0 -5
  170. package/docs/overview/technology-comparison/index.md +0 -40
  171. package/docs/overview/when-livestore/index.md +0 -81
  172. package/docs/overview/why-livestore/index.md +0 -5
  173. package/docs/patterns/ai/index.md +0 -15
  174. package/docs/patterns/anonymous-user-transition/index.md +0 -10
  175. package/docs/patterns/app-evolution/index.md +0 -72
  176. package/docs/patterns/auth/index.md +0 -226
  177. package/docs/patterns/effect/index.md +0 -1495
  178. package/docs/patterns/encryption/index.md +0 -6
  179. package/docs/patterns/external-data/index.md +0 -5
  180. package/docs/patterns/file-management/index.md +0 -11
  181. package/docs/patterns/file-structure/index.md +0 -14
  182. package/docs/patterns/list-ordering/index.md +0 -369
  183. package/docs/patterns/offline/index.md +0 -32
  184. package/docs/patterns/orm/index.md +0 -18
  185. package/docs/patterns/presence/index.md +0 -11
  186. package/docs/patterns/rich-text-editing/index.md +0 -11
  187. package/docs/patterns/server-side-clients/index.md +0 -97
  188. package/docs/patterns/side-effects/index.md +0 -11
  189. package/docs/patterns/state-machines/index.md +0 -11
  190. package/docs/patterns/storybook/index.md +0 -192
  191. package/docs/patterns/undo-redo/index.md +0 -9
  192. package/docs/patterns/version-control/index.md +0 -8
  193. package/docs/platform-adapters/cloudflare-durable-object-adapter/index.md +0 -453
  194. package/docs/platform-adapters/electron-adapter/index.md +0 -15
  195. package/docs/platform-adapters/expo-adapter/index.md +0 -245
  196. package/docs/platform-adapters/node-adapter/index.md +0 -160
  197. package/docs/platform-adapters/tauri-adapter/index.md +0 -15
  198. package/docs/platform-adapters/web-adapter/index.md +0 -218
  199. package/docs/sustainable-open-source/contributing/docs/index.md +0 -94
  200. package/docs/sustainable-open-source/contributing/info/index.md +0 -63
  201. package/docs/sustainable-open-source/contributing/monorepo/index.md +0 -195
  202. package/docs/sustainable-open-source/sponsoring/index.md +0 -104
  203. package/docs/sync-providers/cloudflare/index.md +0 -773
  204. package/docs/sync-providers/custom/index.md +0 -65
  205. package/docs/sync-providers/electricsql/index.md +0 -159
  206. package/docs/sync-providers/s2/index.md +0 -230
  207. package/docs/tutorial/0-welcome/index.md +0 -48
  208. package/docs/tutorial/1-setup-starter-project/index.md +0 -105
  209. package/docs/tutorial/2-deploy-to-cloudflare/index.md +0 -195
  210. package/docs/tutorial/3-read-and-write-todos-via-livestore/index.md +0 -511
  211. package/docs/tutorial/4-sync-data-via-cloudflare/index.md +0 -210
  212. package/docs/tutorial/5-expand-business-logic/index.md +0 -174
  213. package/docs/tutorial/6-persist-ui-state/index.md +0 -453
  214. package/docs/tutorial/7-next-steps/index.md +0 -22
  215. package/docs/understanding-livestore/design-decisions/index.md +0 -33
  216. package/docs/understanding-livestore/event-sourcing/index.md +0 -40
@@ -1,281 +0,0 @@
1
- # Store
2
-
3
- The `Store` is the most common way to interact with LiveStore from your application code. It provides a way to query data, commit events, and subscribe to data changes.
4
-
5
- ## Creating a store
6
-
7
- For how to create a store in React, see the [React integration docs](/framework-integrations/react-integration). The following example shows how to create a store manually:
8
-
9
- ## `reference/store/create-store.ts`
10
-
11
- ```ts filename="reference/store/create-store.ts"
12
-
13
- const adapter = makeAdapter({
14
- storage: { type: 'fs' },
15
- // sync: { backend: makeWsSync({ url: '...' }) },
16
- })
17
-
18
- export const bootstrap = async () => {
19
- const store = await createStorePromise({
20
- schema,
21
- adapter,
22
- storeId: 'some-store-id',
23
- })
24
-
25
- return store
26
- }
27
- ```
28
-
29
- ### `reference/store/schema.ts`
30
-
31
- ```ts filename="reference/store/schema.ts"
32
-
33
- const tables = {
34
- todos: State.SQLite.table({
35
- name: 'todos',
36
- columns: {
37
- id: State.SQLite.text({ primaryKey: true }),
38
- text: State.SQLite.text(),
39
- completed: State.SQLite.boolean({ default: false }),
40
- },
41
- }),
42
- } as const
43
-
44
- const events = {
45
- todoCreated: Events.synced({
46
- name: 'v1.TodoCreated',
47
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
48
- }),
49
- } as const
50
-
51
- const materializers = State.SQLite.materializers(events, {
52
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
53
- tables.todos.insert({ id, text, completed: false }),
54
- ),
55
- })
56
-
57
- const state = State.SQLite.makeState({ tables, materializers })
58
-
59
- export const schema = makeSchema({ events, state })
60
- export const storeTables = tables
61
- export const storeEvents = events
62
- ```
63
-
64
- ## Using a store
65
-
66
- ### Querying data
67
-
68
- ## `reference/store/query-data.ts`
69
-
70
- ```ts filename="reference/store/query-data.ts"
71
- /** biome-ignore-all lint/correctness/noUnusedVariables: docs snippet shows query result */
72
- // ---cut---
73
-
74
- declare const store: Store
75
-
76
- const todos = store.query(storeTables.todos)
77
- console.log(todos)
78
- ```
79
-
80
- ### `reference/store/schema.ts`
81
-
82
- ```ts filename="reference/store/schema.ts"
83
-
84
- const tables = {
85
- todos: State.SQLite.table({
86
- name: 'todos',
87
- columns: {
88
- id: State.SQLite.text({ primaryKey: true }),
89
- text: State.SQLite.text(),
90
- completed: State.SQLite.boolean({ default: false }),
91
- },
92
- }),
93
- } as const
94
-
95
- const events = {
96
- todoCreated: Events.synced({
97
- name: 'v1.TodoCreated',
98
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
99
- }),
100
- } as const
101
-
102
- const materializers = State.SQLite.materializers(events, {
103
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
104
- tables.todos.insert({ id, text, completed: false }),
105
- ),
106
- })
107
-
108
- const state = State.SQLite.makeState({ tables, materializers })
109
-
110
- export const schema = makeSchema({ events, state })
111
- export const storeTables = tables
112
- export const storeEvents = events
113
- ```
114
-
115
- ### Subscribing to data
116
-
117
- ## `reference/store/subscribe.ts`
118
-
119
- ```ts filename="reference/store/subscribe.ts"
120
-
121
- declare const store: Store
122
-
123
- const unsubscribe = store.subscribe(storeTables.todos, (todos) => {
124
- console.log(todos)
125
- })
126
-
127
- unsubscribe()
128
- ```
129
-
130
- ### `reference/store/schema.ts`
131
-
132
- ```ts filename="reference/store/schema.ts"
133
-
134
- const tables = {
135
- todos: State.SQLite.table({
136
- name: 'todos',
137
- columns: {
138
- id: State.SQLite.text({ primaryKey: true }),
139
- text: State.SQLite.text(),
140
- completed: State.SQLite.boolean({ default: false }),
141
- },
142
- }),
143
- } as const
144
-
145
- const events = {
146
- todoCreated: Events.synced({
147
- name: 'v1.TodoCreated',
148
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
149
- }),
150
- } as const
151
-
152
- const materializers = State.SQLite.materializers(events, {
153
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
154
- tables.todos.insert({ id, text, completed: false }),
155
- ),
156
- })
157
-
158
- const state = State.SQLite.makeState({ tables, materializers })
159
-
160
- export const schema = makeSchema({ events, state })
161
- export const storeTables = tables
162
- export const storeEvents = events
163
- ```
164
-
165
- ### Committing events
166
-
167
- ## `reference/store/commit-event.ts`
168
-
169
- ```ts filename="reference/store/commit-event.ts"
170
-
171
- declare const store: Store
172
-
173
- store.commit(storeEvents.todoCreated({ id: '1', text: 'Buy milk' }))
174
- ```
175
-
176
- ### `reference/store/schema.ts`
177
-
178
- ```ts filename="reference/store/schema.ts"
179
-
180
- const tables = {
181
- todos: State.SQLite.table({
182
- name: 'todos',
183
- columns: {
184
- id: State.SQLite.text({ primaryKey: true }),
185
- text: State.SQLite.text(),
186
- completed: State.SQLite.boolean({ default: false }),
187
- },
188
- }),
189
- } as const
190
-
191
- const events = {
192
- todoCreated: Events.synced({
193
- name: 'v1.TodoCreated',
194
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
195
- }),
196
- } as const
197
-
198
- const materializers = State.SQLite.materializers(events, {
199
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
200
- tables.todos.insert({ id, text, completed: false }),
201
- ),
202
- })
203
-
204
- const state = State.SQLite.makeState({ tables, materializers })
205
-
206
- export const schema = makeSchema({ events, state })
207
- export const storeTables = tables
208
- export const storeEvents = events
209
- ```
210
-
211
- ### Streaming events
212
-
213
- Currently only events confirmed by the sync backend are supported.
214
-
215
- ## `reference/store/stream-events.ts`
216
-
217
- ```ts filename="reference/store/stream-events.ts"
218
-
219
- declare const store: Store
220
-
221
- // Run once
222
- for await (const event of store.events()) {
223
- console.log('event from leader', event)
224
- }
225
-
226
- // Continuos stream
227
- const iterator = store.events()[Symbol.asyncIterator]()
228
- try {
229
- while (true) {
230
- const { value, done } = await iterator.next()
231
- if (done) break
232
- console.log('event from stream:', value)
233
- }
234
- } finally {
235
- await iterator.return?.()
236
- }
237
- ```
238
-
239
- ### Shutting down a store
240
-
241
- LiveStore provides two APIs for shutting down a store:
242
-
243
- ## `reference/store/shutdown.ts`
244
-
245
- ```ts filename="reference/store/shutdown.ts"
246
- /** biome-ignore-all lint/correctness/noUnusedVariables: docs snippet demonstrates shutdown helpers */
247
- // ---cut---
248
-
249
- declare const store: Store
250
-
251
- const effectShutdown = Effect.gen(function* () {
252
- yield* Effect.log('Shutting down store')
253
- yield* store.shutdown()
254
- })
255
-
256
- const shutdownWithPromise = async () => {
257
- await store.shutdownPromise()
258
- }
259
- ```
260
-
261
- ## Multiple stores
262
-
263
- You can create and use multiple stores in the same app. This can be useful when breaking up your data model into smaller pieces.
264
-
265
- ## Development/debugging helpers
266
-
267
- A store instance also exposes a `_dev` property that contains some helpful methods for development. For convenience you can access a store on `globalThis`/`window` like via `__debugLiveStore.default._dev` (`default` is the store id):
268
-
269
- ```ts
270
- // Download the SQLite database
271
- __debugLiveStore.default._dev.downloadDb()
272
-
273
- // Download the eventlog database
274
- __debugLiveStore.default._dev.downloadEventlogDb()
275
-
276
- // Reset the store
277
- __debugLiveStore.default._dev.hardReset()
278
-
279
- // See the current sync state
280
- __debugLiveStore.default._dev.syncStates()
281
- ```
@@ -1,136 +0,0 @@
1
- # Syncing
2
-
3
- ## How it works
4
-
5
- LiveStore is based on [the idea of event-sourcing](/understanding-livestore/event-sourcing) which means it syncs events across clients (via a central sync backend) and then materializes the events in the local SQLite database. This means LiveStore isn't syncing the SQLite database itself directly but only the events that are used to materialize the database making sure it's kept in sync across clients.
6
-
7
- The syncing mechanism is similar to how Git works in that regard that it's based on a "push/pull" model. Upstream events always need to be pulled before a client can push its own events to preserve a [global total order of events](https://medium.com/baseds/ordering-distributed-events-29c1dd9d1eff). Local pending events which haven't been pushed yet need to be rebased on top of the latest upstream events before they can be pushed.
8
-
9
- <SyncingDiagram />
10
-
11
- ## Events
12
-
13
- A LiveStore event consists of the following data:
14
- - `seqNum`: event sequence number
15
- - `parentSeqNum`: parent event sequence number
16
- - `name`: event name (refers to a event definition in the schema)
17
- - `args`: event arguments (encoded using the event's schema definition, usually JSON)
18
-
19
- ### Event sequence numbers
20
-
21
- - Event sequence numbers: monotonically increasing integers
22
- - client event sequence number to sync across client sessions (never exposed to the sync backend)
23
-
24
- ### Sync heads
25
-
26
- - The latest event in a eventlog is referred to as the "head" (similar to how Git refers to the latest commit as the "head").
27
- - Given that LiveStore does hierarchical syncing between the client session, the client leader and the sync backend, there are three heads (i.e. the client session head, the client leader head, and the sync backend head).
28
-
29
- ## Sync backend
30
-
31
- The sync backend acts as the global authority and determines the total order of events ("causality"). It's responsible for storing and querying events and for notifying clients when new events are available.
32
-
33
- ### Requirements for sync backend
34
-
35
- - Needs to provide an efficient way to query an ordered list of events given a starting event ID (often referred to as cursor).
36
- - Ideally provides a "reactivity" mechanism to notify clients when new events are available (e.g. via WebSocket, HTTP long-polling, etc).
37
- - Alternatively, the client can periodically query for new events which is less efficient.
38
-
39
- ## Clients
40
-
41
- - Each client initially chooses a random `clientId` as its globally unique ID
42
- - LiveStore uses a 6-char nanoid
43
- - In the unlikely event of a collision which is detected by the sync backend the first time a client tries to push, the client chooses a new random `clientId`, patches the local events with the new `clientId`, and tries again.
44
-
45
- ### Client sessions
46
-
47
- - Each client has at least one client session
48
- - Client sessions within the same client share local data
49
- - In web adapters: multiple tabs/windows can be different sessions within the same client
50
- - Sessions are identified by a `sessionId` which can persist (e.g., across tab reloads in web)
51
- - For adapters which support multiple client sessions (e.g. web), LiveStore also supports local syncing across client sessions (e.g. across browser tabs or worker threads)
52
- - Client session events are not synced to the sync backend
53
-
54
- ## Auth (authentication & authorization)
55
-
56
- - TODO
57
- - Provide basic example
58
- - Encryption
59
-
60
- ## Advanced
61
-
62
- ### Sequence diagrams
63
-
64
- #### Pulling events (without unpushed events)
65
-
66
- ```d2
67
- ...@../../../../src/content/base.d2
68
-
69
- shape: sequence_diagram
70
-
71
- Client: {
72
- label: "Client"
73
- }
74
-
75
- SyncBackend: {
76
- label: "Sync Backend"
77
- }
78
-
79
- Client -> SyncBackend: "`pull` request\n(head_cursor)"
80
- SyncBackend -> SyncBackend: "Get new events\n(since head_cursor)"
81
- SyncBackend -> Client: "New events"
82
- Client -> Client: "Client is in sync"
83
- ```
84
-
85
- #### Pushing events
86
-
87
- ```d2
88
- ...@../../../../src/content/base.d2
89
-
90
- shape: sequence_diagram
91
-
92
- Client: {
93
- label: "Client"
94
- }
95
-
96
- SyncBackend: {
97
- label: "Sync Backend"
98
- }
99
-
100
- Client -> Client: "Commit events"
101
- Client -> SyncBackend: "`push` request\n(new_local_events)"
102
- SyncBackend -> SyncBackend: "Validate & persist"
103
- SyncBackend -> Client: "Push success"
104
- Client -> Client: "Client is in sync"
105
- ```
106
-
107
- ### Rebasing
108
-
109
- ### Merge conflicts
110
-
111
- - Merge conflict handling isn't implemented yet (see [this issue](https://github.com/livestorejs/livestore/issues/253)).
112
- - Merge conflict detection and resolution will be based on the upcoming [facts system functionality](https://github.com/livestorejs/livestore/issues/254).
113
-
114
- ### Compaction
115
-
116
- - Compaction isn't implemented yet (see [this issue](https://github.com/livestorejs/livestore/issues/136))
117
- - Compaction will be based on the upcoming [facts system functionality](https://github.com/livestorejs/livestore/issues/254).
118
-
119
- ### Partitioning
120
-
121
- - Currently LiveStore assumes a 1:1 mapping between an eventlog and a SQLite database.
122
- - In the future, LiveStore aims to support multiple eventlogs (see [this issue](https://github.com/livestorejs/livestore/issues/255)).
123
-
124
- ## Design decisions / trade-offs
125
-
126
- - Require a central sync backend to enforce a global total order of events.
127
- - This means LiveStore can't be used in a fully decentralized/P2P manner.
128
- - Do rebasing on the client side (instead of on the sync backend). This allows the user to have more control over the rebase process.
129
-
130
- ## Notes
131
-
132
- - Rich text data is best handled via CRDTs (see [#263](https://github.com/livestorejs/livestore/issues/263))
133
-
134
- ## Further reading
135
-
136
- - Distributed Systems lecture series by Martin Kleppmann: [YouTube playlist](https://www.youtube.com/playlist?list=PLeKd45zvjcDFUEv_ohr_HdUFe97RItdiB) / [lecture notes](https://www.cl.cam.ac.uk/teaching/2122/ConcDisSys/dist-sys-notes.pdf)
@@ -1,177 +0,0 @@
1
- # LiveStore CLI
2
-
3
- The LiveStore CLI provides tools for creating new projects and integrating with AI assistants through MCP (Model Context Protocol).
4
-
5
- :::caution[Experimental - Not Production Ready]
6
- The LiveStore CLI is an experimental preview and not ready for production use. APIs, commands, and functionality may change significantly. Use for development and evaluation purposes only.
7
- :::
8
-
9
- ## Installation
10
-
11
- You can use the LiveStore CLI in several ways:
12
-
13
- ```bash
14
- # Recommended: Use bunx (no installation needed)
15
- bunx @livestore/cli --help
16
-
17
- # Alternative options:
18
- npm install -g @livestore/cli # Global install
19
- npm install -D @livestore/cli # Project install
20
- npx @livestore/cli --help # Use with npx
21
- ```
22
-
23
- ## Commands
24
-
25
- ### `livestore new-project`
26
- Create a new LiveStore project from available examples.
27
-
28
- ```bash
29
- # Interactive selection
30
- livestore new-project
31
-
32
- # Specify example and path
33
- livestore new-project --example web-todomvc my-project
34
-
35
- # Use specific branch
36
- livestore new-project --branch dev
37
- ```
38
-
39
- ### `livestore mcp`
40
- MCP server tools for AI assistant integration. See [MCP Integration](/building-with-livestore/tools/mcp) for details.
41
-
42
- ```bash
43
- # Start MCP server
44
- livestore mcp
45
-
46
- # Available subcommands
47
- livestore mcp coach # AI coaching assistant (requires API key env var)
48
- livestore mcp tools # Development tools server
49
-
50
- # Coach command requires API key - check implementation for specific variable name
51
- # Example: OPENAI_API_KEY=your_key livestore mcp coach
52
- ```
53
-
54
- ### `livestore sync`
55
-
56
- Import and export events from the sync backend. Useful for backup, migration, and debugging.
57
-
58
- #### Export
59
-
60
- Export all events from the sync backend to a JSON file:
61
-
62
- ```bash
63
- livestore sync export \
64
- --config livestore-cli.config.ts \
65
- --store-id my-store \
66
- events.json
67
- ```
68
-
69
- **Example output:**
70
-
71
- ```
72
- Exporting events from LiveStore...
73
- Config: livestore-cli.config.ts
74
- Store ID: my-store
75
- Output: events.json
76
-
77
- Connecting to sync backend...
78
- ✓ Connected to sync backend: @livestore/cf-sync
79
- Pulling events from sync backend...
80
- Pulled 127 events
81
- Exported 127 events to /path/to/events.json
82
- ```
83
-
84
- **Options:**
85
- - `--config, -c` (required) - Path to a config module that exports `schema` and `syncBackend`
86
- - `--store-id, -i` (required) - Store identifier
87
- - `--client-id` - Client identifier for the sync connection (default: `cli-export`)
88
- - Large exports load data in memory; for very large stores run this on a machine with sufficient RAM.
89
-
90
- #### Import
91
-
92
- Import events from a JSON file to the sync backend:
93
-
94
- ```bash
95
- livestore sync import \
96
- --config livestore-cli.config.ts \
97
- --store-id my-store \
98
- events.json
99
- ```
100
-
101
- **Example output:**
102
-
103
- ```
104
- Importing events to LiveStore...
105
- Config: livestore-cli.config.ts
106
- Store ID: my-store
107
- Input: events.json
108
-
109
- Reading import file...
110
- Found 127 events in export file
111
- Checking for existing events...
112
- Connecting to sync backend...
113
- ✓ Connected to sync backend: @livestore/cf-sync
114
- Pushing events to sync backend...
115
- Pushed 100/127 events
116
- Pushed 127/127 events
117
- Successfully imported 127 events
118
- ```
119
-
120
- **Options:**
121
- - `--config, -c` (required) - Path to a config module that exports `schema` and `syncBackend`
122
- - `--store-id, -i` (required) - Store identifier
123
- - `--client-id` - Client identifier for the sync connection (default: `cli-import`)
124
- - `--force, -f` - Force import even if store ID in the file doesn't match
125
- - `--dry-run` - Validate the import file without actually importing
126
- - Large imports are memory-intensive because the JSON is loaded fully before validation/push.
127
-
128
- **Note:** The sync backend must be empty when importing. The import will fail if events already exist.
129
-
130
- ### Config file
131
-
132
- Both MCP and sync commands require a config file (conventionally named `livestore-cli.config.ts`) that exports:
133
-
134
- ## `reference/cli/config.ts`
135
-
136
- ```ts filename="reference/cli/config.ts"
137
-
138
- // Re-export your app's schema (adjust path to your project)
139
- export { schema } from './schema.ts'
140
-
141
- // Provide a sync backend constructor
142
- export const syncBackend = makeWsSync({
143
- url: process.env.LIVESTORE_SYNC_URL ?? 'ws://localhost:8787',
144
- })
145
-
146
- // Optionally, pass an auth payload (must be JSON-serializable)
147
- export const syncPayload = {
148
- authToken: process.env.LIVESTORE_SYNC_AUTH_TOKEN,
149
- }
150
- ```
151
-
152
- ### `reference/cli/schema.ts`
153
-
154
- ```ts filename="reference/cli/schema.ts"
155
-
156
- const events = {}
157
-
158
- const tables = {
159
- todos: State.SQLite.table({
160
- name: 'todos',
161
- columns: {
162
- id: State.SQLite.text({ primaryKey: true }),
163
- text: State.SQLite.text(),
164
- completed: State.SQLite.boolean({ default: false }),
165
- },
166
- }),
167
- }
168
-
169
- const state = State.SQLite.makeState({ tables, materializers: {} })
170
-
171
- export const schema = makeSchema({ events, state })
172
- ```
173
-
174
- ## Global options
175
-
176
- - `--verbose` - Enable verbose logging
177
- - `--help` - Show command help