@livestore/livestore 0.4.0-dev.22 → 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 (207) 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 +14 -7
  12. package/dist/effect/LiveStore.d.ts.map +1 -1
  13. package/dist/effect/LiveStore.js +0 -15
  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/live-queries/base-class.d.ts +3 -3
  20. package/dist/live-queries/base-class.d.ts.map +1 -1
  21. package/dist/live-queries/base-class.js +2 -2
  22. package/dist/live-queries/base-class.js.map +1 -1
  23. package/dist/live-queries/client-document-get-query.d.ts +1 -1
  24. package/dist/live-queries/client-document-get-query.d.ts.map +1 -1
  25. package/dist/live-queries/client-document-get-query.js +1 -1
  26. package/dist/live-queries/client-document-get-query.js.map +1 -1
  27. package/dist/live-queries/computed.d.ts.map +1 -1
  28. package/dist/live-queries/computed.js +2 -2
  29. package/dist/live-queries/computed.js.map +1 -1
  30. package/dist/live-queries/db-query.js +14 -14
  31. package/dist/live-queries/db-query.js.map +1 -1
  32. package/dist/live-queries/db-query.test.js +2 -2
  33. package/dist/live-queries/db-query.test.js.map +1 -1
  34. package/dist/live-queries/signal.test.js +2 -2
  35. package/dist/live-queries/signal.test.js.map +1 -1
  36. package/dist/mod.d.ts +1 -1
  37. package/dist/mod.d.ts.map +1 -1
  38. package/dist/mod.js.map +1 -1
  39. package/dist/reactive.d.ts +9 -9
  40. package/dist/reactive.d.ts.map +1 -1
  41. package/dist/reactive.js +9 -26
  42. package/dist/reactive.js.map +1 -1
  43. package/dist/reactive.test.js +2 -2
  44. package/dist/reactive.test.js.map +1 -1
  45. package/dist/store/StoreRegistry.d.ts +30 -5
  46. package/dist/store/StoreRegistry.d.ts.map +1 -1
  47. package/dist/store/StoreRegistry.js +54 -31
  48. package/dist/store/StoreRegistry.js.map +1 -1
  49. package/dist/store/StoreRegistry.test.js +251 -250
  50. package/dist/store/StoreRegistry.test.js.map +1 -1
  51. package/dist/store/create-store.d.ts +6 -2
  52. package/dist/store/create-store.d.ts.map +1 -1
  53. package/dist/store/create-store.js +13 -7
  54. package/dist/store/create-store.js.map +1 -1
  55. package/dist/store/devtools.d.ts +1 -1
  56. package/dist/store/devtools.d.ts.map +1 -1
  57. package/dist/store/devtools.js +3 -3
  58. package/dist/store/devtools.js.map +1 -1
  59. package/dist/store/store-eventstream.test.js +2 -2
  60. package/dist/store/store-eventstream.test.js.map +1 -1
  61. package/dist/store/store-types.d.ts +70 -5
  62. package/dist/store/store-types.d.ts.map +1 -1
  63. package/dist/store/store-types.js.map +1 -1
  64. package/dist/store/store-types.test.js +1 -1
  65. package/dist/store/store-types.test.js.map +1 -1
  66. package/dist/store/store.d.ts +81 -2
  67. package/dist/store/store.d.ts.map +1 -1
  68. package/dist/store/store.js +128 -45
  69. package/dist/store/store.js.map +1 -1
  70. package/dist/utils/dev.js.map +1 -1
  71. package/dist/utils/stack-info.js +2 -2
  72. package/dist/utils/stack-info.js.map +1 -1
  73. package/dist/utils/tests/fixture.d.ts +1 -1
  74. package/dist/utils/tests/fixture.d.ts.map +1 -1
  75. package/dist/utils/tests/fixture.js.map +1 -1
  76. package/dist/utils/tests/otel.d.ts.map +1 -1
  77. package/dist/utils/tests/otel.js +5 -5
  78. package/dist/utils/tests/otel.js.map +1 -1
  79. package/package.json +58 -17
  80. package/src/QueryCache.ts +1 -1
  81. package/src/SqliteDbWrapper.test.ts +4 -2
  82. package/src/SqliteDbWrapper.ts +12 -11
  83. package/src/ambient.d.ts +0 -7
  84. package/src/effect/LiveStore.test.ts +61 -0
  85. package/src/effect/LiveStore.ts +17 -26
  86. package/src/live-queries/__snapshots__/db-query.test.ts.snap +336 -231
  87. package/src/live-queries/base-class.ts +7 -6
  88. package/src/live-queries/client-document-get-query.ts +4 -2
  89. package/src/live-queries/computed.ts +3 -2
  90. package/src/live-queries/db-query.test.ts +3 -2
  91. package/src/live-queries/db-query.ts +15 -15
  92. package/src/live-queries/signal.test.ts +3 -2
  93. package/src/mod.ts +1 -0
  94. package/src/reactive.test.ts +3 -2
  95. package/src/reactive.ts +22 -23
  96. package/src/store/StoreRegistry.test.ts +317 -293
  97. package/src/store/StoreRegistry.ts +63 -38
  98. package/src/store/create-store.ts +26 -11
  99. package/src/store/devtools.ts +5 -6
  100. package/src/store/store-eventstream.test.ts +4 -2
  101. package/src/store/store-types.test.ts +3 -1
  102. package/src/store/store-types.ts +47 -8
  103. package/src/store/store.ts +172 -55
  104. package/src/utils/dev.ts +2 -2
  105. package/src/utils/stack-info.ts +2 -2
  106. package/src/utils/tests/fixture.ts +2 -1
  107. package/src/utils/tests/otel.ts +8 -7
  108. package/docs/api/index.md +0 -3
  109. package/docs/building-with-livestore/complex-ui-state/index.md +0 -3
  110. package/docs/building-with-livestore/crud/index.md +0 -3
  111. package/docs/building-with-livestore/data-modeling/index.md +0 -30
  112. package/docs/building-with-livestore/debugging/index.md +0 -17
  113. package/docs/building-with-livestore/devtools/index.md +0 -79
  114. package/docs/building-with-livestore/events/index.md +0 -355
  115. package/docs/building-with-livestore/examples/ai-agent/index.md +0 -5
  116. package/docs/building-with-livestore/examples/todo-workspaces/index.md +0 -885
  117. package/docs/building-with-livestore/examples/turnbased-game/index.md +0 -7
  118. package/docs/building-with-livestore/opentelemetry/index.md +0 -227
  119. package/docs/building-with-livestore/production-checklist/index.md +0 -5
  120. package/docs/building-with-livestore/reactivity-system/index.md +0 -202
  121. package/docs/building-with-livestore/rules-for-ai-agents/index.md +0 -9
  122. package/docs/building-with-livestore/state/materializers/index.md +0 -300
  123. package/docs/building-with-livestore/state/sql-queries/index.md +0 -94
  124. package/docs/building-with-livestore/state/sqlite/index.md +0 -45
  125. package/docs/building-with-livestore/state/sqlite-schema/index.md +0 -306
  126. package/docs/building-with-livestore/state/sqlite-schema-effect/index.md +0 -300
  127. package/docs/building-with-livestore/store/index.md +0 -625
  128. package/docs/building-with-livestore/syncing/index.md +0 -136
  129. package/docs/building-with-livestore/tools/cli/index.md +0 -177
  130. package/docs/building-with-livestore/tools/mcp/index.md +0 -187
  131. package/docs/examples/cloudflare-adapter/index.md +0 -44
  132. package/docs/examples/expo-adapter/index.md +0 -44
  133. package/docs/examples/index.md +0 -55
  134. package/docs/examples/node-adapter/index.md +0 -44
  135. package/docs/examples/web-adapter/index.md +0 -52
  136. package/docs/framework-integrations/custom-elements/index.md +0 -142
  137. package/docs/framework-integrations/react-integration/index.md +0 -937
  138. package/docs/framework-integrations/solid-integration/index.md +0 -293
  139. package/docs/framework-integrations/svelte-integration/index.md +0 -42
  140. package/docs/framework-integrations/vue-integration/index.md +0 -294
  141. package/docs/getting-started/expo/index.md +0 -882
  142. package/docs/getting-started/node/index.md +0 -115
  143. package/docs/getting-started/react-web/index.md +0 -626
  144. package/docs/getting-started/solid/index.md +0 -3
  145. package/docs/getting-started/vue/index.md +0 -471
  146. package/docs/index.md +0 -208
  147. package/docs/llms.txt +0 -146
  148. package/docs/misc/CODE_OF_CONDUCT/index.md +0 -133
  149. package/docs/misc/FAQ/index.md +0 -37
  150. package/docs/misc/community/index.md +0 -88
  151. package/docs/misc/credits/index.md +0 -14
  152. package/docs/misc/design-partners/index.md +0 -13
  153. package/docs/misc/package-management/index.md +0 -21
  154. package/docs/misc/performance/index.md +0 -25
  155. package/docs/misc/resources/index.md +0 -46
  156. package/docs/misc/state-of-the-project/index.md +0 -37
  157. package/docs/misc/troubleshooting/index.md +0 -82
  158. package/docs/overview/concepts/index.md +0 -78
  159. package/docs/overview/how-livestore-works/index.md +0 -56
  160. package/docs/overview/introduction/index.md +0 -413
  161. package/docs/overview/technology-comparison/index.md +0 -40
  162. package/docs/overview/when-livestore/index.md +0 -81
  163. package/docs/overview/why-livestore/index.md +0 -111
  164. package/docs/patterns/ai/index.md +0 -15
  165. package/docs/patterns/anonymous-user-transition/index.md +0 -10
  166. package/docs/patterns/app-evolution/index.md +0 -72
  167. package/docs/patterns/auth/index.md +0 -377
  168. package/docs/patterns/effect/index.md +0 -1505
  169. package/docs/patterns/encryption/index.md +0 -6
  170. package/docs/patterns/external-data/index.md +0 -5
  171. package/docs/patterns/file-management/index.md +0 -11
  172. package/docs/patterns/file-structure/index.md +0 -14
  173. package/docs/patterns/list-ordering/index.md +0 -369
  174. package/docs/patterns/offline/index.md +0 -32
  175. package/docs/patterns/orm/index.md +0 -18
  176. package/docs/patterns/presence/index.md +0 -11
  177. package/docs/patterns/rich-text-editing/index.md +0 -11
  178. package/docs/patterns/server-side-clients/index.md +0 -97
  179. package/docs/patterns/side-effects/index.md +0 -11
  180. package/docs/patterns/state-machines/index.md +0 -11
  181. package/docs/patterns/storybook/index.md +0 -209
  182. package/docs/patterns/undo-redo/index.md +0 -9
  183. package/docs/patterns/version-control/index.md +0 -8
  184. package/docs/platform-adapters/cloudflare-durable-object-adapter/index.md +0 -453
  185. package/docs/platform-adapters/electron-adapter/index.md +0 -15
  186. package/docs/platform-adapters/expo-adapter/index.md +0 -262
  187. package/docs/platform-adapters/node-adapter/index.md +0 -160
  188. package/docs/platform-adapters/tauri-adapter/index.md +0 -15
  189. package/docs/platform-adapters/web-adapter/index.md +0 -287
  190. package/docs/sustainable-open-source/contributing/docs/index.md +0 -94
  191. package/docs/sustainable-open-source/contributing/info/index.md +0 -63
  192. package/docs/sustainable-open-source/contributing/monorepo/index.md +0 -195
  193. package/docs/sustainable-open-source/sponsoring/index.md +0 -104
  194. package/docs/sync-providers/cloudflare/index.md +0 -773
  195. package/docs/sync-providers/custom/index.md +0 -65
  196. package/docs/sync-providers/electricsql/index.md +0 -159
  197. package/docs/sync-providers/s2/index.md +0 -230
  198. package/docs/tutorial/0-welcome/index.md +0 -48
  199. package/docs/tutorial/1-setup-starter-project/index.md +0 -105
  200. package/docs/tutorial/2-deploy-to-cloudflare/index.md +0 -195
  201. package/docs/tutorial/3-read-and-write-todos-via-livestore/index.md +0 -530
  202. package/docs/tutorial/4-sync-data-via-cloudflare/index.md +0 -210
  203. package/docs/tutorial/5-expand-business-logic/index.md +0 -174
  204. package/docs/tutorial/6-persist-ui-state/index.md +0 -453
  205. package/docs/tutorial/7-next-steps/index.md +0 -22
  206. package/docs/understanding-livestore/design-decisions/index.md +0 -33
  207. package/docs/understanding-livestore/event-sourcing/index.md +0 -40
