@livestore/react 0.4.0-dev.21 → 0.4.0-dev.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.md +1 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/StoreRegistryContext.d.ts +56 -0
  4. package/dist/StoreRegistryContext.d.ts.map +1 -0
  5. package/dist/StoreRegistryContext.js +61 -0
  6. package/dist/StoreRegistryContext.js.map +1 -0
  7. package/dist/__tests__/fixture.d.ts +8 -280
  8. package/dist/__tests__/fixture.d.ts.map +1 -1
  9. package/dist/__tests__/fixture.js +9 -84
  10. package/dist/__tests__/fixture.js.map +1 -1
  11. package/dist/experimental/components/LiveList.d.ts +4 -2
  12. package/dist/experimental/components/LiveList.d.ts.map +1 -1
  13. package/dist/experimental/components/LiveList.js +9 -7
  14. package/dist/experimental/components/LiveList.js.map +1 -1
  15. package/dist/experimental/mod.d.ts +0 -1
  16. package/dist/experimental/mod.d.ts.map +1 -1
  17. package/dist/experimental/mod.js +0 -1
  18. package/dist/experimental/mod.js.map +1 -1
  19. package/dist/mod.d.ts +8 -5
  20. package/dist/mod.d.ts.map +1 -1
  21. package/dist/mod.js +6 -4
  22. package/dist/mod.js.map +1 -1
  23. package/dist/useClientDocument.d.ts +1 -26
  24. package/dist/useClientDocument.d.ts.map +1 -1
  25. package/dist/useClientDocument.js +3 -17
  26. package/dist/useClientDocument.js.map +1 -1
  27. package/dist/useClientDocument.test.js +12 -4
  28. package/dist/useClientDocument.test.js.map +1 -1
  29. package/dist/useQuery.d.ts +4 -5
  30. package/dist/useQuery.d.ts.map +1 -1
  31. package/dist/useQuery.js +12 -85
  32. package/dist/useQuery.js.map +1 -1
  33. package/dist/useQuery.test.js +7 -8
  34. package/dist/useQuery.test.js.map +1 -1
  35. package/dist/useRcResource.d.ts.map +1 -1
  36. package/dist/useRcResource.js +9 -5
  37. package/dist/useRcResource.js.map +1 -1
  38. package/dist/useRcResource.test.js +1 -1
  39. package/dist/useRcResource.test.js.map +1 -1
  40. package/dist/useStore.d.ts +61 -46
  41. package/dist/useStore.d.ts.map +1 -1
  42. package/dist/useStore.js +75 -60
  43. package/dist/useStore.js.map +1 -1
  44. package/dist/useStore.test.d.ts.map +1 -0
  45. package/dist/{experimental/multi-store/useStore.test.js → useStore.test.js} +70 -27
  46. package/dist/useStore.test.js.map +1 -0
  47. package/dist/useSyncStatus.d.ts +22 -0
  48. package/dist/useSyncStatus.d.ts.map +1 -0
  49. package/dist/useSyncStatus.js +28 -0
  50. package/dist/useSyncStatus.js.map +1 -0
  51. package/package.json +69 -26
  52. package/src/StoreRegistryContext.tsx +70 -0
  53. package/src/__snapshots__/useClientDocument.test.tsx.snap +112 -78
  54. package/src/__tests__/fixture.tsx +23 -118
  55. package/src/experimental/components/LiveList.tsx +22 -9
  56. package/src/experimental/mod.ts +0 -1
  57. package/src/mod.ts +8 -12
  58. package/src/useClientDocument.test.tsx +16 -6
  59. package/src/useClientDocument.ts +7 -61
  60. package/src/useQuery.test.tsx +8 -8
  61. package/src/useQuery.ts +30 -119
  62. package/src/useRcResource.test.tsx +1 -1
  63. package/src/useRcResource.ts +10 -5
  64. package/src/{experimental/multi-store/useStore.test.tsx → useStore.test.tsx} +117 -39
  65. package/src/useStore.ts +106 -65
  66. package/src/useSyncStatus.ts +34 -0
  67. package/dist/LiveStoreContext.d.ts +0 -40
  68. package/dist/LiveStoreContext.d.ts.map +0 -1
  69. package/dist/LiveStoreContext.js +0 -21
  70. package/dist/LiveStoreContext.js.map +0 -1
  71. package/dist/LiveStoreProvider.d.ts +0 -73
  72. package/dist/LiveStoreProvider.d.ts.map +0 -1
  73. package/dist/LiveStoreProvider.js +0 -233
  74. package/dist/LiveStoreProvider.js.map +0 -1
  75. package/dist/LiveStoreProvider.test.d.ts +0 -2
  76. package/dist/LiveStoreProvider.test.d.ts.map +0 -1
  77. package/dist/LiveStoreProvider.test.js +0 -117
  78. package/dist/LiveStoreProvider.test.js.map +0 -1
  79. package/dist/experimental/multi-store/StoreRegistry.d.ts +0 -105
  80. package/dist/experimental/multi-store/StoreRegistry.d.ts.map +0 -1
  81. package/dist/experimental/multi-store/StoreRegistry.js +0 -184
  82. package/dist/experimental/multi-store/StoreRegistry.js.map +0 -1
  83. package/dist/experimental/multi-store/StoreRegistry.test.d.ts +0 -2
  84. package/dist/experimental/multi-store/StoreRegistry.test.d.ts.map +0 -1
  85. package/dist/experimental/multi-store/StoreRegistry.test.js +0 -381
  86. package/dist/experimental/multi-store/StoreRegistry.test.js.map +0 -1
  87. package/dist/experimental/multi-store/StoreRegistryContext.d.ts +0 -10
  88. package/dist/experimental/multi-store/StoreRegistryContext.d.ts.map +0 -1
  89. package/dist/experimental/multi-store/StoreRegistryContext.js +0 -15
  90. package/dist/experimental/multi-store/StoreRegistryContext.js.map +0 -1
  91. package/dist/experimental/multi-store/mod.d.ts +0 -6
  92. package/dist/experimental/multi-store/mod.d.ts.map +0 -1
  93. package/dist/experimental/multi-store/mod.js +0 -6
  94. package/dist/experimental/multi-store/mod.js.map +0 -1
  95. package/dist/experimental/multi-store/storeOptions.d.ts +0 -4
  96. package/dist/experimental/multi-store/storeOptions.d.ts.map +0 -1
  97. package/dist/experimental/multi-store/storeOptions.js +0 -4
  98. package/dist/experimental/multi-store/storeOptions.js.map +0 -1
  99. package/dist/experimental/multi-store/types.d.ts +0 -25
  100. package/dist/experimental/multi-store/types.d.ts.map +0 -1
  101. package/dist/experimental/multi-store/types.js +0 -2
  102. package/dist/experimental/multi-store/types.js.map +0 -1
  103. package/dist/experimental/multi-store/useStore.d.ts +0 -11
  104. package/dist/experimental/multi-store/useStore.d.ts.map +0 -1
  105. package/dist/experimental/multi-store/useStore.js +0 -16
  106. package/dist/experimental/multi-store/useStore.js.map +0 -1
  107. package/dist/experimental/multi-store/useStore.test.d.ts.map +0 -1
  108. package/dist/experimental/multi-store/useStore.test.js.map +0 -1
  109. package/dist/utils/stack-info.d.ts +0 -4
  110. package/dist/utils/stack-info.d.ts.map +0 -1
  111. package/dist/utils/stack-info.js +0 -10
  112. package/dist/utils/stack-info.js.map +0 -1
  113. package/src/LiveStoreContext.ts +0 -41
  114. package/src/LiveStoreProvider.test.tsx +0 -248
  115. package/src/LiveStoreProvider.tsx +0 -430
  116. package/src/ambient.d.ts +0 -1
  117. package/src/experimental/multi-store/StoreRegistry.test.ts +0 -518
  118. package/src/experimental/multi-store/StoreRegistry.ts +0 -253
  119. package/src/experimental/multi-store/StoreRegistryContext.tsx +0 -23
  120. package/src/experimental/multi-store/mod.ts +0 -5
  121. package/src/experimental/multi-store/storeOptions.ts +0 -8
  122. package/src/experimental/multi-store/types.ts +0 -37
  123. package/src/experimental/multi-store/useStore.ts +0 -26
  124. package/src/utils/stack-info.ts +0 -13
  125. /package/dist/{experimental/multi-store/useStore.test.d.ts → useStore.test.d.ts} +0 -0
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ /**
3
+ * React hook that subscribes to sync status changes.
4
+ *
5
+ * Returns the current synchronization status between the client session and
6
+ * the leader thread. The component re-renders whenever the sync status changes.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * function SyncIndicator() {
11
+ * const status = store.useSyncStatus()
12
+ * return <span>{status.isSynced ? '✓ Synced' : `Syncing (${status.pendingCount} pending)...`}</span>
13
+ * }
14
+ * ```
15
+ *
16
+ * @param options - Options containing the store instance
17
+ * @returns The current sync status
18
+ */
19
+ export const useSyncStatus = (options) => {
20
+ const { store } = options;
21
+ const [status, setStatus] = React.useState(() => store.syncStatus());
22
+ React.useEffect(() => {
23
+ return store.subscribeSyncStatus(setStatus);
24
+ }, [store]);
25
+ React.useDebugValue(`LiveStore:useSyncStatus:${status.isSynced === true ? 'synced' : 'pending'}`);
26
+ return status;
27
+ };
28
+ //# sourceMappingURL=useSyncStatus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSyncStatus.js","sourceRoot":"","sources":["../src/useSyncStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,OAA8B,EAAc,EAAE;IAC1E,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAA;IAEzB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAa,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAA;IAEhF,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,OAAO,KAAK,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAA;IAC7C,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,KAAK,CAAC,aAAa,CAAC,2BAA2B,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAA;IAEjG,OAAO,MAAM,CAAA;AACf,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,45 +1,88 @@
1
1
  {
2
2
  "name": "@livestore/react",
3
- "version": "0.4.0-dev.21",
3
+ "version": "0.4.0-dev.23",
4
+ "license": "Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/livestorejs/livestore.git"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "package.json",
12
+ "src"
13
+ ],
4
14
  "type": "module",
