@livestore/react 0.2.0 → 0.3.0-dev.10

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 (38) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/LiveStoreProvider.d.ts +6 -4
  3. package/dist/LiveStoreProvider.d.ts.map +1 -1
  4. package/dist/LiveStoreProvider.js +45 -28
  5. package/dist/LiveStoreProvider.js.map +1 -1
  6. package/dist/LiveStoreProvider.test.js +8 -2
  7. package/dist/LiveStoreProvider.test.js.map +1 -1
  8. package/dist/__tests__/fixture.d.ts +1 -2
  9. package/dist/__tests__/fixture.d.ts.map +1 -1
  10. package/dist/__tests__/fixture.js +6 -10
  11. package/dist/__tests__/fixture.js.map +1 -1
  12. package/dist/useQuery.d.ts +1 -1
  13. package/dist/useQuery.d.ts.map +1 -1
  14. package/dist/useQuery.js.map +1 -1
  15. package/dist/useRow.js.map +1 -1
  16. package/dist/useRow.test.js +13 -18
  17. package/dist/useRow.test.js.map +1 -1
  18. package/dist/useScopedQuery.d.ts +1 -1
  19. package/dist/useScopedQuery.d.ts.map +1 -1
  20. package/dist/useScopedQuery.js +2 -1
  21. package/dist/useScopedQuery.js.map +1 -1
  22. package/dist/utils/useStateRefWithReactiveInput.d.ts +1 -1
  23. package/dist/utils/useStateRefWithReactiveInput.d.ts.map +1 -1
  24. package/dist/utils/useStateRefWithReactiveInput.js.map +1 -1
  25. package/package.json +18 -17
  26. package/src/LiveStoreProvider.test.tsx +13 -2
  27. package/src/LiveStoreProvider.tsx +68 -36
  28. package/src/__snapshots__/useRow.test.tsx.snap +54 -53
  29. package/src/__tests__/fixture.tsx +6 -11
  30. package/src/useQuery.ts +1 -1
  31. package/src/useRow.test.tsx +71 -71
  32. package/src/useRow.ts +1 -1
  33. package/src/useScopedQuery.ts +3 -2
  34. package/src/utils/useStateRefWithReactiveInput.ts +1 -1
  35. package/dist/useTemporaryQuery.d.ts +0 -22
  36. package/dist/useTemporaryQuery.d.ts.map +0 -1
  37. package/dist/useTemporaryQuery.js +0 -75
  38. package/dist/useTemporaryQuery.js.map +0 -1
@@ -9,5 +9,5 @@ import React from 'react';
9
9
  * - Also see this Tweet for more potential problems: https://twitter.com/schickling/status/1677317711104278528
10
10
  *
11
11
  */
12
- export declare const useStateRefWithReactiveInput: <T>(inputState: T) => [React.MutableRefObject<T>, (newState: T | ((prev: T) => T)) => void];
12
+ export declare const useStateRefWithReactiveInput: <T>(inputState: T) => [React.RefObject<T>, (newState: T | ((prev: T) => T)) => void];
13
13
  //# sourceMappingURL=useStateRefWithReactiveInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useStateRefWithReactiveInput.d.ts","sourceRoot":"","sources":["../../src/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,cAChC,CAAC,KACZ,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAwBtE,CAAA"}
