@livestore/livestore 0.3.0-dev.10 → 0.3.0-dev.12
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/dist/.tsbuildinfo +1 -1
- package/dist/SqliteDbWrapper.d.ts +54 -0
- package/dist/SqliteDbWrapper.d.ts.map +1 -0
- package/dist/SqliteDbWrapper.js +211 -0
- package/dist/SqliteDbWrapper.js.map +1 -0
- package/dist/SynchronousDatabaseWrapper.d.ts +14 -5
- package/dist/SynchronousDatabaseWrapper.d.ts.map +1 -1
- package/dist/SynchronousDatabaseWrapper.js +24 -4
- package/dist/SynchronousDatabaseWrapper.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +12 -8
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +9 -2
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/index.d.ts +6 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/live-queries/base-class.d.ts +57 -21
- package/dist/live-queries/base-class.d.ts.map +1 -1
- package/dist/live-queries/base-class.js +54 -13
- package/dist/live-queries/base-class.js.map +1 -1
- package/dist/live-queries/computed.d.ts +7 -7
- package/dist/live-queries/computed.d.ts.map +1 -1
- package/dist/live-queries/computed.js +34 -11
- package/dist/live-queries/computed.js.map +1 -1
- package/dist/live-queries/db-query.d.ts +67 -0
- package/dist/live-queries/db-query.d.ts.map +1 -0
- package/dist/live-queries/db-query.js +243 -0
- package/dist/live-queries/db-query.js.map +1 -0
- package/dist/live-queries/db-query.test.d.ts +2 -0
- package/dist/live-queries/db-query.test.d.ts.map +1 -0
- package/dist/live-queries/db-query.test.js +113 -0
- package/dist/live-queries/db-query.test.js.map +1 -0
- package/dist/live-queries/db.d.ts +12 -15
- package/dist/live-queries/db.d.ts.map +1 -1
- package/dist/live-queries/db.js +44 -25
- package/dist/live-queries/db.js.map +1 -1
- package/dist/live-queries/db.test.js +16 -14
- package/dist/live-queries/db.test.js.map +1 -1
- package/dist/live-queries/graphql.d.ts +8 -8
- package/dist/live-queries/graphql.d.ts.map +1 -1
- package/dist/live-queries/graphql.js +34 -9
- package/dist/live-queries/graphql.js.map +1 -1
- package/dist/live-queries/make-ref.d.ts +20 -0
- package/dist/live-queries/make-ref.d.ts.map +1 -0
- package/dist/live-queries/make-ref.js +33 -0
- package/dist/live-queries/make-ref.js.map +1 -0
- package/dist/reactive.d.ts +19 -13
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +22 -18
- package/dist/reactive.js.map +1 -1
- package/dist/reactive.test.js +1 -1
- package/dist/reactive.test.js.map +1 -1
- package/dist/row-query-utils.d.ts +6 -6
- package/dist/row-query-utils.d.ts.map +1 -1
- package/dist/row-query-utils.js +15 -11
- package/dist/row-query-utils.js.map +1 -1
- package/dist/store/create-store.d.ts +7 -5
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +21 -7
- package/dist/store/create-store.js.map +1 -1
- package/dist/store/devtools.d.ts +5 -4
- package/dist/store/devtools.d.ts.map +1 -1
- package/dist/store/devtools.js +45 -23
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-types.d.ts +9 -4
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store-types.js.map +1 -1
- package/dist/store/store.d.ts +36 -18
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +127 -75
- package/dist/store/store.js.map +1 -1
- package/dist/utils/expo.d.ts +2 -0
- package/dist/utils/expo.d.ts.map +1 -0
- package/dist/utils/expo.js +8 -0
- package/dist/utils/expo.js.map +1 -0
- package/dist/utils/function-string.d.ts +7 -0
- package/dist/utils/function-string.d.ts.map +1 -0
- package/dist/utils/function-string.js +9 -0
- package/dist/utils/function-string.js.map +1 -0
- package/dist/utils/stack-info.d.ts.map +1 -1
- package/dist/utils/stack-info.js +6 -1
- package/dist/utils/stack-info.js.map +1 -1
- package/dist/utils/stack-info.test.js +54 -1
- package/dist/utils/stack-info.test.js.map +1 -1
- package/dist/utils/tests/fixture.d.ts +2 -6
- package/dist/utils/tests/fixture.d.ts.map +1 -1
- package/dist/utils/tests/fixture.js +3 -5
- package/dist/utils/tests/fixture.js.map +1 -1
- package/dist/utils/tests/mod.d.ts +1 -0
- package/dist/utils/tests/mod.d.ts.map +1 -1
- package/dist/utils/tests/mod.js +1 -0
- package/dist/utils/tests/mod.js.map +1 -1
- package/package.json +5 -5
- package/src/{SynchronousDatabaseWrapper.ts → SqliteDbWrapper.ts} +41 -12
- package/src/effect/LiveStore.ts +22 -14
- package/src/index.ts +14 -7
- package/src/live-queries/__snapshots__/{db.test.ts.snap → db-query.test.ts.snap} +196 -45
- package/src/live-queries/base-class.ts +151 -40
- package/src/live-queries/computed.ts +44 -19
- package/src/live-queries/{db.test.ts → db-query.test.ts} +44 -32
- package/src/live-queries/{db.ts → db-query.ts} +96 -39
- package/src/live-queries/graphql.ts +46 -21
- package/src/live-queries/make-ref.ts +47 -0
- package/src/reactive.test.ts +1 -1
- package/src/reactive.ts +60 -37
- package/src/row-query-utils.ts +32 -21
- package/src/store/create-store.ts +55 -27
- package/src/store/devtools.ts +74 -29
- package/src/store/store-types.ts +6 -4
- package/src/store/store.ts +231 -121
- package/src/utils/function-string.ts +12 -0
- package/src/utils/stack-info.test.ts +58 -1
- package/src/utils/stack-info.ts +6 -1
- package/src/utils/tests/fixture.ts +2 -7
- package/src/utils/tests/mod.ts +1 -0
- package/src/global-state.ts +0 -20
|
@@ -2,8 +2,9 @@ import type {
|
|
|
2
2
|
Adapter,
|
|
3
3
|
BootStatus,
|
|
4
4
|
ClientSession,
|
|
5
|
+
ClientSessionDevtoolsChannel,
|
|
5
6
|
IntentionalShutdownCause,
|
|
6
|
-
|
|
7
|
+
MigrationsReport,
|
|
7
8
|
} from '@livestore/common'
|
|
8
9
|
import { provideOtel, UnexpectedError } from '@livestore/common'
|
|
9
10
|
import type { EventId, LiveStoreSchema, MutationEvent } from '@livestore/common/schema'
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
Effect,
|
|
15
16
|
Exit,
|
|
16
17
|
identity,
|
|
18
|
+
Layer,
|
|
17
19
|
Logger,
|
|
18
20
|
LogLevel,
|
|
19
21
|
MutableHashMap,
|
|
@@ -26,8 +28,7 @@ import {
|
|
|
26
28
|
import { nanoid } from '@livestore/utils/nanoid'
|
|
27
29
|
import * as otel from '@opentelemetry/api'
|
|
28
30
|
|
|
29
|
-
import {
|
|
30
|
-
import type { ReactivityGraph } from '../live-queries/base-class.js'
|
|
31
|
+
import { LiveStoreContextRunning } from '../effect/index.js'
|
|
31
32
|
import { connectDevtoolsToStore } from './devtools.js'
|
|
32
33
|
import { Store } from './store.js'
|
|
33
34
|
import type { BaseGraphQLContext, GraphQLOptions, OtelOptions, ShutdownDeferred } from './store-types.js'
|
|
@@ -36,12 +37,14 @@ export interface CreateStoreOptions<TGraphQLContext extends BaseGraphQLContext,
|
|
|
36
37
|
schema: TSchema
|
|
37
38
|
adapter: Adapter
|
|
38
39
|
storeId: string
|
|
39
|
-
reactivityGraph?: ReactivityGraph
|
|
40
40
|
graphQLOptions?: GraphQLOptions<TGraphQLContext>
|
|
41
41
|
boot?: (
|
|
42
42
|
store: Store<TGraphQLContext, TSchema>,
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
ctx: {
|
|
44
|
+
migrationsReport: MigrationsReport
|
|
45
|
+
parentSpan: otel.Span
|
|
46
|
+
},
|
|
47
|
+
) => void | Promise<void> | Effect.Effect<void, unknown, OtelTracer.OtelTracer | LiveStoreContextRunning>
|
|
45
48
|
batchUpdates?: (run: () => void) => void
|
|
46
49
|
disableDevtools?: boolean
|
|
47
50
|
onBootStatus?: (status: BootStatus) => void
|
|
@@ -95,7 +98,6 @@ export const createStore = <
|
|
|
95
98
|
storeId,
|
|
96
99
|
graphQLOptions,
|
|
97
100
|
boot,
|
|
98
|
-
reactivityGraph = globalReactivityGraph,
|
|
99
101
|
batchUpdates,
|
|
100
102
|
disableDevtools,
|
|
101
103
|
onBootStatus,
|
|
@@ -109,6 +111,8 @@ export const createStore = <
|
|
|
109
111
|
Effect.gen(function* () {
|
|
110
112
|
const lifetimeScope = yield* Scope.make()
|
|
111
113
|
|
|
114
|
+
yield* validateStoreId(storeId)
|
|
115
|
+
|
|
112
116
|
yield* Effect.addFinalizer((_) => Scope.close(lifetimeScope, _))
|
|
113
117
|
|
|
114
118
|
const debugInstanceId = debug?.instanceId ?? nanoid(10)
|
|
@@ -130,7 +134,7 @@ export const createStore = <
|
|
|
130
134
|
|
|
131
135
|
const storeDeferred = yield* Deferred.make<Store>()
|
|
132
136
|
|
|
133
|
-
const connectDevtoolsToStore_ = (storeDevtoolsChannel:
|
|
137
|
+
const connectDevtoolsToStore_ = (storeDevtoolsChannel: ClientSessionDevtoolsChannel) =>
|
|
134
138
|
Effect.gen(function* () {
|
|
135
139
|
const store = yield* storeDeferred
|
|
136
140
|
yield* connectDevtoolsToStore({ storeDevtoolsChannel, store })
|
|
@@ -160,32 +164,44 @@ export const createStore = <
|
|
|
160
164
|
debugInstanceId,
|
|
161
165
|
}).pipe(Effect.withPerformanceMeasure('livestore:makeAdapter'), Effect.withSpan('createStore:makeAdapter'))
|
|
162
166
|
|
|
167
|
+
if (LS_DEV && clientSession.leaderThread.initialState.migrationsReport.migrations.length > 0) {
|
|
168
|
+
yield* Effect.logDebug(
|
|
169
|
+
'[@livestore/livestore:createStore] migrationsReport',
|
|
170
|
+
...clientSession.leaderThread.initialState.migrationsReport.migrations.map(
|
|
171
|
+
(m) =>
|
|
172
|
+
`Schema hash mismatch for table '${m.tableName}' (DB: ${m.hashes.actual}, expected: ${m.hashes.expected}), migrating table...`,
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
163
177
|
// TODO fill up with unsynced mutation events from the client session
|
|
164
178
|
const unsyncedMutationEvents = MutableHashMap.empty<EventId.EventId, MutationEvent.ForSchema<TSchema>>()
|
|
165
179
|
|
|
166
|
-
const store = Store
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
)
|
|
180
|
+
const store = new Store<TGraphQLContext, TSchema>({
|
|
181
|
+
clientSession,
|
|
182
|
+
schema,
|
|
183
|
+
graphQLOptions,
|
|
184
|
+
otelOptions: { tracer: otelTracer, rootSpanContext: otelRootSpanContext },
|
|
185
|
+
disableDevtools,
|
|
186
|
+
unsyncedMutationEvents,
|
|
187
|
+
lifetimeScope,
|
|
188
|
+
runtime,
|
|
189
|
+
// NOTE during boot we're not yet executing mutations in a batched context
|
|
190
|
+
// but only set the provided `batchUpdates` function after boot
|
|
191
|
+
batchUpdates: (run) => run(),
|
|
192
|
+
storeId,
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
// Starts background fibers (syncing, mutation processing, etc) for store
|
|
196
|
+
yield* store.boot
|
|
184
197
|
|
|
185
198
|
if (boot !== undefined) {
|
|
186
199
|
// TODO also incorporate `boot` function progress into `bootStatusQueue`
|
|
187
|
-
yield* Effect.tryAll(() =>
|
|
200
|
+
yield* Effect.tryAll(() =>
|
|
201
|
+
boot(store, { migrationsReport: clientSession.leaderThread.initialState.migrationsReport, parentSpan: span }),
|
|
202
|
+
).pipe(
|
|
188
203
|
UnexpectedError.mapToUnexpectedError,
|
|
204
|
+
Effect.provide(Layer.succeed(LiveStoreContextRunning, { stage: 'running', store: store as any as Store })),
|
|
189
205
|
Effect.withSpan('createStore:boot'),
|
|
190
206
|
)
|
|
191
207
|
}
|
|
@@ -208,3 +224,15 @@ export const createStore = <
|
|
|
208
224
|
Scope.extend(lifetimeScope),
|
|
209
225
|
)
|
|
210
226
|
})
|
|
227
|
+
|
|
228
|
+
const validateStoreId = (storeId: string) =>
|
|
229
|
+
Effect.gen(function* () {
|
|
230
|
+
const validChars = /^[a-zA-Z0-9_-]+$/
|
|
231
|
+
|
|
232
|
+
if (!validChars.test(storeId)) {
|
|
233
|
+
return yield* UnexpectedError.make({
|
|
234
|
+
cause: `Invalid storeId: ${storeId}. Only alphanumeric characters, underscores, and hyphens are allowed.`,
|
|
235
|
+
payload: { storeId },
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
})
|
package/src/store/devtools.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientSession, DebugInfo } from '@livestore/common'
|
|
1
|
+
import type { ClientSession, ClientSessionSyncProcessor, DebugInfo, SyncState } from '@livestore/common'
|
|
2
2
|
import { Devtools, liveStoreVersion, UnexpectedError } from '@livestore/common'
|
|
3
3
|
import { throttle } from '@livestore/utils'
|
|
4
4
|
import type { WebChannel } from '@livestore/utils/effect'
|
|
@@ -6,15 +6,16 @@ import { Effect, Stream } from '@livestore/utils/effect'
|
|
|
6
6
|
|
|
7
7
|
import type { LiveQuery, ReactivityGraph } from '../live-queries/base-class.js'
|
|
8
8
|
import { NOT_REFRESHED_YET } from '../reactive.js'
|
|
9
|
-
import type {
|
|
10
|
-
import { emptyDebugInfo as makeEmptyDebugInfo } from '../
|
|
9
|
+
import type { SqliteDbWrapper } from '../SqliteDbWrapper.js'
|
|
10
|
+
import { emptyDebugInfo as makeEmptyDebugInfo } from '../SqliteDbWrapper.js'
|
|
11
11
|
import type { ReferenceCountedSet } from '../utils/data-structures.js'
|
|
12
12
|
|
|
13
13
|
type IStore = {
|
|
14
14
|
clientSession: ClientSession
|
|
15
15
|
reactivityGraph: ReactivityGraph
|
|
16
|
-
|
|
16
|
+
sqliteDbWrapper: SqliteDbWrapper
|
|
17
17
|
activeQueries: ReferenceCountedSet<LiveQuery<any>>
|
|
18
|
+
syncProcessor: ClientSessionSyncProcessor
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
type Unsub = () => void
|
|
@@ -34,13 +35,17 @@ export const connectDevtoolsToStore = ({
|
|
|
34
35
|
storeDevtoolsChannel,
|
|
35
36
|
store,
|
|
36
37
|
}: {
|
|
37
|
-
storeDevtoolsChannel: WebChannel.WebChannel<
|
|
38
|
+
storeDevtoolsChannel: WebChannel.WebChannel<
|
|
39
|
+
Devtools.ClientSession.MessageToApp,
|
|
40
|
+
Devtools.ClientSession.MessageFromApp
|
|
41
|
+
>
|
|
38
42
|
store: IStore
|
|
39
43
|
}) =>
|
|
40
44
|
Effect.gen(function* () {
|
|
41
45
|
const reactivityGraphSubcriptions: SubMap = new Map()
|
|
42
46
|
const liveQueriesSubscriptions: SubMap = new Map()
|
|
43
47
|
const debugInfoHistorySubscriptions: SubMap = new Map()
|
|
48
|
+
const syncHeadClientSessionSubscriptions: SubMap = new Map()
|
|
44
49
|
|
|
45
50
|
const { clientId, sessionId } = store.clientSession
|
|
46
51
|
|
|
@@ -49,13 +54,14 @@ export const connectDevtoolsToStore = ({
|
|
|
49
54
|
reactivityGraphSubcriptions.forEach((unsub) => unsub())
|
|
50
55
|
liveQueriesSubscriptions.forEach((unsub) => unsub())
|
|
51
56
|
debugInfoHistorySubscriptions.forEach((unsub) => unsub())
|
|
57
|
+
syncHeadClientSessionSubscriptions.forEach((unsub) => unsub())
|
|
52
58
|
}),
|
|
53
59
|
)
|
|
54
60
|
|
|
55
|
-
const sendToDevtools = (message: Devtools.
|
|
61
|
+
const sendToDevtools = (message: Devtools.ClientSession.MessageFromApp) =>
|
|
56
62
|
storeDevtoolsChannel.send(message).pipe(Effect.tapCauseLogPretty, Effect.runFork)
|
|
57
63
|
|
|
58
|
-
const onMessage = (decodedMessage: typeof Devtools.
|
|
64
|
+
const onMessage = (decodedMessage: typeof Devtools.ClientSession.MessageToApp.Type) => {
|
|
59
65
|
// console.debug('@livestore/livestore:store:devtools:onMessage', decodedMessage)
|
|
60
66
|
|
|
61
67
|
if (decodedMessage.clientId !== clientId || decodedMessage.sessionId !== sessionId) {
|
|
@@ -63,7 +69,7 @@ export const connectDevtoolsToStore = ({
|
|
|
63
69
|
return
|
|
64
70
|
}
|
|
65
71
|
|
|
66
|
-
if (decodedMessage._tag === 'LSD.Disconnect') {
|
|
72
|
+
if (decodedMessage._tag === 'LSD.ClientSession.Disconnect') {
|
|
67
73
|
// console.error('TODO handle disconnect properly in store')
|
|
68
74
|
return
|
|
69
75
|
}
|
|
@@ -73,7 +79,7 @@ export const connectDevtoolsToStore = ({
|
|
|
73
79
|
const requestIdleCallback = globalThis.requestIdleCallback ?? ((cb: () => void) => cb())
|
|
74
80
|
|
|
75
81
|
switch (decodedMessage._tag) {
|
|
76
|
-
case 'LSD.ReactivityGraphSubscribe': {
|
|
82
|
+
case 'LSD.ClientSession.ReactivityGraphSubscribe': {
|
|
77
83
|
const includeResults = decodedMessage.includeResults
|
|
78
84
|
|
|
79
85
|
const send = () =>
|
|
@@ -82,7 +88,7 @@ export const connectDevtoolsToStore = ({
|
|
|
82
88
|
requestIdleCallback(
|
|
83
89
|
() =>
|
|
84
90
|
sendToDevtools(
|
|
85
|
-
Devtools.ReactivityGraphRes.make({
|
|
91
|
+
Devtools.ClientSession.ReactivityGraphRes.make({
|
|
86
92
|
reactivityGraph: store.reactivityGraph.getSnapshot({ includeResults }),
|
|
87
93
|
requestId,
|
|
88
94
|
clientId,
|
|
@@ -104,10 +110,10 @@ export const connectDevtoolsToStore = ({
|
|
|
104
110
|
|
|
105
111
|
break
|
|
106
112
|
}
|
|
107
|
-
case 'LSD.DebugInfoReq': {
|
|
113
|
+
case 'LSD.ClientSession.DebugInfoReq': {
|
|
108
114
|
sendToDevtools(
|
|
109
|
-
Devtools.DebugInfoRes.make({
|
|
110
|
-
debugInfo: store.
|
|
115
|
+
Devtools.ClientSession.DebugInfoRes.make({
|
|
116
|
+
debugInfo: store.sqliteDbWrapper.debugInfo,
|
|
111
117
|
requestId,
|
|
112
118
|
clientId,
|
|
113
119
|
sessionId,
|
|
@@ -116,23 +122,23 @@ export const connectDevtoolsToStore = ({
|
|
|
116
122
|
)
|
|
117
123
|
break
|
|
118
124
|
}
|
|
119
|
-
case 'LSD.DebugInfoHistorySubscribe': {
|
|
125
|
+
case 'LSD.ClientSession.DebugInfoHistorySubscribe': {
|
|
120
126
|
const buffer: DebugInfo[] = []
|
|
121
127
|
let hasStopped = false
|
|
122
128
|
let tickHandle: number | undefined
|
|
123
129
|
|
|
124
130
|
const tick = () => {
|
|
125
|
-
buffer.push(store.
|
|
131
|
+
buffer.push(store.sqliteDbWrapper.debugInfo)
|
|
126
132
|
|
|
127
133
|
// NOTE this resets the debug info, so all other "readers" e.g. in other `requestAnimationFrame` loops,
|
|
128
134
|
// will get the empty debug info
|
|
129
135
|
// TODO We need to come up with a more graceful way to do store. Probably via a single global
|
|
130
136
|
// `requestAnimationFrame` loop that is passed in somehow.
|
|
131
|
-
store.
|
|
137
|
+
store.sqliteDbWrapper.debugInfo = makeEmptyDebugInfo()
|
|
132
138
|
|
|
133
139
|
if (buffer.length > 10) {
|
|
134
140
|
sendToDevtools(
|
|
135
|
-
Devtools.DebugInfoHistoryRes.make({
|
|
141
|
+
Devtools.ClientSession.DebugInfoHistoryRes.make({
|
|
136
142
|
debugInfoHistory: buffer,
|
|
137
143
|
requestId,
|
|
138
144
|
clientId,
|
|
@@ -162,36 +168,40 @@ export const connectDevtoolsToStore = ({
|
|
|
162
168
|
|
|
163
169
|
break
|
|
164
170
|
}
|
|
165
|
-
case 'LSD.DebugInfoHistoryUnsubscribe': {
|
|
171
|
+
case 'LSD.ClientSession.DebugInfoHistoryUnsubscribe': {
|
|
166
172
|
// NOTE given WebMesh channels have persistent retry behaviour, it can happen that a previous
|
|
167
173
|
// WebMesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
|
168
174
|
debugInfoHistorySubscriptions.get(requestId)?.()
|
|
169
175
|
debugInfoHistorySubscriptions.delete(requestId)
|
|
170
176
|
break
|
|
171
177
|
}
|
|
172
|
-
case 'LSD.DebugInfoResetReq': {
|
|
173
|
-
store.
|
|
174
|
-
sendToDevtools(
|
|
178
|
+
case 'LSD.ClientSession.DebugInfoResetReq': {
|
|
179
|
+
store.sqliteDbWrapper.debugInfo.slowQueries.clear()
|
|
180
|
+
sendToDevtools(
|
|
181
|
+
Devtools.ClientSession.DebugInfoResetRes.make({ requestId, clientId, sessionId, liveStoreVersion }),
|
|
182
|
+
)
|
|
175
183
|
break
|
|
176
184
|
}
|
|
177
|
-
case 'LSD.DebugInfoRerunQueryReq': {
|
|
185
|
+
case 'LSD.ClientSession.DebugInfoRerunQueryReq': {
|
|
178
186
|
const { queryStr, bindValues, queriedTables } = decodedMessage
|
|
179
|
-
store.
|
|
180
|
-
sendToDevtools(
|
|
187
|
+
store.sqliteDbWrapper.select(queryStr, bindValues, { queriedTables, skipCache: true })
|
|
188
|
+
sendToDevtools(
|
|
189
|
+
Devtools.ClientSession.DebugInfoRerunQueryRes.make({ requestId, clientId, sessionId, liveStoreVersion }),
|
|
190
|
+
)
|
|
181
191
|
break
|
|
182
192
|
}
|
|
183
|
-
case 'LSD.ReactivityGraphUnsubscribe': {
|
|
193
|
+
case 'LSD.ClientSession.ReactivityGraphUnsubscribe': {
|
|
184
194
|
// NOTE given WebMesh channels have persistent retry behaviour, it can happen that a previous
|
|
185
195
|
// WebMesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
|
186
196
|
reactivityGraphSubcriptions.get(requestId)?.()
|
|
187
197
|
break
|
|
188
198
|
}
|
|
189
|
-
case 'LSD.LiveQueriesSubscribe': {
|
|
199
|
+
case 'LSD.ClientSession.LiveQueriesSubscribe': {
|
|
190
200
|
const send = () =>
|
|
191
201
|
requestIdleCallback(
|
|
192
202
|
() =>
|
|
193
203
|
sendToDevtools(
|
|
194
|
-
Devtools.LiveQueriesRes.make({
|
|
204
|
+
Devtools.ClientSession.LiveQueriesRes.make({
|
|
195
205
|
liveQueries: [...store.activeQueries].map((q) => ({
|
|
196
206
|
_tag: q._tag,
|
|
197
207
|
id: q.id,
|
|
@@ -222,14 +232,49 @@ export const connectDevtoolsToStore = ({
|
|
|
222
232
|
|
|
223
233
|
break
|
|
224
234
|
}
|
|
225
|
-
case 'LSD.LiveQueriesUnsubscribe': {
|
|
235
|
+
case 'LSD.ClientSession.LiveQueriesUnsubscribe': {
|
|
226
236
|
// NOTE given WebMesh channels have persistent retry behaviour, it can happen that a previous
|
|
227
237
|
// WebMesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
|
228
238
|
liveQueriesSubscriptions.get(requestId)?.()
|
|
229
239
|
liveQueriesSubscriptions.delete(requestId)
|
|
230
240
|
break
|
|
231
241
|
}
|
|
232
|
-
|
|
242
|
+
case 'LSD.ClientSession.SyncHeadSubscribe': {
|
|
243
|
+
const send = (syncState: SyncState) =>
|
|
244
|
+
sendToDevtools(
|
|
245
|
+
Devtools.ClientSession.SyncHeadRes.make({
|
|
246
|
+
local: syncState.localHead,
|
|
247
|
+
upstream: syncState.upstreamHead,
|
|
248
|
+
requestId,
|
|
249
|
+
clientId,
|
|
250
|
+
sessionId,
|
|
251
|
+
liveStoreVersion,
|
|
252
|
+
}),
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
send(store.syncProcessor.syncState.pipe(Effect.runSync))
|
|
256
|
+
|
|
257
|
+
syncHeadClientSessionSubscriptions.set(
|
|
258
|
+
requestId,
|
|
259
|
+
store.syncProcessor.syncState.changes.pipe(
|
|
260
|
+
Stream.tap((syncState) => send(syncState)),
|
|
261
|
+
Stream.runDrain,
|
|
262
|
+
Effect.interruptible,
|
|
263
|
+
Effect.tapCauseLogPretty,
|
|
264
|
+
Effect.runCallback,
|
|
265
|
+
),
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
break
|
|
269
|
+
}
|
|
270
|
+
case 'LSD.ClientSession.SyncHeadUnsubscribe': {
|
|
271
|
+
syncHeadClientSessionSubscriptions.get(requestId)?.()
|
|
272
|
+
syncHeadClientSessionSubscriptions.delete(requestId)
|
|
273
|
+
break
|
|
274
|
+
}
|
|
275
|
+
default: {
|
|
276
|
+
console.warn(`[LSD.ClientSession] Unknown message`, decodedMessage)
|
|
277
|
+
}
|
|
233
278
|
}
|
|
234
279
|
}
|
|
235
280
|
|
package/src/store/store-types.ts
CHANGED
|
@@ -5,9 +5,8 @@ import { Schema } from '@livestore/utils/effect'
|
|
|
5
5
|
import type * as otel from '@opentelemetry/api'
|
|
6
6
|
import type { GraphQLSchema } from 'graphql'
|
|
7
7
|
|
|
8
|
-
import type { ReactivityGraph } from '../live-queries/base-class.js'
|
|
9
8
|
import type { DebugRefreshReasonBase } from '../reactive.js'
|
|
10
|
-
import type {
|
|
9
|
+
import type { SqliteDbWrapper } from '../SqliteDbWrapper.js'
|
|
11
10
|
import type { StackInfo } from '../utils/stack-info.js'
|
|
12
11
|
import type { Store } from './store.js'
|
|
13
12
|
|
|
@@ -43,7 +42,7 @@ export type BaseGraphQLContext = {
|
|
|
43
42
|
|
|
44
43
|
export type GraphQLOptions<TContext> = {
|
|
45
44
|
schema: GraphQLSchema
|
|
46
|
-
makeContext: (db:
|
|
45
|
+
makeContext: (db: SqliteDbWrapper, tracer: otel.Tracer, sessionId: string) => TContext
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
export type OtelOptions = {
|
|
@@ -61,7 +60,6 @@ export type StoreOptions<
|
|
|
61
60
|
// TODO remove graphql-related stuff from store and move to GraphQL query directly
|
|
62
61
|
graphQLOptions?: GraphQLOptions<TGraphQLContext>
|
|
63
62
|
otelOptions: OtelOptions
|
|
64
|
-
reactivityGraph: ReactivityGraph
|
|
65
63
|
disableDevtools?: boolean
|
|
66
64
|
lifetimeScope: Scope.Scope
|
|
67
65
|
runtime: Runtime.Runtime<Scope.Scope>
|
|
@@ -87,6 +85,8 @@ export type RefreshReason =
|
|
|
87
85
|
label?: string
|
|
88
86
|
stackInfo?: StackInfo
|
|
89
87
|
}
|
|
88
|
+
| { _tag: 'subscribe.initial'; label?: string }
|
|
89
|
+
| { _tag: 'subscribe.update'; label?: string }
|
|
90
90
|
| { _tag: 'manual'; label?: string }
|
|
91
91
|
|
|
92
92
|
export type QueryDebugInfo = {
|
|
@@ -108,3 +108,5 @@ export type StoreMutateOptions = {
|
|
|
108
108
|
spanLinks?: otel.Link[]
|
|
109
109
|
otelContext?: otel.Context
|
|
110
110
|
}
|
|
111
|
+
|
|
112
|
+
export type Unsubscribe = () => void
|