5
15
  "sideEffects": false,
6
16
  "exports": {
7
17
  ".": "./dist/mod.js",
8
18
  "./experimental": "./dist/experimental/mod.js"
9
19
  },
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
10
23
  "dependencies": {
11
24
  "@opentelemetry/api": "1.9.0",
12
- "@livestore/common": "0.4.0-dev.21",
13
- "@livestore/utils": "0.4.0-dev.21",
14
- "@livestore/livestore": "0.4.0-dev.21"
25
+ "@livestore/common": "^0.4.0-dev.23",
26
+ "@livestore/framework-toolkit": "^0.4.0-dev.23",
27
+ "@livestore/livestore": "^0.4.0-dev.23",
28
+ "@livestore/utils": "^0.4.0-dev.23"
15
29
  },
16
30
  "devDependencies": {
17
- "@opentelemetry/sdk-trace-base": "2.0.1",
18
- "@testing-library/dom": "^10.4.1",
19
- "@testing-library/react": "^16.3.0",
20
- "@types/react": "19.1.13",
21
- "@types/react-dom": "19.1.9",
22
- "jsdom": "^26.1.0",
23
- "react": "19.1.0",
24
- "react-dom": "19.1.0",
25
- "react-window": "^1.8.11",
26
- "typescript": "5.9.2",
27
- "vite": "7.2.4",
31
+ "@opentelemetry/sdk-trace-base": "2.2.0",
32
+ "@testing-library/dom": "10.4.1",
33
+ "@testing-library/react": "16.3.1",
34
+ "@types/react": "19.2.7",
35
+ "@types/react-dom": "19.2.3",
36
+ "@types/react-window": "1.8.8",
37
+ "jsdom": "26.1.0",
38
+ "react": "19.2.3",
39
+ "react-dom": "19.2.3",
40
+ "react-window": "1.8.11",
41
+ "typescript": "5.9.3",
42
+ "vite": "7.3.1",
28
43
  "vitest": "3.2.4",
29
- "@livestore/adapter-web": "0.4.0-dev.21",
30
- "@livestore/utils-dev": "0.4.0-dev.21"
44
+ "@livestore/adapter-web": "^0.4.0-dev.23",
45
+ "@livestore/utils-dev": "^0.4.0-dev.23"
31
46
  },
