@livestore/livestore 0.3.0-dev.4 → 0.3.0-dev.40
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/QueryCache.d.ts.map +1 -1
- package/dist/SqliteDbWrapper.d.ts +60 -0
- package/dist/SqliteDbWrapper.d.ts.map +1 -0
- package/dist/{SynchronousDatabaseWrapper.js → SqliteDbWrapper.js} +69 -34
- package/dist/SqliteDbWrapper.js.map +1 -0
- package/dist/effect/LiveStore.d.ts +6 -34
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +10 -12
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/effect/mod.d.ts +3 -0
- package/dist/effect/mod.d.ts.map +1 -0
- package/dist/effect/mod.js +3 -0
- package/dist/effect/mod.js.map +1 -0
- package/dist/internal/mod.d.ts +3 -0
- package/dist/internal/mod.d.ts.map +1 -0
- package/dist/internal/mod.js +3 -0
- package/dist/internal/mod.js.map +1 -0
- package/dist/live-queries/base-class.d.ts +65 -27
- 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/client-document-get-query.d.ts +12 -0
- package/dist/live-queries/client-document-get-query.d.ts.map +1 -0
- package/dist/live-queries/client-document-get-query.js +18 -0
- package/dist/live-queries/client-document-get-query.js.map +1 -0
- package/dist/live-queries/computed.d.ts +12 -14
- package/dist/live-queries/computed.d.ts.map +1 -1
- package/dist/live-queries/computed.js +37 -15
- package/dist/live-queries/computed.js.map +1 -1
- package/dist/live-queries/db-query.d.ts +64 -0
- package/dist/live-queries/db-query.d.ts.map +1 -0
- package/dist/live-queries/{db.js → db-query.js} +83 -41
- 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 +133 -0
- package/dist/live-queries/db-query.test.js.map +1 -0
- package/dist/live-queries/mod.d.ts +5 -0
- package/dist/live-queries/mod.d.ts.map +1 -0
- package/dist/live-queries/mod.js +5 -0
- package/dist/live-queries/mod.js.map +1 -0
- package/dist/live-queries/signal.d.ts +20 -0
- package/dist/live-queries/signal.d.ts.map +1 -0
- package/dist/live-queries/signal.js +33 -0
- package/dist/live-queries/signal.js.map +1 -0
- package/dist/live-queries/signal.test.d.ts +2 -0
- package/dist/live-queries/signal.test.d.ts.map +1 -0
- package/dist/live-queries/signal.test.js +17 -0
- package/dist/live-queries/signal.test.js.map +1 -0
- package/dist/mod.d.ts +14 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +13 -0
- package/dist/mod.js.map +1 -0
- package/dist/reactive.d.ts +23 -17
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +23 -19
- package/dist/reactive.js.map +1 -1
- package/dist/reactive.test.js +1 -1
- package/dist/reactive.test.js.map +1 -1
- package/dist/store/create-store.d.ts +70 -12
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +69 -19
- 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 +103 -47
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-types.d.ts +32 -42
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store-types.js +2 -5
- package/dist/store/store-types.js.map +1 -1
- package/dist/store/store.d.ts +104 -39
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +261 -214
- package/dist/store/store.js.map +1 -1
- package/dist/utils/data-structures.d.ts.map +1 -1
- package/dist/utils/dev.d.ts.map +1 -1
- package/dist/utils/dev.js +6 -1
- package/dist/utils/dev.js.map +1 -1
- 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 +59 -216
- package/dist/utils/tests/fixture.d.ts.map +1 -1
- package/dist/utils/tests/fixture.js +23 -18
- 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/dist/utils/tests/otel.d.ts.map +1 -1
- package/dist/utils/tests/otel.js +8 -3
- package/dist/utils/tests/otel.js.map +1 -1
- package/package.json +29 -26
- package/src/{SynchronousDatabaseWrapper.ts → SqliteDbWrapper.ts} +92 -42
- package/src/effect/LiveStore.ts +27 -64
- package/src/effect/{index.ts → mod.ts} +2 -3
- package/src/internal/mod.ts +2 -0
- package/src/live-queries/__snapshots__/{db.test.ts.snap → db-query.test.ts.snap} +220 -45
- package/src/live-queries/base-class.ts +152 -50
- package/src/live-queries/client-document-get-query.ts +52 -0
- package/src/live-queries/computed.ts +51 -33
- package/src/live-queries/db-query.test.ts +192 -0
- package/src/live-queries/{db.ts → db-query.ts} +140 -82
- package/src/live-queries/mod.ts +4 -0
- package/src/live-queries/signal.test.ts +25 -0
- package/src/live-queries/signal.ts +47 -0
- package/src/mod.ts +42 -0
- package/src/reactive.test.ts +1 -1
- package/src/reactive.ts +66 -43
- package/src/store/create-store.ts +187 -59
- package/src/store/devtools.ts +136 -54
- package/src/store/store-types.ts +31 -43
- package/src/store/store.ts +385 -309
- package/src/utils/dev.ts +6 -1
- 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 +22 -31
- package/src/utils/tests/mod.ts +1 -0
- package/src/utils/tests/otel.ts +10 -3
- package/dist/SynchronousDatabaseWrapper.d.ts +0 -41
- package/dist/SynchronousDatabaseWrapper.d.ts.map +0 -1
- package/dist/SynchronousDatabaseWrapper.js.map +0 -1
- package/dist/effect/index.d.ts +0 -2
- package/dist/effect/index.d.ts.map +0 -1
- package/dist/effect/index.js +0 -2
- package/dist/effect/index.js.map +0 -1
- package/dist/global-state.d.ts +0 -14
- package/dist/global-state.d.ts.map +0 -1
- package/dist/global-state.js +0 -16
- package/dist/global-state.js.map +0 -1
- package/dist/index.d.ts +0 -20
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -16
- package/dist/index.js.map +0 -1
- package/dist/live-queries/db.d.ts +0 -66
- package/dist/live-queries/db.d.ts.map +0 -1
- package/dist/live-queries/db.js.map +0 -1
- package/dist/live-queries/db.test.d.ts +0 -2
- package/dist/live-queries/db.test.d.ts.map +0 -1
- package/dist/live-queries/db.test.js +0 -118
- package/dist/live-queries/db.test.js.map +0 -1
- package/dist/live-queries/graphql.d.ts +0 -49
- package/dist/live-queries/graphql.d.ts.map +0 -1
- package/dist/live-queries/graphql.js +0 -122
- package/dist/live-queries/graphql.js.map +0 -1
- package/dist/row-query-utils.d.ts +0 -17
- package/dist/row-query-utils.d.ts.map +0 -1
- package/dist/row-query-utils.js +0 -31
- package/dist/row-query-utils.js.map +0 -1
- package/dist/utils/otel.d.ts +0 -4
- package/dist/utils/otel.d.ts.map +0 -1
- package/dist/utils/otel.js +0 -6
- package/dist/utils/otel.js.map +0 -1
- package/src/global-state.ts +0 -20
- package/src/index.ts +0 -66
- package/src/live-queries/db.test.ts +0 -154
- package/src/live-queries/graphql.ts +0 -219
- package/src/row-query-utils.ts +0 -66
- package/src/utils/otel.ts +0 -9
- package/tsconfig.json +0 -18
- package/vitest.config.js +0 -9
package/src/store/devtools.ts
CHANGED
@@ -1,20 +1,22 @@
|
|
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'
|
5
5
|
import { Effect, Stream } from '@livestore/utils/effect'
|
6
|
+
import { nanoid } from '@livestore/utils/nanoid'
|
6
7
|
|
7
8
|
import type { LiveQuery, ReactivityGraph } from '../live-queries/base-class.js'
|
8
9
|
import { NOT_REFRESHED_YET } from '../reactive.js'
|
9
|
-
import type {
|
10
|
-
import { emptyDebugInfo as makeEmptyDebugInfo } from '../
|
10
|
+
import type { SqliteDbWrapper } from '../SqliteDbWrapper.js'
|
11
|
+
import { emptyDebugInfo as makeEmptyDebugInfo } from '../SqliteDbWrapper.js'
|
11
12
|
import type { ReferenceCountedSet } from '../utils/data-structures.js'
|
12
13
|
|
13
14
|
type IStore = {
|
14
15
|
clientSession: ClientSession
|
15
16
|
reactivityGraph: ReactivityGraph
|
16
|
-
|
17
|
+
sqliteDbWrapper: SqliteDbWrapper
|
17
18
|
activeQueries: ReferenceCountedSet<LiveQuery<any>>
|
19
|
+
syncProcessor: ClientSessionSyncProcessor
|
18
20
|
}
|
19
21
|
|
20
22
|
type Unsub = () => void
|
@@ -34,47 +36,65 @@ export const connectDevtoolsToStore = ({
|
|
34
36
|
storeDevtoolsChannel,
|
35
37
|
store,
|
36
38
|
}: {
|
37
|
-
storeDevtoolsChannel: WebChannel.WebChannel<
|
39
|
+
storeDevtoolsChannel: WebChannel.WebChannel<
|
40
|
+
Devtools.ClientSession.MessageToApp,
|
41
|
+
Devtools.ClientSession.MessageFromApp
|
42
|
+
>
|
38
43
|
store: IStore
|
39
44
|
}) =>
|
40
45
|
Effect.gen(function* () {
|
41
|
-
const appHostId = store.clientSession.coordinator.devtools.appHostId
|
42
|
-
|
43
46
|
const reactivityGraphSubcriptions: SubMap = new Map()
|
44
47
|
const liveQueriesSubscriptions: SubMap = new Map()
|
45
48
|
const debugInfoHistorySubscriptions: SubMap = new Map()
|
49
|
+
const syncHeadClientSessionSubscriptions: SubMap = new Map()
|
50
|
+
|
51
|
+
const { clientId, sessionId } = store.clientSession
|
46
52
|
|
47
53
|
yield* Effect.addFinalizer(() =>
|
48
54
|
Effect.sync(() => {
|
49
55
|
reactivityGraphSubcriptions.forEach((unsub) => unsub())
|
50
56
|
liveQueriesSubscriptions.forEach((unsub) => unsub())
|
51
57
|
debugInfoHistorySubscriptions.forEach((unsub) => unsub())
|
58
|
+
syncHeadClientSessionSubscriptions.forEach((unsub) => unsub())
|
52
59
|
}),
|
53
60
|
)
|
54
61
|
|
55
|
-
const
|
62
|
+
const handledRequestIds = new Set<RequestId>()
|
63
|
+
|
64
|
+
const sendToDevtools = (message: Devtools.ClientSession.MessageFromApp) =>
|
56
65
|
storeDevtoolsChannel.send(message).pipe(Effect.tapCauseLogPretty, Effect.runFork)
|
57
66
|
|
58
|
-
const onMessage = (decodedMessage: typeof Devtools.
|
67
|
+
const onMessage = (decodedMessage: typeof Devtools.ClientSession.MessageToApp.Type) => {
|
59
68
|
// console.debug('@livestore/livestore:store:devtools:onMessage', decodedMessage)
|
60
69
|
|
61
|
-
if (decodedMessage.
|
70
|
+
if (decodedMessage.clientId !== clientId || decodedMessage.sessionId !== sessionId) {
|
62
71
|
// console.log(`Unknown message`, event)
|
63
72
|
return
|
64
73
|
}
|
65
74
|
|
66
|
-
if (decodedMessage._tag === 'LSD.Disconnect') {
|
67
|
-
console.error('TODO handle disconnect properly in store')
|
75
|
+
if (decodedMessage._tag === 'LSD.ClientSession.Disconnect') {
|
76
|
+
// console.error('TODO handle disconnect properly in store')
|
68
77
|
return
|
69
78
|
}
|
70
79
|
|
71
80
|
const requestId = decodedMessage.requestId
|
72
81
|
|
82
|
+
// TODO we should try to move the duplicate message handling on the webmesh layer
|
83
|
+
// So far I could only observe this problem with webmesh proxy channels (e.g. for Expo)
|
84
|
+
// Proof: https://share.cleanshot.com/V9G87B0B
|
85
|
+
// Also see `leader-worker-devtools.ts` for same problem
|
86
|
+
if (handledRequestIds.has(requestId)) {
|
87
|
+
return
|
88
|
+
}
|
89
|
+
|
90
|
+
handledRequestIds.add(requestId)
|
91
|
+
|
73
92
|
const requestIdleCallback = globalThis.requestIdleCallback ?? ((cb: () => void) => cb())
|
74
93
|
|
75
94
|
switch (decodedMessage._tag) {
|
76
|
-
case 'LSD.ReactivityGraphSubscribe': {
|
95
|
+
case 'LSD.ClientSession.ReactivityGraphSubscribe': {
|
77
96
|
const includeResults = decodedMessage.includeResults
|
97
|
+
const { subscriptionId } = decodedMessage
|
78
98
|
|
79
99
|
const send = () =>
|
80
100
|
// In order to not add more work to the current tick, we use requestIdleCallback
|
@@ -82,11 +102,13 @@ export const connectDevtoolsToStore = ({
|
|
82
102
|
requestIdleCallback(
|
83
103
|
() =>
|
84
104
|
sendToDevtools(
|
85
|
-
Devtools.ReactivityGraphRes.make({
|
105
|
+
Devtools.ClientSession.ReactivityGraphRes.make({
|
86
106
|
reactivityGraph: store.reactivityGraph.getSnapshot({ includeResults }),
|
87
|
-
requestId,
|
88
|
-
|
107
|
+
requestId: nanoid(10),
|
108
|
+
clientId,
|
109
|
+
sessionId,
|
89
110
|
liveStoreVersion,
|
111
|
+
subscriptionId,
|
90
112
|
}),
|
91
113
|
),
|
92
114
|
{ timeout: 500 },
|
@@ -99,42 +121,46 @@ export const connectDevtoolsToStore = ({
|
|
99
121
|
// This might need to be tweaked further and possibly be exposed to the user in some way.
|
100
122
|
const throttledSend = throttle(send, 20)
|
101
123
|
|
102
|
-
reactivityGraphSubcriptions.set(
|
124
|
+
reactivityGraphSubcriptions.set(subscriptionId, store.reactivityGraph.subscribeToRefresh(throttledSend))
|
103
125
|
|
104
126
|
break
|
105
127
|
}
|
106
|
-
case 'LSD.DebugInfoReq': {
|
128
|
+
case 'LSD.ClientSession.DebugInfoReq': {
|
107
129
|
sendToDevtools(
|
108
|
-
Devtools.DebugInfoRes.make({
|
109
|
-
debugInfo: store.
|
130
|
+
Devtools.ClientSession.DebugInfoRes.make({
|
131
|
+
debugInfo: store.sqliteDbWrapper.debugInfo,
|
110
132
|
requestId,
|
111
|
-
|
133
|
+
clientId,
|
134
|
+
sessionId,
|
112
135
|
liveStoreVersion,
|
113
136
|
}),
|
114
137
|
)
|
115
138
|
break
|
116
139
|
}
|
117
|
-
case 'LSD.DebugInfoHistorySubscribe': {
|
140
|
+
case 'LSD.ClientSession.DebugInfoHistorySubscribe': {
|
141
|
+
const { subscriptionId } = decodedMessage
|
118
142
|
const buffer: DebugInfo[] = []
|
119
143
|
let hasStopped = false
|
120
144
|
let tickHandle: number | undefined
|
121
145
|
|
122
146
|
const tick = () => {
|
123
|
-
buffer.push(store.
|
147
|
+
buffer.push(store.sqliteDbWrapper.debugInfo)
|
124
148
|
|
125
149
|
// NOTE this resets the debug info, so all other "readers" e.g. in other `requestAnimationFrame` loops,
|
126
150
|
// will get the empty debug info
|
127
151
|
// TODO We need to come up with a more graceful way to do store. Probably via a single global
|
128
152
|
// `requestAnimationFrame` loop that is passed in somehow.
|
129
|
-
store.
|
153
|
+
store.sqliteDbWrapper.debugInfo = makeEmptyDebugInfo()
|
130
154
|
|
131
155
|
if (buffer.length > 10) {
|
132
156
|
sendToDevtools(
|
133
|
-
Devtools.DebugInfoHistoryRes.make({
|
157
|
+
Devtools.ClientSession.DebugInfoHistoryRes.make({
|
134
158
|
debugInfoHistory: buffer,
|
135
|
-
requestId,
|
136
|
-
|
159
|
+
requestId: nanoid(10),
|
160
|
+
clientId,
|
161
|
+
sessionId,
|
137
162
|
liveStoreVersion,
|
163
|
+
subscriptionId,
|
138
164
|
}),
|
139
165
|
)
|
140
166
|
buffer.length = 0
|
@@ -155,44 +181,53 @@ export const connectDevtoolsToStore = ({
|
|
155
181
|
}
|
156
182
|
}
|
157
183
|
|
158
|
-
debugInfoHistorySubscriptions.set(
|
184
|
+
debugInfoHistorySubscriptions.set(subscriptionId, unsub)
|
159
185
|
|
160
186
|
break
|
161
187
|
}
|
162
|
-
case 'LSD.DebugInfoHistoryUnsubscribe': {
|
163
|
-
|
164
|
-
//
|
165
|
-
|
166
|
-
debugInfoHistorySubscriptions.
|
188
|
+
case 'LSD.ClientSession.DebugInfoHistoryUnsubscribe': {
|
189
|
+
const { subscriptionId } = decodedMessage
|
190
|
+
// NOTE given Webmesh channels have persistent retry behaviour, it can happen that a previous
|
191
|
+
// Webmesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
192
|
+
debugInfoHistorySubscriptions.get(subscriptionId)?.()
|
193
|
+
debugInfoHistorySubscriptions.delete(subscriptionId)
|
167
194
|
break
|
168
195
|
}
|
169
|
-
case 'LSD.DebugInfoResetReq': {
|
170
|
-
store.
|
171
|
-
sendToDevtools(
|
196
|
+
case 'LSD.ClientSession.DebugInfoResetReq': {
|
197
|
+
store.sqliteDbWrapper.debugInfo.slowQueries.clear()
|
198
|
+
sendToDevtools(
|
199
|
+
Devtools.ClientSession.DebugInfoResetRes.make({ requestId, clientId, sessionId, liveStoreVersion }),
|
200
|
+
)
|
172
201
|
break
|
173
202
|
}
|
174
|
-
case 'LSD.DebugInfoRerunQueryReq': {
|
203
|
+
case 'LSD.ClientSession.DebugInfoRerunQueryReq': {
|
175
204
|
const { queryStr, bindValues, queriedTables } = decodedMessage
|
176
|
-
store.
|
177
|
-
sendToDevtools(
|
205
|
+
store.sqliteDbWrapper.select(queryStr, bindValues, { queriedTables, skipCache: true })
|
206
|
+
sendToDevtools(
|
207
|
+
Devtools.ClientSession.DebugInfoRerunQueryRes.make({ requestId, clientId, sessionId, liveStoreVersion }),
|
208
|
+
)
|
178
209
|
break
|
179
210
|
}
|
180
|
-
case 'LSD.ReactivityGraphUnsubscribe': {
|
181
|
-
|
182
|
-
//
|
183
|
-
|
211
|
+
case 'LSD.ClientSession.ReactivityGraphUnsubscribe': {
|
212
|
+
const { subscriptionId } = decodedMessage
|
213
|
+
// NOTE given Webmesh channels have persistent retry behaviour, it can happen that a previous
|
214
|
+
// Webmesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
215
|
+
reactivityGraphSubcriptions.get(subscriptionId)?.()
|
216
|
+
reactivityGraphSubcriptions.delete(subscriptionId)
|
184
217
|
break
|
185
218
|
}
|
186
|
-
case 'LSD.LiveQueriesSubscribe': {
|
219
|
+
case 'LSD.ClientSession.LiveQueriesSubscribe': {
|
220
|
+
const { subscriptionId } = decodedMessage
|
187
221
|
const send = () =>
|
188
222
|
requestIdleCallback(
|
189
223
|
() =>
|
190
224
|
sendToDevtools(
|
191
|
-
Devtools.LiveQueriesRes.make({
|
225
|
+
Devtools.ClientSession.LiveQueriesRes.make({
|
192
226
|
liveQueries: [...store.activeQueries].map((q) => ({
|
193
227
|
_tag: q._tag,
|
194
228
|
id: q.id,
|
195
229
|
label: q.label,
|
230
|
+
hash: q.def.hash,
|
196
231
|
runs: q.runs,
|
197
232
|
executionTimes: q.executionTimes.map((_) => Number(_.toString().slice(0, 5))),
|
198
233
|
lastestResult:
|
@@ -201,9 +236,11 @@ export const connectDevtoolsToStore = ({
|
|
201
236
|
: q.results$.previousResult,
|
202
237
|
activeSubscriptions: Array.from(q.activeSubscriptions),
|
203
238
|
})),
|
204
|
-
requestId,
|
239
|
+
requestId: nanoid(10),
|
205
240
|
liveStoreVersion,
|
206
|
-
|
241
|
+
clientId,
|
242
|
+
sessionId,
|
243
|
+
subscriptionId,
|
207
244
|
}),
|
208
245
|
),
|
209
246
|
{ timeout: 500 },
|
@@ -214,18 +251,63 @@ export const connectDevtoolsToStore = ({
|
|
214
251
|
// Same as in the reactivity graph subscription case above, we need to throttle the updates
|
215
252
|
const throttledSend = throttle(send, 20)
|
216
253
|
|
217
|
-
liveQueriesSubscriptions.set(
|
254
|
+
liveQueriesSubscriptions.set(subscriptionId, store.reactivityGraph.subscribeToRefresh(throttledSend))
|
218
255
|
|
219
256
|
break
|
220
257
|
}
|
221
|
-
case 'LSD.LiveQueriesUnsubscribe': {
|
222
|
-
|
223
|
-
//
|
224
|
-
|
225
|
-
liveQueriesSubscriptions.
|
258
|
+
case 'LSD.ClientSession.LiveQueriesUnsubscribe': {
|
259
|
+
const { subscriptionId } = decodedMessage
|
260
|
+
// NOTE given Webmesh channels have persistent retry behaviour, it can happen that a previous
|
261
|
+
// Webmesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
262
|
+
liveQueriesSubscriptions.get(subscriptionId)?.()
|
263
|
+
liveQueriesSubscriptions.delete(subscriptionId)
|
226
264
|
break
|
227
265
|
}
|
228
|
-
|
266
|
+
case 'LSD.ClientSession.SyncHeadSubscribe': {
|
267
|
+
const { subscriptionId } = decodedMessage
|
268
|
+
const send = (syncState: SyncState.SyncState) =>
|
269
|
+
sendToDevtools(
|
270
|
+
Devtools.ClientSession.SyncHeadRes.make({
|
271
|
+
local: syncState.localHead,
|
272
|
+
upstream: syncState.upstreamHead,
|
273
|
+
requestId: nanoid(10),
|
274
|
+
clientId,
|
275
|
+
sessionId,
|
276
|
+
liveStoreVersion,
|
277
|
+
subscriptionId,
|
278
|
+
}),
|
279
|
+
)
|
280
|
+
|
281
|
+
send(store.syncProcessor.syncState.pipe(Effect.runSync))
|
282
|
+
|
283
|
+
syncHeadClientSessionSubscriptions.set(
|
284
|
+
subscriptionId,
|
285
|
+
store.syncProcessor.syncState.changes.pipe(
|
286
|
+
Stream.tap((syncState) => send(syncState)),
|
287
|
+
Stream.runDrain,
|
288
|
+
Effect.interruptible,
|
289
|
+
Effect.tapCauseLogPretty,
|
290
|
+
Effect.runCallback,
|
291
|
+
),
|
292
|
+
)
|
293
|
+
|
294
|
+
break
|
295
|
+
}
|
296
|
+
case 'LSD.ClientSession.SyncHeadUnsubscribe': {
|
297
|
+
const { subscriptionId } = decodedMessage
|
298
|
+
// NOTE given Webmesh channels have persistent retry behaviour, it can happen that a previous
|
299
|
+
// Webmesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
300
|
+
syncHeadClientSessionSubscriptions.get(subscriptionId)?.()
|
301
|
+
syncHeadClientSessionSubscriptions.delete(subscriptionId)
|
302
|
+
break
|
303
|
+
}
|
304
|
+
case 'LSD.ClientSession.Ping': {
|
305
|
+
sendToDevtools(Devtools.ClientSession.Pong.make({ requestId, clientId, sessionId, liveStoreVersion }))
|
306
|
+
break
|
307
|
+
}
|
308
|
+
default: {
|
309
|
+
console.warn(`[LSD.ClientSession] Unknown message`, decodedMessage)
|
310
|
+
}
|
229
311
|
}
|
230
312
|
}
|
231
313
|
|
package/src/store/store-types.ts
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
import type { ClientSession, IntentionalShutdownCause, UnexpectedError } from '@livestore/common'
|
2
|
-
import type {
|
3
|
-
import type {
|
4
|
-
import {
|
1
|
+
import type { ClientSession, IntentionalShutdownCause, StoreInterrupted, UnexpectedError } from '@livestore/common'
|
2
|
+
import type { LiveStoreEvent, LiveStoreSchema } from '@livestore/common/schema'
|
3
|
+
import type { Effect, Runtime, Scope } from '@livestore/utils/effect'
|
4
|
+
import { Deferred } from '@livestore/utils/effect'
|
5
5
|
import type * as otel from '@opentelemetry/api'
|
6
|
-
import type { GraphQLSchema } from 'graphql'
|
7
6
|
|
8
|
-
import type { ReactivityGraph } from '../live-queries/base-class.js'
|
9
7
|
import type { DebugRefreshReasonBase } from '../reactive.js'
|
10
|
-
import type { SynchronousDatabaseWrapper } from '../SynchronousDatabaseWrapper.js'
|
11
8
|
import type { StackInfo } from '../utils/stack-info.js'
|
12
9
|
import type { Store } from './store.js'
|
13
10
|
|
@@ -19,63 +16,49 @@ export type LiveStoreContext =
|
|
19
16
|
}
|
20
17
|
| {
|
21
18
|
stage: 'shutdown'
|
22
|
-
cause: IntentionalShutdownCause |
|
19
|
+
cause: IntentionalShutdownCause | StoreInterrupted
|
23
20
|
}
|
24
21
|
|
25
|
-
export
|
26
|
-
export
|
27
|
-
|
28
|
-
export type ShutdownDeferred = Deferred.Deferred<
|
22
|
+
export type ShutdownDeferred = Deferred.Deferred<void, UnexpectedError | IntentionalShutdownCause | StoreInterrupted>
|
23
|
+
export const makeShutdownDeferred: Effect.Effect<ShutdownDeferred> = Deferred.make<
|
29
24
|
void,
|
30
|
-
UnexpectedError | IntentionalShutdownCause | StoreInterrupted
|
31
|
-
>
|
25
|
+
UnexpectedError | IntentionalShutdownCause | StoreInterrupted
|
26
|
+
>()
|
32
27
|
|
33
28
|
export type LiveStoreContextRunning = {
|
34
29
|
stage: 'running'
|
35
30
|
store: Store
|
36
31
|
}
|
37
32
|
|
38
|
-
export type BaseGraphQLContext = {
|
39
|
-
queriedTables: Set<string>
|
40
|
-
/** Needed by Pothos Otel plugin for resolver tracing to work */
|
41
|
-
otelContext?: otel.Context
|
42
|
-
}
|
43
|
-
|
44
|
-
export type GraphQLOptions<TContext> = {
|
45
|
-
schema: GraphQLSchema
|
46
|
-
makeContext: (db: SynchronousDatabaseWrapper, tracer: otel.Tracer, sessionId: string) => TContext
|
47
|
-
}
|
48
|
-
|
49
33
|
export type OtelOptions = {
|
50
34
|
tracer: otel.Tracer
|
51
35
|
rootSpanContext: otel.Context
|
52
36
|
}
|
53
37
|
|
54
|
-
export type StoreOptions<
|
55
|
-
TGraphQLContext extends BaseGraphQLContext,
|
56
|
-
TSchema extends LiveStoreSchema = LiveStoreSchema,
|
57
|
-
> = {
|
38
|
+
export type StoreOptions<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext = {}> = {
|
58
39
|
clientSession: ClientSession
|
59
40
|
schema: TSchema
|
60
41
|
storeId: string
|
61
|
-
|
62
|
-
graphQLOptions?: GraphQLOptions<TGraphQLContext>
|
42
|
+
context: TContext
|
63
43
|
otelOptions: OtelOptions
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
44
|
+
effectContext: {
|
45
|
+
runtime: Runtime.Runtime<Scope.Scope>
|
46
|
+
lifetimeScope: Scope.Scope
|
47
|
+
}
|
48
|
+
confirmUnsavedChanges: boolean
|
68
49
|
batchUpdates: (runUpdates: () => void) => void
|
69
|
-
|
70
|
-
|
50
|
+
params: {
|
51
|
+
leaderPushBatchSize: number
|
52
|
+
}
|
53
|
+
__runningInDevtools: boolean
|
71
54
|
}
|
72
55
|
|
73
56
|
export type RefreshReason =
|
74
57
|
| DebugRefreshReasonBase
|
75
58
|
| {
|
76
|
-
_tag: '
|
77
|
-
/** The
|
78
|
-
|
59
|
+
_tag: 'commit'
|
60
|
+
/** The events that were applied */
|
61
|
+
events: ReadonlyArray<LiveStoreEvent.AnyDecoded | LiveStoreEvent.PartialAnyDecoded>
|
79
62
|
|
80
63
|
/** The tables that were written to by the event */
|
81
64
|
writeTables: ReadonlyArray<string>
|
@@ -87,10 +70,12 @@ export type RefreshReason =
|
|
87
70
|
label?: string
|
88
71
|
stackInfo?: StackInfo
|
89
72
|
}
|
73
|
+
| { _tag: 'subscribe.initial'; label?: string }
|
74
|
+
| { _tag: 'subscribe.update'; label?: string }
|
90
75
|
| { _tag: 'manual'; label?: string }
|
91
76
|
|
92
77
|
export type QueryDebugInfo = {
|
93
|
-
_tag:
|
78
|
+
_tag: string
|
94
79
|
label: string
|
95
80
|
query: string
|
96
81
|
durationMs: number
|
@@ -98,13 +83,16 @@ export type QueryDebugInfo = {
|
|
98
83
|
|
99
84
|
export type StoreOtel = {
|
100
85
|
tracer: otel.Tracer
|
101
|
-
|
86
|
+
rootSpanContext: otel.Context
|
87
|
+
commitsSpanContext: otel.Context
|
102
88
|
queriesSpanContext: otel.Context
|
103
89
|
}
|
104
90
|
|
105
|
-
export type
|
91
|
+
export type StoreCommitOptions = {
|
106
92
|
label?: string
|
107
93
|
skipRefresh?: boolean
|
108
94
|
spanLinks?: otel.Link[]
|
109
95
|
otelContext?: otel.Context
|
110
96
|
}
|
97
|
+
|
98
|
+
export type Unsubscribe = () => void
|