1
+ {"version":3,"file":"useStateRefWithReactiveInput.d.ts","sourceRoot":"","sources":["../../src/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,cAChC,CAAC,KACZ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAwB/D,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"useStateRefWithReactiveInput.js","sourceRoot":"","sources":["../../src/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,UAAa,EAC0D,EAAE;IACzE,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IAEvC,MAAM,sBAAsB,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAE5C,IAAI,sBAAsB,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAClD,sBAAsB,CAAC,OAAO,GAAG,UAAU,CAAA;QAE3C,qHAAqH;QACrH,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAA;IAC/B,CAAC;IAED,MAAM,mBAAmB,GAAG,KAAK,CAAC,WAAW,CAC3C,CAAC,QAA8B,EAAE,EAAE;QACjC,wEAAwE;QACxE,MAAM,GAAG,GAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;QAClF,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAA;QACtB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACxB,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,OAAO,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;AACxC,CAAC,CAAA;AAED,yGAAyG;AACzG,iFAAiF;AACjF,4GAA4G;AAC5G,yEAAyE;AAEzE,wCAAwC;AACxC,mCAAmC;AACnC,MAAM;AAEN,6CAA6C;AAC7C,IAAI"}
1
+ {"version":3,"file":"useStateRefWithReactiveInput.js","sourceRoot":"","sources":["../../src/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,UAAa,EACmD,EAAE;IAClE,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IAEvC,MAAM,sBAAsB,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAE5C,IAAI,sBAAsB,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAClD,sBAAsB,CAAC,OAAO,GAAG,UAAU,CAAA;QAE3C,qHAAqH;QACrH,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAA;IAC/B,CAAC;IAED,MAAM,mBAAmB,GAAG,KAAK,CAAC,WAAW,CAC3C,CAAC,QAA8B,EAAE,EAAE;QACjC,wEAAwE;QACxE,MAAM,GAAG,GAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;QAClF,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAA;QACtB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACxB,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,OAAO,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;AACxC,CAAC,CAAA;AAED,yGAAyG;AACzG,iFAAiF;AACjF,4GAA4G;AAC5G,yEAAyE;AAEzE,wCAAwC;AACxC,mCAAmC;AACnC,MAAM;AAEN,6CAA6C;AAC7C,IAAI"}
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@livestore/react",
3
- "version": "0.2.0",
3
+ "version": "0.3.0-dev.10",
4
4
  "type": "module",
5
+ "sideEffects": false,
5
6
  "exports": {
6
7
  ".": {
7
8
  "types": "./dist/mod.d.ts",
@@ -21,28 +22,28 @@
21
22
  }
22
23
  },
23
24
  "dependencies": {
24
- "@opentelemetry/api": "^1.9.0",
25
- "@livestore/utils": "0.2.0",
26
- "@livestore/db-schema": "0.2.0",
27
- "@livestore/livestore": "0.2.0",
28
- "@livestore/common": "0.2.0"
25
+ "@opentelemetry/api": "1.9.0",
26
+ "@livestore/common": "0.3.0-dev.10",
27
+ "@livestore/livestore": "0.3.0-dev.10",
28
+ "@livestore/utils": "0.3.0-dev.10",
29
+ "@livestore/db-schema": "0.3.0-dev.10"
29
30
  },
30
31
  "devDependencies": {
31
- "@opentelemetry/sdk-trace-base": "1.27.0",
32
+ "@opentelemetry/sdk-trace-base": "^1.30.1",
32
33
  "@testing-library/react": "^16.0.1",
33
- "@types/react": "^18.3.12",
34
- "@types/react-dom": "^18.3.1",
35
- "jsdom": "^25.0.1",
36
- "react": "^18.3.1",
37
- "react-dom": "^18.3.1",
38
- "react-window": "^1.8.10",
39
- "typescript": "5.5.4",
40
- "vite": "5.4.10",
34
+ "@types/react": "^19.0.8",
35
+ "@types/react-dom": "^19.0.3",
36
+ "jsdom": "^26.0.0",
37
+ "react": "^19.0.0",
38
+ "react-dom": "^19.0.0",
39
+ "react-window": "^1.8.11",
40
+ "typescript": "^5.7.2",
41
+ "vite": "^6.0.11",
41
42
  "vitest": "^2.1.4",
42
- "@livestore/web": "0.2.0"
43
+ "@livestore/web": "0.3.0-dev.10"
43
44
  },
44
45
  "peerDependencies": {
45
- "react": "^18"
46
+ "react": "~19.0.0"
46
47
  },
47
48
  "publishConfig": {
48
49
  "access": "public"
@@ -1,4 +1,5 @@
1
1
  import { sql } from '@livestore/common'
2
+ import { rawSqlMutation } from '@livestore/common/schema'
2
3
  import { queryDb, type Store } from '@livestore/livestore'
3
4
  import { Schema } from '@livestore/utils/effect'
4
5
  import { makeInMemoryAdapter } from '@livestore/web'
@@ -30,7 +31,11 @@ describe('LiveStoreProvider', () => {
30
31
  const Root = ({ forceUpdate }: { forceUpdate: number }) => {
31
32
  const bootCb = React.useCallback(
32
33
  (store: Store) =>
33
- store.__execute(sql`INSERT OR IGNORE INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);`),
34
+ store.mutate(
35
+ rawSqlMutation({
36
+ sql: sql`INSERT OR IGNORE INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)`,
37
+ }),
38
+ ),
34
39
  [],
35
40
  )
36
41
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -69,6 +74,8 @@ describe('LiveStoreProvider', () => {
69
74
  await waitFor(() => screen.getByText('LiveStore Shutdown due to abort signal'))
70
75
  })
71
76
 
77
+ // TODO test aborting during boot
78
+
72
79
  it('error during boot', async () => {
73
80
  let appRenderCount = 0
74
81
 
@@ -81,7 +88,11 @@ describe('LiveStoreProvider', () => {
81
88
  const Root = ({ forceUpdate }: { forceUpdate: number }) => {
82
89
  const bootCb = React.useCallback(
83
90
  (store: Store) =>
84
- store.__execute(sql`INSERT INTO todos_mising_table (id, text, completed) VALUES ('t1', 'buy milk', 0);`),
91
+ store.mutate(
92
+ rawSqlMutation({
93
+ sql: sql`INSERT OR IGNORE INTO todos_missing_table (id, text, completed) VALUES ('t1', 'buy milk', 0)`,
94
+ }),
95
+ ),
85
96
  [],
86
97
  )
87
98
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1,5 +1,5 @@
1
1
  import type { Adapter, BootStatus, IntentionalShutdownCause } from '@livestore/common'
2
- import { UnexpectedError } from '@livestore/common'
2
+ import { provideOtel, UnexpectedError } from '@livestore/common'
3
3
  import type { LiveStoreSchema } from '@livestore/common/schema'
4
4
  import type {
5
5
  BaseGraphQLContext,
@@ -7,11 +7,13 @@ import type {
7
7
  GraphQLOptions,
8
8
  LiveStoreContext as StoreContext_,
9
9
  OtelOptions,
10
+ ShutdownDeferred,
10
11
  Store,
11
12
  } from '@livestore/livestore'
12
13
  import { createStore, StoreAbort, StoreInterrupted } from '@livestore/livestore'
13
- import { errorToString } from '@livestore/utils'
14
- import { Effect, FiberSet, Logger, LogLevel, Schema } from '@livestore/utils/effect'
14
+ import { errorToString, LS_DEV } from '@livestore/utils'
15
+ import type { OtelTracer } from '@livestore/utils/effect'
16
+ import { Deferred, Effect, Exit, identity, Logger, LogLevel, Schema, Scope, TaskTracing } from '@livestore/utils/effect'
15
17
  import type * as otel from '@opentelemetry/api'
16
18
  import type { ReactElement, ReactNode } from 'react'
17
19
  import React from 'react'
@@ -26,7 +28,7 @@ interface LiveStoreProviderProps<GraphQLContext extends BaseGraphQLContext> {
26
28
  *
27
29
  * The `storeId` is also used for persistence.
28
30
  *
29
- * Make sure to also provide `storeId` to `mountDevtools` in `_devtools.html`.
31
+ * Make sure to also configure `storeId` in LiveStore Devtools (e.g. in Vite plugin).
30
32
  *
31
33
  * @default 'default'
32
34
  */
@@ -34,9 +36,9 @@ interface LiveStoreProviderProps<GraphQLContext extends BaseGraphQLContext> {
34
36
  boot?: (
35
37
  store: Store<GraphQLContext, LiveStoreSchema>,
36
38
  parentSpan: otel.Span,
37
- ) => void | Promise<void> | Effect.Effect<void, unknown, otel.Tracer>
39
+ ) => void | Promise<void> | Effect.Effect<void, unknown, OtelTracer.OtelTracer>
38
40
  graphQLOptions?: GraphQLOptions<GraphQLContext>
39
- otelOptions?: OtelOptions
41
+ otelOptions?: Partial<OtelOptions>
40
42
  renderLoading: (status: BootStatus) => ReactElement
41
43
  renderError?: (error: UnexpectedError | unknown) => ReactElement
42
44
  renderShutdown?: (cause: IntentionalShutdownCause | StoreAbort) => ReactElement
@@ -69,7 +71,9 @@ const defaultRenderShutdown = (cause: IntentionalShutdownCause | StoreAbort) =>
69
71
  ? 'devtools import'
70
72
  : cause.reason === 'devtools-reset'
71
73
  ? 'devtools reset'
72
- : 'unknown reason'
74
+ : cause.reason === 'manual'
75
+ ? 'manual shutdown'
76
+ : 'unknown reason'
73
77
 
74
78
  return <>LiveStore Shutdown due to {reason}</>
75
79
  }
@@ -88,7 +92,7 @@ export const LiveStoreProvider = <GraphQLContext extends BaseGraphQLContext>({
88
92
  batchUpdates,
89
93
  disableDevtools,
90
94
  signal,
91
- }: LiveStoreProviderProps<GraphQLContext> & { children?: ReactNode }): JSX.Element => {
95
+ }: LiveStoreProviderProps<GraphQLContext> & { children?: ReactNode }): React.ReactElement => {
92
96
  const storeCtx = useCreateStore({
93
97
  storeId,
94
98
  schema,
@@ -114,6 +118,9 @@ export const LiveStoreProvider = <GraphQLContext extends BaseGraphQLContext>({
114
118
  }
115
119
 
116
120
  globalThis.__debugLiveStore ??= {}
121
+ if (Object.keys(globalThis.__debugLiveStore).length === 0) {
122
+ globalThis.__debugLiveStore['_'] = storeCtx.store
123
+ }
117
124
  globalThis.__debugLiveStore[storeId] = storeCtx.store
118
125
 
119
126
  return <LiveStoreContext.Provider value={storeCtx}>{children}</LiveStoreContext.Provider>
@@ -142,15 +149,20 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
142
149
  disableDevtools,
143
150
  reactivityGraph,
144
151
  signal,
145
- }: CreateStoreOptions<GraphQLContext, LiveStoreSchema> & { signal?: AbortSignal }) => {
152
+ }: CreateStoreOptions<GraphQLContext, LiveStoreSchema> & {
153
+ signal?: AbortSignal
154
+ otelOptions?: Partial<OtelOptions>
155
+ }) => {
146
156
  const [_, rerender] = React.useState(0)
147
157
  const ctxValueRef = React.useRef<{
148
158
  value: StoreContext_ | BootStatus
149
- fiberSet: FiberSet.FiberSet | undefined
159
+ componentScope: Scope.CloseableScope | undefined
160
+ shutdownDeferred: ShutdownDeferred | undefined
150
161
  counter: number
151
162
  }>({
152
163
  value: { stage: 'loading' },
153
- fiberSet: undefined,
164
+ componentScope: undefined,
165
+ shutdownDeferred: undefined,
154
166
  counter: 0,
155
167
  })
156
168
 
@@ -168,12 +180,17 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
168
180
  signal,
169
181
  })
170
182
 
171
- const interrupt = (fiberSet: FiberSet.FiberSet, error: StoreAbort | StoreInterrupted) =>
183
+ const interrupt = (
184
+ componentScope: Scope.CloseableScope,
185
+ shutdownDeferred: ShutdownDeferred,
186
+ error: StoreAbort | StoreInterrupted,
187
+ ) =>
172
188
  Effect.gen(function* () {
173
- yield* FiberSet.clear(fiberSet)
174
- yield* FiberSet.run(fiberSet, Effect.fail(error))
189
+ // console.log('[@livestore/livestore/react] interupting', error)
190
+ yield* Scope.close(componentScope, Exit.fail(error))
191
+ yield* Deferred.fail(shutdownDeferred, error)
175
192
  }).pipe(
176
- Effect.tapErrorCause((cause) => Effect.logDebug(`[@livestore/livestore/react] interupting`, cause)),
193
+ Effect.tapErrorCause((cause) => Effect.logDebug('[@livestore/livestore/react] interupting', cause)),
177
194
  Effect.runFork,
178
195
  )
179
196
 
@@ -199,11 +216,17 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
199
216
  reactivityGraph,
200
217
  signal,
201
218
  }
202
- if (ctxValueRef.current.fiberSet !== undefined) {
203
- interrupt(ctxValueRef.current.fiberSet, new StoreInterrupted())
204
- ctxValueRef.current.fiberSet = undefined
219
+ if (ctxValueRef.current.componentScope !== undefined && ctxValueRef.current.shutdownDeferred !== undefined) {
220
+ interrupt(ctxValueRef.current.componentScope, ctxValueRef.current.shutdownDeferred, new StoreInterrupted())
221
+ ctxValueRef.current.componentScope = undefined
222
+ ctxValueRef.current.shutdownDeferred = undefined
223
+ }
224
+ ctxValueRef.current = {
225
+ value: { stage: 'loading' },
226
+ componentScope: undefined,
227
+ shutdownDeferred: undefined,
228
+ counter: ctxValueRef.current.counter + 1,
205
229
  }
206
- ctxValueRef.current = { value: { stage: 'loading' }, fiberSet: undefined, counter: ctxValueRef.current.counter + 1 }
207
230
  }
208
231
 
209
232
  React.useEffect(() => {
@@ -216,47 +239,52 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
216
239
  }
217
240
 
218
241
  signal?.addEventListener('abort', () => {
219
- if (ctxValueRef.current.fiberSet !== undefined && ctxValueRef.current.counter === counter) {
220
- interrupt(ctxValueRef.current.fiberSet, new StoreAbort())
221
- ctxValueRef.current.fiberSet = undefined
242
+ if (
243
+ ctxValueRef.current.componentScope !== undefined &&
244
+ ctxValueRef.current.shutdownDeferred !== undefined &&
245
+ ctxValueRef.current.counter === counter
246
+ ) {
247
+ interrupt(ctxValueRef.current.componentScope, ctxValueRef.current.shutdownDeferred, new StoreAbort())
248
+ ctxValueRef.current.componentScope = undefined
249
+ ctxValueRef.current.shutdownDeferred = undefined
222
250
  }
223
251
  })
224
252
 
225
253
  Effect.gen(function* () {
226
- const fiberSet = yield* FiberSet.make<
227
- unknown,
254
+ const componentScope = yield* Scope.make()
255
+ const shutdownDeferred = yield* Deferred.make<
256
+ void,
228
257
  UnexpectedError | IntentionalShutdownCause | StoreAbort | StoreInterrupted
229
258
  >()
230
259
 
231
- ctxValueRef.current.fiberSet = fiberSet
260
+ ctxValueRef.current.componentScope = componentScope
261
+ ctxValueRef.current.shutdownDeferred = shutdownDeferred
232
262
 
233
263
  yield* Effect.gen(function* () {
234
264
  const store = yield* createStore({
235
- fiberSet,
236
265
  schema,
237
266
  storeId,
238
267
  graphQLOptions,
239
- otelOptions,
240
268
  boot,
241
269
  adapter,
242
270
  reactivityGraph,
243
271
  batchUpdates,
244
272
  disableDevtools,
273
+ shutdownDeferred,
245
274
  onBootStatus: (status) => {
246
275
  if (ctxValueRef.current.value.stage === 'running' || ctxValueRef.current.value.stage === 'error') return
247
276
  setContextValue(status)
248
277
  },
249
- })
278
+ }).pipe(Effect.tapErrorCause((cause) => Deferred.failCause(shutdownDeferred, cause)))
250
279
 
251
280
  setContextValue({ stage: 'running', store })
252
-
253
- yield* Effect.never
254
- }).pipe(Effect.scoped, FiberSet.run(fiberSet))
281
+ }).pipe(Scope.extend(componentScope), Effect.forkIn(componentScope))
255
282
 
256
283
  const shutdownContext = (cause: IntentionalShutdownCause | StoreAbort) =>
257
284
  Effect.sync(() => setContextValue({ stage: 'shutdown', cause }))
258
285
 
259
- yield* FiberSet.join(fiberSet).pipe(
286
+ yield* Deferred.await(shutdownDeferred).pipe(
287
+ Effect.tapErrorCause((cause) => Effect.logDebug('[@livestore/livestore/react] shutdown', cause)),
260
288
  Effect.catchTag('LiveStore.IntentionalShutdownCause', (cause) => shutdownContext(cause)),
261
289
  Effect.catchTag('LiveStore.StoreAbort', (cause) => shutdownContext(cause)),
262
290
  Effect.tapError((error) => Effect.sync(() => setContextValue({ stage: 'error', error }))),
@@ -269,17 +297,21 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
269
297
  // shutdown before a new one is created - especially when shutdown logic is async. You can't trust `React.useEffect`.
270
298
  // Thank you to Mattia Manzati for this idea.
271
299
  withSemaphore(storeId),
300
+ Effect.withSpan('@livestore/react:useCreateStore'),
301
+ LS_DEV ? TaskTracing.withAsyncTaggingTracing((name: string) => (console as any).createTask(name)) : identity,
302
+ provideOtel({ parentSpanContext: otelOptions?.rootSpanContext, otelTracer: otelOptions?.tracer }),
272
303
  Effect.tapCauseLogPretty,
273
304
  Effect.annotateLogs({ thread: 'window' }),
274
- Effect.provide(Logger.pretty),
305
+ Effect.provide(Logger.prettyWithThread('window')),
275
306
  Logger.withMinimumLogLevel(LogLevel.Debug),
276
307
  Effect.runFork,
277
308
  )
278
309
 
279
310
  return () => {
280
- if (ctxValueRef.current.fiberSet !== undefined) {
281
- interrupt(ctxValueRef.current.fiberSet, new StoreInterrupted())
282
- ctxValueRef.current.fiberSet = undefined
311
+ if (ctxValueRef.current.componentScope !== undefined && ctxValueRef.current.shutdownDeferred !== undefined) {
312
+ interrupt(ctxValueRef.current.componentScope, ctxValueRef.current.shutdownDeferred, new StoreInterrupted())
313
+ ctxValueRef.current.componentScope = undefined
314
+ ctxValueRef.current.shutdownDeferred = undefined
283
315
  }
284
316
  }
285
317
  }, [
@@ -1,8 +1,12 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`useRow > otel > should update the data based on component key > strictMode=false 1`] = `
3
+ exports[`useRow > otel > should update the data based on component key strictMode={ strictMode: false } 1`] = `
4
4
  {
5
- "_name": "test",
5
+ "_name": "createStore",
6
+ "attributes": {
7
+ "debugInstanceId": "test",
8
+ "storeId": "default",
9
+ },
6
10
  "children": [
7
11
  {
8
12
  "_name": "livestore.in-memory-db:execute",
@@ -17,6 +21,9 @@ exports[`useRow > otel > should update the data based on component key > strictM
17
21
  ",
18
22
  },
19
23
  },
24
+ {
25
+ "_name": "LiveStore:createStore",
26
+ },
20
27
  {
21
28
  "_name": "sql-in-memory-select",
22
29
  "attributes": {
@@ -33,6 +40,9 @@ exports[`useRow > otel > should update the data based on component key > strictM
33
40
  "sql.rowsCount": 1,
34
41
  },
35
42
  },
43
+ {
44
+ "_name": "LiveStore:sync",
45
+ },
36
46
  {
37
47
  "_name": "LiveStore:mutations",
38
48
  "children": [
@@ -43,27 +53,16 @@ exports[`useRow > otel > should update the data based on component key > strictM
43
53
  },
44
54
  "children": [
45
55
  {
46
- "_name": "LiveStore:processWrites",
56
+ "_name": "LiveStore:mutate:applyMutations",
47
57
  "attributes": {
48
58
  "livestore.mutateLabel": "mutate",
49
59
  },
50
60
  "children": [
51
61
  {
52
- "_name": "LiveStore:mutateWithoutRefresh",
62
+ "_name": "livestore.in-memory-db:execute",
53
63
  "attributes": {
54
- "livestore.args": "{
55
- "sql": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')"
56
- }",
57
- "livestore.mutation": "livestore.RawSql",
64
+ "sql.query": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')",
58
65
  },
59
- "children": [
60
- {
61
- "_name": "livestore.in-memory-db:execute",
62
- "attributes": {
63
- "sql.query": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')",
64
- },
65
- },
66
- ],
67
66
  },
68
67
  ],
69
68
  },
@@ -98,19 +97,24 @@ exports[`useRow > otel > should update the data based on component key > strictM
98
97
  },
99
98
  "children": [
100
99
  {
101
- "_name": "LiveStore:mutateWithoutRefresh",
100
+ "_name": "LiveStore:mutate",
102
101
  "attributes": {
103
- "livestore.args": "{
104
- "id": "u1"
105
- }",
106
- "livestore.mutation": "_Derived_Create_UserInfo",
102
+ "livestore.mutateLabel": "mutate",
107
103
  },
108
104
  "children": [
109
105
  {
110
- "_name": "livestore.in-memory-db:execute",
106
+ "_name": "LiveStore:mutate:applyMutations",
111
107
  "attributes": {
112
- "sql.query": "INSERT INTO UserInfo (username, text, id) VALUES ($username, $text, $id)",
108
+ "livestore.mutateLabel": "mutate",
113
109
  },
110
+ "children": [
111
+ {
112
+ "_name": "livestore.in-memory-db:execute",
113
+ "attributes": {
114
+ "sql.query": "INSERT INTO UserInfo (username, text, id) VALUES ($username, $text, $id)",
115
+ },
116
+ },
117
+ ],
114
118
  },
115
119
  ],
116
120
  },
@@ -196,9 +200,13 @@ exports[`useRow > otel > should update the data based on component key > strictM
196
200
  }
197
201
  `;
198
202
 
199
- exports[`useRow > otel > should update the data based on component key > strictMode=true 1`] = `
203
+ exports[`useRow > otel > should update the data based on component key strictMode={ strictMode: true } 1`] = `
200
204
  {
201
- "_name": "test",
205
+ "_name": "createStore",
206
+ "attributes": {
207
+ "debugInstanceId": "test",
208
+ "storeId": "default",
209
+ },
202
210
  "children": [
203
211
  {
204
212
  "_name": "livestore.in-memory-db:execute",
@@ -213,6 +221,9 @@ exports[`useRow > otel > should update the data based on component key > strictM
213
221
  ",
214
222
  },
215
223
  },
224
+ {
225
+ "_name": "LiveStore:createStore",
226
+ },
216
227
  {
217
228
  "_name": "sql-in-memory-select",
218
229
  "attributes": {
@@ -229,6 +240,9 @@ exports[`useRow > otel > should update the data based on component key > strictM
229
240
  "sql.rowsCount": 1,
230
241
  },
231
242
  },
243
+ {
244
+ "_name": "LiveStore:sync",
245
+ },
232
246
  {
233
247
  "_name": "LiveStore:mutations",
234
248
  "children": [
@@ -239,27 +253,16 @@ exports[`useRow > otel > should update the data based on component key > strictM
239
253
  },
240
254
  "children": [
241
255
  {
242
- "_name": "LiveStore:processWrites",
256
+ "_name": "LiveStore:mutate:applyMutations",
243
257
  "attributes": {
244
258
  "livestore.mutateLabel": "mutate",
245
259
  },
246
260
  "children": [
247
261
  {
248
- "_name": "LiveStore:mutateWithoutRefresh",
262
+ "_name": "livestore.in-memory-db:execute",
249
263
  "attributes": {
250
- "livestore.args": "{
251
- "sql": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')"
252
- }",
253
- "livestore.mutation": "livestore.RawSql",
264
+ "sql.query": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')",
254
265
  },
255
- "children": [
256
- {
257
- "_name": "livestore.in-memory-db:execute",
258
- "attributes": {
259
- "sql.query": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')",
260
- },
261
- },
262
- ],
263
266
  },
264
267
  ],
265
268
  },
@@ -294,19 +297,24 @@ exports[`useRow > otel > should update the data based on component key > strictM
294
297
  },
295
298
  "children": [
296
299
  {
297
- "_name": "LiveStore:mutateWithoutRefresh",
300
+ "_name": "LiveStore:mutate",
298
301
  "attributes": {
299
- "livestore.args": "{
300
- "id": "u1"
301
- }",
302
- "livestore.mutation": "_Derived_Create_UserInfo",
302
+ "livestore.mutateLabel": "mutate",
303
303
  },
304
304
  "children": [
305
305
  {
306
- "_name": "livestore.in-memory-db:execute",
306
+ "_name": "LiveStore:mutate:applyMutations",
307
307
  "attributes": {
308
- "sql.query": "INSERT INTO UserInfo (username, text, id) VALUES ($username, $text, $id)",
308
+ "livestore.mutateLabel": "mutate",
309
309
  },
310
+ "children": [
311
+ {
312
+ "_name": "livestore.in-memory-db:execute",
313
+ "attributes": {
314
+ "sql.query": "INSERT INTO UserInfo (username, text, id) VALUES ($username, $text, $id)",
315
+ },
316
+ },
317
+ ],
310
318
  },
311
319
  ],
312
320
  },
@@ -341,13 +349,6 @@ exports[`useRow > otel > should update the data based on component key > strictM
341
349
  "queryLabel": "db(row:UserInfo:u1)",
342
350
  },
343
351
  },
344
- {
345
- "_name": "LiveStore.subscribe",
346
- "attributes": {
347
- "label": "db(row:UserInfo:u1)",
348
- "queryLabel": "db(row:UserInfo:u1)",
349
- },
350
- },
351
352
  ],
352
353
  },
353
354
  ],
@@ -1,7 +1,8 @@
1
+ import { provideOtel } from '@livestore/common'
1
2
  import { DbSchema, makeSchema } from '@livestore/common/schema'
2
3
  import type { LiveStoreContextRunning } from '@livestore/livestore'
3
4
  import { createStore, globalReactivityGraph, makeReactivityGraph } from '@livestore/livestore'
4
- import { Effect, FiberSet } from '@livestore/utils/effect'
5
+ import { Effect } from '@livestore/utils/effect'
5
6
  import { makeInMemoryAdapter } from '@livestore/web'
6
7
  import type * as otel from '@opentelemetry/api'
7
8
  import React from 'react'
@@ -65,7 +66,7 @@ export const makeTodoMvcReact = ({
65
66
  otelTracer,
66
67
  otelContext,
67
68
  useGlobalReactivityGraph = true,
68
- strictMode = process.env.REACT_STRICT_MODE !== undefined,
69
+ strictMode,
69
70
  }: {
70
71
  otelTracer?: otel.Tracer
71
72
  otelContext?: otel.Context
@@ -90,18 +91,12 @@ export const makeTodoMvcReact = ({
90
91
 
91
92
  const reactivityGraph = useGlobalReactivityGraph ? globalReactivityGraph : makeReactivityGraph()
92
93
 
93
- const fiberSet = yield* FiberSet.make()
94
-
95
94
  const store = yield* createStore({
96
95
  schema,
97
96
  storeId: 'default',
98
97
  adapter: makeInMemoryAdapter(),
99
98
  reactivityGraph,
100
- otelOptions: {
101
- tracer: otelTracer,
102
- rootSpanContext: otelContext,
103
- },
104
- fiberSet,
99
+ debug: { instanceId: 'test' },
105
100
  })
106
101
 
107
102
  // TODO improve typing of `LiveStoreContext`
@@ -117,5 +112,5 @@ export const makeTodoMvcReact = ({
117
112
  </MaybeStrictMode>
118
113
  )
119
114
 
120
- return { wrapper, store, reactivityGraph, makeRenderCount, strictMode }
121
- })
115
+ return { wrapper, store, reactivityGraph, makeRenderCount }
116
+ }).pipe(provideOtel({ parentSpanContext: otelContext, otelTracer }))
package/src/useQuery.ts CHANGED
@@ -28,7 +28,7 @@ export const useQuery = <TQuery extends LiveQueryAny>(query: TQuery): GetResult<
28
28
  export const useQueryRef = <TQuery extends LiveQueryAny>(
29
29
  query$: TQuery,
30
30
  parentOtelContext?: otel.Context,
31
- ): React.MutableRefObject<GetResult<TQuery>> => {
31
+ ): React.RefObject<GetResult<TQuery>> => {
32
32
  const { store } = useStore()
33
33
 
34
34
  React.useDebugValue(`LiveStore:useQuery:${query$.id}:${query$.label}`)