32
- "files": [
33
- "package.json",
34
- "src",
35
- "dist"
36
- ],
37
- "license": "Apache-2.0",
38
47
  "peerDependencies": {
39
- "react": "^19.1.0"
48
+ "@effect/ai": "^0.35.0",
49
+ "@effect/cli": "^0.75.1",
50
+ "@effect/cluster": "^0.58.2",
51
+ "@effect/experimental": "^0.60.0",
52
+ "@effect/opentelemetry": "^0.63.0",
53
+ "@effect/platform": "^0.96.1",
54
+ "@effect/platform-browser": "^0.76.0",
55
+ "@effect/platform-bun": "^0.89.0",
56
+ "@effect/platform-node": "^0.106.0",
57
+ "@effect/printer": "^0.49.0",
58
+ "@effect/printer-ansi": "^0.49.0",
59
+ "@effect/rpc": "^0.75.1",
60
+ "@effect/sql": "^0.51.1",
61
+ "@effect/typeclass": "^0.40.0",
62
+ "@effect/vitest": "^0.29.0",
63
+ "@opentelemetry/api": "^1.9.0",
64
+ "@opentelemetry/resources": "^2.2.0",
65
+ "@standard-schema/spec": "^1.1.0",
66
+ "effect": "^3.21.2",
67
+ "react": "^19.0.0"
40
68
  },
