@livestore/livestore 0.4.0-dev.22 → 0.4.0-dev.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/README.md +0 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/QueryCache.js +1 -1
  4. package/dist/QueryCache.js.map +1 -1
  5. package/dist/SqliteDbWrapper.d.ts +5 -5
  6. package/dist/SqliteDbWrapper.d.ts.map +1 -1
  7. package/dist/SqliteDbWrapper.js +8 -8
  8. package/dist/SqliteDbWrapper.js.map +1 -1
  9. package/dist/SqliteDbWrapper.test.js +2 -2
  10. package/dist/SqliteDbWrapper.test.js.map +1 -1
  11. package/dist/effect/LiveStore.d.ts +14 -7
  12. package/dist/effect/LiveStore.d.ts.map +1 -1
  13. package/dist/effect/LiveStore.js +0 -15
  14. package/dist/effect/LiveStore.js.map +1 -1
  15. package/dist/effect/LiveStore.test.d.ts +2 -0
  16. package/dist/effect/LiveStore.test.d.ts.map +1 -0
  17. package/dist/effect/LiveStore.test.js +42 -0
  18. package/dist/effect/LiveStore.test.js.map +1 -0
  19. package/dist/live-queries/base-class.d.ts +3 -3
  20. package/dist/live-queries/base-class.d.ts.map +1 -1
  21. package/dist/live-queries/base-class.js +2 -2
  22. package/dist/live-queries/base-class.js.map +1 -1
  23. package/dist/live-queries/client-document-get-query.d.ts +1 -1
  24. package/dist/live-queries/client-document-get-query.d.ts.map +1 -1
  25. package/dist/live-queries/client-document-get-query.js +1 -1
  26. package/dist/live-queries/client-document-get-query.js.map +1 -1
  27. package/dist/live-queries/computed.d.ts.map +1 -1
  28. package/dist/live-queries/computed.js +2 -2
  29. package/dist/live-queries/computed.js.map +1 -1
  30. package/dist/live-queries/db-query.js +14 -14
  31. package/dist/live-queries/db-query.js.map +1 -1
  32. package/dist/live-queries/db-query.test.js +2 -2
  33. package/dist/live-queries/db-query.test.js.map +1 -1
  34. package/dist/live-queries/signal.test.js +2 -2
  35. package/dist/live-queries/signal.test.js.map +1 -1
  36. package/dist/mod.d.ts +1 -1
  37. package/dist/mod.d.ts.map +1 -1
  38. package/dist/mod.js.map +1 -1
  39. package/dist/reactive.d.ts +9 -9
  40. package/dist/reactive.d.ts.map +1 -1
  41. package/dist/reactive.js +9 -26
  42. package/dist/reactive.js.map +1 -1
  43. package/dist/reactive.test.js +2 -2
  44. package/dist/reactive.test.js.map +1 -1
  45. package/dist/store/StoreRegistry.d.ts +30 -5
  46. package/dist/store/StoreRegistry.d.ts.map +1 -1
  47. package/dist/store/StoreRegistry.js +54 -31
  48. package/dist/store/StoreRegistry.js.map +1 -1
  49. package/dist/store/StoreRegistry.test.js +251 -250
  50. package/dist/store/StoreRegistry.test.js.map +1 -1
  51. package/dist/store/create-store.d.ts +6 -2
  52. package/dist/store/create-store.d.ts.map +1 -1
  53. package/dist/store/create-store.js +13 -7
  54. package/dist/store/create-store.js.map +1 -1
  55. package/dist/store/devtools.d.ts +1 -1
  56. package/dist/store/devtools.d.ts.map +1 -1
  57. package/dist/store/devtools.js +3 -3
  58. package/dist/store/devtools.js.map +1 -1
  59. package/dist/store/store-eventstream.test.js +2 -2
  60. package/dist/store/store-eventstream.test.js.map +1 -1
  61. package/dist/store/store-types.d.ts +70 -5
  62. package/dist/store/store-types.d.ts.map +1 -1
  63. package/dist/store/store-types.js.map +1 -1
  64. package/dist/store/store-types.test.js +1 -1
  65. package/dist/store/store-types.test.js.map +1 -1
  66. package/dist/store/store.d.ts +81 -2
  67. package/dist/store/store.d.ts.map +1 -1
  68. package/dist/store/store.js +128 -45
  69. package/dist/store/store.js.map +1 -1
  70. package/dist/utils/dev.js.map +1 -1
  71. package/dist/utils/stack-info.js +2 -2
  72. package/dist/utils/stack-info.js.map +1 -1
  73. package/dist/utils/tests/fixture.d.ts +1 -1
  74. package/dist/utils/tests/fixture.d.ts.map +1 -1
  75. package/dist/utils/tests/fixture.js.map +1 -1
  76. package/dist/utils/tests/otel.d.ts.map +1 -1
  77. package/dist/utils/tests/otel.js +5 -5
  78. package/dist/utils/tests/otel.js.map +1 -1
  79. package/package.json +58 -17
  80. package/src/QueryCache.ts +1 -1
  81. package/src/SqliteDbWrapper.test.ts +4 -2
  82. package/src/SqliteDbWrapper.ts +12 -11
  83. package/src/ambient.d.ts +0 -7
  84. package/src/effect/LiveStore.test.ts +61 -0
  85. package/src/effect/LiveStore.ts +17 -26
  86. package/src/live-queries/__snapshots__/db-query.test.ts.snap +336 -231
  87. package/src/live-queries/base-class.ts +7 -6
  88. package/src/live-queries/client-document-get-query.ts +4 -2
  89. package/src/live-queries/computed.ts +3 -2
  90. package/src/live-queries/db-query.test.ts +3 -2
  91. package/src/live-queries/db-query.ts +15 -15
  92. package/src/live-queries/signal.test.ts +3 -2
  93. package/src/mod.ts +1 -0
  94. package/src/reactive.test.ts +3 -2
  95. package/src/reactive.ts +22 -23
  96. package/src/store/StoreRegistry.test.ts +317 -293
  97. package/src/store/StoreRegistry.ts +63 -38
  98. package/src/store/create-store.ts +26 -11
  99. package/src/store/devtools.ts +5 -6
  100. package/src/store/store-eventstream.test.ts +4 -2
  101. package/src/store/store-types.test.ts +3 -1
  102. package/src/store/store-types.ts +47 -8
  103. package/src/store/store.ts +172 -55
  104. package/src/utils/dev.ts +2 -2
  105. package/src/utils/stack-info.ts +2 -2
  106. package/src/utils/tests/fixture.ts +2 -1
  107. package/src/utils/tests/otel.ts +8 -7
  108. package/docs/api/index.md +0 -3
  109. package/docs/building-with-livestore/complex-ui-state/index.md +0 -3
  110. package/docs/building-with-livestore/crud/index.md +0 -3
  111. package/docs/building-with-livestore/data-modeling/index.md +0 -30
  112. package/docs/building-with-livestore/debugging/index.md +0 -17
  113. package/docs/building-with-livestore/devtools/index.md +0 -79
  114. package/docs/building-with-livestore/events/index.md +0 -355
  115. package/docs/building-with-livestore/examples/ai-agent/index.md +0 -5
  116. package/docs/building-with-livestore/examples/todo-workspaces/index.md +0 -885
  117. package/docs/building-with-livestore/examples/turnbased-game/index.md +0 -7
  118. package/docs/building-with-livestore/opentelemetry/index.md +0 -227
  119. package/docs/building-with-livestore/production-checklist/index.md +0 -5
  120. package/docs/building-with-livestore/reactivity-system/index.md +0 -202
  121. package/docs/building-with-livestore/rules-for-ai-agents/index.md +0 -9
  122. package/docs/building-with-livestore/state/materializers/index.md +0 -300
  123. package/docs/building-with-livestore/state/sql-queries/index.md +0 -94
  124. package/docs/building-with-livestore/state/sqlite/index.md +0 -45
  125. package/docs/building-with-livestore/state/sqlite-schema/index.md +0 -306
  126. package/docs/building-with-livestore/state/sqlite-schema-effect/index.md +0 -300
  127. package/docs/building-with-livestore/store/index.md +0 -625
  128. package/docs/building-with-livestore/syncing/index.md +0 -136
  129. package/docs/building-with-livestore/tools/cli/index.md +0 -177
  130. package/docs/building-with-livestore/tools/mcp/index.md +0 -187
  131. package/docs/examples/cloudflare-adapter/index.md +0 -44
  132. package/docs/examples/expo-adapter/index.md +0 -44
  133. package/docs/examples/index.md +0 -55
  134. package/docs/examples/node-adapter/index.md +0 -44
  135. package/docs/examples/web-adapter/index.md +0 -52
  136. package/docs/framework-integrations/custom-elements/index.md +0 -142
  137. package/docs/framework-integrations/react-integration/index.md +0 -937
  138. package/docs/framework-integrations/solid-integration/index.md +0 -293
  139. package/docs/framework-integrations/svelte-integration/index.md +0 -42
  140. package/docs/framework-integrations/vue-integration/index.md +0 -294
  141. package/docs/getting-started/expo/index.md +0 -882
  142. package/docs/getting-started/node/index.md +0 -115
  143. package/docs/getting-started/react-web/index.md +0 -626
  144. package/docs/getting-started/solid/index.md +0 -3
  145. package/docs/getting-started/vue/index.md +0 -471
  146. package/docs/index.md +0 -208
  147. package/docs/llms.txt +0 -146
  148. package/docs/misc/CODE_OF_CONDUCT/index.md +0 -133
  149. package/docs/misc/FAQ/index.md +0 -37
  150. package/docs/misc/community/index.md +0 -88
  151. package/docs/misc/credits/index.md +0 -14
  152. package/docs/misc/design-partners/index.md +0 -13
  153. package/docs/misc/package-management/index.md +0 -21
  154. package/docs/misc/performance/index.md +0 -25
  155. package/docs/misc/resources/index.md +0 -46
  156. package/docs/misc/state-of-the-project/index.md +0 -37
  157. package/docs/misc/troubleshooting/index.md +0 -82
  158. package/docs/overview/concepts/index.md +0 -78
  159. package/docs/overview/how-livestore-works/index.md +0 -56
  160. package/docs/overview/introduction/index.md +0 -413
  161. package/docs/overview/technology-comparison/index.md +0 -40
  162. package/docs/overview/when-livestore/index.md +0 -81
  163. package/docs/overview/why-livestore/index.md +0 -111
  164. package/docs/patterns/ai/index.md +0 -15
  165. package/docs/patterns/anonymous-user-transition/index.md +0 -10
  166. package/docs/patterns/app-evolution/index.md +0 -72
  167. package/docs/patterns/auth/index.md +0 -377
  168. package/docs/patterns/effect/index.md +0 -1505
  169. package/docs/patterns/encryption/index.md +0 -6
  170. package/docs/patterns/external-data/index.md +0 -5
  171. package/docs/patterns/file-management/index.md +0 -11
  172. package/docs/patterns/file-structure/index.md +0 -14
  173. package/docs/patterns/list-ordering/index.md +0 -369
  174. package/docs/patterns/offline/index.md +0 -32
  175. package/docs/patterns/orm/index.md +0 -18
  176. package/docs/patterns/presence/index.md +0 -11
  177. package/docs/patterns/rich-text-editing/index.md +0 -11
  178. package/docs/patterns/server-side-clients/index.md +0 -97
  179. package/docs/patterns/side-effects/index.md +0 -11
  180. package/docs/patterns/state-machines/index.md +0 -11
  181. package/docs/patterns/storybook/index.md +0 -209
  182. package/docs/patterns/undo-redo/index.md +0 -9
  183. package/docs/patterns/version-control/index.md +0 -8
  184. package/docs/platform-adapters/cloudflare-durable-object-adapter/index.md +0 -453
  185. package/docs/platform-adapters/electron-adapter/index.md +0 -15
  186. package/docs/platform-adapters/expo-adapter/index.md +0 -262
  187. package/docs/platform-adapters/node-adapter/index.md +0 -160
  188. package/docs/platform-adapters/tauri-adapter/index.md +0 -15
  189. package/docs/platform-adapters/web-adapter/index.md +0 -287
  190. package/docs/sustainable-open-source/contributing/docs/index.md +0 -94
  191. package/docs/sustainable-open-source/contributing/info/index.md +0 -63
  192. package/docs/sustainable-open-source/contributing/monorepo/index.md +0 -195
  193. package/docs/sustainable-open-source/sponsoring/index.md +0 -104
  194. package/docs/sync-providers/cloudflare/index.md +0 -773
  195. package/docs/sync-providers/custom/index.md +0 -65
  196. package/docs/sync-providers/electricsql/index.md +0 -159
  197. package/docs/sync-providers/s2/index.md +0 -230
  198. package/docs/tutorial/0-welcome/index.md +0 -48
  199. package/docs/tutorial/1-setup-starter-project/index.md +0 -105
  200. package/docs/tutorial/2-deploy-to-cloudflare/index.md +0 -195
  201. package/docs/tutorial/3-read-and-write-todos-via-livestore/index.md +0 -530
  202. package/docs/tutorial/4-sync-data-via-cloudflare/index.md +0 -210
  203. package/docs/tutorial/5-expand-business-logic/index.md +0 -174
  204. package/docs/tutorial/6-persist-ui-state/index.md +0 -453
  205. package/docs/tutorial/7-next-steps/index.md +0 -22
  206. package/docs/understanding-livestore/design-decisions/index.md +0 -33
  207. package/docs/understanding-livestore/event-sourcing/index.md +0 -40