@@ -1,625 +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
- ## Effect integration
262
-
263
- For applications using [Effect](https://effect.website), LiveStore provides a type-safe way to access stores through the Effect layer system via `makeStoreContext()`.
264
-
265
- ### Creating a typed store context
266
-
267
- Use `makeStoreContext()` to create a typed context that preserves your schema types:
268
-
269
- ## `reference/store/effect/make-store-context.ts`
270
-
271
- ```ts filename="reference/store/effect/make-store-context.ts"
272
-
273
- // ---cut---
274
- // Define a typed store context with your schema
275
- export const TodoStore = Store.Tag(schema, 'todos')
276
-
277
- // Create a layer to initialize the store
278
- const adapter = makeAdapter({ storage: { type: 'fs' } })
279
-
280
- export const TodoStoreLayer = TodoStore.layer({
281
- adapter,
282
- batchUpdates: (cb) => cb(), // For Node.js; use React's unstable_batchedUpdates in React apps
283
- })
284
- ```
285
-
286
- ### `reference/store/effect/schema.ts`
287
-
288
- ```ts filename="reference/store/effect/schema.ts"
289
-
290
- const tables = {
291
- todos: State.SQLite.table({
292
- name: 'todos',
293
- columns: {
294
- id: State.SQLite.text({ primaryKey: true }),
295
- text: State.SQLite.text(),
296
- completed: State.SQLite.boolean({ default: false }),
297
- },
298
- }),
299
- } as const
300
-
301
- const events = {
302
- todoCreated: Events.synced({
303
- name: 'v1.TodoCreated',
304
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
305
- }),
306
- todoCompleted: Events.synced({
307
- name: 'v1.TodoCompleted',
308
- schema: Schema.Struct({ id: Schema.String }),
309
- }),
310
- } as const
311
-
312
- const materializers = State.SQLite.materializers(events, {
313
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
314
- tables.todos.insert({ id, text, completed: false }),
315
- ),
316
- [events.todoCompleted.name]: defineMaterializer(events.todoCompleted, ({ id }) =>
317
- tables.todos.update({ completed: true }).where({ id }),
318
- ),
319
- })
320
-
321
- const state = State.SQLite.makeState({ tables, materializers })
322
-
323
- export const schema = makeSchema({ events, state })
324
- export const storeTables = tables
325
- export const storeEvents = events
326
- ```
327
-
328
- The factory takes your schema type as a generic parameter and returns a `StoreContext` with:
329
- - `Tag` - Context tag for dependency injection
330
- - `Layer` - Creates a layer that initializes the store
331
- - `DeferredTag` - For async initialization patterns
332
- - `DeferredLayer` - Layer providing the deferred context
333
- - `fromDeferred` - Layer that waits for deferred initialization
334
-
335
- ### Using the store in Effect services
336
-
337
- Access the store in Effect code with full type safety and autocomplete:
338
-
339
- ## `reference/store/effect/usage-in-service.ts`
340
-
341
- ```ts filename="reference/store/effect/usage-in-service.ts"
342
-
343
- // ---cut---
344
- // Access the store in Effect code with full type safety
345
- const _todoService = Effect.gen(function* () {
346
- // Yield the store directly (it's a Context.Tag)
347
- const { store } = yield* TodoStore
348
-
349
- // Query with autocomplete for tables
350
- const todos = store.query(storeTables.todos.select())
351
-
352
- // Commit events
353
- store.commit(storeEvents.todoCreated({ id: '1', text: 'Buy milk' }))
354
-
355
- return todos
356
- })
357
-
358
- // Or use static accessors for a more functional style
359
- const _todoServiceAlt = Effect.gen(function* () {
360
- // Query using static accessor
361
- const todos = yield* TodoStore.query(storeTables.todos.select())
362
-
363
- // Commit using static accessor
364
- yield* TodoStore.commit(storeEvents.todoCreated({ id: '1', text: 'Buy milk' }))
365
-
366
- return todos
367
- })
368
- ```
369
-
370
- ### `reference/store/effect/make-store-context.ts`
371
-
372
- ```ts filename="reference/store/effect/make-store-context.ts"
373
-
374
- // ---cut---
375
- // Define a typed store context with your schema
376
- export const TodoStore = Store.Tag(schema, 'todos')
377
-
378
- // Create a layer to initialize the store
379
- const adapter = makeAdapter({ storage: { type: 'fs' } })
380
-
381
- export const TodoStoreLayer = TodoStore.layer({
382
- adapter,
383
- batchUpdates: (cb) => cb(), // For Node.js; use React's unstable_batchedUpdates in React apps
384
- })
385
- ```
386
-
387
- ### `reference/store/effect/schema.ts`
388
-
389
- ```ts filename="reference/store/effect/schema.ts"
390
-
391
- const tables = {
392
- todos: State.SQLite.table({
393
- name: 'todos',
394
- columns: {
395
- id: State.SQLite.text({ primaryKey: true }),
396
- text: State.SQLite.text(),
397
- completed: State.SQLite.boolean({ default: false }),
398
- },
399
- }),
400
- } as const
401
-
402
- const events = {
403
- todoCreated: Events.synced({
404
- name: 'v1.TodoCreated',
405
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
406
- }),
407
- todoCompleted: Events.synced({
408
- name: 'v1.TodoCompleted',
409
- schema: Schema.Struct({ id: Schema.String }),
410
- }),
411
- } as const
412
-
413
- const materializers = State.SQLite.materializers(events, {
414
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
415
- tables.todos.insert({ id, text, completed: false }),
416
- ),
417
- [events.todoCompleted.name]: defineMaterializer(events.todoCompleted, ({ id }) =>
418
- tables.todos.update({ completed: true }).where({ id }),
419
- ),
420
- })
421
-
422
- const state = State.SQLite.makeState({ tables, materializers })
423
-
424
- export const schema = makeSchema({ events, state })
425
- export const storeTables = tables
426
- export const storeEvents = events
427
- ```
428
-
429
- ### Layer composition
430
-
431
- Compose store layers with your application services:
432
-
433
- ## `reference/store/effect/layer-composition.ts`
434
-
435
- ```ts filename="reference/store/effect/layer-composition.ts"
436
-
437
- // ---cut---
438
- // Define services that depend on the store
439
- class TodoService extends Effect.Service<TodoService>()('TodoService', {
440
- effect: Effect.gen(function* () {
441
- const { store } = yield* TodoStore
442
-
443
- const createTodo = (id: string, text: string) =>
444
- Effect.sync(() => store.commit(storeEvents.todoCreated({ id, text })))
445
-
446
- const completeTodo = (id: string) => Effect.sync(() => store.commit(storeEvents.todoCompleted({ id })))
447
-
448
- return { createTodo, completeTodo } as const
449
- }),
450
- dependencies: [TodoStoreLayer],
451
- }) {}
452
-
453
- // Compose everything into a main layer
454
- const MainLayer = Layer.mergeAll(TodoStoreLayer, TodoService.Default)
455
-
456
- // Use in your application
457
- const program = Effect.gen(function* () {
458
- const todoService = yield* TodoService
459
- yield* todoService.createTodo('1', 'Learn Effect')
460
- yield* todoService.completeTodo('1')
461
- })
462
-
463
- // Provide MainLayer when running (OtelTracer is also required)
464
- void program.pipe(Effect.provide(MainLayer))
465
- ```
466
-
467
- ### `reference/store/effect/make-store-context.ts`
468
-
469
- ```ts filename="reference/store/effect/make-store-context.ts"
470
-
471
- // ---cut---
472
- // Define a typed store context with your schema
473
- export const TodoStore = Store.Tag(schema, 'todos')
474
-
475
- // Create a layer to initialize the store
476
- const adapter = makeAdapter({ storage: { type: 'fs' } })
477
-
478
- export const TodoStoreLayer = TodoStore.layer({
479
- adapter,
480
- batchUpdates: (cb) => cb(), // For Node.js; use React's unstable_batchedUpdates in React apps
481
- })
482
- ```
483
-
484
- ### `reference/store/effect/schema.ts`
485
-
486
- ```ts filename="reference/store/effect/schema.ts"
487
-
488
- const tables = {
489
- todos: State.SQLite.table({
490
- name: 'todos',
491
- columns: {
492
- id: State.SQLite.text({ primaryKey: true }),
493
- text: State.SQLite.text(),
494
- completed: State.SQLite.boolean({ default: false }),
495
- },
496
- }),
497
- } as const
498
-
499
- const events = {
500
- todoCreated: Events.synced({
501
- name: 'v1.TodoCreated',
502
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
503
- }),
504
- todoCompleted: Events.synced({
505
- name: 'v1.TodoCompleted',
506
- schema: Schema.Struct({ id: Schema.String }),
507
- }),
508
- } as const
509
-
510
- const materializers = State.SQLite.materializers(events, {
511
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
512
- tables.todos.insert({ id, text, completed: false }),
513
- ),
514
- [events.todoCompleted.name]: defineMaterializer(events.todoCompleted, ({ id }) =>
515
- tables.todos.update({ completed: true }).where({ id }),
516
- ),
517
- })
518
-
519
- const state = State.SQLite.makeState({ tables, materializers })
520
-
521
- export const schema = makeSchema({ events, state })
522
- export const storeTables = tables
523
- export const storeEvents = events
524
- ```
525
-
526
- ### Multiple stores with Effect
527
-
528
- Each store gets a unique context tag, allowing multiple stores in the same Effect context:
529
-
530
- ## `reference/store/effect/multiple-stores.ts`
531
-
532
- ```ts filename="reference/store/effect/multiple-stores.ts"
533
-
534
- // For demonstration, we'll use the same schema for both stores
535
- const settingsSchema = mainSchema
536
-
537
- // ---cut---
538
- // Define multiple typed store contexts
539
- const MainStore = Store.Tag(mainSchema, 'main')
540
- const SettingsStore = Store.Tag(settingsSchema, 'settings')
541
-
542
- // Each store has its own layer
543
- const adapter = makeAdapter({ storage: { type: 'fs' } })
544
-
545
- const MainStoreLayer = MainStore.layer({ adapter, batchUpdates: (cb) => cb() })
546
- const SettingsStoreLayer = SettingsStore.layer({ adapter, batchUpdates: (cb) => cb() })
547
-
548
- // Compose layers together
549
- const _AllStoresLayer = Layer.mergeAll(MainStoreLayer, SettingsStoreLayer)
550
-
551
- // Both stores available in Effect code
552
- const _program = Effect.gen(function* () {
553
- const { store: mainStore } = yield* MainStore
554
- const { store: settingsStore } = yield* SettingsStore
555
-
556
- // Each store is independently typed
557
- return { mainStore, settingsStore }
558
- })
559
- ```
560
-
561
- ### `reference/store/effect/schema.ts`
562
-
563
- ```ts filename="reference/store/effect/schema.ts"
564
-
565
- const tables = {
566
- todos: State.SQLite.table({
567
- name: 'todos',
568
- columns: {
569
- id: State.SQLite.text({ primaryKey: true }),
570
- text: State.SQLite.text(),
571
- completed: State.SQLite.boolean({ default: false }),
572
- },
573
- }),
574
- } as const
575
-
576
- const events = {
577
- todoCreated: Events.synced({
578
- name: 'v1.TodoCreated',
579
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
580
- }),
581
- todoCompleted: Events.synced({
582
- name: 'v1.TodoCompleted',
583
- schema: Schema.Struct({ id: Schema.String }),
584
- }),
585
- } as const
586
-
587
- const materializers = State.SQLite.materializers(events, {
588
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
589
- tables.todos.insert({ id, text, completed: false }),
590
- ),
591
- [events.todoCompleted.name]: defineMaterializer(events.todoCompleted, ({ id }) =>
592
- tables.todos.update({ completed: true }).where({ id }),
593
- ),
594
- })
595
-
596
- const state = State.SQLite.makeState({ tables, materializers })
597
-
598
- export const schema = makeSchema({ events, state })
599
- export const storeTables = tables
600
- export const storeEvents = events
601
- ```
602
-
603
- For more Effect patterns including Effect Atom integration, see the [Effect patterns](/patterns/effect) page.
604
-
605
- ## Multiple stores
606
-
607
- You can create and use multiple stores in the same app. This can be useful when breaking up your data model into smaller pieces.
608
-
609
- ## Development/debugging helpers
610
-
611
- 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):
612
-
613
- ```ts
614
- // Download the SQLite database
615
- __debugLiveStore.default._dev.downloadDb()
616
-
617
- // Download the eventlog database
618
- __debugLiveStore.default._dev.downloadEventlogDb()
619
-
620
- // Reset the store
621
- __debugLiveStore.default._dev.hardReset()
622
-
623
- // See the current sync state
624
- __debugLiveStore.default._dev.syncStates()
625
- ```