41
- "publishConfig": {
42
- "access": "public"
69
+ "$genie": {
70
+ "source": "package.json.genie.ts",
71
+ "warning": "DO NOT EDIT - changes will be overwritten",
72
+ "workspaceClosureDirs": [
73
+ "packages/@livestore/adapter-web",
74
+ "packages/@livestore/common",
75
+ "packages/@livestore/common-cf",
76
+ "packages/@livestore/devtools-web-common",
77
+ "packages/@livestore/framework-toolkit",
78
+ "packages/@livestore/livestore",
79
+ "packages/@livestore/react",
80
+ "packages/@livestore/sqlite-wasm",
81
+ "packages/@livestore/utils",
82
+ "packages/@livestore/utils-dev",
83
+ "packages/@livestore/wa-sqlite",
84
+ "packages/@livestore/webmesh"
85
+ ]
43
86
  },
44
87
  "scripts": {
45
88
  "build": "tsc",
@@ -0,0 +1,70 @@
1
+ import * as React from 'react'
2
+
3
+ import type { StoreRegistry } from '@livestore/livestore'
4
+
5
+ export const StoreRegistryContext = React.createContext<StoreRegistry | undefined>(undefined)
6
+
7
+ export type StoreRegistryProviderProps = {
8
+ storeRegistry: StoreRegistry
9
+ children: React.ReactNode
10
+ }
11
+
12
+ /**
13
+ * React context provider that makes a {@link StoreRegistry} available to descendant components.
14
+ *
15
+ * Wrap your application (or a subtree) with this provider to enable {@link useStore} and
16
+ * {@link useStoreRegistry} hooks within that tree.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * import { StoreRegistry } from '@livestore/livestore'
21
+ * import { StoreRegistryProvider } from '@livestore/react'
22
+ * import { unstable_batchedUpdates as batchUpdates } from 'react-dom'
23
+ *
24
+ * const storeRegistry = new StoreRegistry({
25
+ * defaultOptions: { batchUpdates }
26
+ * })
27
+ *
28
+ * function App() {
29
+ * return (
30
+ * <StoreRegistryProvider storeRegistry={storeRegistry}>
31
+ * <MyComponent />
32
+ * </StoreRegistryProvider>
33
+ * )
34
+ * }
35
+ * ```
36
+ */
37
+ export const StoreRegistryProvider = ({ storeRegistry, children }: StoreRegistryProviderProps): React.JSX.Element => {
38
+ return <StoreRegistryContext value={storeRegistry}>{children}</StoreRegistryContext>
39
+ }
40
+
41
+ /**
42
+ * Hook to access the {@link StoreRegistry} from context. Useful for advanced operations like preloading.
43
+ *
44
+ * @param override - Optional registry to use instead of the context value.
45
+ * When provided, skips context lookup entirely.
46
+ * @returns The registry provided by the nearest {@link StoreRegistryProvider} ancestor, or the `override` if provided.
47
+ * @throws Error if called outside a {@link StoreRegistryProvider} and no override is provided
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * function PreloadButton({ issueId }: { issueId: string }) {
52
+ * const storeRegistry = useStoreRegistry()
53
+ *
54
+ * const handleMouseEnter = () => {
55
+ * storeRegistry.preload(issueStoreOptions(issueId))
56
+ * }
57
+ *
58
+ * return <button onMouseEnter={handleMouseEnter}>View Issue</button>
59
+ * }
60
+ * ```
61
+ */
62
+ export const useStoreRegistry = (override?: StoreRegistry) => {
63
+ if (override !== undefined) return override
64
+
65
+ const storeRegistry = React.use(StoreRegistryContext)
66
+
67
+ if (storeRegistry == null) throw new Error('useStoreRegistry() must be used within <StoreRegistryProvider>')
68
+
69
+ return storeRegistry
70
+ }
@@ -8,6 +8,9 @@ exports[`useClientDocument > otel > should update the data based on component ke
8
8
  "storeId": "default",
9
9
  },
10
10
  "children": [
11
+ {
12
+ "_name": "makeClientSessionSyncProcessor",
13
+ },
11
14
  {
12
15
  "_name": "livestore.in-memory-db:execute",
13
16
  "attributes": {
@@ -21,29 +24,31 @@ exports[`useClientDocument > otel > should update the data based on component ke
21
24
  },
22
25
  },
23
26
  {
24
- "_name": "@livestore/common:LeaderSyncProcessor:push",
25
- "attributes": {
26
- "batch": "undefined",
27
- "batchSize": 1,
28
- },
29
- },
30
- {
31
- "_name": "@livestore/common:LeaderSyncProcessor:push",
32
- "attributes": {
33
- "batch": "undefined",
34
- "batchSize": 1,
35
- },
36
- },
37
- {
38
- "_name": "client-session-sync-processor:pull",
39
- "attributes": {
40
- "code.stacktrace": "<STACKTRACE>",
41
- "span.label": "⚠︎ Interrupted",
42
- "status.interrupted": true,
43
- },
44
- },
45
- {
46
- "_name": "LiveStore:sync",
27
+ "_name": "client-session-sync-processor:boot",
28
+ "children": [
29
+ {
30
+ "_name": "@livestore/common:LeaderSyncProcessor:push",
31
+ "attributes": {
32
+ "batch": "undefined",
33
+ "batchSize": 1,
34
+ },
35
+ },
36
+ {
37
+ "_name": "@livestore/common:LeaderSyncProcessor:push",
38
+ "attributes": {
39
+ "batch": "undefined",
40
+ "batchSize": 1,
41
+ },
42
+ },
43
+ {
44
+ "_name": "client-session-sync-processor:pull",
45
+ "attributes": {
46
+ "code.stacktrace": "<STACKTRACE>",
47
+ "span.label": "⚠︎ Interrupted",
48
+ "status.interrupted": true,
49
+ },
50
+ },
51
+ ],
47
52
  },
48
53
  {
49
54
  "_name": "LiveStore:commits",
@@ -194,14 +199,10 @@ exports[`useClientDocument > otel > should update the data based on component ke
194
199
  },
195
200
  "children": [
196
201
  {
197
- "_name": "client-session-sync-processor:push",
198
- "attributes": {
199
- "batchSize": 1,
200
- "eventCounts": "{
201
- "UserInfoSet": 1
202
- }",
203
- "mergeResultTag": "advance",
204
- },
202
+ "_name": "client-session-sync-processor:encode-events",
203
+ },
204
+ {
205
+ "_name": "client-session-sync-processor:materialize-events",
205
206
  "children": [
206
207
  {
207
208
  "_name": "client-session-sync-processor:materialize-event",
@@ -220,6 +221,16 @@ exports[`useClientDocument > otel > should update the data based on component ke
220
221
  },
221
222
  ],
222
223
  },