@@ -1,79 +0,0 @@
1
- # Devtools
2
-
3
- NOTE: Once LiveStore is open source, the devtools will be a [sponsor-only benefit](/sustainable-open-source/sponsoring).
4
-
5
- ## Features
6
-
7
- - Real-time data browser with 2-way sync
8
- ![](https://share.cleanshot.com/F79hpTCY+)
9
- - Query inspector
10
- ![](https://share.cleanshot.com/pkr2jqgb+)
11
- - Eventlog browser
12
- ![](https://share.cleanshot.com/PTgXpcPm+)
13
- - Sync status
14
- ![](https://share.cleanshot.com/VsKY3KnR+)
15
- - Export/import
16
- ![](https://share.cleanshot.com/LQKYX6rq+)
17
- - Reactivity graph / signals inspector
18
- ![](https://share.cleanshot.com/M26FHD6j+)
19
- - SQLite playground
20
- ![](https://share.cleanshot.com/BcWmLmn2+)
21
-
22
- ## Adapters
23
-
24
- ### `@livestore/adapter-web`:
25
-
26
- Requires the `@livestore/devtools-vite` package to be installed and configured in your Vite config:
27
-
28
- ## `reference/devtools/vite-config.ts`
29
-
30
- ```ts filename="reference/devtools/vite-config.ts"
31
-
32
- export default defineConfig({
33
- // ...
34
- plugins: [livestoreDevtoolsPlugin({ schemaPath: './src/livestore/schema.ts' })],
35
- })
36
- ```
37
-
38
- The devtools can be opened in a separate tab (via e.g. `localhost:3000/_livestore/web). You should see the Devtools URL logged in the browser console when running the app.
39
-
40
- #### Chrome extension
41
-
42
- You can also use the Devtools Chrome extension.
43
-
44
- ![](https://share.cleanshot.com/wlM4ybFn+)
45
-
46
- Please make sure to manually install the extension version matching the LiveStore version you are using by downloading the appropriate version from the [GitHub releases page](https://github.com/livestorejs/livestore/releases) and installing it manually via `chrome://extensions/`.
47
-
48
- To install the extension:
49
-
50
- 1. **Unpack the ZIP file** (e.g. `livestore-devtools-chrome-0.3.0.zip`) into a folder on your computer.
51
- 2. Navigate to `chrome://extensions/` and enable **Developer mode** (toggle in the top-right corner).
52
- 3. Click **"Load unpacked"** and select the unpacked folder or drag and drop the folder onto the page.
53
-
54
- ### `@livestore/adapter-expo`:
55
-
56
- Requires the `@livestore/devtools-expo` package to be installed and configured in your metro config:
57
-
58
- ## `reference/devtools/metro-config.ts`
59
-
60
- ```ts filename="reference/devtools/metro-config.ts"
61
- // @noErrors
62
- // metro.config.js
63
- const { getDefaultConfig } = require('expo/metro-config')
64
- const { addLiveStoreDevtoolsMiddleware } = require('@livestore/devtools-expo')
65
-
66
- const config = getDefaultConfig(__dirname)
67
-
68
- addLiveStoreDevtoolsMiddleware(config, { schemaPath: './src/livestore/schema.ts' })
69
-
70
- module.exports = config
71
- ```
72
-
73
- You can open the devtools by pressing `Shift+m` in the Expo CLI process and then selecting `@livestore/devtools-expo` which will open the devtools in a new tab.
74
-
75
- ### `@livestore/adapter-node`:
76
-
77
- Devtools are configured out of the box for the `makePersistedAdapter` variant (note currently not supported for the `makeInMemoryAdapter` variant).
78
-
79
- You should see the Devtools URL logged when running the app.
@@ -1,355 +0,0 @@
1
- # Events
2
-
3
- ## Event definitions
4
-
5
- There are two types of events:
6
-
7
- - `synced`: Events that are synced across clients
8
- - `clientOnly`: Events that are only processed locally on the client (but still synced across client sessions e.g. across browser tabs/windows)
9
-
10
- An event definition consists of a unique name of the event and a schema for the event arguments. It's recommended to version event definitions to make it easier to evolve them over time.
11
-
12
- Events will be synced across clients and materialized into state (i.e. SQLite tables) via [materializers](/building-with-livestore/state/materializers).
13
-
14
- ### Example
15
-
16
- ## `reference/events/livestore-schema.ts`
17
-
18
- ```ts filename="reference/events/livestore-schema.ts"
19
- // livestore/schema.ts
20
-
21
- export const events = {
22
- todoCreated: Events.synced({
23
- name: 'v1.TodoCreated',
24
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
25
- }),
26
- todoCompleted: Events.synced({
27
- name: 'v1.TodoCompleted',
28
- schema: Schema.Struct({ id: Schema.String }),
29
- }),
30
- } as const
31
- ```
32
-
33
- ### Commiting events
34
-
35
- ## `reference/events/commit.ts`
36
-
37
- ```ts filename="reference/events/commit.ts"
38
- // somewhere in your app
39
-
40
- declare const store: Store
41
-
42
- store.commit(events.todoCreated({ id: '1', text: 'Buy milk' }))
43
- ```
44
-
45
- ### `reference/events/livestore-schema.ts`
46
-
47
- ```ts filename="reference/events/livestore-schema.ts"
48
- // livestore/schema.ts
49
-
50
- export const events = {
51
- todoCreated: Events.synced({
52
- name: 'v1.TodoCreated',
53
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
54
- }),
55
- todoCompleted: Events.synced({
56
- name: 'v1.TodoCompleted',
57
- schema: Schema.Struct({ id: Schema.String }),
58
- }),
59
- } as const
60
- ```
61
-
62
- ### Streaming events
63
-
64
- Currently only events confirmed by the sync backend are supported.
65
-
66
- ## `reference/events/stream.ts`
67
-
68
- ```ts filename="reference/events/stream.ts"
69
-
70
- declare const store: Store
71
-
72
- for await (const event of store.events()) {
73
- console.log('event from leader', event)
74
- }
75
- ```
76
-
77
- ### Best practices
78
-
79
- - It's strongly recommended to use past-tense event names (e.g. `todoCreated`/`createdTodo` instead of `todoCreate`/`createTodo`) to indicate something already occurred.
80
- - When generating IDs for events (e.g. for the todo in the example above), it's recommended to use a globally unique ID generator (e.g. UUID, nanoid, etc.) to avoid conflicts. For convenience, `@livestore/livestore` re-exports the `nanoid` function.
81
- - TODO: write down more best practices
82
- - TODO: mention AI linting (either manually or via a CI step)
83
- - core idea: feed list of best practices to AI and check if events adhere to them + get suggestions if not
84
- - It's recommended to avoid `DELETE` events and instead use soft-deletes (e.g. add a `deleted` date/boolean column with a default value of `null`). This helps avoid some common concurrency issues.
85
-
86
- ## Nodes in the LiveStore system
87
-
88
- <EventNodesDiagram class="my-8" />
89
-
90
- #### Client Session
91
- - `SyncState`: in-memory for pending events only
92
- - `dbState`: Materialized state that matches the schema (SQLite database)
93
-
94
- #### Client Leader
95
- - `dbEventLog`: Database that stores the durable event log and tracks global sequence of events which the backend has acknowledged
96
- - `dbState`: Materialized state that matches the schema (SQLite database) so leader can materialize events and handle rollbacks
97
-
98
- #### Sync backend
99
- - `EventLog`: Any storage solution that supports pushing and pulling events. Append only storage.
100
-
101
- ### Happy event path
102
-
103
- 1. Client session commits an event
104
- - Client session merges the new event `e3` into its local `SyncState` as pending
105
- - Client session pushes the pending event to the client leader thread; the leader still shows the previous head until it persists the event
106
- <EventsVisualizer
107
- client={["e1", "e2", "A:e3'{todoCreated}"]}
108
- leader={["e1", "e2"]}
109
- backend={["e1", "e2"]} />
110
-
111
- 2. Client leader persists the event
112
- - Client leader materializes the event and writes it to `EventLog`
113
- - Event `e3` remains unconfirmed from the leader's perspective because the backend has not acknowledged it yet
114
- <EventsVisualizer
115
- client={["e1", "e2", "A:e3'{todoCreated}"]}
116
- leader={["e1", "e2", "A:e3'{todoCreated}"]}
117
- backend={["e1", "e2"]} />
118
-
119
- 3. Leader thread emits signal back to subscribed clients
120
- - Client session merges the authoritative event from the leader
121
- - Event transitions from pending to confirmed on the client while the leader still waits for backend confirmation
122
- <EventsVisualizer
123
- client={["e1", "e2", "A:e3{todoCreated}"]}
124
- leader={["e1", "e2", "A:e3'{todoCreated}"]}
125
- backend={["e1", "e2"]} />
126
-
127
- 4. Leader thread pushes the event to the sync backend
128
- - Leader pushes the pending event upstream; it stays marked as unconfirmed in the client leader's eventlog until the backend acknowledges receipt
129
- <EventsVisualizer
130
- client={["e1", "e2", "A:e3{todoCreated}"]}
131
- leader={["e1", "e2", "A:e3'{todoCreated}"]}
132
- backend={["e1", "e2"]} />
133
-
134
- 5. Sync backend pulls the event from the client leader
135
- - Sync backend acknowledges the event and advances its head
136
- - Client leader receives the acknowledgement and marks the event as confirmed
137
- - All heads align on the confirmed sequence
138
- <EventsVisualizer
139
- client={["e1", "e2", "A:e3{todoCreated}"]}
140
- leader={["e1", "e2", "A:e3{todoCreated}"]}
141
- backend={["e1", "e2", "A:e3{todoCreated}"]} />
142
-
143
- ### Conflict resolution
144
-
145
- This example shows how a client session rebases its pending events when new authoritative events arrive from upstream. Client `A` owns the local work that gets rebased, while client `B` introduces the authoritative change. Colors follow the client IDs so lineage remains visible, and origin notation tracks the rebased event.
146
-
147
- 1. Client session has local pending work while upstream advances
148
- - Client session holds pending event `A:e3'{todoRenamed}` built on top of shared history `e1 → e2`
149
- - Sync backend publishes authoritative event `B:e3{todoRenamed}` that replaces the client's local change
150
- <EventsVisualizer
151
- client={["e1", "e2", "A:e3{todoRenamed}"]}
152
- leader={["e1", "e2", "A:e3'{todoRenamed}"]}
153
- backend={["e1", "e2", "B:e3{todoRenamed}"]} />
154
-
155
- 2. Client leader pulls authoritative events from the sync backend
156
- - Client compares its pending chain with upstream events and spots the divergence at `e2`
157
- - Client rolls back events and state to the point of divergence
158
- <EventsVisualizer
159
- client={["e1", "e2"]}
160
- leader={["e1", "e2"]}
161
- backend={["e1", "e2", "B:e3{todoRenamed}"]} />
162
-
163
- 3. Client applies authoritative upstream events
164
- - Client session and leader apply the authoritative upstream events and advances their heads to `e3`
165
- <EventsVisualizer
166
- client={["e1", "e2", "B:e3{todoRenamed}"]}
167
- leader={["e1", "e2", "B:e3{todoRenamed}"]}
168
- backend={["e1", "e2", "B:e3{todoRenamed}"]} />
169
-
170
- 4. Client replays its local pending events on top of the new head
171
- - Stored original events keep their payload but their sequence number gets updated to follow upstream head
172
- - Each newly numbered event is re-appplied and materialized to state in both client session and client leader
173
- <EventsVisualizer
174
- client={["e1", "e2", "B:e3{todoRenamed}", "A:e4{todoRenamed}/e3"]}
175
- leader={["e1", "e2", "B:e3{todoRenamed}", "A:e4'{todoRenamed}/e3"]}
176
- backend={["e1", "e2", "B:e3{todoRenamed}"]} />
177
-
178
- 5. Client pushes its local pending events to sync backend
179
- - Upon receipt local pending events are marked as confirmed and the client leader advances its head to `e4`
180
- <EventsVisualizer
181
- client={["e1", "e2", "B:e3{todoRenamed}", "A:e4{todoRenamed}/e3"]}
182
- leader={["e1", "e2", "B:e3{todoRenamed}", "A:e4{todoRenamed}/e3"]}
183
- backend={["e1", "e2", "B:e3{todoRenamed}", "A:e4{todoRenamed}/e3"]} />
184
-
185
- ## Unknown events
186
-
187
- Older clients might receive events that were introduced in newer app versions. Configure the behaviour centrally via `unknownEventHandling` when constructing the schema:
188
-
189
- ## `reference/events/unknown-event-handling.ts`
190
-
191
- ```ts filename="reference/events/unknown-event-handling.ts"
192
-
193
- const tables = {
194
- todos: State.SQLite.table({
195
- name: 'todos',
196
- columns: {
197
- id: State.SQLite.text({ primaryKey: true }),
198
- text: State.SQLite.text(),
199
- },
200
- }),
201
- } as const
202
-
203
- const events = {
204
- todoCreated: Events.synced({
205
- name: 'v1.TodoCreated',
206
- schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
207
- }),
208
- } as const
209
-
210
- const materializers = State.SQLite.materializers(events, {
211
- [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
212
- tables.todos.insert({ id, text }),
213
- ),
214
- })
215
-
216
- const state = State.SQLite.makeState({ tables, materializers })
217
-
218
- // ---cut---
219
-
220
- const _schema = makeSchema({
221
- events,
222
- state,
223
- unknownEventHandling: {
224
- strategy: 'callback',
225
- onUnknownEvent: (event, error) => {
226
- console.warn('LiveStore saw an unknown event', { event, reason: error.reason })
227
- },
228
- },
229
- })
230
- ```
231
-
232
- Pick `'warn'` (default) to log every occurrence, `'ignore'` to silently drop new events until the client updates, `'fail'` to halt immediately, or `'callback'` to delegate to custom logging/telemetry while continuing to process the log.
233
-
234
- ## Schema evolution \{#schema-evolution\}
235
-
236
- - Event definitions can't be removed after they were added to your app.
237
- - Event schema definitions can be evolved as long as the changes are forward-compatible.
238
- - That means data encoded with the old schema can be decoded with the new schema.
239
- - In practice, this means ...
240
- - for structs ...
241
- - you can add new fields if they have default values or are optional
242
- - you can remove fields
243
-
244
- ## Event format
245
-
246
- Each event has the following structure:
247
-
248
- | Field | Description |
249
- |-------|-------------|
250
- | `name` | Event name matching the event definition |
251
- | `args` | Event arguments as defined by the event schema |
252
- | `seqNum` | Sequence number identifying this event |
253
- | `parentSeqNum` | Parent event's sequence number (for causal ordering) |
254
- | `clientId` | Identifier of the client that created the event |
255
- | `sessionId` | Identifier of the session |
256
-
257
- ### Encoded vs decoded events
258
-
259
- Events exist in two formats:
260
-
261
- **Decoded** - Native TypeScript types used in application code:
262
-
263
- ```json
264
- {
265
- "name": "todoCreated-v1",
266
- "args": { "id": "abc123", "text": "Buy milk", "createdAt": Date },
267
- "seqNum": 5,
268
- "parentSeqNum": 4,
269
- "clientId": "client-xyz",
270
- "sessionId": "session-123"
271
- }
272
- ```
273
-
274
- **Encoded** - Serialized format for storage and sync:
275
-
276
- ```json
277
- {
278
- "name": "todoCreated-v1",
279
- "args": { "id": "abc123", "text": "Buy milk", "createdAt": "2024-01-15T10:30:00.000Z" },
280
- "seqNum": 5,
281
- "parentSeqNum": 4,
282
- "clientId": "client-xyz",
283
- "sessionId": "session-123"
284
- }
285
- ```
286
-
287
- The `args` field is encoded according to the event's schema (e.g., `Date` objects become ISO strings, binary data becomes base64). LiveStore handles encoding/decoding automatically.
288
-
289
- ### Client-side sequence numbers
290
-
291
- On the client, sequence numbers are expanded to track additional information for local events:
292
-
293
- ```json
294
- {
295
- "seqNum": { "global": 5, "client": 1, "rebaseGeneration": 0 },
296
- "parentSeqNum": { "global": 5, "client": 0, "rebaseGeneration": 0 }
297
- }
298
- ```
299
-
300
- - **global**: Globally unique integer assigned by the sync backend (`EventSequenceNumber.Global`)
301
- - **client**: Client-local counter (0 for synced events, increments for client-only events) (`EventSequenceNumber.Client`)
302
- - **rebaseGeneration**: Increments when the client rebases unconfirmed events
303
-
304
- Events can be represented as strings like `e5` (global event 5), `e5.1` (client-local event), or `e5r1` (after a rebase).
305
-
306
- For the full type definitions, see [`LiveStoreEvent`](https://github.com/livestorejs/livestore/tree/dev/packages/@livestore/common/src/schema/LiveStoreEvent) and [`EventSequenceNumber`](https://github.com/livestorejs/livestore/tree/dev/packages/@livestore/common/src/schema/EventSequenceNumber).
307
-
308
- ### Event type namespaces
309
-
310
- LiveStore organizes event types into namespaces based on their usage context:
311
-
312
- | Namespace | Description | Sequence Number Format |
313
- |-----------|-------------|----------------------|
314
- | `LiveStoreEvent.Input` | Events without sequence numbers (for committing) | None |
315
- | `LiveStoreEvent.Global` | Sync backend format | Integer (`seqNum: number`) |
316
- | `LiveStoreEvent.Client` | Client-side format with full metadata | Struct (`seqNum: { global, client, rebaseGeneration }`) |
317
-
318
- ## `reference/events/event-type-namespaces.ts`
319
-
320
- ```ts filename="reference/events/event-type-namespaces.ts"
321
-
322
- // Input events (no sequence numbers) - used when committing
323
- const _input: LiveStoreEvent.Input.Decoded = {
324
- name: 'todoCreated-v1',
325
- args: { id: 'abc123', text: 'Buy milk' },
326
- }
327
-
328
- // Global events (sync backend format) - integer sequence numbers
329
- const _global: LiveStoreEvent.Global.Encoded = {
330
- name: 'todoCreated-v1',
331
- args: { id: 'abc123', text: 'Buy milk' },
332
- seqNum: EventSequenceNumber.Global.make(5),
333
- parentSeqNum: EventSequenceNumber.Global.make(4),
334
- clientId: 'client-xyz',
335
- sessionId: 'session-123',
336
- }
337
-
338
- // Client events (local format) - composite sequence numbers
339
- const _client: LiveStoreEvent.Client.Encoded = {
340
- name: 'todoCreated-v1',
341
- args: { id: 'abc123', text: 'Buy milk' },
342
- seqNum: EventSequenceNumber.Client.Composite.make({ global: 5, client: 0, rebaseGeneration: 0 }),
343
- parentSeqNum: EventSequenceNumber.Client.Composite.make({ global: 4, client: 0, rebaseGeneration: 0 }),
344
- clientId: 'client-xyz',
345
- sessionId: 'session-123',
346
- }
347
- ```
348
-
349
- ## Eventlog
350
-
351
- The history of all events that have been committed is stored forms the "eventlog". It is persisted in the client as well as in the sync backend.
352
-
353
- Example `eventlog.db`:
354
-
355
- ![](https://share.cleanshot.com/R6ny879w+)
@@ -1,5 +0,0 @@
1
- # AI agent
2
-
3
- LiveStore is a great fit for building AI agents.
4
-
5
- TODO: actually write this section