@livestore/livestore 0.4.0-dev.21 → 0.4.0-dev.22
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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/effect/LiveStore.d.ts +123 -2
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +195 -1
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/effect/mod.d.ts +1 -1
- package/dist/effect/mod.d.ts.map +1 -1
- package/dist/effect/mod.js +3 -1
- package/dist/effect/mod.js.map +1 -1
- package/dist/mod.d.ts +1 -0
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +1 -0
- package/dist/mod.js.map +1 -1
- package/dist/store/StoreRegistry.d.ts +190 -0
- package/dist/store/StoreRegistry.d.ts.map +1 -0
- package/dist/store/StoreRegistry.js +244 -0
- package/dist/store/StoreRegistry.js.map +1 -0
- package/dist/store/StoreRegistry.test.d.ts +2 -0
- package/dist/store/StoreRegistry.test.d.ts.map +1 -0
- package/dist/store/StoreRegistry.test.js +380 -0
- package/dist/store/StoreRegistry.test.js.map +1 -0
- package/dist/store/create-store.d.ts +50 -4
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +19 -0
- package/dist/store/create-store.js.map +1 -1
- package/dist/store/devtools.d.ts.map +1 -1
- package/dist/store/devtools.js +13 -0
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-types.d.ts +10 -25
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store-types.js.map +1 -1
- package/dist/store/store.d.ts +23 -6
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +20 -2
- package/dist/store/store.js.map +1 -1
- package/docs/building-with-livestore/complex-ui-state/index.md +0 -2
- package/docs/building-with-livestore/crud/index.md +0 -2
- package/docs/building-with-livestore/data-modeling/index.md +29 -0
- package/docs/building-with-livestore/examples/todo-workspaces/index.md +0 -6
- package/docs/building-with-livestore/opentelemetry/index.md +25 -6
- package/docs/building-with-livestore/rules-for-ai-agents/index.md +2 -2
- package/docs/building-with-livestore/state/sql-queries/index.md +22 -0
- package/docs/building-with-livestore/state/sqlite-schema/index.md +2 -2
- package/docs/building-with-livestore/store/index.md +344 -0
- package/docs/framework-integrations/react-integration/index.md +380 -361
- package/docs/framework-integrations/vue-integration/index.md +2 -2
- package/docs/getting-started/expo/index.md +189 -43
- package/docs/getting-started/react-web/index.md +77 -24
- package/docs/getting-started/vue/index.md +3 -3
- package/docs/index.md +1 -2
- package/docs/llms.txt +0 -1
- package/docs/misc/troubleshooting/index.md +3 -3
- package/docs/overview/how-livestore-works/index.md +1 -1
- package/docs/overview/introduction/index.md +409 -1
- package/docs/overview/why-livestore/index.md +108 -2
- package/docs/patterns/auth/index.md +185 -34
- package/docs/patterns/effect/index.md +11 -1
- package/docs/patterns/storybook/index.md +43 -26
- package/docs/platform-adapters/expo-adapter/index.md +36 -19
- package/docs/platform-adapters/web-adapter/index.md +71 -2
- package/docs/tutorial/1-setup-starter-project/index.md +5 -5
- package/docs/tutorial/3-read-and-write-todos-via-livestore/index.md +54 -35
- package/docs/tutorial/5-expand-business-logic/index.md +1 -1
- package/docs/tutorial/6-persist-ui-state/index.md +12 -12
- package/package.json +6 -6
- package/src/effect/LiveStore.ts +385 -3
- package/src/effect/mod.ts +13 -1
- package/src/mod.ts +1 -0
- package/src/store/StoreRegistry.test.ts +516 -0
- package/src/store/StoreRegistry.ts +393 -0
- package/src/store/create-store.ts +50 -4
- package/src/store/devtools.ts +15 -0
- package/src/store/store-types.ts +17 -5
- package/src/store/store.ts +25 -5
- package/docs/building-with-livestore/examples/index.md +0 -30
|
@@ -110,7 +110,7 @@ Here's a quick summary of the code:
|
|
|
110
110
|
The `tables`, `events` and `materializers` are packaged up into a `schema` object that's needed in the parts of your app where you interact with LiveStore.
|
|
111
111
|
|
|
112
112
|
:::note[Versioning events and materializers]
|
|
113
|
-
You may have noticed that event and materializer names are prefixed with `v1`.
|
|
113
|
+
You may have noticed that event and materializer names are prefixed with `v1`.
|
|
114
114
|
|
|
115
115
|
It's good practice in LiveStore to version your events and materializers to ensure future compatibility between them as your app evolves.
|
|
116
116
|
:::
|
|
@@ -120,9 +120,10 @@ It's good practice in LiveStore to version your events and materializers to ensu
|
|
|
120
120
|
To now "connect" LiveStore with your React app, you need to:
|
|
121
121
|
|
|
122
122
|
1. Create the [LiveStore web worker](/platform-adapters/web-adapter#web-worker) that is responsible for the logic of persisting data on your file system.
|
|
123
|
-
2. Create a LiveStore [adapter](/platform-adapters/web-adapter) that enables
|
|
124
|
-
3.
|
|
125
|
-
4.
|
|
123
|
+
2. Create a LiveStore [adapter](/platform-adapters/web-adapter) that enables persistence with local SQLite via [OPFS](https://web.dev/articles/origin-private-file-system).
|
|
124
|
+
3. Create a store configuration file that exports a custom hook wrapping [`useStore()`](/framework-integrations/react-integration#1-configure-the-store).
|
|
125
|
+
4. Create and provide a `StoreRegistry` with [`<StoreRegistryProvider>`](/framework-integrations/react-integration#2-set-up-the-registry) in `main.tsx`.
|
|
126
|
+
5. Update your Vite Config to work with LiveStore.
|
|
126
127
|
|
|
127
128
|
Let's get started!
|
|
128
129
|
|
|
@@ -145,9 +146,13 @@ This is boilerplate code that you'll almost never need to touch. (In this tutori
|
|
|
145
146
|
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](https://vite.dev/guide/features.html#web-workers).
|
|
146
147
|
:::
|
|
147
148
|
|
|
148
|
-
Next,
|
|
149
|
+
Next, create a `store.ts` file that defines your store configuration and a `useAppStore()` hook:
|
|
149
150
|
|
|
150
|
-
```
|
|
151
|
+
```bash
|
|
152
|
+
touch src/livestore/store.ts
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
```ts title="src/livestore/store.ts"
|
|
151
156
|
|
|
152
157
|
const adapter = makePersistedAdapter({
|
|
153
158
|
storage: { type: 'opfs' },
|
|
@@ -155,23 +160,37 @@ const adapter = makePersistedAdapter({
|
|
|
155
160
|
sharedWorker: LiveStoreSharedWorker,
|
|
156
161
|
})
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
163
|
+
export const useAppStore = () =>
|
|
164
|
+
useStore({
|
|
165
|
+
storeId: 'todo-db-tutorial',
|
|
166
|
+
schema,
|
|
167
|
+
adapter,
|
|
168
|
+
batchUpdates,
|
|
169
|
+
})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Then, update `main.tsx` to wrap your `<App>` component inside the `<StoreRegistryProvider>`:
|
|
173
|
+
|
|
174
|
+
```tsx title="src/main.tsx"
|
|
175
|
+
|
|
176
|
+
const Root = () => {
|
|
177
|
+
const [storeRegistry] = useState(() => new StoreRegistry())
|
|
178
|
+
return (
|
|
179
|
+
<Suspense fallback={<div>Loading LiveStore...</div>}>
|
|
180
|
+
<StoreRegistryProvider storeRegistry={storeRegistry}>
|
|
181
|
+
<App />
|
|
182
|
+
</StoreRegistryProvider>
|
|
183
|
+
</Suspense>
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
createRoot(document.getElementById('root')!).render(<Root />)
|
|
169
188
|
```
|
|
170
189
|
|
|
171
190
|
:::note[So many "workers" ...]
|
|
172
191
|
There's some ambiguity with the "worker" terminology in this tutorial. In general, there are three different kinds of Workers at play.
|
|
173
192
|
- The **LiveStore web worker** (`LiveStoreWorker`); this is the Worker you defined in `livestore.worker.ts`. Technically, this is a _browser_ web worker, i.e. a separate JavaScript thread that runs in the browser, isolated from the main UI thread.
|
|
174
|
-
- The **LiveStore shared web worker** (`LiveStoreSharedWorker`); you just imported it from `@livestore/adapter-web/shared-worker`, also a _browser_ web worker. It's actually more of an _implementation detail_ but currently required to be exposed, so that the setup works with Vite.
|
|
193
|
+
- The **LiveStore shared web worker** (`LiveStoreSharedWorker`); you just imported it from `@livestore/adapter-web/shared-worker`, also a _browser_ web worker. It's actually more of an _implementation detail_ but currently required to be exposed, so that the setup works with Vite.
|
|
175
194
|
- The **Cloudflare Worker** that will automatically sync the data in the background; you'll set this up in the next step.
|
|
176
195
|
|
|
177
196
|
Note that both the LiveStore web worker and the LiveStore Shared web worker are regular [web workers,](https://www.dhiwise.com/post/web-workers-vs-service-workers-in-javascript#what-are-web-workers-) not [service workers](https://www.dhiwise.com/post/web-workers-vs-service-workers-in-javascript#what-are-service-workers-)!
|
|
@@ -181,7 +200,7 @@ Here's how to think about the workers in the context of browser tabs (or windows
|
|
|
181
200
|
```
|
|
182
201
|
Tab 1 ──┐
|
|
183
202
|
Tab 2 ──┼──→ Shared Worker (tab coordination) ──→ Web Worker (persistence)
|
|
184
|
-
Tab 3 ──┘
|
|
203
|
+
Tab 3 ──┘
|
|
185
204
|
```
|
|
186
205
|
|
|
187
206
|
:::
|
|
@@ -202,7 +221,7 @@ export default defineConfig({
|
|
|
202
221
|
})
|
|
203
222
|
```
|
|
204
223
|
|
|
205
|
-
Now, your app is set up to start reading and writing data in a local SQLite database via LiveStore. If you run the app via `pnpm dev`, you'll briefly see a loading screen (
|
|
224
|
+
Now, your app is set up to start reading and writing data in a local SQLite database via LiveStore. If you run the app via `pnpm dev`, you'll briefly see a loading screen (the Suspense fallback) before the todo list UI from the previous steps will appear again:
|
|
206
225
|
|
|
207
226
|

|
|
208
227
|
|
|
@@ -210,16 +229,16 @@ The todos themselves are not yet persisted because you haven't modified the logi
|
|
|
210
229
|
|
|
211
230
|
## Read and write todos from local SQLite via LiveStore
|
|
212
231
|
|
|
213
|
-
The current version of the app still stores the todos _in-memory_ via the [state](https://react.dev/learn/state-a-components-memory) of your
|
|
232
|
+
The current version of the app still stores the todos _in-memory_ via the [state](https://react.dev/learn/state-a-components-memory) of your `<App>` component. However, with the basic LiveStore setup in place, you can now move to persisting your todos inside SQLite via LiveStore!
|
|
214
233
|
|
|
215
234
|
In order to read todos, you need to define a LiveStore [query](/building-with-livestore/state/sql-queries). LiveStore queries are _live_ or _reactive_, meaning they will automatically update your UI components when the underlying data changes.
|
|
216
235
|
|
|
217
|
-
Here's how you can define and use a query to fetch all todos from the local SQLite database using LiveStore inside the
|
|
236
|
+
Here's how you can define and use a query to fetch all todos from the local SQLite database using LiveStore inside the `<App>` component (you don't need to update your code yet, you'll get the full snippet at the end of this section):
|
|
218
237
|
|
|
219
238
|
```diff title="src/App.tsx" lang="ts"
|
|
220
239
|
function App() {
|
|
221
240
|
|
|
222
|
-
+ const
|
|
241
|
+
+ const store = useAppStore()
|
|
223
242
|
|
|
224
243
|
// The trailing `$` is a convention to indicate that this
|
|
225
244
|
// variable is a "live query".
|
|
@@ -231,7 +250,7 @@ function App() {
|
|
|
231
250
|
+ const todos = store.useQuery(todos$)
|
|
232
251
|
- const [todos, setTodos] = useState<Todo[]>([])
|
|
233
252
|
|
|
234
|
-
// ... remaining code for the
|
|
253
|
+
// ... remaining code for the `<App>` component
|
|
235
254
|
}
|
|
236
255
|
```
|
|
237
256
|
|
|
@@ -242,13 +261,13 @@ This was only half of the job though: Right now your code would throw a type err
|
|
|
242
261
|
```diff title="src/App.tsx" lang="ts"
|
|
243
262
|
function App() {
|
|
244
263
|
|
|
245
|
-
const
|
|
264
|
+
const store = useAppStore()
|
|
246
265
|
|
|
247
266
|
const todos$ = queryDb(() => tables.todos.select())
|
|
248
267
|
|
|
249
268
|
const todos = store.useQuery(todos$)
|
|
250
269
|
|
|
251
|
-
// Commit an event to the `store` instead of
|
|
270
|
+
// Commit an event to the `store` instead of
|
|
252
271
|
// updating local React state.
|
|
253
272
|
const addTodo = () => {
|
|
254
273
|
+ store.commit(
|
|
@@ -257,7 +276,7 @@ function App() {
|
|
|
257
276
|
setInput('')
|
|
258
277
|
}
|
|
259
278
|
|
|
260
|
-
// Commit an event to the `store` instead of
|
|
279
|
+
// Commit an event to the `store` instead of
|
|
261
280
|
// updating local React state.
|
|
262
281
|
const deleteTodo = (id: number) => {
|
|
263
282
|
+ store.commit(
|
|
@@ -265,7 +284,7 @@ function App() {
|
|
|
265
284
|
+ )
|
|
266
285
|
}
|
|
267
286
|
|
|
268
|
-
// ... remaining code for the
|
|
287
|
+
// ... remaining code for the `<App>` component
|
|
269
288
|
|
|
270
289
|
}
|
|
271
290
|
```
|
|
@@ -274,13 +293,13 @@ See how the data now will flow through the app _unidirectionally_ with this setu
|
|
|
274
293
|
|
|
275
294
|
Let's follow it from the first time the app is started:
|
|
276
295
|
|
|
277
|
-
1. The
|
|
296
|
+
1. The `<App>` component registers the `todos$` "live query" with the store.
|
|
278
297
|
1. The query fires initially; the returned `todos` array is empty.
|
|
279
|
-
1. The
|
|
298
|
+
1. The `<App>` component renders an empty list.
|
|
280
299
|
1. A user adds a `todo`; the `todoCreated` event is triggered and committed to the DB.
|
|
281
300
|
1. The `v1.TodoCreated` materializer is invoked and writes the data into the DB.
|
|
282
301
|
1. The `todos$` query fires again because the state of the DB changed; the returned `todos` array now contains the newly created todo.
|
|
283
|
-
1. The
|
|
302
|
+
1. The `<App>` component renders a single todo.
|
|
284
303
|
|
|
285
304
|
Now try it out! Here's the full code for `App.tsx` that you can copy and paste:
|
|
286
305
|
|
|
@@ -288,7 +307,7 @@ Now try it out! Here's the full code for `App.tsx` that you can copy and paste:
|
|
|
288
307
|
|
|
289
308
|
function App() {
|
|
290
309
|
|
|
291
|
-
const
|
|
310
|
+
const store = useAppStore()
|
|
292
311
|
|
|
293
312
|
const todos$ = queryDb(() => tables.todos.select())
|
|
294
313
|
const todos = store.useQuery(todos$)
|
|
@@ -435,7 +454,7 @@ Here's a little GIF demonstrating the current state of the live updates via brow
|
|
|
435
454
|
|
|
436
455
|

|
|
437
456
|
|
|
438
|
-
- When a change is made in one Chrome window, it is automatically reflected in the other Chrome window.
|
|
457
|
+
- When a change is made in one Chrome window, it is automatically reflected in the other Chrome window.
|
|
439
458
|
- Similarly, when a change is made in one Safari window, it is automatically reflected in the other Safari window.
|
|
440
459
|
|
|
441
460
|
To recap, here's a visualization of the data flow in the app at this point:
|
|
@@ -444,7 +463,7 @@ To recap, here's a visualization of the data flow in the app at this point:
|
|
|
444
463
|
|
|
445
464
|
## Set up LiveStore DevTools
|
|
446
465
|
|
|
447
|
-
You may have wondered: "If the data is persisted, _where_ is it?". If the data is somewhere on your file system, you _should_ be able to spin up a database viewer of your choice and inspect the local SQLite DB file.
|
|
466
|
+
You may have wondered: "If the data is persisted, _where_ is it?". If the data is somewhere on your file system, you _should_ be able to spin up a database viewer of your choice and inspect the local SQLite DB file.
|
|
448
467
|
|
|
449
468
|
Unfortunately, that's not how OPFS works. While the SQLite files do exist _somewhere_ on your file system, they are hidden in the browser's internals and not easily accessible.
|
|
450
469
|
|
|
@@ -452,7 +471,7 @@ That being said, there is a convenient way how you can actually see the data on
|
|
|
452
471
|
|
|
453
472
|
:::note[LiveStore DevTools are a sponsor-only feature]
|
|
454
473
|
|
|
455
|
-
Our goal is to grow the project in a [sustainable](/sustainable-open-source/sponsoring#goal-sustainable-open-source) way (e.g. not rely on VC funding), that's why DevTools are currently a [sponsor-only](/sustainable-open-source/sponsoring) feature.
|
|
474
|
+
Our goal is to grow the project in a [sustainable](/sustainable-open-source/sponsoring#goal-sustainable-open-source) way (e.g. not rely on VC funding), that's why DevTools are currently a [sponsor-only](/sustainable-open-source/sponsoring) feature.
|
|
456
475
|
|
|
457
476
|
That being said, we still include them in this tutorial since you'll be able to use them without sponsorship for one week.
|
|
458
477
|
|
|
@@ -5,9 +5,9 @@ As you saw in the beginning of the tutorial, the state of an application is typi
|
|
|
5
5
|
- **App state**: State that represents the _application data_ a user needs to achieve their goals with your app. In your current case, that's the list of todos. App state _typically_ lives in the Cloud somewhere (in traditional apps, the Cloud is the source of truth for it; in local-first apps, the data is stored locally and backed up in the Cloud).
|
|
6
6
|
- **UI state**: UI state that is only relevant for a particular browser session.
|
|
7
7
|
|
|
8
|
-
Many websites have the problem of "losing UI state" on browser refreshes. This can be incredibly frustrating for users, especially when they've already invested a lot of time getting to a certain point in an app (e.g. filling out a form). Then, the site reloads for some reason and they have to start over!
|
|
8
|
+
Many websites have the problem of "losing UI state" on browser refreshes. This can be incredibly frustrating for users, especially when they've already invested a lot of time getting to a certain point in an app (e.g. filling out a form). Then, the site reloads for some reason and they have to start over!
|
|
9
9
|
|
|
10
|
-
With LiveStore, this problem is easily solved: It allows you to persist _UI state_ (e.g. form inputs, active tabs, custom UI elements, and pretty much anything you'd otherwise manage via `React.useState`). This means users can always pick up exactly where they left off.
|
|
10
|
+
With LiveStore, this problem is easily solved: It allows you to persist _UI state_ (e.g. form inputs, active tabs, custom UI elements, and pretty much anything you'd otherwise manage via `React.useState()`). This means users can always pick up exactly where they left off.
|
|
11
11
|
|
|
12
12
|
## Add another UI element
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@ First, update `App.tsx` to look as follows:
|
|
|
17
17
|
|
|
18
18
|
function App() {
|
|
19
19
|
|
|
20
|
-
const
|
|
20
|
+
const store = useAppStore()
|
|
21
21
|
|
|
22
22
|
const todos$ = queryDb(() => tables.todos.select())
|
|
23
23
|
const todos = store.useQuery(todos$)
|
|
@@ -175,7 +175,7 @@ export const tables = {
|
|
|
175
175
|
On this table, you define:
|
|
176
176
|
|
|
177
177
|
- A name for this client document.
|
|
178
|
-
- The structure of the client document via `schema`; in your case:
|
|
178
|
+
- The structure of the client document via `schema`; in your case:
|
|
179
179
|
- The current state of the `input` text field for adding a new todo.
|
|
180
180
|
- The `filter` that'll be used to filter the todos according to their `completed` status.
|
|
181
181
|
- Default values for this client document.
|
|
@@ -209,9 +209,9 @@ Here, both the event definition and materializer are automatically derived from
|
|
|
209
209
|
|
|
210
210
|
## Implement local state with LiveStore
|
|
211
211
|
|
|
212
|
-
In this step, you need to add the local state for the tabbed UI element to the
|
|
212
|
+
In this step, you need to add the local state for the tabbed UI element to the `<App>` component. Additionally, you're going to replace the `useState()` hook that you currently use for the `input` state with LiveStore's approach as well.
|
|
213
213
|
|
|
214
|
-
Replace the `useState` usage for `input` and `filter` with LiveStore's [`useClientDocument`](/framework-integrations/react-integration#
|
|
214
|
+
Replace the `useState()` usage for `input` and `filter` with LiveStore's [`useClientDocument()`](/framework-integrations/react-integration#storeuseclientdocumenttable-id-options):
|
|
215
215
|
|
|
216
216
|
```diff title="src/App.tsx" lang="tsx"
|
|
217
217
|
+const [{ input, filter }, setUiState, , uiState$] = store.useClientDocument(tables.uiState)
|
|
@@ -224,16 +224,16 @@ Replace the `useState` usage for `input` and `filter` with LiveStore's [`useClie
|
|
|
224
224
|
-const updatedFilter = (filter: Filter) => store.commit(events.uiStateSet({ filter }))
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
-
Don't forget to update the imports to include the `Filter` type and drop `useState`:
|
|
227
|
+
Don't forget to update the imports to include the `Filter` type and drop `useState()`:
|
|
228
228
|
|
|
229
229
|
```diff title="src/App.tsx" lang="tsx"
|
|
230
230
|
-import { useState } from 'react'
|
|
231
231
|
|
|
232
232
|
```
|
|
233
233
|
|
|
234
|
-
`useClientDocument` persists the UI state inside LiveStore while giving you a React-friendly setter function similar to `useState`.
|
|
234
|
+
`useClientDocument()` persists the UI state inside LiveStore while giving you a React-friendly setter function similar to `useState()`.
|
|
235
235
|
|
|
236
|
-
Since you've renamed the functions to update the values of `input` and `filter` you need to adjust the parts of the
|
|
236
|
+
Since you've renamed the functions to update the values of `input` and `filter` you need to adjust the parts of the `<App>` component where they are used:
|
|
237
237
|
|
|
238
238
|
- `setInput` → `updatedInput`
|
|
239
239
|
- `setFilter` → `updatedFilter`
|
|
@@ -276,15 +276,15 @@ const todos$ = queryDb((
|
|
|
276
276
|
const todos = store.useQuery(todos$)
|
|
277
277
|
```
|
|
278
278
|
|
|
279
|
-
Here, `uiState$` comes from `useClientDocument`, ensuring that the todos query automatically reacts whenever the persisted UI state changes.
|
|
279
|
+
Here, `uiState$` comes from `useClientDocument()`, ensuring that the todos query automatically reacts whenever the persisted UI state changes.
|
|
280
280
|
|
|
281
|
-
This is the final code for the
|
|
281
|
+
This is the final code for the `<App>` component:
|
|
282
282
|
|
|
283
283
|
```tsx title="src/App.tsx"
|
|
284
284
|
|
|
285
285
|
function App() {
|
|
286
286
|
|
|
287
|
-
const
|
|
287
|
+
const store = useAppStore()
|
|
288
288
|
|
|
289
289
|
const [{ input, filter }, setUiState, , uiState$] = store.useClientDocument(tables.uiState)
|
|
290
290
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livestore/livestore",
|
|
3
|
-
"version": "0.4.0-dev.
|
|
3
|
+
"version": "0.4.0-dev.22",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"exports": {
|
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@opentelemetry/api": "1.9.0",
|
|
14
|
-
"@livestore/common": "0.4.0-dev.
|
|
15
|
-
"@livestore/utils": "0.4.0-dev.
|
|
14
|
+
"@livestore/common": "0.4.0-dev.22",
|
|
15
|
+
"@livestore/utils": "0.4.0-dev.22"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@opentelemetry/sdk-trace-base": "2.0
|
|
18
|
+
"@opentelemetry/sdk-trace-base": "2.2.0",
|
|
19
19
|
"jsdom": "^26.1.0",
|
|
20
20
|
"typescript": "5.9.2",
|
|
21
21
|
"vite": "7.2.4",
|
|
22
22
|
"vitest": "3.2.4",
|
|
23
|
-
"@livestore/
|
|
24
|
-
"@livestore/
|
|
23
|
+
"@livestore/utils-dev": "0.4.0-dev.22",
|
|
24
|
+
"@livestore/adapter-web": "0.4.0-dev.22"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"package.json",
|