224
+ {
225
+ "_name": "client-session-sync-processor:push",
226
+ "attributes": {
227
+ "batchSize": 1,
228
+ "eventCounts": "{
229
+ "UserInfoSet": 1
230
+ }",
231
+ "mergeResultTag": "advance",
232
+ },
233
+ },
223
234
  ],
224
235
  },
225
236
  {
@@ -232,14 +243,10 @@ exports[`useClientDocument > otel > should update the data based on component ke
232
243
  },
233
244
  "children": [
234
245
  {
235
- "_name": "client-session-sync-processor:push",
236
- "attributes": {
237
- "batchSize": 1,
238
- "eventCounts": "{
239
- "UserInfoSet": 1
240
- }",
241
- "mergeResultTag": "advance",
242
- },
246
+ "_name": "client-session-sync-processor:encode-events",
247
+ },
248
+ {
249
+ "_name": "client-session-sync-processor:materialize-events",
243
250
  "children": [
244
251
  {
245
252
  "_name": "client-session-sync-processor:materialize-event",
@@ -258,6 +265,16 @@ exports[`useClientDocument > otel > should update the data based on component ke
258
265
  },
259
266
  ],
260
267
  },
268
+ {
269
+ "_name": "client-session-sync-processor:push",
270
+ "attributes": {
271
+ "batchSize": 1,
272
+ "eventCounts": "{
273
+ "UserInfoSet": 1
274
+ }",
275
+ "mergeResultTag": "advance",
276
+ },
277
+ },
261
278
  ],
