@livestore/livestore 0.0.0-snapshot-ee8e0fc3b894cf3159269c9c8969a8fc4b398dca → 0.0.0-snapshot-fec375f0f61a7bc75278adc60d1a55f96a9c292a
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/store/create-store.d.ts +8 -1
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +3 -2
- package/dist/store/create-store.js.map +1 -1
- package/dist/store/devtools.d.ts.map +1 -1
- package/dist/store/devtools.js +40 -15
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-types.d.ts +1 -0
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store.d.ts +1 -1
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +2 -1
- package/dist/store/store.js.map +1 -1
- package/package.json +4 -4
- package/src/store/create-store.ts +10 -1
- package/src/store/devtools.ts +43 -15
- package/src/store/store-types.ts +1 -0
- package/src/store/store.ts +2 -0
package/src/store/devtools.ts
CHANGED
|
@@ -3,6 +3,7 @@ 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'
|
|
@@ -58,6 +59,8 @@ export const connectDevtoolsToStore = ({
|
|
|
58
59
|
}),
|
|
59
60
|
)
|
|
60
61
|
|
|
62
|
+
const handledRequestIds = new Set<RequestId>()
|
|
63
|
+
|
|
61
64
|
const sendToDevtools = (message: Devtools.ClientSession.MessageFromApp) =>
|
|
62
65
|
storeDevtoolsChannel.send(message).pipe(Effect.tapCauseLogPretty, Effect.runFork)
|
|
63
66
|
|
|
@@ -76,11 +79,22 @@ export const connectDevtoolsToStore = ({
|
|
|
76
79
|
|
|
77
80
|
const requestId = decodedMessage.requestId
|
|
78
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
|
+
|
|
79
92
|
const requestIdleCallback = globalThis.requestIdleCallback ?? ((cb: () => void) => cb())
|
|
80
93
|
|
|
81
94
|
switch (decodedMessage._tag) {
|
|
82
95
|
case 'LSD.ClientSession.ReactivityGraphSubscribe': {
|
|
83
96
|
const includeResults = decodedMessage.includeResults
|
|
97
|
+
const { subscriptionId } = decodedMessage
|
|
84
98
|
|
|
85
99
|
const send = () =>
|
|
86
100
|
// In order to not add more work to the current tick, we use requestIdleCallback
|
|
@@ -90,10 +104,11 @@ export const connectDevtoolsToStore = ({
|
|
|
90
104
|
sendToDevtools(
|
|
91
105
|
Devtools.ClientSession.ReactivityGraphRes.make({
|
|
92
106
|
reactivityGraph: store.reactivityGraph.getSnapshot({ includeResults }),
|
|
93
|
-
requestId,
|
|
107
|
+
requestId: nanoid(10),
|
|
94
108
|
clientId,
|
|
95
109
|
sessionId,
|
|
96
110
|
liveStoreVersion,
|
|
111
|
+
subscriptionId,
|
|
97
112
|
}),
|
|
98
113
|
),
|
|
99
114
|
{ timeout: 500 },
|
|
@@ -106,7 +121,7 @@ export const connectDevtoolsToStore = ({
|
|
|
106
121
|
// This might need to be tweaked further and possibly be exposed to the user in some way.
|
|
107
122
|
const throttledSend = throttle(send, 20)
|
|
108
123
|
|
|
109
|
-
reactivityGraphSubcriptions.set(
|
|
124
|
+
reactivityGraphSubcriptions.set(subscriptionId, store.reactivityGraph.subscribeToRefresh(throttledSend))
|
|
110
125
|
|
|
111
126
|
break
|
|
112
127
|
}
|
|
@@ -123,6 +138,7 @@ export const connectDevtoolsToStore = ({
|
|
|
123
138
|
break
|
|
124
139
|
}
|
|
125
140
|
case 'LSD.ClientSession.DebugInfoHistorySubscribe': {
|
|
141
|
+
const { subscriptionId } = decodedMessage
|
|
126
142
|
const buffer: DebugInfo[] = []
|
|
127
143
|
let hasStopped = false
|
|
128
144
|
let tickHandle: number | undefined
|
|
@@ -140,10 +156,11 @@ export const connectDevtoolsToStore = ({
|
|
|
140
156
|
sendToDevtools(
|
|
141
157
|
Devtools.ClientSession.DebugInfoHistoryRes.make({
|
|
142
158
|
debugInfoHistory: buffer,
|
|
143
|
-
requestId,
|
|
159
|
+
requestId: nanoid(10),
|
|
144
160
|
clientId,
|
|
145
161
|
sessionId,
|
|
146
162
|
liveStoreVersion,
|
|
163
|
+
subscriptionId,
|
|
147
164
|
}),
|
|
148
165
|
)
|
|
149
166
|
buffer.length = 0
|
|
@@ -164,15 +181,16 @@ export const connectDevtoolsToStore = ({
|
|
|
164
181
|
}
|
|
165
182
|
}
|
|
166
183
|
|
|
167
|
-
debugInfoHistorySubscriptions.set(
|
|
184
|
+
debugInfoHistorySubscriptions.set(subscriptionId, unsub)
|
|
168
185
|
|
|
169
186
|
break
|
|
170
187
|
}
|
|
171
188
|
case 'LSD.ClientSession.DebugInfoHistoryUnsubscribe': {
|
|
189
|
+
const { subscriptionId } = decodedMessage
|
|
172
190
|
// NOTE given WebMesh channels have persistent retry behaviour, it can happen that a previous
|
|
173
191
|
// WebMesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
|
174
|
-
debugInfoHistorySubscriptions.get(
|
|
175
|
-
debugInfoHistorySubscriptions.delete(
|
|
192
|
+
debugInfoHistorySubscriptions.get(subscriptionId)?.()
|
|
193
|
+
debugInfoHistorySubscriptions.delete(subscriptionId)
|
|
176
194
|
break
|
|
177
195
|
}
|
|
178
196
|
case 'LSD.ClientSession.DebugInfoResetReq': {
|
|
@@ -191,12 +209,15 @@ export const connectDevtoolsToStore = ({
|
|
|
191
209
|
break
|
|
192
210
|
}
|
|
193
211
|
case 'LSD.ClientSession.ReactivityGraphUnsubscribe': {
|
|
212
|
+
const { subscriptionId } = decodedMessage
|
|
194
213
|
// NOTE given WebMesh channels have persistent retry behaviour, it can happen that a previous
|
|
195
214
|
// WebMesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
|
196
|
-
reactivityGraphSubcriptions.get(
|
|
215
|
+
reactivityGraphSubcriptions.get(subscriptionId)?.()
|
|
216
|
+
reactivityGraphSubcriptions.delete(subscriptionId)
|
|
197
217
|
break
|
|
198
218
|
}
|
|
199
219
|
case 'LSD.ClientSession.LiveQueriesSubscribe': {
|
|
220
|
+
const { subscriptionId } = decodedMessage
|
|
200
221
|
const send = () =>
|
|
201
222
|
requestIdleCallback(
|
|
202
223
|
() =>
|
|
@@ -214,10 +235,11 @@ export const connectDevtoolsToStore = ({
|
|
|
214
235
|
: q.results$.previousResult,
|
|
215
236
|
activeSubscriptions: Array.from(q.activeSubscriptions),
|
|
216
237
|
})),
|
|
217
|
-
requestId,
|
|
238
|
+
requestId: nanoid(10),
|
|
218
239
|
liveStoreVersion,
|
|
219
240
|
clientId,
|
|
220
241
|
sessionId,
|
|
242
|
+
subscriptionId,
|
|
221
243
|
}),
|
|
222
244
|
),
|
|
223
245
|
{ timeout: 500 },
|
|
@@ -228,34 +250,37 @@ export const connectDevtoolsToStore = ({
|
|
|
228
250
|
// Same as in the reactivity graph subscription case above, we need to throttle the updates
|
|
229
251
|
const throttledSend = throttle(send, 20)
|
|
230
252
|
|
|
231
|
-
liveQueriesSubscriptions.set(
|
|
253
|
+
liveQueriesSubscriptions.set(subscriptionId, store.reactivityGraph.subscribeToRefresh(throttledSend))
|
|
232
254
|
|
|
233
255
|
break
|
|
234
256
|
}
|
|
235
257
|
case 'LSD.ClientSession.LiveQueriesUnsubscribe': {
|
|
258
|
+
const { subscriptionId } = decodedMessage
|
|
236
259
|
// NOTE given WebMesh channels have persistent retry behaviour, it can happen that a previous
|
|
237
260
|
// WebMesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
|
238
|
-
liveQueriesSubscriptions.get(
|
|
239
|
-
liveQueriesSubscriptions.delete(
|
|
261
|
+
liveQueriesSubscriptions.get(subscriptionId)?.()
|
|
262
|
+
liveQueriesSubscriptions.delete(subscriptionId)
|
|
240
263
|
break
|
|
241
264
|
}
|
|
242
265
|
case 'LSD.ClientSession.SyncHeadSubscribe': {
|
|
266
|
+
const { subscriptionId } = decodedMessage
|
|
243
267
|
const send = (syncState: SyncState.SyncState) =>
|
|
244
268
|
sendToDevtools(
|
|
245
269
|
Devtools.ClientSession.SyncHeadRes.make({
|
|
246
270
|
local: syncState.localHead,
|
|
247
271
|
upstream: syncState.upstreamHead,
|
|
248
|
-
requestId,
|
|
272
|
+
requestId: nanoid(10),
|
|
249
273
|
clientId,
|
|
250
274
|
sessionId,
|
|
251
275
|
liveStoreVersion,
|
|
276
|
+
subscriptionId,
|
|
252
277
|
}),
|
|
253
278
|
)
|
|
254
279
|
|
|
255
280
|
send(store.syncProcessor.syncState.pipe(Effect.runSync))
|
|
256
281
|
|
|
257
282
|
syncHeadClientSessionSubscriptions.set(
|
|
258
|
-
|
|
283
|
+
subscriptionId,
|
|
259
284
|
store.syncProcessor.syncState.changes.pipe(
|
|
260
285
|
Stream.tap((syncState) => send(syncState)),
|
|
261
286
|
Stream.runDrain,
|
|
@@ -268,8 +293,11 @@ export const connectDevtoolsToStore = ({
|
|
|
268
293
|
break
|
|
269
294
|
}
|
|
270
295
|
case 'LSD.ClientSession.SyncHeadUnsubscribe': {
|
|
271
|
-
|
|
272
|
-
|
|
296
|
+
const { subscriptionId } = decodedMessage
|
|
297
|
+
// NOTE given WebMesh channels have persistent retry behaviour, it can happen that a previous
|
|
298
|
+
// WebMesh channel will send a unsubscribe message for an old requestId. Thus the `?.()` handling.
|
|
299
|
+
syncHeadClientSessionSubscriptions.get(subscriptionId)?.()
|
|
300
|
+
syncHeadClientSessionSubscriptions.delete(subscriptionId)
|
|
273
301
|
break
|
|
274
302
|
}
|
|
275
303
|
default: {
|
package/src/store/store-types.ts
CHANGED
|
@@ -39,6 +39,7 @@ export type StoreOptions<TSchema extends LiveStoreSchema = LiveStoreSchema, TCon
|
|
|
39
39
|
disableDevtools?: boolean
|
|
40
40
|
lifetimeScope: Scope.Scope
|
|
41
41
|
runtime: Runtime.Runtime<Scope.Scope>
|
|
42
|
+
confirmUnsavedChanges: boolean
|
|
42
43
|
batchUpdates: (runUpdates: () => void) => void
|
|
43
44
|
// TODO validate whether we still need this
|
|
44
45
|
unsyncedMutationEvents: MutableHashMap.MutableHashMap<EventId.EventId, MutationEvent.ForSchema<TSchema>>
|
package/src/store/store.ts
CHANGED
|
@@ -103,6 +103,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
103
103
|
lifetimeScope,
|
|
104
104
|
runtime,
|
|
105
105
|
params,
|
|
106
|
+
confirmUnsavedChanges,
|
|
106
107
|
}: StoreOptions<TSchema, TContext>) {
|
|
107
108
|
super()
|
|
108
109
|
|
|
@@ -173,6 +174,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
173
174
|
params: {
|
|
174
175
|
leaderPushBatchSize: params.leaderPushBatchSize,
|
|
175
176
|
},
|
|
177
|
+
confirmUnsavedChanges,
|
|
176
178
|
})
|
|
177
179
|
|
|
178
180
|
this.__mutationEventSchema = MutationEvent.makeMutationEventSchemaMemo(schema)
|