@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,115 +0,0 @@
1
- # Node
2
-
3
- ## Minimal example
4
-
5
- ## `getting-started/node/minimal-example.ts`
6
-
7
- ```ts filename="getting-started/node/minimal-example.ts"
8
- /** biome-ignore-all lint/correctness/noUnusedVariables: docs snippet keeps inline setup */
9
- // ---cut---
10
-
11
- const adapter = makeAdapter({
12
- storage: { type: 'fs' },
13
- // sync: { backend: makeWsSync({ url: 'ws://localhost:8787' }) },
14
- })
15
-
16
- const main = async () => {
17
- const store = await createStorePromise({ adapter, schema, storeId: 'demo-store' })
18
-
19
- const todos = store.query(tables.todos)
20
- console.log(todos)
21
- }
22
-
23
- main().catch(() => undefined)
24
- ```
25
-
26
- ### `getting-started/node/livestore/schema.ts`
27
-
28
- ```ts filename="getting-started/node/livestore/schema.ts"
29
-
30
- export const tables = {
31
- todos: State.SQLite.table({
32
- name: 'todos',
33
- columns: {
34
- id: State.SQLite.text({ primaryKey: true }),
35
- text: State.SQLite.text(),
36
- completed: State.SQLite.boolean({ default: false }),
37
- },
38
- }),
39
- } as const
40
-
41
- export const events = {
42
- todoCreated: Events.synced({
43
- name: 'v1.TodoCreated',
44
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
45
- }),
46
- } as const
47
-
48
- const materializers = State.SQLite.materializers(events, {
49
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
50
- tables.todos.insert({ id, text, completed: false }),
51
- ),
52
- })
53
-
54
- const state = State.SQLite.makeState({ tables, materializers })
55
-
56
- export const schema = makeSchema({ events, state })
57
- ```
58
-
59
- ### Option A: Quick start
60
-
61
- For a quick start, we recommend using our template app following the steps below.
62
-
63
- {/* For existing projects, see [Existing project setup](#existing-project-setup). */}
64
-
65
- <Steps>
66
-
67
- 1. **Set up project from template**
68
-
69
- <Tabs syncKey="package-manager">
70
- <TabItem label="bun">
71
- <Code code={makeCreate('node-todomvc-sync-cf', 'bunx')} lang="sh" />
72
- </TabItem>
73
- <TabItem label="pnpm">
74
- <Code code={makeCreate('node-todomvc-sync-cf', 'pnpm dlx')} lang="sh" />
75
- </TabItem>
76
- <TabItem label="npm">
77
- <Code code={makeCreate('node-todomvc-sync-cf', 'npx')} lang="sh" />
78
- </TabItem>
79
- </Tabs>
80
-
81
- Replace `livestore-app` with your desired app name.
82
-
83
- 2. **Install dependencies**
84
-
85
- 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).
86
-
87
- <Tabs syncKey="package-manager">
88
- <TabItem label="bun">
89
- <Code code="bun install" lang="sh" />
90
- </TabItem>
91
- <TabItem label="pnpm">
92
- <Code code="pnpm install" lang="sh" />
93
- </TabItem>
94
- <TabItem label="npm">
95
- <Code code="npm install" lang="sh" />
96
- </TabItem>
97
- </Tabs>
98
-
99
- Pro tip: You can use [direnv](https://direnv.net/) to manage environment variables.
100
-
101
- 3. **Run dev environment**
102
-
103
- <Tabs syncKey="package-manager">
104
- <TabItem label="bun">
105
- <Code code="bun start" lang="sh" />
106
- </TabItem>
107
- <TabItem label="pnpm">
108
- <Code code="pnpm start" lang="sh" />
109
- </TabItem>
110
- <TabItem label="npm">
111
- <Code code="npm run start" lang="sh" />
112
- </TabItem>
113
- </Tabs>
114
-
115
- </Steps>
@@ -1,573 +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
- ## Add the LiveStore provider
254
-
255
- To make the LiveStore available throughout your app, wrap your app's root component with the `LiveStoreProvider` component from `@livestore/react`. This provider manages your app's data store, loading, and error states.
256
-
257
- Here's an example:
258
-
259
- ## `getting-started/react-web/Root.tsx`
260
-
261
- ```tsx filename="getting-started/react-web/Root.tsx"
262
-
263
- const adapter = makePersistedAdapter({
264
- storage: { type: 'opfs' },
265
- worker: LiveStoreWorker,
266
- sharedWorker: LiveStoreSharedWorker,
267
- })
268
-
269
- export const App: React.FC = () => (
270
- <LiveStoreProvider
271
- schema={schema}
272
- adapter={adapter}
273
- renderLoading={(_) => <div>Loading LiveStore ({_.stage})...</div>}
274
- batchUpdates={batchUpdates}
275
- storeId="my-app-store"
276
- >
277
- <div className="todoapp">{/* Your app components go here */}</div>
278
- </LiveStoreProvider>
279
- )
280
- ```
281
-
282
- ### `getting-started/react-web/livestore/schema.ts`
283
-
284
- ```ts filename="getting-started/react-web/livestore/schema.ts"
285
-
286
- // You can model your state as SQLite tables (https://docs.livestore.dev/reference/state/sqlite-schema)
287
- export const tables = {
288
- todos: State.SQLite.table({
289
- name: 'todos',
290
- columns: {
291
- id: State.SQLite.text({ primaryKey: true }),
292
- text: State.SQLite.text({ default: '' }),
293
- completed: State.SQLite.boolean({ default: false }),
294
- deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
295
- },
296
- }),
297
- // Client documents can be used for local-only state (e.g. form inputs)
298
- uiState: State.SQLite.clientDocument({
299
- name: 'uiState',
300
- schema: Schema.Struct({ newTodoText: Schema.String, filter: Schema.Literal('all', 'active', 'completed') }),
301
- default: { id: SessionIdSymbol, value: { newTodoText: '', filter: 'all' } },
302
- }),
303
- }
304
-
305
- // Events describe data changes (https://docs.livestore.dev/reference/events)
306
- export const events = {
307
- todoCreated: Events.synced({
308
- name: 'v1.TodoCreated',
309
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
310
- }),
311
- todoCompleted: Events.synced({
312
- name: 'v1.TodoCompleted',
313
- schema: Schema.Struct({ id: Schema.String }),
314
- }),
315
- todoUncompleted: Events.synced({
316
- name: 'v1.TodoUncompleted',
317
- schema: Schema.Struct({ id: Schema.String }),
318
- }),
319
- todoDeleted: Events.synced({
320
- name: 'v1.TodoDeleted',
321
- schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
322
- }),
323
- todoClearedCompleted: Events.synced({
324
- name: 'v1.TodoClearedCompleted',
325
- schema: Schema.Struct({ deletedAt: Schema.Date }),
326
- }),
327
- uiStateSet: tables.uiState.set,
328
- }
329
-
330
- // Materializers are used to map events to state (https://docs.livestore.dev/reference/state/materializers)
331
- const materializers = State.SQLite.materializers(events, {
332
- 'v1.TodoCreated': ({ id, text }) => tables.todos.insert({ id, text, completed: false }),
333
- 'v1.TodoCompleted': ({ id }) => tables.todos.update({ completed: true }).where({ id }),
334
- 'v1.TodoUncompleted': ({ id }) => tables.todos.update({ completed: false }).where({ id }),
335
- 'v1.TodoDeleted': ({ id, deletedAt }) => tables.todos.update({ deletedAt }).where({ id }),
336
- 'v1.TodoClearedCompleted': ({ deletedAt }) => tables.todos.update({ deletedAt }).where({ completed: true }),
337
- })
338
-
339
- const state = State.SQLite.makeState({ tables, materializers })
340
-
341
- export const schema = makeSchema({ events, state })
342
- ```
343
-
344
- ### Commit events
345
-
346
- After wrapping your app with the `LiveStoreProvider`, you can use the `useStore` hook from any component to commit events.
347
-
348
- Here's an example:
349
-
350
- ## `getting-started/react-web/Header.tsx`
351
-
352
- ```tsx filename="getting-started/react-web/Header.tsx"
353
-
354
- const uiState$ = queryDb(tables.uiState.get(), { label: 'uiState' })
355
-
356
- export const Header: React.FC = () => {
357
- const { store } = useStore()
358
- const { newTodoText } = store.useQuery(uiState$)
359
-
360
- const updateNewTodoText = (text: string) => store.commit(events.uiStateSet({ newTodoText: text }))
361
-
362
- const createTodo = () =>
363
- store.commit(
364
- events.todoCreated({ id: crypto.randomUUID(), text: newTodoText }),
365
- events.uiStateSet({ newTodoText: '' }),
366
- )
367
-
368
- return (
369
- <header className="header">
370
- <h1>TodoMVC</h1>
371
- <input
372
- className="new-todo"
373
- placeholder="What needs to be done?"
374
- value={newTodoText}
375
- onChange={(e) => updateNewTodoText(e.target.value)}
376
- onKeyDown={(e) => {
377
- if (e.key === 'Enter') {
378
- createTodo()
379
- }
380
- }}
381
- />
382
- </header>
383
- )
384
- }
385
- ```
386
-
387
- ### `getting-started/react-web/livestore/schema.ts`
388
-
389
- ```ts filename="getting-started/react-web/livestore/schema.ts"
390
-
391
- // You can model your state as SQLite tables (https://docs.livestore.dev/reference/state/sqlite-schema)
392
- export const tables = {
393
- todos: State.SQLite.table({
394
- name: 'todos',
395
- columns: {
396
- id: State.SQLite.text({ primaryKey: true }),
397
- text: State.SQLite.text({ default: '' }),
398
- completed: State.SQLite.boolean({ default: false }),
399
- deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
400
- },
401
- }),
402
- // Client documents can be used for local-only state (e.g. form inputs)
403
- uiState: State.SQLite.clientDocument({
404
- name: 'uiState',
405
- schema: Schema.Struct({ newTodoText: Schema.String, filter: Schema.Literal('all', 'active', 'completed') }),
406
- default: { id: SessionIdSymbol, value: { newTodoText: '', filter: 'all' } },
407
- }),
408
- }
409
-
410
- // Events describe data changes (https://docs.livestore.dev/reference/events)
411
- export const events = {
412
- todoCreated: Events.synced({
413
- name: 'v1.TodoCreated',
414
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
415
- }),
416
- todoCompleted: Events.synced({
417
- name: 'v1.TodoCompleted',
418
- schema: Schema.Struct({ id: Schema.String }),
419
- }),
420
- todoUncompleted: Events.synced({
421
- name: 'v1.TodoUncompleted',
422
- schema: Schema.Struct({ id: Schema.String }),
423
- }),
424
- todoDeleted: Events.synced({
425
- name: 'v1.TodoDeleted',
426
- schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
427
- }),
428
- todoClearedCompleted: Events.synced({
429
- name: 'v1.TodoClearedCompleted',
430
- schema: Schema.Struct({ deletedAt: Schema.Date }),
431
- }),
432
- uiStateSet: tables.uiState.set,
433
- }
434
-
435
- // Materializers are used to map events to state (https://docs.livestore.dev/reference/state/materializers)
436
- const materializers = State.SQLite.materializers(events, {
437
- 'v1.TodoCreated': ({ id, text }) => tables.todos.insert({ id, text, completed: false }),
438
- 'v1.TodoCompleted': ({ id }) => tables.todos.update({ completed: true }).where({ id }),
439
- 'v1.TodoUncompleted': ({ id }) => tables.todos.update({ completed: false }).where({ id }),
440
- 'v1.TodoDeleted': ({ id, deletedAt }) => tables.todos.update({ deletedAt }).where({ id }),
441
- 'v1.TodoClearedCompleted': ({ deletedAt }) => tables.todos.update({ deletedAt }).where({ completed: true }),
442
- })
443
-
444
- const state = State.SQLite.makeState({ tables, materializers })
445
-
446
- export const schema = makeSchema({ events, state })
447
- ```
448
-
449
- ## Queries
450
-
451
- To retrieve data from the database, first define a query using `queryDb` from `@livestore/livestore`. Then, execute the query with the `useQuery` hook from `@livestore/react`.
452
-
453
- Consider abstracting queries into a separate file to keep your code organized, though you can also define them directly within components if preferred.
454
-
455
- Here's an example:
456
-
457
- ## `getting-started/react-web/MainSection.tsx`
458
-
459
- ```tsx filename="getting-started/react-web/MainSection.tsx"
460
-
461
- const uiState$ = queryDb(tables.uiState.get(), { label: 'uiState' })
462
-
463
- const visibleTodos$ = queryDb(
464
- (get) => {
465
- const { filter } = get(uiState$)
466
- return tables.todos.where({
467
- deletedAt: null,
468
- completed: filter === 'all' ? undefined : filter === 'completed',
469
- })
470
- },
471
- { label: 'visibleTodos' },
472
- )
473
-
474
- export const MainSection: React.FC = () => {
475
- const { store } = useStore()
476
-
477
- const toggleTodo = React.useCallback(
478
- ({ id, completed }: typeof tables.todos.Type) =>
479
- store.commit(completed ? events.todoUncompleted({ id }) : events.todoCompleted({ id })),
480
- [store],
481
- )
482
-
483
- const visibleTodos = store.useQuery(visibleTodos$)
484
-
485
- return (
486
- <section className="main">
487
- <ul className="todo-list">
488
- {visibleTodos.map((todo) => (
489
- <li key={todo.id}>
490
- <div className="view">
491
- <input
492
- type="checkbox"
493
- className="toggle"
494
- id={`todo-${todo.id}`}
495
- checked={todo.completed}
496
- onChange={() => toggleTodo(todo)}
497
- />
498
- <label htmlFor={`todo-${todo.id}`}>{todo.text}</label>
499
- <button
500
- type="button"
501
- className="destroy"
502
- onClick={() => store.commit(events.todoDeleted({ id: todo.id, deletedAt: new Date() }))}
503
- />
504
- </div>
505
- </li>
506
- ))}
507
- </ul>
508
- </section>
509
- )
510
- }
511
- ```
512
-
513
- ### `getting-started/react-web/livestore/schema.ts`
514
-
515
- ```ts filename="getting-started/react-web/livestore/schema.ts"
516
-
517
- // You can model your state as SQLite tables (https://docs.livestore.dev/reference/state/sqlite-schema)
518
- export const tables = {
519
- todos: State.SQLite.table({
520
- name: 'todos',
521
- columns: {
522
- id: State.SQLite.text({ primaryKey: true }),
523
- text: State.SQLite.text({ default: '' }),
524
- completed: State.SQLite.boolean({ default: false }),
525
- deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
526
- },
527
- }),
528
- // Client documents can be used for local-only state (e.g. form inputs)
529
- uiState: State.SQLite.clientDocument({
530
- name: 'uiState',
531
- schema: Schema.Struct({ newTodoText: Schema.String, filter: Schema.Literal('all', 'active', 'completed') }),
532
- default: { id: SessionIdSymbol, value: { newTodoText: '', filter: 'all' } },
533
- }),
534
- }
535
-
536
- // Events describe data changes (https://docs.livestore.dev/reference/events)
537
- export const events = {
538
- todoCreated: Events.synced({
539
- name: 'v1.TodoCreated',
540
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
541
- }),
542
- todoCompleted: Events.synced({
543
- name: 'v1.TodoCompleted',
544
- schema: Schema.Struct({ id: Schema.String }),
545
- }),
546
- todoUncompleted: Events.synced({
547
- name: 'v1.TodoUncompleted',
548
- schema: Schema.Struct({ id: Schema.String }),
549
- }),
550
- todoDeleted: Events.synced({
551
- name: 'v1.TodoDeleted',
552
- schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
553
- }),
554
- todoClearedCompleted: Events.synced({
555
- name: 'v1.TodoClearedCompleted',
556
- schema: Schema.Struct({ deletedAt: Schema.Date }),
557
- }),
558
- uiStateSet: tables.uiState.set,
559
- }
560
-
561
- // Materializers are used to map events to state (https://docs.livestore.dev/reference/state/materializers)
562
- const materializers = State.SQLite.materializers(events, {
563
- 'v1.TodoCreated': ({ id, text }) => tables.todos.insert({ id, text, completed: false }),
564
- 'v1.TodoCompleted': ({ id }) => tables.todos.update({ completed: true }).where({ id }),
565
- 'v1.TodoUncompleted': ({ id }) => tables.todos.update({ completed: false }).where({ id }),
566
- 'v1.TodoDeleted': ({ id, deletedAt }) => tables.todos.update({ deletedAt }).where({ id }),
567
- 'v1.TodoClearedCompleted': ({ deletedAt }) => tables.todos.update({ deletedAt }).where({ completed: true }),
568
- })
569
-
570
- const state = State.SQLite.makeState({ tables, materializers })
571
-
572
- export const schema = makeSchema({ events, state })
573
- ```
@@ -1,3 +0,0 @@
1
- # Solid
2
-
3
- TODO