262
279
  },
263
280
  ]
@@ -271,6 +288,9 @@ exports[`useClientDocument > otel > should update the data based on component ke
271
288
  "storeId": "default",
272
289
  },
273
290
  "children": [
291
+ {
292
+ "_name": "makeClientSessionSyncProcessor",
293
+ },
274
294
  {
275
295
  "_name": "livestore.in-memory-db:execute",
276
296
  "attributes": {
@@ -284,29 +304,31 @@ exports[`useClientDocument > otel > should update the data based on component ke
284
304
  },
285
305
  },
286
306
  {
287
- "_name": "@livestore/common:LeaderSyncProcessor:push",
288
- "attributes": {
289
- "batch": "undefined",
290
- "batchSize": 1,
291
- },
292
- },
293
- {
294
- "_name": "@livestore/common:LeaderSyncProcessor:push",
295
- "attributes": {
296
- "batch": "undefined",
297
- "batchSize": 1,
298
- },
299
- },
300
- {
301
- "_name": "client-session-sync-processor:pull",
302
- "attributes": {
303
- "code.stacktrace": "<STACKTRACE>",
304
- "span.label": "⚠︎ Interrupted",
305
- "status.interrupted": true,
306
- },
307
- },
308
- {
309
- "_name": "LiveStore:sync",
307
+ "_name": "client-session-sync-processor:boot",
308
+ "children": [
309
+ {
310
+ "_name": "@livestore/common:LeaderSyncProcessor:push",
311
+ "attributes": {
312
+ "batch": "undefined",
313
+ "batchSize": 1,
314
+ },
315
+ },
316
+ {
317
+ "_name": "@livestore/common:LeaderSyncProcessor:push",
318
+ "attributes": {
319
+ "batch": "undefined",
320
+ "batchSize": 1,
321
+ },
322
+ },
323
+ {
324
+ "_name": "client-session-sync-processor:pull",
325
+ "attributes": {
326
+ "code.stacktrace": "<STACKTRACE>",
327
+ "span.label": "⚠︎ Interrupted",
328
+ "status.interrupted": true,
329
+ },
330
+ },
331
+ ],
310
332
  },
311
333
  {
312
334
  "_name": "LiveStore:commits",
@@ -395,14 +417,10 @@ exports[`useClientDocument > otel > should update the data based on component ke
395
417
  },
396
418
  "children": [
397
419
  {
398
- "_name": "client-session-sync-processor:push",
399
- "attributes": {
400
- "batchSize": 1,
401
- "eventCounts": "{
402
- "UserInfoSet": 1
403
- }",
404
- "mergeResultTag": "advance",
405
- },
420
+ "_name": "client-session-sync-processor:encode-events",
421
+ },
422
+ {
423
+ "_name": "client-session-sync-processor:materialize-events",
406
424
  "children": [
407
425
  {
408
426
  "_name": "client-session-sync-processor:materialize-event",
@@ -421,6 +439,16 @@ exports[`useClientDocument > otel > should update the data based on component ke
421
439
  },
422
440
  ],
423
441
  },
442
+ {
443
+ "_name": "client-session-sync-processor:push",
444
+ "attributes": {
445
+ "batchSize": 1,
446
+ "eventCounts": "{
447
+ "UserInfoSet": 1
448
+ }",
449
+ "mergeResultTag": "advance",
450
+ },
451
+ },
424
452
  ],
