@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,626 +0,0 @@
1
- # Getting started with LiveStore + React
2
-
3
- export const CODE = {
4
- viteConfig: viteConfigCode,
5
- }
6
-
7
- {/* We're adjusting the package to use the dev version on the dev branch */}
8
- export const manualInstallDepsStr = [
9
- '@livestore/livestore' + versionNpmSuffix,
10
- '@livestore/wa-sqlite' + versionNpmSuffix,
11
- '@livestore/adapter-web' + versionNpmSuffix,
12
- '@livestore/react' + versionNpmSuffix,
13
- '@livestore/peer-deps' + versionNpmSuffix,
14
- '@livestore/sync-cf' + versionNpmSuffix,
15
- '@livestore/devtools-vite' + versionNpmSuffix,
16
- ].join(' ')
17
-
18
- ## Prerequisites
19
-
20
- - Recommended: Bun 1.2 or higher
21
- - Node.js {MIN_NODE_VERSION} or higher
22
-
23
- ### Option A: Quick start
24
-
25
- For a quick start, we recommend using our template app following the steps below.
26
-
27
- For existing projects, see [Existing project setup](#existing-project-setup).
28
-
29
- <Steps>
30
-
31
- 1. **Set up project from template**
32
-
33
- <Tabs syncKey="package-manager">
34
- <TabItem label="bun">
35
- <Code code={makeCreate('web-todomvc-sync-cf', 'bunx')} lang="sh" />
36
- </TabItem>
37
- <TabItem label="pnpm">
38
- <Code code={makeCreate('web-todomvc-sync-cf', 'pnpm dlx')} lang="sh" />
39
- </TabItem>
40
- <TabItem label="npm">
41
- <Code code={makeCreate('web-todomvc-sync-cf', 'npx')} lang="sh" />
42
- </TabItem>
43
- </Tabs>
44
-
45
- Replace `livestore-app` with your desired app name.
46
-
47
- 2. **Install dependencies**
48
-
49
- It's strongly recommended to use `bun` or `pnpm` for the simplest and most reliable dependency setup (see [note on package management](/misc/package-management) for more details).
50
-
51
- <Tabs syncKey="package-manager">
52
- <TabItem label="bun">
53
- <Code code="bun install" lang="sh" />
54
- </TabItem>
55
- <TabItem label="pnpm">
56
- <Code code="pnpm install" lang="sh" />
57
- </TabItem>
58
- <TabItem label="npm">
59
- <Code code="npm install" lang="sh" />
60
- </TabItem>
61
- </Tabs>
62
-
63
- Pro tip: You can use [direnv](https://direnv.net/) to manage environment variables.
64
-
65
- 3. **Run dev environment**
66
-
67
- <Tabs syncKey="package-manager">
68
- <TabItem label="bun">
69
- <Code code="bun dev" lang="sh" />
70
- </TabItem>
71
- <TabItem label="pnpm">
72
- <Code code="pnpm dev" lang="sh" />
73
- </TabItem>
74
- <TabItem label="npm">
75
- <Code code="npm run dev" lang="sh" />
76
- </TabItem>
77
- </Tabs>
78
-
79
- 4. **Open browser**
80
-
81
- Open `http://localhost:60000` in your browser.
82
-
83
- You can also open the devtools by going to `http://localhost:60000/_livestore`.
84
-
85
- </Steps>
86
-
87
- ### Option B: Existing project setup \{#existing-project-setup\}
88
-
89
- <Steps>
90
-
91
- 1. **Install dependencies**
92
-
93
- <Tabs syncKey="package-manager">
94
- <TabItem label="bun">
95
- <Code code={'bun install ' + manualInstallDepsStr} lang="sh" />
96
- </TabItem>
97
- <TabItem label="pnpm">
98
- <Code code={'pnpm add ' + manualInstallDepsStr} lang="sh" />
99
- </TabItem>
100
- <TabItem label="npm">
101
- <Code code={'npm install ' + manualInstallDepsStr} lang="sh" />
102
- </TabItem>
103
- </Tabs>
104
-
105
- 2. **Update Vite config**
106
-
107
- Add the following code to your `vite.config.js` file:
108
-
109
- <Code code={viteConfigCode} lang="js" title="vite.config.js" />
110
- </Steps>
111
-
112
- ## Define your schema
113
-
114
- Create a file named `schema.ts` inside the `src/livestore` folder. This file defines your LiveStore schema consisting of your app's event definitions (describing how data changes), derived state (i.e. SQLite tables), and materializers (how state is derived from events).
115
-
116
- Here's an example schema:
117
-
118
- ## `getting-started/react-web/livestore/schema.ts`
119
-
120
- ```ts filename="getting-started/react-web/livestore/schema.ts"
121
-
122
- // You can model your state as SQLite tables (https://docs.livestore.dev/reference/state/sqlite-schema)
123
- export const tables = {
124
- todos: State.SQLite.table({
125
- name: 'todos',
126
- columns: {
127
- id: State.SQLite.text({ primaryKey: true }),
128
- text: State.SQLite.text({ default: '' }),
129
- completed: State.SQLite.boolean({ default: false }),
130
- deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
131
- },
132
- }),
133
- // Client documents can be used for local-only state (e.g. form inputs)
134
- uiState: State.SQLite.clientDocument({
135
- name: 'uiState',
136
- schema: Schema.Struct({ newTodoText: Schema.String, filter: Schema.Literal('all', 'active', 'completed') }),
137
- default: { id: SessionIdSymbol, value: { newTodoText: '', filter: 'all' } },
138
- }),
139
- }
140
-
141
- // Events describe data changes (https://docs.livestore.dev/reference/events)
142
- export const events = {
143
- todoCreated: Events.synced({
144
- name: 'v1.TodoCreated',
145
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
146
- }),
147
- todoCompleted: Events.synced({
148
- name: 'v1.TodoCompleted',
149
- schema: Schema.Struct({ id: Schema.String }),
150
- }),
151
- todoUncompleted: Events.synced({
152
- name: 'v1.TodoUncompleted',
153
- schema: Schema.Struct({ id: Schema.String }),
154
- }),
155
- todoDeleted: Events.synced({
156
- name: 'v1.TodoDeleted',
157
- schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
158
- }),
159
- todoClearedCompleted: Events.synced({
160
- name: 'v1.TodoClearedCompleted',
161
- schema: Schema.Struct({ deletedAt: Schema.Date }),
162
- }),
163
- uiStateSet: tables.uiState.set,
164
- }
165
-
166
- // Materializers are used to map events to state (https://docs.livestore.dev/reference/state/materializers)
167
- const materializers = State.SQLite.materializers(events, {
168
- 'v1.TodoCreated': ({ id, text }) => tables.todos.insert({ id, text, completed: false }),
169
- 'v1.TodoCompleted': ({ id }) => tables.todos.update({ completed: true }).where({ id }),
170
- 'v1.TodoUncompleted': ({ id }) => tables.todos.update({ completed: false }).where({ id }),
171
- 'v1.TodoDeleted': ({ id, deletedAt }) => tables.todos.update({ deletedAt }).where({ id }),
172
- 'v1.TodoClearedCompleted': ({ deletedAt }) => tables.todos.update({ deletedAt }).where({ completed: true }),
173
- })
174
-
175
- const state = State.SQLite.makeState({ tables, materializers })
176
-
177
- export const schema = makeSchema({ events, state })
178
- ```
179
-
180
- ## Create the LiveStore worker
181
-
182
- Create a file named `livestore.worker.ts` inside the `src` folder. This file will contain the LiveStore web worker. When importing this file, make sure to add the `?worker` extension to the import path to ensure that Vite treats it as a worker file.
183
-
184
- ## `getting-started/react-web/livestore.worker.ts`
185
-
186
- ```ts filename="getting-started/react-web/livestore.worker.ts"
187
-
188
- makeWorker({ schema })
189
- ```
190
-
191
- ### `getting-started/react-web/livestore/schema.ts`
192
-
193
- ```ts filename="getting-started/react-web/livestore/schema.ts"
194
-
195
- // You can model your state as SQLite tables (https://docs.livestore.dev/reference/state/sqlite-schema)
196
- export const tables = {
197
- todos: State.SQLite.table({
198
- name: 'todos',
199
- columns: {
200
- id: State.SQLite.text({ primaryKey: true }),
201
- text: State.SQLite.text({ default: '' }),
202
- completed: State.SQLite.boolean({ default: false }),
203
- deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
204
- },
205
- }),
206
- // Client documents can be used for local-only state (e.g. form inputs)
207
- uiState: State.SQLite.clientDocument({
208
- name: 'uiState',
209
- schema: Schema.Struct({ newTodoText: Schema.String, filter: Schema.Literal('all', 'active', 'completed') }),
210
- default: { id: SessionIdSymbol, value: { newTodoText: '', filter: 'all' } },
211
- }),
212
- }
213
-
214
- // Events describe data changes (https://docs.livestore.dev/reference/events)
215
- export const events = {
216
- todoCreated: Events.synced({
217
- name: 'v1.TodoCreated',
218
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
219
- }),
220
- todoCompleted: Events.synced({
221
- name: 'v1.TodoCompleted',
222
- schema: Schema.Struct({ id: Schema.String }),
223
- }),
224
- todoUncompleted: Events.synced({
225
- name: 'v1.TodoUncompleted',
226
- schema: Schema.Struct({ id: Schema.String }),
227
- }),
228
- todoDeleted: Events.synced({
229
- name: 'v1.TodoDeleted',
230
- schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
231
- }),
232
- todoClearedCompleted: Events.synced({
233
- name: 'v1.TodoClearedCompleted',
234
- schema: Schema.Struct({ deletedAt: Schema.Date }),
235
- }),
236
- uiStateSet: tables.uiState.set,
237
- }
238
-
239
- // Materializers are used to map events to state (https://docs.livestore.dev/reference/state/materializers)
240
- const materializers = State.SQLite.materializers(events, {
241
- 'v1.TodoCreated': ({ id, text }) => tables.todos.insert({ id, text, completed: false }),
242
- 'v1.TodoCompleted': ({ id }) => tables.todos.update({ completed: true }).where({ id }),
243
- 'v1.TodoUncompleted': ({ id }) => tables.todos.update({ completed: false }).where({ id }),
244
- 'v1.TodoDeleted': ({ id, deletedAt }) => tables.todos.update({ deletedAt }).where({ id }),
245
- 'v1.TodoClearedCompleted': ({ deletedAt }) => tables.todos.update({ deletedAt }).where({ completed: true }),
246
- })
247
-
248
- const state = State.SQLite.makeState({ tables, materializers })
249
-
250
- export const schema = makeSchema({ events, state })
251
- ```
252
-
253
- ## Configure the store
254
-
255
- Create a `store.ts` file in the `src` folder. This file configures the store adapter and exports a custom hook that components will use to access the store.
256
-
257
- The `useStore()` hook accepts store configuration options (schema, adapter, store ID) and returns a store instance. It suspends while the store is loading, so make sure to use a `Suspense` boundary to handle the loading state.
258
-
259
- ## `getting-started/react-web/store.ts`
260
-
261
- ```ts filename="getting-started/react-web/store.ts"
262
-
263
- const adapter = makePersistedAdapter({
264
- storage: { type: 'opfs' },
265
- worker: LiveStoreWorker,
266
- sharedWorker: LiveStoreSharedWorker,
267
- })
268
-
269
- export const useAppStore = () =>
270
- useStore({
271
- storeId: 'app-root',
272
- schema,
273
- adapter,
274
- batchUpdates,
275
- })
276
- ```
277
-
278
- ### `getting-started/react-web/livestore/schema.ts`
279
-
280
- ```ts filename="getting-started/react-web/livestore/schema.ts"
281
-
282
- // You can model your state as SQLite tables (https://docs.livestore.dev/reference/state/sqlite-schema)
283
- export const tables = {
284
- todos: State.SQLite.table({
285
- name: 'todos',
286
- columns: {
287
- id: State.SQLite.text({ primaryKey: true }),
288
- text: State.SQLite.text({ default: '' }),
289
- completed: State.SQLite.boolean({ default: false }),
290
- deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
291
- },
292
- }),
293
- // Client documents can be used for local-only state (e.g. form inputs)
294
- uiState: State.SQLite.clientDocument({
295
- name: 'uiState',
296
- schema: Schema.Struct({ newTodoText: Schema.String, filter: Schema.Literal('all', 'active', 'completed') }),
297
- default: { id: SessionIdSymbol, value: { newTodoText: '', filter: 'all' } },
298
- }),
299
- }
300
-
301
- // Events describe data changes (https://docs.livestore.dev/reference/events)
302
- export const events = {
303
- todoCreated: Events.synced({
304
- name: 'v1.TodoCreated',
305
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
306
- }),
307
- todoCompleted: Events.synced({
308
- name: 'v1.TodoCompleted',
309
- schema: Schema.Struct({ id: Schema.String }),
310
- }),
311
- todoUncompleted: Events.synced({
312
- name: 'v1.TodoUncompleted',
313
- schema: Schema.Struct({ id: Schema.String }),
314
- }),
315
- todoDeleted: Events.synced({
316
- name: 'v1.TodoDeleted',
317
- schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
318
- }),
319
- todoClearedCompleted: Events.synced({
320
- name: 'v1.TodoClearedCompleted',
321
- schema: Schema.Struct({ deletedAt: Schema.Date }),
322
- }),
323
- uiStateSet: tables.uiState.set,
324
- }
325
-
326
- // Materializers are used to map events to state (https://docs.livestore.dev/reference/state/materializers)
327
- const materializers = State.SQLite.materializers(events, {
328
- 'v1.TodoCreated': ({ id, text }) => tables.todos.insert({ id, text, completed: false }),
329
- 'v1.TodoCompleted': ({ id }) => tables.todos.update({ completed: true }).where({ id }),
330
- 'v1.TodoUncompleted': ({ id }) => tables.todos.update({ completed: false }).where({ id }),
331
- 'v1.TodoDeleted': ({ id, deletedAt }) => tables.todos.update({ deletedAt }).where({ id }),
332
- 'v1.TodoClearedCompleted': ({ deletedAt }) => tables.todos.update({ deletedAt }).where({ completed: true }),
333
- })
334
-
335
- const state = State.SQLite.makeState({ tables, materializers })
336
-
337
- export const schema = makeSchema({ events, state })
338
- ```
339
-
340
- ## Set up the store registry
341
-
342
- To enable store management throughout your app, create a `StoreRegistry` and provide it with a `<StoreRegistryProvider>`. The registry manages store instance lifecycles (loading, caching, disposal).
343
-
344
- Wrap the provider in a `Suspense` boundary to handle the loading state for when the store is loading.
345
-
346
- ## `getting-started/react-web/Root.tsx`
347
-
348
- ```tsx filename="getting-started/react-web/Root.tsx"
349
-
350
- export const App: React.FC = () => {
351
- const [storeRegistry] = useState(() => new StoreRegistry())
352
-
353
- return (
354
- <Suspense fallback={<div>Loading app...</div>}>
355
- <StoreRegistryProvider storeRegistry={storeRegistry}>
356
- <div className="todoapp">{/* Your app components go here */}</div>
357
- </StoreRegistryProvider>
358
- </Suspense>
359
- )
360
- }
361
- ```
362
-
363
- ## Commit events
364
-
365
- After setting up the registry, use the `useAppStore()` hook from any component to access the store and commit events.
366
-
367
- ## `getting-started/react-web/Header.tsx`
368
-
369
- ```tsx filename="getting-started/react-web/Header.tsx"
370
-
371
- const uiState$ = queryDb(tables.uiState.get(), { label: 'uiState' })
372
-
373
- export const Header: React.FC = () => {
374
- const store = useAppStore()
375
- const { newTodoText } = store.useQuery(uiState$)
376
-
377
- const updateNewTodoText = (text: string) => store.commit(events.uiStateSet({ newTodoText: text }))
378
-
379
- const createTodo = () =>
380
- store.commit(
381
- events.todoCreated({ id: crypto.randomUUID(), text: newTodoText }),
382
- events.uiStateSet({ newTodoText: '' }),
383
- )
384
-
385
- return (
386
- <header className="header">
387
- <h1>TodoMVC</h1>
388
- <input
389
- className="new-todo"
390
- placeholder="What needs to be done?"
391
- value={newTodoText}
392
- onChange={(e) => updateNewTodoText(e.target.value)}
393
- onKeyDown={(e) => {
394
- if (e.key === 'Enter') {
395
- createTodo()
396
- }
397
- }}
398
- />
399
- </header>
400
- )
401
- }
402
- ```
403
-
404
- ### `getting-started/react-web/livestore/schema.ts`
405
-
406
- ```ts filename="getting-started/react-web/livestore/schema.ts"
407
-
408
- // You can model your state as SQLite tables (https://docs.livestore.dev/reference/state/sqlite-schema)
409
- export const tables = {
410
- todos: State.SQLite.table({
411
- name: 'todos',
412
- columns: {
413
- id: State.SQLite.text({ primaryKey: true }),
414
- text: State.SQLite.text({ default: '' }),
415
- completed: State.SQLite.boolean({ default: false }),
416
- deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
417
- },
418
- }),
419
- // Client documents can be used for local-only state (e.g. form inputs)
420
- uiState: State.SQLite.clientDocument({
421
- name: 'uiState',
422
- schema: Schema.Struct({ newTodoText: Schema.String, filter: Schema.Literal('all', 'active', 'completed') }),
423
- default: { id: SessionIdSymbol, value: { newTodoText: '', filter: 'all' } },
424
- }),
425
- }
426
-
427
- // Events describe data changes (https://docs.livestore.dev/reference/events)
428
- export const events = {
429
- todoCreated: Events.synced({
430
- name: 'v1.TodoCreated',
431
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
432
- }),
433
- todoCompleted: Events.synced({
434
- name: 'v1.TodoCompleted',
435
- schema: Schema.Struct({ id: Schema.String }),
436
- }),
437
- todoUncompleted: Events.synced({
438
- name: 'v1.TodoUncompleted',
439
- schema: Schema.Struct({ id: Schema.String }),
440
- }),
441
- todoDeleted: Events.synced({
442
- name: 'v1.TodoDeleted',
443
- schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
444
- }),
445
- todoClearedCompleted: Events.synced({
446
- name: 'v1.TodoClearedCompleted',
447
- schema: Schema.Struct({ deletedAt: Schema.Date }),
448
- }),
449
- uiStateSet: tables.uiState.set,
450
- }
451
-
452
- // Materializers are used to map events to state (https://docs.livestore.dev/reference/state/materializers)
453
- const materializers = State.SQLite.materializers(events, {
454
- 'v1.TodoCreated': ({ id, text }) => tables.todos.insert({ id, text, completed: false }),
455
- 'v1.TodoCompleted': ({ id }) => tables.todos.update({ completed: true }).where({ id }),
456
- 'v1.TodoUncompleted': ({ id }) => tables.todos.update({ completed: false }).where({ id }),
457
- 'v1.TodoDeleted': ({ id, deletedAt }) => tables.todos.update({ deletedAt }).where({ id }),
458
- 'v1.TodoClearedCompleted': ({ deletedAt }) => tables.todos.update({ deletedAt }).where({ completed: true }),
459
- })
460
-
461
- const state = State.SQLite.makeState({ tables, materializers })
462
-
463
- export const schema = makeSchema({ events, state })
464
- ```
465
-
466
- ### `getting-started/react-web/store.ts`
467
-
468
- ```ts filename="getting-started/react-web/store.ts"
469
-
470
- const adapter = makePersistedAdapter({
471
- storage: { type: 'opfs' },
472
- worker: LiveStoreWorker,
473
- sharedWorker: LiveStoreSharedWorker,
474
- })
475
-
476
- export const useAppStore = () =>
477
- useStore({
478
- storeId: 'app-root',
479
- schema,
480
- adapter,
481
- batchUpdates,
482
- })
483
- ```
484
-
485
- ## Queries
486
-
487
- To retrieve data from the database, define a query using `queryDb` from `@livestore/livestore`, then execute it with `store.useQuery()`.
488
-
489
- Consider abstracting queries into a separate file to keep your code organized, though you can also define them directly within components if preferred.
490
-
491
- ## `getting-started/react-web/MainSection.tsx`
492
-
493
- ```tsx filename="getting-started/react-web/MainSection.tsx"
494
-
495
- const uiState$ = queryDb(tables.uiState.get(), { label: 'uiState' })
496
-
497
- const visibleTodos$ = queryDb(
498
- (get) => {
499
- const { filter } = get(uiState$)
500
- return tables.todos.where({
501
- deletedAt: null,
502
- completed: filter === 'all' ? undefined : filter === 'completed',
503
- })
504
- },
505
- { label: 'visibleTodos' },
506
- )
507
-
508
- export const MainSection: React.FC = () => {
509
- const store = useAppStore()
510
-
511
- const toggleTodo = React.useCallback(
512
- ({ id, completed }: typeof tables.todos.Type) =>
513
- store.commit(completed ? events.todoUncompleted({ id }) : events.todoCompleted({ id })),
514
- [store],
515
- )
516
-
517
- const visibleTodos = store.useQuery(visibleTodos$)
518
-
519
- return (
520
- <section className="main">
521
- <ul className="todo-list">
522
- {visibleTodos.map((todo) => (
523
- <li key={todo.id}>
524
- <div className="view">
525
- <input
526
- type="checkbox"
527
- className="toggle"
528
- id={`todo-${todo.id}`}
529
- checked={todo.completed}
530
- onChange={() => toggleTodo(todo)}
531
- />
532
- <label htmlFor={`todo-${todo.id}`}>{todo.text}</label>
533
- <button
534
- type="button"
535
- className="destroy"
536
- onClick={() => store.commit(events.todoDeleted({ id: todo.id, deletedAt: new Date() }))}
537
- />
538
- </div>
539
- </li>
540
- ))}
541
- </ul>
542
- </section>
543
- )
544
- }
545
- ```
546
-
547
- ### `getting-started/react-web/livestore/schema.ts`
548
-
549
- ```ts filename="getting-started/react-web/livestore/schema.ts"
550
-
551
- // You can model your state as SQLite tables (https://docs.livestore.dev/reference/state/sqlite-schema)
552
- export const tables = {
553
- todos: State.SQLite.table({
554
- name: 'todos',
555
- columns: {
556
- id: State.SQLite.text({ primaryKey: true }),
557
- text: State.SQLite.text({ default: '' }),
558
- completed: State.SQLite.boolean({ default: false }),
559
- deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
560
- },
561
- }),
562
- // Client documents can be used for local-only state (e.g. form inputs)
563
- uiState: State.SQLite.clientDocument({
564
- name: 'uiState',
565
- schema: Schema.Struct({ newTodoText: Schema.String, filter: Schema.Literal('all', 'active', 'completed') }),
566
- default: { id: SessionIdSymbol, value: { newTodoText: '', filter: 'all' } },
567
- }),
568
- }
569
-
570
- // Events describe data changes (https://docs.livestore.dev/reference/events)
571
- export const events = {
572
- todoCreated: Events.synced({
573
- name: 'v1.TodoCreated',
574
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
575
- }),
576
- todoCompleted: Events.synced({
577
- name: 'v1.TodoCompleted',
578
- schema: Schema.Struct({ id: Schema.String }),
579
- }),
580
- todoUncompleted: Events.synced({
581
- name: 'v1.TodoUncompleted',
582
- schema: Schema.Struct({ id: Schema.String }),
583
- }),
584
- todoDeleted: Events.synced({
585
- name: 'v1.TodoDeleted',
586
- schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
587
- }),
588
- todoClearedCompleted: Events.synced({
589
- name: 'v1.TodoClearedCompleted',
590
- schema: Schema.Struct({ deletedAt: Schema.Date }),
591
- }),
592
- uiStateSet: tables.uiState.set,
593
- }
594
-
595
- // Materializers are used to map events to state (https://docs.livestore.dev/reference/state/materializers)
596
- const materializers = State.SQLite.materializers(events, {
597
- 'v1.TodoCreated': ({ id, text }) => tables.todos.insert({ id, text, completed: false }),
598
- 'v1.TodoCompleted': ({ id }) => tables.todos.update({ completed: true }).where({ id }),
599
- 'v1.TodoUncompleted': ({ id }) => tables.todos.update({ completed: false }).where({ id }),
600
- 'v1.TodoDeleted': ({ id, deletedAt }) => tables.todos.update({ deletedAt }).where({ id }),
601
- 'v1.TodoClearedCompleted': ({ deletedAt }) => tables.todos.update({ deletedAt }).where({ completed: true }),
602
- })
603
-
604
- const state = State.SQLite.makeState({ tables, materializers })
605
-
606
- export const schema = makeSchema({ events, state })
607
- ```
608
-
609
- ### `getting-started/react-web/store.ts`
610
-
611
- ```ts filename="getting-started/react-web/store.ts"
612
-
613
- const adapter = makePersistedAdapter({
614
- storage: { type: 'opfs' },
615
- worker: LiveStoreWorker,
616
- sharedWorker: LiveStoreSharedWorker,
617
- })
618
-
619
- export const useAppStore = () =>
620
- useStore({
621
- storeId: 'app-root',
622
- schema,
623
- adapter,
624
- batchUpdates,
625
- })
626
- ```
@@ -1,3 +0,0 @@
1
- # Solid
2
-
3
- TODO