@livestore/livestore 0.0.12 → 0.0.15
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 +7 -7
- package/dist/.tsbuildinfo +1 -0
- package/dist/QueryCache.d.ts +20 -0
- package/dist/QueryCache.d.ts.map +1 -0
- package/dist/QueryCache.js +71 -0
- package/dist/QueryCache.js.map +1 -0
- package/dist/__tests__/react/fixture.d.ts +25 -0
- package/dist/__tests__/react/fixture.d.ts.map +1 -0
- package/dist/__tests__/react/fixture.js +60 -0
- package/dist/__tests__/react/fixture.js.map +1 -0
- package/dist/__tests__/react/useLiveStoreComponent.test.d.ts +2 -0
- package/dist/__tests__/react/useLiveStoreComponent.test.d.ts.map +1 -0
- package/dist/__tests__/react/useLiveStoreComponent.test.js +78 -0
- package/dist/__tests__/react/useLiveStoreComponent.test.js.map +1 -0
- package/dist/__tests__/reactive.test.d.ts +2 -0
- package/dist/__tests__/reactive.test.d.ts.map +1 -0
- package/dist/__tests__/reactive.test.js +197 -0
- package/dist/__tests__/reactive.test.js.map +1 -0
- package/dist/bounded-collections.d.ts +34 -0
- package/dist/bounded-collections.d.ts.map +1 -0
- package/dist/bounded-collections.js +103 -0
- package/dist/bounded-collections.js.map +1 -0
- package/dist/componentKey.d.ts +20 -0
- package/dist/componentKey.d.ts.map +1 -0
- package/dist/componentKey.js +3 -0
- package/dist/componentKey.js.map +1 -0
- package/dist/effect/LiveStore.d.ts +36 -0
- package/dist/effect/LiveStore.d.ts.map +1 -0
- package/dist/effect/LiveStore.js +41 -0
- package/dist/effect/LiveStore.js.map +1 -0
- package/dist/effect/index.d.ts +2 -0
- package/dist/effect/index.d.ts.map +1 -0
- package/dist/effect/index.js +2 -0
- package/dist/effect/index.js.map +1 -0
- package/dist/events.d.ts +7 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +2 -0
- package/dist/events.js.map +1 -0
- package/dist/inMemoryDatabase.d.ts +56 -0
- package/dist/inMemoryDatabase.d.ts.map +1 -0
- package/dist/inMemoryDatabase.js +223 -0
- package/dist/inMemoryDatabase.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations.d.ts +16 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +67 -0
- package/dist/migrations.js.map +1 -0
- package/dist/otel.d.ts +4 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +6 -0
- package/dist/otel.js.map +1 -0
- package/dist/react/LiveStoreContext.d.ts +11 -0
- package/dist/react/LiveStoreContext.d.ts.map +1 -0
- package/dist/react/LiveStoreContext.js +10 -0
- package/dist/react/LiveStoreContext.js.map +1 -0
- package/dist/react/LiveStoreProvider.d.ts +20 -0
- package/dist/react/LiveStoreProvider.d.ts.map +1 -0
- package/dist/react/LiveStoreProvider.js +52 -0
- package/dist/react/LiveStoreProvider.js.map +1 -0
- package/dist/react/index.d.ts +8 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +6 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/useGraphQL.d.ts +13 -0
- package/dist/react/useGraphQL.d.ts.map +1 -0
- package/dist/react/useGraphQL.js +85 -0
- package/dist/react/useGraphQL.js.map +1 -0
- package/dist/react/useLiveStoreComponent.d.ts +75 -0
- package/dist/react/useLiveStoreComponent.d.ts.map +1 -0
- package/dist/react/useLiveStoreComponent.js +317 -0
- package/dist/react/useLiveStoreComponent.js.map +1 -0
- package/dist/react/useQuery.d.ts +3 -0
- package/dist/react/useQuery.d.ts.map +1 -0
- package/dist/react/useQuery.js +38 -0
- package/dist/react/useQuery.js.map +1 -0
- package/dist/react/utils/useStateRefWithReactiveInput.d.ts +13 -0
- package/dist/react/utils/useStateRefWithReactiveInput.d.ts.map +1 -0
- package/dist/react/utils/useStateRefWithReactiveInput.js +38 -0
- package/dist/react/utils/useStateRefWithReactiveInput.js.map +1 -0
- package/dist/reactive.d.ts +140 -0
- package/dist/reactive.d.ts.map +1 -0
- package/dist/reactive.js +302 -0
- package/dist/reactive.js.map +1 -0
- package/dist/reactiveQueries/base-class.d.ts +27 -0
- package/dist/reactiveQueries/base-class.d.ts.map +1 -0
- package/dist/reactiveQueries/base-class.js +23 -0
- package/dist/reactiveQueries/base-class.js.map +1 -0
- package/dist/reactiveQueries/graphql.d.ts +25 -0
- package/dist/reactiveQueries/graphql.d.ts.map +1 -0
- package/dist/reactiveQueries/graphql.js +18 -0
- package/dist/reactiveQueries/graphql.js.map +1 -0
- package/dist/reactiveQueries/js.d.ts +19 -0
- package/dist/reactiveQueries/js.d.ts.map +1 -0
- package/dist/reactiveQueries/js.js +13 -0
- package/dist/reactiveQueries/js.js.map +1 -0
- package/dist/reactiveQueries/sql.d.ts +31 -0
- package/dist/reactiveQueries/sql.d.ts.map +1 -0
- package/dist/reactiveQueries/sql.js +32 -0
- package/dist/reactiveQueries/sql.js.map +1 -0
- package/dist/schema.d.ts +81 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +46 -0
- package/dist/schema.js.map +1 -0
- package/dist/storage/in-memory/index.d.ts +15 -0
- package/dist/storage/in-memory/index.d.ts.map +1 -0
- package/dist/storage/in-memory/index.js +14 -0
- package/dist/storage/in-memory/index.js.map +1 -0
- package/dist/storage/index.d.ts +14 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +9 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/tauri/index.d.ts +19 -0
- package/dist/storage/tauri/index.d.ts.map +1 -0
- package/dist/storage/tauri/index.js +38 -0
- package/dist/storage/tauri/index.js.map +1 -0
- package/dist/storage/utils/idb.d.ts +10 -0
- package/dist/storage/utils/idb.d.ts.map +1 -0
- package/dist/storage/utils/idb.js +58 -0
- package/dist/storage/utils/idb.js.map +1 -0
- package/dist/storage/web-worker/index.d.ts +27 -0
- package/dist/storage/web-worker/index.d.ts.map +1 -0
- package/dist/storage/web-worker/index.js +74 -0
- package/dist/storage/web-worker/index.js.map +1 -0
- package/dist/storage/web-worker/worker.d.ts +13 -0
- package/dist/storage/web-worker/worker.d.ts.map +1 -0
- package/dist/storage/web-worker/worker.js +110 -0
- package/dist/storage/web-worker/worker.js.map +1 -0
- package/dist/store.d.ts +199 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +603 -0
- package/dist/store.js.map +1 -0
- package/dist/util.d.ts +28 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +55 -0
- package/dist/util.js.map +1 -0
- package/package.json +46 -19
- package/src/__tests__/react/fixture.tsx +23 -32
- package/src/__tests__/reactive.test.ts +3 -4
- package/src/effect/LiveStore.ts +22 -31
- package/src/events.ts +1 -1
- package/src/inMemoryDatabase.ts +115 -140
- package/src/index.ts +20 -20
- package/src/migrations.ts +119 -0
- package/src/otel.ts +0 -11
- package/src/react/LiveStoreProvider.tsx +24 -23
- package/src/react/index.ts +10 -1
- package/src/react/useGraphQL.ts +28 -2
- package/src/react/useLiveStoreComponent.ts +134 -50
- package/src/react/useQuery.ts +56 -0
- package/src/reactive.ts +6 -4
- package/src/reactiveQueries/base-class.ts +9 -3
- package/src/reactiveQueries/graphql.ts +4 -4
- package/src/reactiveQueries/js.ts +2 -2
- package/src/reactiveQueries/sql.ts +6 -6
- package/src/schema.ts +69 -145
- package/src/storage/in-memory/index.ts +21 -0
- package/src/storage/index.ts +27 -0
- package/src/{backends/tauri.ts → storage/tauri/index.ts} +14 -28
- package/src/storage/web-worker/index.ts +116 -0
- package/src/{backends/web-worker.ts → storage/web-worker/worker.ts} +17 -52
- package/src/store.ts +171 -98
- package/src/util.ts +13 -3
- package/tsconfig.json +1 -3
- package/src/backends/base.ts +0 -67
- package/src/backends/index.ts +0 -98
- package/src/backends/noop.ts +0 -32
- package/src/backends/web-in-memory.ts +0 -65
- package/src/backends/web.ts +0 -97
- package/src/react/useGlobalQuery.ts +0 -40
- /package/src/{backends → storage}/utils/idb.ts +0 -0
package/src/react/useGraphQL.ts
CHANGED
|
@@ -15,6 +15,12 @@ export type UseLiveStoreComponentProps<TResult extends Record<string, any>, TVar
|
|
|
15
15
|
reactDeps?: React.DependencyList
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
type Variables = Record<string, any>
|
|
19
|
+
|
|
20
|
+
// TODO get rid of the query cache in favour of the new side-effect-free query definition approach https://www.notion.so/schickling/New-query-definition-approach-1097a78ef0e9495bac25f90417374756?pvs=4
|
|
21
|
+
// NOTE we're using a nested map here since we need to resolve 2 levels of object identities (query + variables)
|
|
22
|
+
// const queryCache = new Map<DocumentNode<any, any>, Map<Variables, LiveStoreGraphQLQuery<any, any, any>>>()
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* This is needed because the `React.useMemo` call below, can sometimes be called multiple times 🤷,
|
|
20
26
|
* so we need to "cache" the fact that we've already started a span for this component.
|
|
@@ -24,7 +30,7 @@ const spanAlreadyStartedCache = new Map<string, { span: otel.Span; otelContext:
|
|
|
24
30
|
|
|
25
31
|
// TODO 1) figure out a way to make `variables` optional if the query doesn't have any variables (probably requires positional args)
|
|
26
32
|
// TODO 2) allow `.pipe` on the resulting query (possibly as a separate optional prop)
|
|
27
|
-
export const useGraphQL = <TResult extends Record<string, any>, TVariables extends
|
|
33
|
+
export const useGraphQL = <TResult extends Record<string, any>, TVariables extends Variables = {}>({
|
|
28
34
|
query,
|
|
29
35
|
variables,
|
|
30
36
|
componentKey: componentKeyConfig,
|
|
@@ -62,7 +68,27 @@ export const useGraphQL = <TResult extends Record<string, any>, TVariables exten
|
|
|
62
68
|
)
|
|
63
69
|
|
|
64
70
|
const makeLiveStoreQuery = React.useCallback(
|
|
65
|
-
() =>
|
|
71
|
+
() => {
|
|
72
|
+
return store.queryGraphQL(query, () => variables ?? ({} as TVariables), { componentKey, otelContext })
|
|
73
|
+
|
|
74
|
+
// NOTE I had to disable the caching below as still led to many problems
|
|
75
|
+
// We should just implement the new query definition approach instead
|
|
76
|
+
|
|
77
|
+
// const queryCacheForQuery = queryCache.get(query)
|
|
78
|
+
// if (queryCacheForQuery && queryCacheForQuery.has(variables)) {
|
|
79
|
+
// return queryCacheForQuery.get(variables)!
|
|
80
|
+
// }
|
|
81
|
+
|
|
82
|
+
// const newQuery = store.queryGraphQL(query, () => variables ?? ({} as TVariables), { componentKey, otelContext })
|
|
83
|
+
|
|
84
|
+
// if (queryCacheForQuery) {
|
|
85
|
+
// queryCacheForQuery.set(variables, newQuery)
|
|
86
|
+
// } else {
|
|
87
|
+
// queryCache.set(query, new Map([[variables, newQuery]]))
|
|
88
|
+
// }
|
|
89
|
+
|
|
90
|
+
// return newQuery
|
|
91
|
+
},
|
|
66
92
|
// NOTE: we don't include the queries function passed in by the user here;
|
|
67
93
|
// the reason is that we don't want to force them to memoize that function.
|
|
68
94
|
// Instead, we just assume that the function always has the same contents.
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'
|
|
2
|
-
import {
|
|
2
|
+
import type { LiteralUnion, PrettifyFlat } from '@livestore/utils'
|
|
3
|
+
import { omit, shouldNeverHappen } from '@livestore/utils'
|
|
4
|
+
import { Schema } from '@livestore/utils/effect'
|
|
3
5
|
import * as otel from '@opentelemetry/api'
|
|
6
|
+
import { SqliteAst, SqliteDsl } from 'effect-db-schema'
|
|
4
7
|
import { isEqual, mapValues } from 'lodash-es'
|
|
5
8
|
import type { DependencyList } from 'react'
|
|
6
9
|
import React from 'react'
|
|
@@ -8,12 +11,12 @@ import { v4 as uuid } from 'uuid'
|
|
|
8
11
|
|
|
9
12
|
import type { ComponentKey } from '../componentKey.js'
|
|
10
13
|
import { labelForKey, tableNameForComponentKey } from '../componentKey.js'
|
|
11
|
-
import
|
|
14
|
+
import { migrateTable } from '../migrations.js'
|
|
12
15
|
import type { LiveStoreGraphQLQuery } from '../reactiveQueries/graphql.js'
|
|
13
16
|
import type { LiveStoreJSQuery } from '../reactiveQueries/js.js'
|
|
14
17
|
import type { LiveStoreSQLQuery } from '../reactiveQueries/sql.js'
|
|
15
|
-
import
|
|
16
|
-
import type { BaseGraphQLContext, LiveStoreQuery, QueryResult, Store } from '../store.js'
|
|
18
|
+
import { SCHEMA_META_TABLE } from '../schema.js'
|
|
19
|
+
import type { BaseGraphQLContext, GetAtomResult, LiveStoreQuery, QueryResult, Store } from '../store.js'
|
|
17
20
|
import type { Bindable } from '../util.js'
|
|
18
21
|
import { sql } from '../util.js'
|
|
19
22
|
import { useStore } from './LiveStoreContext.js'
|
|
@@ -22,20 +25,24 @@ import { useStateRefWithReactiveInput } from './utils/useStateRefWithReactiveInp
|
|
|
22
25
|
export interface QueryDefinitions {
|
|
23
26
|
[queryName: string]: LiveStoreQuery
|
|
24
27
|
}
|
|
25
|
-
|
|
28
|
+
|
|
29
|
+
export type QueryResults<TQuery> = { [queryName in keyof TQuery]: PrettifyFlat<QueryResult<TQuery[queryName]>> }
|
|
26
30
|
|
|
27
31
|
export type ReactiveSQL = <TResult>(
|
|
28
|
-
|
|
32
|
+
query: string | ((get: GetAtomResult) => string),
|
|
29
33
|
queriedTables: string[],
|
|
30
34
|
bindValues?: Bindable | undefined,
|
|
31
35
|
) => LiveStoreSQLQuery<TResult>
|
|
36
|
+
|
|
37
|
+
export type ReactiveJS = <TResult>(query: (get: GetAtomResult) => TResult) => LiveStoreJSQuery<TResult>
|
|
38
|
+
|
|
32
39
|
export type ReactiveGraphQL = <
|
|
33
40
|
TResult extends Record<string, any>,
|
|
34
41
|
TVariables extends Record<string, any>,
|
|
35
42
|
TContext extends BaseGraphQLContext,
|
|
36
43
|
>(
|
|
37
44
|
query: DocumentNode<TResult, TVariables>,
|
|
38
|
-
|
|
45
|
+
variableValues: TVariables | ((get: GetAtomResult) => TVariables),
|
|
39
46
|
label?: string,
|
|
40
47
|
) => LiveStoreGraphQLQuery<TResult, TVariables, TContext>
|
|
41
48
|
|
|
@@ -48,16 +55,20 @@ type RegisterSubscription = <TQuery extends LiveStoreQuery>(
|
|
|
48
55
|
type GenQueries<TQueries, TStateResult> = (args: {
|
|
49
56
|
rxSQL: ReactiveSQL
|
|
50
57
|
rxGraphQL: ReactiveGraphQL
|
|
51
|
-
|
|
58
|
+
rxJS: ReactiveJS
|
|
52
59
|
state$: LiveStoreJSQuery<TStateResult>
|
|
53
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Registers a subscription.
|
|
62
|
+
*
|
|
63
|
+
* Passed down for some manual subscribing. Use carefully.
|
|
64
|
+
*/
|
|
54
65
|
subscribe: RegisterSubscription
|
|
55
66
|
isTemporaryQuery: boolean
|
|
56
67
|
}) => TQueries
|
|
57
68
|
|
|
58
|
-
export type UseLiveStoreComponentProps<TQueries,
|
|
59
|
-
stateSchema?:
|
|
60
|
-
queries?: GenQueries<TQueries,
|
|
69
|
+
export type UseLiveStoreComponentProps<TQueries, TStateColumns extends ComponentColumns> = {
|
|
70
|
+
stateSchema?: SqliteDsl.TableDefinition<string, TStateColumns>
|
|
71
|
+
queries?: GenQueries<TQueries, SqliteDsl.FromColumns.RowDecoded<TStateColumns>>
|
|
61
72
|
reactDeps?: React.DependencyList
|
|
62
73
|
componentKey: ComponentKeyConfig
|
|
63
74
|
}
|
|
@@ -72,12 +83,17 @@ export type ComponentKeyConfig = {
|
|
|
72
83
|
id: LiteralUnion<'singleton' | '__ephemeral__', string>
|
|
73
84
|
}
|
|
74
85
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
id: string
|
|
78
|
-
[key: string]: string | number | boolean | null
|
|
86
|
+
// TODO enforce columns are non-nullable or have a default
|
|
87
|
+
export interface ComponentColumns extends SqliteDsl.Columns {
|
|
88
|
+
id: SqliteDsl.ColumnDefinition<SqliteDsl.FieldType.FieldTypeText<string, string>, false>
|
|
79
89
|
}
|
|
80
90
|
|
|
91
|
+
// type ComponentState = {
|
|
92
|
+
// /** Equivalent to `componentKey.key` */
|
|
93
|
+
// id: string
|
|
94
|
+
// [key: string]: string | number | boolean | null
|
|
95
|
+
// }
|
|
96
|
+
|
|
81
97
|
/**
|
|
82
98
|
* This is needed because the `React.useMemo` call below, can sometimes be called multiple times 🤷,
|
|
83
99
|
* so we need to "cache" the fact that we've already started a span for this component.
|
|
@@ -90,23 +106,33 @@ type UseLiveStoreJsonState<TState> = <TResult>(
|
|
|
90
106
|
parse?: (_: unknown) => TResult,
|
|
91
107
|
) => [value: TResult, setValue: (newVal: TResult | ((prevVal: TResult) => TResult)) => void]
|
|
92
108
|
|
|
109
|
+
export type GetStateType<TTableDef extends SqliteDsl.TableDefinition<any, any>> = SqliteDsl.FromColumns.RowDecoded<
|
|
110
|
+
TTableDef['columns']
|
|
111
|
+
>
|
|
112
|
+
|
|
113
|
+
export type GetStateTypeEncoded<TTableDef extends SqliteDsl.TableDefinition<any, any>> =
|
|
114
|
+
SqliteDsl.FromColumns.RowEncoded<TTableDef['columns']>
|
|
115
|
+
|
|
93
116
|
/**
|
|
94
117
|
* Create reactive queries within a component.
|
|
95
118
|
* @param config.queries A function that returns a map of named reactive queries.
|
|
96
119
|
* @param config.componentKey A function that returns a unique key for this component.
|
|
97
120
|
* @param config.reactDeps A list of React-level dependencies that will refresh the queries.
|
|
98
121
|
*/
|
|
99
|
-
export const useLiveStoreComponent = <
|
|
122
|
+
export const useLiveStoreComponent = <TStateColumns extends ComponentColumns, TQueries extends QueryDefinitions>({
|
|
100
123
|
stateSchema: stateSchema_,
|
|
101
124
|
queries = () => ({}) as TQueries,
|
|
102
125
|
componentKey: componentKeyConfig,
|
|
103
126
|
reactDeps = [],
|
|
104
|
-
}: UseLiveStoreComponentProps<TQueries,
|
|
127
|
+
}: UseLiveStoreComponentProps<TQueries, TStateColumns>): {
|
|
105
128
|
queryResults: QueryResults<TQueries>
|
|
106
|
-
state:
|
|
107
|
-
setState: Setters<
|
|
108
|
-
useLiveStoreJsonState: UseLiveStoreJsonState<
|
|
129
|
+
state: SqliteDsl.FromColumns.RowDecoded<TStateColumns>
|
|
130
|
+
setState: Setters<SqliteDsl.FromColumns.RowDecoded<TStateColumns>>
|
|
131
|
+
useLiveStoreJsonState: UseLiveStoreJsonState<SqliteDsl.FromColumns.RowDecoded<TStateColumns>>
|
|
109
132
|
} => {
|
|
133
|
+
type TComponentState = SqliteDsl.FromColumns.RowDecoded<TStateColumns>
|
|
134
|
+
|
|
135
|
+
// TODO validate schema to make sure each column has a default value
|
|
110
136
|
// TODO we should clean up the state schema handling to remove this special handling for the `id` column
|
|
111
137
|
const stateSchema = React.useMemo(
|
|
112
138
|
() => (stateSchema_ ? { ...stateSchema_, columns: omit(stateSchema_.columns, 'id' as any) } : undefined),
|
|
@@ -115,7 +141,7 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
115
141
|
|
|
116
142
|
// performance.mark('useLiveStoreComponent:start')
|
|
117
143
|
const componentKey = useComponentKey(componentKeyConfig, reactDeps)
|
|
118
|
-
const { store
|
|
144
|
+
const { store } = useStore()
|
|
119
145
|
|
|
120
146
|
const componentKeyLabel = React.useMemo(() => labelForKey(componentKey), [componentKey])
|
|
121
147
|
|
|
@@ -158,14 +184,17 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
158
184
|
isTemporaryQuery: boolean
|
|
159
185
|
}) =>
|
|
160
186
|
queries({
|
|
161
|
-
rxSQL: <T>(
|
|
162
|
-
|
|
187
|
+
rxSQL: <T>(
|
|
188
|
+
genQuery: string | ((get: GetAtomResult) => string),
|
|
189
|
+
queriedTables: string[],
|
|
190
|
+
bindValues?: Bindable,
|
|
191
|
+
) => store.querySQL<T>(genQuery, { queriedTables, bindValues, otelContext, componentKey }),
|
|
163
192
|
rxGraphQL: <Result extends Record<string, any>, Variables extends Record<string, any>>(
|
|
164
193
|
query: DocumentNode<Result, Variables>,
|
|
165
|
-
genVariableValues: (get:
|
|
194
|
+
genVariableValues: Variables | ((get: GetAtomResult) => Variables),
|
|
166
195
|
label?: string,
|
|
167
196
|
) => store.queryGraphQL(query, genVariableValues, { componentKey, label, otelContext }),
|
|
168
|
-
|
|
197
|
+
rxJS: <T>(genQuery: (get: GetAtomResult) => T) => store.queryJS(genQuery, { componentKey, otelContext }),
|
|
169
198
|
state$,
|
|
170
199
|
subscribe: registerSubscription,
|
|
171
200
|
isTemporaryQuery,
|
|
@@ -177,7 +206,7 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
177
206
|
// This makes sense for LiveStore because the component config should be static.
|
|
178
207
|
// TODO: document this and consider whether it's the right API surface.
|
|
179
208
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
180
|
-
[store, componentKey
|
|
209
|
+
[store, componentKey],
|
|
181
210
|
)
|
|
182
211
|
|
|
183
212
|
const defaultComponentState = React.useMemo(() => {
|
|
@@ -185,11 +214,17 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
185
214
|
stateSchema === undefined ? {} : mapValues(stateSchema.columns, (c) => c.default)
|
|
186
215
|
) as TComponentState
|
|
187
216
|
|
|
217
|
+
// @ts-expect-error TODO fix typing
|
|
188
218
|
defaultState.id = componentKeyConfig.id
|
|
189
219
|
|
|
190
220
|
return defaultState
|
|
191
221
|
}, [componentKeyConfig.id, stateSchema])
|
|
192
222
|
|
|
223
|
+
const componentStateEffectSchema = React.useMemo(
|
|
224
|
+
() => (stateSchema ? SqliteDsl.structSchemaForTable(stateSchema) : Schema.any),
|
|
225
|
+
[stateSchema],
|
|
226
|
+
)
|
|
227
|
+
|
|
193
228
|
// Step 1:
|
|
194
229
|
// Synchronously create state and queries for initial render pass.
|
|
195
230
|
// We do this in a temporary query context which cleans up after itself, making it idempotent
|
|
@@ -198,32 +233,56 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
198
233
|
return store.otel.tracer.startActiveSpan('LiveStore:useLiveStoreComponent:initial', {}, otelContext, (span) => {
|
|
199
234
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
200
235
|
|
|
236
|
+
// NOTE `inTempQueryContext` automatically destroys the queries once the callback is done
|
|
201
237
|
return store.inTempQueryContext(() => {
|
|
202
238
|
try {
|
|
203
239
|
// create state query
|
|
204
|
-
let
|
|
240
|
+
let state$: LiveStoreJSQuery<TComponentState>
|
|
205
241
|
if (stateSchema === undefined) {
|
|
206
242
|
// TODO don't set up a query if there's no state schema (keeps the graph more clean)
|
|
207
|
-
|
|
243
|
+
state$ = store.queryJS(() => ({}), {
|
|
208
244
|
componentKey,
|
|
209
245
|
otelContext,
|
|
210
246
|
}) as unknown as LiveStoreJSQuery<TComponentState>
|
|
211
247
|
} else {
|
|
212
248
|
const componentTableName = tableNameForComponentKey(componentKey)
|
|
213
249
|
const whereClause = componentKey._tag === 'singleton' ? '' : `where id = '${componentKey.id}'`
|
|
214
|
-
|
|
215
|
-
|
|
250
|
+
|
|
251
|
+
// TODO find a better solution for this
|
|
252
|
+
if (store.tableRefs[componentTableName] === undefined) {
|
|
253
|
+
const schemaHash = SqliteAst.hash(stateSchema.ast)
|
|
254
|
+
const res = store.inMemoryDB.select<{ schemaHash: number }>(
|
|
255
|
+
sql`SELECT schemaHash FROM ${SCHEMA_META_TABLE} WHERE tableName = '${componentTableName}'`,
|
|
256
|
+
)
|
|
257
|
+
if (res.length === 0 || res[0]!.schemaHash !== schemaHash) {
|
|
258
|
+
migrateTable({ db: store._proxyDb, tableDef: stateSchema.ast, otelContext, schemaHash })
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
store.tableRefs[componentTableName] = store.graph.makeRef(null, {
|
|
262
|
+
equal: () => false,
|
|
263
|
+
label: componentTableName,
|
|
264
|
+
meta: { liveStoreRefType: 'table' },
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
state$ = store
|
|
269
|
+
.querySQL(() => sql`select * from ${componentTableName} ${whereClause} limit 1`, {
|
|
216
270
|
queriedTables: [componentTableName],
|
|
217
271
|
componentKey,
|
|
218
272
|
label: `localState:query:${componentKeyLabel}`,
|
|
219
273
|
otelContext,
|
|
220
274
|
})
|
|
221
|
-
|
|
275
|
+
// TODO consider to instead of just returning the default value, to write the default component state to the DB
|
|
276
|
+
.pipe<TComponentState>((results) =>
|
|
277
|
+
results.length === 1
|
|
278
|
+
? Schema.parseSync(componentStateEffectSchema)(results[0]!)
|
|
279
|
+
: defaultComponentState,
|
|
280
|
+
)
|
|
222
281
|
}
|
|
223
|
-
const initialComponentState =
|
|
282
|
+
const initialComponentState = state$.results$.result
|
|
224
283
|
|
|
225
284
|
const queries = generateQueries({
|
|
226
|
-
state$:
|
|
285
|
+
state$: state$,
|
|
227
286
|
otelContext,
|
|
228
287
|
registerSubscription: () => {},
|
|
229
288
|
isTemporaryQuery: true,
|
|
@@ -231,7 +290,11 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
231
290
|
for (const [name, query] of Object.entries(queries)) {
|
|
232
291
|
query.label = name
|
|
233
292
|
}
|
|
234
|
-
const initialQueryResults = mapValues(
|
|
293
|
+
const initialQueryResults = mapValues(
|
|
294
|
+
queries,
|
|
295
|
+
(query) => query.results$.result,
|
|
296
|
+
// TODO improve typing
|
|
297
|
+
) as unknown as QueryResults<TQueries>
|
|
235
298
|
|
|
236
299
|
return { initialComponentState, initialQueryResults }
|
|
237
300
|
} finally {
|
|
@@ -239,7 +302,16 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
239
302
|
}
|
|
240
303
|
})
|
|
241
304
|
})
|
|
242
|
-
}, [
|
|
305
|
+
}, [
|
|
306
|
+
store,
|
|
307
|
+
otelContext,
|
|
308
|
+
stateSchema,
|
|
309
|
+
generateQueries,
|
|
310
|
+
componentKey,
|
|
311
|
+
componentKeyLabel,
|
|
312
|
+
componentStateEffectSchema,
|
|
313
|
+
defaultComponentState,
|
|
314
|
+
])
|
|
243
315
|
|
|
244
316
|
// Now that we've computed the initial state synchronously,
|
|
245
317
|
// we can set up our useState calls w/ a default value populated...
|
|
@@ -251,10 +323,13 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
251
323
|
stateSchema === undefined
|
|
252
324
|
? {}
|
|
253
325
|
: // TODO: do we have a better type for the values that can go in SQLite?
|
|
254
|
-
mapValues(stateSchema.columns, (
|
|
326
|
+
mapValues(stateSchema.columns, (column, columnName) => (value: string | number) => {
|
|
255
327
|
// Don't update the state if it's the same as the value already seen in the component
|
|
328
|
+
// @ts-expect-error TODO fix typing
|
|
256
329
|
if (componentStateRef.current[columnName] === value) return
|
|
257
330
|
|
|
331
|
+
const encodedValue = Schema.encodeSync(column.type.codec)(value)
|
|
332
|
+
|
|
258
333
|
if (['componentKey', 'columnNames'].includes(columnName)) {
|
|
259
334
|
shouldNeverHappen(`Can't use reserved column name ${columnName}`)
|
|
260
335
|
}
|
|
@@ -262,7 +337,7 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
262
337
|
return store.applyEvent('updateComponentState', {
|
|
263
338
|
componentKey,
|
|
264
339
|
columnNames: [columnName],
|
|
265
|
-
[columnName]:
|
|
340
|
+
[columnName]: encodedValue,
|
|
266
341
|
})
|
|
267
342
|
})
|
|
268
343
|
) as Setters<TComponentState>
|
|
@@ -270,6 +345,7 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
270
345
|
setState.setMany = (columnValues: Partial<TComponentState>) => {
|
|
271
346
|
// TODO use hashing instead
|
|
272
347
|
// Don't update the state if it's the same as the value already seen in the component
|
|
348
|
+
// @ts-expect-error TODO fix typing
|
|
273
349
|
if (Object.entries(columnValues).every(([columnName, value]) => componentStateRef.current[columnName] === value)) {
|
|
274
350
|
return
|
|
275
351
|
}
|
|
@@ -293,7 +369,12 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
293
369
|
// create state query
|
|
294
370
|
let state$: LiveStoreJSQuery<TComponentState>
|
|
295
371
|
if (stateSchema === undefined) {
|
|
296
|
-
|
|
372
|
+
// TODO remove this query
|
|
373
|
+
state$ = store.queryJS(() => ({}) as TComponentState, {
|
|
374
|
+
componentKey,
|
|
375
|
+
otelContext,
|
|
376
|
+
label: 'empty-component-state',
|
|
377
|
+
})
|
|
297
378
|
} else {
|
|
298
379
|
const componentTableName = tableNameForComponentKey(componentKey)
|
|
299
380
|
insertRowForComponentInstance({ store, componentKey, stateSchema })
|
|
@@ -306,7 +387,10 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
306
387
|
label: `localState:query:${componentKeyLabel}`,
|
|
307
388
|
otelContext,
|
|
308
389
|
})
|
|
309
|
-
|
|
390
|
+
// TODO consider to instead of just returning the default value, to write the default component state to the DB
|
|
391
|
+
.pipe<TComponentState>((results) =>
|
|
392
|
+
results.length === 1 ? Schema.parseSync(componentStateEffectSchema)(results[0]!) : defaultComponentState,
|
|
393
|
+
)
|
|
310
394
|
}
|
|
311
395
|
|
|
312
396
|
unsubs.push(
|
|
@@ -322,25 +406,25 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
|
|
|
322
406
|
),
|
|
323
407
|
)
|
|
324
408
|
|
|
325
|
-
const registerSubscription: RegisterSubscription = (query
|
|
409
|
+
const registerSubscription: RegisterSubscription = (query$, callback, onUnsubscribe) => {
|
|
326
410
|
unsubs.push(
|
|
327
411
|
store.subscribe(
|
|
328
|
-
query
|
|
412
|
+
query$,
|
|
329
413
|
(results) => {
|
|
330
414
|
callback(results)
|
|
331
415
|
},
|
|
332
416
|
onUnsubscribe,
|
|
333
|
-
{ label: `useLiveStoreComponent:query:manual-subscribe:${query
|
|
417
|
+
{ label: `useLiveStoreComponent:query:manual-subscribe:${query$.label}` },
|
|
334
418
|
),
|
|
335
419
|
)
|
|
336
420
|
}
|
|
337
421
|
|
|
338
422
|
const queries = generateQueries({ state$, otelContext, registerSubscription, isTemporaryQuery: false })
|
|
339
|
-
|
|
340
|
-
for (const [name, query] of Object.entries(queries)) {
|
|
341
|
-
query.label = name
|
|
342
|
-
}
|
|
423
|
+
|
|
343
424
|
for (const [key, query] of Object.entries(queries)) {
|
|
425
|
+
// Use the field name given to this query in the useQueries hook as its label
|
|
426
|
+
query.label = key
|
|
427
|
+
|
|
344
428
|
unsubs.push(
|
|
345
429
|
store.subscribe(
|
|
346
430
|
query,
|
|
@@ -447,14 +531,14 @@ export const useComponentKey = ({ name, id }: ComponentKeyConfig, deps: Dependen
|
|
|
447
531
|
* Create a row storing the state for a component instance, if none exists yet.
|
|
448
532
|
* Initialized with default values, and keyed on the component key.
|
|
449
533
|
*/
|
|
450
|
-
const insertRowForComponentInstance =
|
|
534
|
+
const insertRowForComponentInstance = ({
|
|
451
535
|
store,
|
|
452
536
|
componentKey,
|
|
453
537
|
stateSchema,
|
|
454
538
|
}: {
|
|
455
539
|
store: Store<BaseGraphQLContext>
|
|
456
540
|
componentKey: ComponentKey
|
|
457
|
-
stateSchema:
|
|
541
|
+
stateSchema: SqliteDsl.TableDefinition<string, SqliteDsl.Columns>
|
|
458
542
|
}) => {
|
|
459
543
|
const columnNames = ['id', ...Object.keys(stateSchema.columns)]
|
|
460
544
|
const columnValues = columnNames.map((name) => `$${name}`).join(', ')
|
|
@@ -467,8 +551,8 @@ const insertRowForComponentInstance = <T>({
|
|
|
467
551
|
void store.execute(
|
|
468
552
|
insertQuery,
|
|
469
553
|
{
|
|
470
|
-
id: componentKey.id,
|
|
471
554
|
...mapValues(stateSchema.columns, (column) => prepareValueForSql(column.default ?? null)),
|
|
555
|
+
id: componentKey.id,
|
|
472
556
|
},
|
|
473
557
|
[tableName],
|
|
474
558
|
)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { labelForKey } from '../componentKey.js'
|
|
4
|
+
import type { QueryDefinition } from '../effect/LiveStore.js'
|
|
5
|
+
import type { LiveStoreQuery, QueryResult, Store } from '../store.js'
|
|
6
|
+
import { useStore } from './LiveStoreContext.js'
|
|
7
|
+
|
|
8
|
+
// TODO get rid of the query cache in favour of the new side-effect-free query definition approach https://www.notion.so/schickling/New-query-definition-approach-1097a78ef0e9495bac25f90417374756?pvs=4
|
|
9
|
+
const queryCache = new Map<QueryDefinition, LiveStoreQuery>()
|
|
10
|
+
|
|
11
|
+
export const useQuery = <Q extends LiveStoreQuery>(queryDef: (store: Store) => Q): QueryResult<Q> => {
|
|
12
|
+
const { store } = useStore()
|
|
13
|
+
const query = React.useMemo(() => {
|
|
14
|
+
if (queryCache.has(queryDef)) return queryCache.get(queryDef) as Q
|
|
15
|
+
|
|
16
|
+
const query = queryDef(store)
|
|
17
|
+
queryCache.set(queryDef, query)
|
|
18
|
+
return query
|
|
19
|
+
}, [store, queryDef])
|
|
20
|
+
|
|
21
|
+
// We know the query has a result by the time we use it; so we can synchronously populate a default state
|
|
22
|
+
const [value, setValue] = React.useState<QueryResult<Q>>(query.results$.result)
|
|
23
|
+
|
|
24
|
+
// Subscribe to future updates for this query
|
|
25
|
+
React.useEffect(() => {
|
|
26
|
+
return store.otel.tracer.startActiveSpan(
|
|
27
|
+
`LiveStore:useQuery:${labelForKey(query.componentKey)}:${query.label}`,
|
|
28
|
+
{ attributes: { label: query.label } },
|
|
29
|
+
query.otelContext,
|
|
30
|
+
(span) => {
|
|
31
|
+
const cancel = store.subscribe(
|
|
32
|
+
query,
|
|
33
|
+
(v) => {
|
|
34
|
+
// NOTE: we return a reference to the result object within LiveStore;
|
|
35
|
+
// this implies that app code must not mutate the results, or else
|
|
36
|
+
// there may be weird reactivity bugs.
|
|
37
|
+
return setValue(v)
|
|
38
|
+
},
|
|
39
|
+
undefined,
|
|
40
|
+
{ label: query.label },
|
|
41
|
+
)
|
|
42
|
+
return () => {
|
|
43
|
+
// // NOTE destroying the whole query will also unsubscribe it
|
|
44
|
+
// query.destroy()
|
|
45
|
+
|
|
46
|
+
// TODO for now we'll still `cancel` manually, but we should remove this once we have some kind of
|
|
47
|
+
// ARC-based system
|
|
48
|
+
cancel()
|
|
49
|
+
span.end()
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
}, [query, store])
|
|
54
|
+
|
|
55
|
+
return value
|
|
56
|
+
}
|
package/src/reactive.ts
CHANGED
|
@@ -30,6 +30,9 @@ import { isEqual, max, uniqueId } from 'lodash-es'
|
|
|
30
30
|
|
|
31
31
|
import { BoundArray } from './bounded-collections.js'
|
|
32
32
|
|
|
33
|
+
const NOT_REFRESHED_YET = Symbol.for('NOT_REFRESHED_YET')
|
|
34
|
+
type NOT_REFRESHED_YET = typeof NOT_REFRESHED_YET
|
|
35
|
+
|
|
33
36
|
export type GetAtom = <T>(atom: Atom<T>) => T
|
|
34
37
|
|
|
35
38
|
export type Ref<T> = {
|
|
@@ -59,7 +62,7 @@ type BaseThunk<T> = {
|
|
|
59
62
|
equal: (a: T, b: T) => boolean
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
type UnevaluatedThunk<T> = BaseThunk<T> & { result:
|
|
65
|
+
type UnevaluatedThunk<T> = BaseThunk<T> & { result: NOT_REFRESHED_YET }
|
|
63
66
|
export type Thunk<T> = BaseThunk<T> & { result: T }
|
|
64
67
|
|
|
65
68
|
export type Atom<T> = Ref<T> | Thunk<T>
|
|
@@ -201,7 +204,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
|
|
|
201
204
|
const thunk: UnevaluatedThunk<T> = {
|
|
202
205
|
_tag: 'thunk',
|
|
203
206
|
id: uniqueNodeId(),
|
|
204
|
-
result:
|
|
207
|
+
result: NOT_REFRESHED_YET,
|
|
205
208
|
height: 0,
|
|
206
209
|
getResult,
|
|
207
210
|
sub: new Set(),
|
|
@@ -342,7 +345,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
|
|
|
342
345
|
this.addEdge(context, atom)
|
|
343
346
|
|
|
344
347
|
const dependencyMightBeStale = context._tag !== 'effect' && context.height <= atom.height
|
|
345
|
-
const dependencyNotRefreshedYet = atom.result ===
|
|
348
|
+
const dependencyNotRefreshedYet = atom.result === NOT_REFRESHED_YET
|
|
346
349
|
|
|
347
350
|
if (dependencyMightBeStale || dependencyNotRefreshedYet) {
|
|
348
351
|
throw new DependencyNotReadyError(
|
|
@@ -350,7 +353,6 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
|
|
|
350
353
|
)
|
|
351
354
|
}
|
|
352
355
|
|
|
353
|
-
// TODO handle case when `atom.result` is undefined
|
|
354
356
|
return atom.result
|
|
355
357
|
}
|
|
356
358
|
|
|
@@ -5,13 +5,13 @@ import type { Store } from '../store.js'
|
|
|
5
5
|
|
|
6
6
|
export type UnsubscribeQuery = () => void
|
|
7
7
|
|
|
8
|
-
export abstract class LiveStoreQueryBase {
|
|
8
|
+
export abstract class LiveStoreQueryBase<TResult> {
|
|
9
9
|
/** The key for the associated component */
|
|
10
10
|
componentKey: ComponentKey
|
|
11
11
|
/** Human-readable label for the query for debugging */
|
|
12
12
|
label: string
|
|
13
13
|
/** A pointer back to the store containing this query */
|
|
14
|
-
store: Store
|
|
14
|
+
store: Store
|
|
15
15
|
/** Otel Span is started in LiveStore store but ended in this query */
|
|
16
16
|
otelContext: otel.Context
|
|
17
17
|
|
|
@@ -26,7 +26,7 @@ export abstract class LiveStoreQueryBase {
|
|
|
26
26
|
}: {
|
|
27
27
|
componentKey: ComponentKey
|
|
28
28
|
label: string
|
|
29
|
-
store: Store
|
|
29
|
+
store: Store
|
|
30
30
|
otelContext: otel.Context
|
|
31
31
|
}) {
|
|
32
32
|
this.componentKey = componentKey
|
|
@@ -46,4 +46,10 @@ export abstract class LiveStoreQueryBase {
|
|
|
46
46
|
unsubscribe()
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
subscribe = (
|
|
51
|
+
onNewValue: (value: TResult) => void,
|
|
52
|
+
onSubsubscribe?: () => void,
|
|
53
|
+
options?: { label?: string } | undefined,
|
|
54
|
+
): (() => void) => this.store.subscribe(this as any, onNewValue as any, onSubsubscribe, options)
|
|
49
55
|
}
|
|
@@ -2,8 +2,8 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
|
|
|
2
2
|
import type * as otel from '@opentelemetry/api'
|
|
3
3
|
|
|
4
4
|
import type { ComponentKey } from '../componentKey.js'
|
|
5
|
-
import type {
|
|
6
|
-
import type { BaseGraphQLContext, Store } from '../store.js'
|
|
5
|
+
import type { Thunk } from '../reactive.js'
|
|
6
|
+
import type { BaseGraphQLContext, GetAtomResult, Store } from '../store.js'
|
|
7
7
|
import { LiveStoreQueryBase } from './base-class.js'
|
|
8
8
|
import type { LiveStoreJSQuery } from './js.js'
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@ export class LiveStoreGraphQLQuery<
|
|
|
11
11
|
TResult extends Record<string, any>,
|
|
12
12
|
VariableValues extends Record<string, any>,
|
|
13
13
|
TContext extends BaseGraphQLContext,
|
|
14
|
-
> extends LiveStoreQueryBase {
|
|
14
|
+
> extends LiveStoreQueryBase<TResult> {
|
|
15
15
|
_tag: 'graphql' = 'graphql'
|
|
16
16
|
|
|
17
17
|
/** The abstract GraphQL query */
|
|
@@ -39,7 +39,7 @@ export class LiveStoreGraphQLQuery<
|
|
|
39
39
|
this.results$ = results$
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
pipe = <U>(f: (x: TResult, get:
|
|
42
|
+
pipe = <U>(f: (x: TResult, get: GetAtomResult) => U): LiveStoreJSQuery<U> =>
|
|
43
43
|
this.store.queryJS(
|
|
44
44
|
(get) => {
|
|
45
45
|
const results = get(this.results$)
|
|
@@ -5,7 +5,7 @@ import type { GetAtom, Thunk } from '../reactive.js'
|
|
|
5
5
|
import type { Store } from '../store.js'
|
|
6
6
|
import { LiveStoreQueryBase } from './base-class.js'
|
|
7
7
|
|
|
8
|
-
export class LiveStoreJSQuery<TResult> extends LiveStoreQueryBase {
|
|
8
|
+
export class LiveStoreJSQuery<TResult> extends LiveStoreQueryBase<TResult> {
|
|
9
9
|
_tag: 'js' = 'js'
|
|
10
10
|
/** A reactive thunk representing the query results */
|
|
11
11
|
results$: Thunk<TResult>
|
|
@@ -17,7 +17,7 @@ export class LiveStoreJSQuery<TResult> extends LiveStoreQueryBase {
|
|
|
17
17
|
results$: Thunk<TResult>
|
|
18
18
|
componentKey: ComponentKey
|
|
19
19
|
label: string
|
|
20
|
-
store: Store
|
|
20
|
+
store: Store
|
|
21
21
|
otelContext: otel.Context
|
|
22
22
|
}) {
|
|
23
23
|
super(baseProps)
|