425
453
  },
426
454
  {
@@ -433,14 +461,10 @@ exports[`useClientDocument > otel > should update the data based on component ke
433
461
  },
434
462
  "children": [
435
463
  {
436
- "_name": "client-session-sync-processor:push",
437
- "attributes": {
438
- "batchSize": 1,
439
- "eventCounts": "{
440
- "UserInfoSet": 1
441
- }",
442
- "mergeResultTag": "advance",
443
- },
464
+ "_name": "client-session-sync-processor:encode-events",
465
+ },
466
+ {
467
+ "_name": "client-session-sync-processor:materialize-events",
444
468
  "children": [
445
469
  {
446
470
  "_name": "client-session-sync-processor:materialize-event",
@@ -459,6 +483,16 @@ exports[`useClientDocument > otel > should update the data based on component ke
459
483
  },
460
484
  ],
461
485
  },
486
+ {
487
+ "_name": "client-session-sync-processor:push",
488
+ "attributes": {
489
+ "batchSize": 1,
490
+ "eventCounts": "{
491
+ "UserInfoSet": 1
492
+ }",
493
+ "mergeResultTag": "advance",
494
+ },
495
+ },
462
496
  ],
463
497
  },
464
498
  ]
@@ -1,110 +1,32 @@
1
- import { makeInMemoryAdapter } from '@livestore/adapter-web'
2
- import { provideOtel, type UnknownError } from '@livestore/common'
3
- import { Events, makeSchema, State } from '@livestore/common/schema'
4
- import type { LiveStoreSchema, SqliteDsl, Store } from '@livestore/livestore'
5
- import { createStore } from '@livestore/livestore'
6
- import { omitUndefineds } from '@livestore/utils'
7
- import { Effect, Schema, type Scope } from '@livestore/utils/effect'
8
- import type * as otel from '@opentelemetry/api'
1
+ import type { UnknownError } from '@livestore/common'
2
+ import {
3
+ type AppState,
4
+ type CreateTodoMvcStoreOptions,
5
+ createTodoMvcStore,
6
+ events,
7
+ type Filter,
8
+ schema,
9
+ type Todo,
10
+ tables,
11
+ } from '@livestore/framework-toolkit/testing'
12
+ import type { Store } from '@livestore/livestore'
13
+ import { Effect, type Scope } from '@livestore/utils/effect'
9
14
  import React from 'react'
10
15
 
11
16
  import * as LiveStoreReact from '../mod.ts'
12
17
 
13
- export type Todo = {
14
- id: string
15
- text: string
16
- completed: boolean
17
- }
18
-
19
- export type Filter = 'all' | 'active' | 'completed'
20
-
21
- export type AppState = {
22
- newTodoText: string
23
- filter: Filter
24
- }
25
-
26
- const todos = State.SQLite.table({
27
- name: 'todos',
28
- columns: {
29
- id: State.SQLite.text({ primaryKey: true }),
30
- text: State.SQLite.text({ default: '', nullable: false }),
31
- completed: State.SQLite.boolean({ default: false, nullable: false }),
32
- },
33
- })
34
-
35
- const app = State.SQLite.table({
36
- name: 'app',
37
- columns: {
38
- id: State.SQLite.text({ primaryKey: true, default: 'static' }),
39
- newTodoText: State.SQLite.text({ default: '', nullable: true }),
40
- filter: State.SQLite.text({ default: 'all', nullable: false }),
41
- },
42
- })
18
+ // Re-export shared types and schema
19
+ export { events, schema, tables }
20
+ export type { AppState, Filter, Todo }
43
21
 
