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