@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.
- 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 +130 -2
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +185 -6
- 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/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/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 +2 -1
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +1 -0
- 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 +215 -0
- package/dist/store/StoreRegistry.d.ts.map +1 -0
- package/dist/store/StoreRegistry.js +267 -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 +381 -0
- package/dist/store/StoreRegistry.test.js.map +1 -0
- package/dist/store/create-store.d.ts +56 -6
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +32 -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 +16 -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 +59 -9
- 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 +102 -6
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +148 -47
- 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 +59 -18
- 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 +381 -8
- package/src/effect/mod.ts +13 -1
- 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 +2 -0
- package/src/reactive.test.ts +3 -2
- package/src/reactive.ts +22 -23
- package/src/store/StoreRegistry.test.ts +540 -0
- package/src/store/StoreRegistry.ts +418 -0
- package/src/store/create-store.ts +76 -15
- package/src/store/devtools.ts +20 -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 +64 -13
- package/src/store/store.ts +197 -60
- 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 -5
- package/docs/building-with-livestore/crud/index.md +0 -5
- package/docs/building-with-livestore/data-modeling/index.md +0 -1
- 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/index.md +0 -30
- package/docs/building-with-livestore/examples/todo-workspaces/index.md +0 -891
- package/docs/building-with-livestore/examples/turnbased-game/index.md +0 -7
- package/docs/building-with-livestore/opentelemetry/index.md +0 -208
- 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 -72
- 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 -281
- 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 -918
- 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 -736
- package/docs/getting-started/node/index.md +0 -115
- package/docs/getting-started/react-web/index.md +0 -573
- package/docs/getting-started/solid/index.md +0 -3
- package/docs/getting-started/vue/index.md +0 -471
- package/docs/index.md +0 -209
- package/docs/llms.txt +0 -147
- 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 -5
- 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 -5
- 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 -226
- package/docs/patterns/effect/index.md +0 -1495
- 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 -192
- 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 -245
- 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 -218
- 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 -511
- 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,7 +0,0 @@
|
|
|
1
|
-
# Turn-based game
|
|
2
|
-
|
|
3
|
-
LiveStore is a great fit for turn-based games. In this guide we'll look at a simple turn-based game and how to model it in LiveStore.
|
|
4
|
-
|
|
5
|
-
General idea: Let server enforce the logic that each player only commits one action per turn.
|
|
6
|
-
|
|
7
|
-
TODO: write rest of guide
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
# OpenTelemetry
|
|
2
|
-
|
|
3
|
-
LiveStore has built-in support for OpenTelemetry.
|
|
4
|
-
|
|
5
|
-
## Usage with React
|
|
6
|
-
|
|
7
|
-
<Tabs>
|
|
8
|
-
<TabItem label="otel.ts">
|
|
9
|
-
|
|
10
|
-
## `reference/opentelemetry/otel.ts`
|
|
11
|
-
|
|
12
|
-
```ts filename="reference/opentelemetry/otel.ts"
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Configure a browser tracer that preserves parent/child spans across async work.
|
|
16
|
-
* Requires a zone.js runtime (e.g. provided by many frameworks) so the ZoneContextManager
|
|
17
|
-
* can keep context during timers, promises, and event callbacks.
|
|
18
|
-
*/
|
|
19
|
-
export const makeTracer = (serviceName: string) => {
|
|
20
|
-
const url = import.meta.env.VITE_OTEL_EXPORTER_OTLP_ENDPOINT as string | undefined
|
|
21
|
-
const provider = new WebTracerProvider({
|
|
22
|
-
spanProcessors: url ? [new SimpleSpanProcessor(new OTLPTraceExporter({ url: `${url}/v1/traces` }))] : [],
|
|
23
|
-
resource: resourceFromAttributes({ 'service.name': serviceName }),
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
provider.register({
|
|
27
|
-
contextManager: new ZoneContextManager(),
|
|
28
|
-
propagator: new W3CTraceContextPropagator(),
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
return provider.getTracer('livestore')
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export const tracer = makeTracer('my-app')
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
</TabItem>
|
|
38
|
-
<TabItem label="App.tsx">
|
|
39
|
-
|
|
40
|
-
## `reference/opentelemetry/app.tsx`
|
|
41
|
-
|
|
42
|
-
```tsx filename="reference/opentelemetry/app.tsx"
|
|
43
|
-
/** biome-ignore-all lint/correctness/noUnusedVariables: docs snippet */
|
|
44
|
-
|
|
45
|
-
const adapter = makeInMemoryAdapter()
|
|
46
|
-
|
|
47
|
-
// ---cut---
|
|
48
|
-
export const Root: FC<{ children: ReactNode }> = ({ children }) => (
|
|
49
|
-
<LiveStoreProvider schema={schema} adapter={adapter} batchUpdates={batchUpdates} otelOptions={{ tracer }}>
|
|
50
|
-
{children}
|
|
51
|
-
</LiveStoreProvider>
|
|
52
|
-
)
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### `reference/framework-integrations/react/schema.ts`
|
|
56
|
-
|
|
57
|
-
```ts filename="reference/framework-integrations/react/schema.ts"
|
|
58
|
-
|
|
59
|
-
export const tables = {
|
|
60
|
-
todos: State.SQLite.table({
|
|
61
|
-
name: 'todos',
|
|
62
|
-
columns: {
|
|
63
|
-
id: State.SQLite.text({ primaryKey: true }),
|
|
64
|
-
text: State.SQLite.text(),
|
|
65
|
-
completed: State.SQLite.boolean({ default: false }),
|
|
66
|
-
},
|
|
67
|
-
}),
|
|
68
|
-
uiState: State.SQLite.clientDocument({
|
|
69
|
-
name: 'UiState',
|
|
70
|
-
schema: Schema.Struct({ text: Schema.String }),
|
|
71
|
-
default: { value: { text: '' } },
|
|
72
|
-
}),
|
|
73
|
-
} as const
|
|
74
|
-
|
|
75
|
-
export const events = {
|
|
76
|
-
todoCreated: Events.synced({
|
|
77
|
-
name: 'v1.TodoCreated',
|
|
78
|
-
schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
|
|
79
|
-
}),
|
|
80
|
-
} as const
|
|
81
|
-
|
|
82
|
-
const materializers = State.SQLite.materializers(events, {
|
|
83
|
-
[events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
|
|
84
|
-
tables.todos.insert({ id, text, completed: false }),
|
|
85
|
-
),
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
const state = State.SQLite.makeState({ tables, materializers })
|
|
89
|
-
|
|
90
|
-
export const schema = makeSchema({ events, state })
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### `reference/opentelemetry/otel.ts`
|
|
94
|
-
|
|
95
|
-
```ts filename="reference/opentelemetry/otel.ts"
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Configure a browser tracer that preserves parent/child spans across async work.
|
|
99
|
-
* Requires a zone.js runtime (e.g. provided by many frameworks) so the ZoneContextManager
|
|
100
|
-
* can keep context during timers, promises, and event callbacks.
|
|
101
|
-
*/
|
|
102
|
-
export const makeTracer = (serviceName: string) => {
|
|
103
|
-
const url = import.meta.env.VITE_OTEL_EXPORTER_OTLP_ENDPOINT as string | undefined
|
|
104
|
-
const provider = new WebTracerProvider({
|
|
105
|
-
spanProcessors: url ? [new SimpleSpanProcessor(new OTLPTraceExporter({ url: `${url}/v1/traces` }))] : [],
|
|
106
|
-
resource: resourceFromAttributes({ 'service.name': serviceName }),
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
provider.register({
|
|
110
|
-
contextManager: new ZoneContextManager(),
|
|
111
|
-
propagator: new W3CTraceContextPropagator(),
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
return provider.getTracer('livestore')
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export const tracer = makeTracer('my-app')
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### `reference/opentelemetry/schema.ts`
|
|
121
|
-
|
|
122
|
-
```ts filename="reference/opentelemetry/schema.ts"
|
|
123
|
-
export { schema } from '../framework-integrations/react/schema.ts'
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
</TabItem>
|
|
127
|
-
<TabItem label="livestore.worker.ts">
|
|
128
|
-
|
|
129
|
-
## `reference/opentelemetry/livestore.worker.ts`
|
|
130
|
-
|
|
131
|
-
```ts filename="reference/opentelemetry/livestore.worker.ts"
|
|
132
|
-
|
|
133
|
-
makeWorker({ schema, otelOptions: { tracer } })
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### `reference/framework-integrations/react/schema.ts`
|
|
137
|
-
|
|
138
|
-
```ts filename="reference/framework-integrations/react/schema.ts"
|
|
139
|
-
|
|
140
|
-
export const tables = {
|
|
141
|
-
todos: State.SQLite.table({
|
|
142
|
-
name: 'todos',
|
|
143
|
-
columns: {
|
|
144
|
-
id: State.SQLite.text({ primaryKey: true }),
|
|
145
|
-
text: State.SQLite.text(),
|
|
146
|
-
completed: State.SQLite.boolean({ default: false }),
|
|
147
|
-
},
|
|
148
|
-
}),
|
|
149
|
-
uiState: State.SQLite.clientDocument({
|
|
150
|
-
name: 'UiState',
|
|
151
|
-
schema: Schema.Struct({ text: Schema.String }),
|
|
152
|
-
default: { value: { text: '' } },
|
|
153
|
-
}),
|
|
154
|
-
} as const
|
|
155
|
-
|
|
156
|
-
export const events = {
|
|
157
|
-
todoCreated: Events.synced({
|
|
158
|
-
name: 'v1.TodoCreated',
|
|
159
|
-
schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
|
|
160
|
-
}),
|
|
161
|
-
} as const
|
|
162
|
-
|
|
163
|
-
const materializers = State.SQLite.materializers(events, {
|
|
164
|
-
[events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
|
|
165
|
-
tables.todos.insert({ id, text, completed: false }),
|
|
166
|
-
),
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
const state = State.SQLite.makeState({ tables, materializers })
|
|
170
|
-
|
|
171
|
-
export const schema = makeSchema({ events, state })
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### `reference/opentelemetry/otel.ts`
|
|
175
|
-
|
|
176
|
-
```ts filename="reference/opentelemetry/otel.ts"
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Configure a browser tracer that preserves parent/child spans across async work.
|
|
180
|
-
* Requires a zone.js runtime (e.g. provided by many frameworks) so the ZoneContextManager
|
|
181
|
-
* can keep context during timers, promises, and event callbacks.
|
|
182
|
-
*/
|
|
183
|
-
export const makeTracer = (serviceName: string) => {
|
|
184
|
-
const url = import.meta.env.VITE_OTEL_EXPORTER_OTLP_ENDPOINT as string | undefined
|
|
185
|
-
const provider = new WebTracerProvider({
|
|
186
|
-
spanProcessors: url ? [new SimpleSpanProcessor(new OTLPTraceExporter({ url: `${url}/v1/traces` }))] : [],
|
|
187
|
-
resource: resourceFromAttributes({ 'service.name': serviceName }),
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
provider.register({
|
|
191
|
-
contextManager: new ZoneContextManager(),
|
|
192
|
-
propagator: new W3CTraceContextPropagator(),
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
return provider.getTracer('livestore')
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export const tracer = makeTracer('my-app')
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### `reference/opentelemetry/schema.ts`
|
|
202
|
-
|
|
203
|
-
```ts filename="reference/opentelemetry/schema.ts"
|
|
204
|
-
export { schema } from '../framework-integrations/react/schema.ts'
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
</TabItem>
|
|
208
|
-
</Tabs>
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
# Reactivity system
|
|
2
|
-
|
|
3
|
-
LiveStore has a high-performance, fine-grained reactivity system built in which is similar to Signals (e.g. in [SolidJS](https://docs.solidjs.com/concepts/signals)).
|
|
4
|
-
|
|
5
|
-
## Defining reactive state
|
|
6
|
-
|
|
7
|
-
LiveStore provides 3 types of reactive state:
|
|
8
|
-
- Reactive SQL queries on top of SQLite state (`queryDb()`)
|
|
9
|
-
- Reactive state values (`signal()`)
|
|
10
|
-
- Reactive computed values (`computed()`)
|
|
11
|
-
|
|
12
|
-
Reactive state variables end on a `$` by convention (e.g. `todos$`). The `label` option is optional but can be used to identify the reactive state variable in the devtools.
|
|
13
|
-
|
|
14
|
-
### Reactive SQL queries
|
|
15
|
-
|
|
16
|
-
## `reference/reactivity-system/query-db.ts`
|
|
17
|
-
|
|
18
|
-
```ts filename="reference/reactivity-system/query-db.ts"
|
|
19
|
-
/** biome-ignore-all lint/correctness/noUnusedVariables: docs snippet exposes intermediate streams */
|
|
20
|
-
// ---cut---
|
|
21
|
-
|
|
22
|
-
const tables = {
|
|
23
|
-
todos: State.SQLite.table({
|
|
24
|
-
name: 'todos',
|
|
25
|
-
columns: {
|
|
26
|
-
id: State.SQLite.text({ primaryKey: true }),
|
|
27
|
-
text: State.SQLite.text(),
|
|
28
|
-
completed: State.SQLite.boolean({ default: false }),
|
|
29
|
-
createdAt: State.SQLite.datetime(),
|
|
30
|
-
},
|
|
31
|
-
}),
|
|
32
|
-
} as const
|
|
33
|
-
|
|
34
|
-
const uiState$ = signal({ showCompleted: false }, { label: 'uiState$' })
|
|
35
|
-
|
|
36
|
-
const todos$ = queryDb(tables.todos.orderBy('createdAt', 'desc'), { label: 'todos$' })
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
const todos$ = queryDb(
|
|
40
|
-
(get) => {
|
|
41
|
-
const { showCompleted } = get(uiState$)
|
|
42
|
-
return tables.todos.where(showCompleted ? { completed: true } : {})
|
|
43
|
-
},
|
|
44
|
-
{ label: 'todos$' },
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Signals
|
|
50
|
-
|
|
51
|
-
Signals are reactive state values that can be set and get. This can be useful for state that is not materialized from events into SQLite tables.
|
|
52
|
-
|
|
53
|
-
## `reference/reactivity-system/signals.ts`
|
|
54
|
-
|
|
55
|
-
```ts filename="reference/reactivity-system/signals.ts"
|
|
56
|
-
|
|
57
|
-
declare const store: Store
|
|
58
|
-
|
|
59
|
-
const now$ = signal(Date.now(), { label: 'now$' })
|
|
60
|
-
|
|
61
|
-
setInterval(() => {
|
|
62
|
-
store.setSignal(now$, Date.now())
|
|
63
|
-
}, 1000)
|
|
64
|
-
|
|
65
|
-
const num$ = signal(0, { label: 'num$' })
|
|
66
|
-
const increment = () => store.setSignal(num$, (prev) => prev + 1)
|
|
67
|
-
|
|
68
|
-
increment()
|
|
69
|
-
increment()
|
|
70
|
-
|
|
71
|
-
console.log(store.query(num$))
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Computed values
|
|
75
|
-
|
|
76
|
-
## `reference/reactivity-system/computed.ts`
|
|
77
|
-
|
|
78
|
-
```ts filename="reference/reactivity-system/computed.ts"
|
|
79
|
-
/** biome-ignore-all lint/correctness/noUnusedVariables: docs snippet highlights derived signal */
|
|
80
|
-
// ---cut---
|
|
81
|
-
|
|
82
|
-
const num$ = signal(0, { label: 'num$' })
|
|
83
|
-
const duplicated$ = computed((get) => get(num$) * 2, { label: 'duplicated$' })
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Accessing reactive state
|
|
87
|
-
|
|
88
|
-
Reactive state is always bound to a `Store` instance. You can access the current value of reactive state the following ways:
|
|
89
|
-
|
|
90
|
-
### Using the `Store` instance
|
|
91
|
-
|
|
92
|
-
## `reference/reactivity-system/store-access.ts`
|
|
93
|
-
|
|
94
|
-
```ts filename="reference/reactivity-system/store-access.ts"
|
|
95
|
-
|
|
96
|
-
declare const store: Store
|
|
97
|
-
|
|
98
|
-
const tables = {
|
|
99
|
-
todos: State.SQLite.table({
|
|
100
|
-
name: 'todos',
|
|
101
|
-
columns: {
|
|
102
|
-
id: State.SQLite.text({ primaryKey: true }),
|
|
103
|
-
title: State.SQLite.text(),
|
|
104
|
-
completed: State.SQLite.boolean({ default: false }),
|
|
105
|
-
},
|
|
106
|
-
}),
|
|
107
|
-
} as const
|
|
108
|
-
|
|
109
|
-
const count$ = queryDb(tables.todos.count(), { label: 'count$' })
|
|
110
|
-
const count = store.query(count$)
|
|
111
|
-
console.log(count)
|
|
112
|
-
|
|
113
|
-
const unsubscribe = store.subscribe(count$, (value) => {
|
|
114
|
-
console.log(value)
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
unsubscribe()
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### Via framework integrations
|
|
121
|
-
|
|
122
|
-
#### React
|
|
123
|
-
|
|
124
|
-
## `reference/reactivity-system/react-component.tsx`
|
|
125
|
-
|
|
126
|
-
```tsx filename="reference/reactivity-system/react-component.tsx"
|
|
127
|
-
|
|
128
|
-
declare const state$: LiveQueryDef<number>
|
|
129
|
-
|
|
130
|
-
export const MyComponent: FC = () => {
|
|
131
|
-
const value = useQuery(state$)
|
|
132
|
-
|
|
133
|
-
return <div>{value}</div>
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
#### Solid
|
|
138
|
-
|
|
139
|
-
## `reference/reactivity-system/solid-component.tsx`
|
|
140
|
-
|
|
141
|
-
```tsx filename="reference/reactivity-system/solid-component.tsx"
|
|
142
|
-
|
|
143
|
-
declare const state$: LiveQueryDef<number>
|
|
144
|
-
|
|
145
|
-
export const MyComponent = () => {
|
|
146
|
-
const value = query(state$, 0)
|
|
147
|
-
|
|
148
|
-
return <div>{value()}</div>
|
|
149
|
-
}
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### Reacting to changing variables passed to queries
|
|
153
|
-
|
|
154
|
-
If your query depends on a variable passed in by the component, use the deps array to react to changes in this variable.
|
|
155
|
-
|
|
156
|
-
## `reference/reactivity-system/deps-query.tsx`
|
|
157
|
-
|
|
158
|
-
```tsx filename="reference/reactivity-system/deps-query.tsx"
|
|
159
|
-
|
|
160
|
-
const tables = {
|
|
161
|
-
todos: State.SQLite.table({
|
|
162
|
-
name: 'todos',
|
|
163
|
-
columns: {
|
|
164
|
-
id: State.SQLite.text({ primaryKey: true }),
|
|
165
|
-
text: State.SQLite.text(),
|
|
166
|
-
completed: State.SQLite.boolean({ default: false }),
|
|
167
|
-
},
|
|
168
|
-
}),
|
|
169
|
-
} as const
|
|
170
|
-
|
|
171
|
-
declare const store: Store & ReactApi
|
|
172
|
-
|
|
173
|
-
export const todos$ = ({ showCompleted }: { showCompleted: boolean }) =>
|
|
174
|
-
queryDb(
|
|
175
|
-
() => {
|
|
176
|
-
return tables.todos.where(showCompleted ? { completed: true } : {})
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
label: 'todos$',
|
|
180
|
-
deps: [showCompleted ? 'true' : 'false'],
|
|
181
|
-
},
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
export const MyComponent: FC<{ showCompleted: boolean }> = ({ showCompleted }) => {
|
|
185
|
-
const todos = store.useQuery(todos$({ showCompleted })) as ReadonlyArray<{
|
|
186
|
-
id: string
|
|
187
|
-
text: string
|
|
188
|
-
completed: boolean
|
|
189
|
-
}>
|
|
190
|
-
|
|
191
|
-
return <div>{todos.length} Done</div>
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## Further reading
|
|
196
|
-
|
|
197
|
-
- [Riffle](https://riffle.systems/essays/prelude/): Building data-centric apps with a reactive relational database
|
|
198
|
-
- [Adapton](http://adapton.org/) / [miniAdapton](https://arxiv.org/pdf/1609.05337)
|
|
199
|
-
|
|
200
|
-
## Related technologies
|
|
201
|
-
|
|
202
|
-
- [Signia](https://signia.tldraw.dev/): Signia is a minimal, fast, and scalable signals library for TypeScript developed by TLDraw.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Rules for AI agents
|
|
2
|
-
|
|
3
|
-
## AGENTS.md
|
|
4
|
-
|
|
5
|
-
Add the content of this `AGENTS.md` file or other custom rules:
|
|
6
|
-
|
|
7
|
-
```md
|
|
8
|
-
- When you need to look up information about LiveStore, always use the `docs` directory that's shipped inside `node_modules/@livestore/livestore/docs`.
|
|
9
|
-
```
|