44
- const userInfo = State.SQLite.clientDocument({
45
- name: 'UserInfo',
46
- schema: Schema.Struct({
47
- username: Schema.String,
48
- text: Schema.String,
49
- }),
50
- default: { value: { username: '', text: '' } },
51
- })
52
-
53
- const AppRouterSchema = State.SQLite.clientDocument({
54
- name: 'AppRouter',
55
- schema: Schema.Struct({
56
- currentTaskId: Schema.String.pipe(Schema.NullOr),
57
- }),
58
- default: {
59
- value: { currentTaskId: null },
60
- id: 'singleton',
61
- },
62
- })
63
-
64
- const kv = State.SQLite.clientDocument({
65
- name: 'Kv',
66
- schema: Schema.Any,
67
- default: { value: null },
68
- })
69
-
70
- export const events = {
71
- todoCreated: Events.synced({
72
- name: 'todoCreated',
73
- schema: Schema.Struct({ id: Schema.String, text: Schema.String, completed: Schema.Boolean }),
74
- }),
75
- todoUpdated: Events.synced({
76
- name: 'todoUpdated',
77
- schema: Schema.Struct({
78
- id: Schema.String,
79
- text: Schema.String.pipe(Schema.optional),
80
- completed: Schema.Boolean.pipe(Schema.optional),
81
- }),
82
- }),
83
- AppRouterSet: AppRouterSchema.set,
84
- UserInfoSet: userInfo.set,
85
- KvSet: kv.set,
86
- }
87
-
88
- const materializers = State.SQLite.materializers(events, {
89
- todoCreated: ({ id, text, completed }) => todos.insert({ id, text, completed }),
90
- todoUpdated: ({ id, text, completed }) => todos.update({ ...omitUndefineds({ completed, text }) }).where({ id }),
91
- })
92
-
93
- export const tables = { todos, app, userInfo, AppRouterSchema, kv }
94
-
95
- const state = State.SQLite.makeState({ tables, materializers })
96
- export const schema = makeSchema({ state, events })
97
-
98
- export type MakeTodoMvcReactOptions = {
99
- otelTracer?: otel.Tracer | undefined
100
- otelContext?: otel.Context | undefined
22
+ export type MakeTodoMvcReactOptions = CreateTodoMvcStoreOptions & {
101
23
  strictMode?: boolean | undefined
102
24
  }
103
25
 
104
26
  export const makeTodoMvcReact: (opts?: MakeTodoMvcReactOptions) => Effect.Effect<
105
27
  {
106
28
  wrapper: ({ children }: any) => React.JSX.Element
107
- store: Store<LiveStoreSchema<SqliteDsl.DbSchema, State.SQLite.EventDefRecord>, {}> & LiveStoreReact.ReactApi
29
+ store: Store<typeof schema> & LiveStoreReact.ReactApi
108
30
  renderCount: { readonly val: number; inc: () => void }
109
31
  },
110
32
  UnknownError,
@@ -116,7 +38,7 @@ export const makeTodoMvcReact: (opts?: MakeTodoMvcReactOptions) => Effect.Effect
116
38
  let val = 0
117
39
 
118
40
  const inc = () => {
119
- val += strictMode ? 0.5 : 1
41
+ val += strictMode === true ? 0.5 : 1
120
42
  }
121
43
 
122
44
  return {
@@ -127,32 +49,15 @@ export const makeTodoMvcReact: (opts?: MakeTodoMvcReactOptions) => Effect.Effect
127
49
  }
128
50
  }
129
51
 
130
- const store: Store<any> = yield* createStore({
131
- schema,
132
- storeId: 'default',
133
- adapter: makeInMemoryAdapter(),
134
- debug: { instanceId: 'test' },
135
- })
52
+ const store = yield* createTodoMvcStore(opts)
136
53
 
137
54
  const storeWithReactApi = LiveStoreReact.withReactApi(store)
138
55
 
139
- // TODO improve typing of `LiveStoreContext`
140
- const storeContext = {
141
- stage: 'running' as const,
142
- store: storeWithReactApi,
143
- }
144
-
145
- const MaybeStrictMode = strictMode ? React.StrictMode : React.Fragment
56
+ const MaybeStrictMode = strictMode === true ? React.StrictMode : React.Fragment
146
57
 
147
- const wrapper = ({ children }: any) => (
148
- <MaybeStrictMode>
149
- <LiveStoreReact.LiveStoreContext.Provider value={storeContext}>
150
- {children}
151
- </LiveStoreReact.LiveStoreContext.Provider>
152
- </MaybeStrictMode>
153
- )
58
+ const wrapper = ({ children }: any) => <MaybeStrictMode>{children}</MaybeStrictMode>
154
59
 
155
60
  const renderCount = makeRenderCount()
156
61
 
157
62
  return { wrapper, store: storeWithReactApi, renderCount }
158
- }).pipe(provideOtel(omitUndefineds({ parentSpanContext: opts.otelContext, otelTracer: opts.otelTracer })))
63
+ })