@livestore/livestore 0.3.0-dev.19 → 0.3.0-dev.21
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.map +1 -1
- package/dist/SqliteDbWrapper.js +1 -2
- package/dist/SqliteDbWrapper.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +6 -38
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +6 -18
- 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 +10 -6
- package/dist/live-queries/base-class.d.ts.map +1 -1
- package/dist/live-queries/base-class.js.map +1 -1
- package/dist/live-queries/computed.d.ts.map +1 -1
- package/dist/live-queries/computed.js +1 -1
- package/dist/live-queries/computed.js.map +1 -1
- package/dist/live-queries/db-query.d.ts.map +1 -1
- package/dist/live-queries/db-query.js +1 -2
- package/dist/live-queries/db-query.js.map +1 -1
- package/dist/live-queries/db-query.test.js +4 -1
- package/dist/live-queries/db-query.test.js.map +1 -1
- 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/{index.d.ts → mod.d.ts} +3 -8
- package/dist/mod.d.ts.map +1 -0
- package/dist/{index.js → mod.js} +2 -6
- package/dist/mod.js.map +1 -0
- package/dist/store/create-store.d.ts +42 -9
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +14 -5
- 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 +4 -14
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store.d.ts +4 -6
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +5 -9
- package/dist/store/store.js.map +1 -1
- package/dist/utils/tests/fixture.d.ts +1 -1
- package/dist/utils/tests/fixture.d.ts.map +1 -1
- package/dist/utils/tests/fixture.js.map +1 -1
- package/package.json +20 -22
- package/src/SqliteDbWrapper.ts +8 -2
- package/src/effect/LiveStore.ts +22 -70
- package/src/effect/{index.ts → mod.ts} +2 -3
- package/src/internal/mod.ts +2 -0
- package/src/live-queries/base-class.ts +12 -7
- package/src/live-queries/computed.ts +1 -1
- package/src/live-queries/db-query.test.ts +4 -1
- package/src/live-queries/db-query.ts +1 -1
- package/src/live-queries/mod.ts +4 -0
- package/src/{index.ts → mod.ts} +3 -35
- package/src/store/create-store.ts +66 -21
- package/src/store/devtools.ts +43 -15
- package/src/store/store-types.ts +4 -20
- package/src/store/store.ts +10 -24
- package/src/utils/tests/fixture.ts +1 -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/index.d.ts.map +0 -1
- package/dist/index.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 -147
- package/dist/live-queries/graphql.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/live-queries/graphql.ts +0 -244
- package/src/utils/otel.ts +0 -9
|
@@ -11,6 +11,7 @@ import type { EventId, LiveStoreSchema, MutationEvent } from '@livestore/common/
|
|
|
11
11
|
import { LS_DEV } from '@livestore/utils'
|
|
12
12
|
import type { Cause } from '@livestore/utils/effect'
|
|
13
13
|
import {
|
|
14
|
+
Context,
|
|
14
15
|
Deferred,
|
|
15
16
|
Effect,
|
|
16
17
|
Exit,
|
|
@@ -28,22 +29,63 @@ import {
|
|
|
28
29
|
import { nanoid } from '@livestore/utils/nanoid'
|
|
29
30
|
import * as otel from '@opentelemetry/api'
|
|
30
31
|
|
|
31
|
-
import { LiveStoreContextRunning } from '../effect/index.js'
|
|
32
32
|
import { connectDevtoolsToStore } from './devtools.js'
|
|
33
33
|
import { Store } from './store.js'
|
|
34
|
-
import type {
|
|
34
|
+
import type {
|
|
35
|
+
LiveStoreContextRunning as LiveStoreContextRunning_,
|
|
36
|
+
OtelOptions,
|
|
37
|
+
ShutdownDeferred,
|
|
38
|
+
} from './store-types.js'
|
|
35
39
|
|
|
36
40
|
export const DEFAULT_PARAMS = {
|
|
37
41
|
leaderPushBatchSize: 1,
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
export
|
|
44
|
+
export class LiveStoreContextRunning extends Context.Tag('@livestore/livestore/effect/LiveStoreContextRunning')<
|
|
45
|
+
LiveStoreContextRunning,
|
|
46
|
+
LiveStoreContextRunning_
|
|
47
|
+
>() {
|
|
48
|
+
static fromDeferred = Effect.gen(function* () {
|
|
49
|
+
const deferred = yield* DeferredStoreContext
|
|
50
|
+
const ctx = yield* deferred
|
|
51
|
+
return Layer.succeed(LiveStoreContextRunning, ctx)
|
|
52
|
+
}).pipe(Layer.unwrapScoped)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class DeferredStoreContext extends Context.Tag('@livestore/livestore/effect/DeferredStoreContext')<
|
|
56
|
+
DeferredStoreContext,
|
|
57
|
+
Deferred.Deferred<LiveStoreContextRunning['Type'], UnexpectedError>
|
|
58
|
+
>() {}
|
|
59
|
+
|
|
60
|
+
export type LiveStoreContextProps<TSchema extends LiveStoreSchema, TContext = {}> = {
|
|
61
|
+
schema: TSchema
|
|
62
|
+
/**
|
|
63
|
+
* The `storeId` can be used to isolate multiple stores from each other.
|
|
64
|
+
* So it can be useful for multi-tenancy scenarios.
|
|
65
|
+
*
|
|
66
|
+
* The `storeId` is also used for persistence.
|
|
67
|
+
*
|
|
68
|
+
* @default 'default'
|
|
69
|
+
*/
|
|
70
|
+
storeId?: string
|
|
71
|
+
/** Can be useful for custom live query implementations (e.g. see `@livestore/graphql`) */
|
|
72
|
+
context?: TContext
|
|
73
|
+
boot?: (
|
|
74
|
+
store: Store<TSchema, TContext>,
|
|
75
|
+
) => Effect.Effect<void, unknown, OtelTracer.OtelTracer | LiveStoreContextRunning>
|
|
76
|
+
adapter: Adapter
|
|
77
|
+
disableDevtools?: boolean
|
|
78
|
+
onBootStatus?: (status: BootStatus) => void
|
|
79
|
+
batchUpdates: (run: () => void) => void
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface CreateStoreOptions<TSchema extends LiveStoreSchema, TContext = {}> {
|
|
41
83
|
schema: TSchema
|
|
42
84
|
adapter: Adapter
|
|
43
85
|
storeId: string
|
|
44
|
-
|
|
86
|
+
context?: TContext
|
|
45
87
|
boot?: (
|
|
46
|
-
store: Store<
|
|
88
|
+
store: Store<TSchema, TContext>,
|
|
47
89
|
ctx: {
|
|
48
90
|
migrationsReport: MigrationsReport
|
|
49
91
|
parentSpan: otel.Span
|
|
@@ -53,6 +95,13 @@ export interface CreateStoreOptions<TGraphQLContext extends BaseGraphQLContext,
|
|
|
53
95
|
disableDevtools?: boolean
|
|
54
96
|
onBootStatus?: (status: BootStatus) => void
|
|
55
97
|
shutdownDeferred?: ShutdownDeferred
|
|
98
|
+
/**
|
|
99
|
+
* Currently only used in the web adapter:
|
|
100
|
+
* If true, registers a beforeunload event listener to confirm unsaved changes.
|
|
101
|
+
*
|
|
102
|
+
* @default true
|
|
103
|
+
*/
|
|
104
|
+
confirmUnsavedChanges?: boolean
|
|
56
105
|
params?: {
|
|
57
106
|
leaderPushBatchSize?: number
|
|
58
107
|
}
|
|
@@ -62,17 +111,14 @@ export interface CreateStoreOptions<TGraphQLContext extends BaseGraphQLContext,
|
|
|
62
111
|
}
|
|
63
112
|
|
|
64
113
|
/** Create a new LiveStore Store */
|
|
65
|
-
export const createStorePromise = async <
|
|
66
|
-
TGraphQLContext extends BaseGraphQLContext,
|
|
67
|
-
TSchema extends LiveStoreSchema = LiveStoreSchema,
|
|
68
|
-
>({
|
|
114
|
+
export const createStorePromise = async <TSchema extends LiveStoreSchema = LiveStoreSchema, TContext = {}>({
|
|
69
115
|
signal,
|
|
70
116
|
otelOptions,
|
|
71
117
|
...options
|
|
72
|
-
}: CreateStoreOptions<
|
|
118
|
+
}: CreateStoreOptions<TSchema, TContext> & {
|
|
73
119
|
signal?: AbortSignal
|
|
74
120
|
otelOptions?: Partial<OtelOptions>
|
|
75
|
-
}): Promise<Store<
|
|
121
|
+
}): Promise<Store<TSchema, TContext>> =>
|
|
76
122
|
Effect.gen(function* () {
|
|
77
123
|
const scope = yield* Scope.make()
|
|
78
124
|
const runtime = yield* Effect.runtime()
|
|
@@ -91,19 +137,16 @@ export const createStorePromise = async <
|
|
|
91
137
|
provideOtel({ parentSpanContext: otelOptions?.rootSpanContext, otelTracer: otelOptions?.tracer }),
|
|
92
138
|
Effect.tapCauseLogPretty,
|
|
93
139
|
Effect.annotateLogs({ thread: 'window' }),
|
|
94
|
-
Effect.provide(Logger.
|
|
140
|
+
Effect.provide(Logger.prettyWithThread('window')),
|
|
95
141
|
Logger.withMinimumLogLevel(LogLevel.Debug),
|
|
96
142
|
Effect.runPromise,
|
|
97
143
|
)
|
|
98
144
|
|
|
99
|
-
export const createStore = <
|
|
100
|
-
TGraphQLContext extends BaseGraphQLContext,
|
|
101
|
-
TSchema extends LiveStoreSchema = LiveStoreSchema,
|
|
102
|
-
>({
|
|
145
|
+
export const createStore = <TSchema extends LiveStoreSchema = LiveStoreSchema, TContext = {}>({
|
|
103
146
|
schema,
|
|
104
147
|
adapter,
|
|
105
148
|
storeId,
|
|
106
|
-
|
|
149
|
+
context = {} as TContext,
|
|
107
150
|
boot,
|
|
108
151
|
batchUpdates,
|
|
109
152
|
disableDevtools,
|
|
@@ -111,8 +154,9 @@ export const createStore = <
|
|
|
111
154
|
shutdownDeferred,
|
|
112
155
|
params,
|
|
113
156
|
debug,
|
|
114
|
-
|
|
115
|
-
|
|
157
|
+
confirmUnsavedChanges = true,
|
|
158
|
+
}: CreateStoreOptions<TSchema, TContext>): Effect.Effect<
|
|
159
|
+
Store<TSchema, TContext>,
|
|
116
160
|
UnexpectedError,
|
|
117
161
|
Scope.Scope | OtelTracer.OtelTracer
|
|
118
162
|
> =>
|
|
@@ -199,15 +243,16 @@ export const createStore = <
|
|
|
199
243
|
// TODO fill up with unsynced mutation events from the client session
|
|
200
244
|
const unsyncedMutationEvents = MutableHashMap.empty<EventId.EventId, MutationEvent.ForSchema<TSchema>>()
|
|
201
245
|
|
|
202
|
-
const store = new Store<
|
|
246
|
+
const store = new Store<TSchema, TContext>({
|
|
203
247
|
clientSession,
|
|
204
248
|
schema,
|
|
205
|
-
|
|
249
|
+
context,
|
|
206
250
|
otelOptions: { tracer: otelTracer, rootSpanContext: otelRootSpanContext },
|
|
207
251
|
disableDevtools,
|
|
208
252
|
unsyncedMutationEvents,
|
|
209
253
|
lifetimeScope,
|
|
210
254
|
runtime,
|
|
255
|
+
confirmUnsavedChanges,
|
|
211
256
|
// NOTE during boot we're not yet executing mutations in a batched context
|
|
212
257
|
// but only set the provided `batchUpdates` function after boot
|
|
213
258
|
batchUpdates: (run) => run(),
|
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
|
@@ -2,10 +2,8 @@ import type { ClientSession, IntentionalShutdownCause, StoreInterrupted, Unexpec
|
|
|
2
2
|
import type { EventId, LiveStoreSchema, MutationEvent } from '@livestore/common/schema'
|
|
3
3
|
import type { Deferred, MutableHashMap, Runtime, Scope } from '@livestore/utils/effect'
|
|
4
4
|
import type * as otel from '@opentelemetry/api'
|
|
5
|
-
import type { GraphQLSchema } from 'graphql'
|
|
6
5
|
|
|
7
6
|
import type { DebugRefreshReasonBase } from '../reactive.js'
|
|
8
|
-
import type { SqliteDbWrapper } from '../SqliteDbWrapper.js'
|
|
9
7
|
import type { StackInfo } from '../utils/stack-info.js'
|
|
10
8
|
import type { Store } from './store.js'
|
|
11
9
|
|
|
@@ -27,35 +25,21 @@ export type LiveStoreContextRunning = {
|
|
|
27
25
|
store: Store
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
export type BaseGraphQLContext = {
|
|
31
|
-
queriedTables: Set<string>
|
|
32
|
-
/** Needed by Pothos Otel plugin for resolver tracing to work */
|
|
33
|
-
otelContext?: otel.Context
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export type GraphQLOptions<TContext> = {
|
|
37
|
-
schema: GraphQLSchema
|
|
38
|
-
makeContext: (db: SqliteDbWrapper, tracer: otel.Tracer, sessionId: string) => TContext
|
|
39
|
-
}
|
|
40
|
-
|
|
41
28
|
export type OtelOptions = {
|
|
42
29
|
tracer: otel.Tracer
|
|
43
30
|
rootSpanContext: otel.Context
|
|
44
31
|
}
|
|
45
32
|
|
|
46
|
-
export type StoreOptions<
|
|
47
|
-
TGraphQLContext extends BaseGraphQLContext,
|
|
48
|
-
TSchema extends LiveStoreSchema = LiveStoreSchema,
|
|
49
|
-
> = {
|
|
33
|
+
export type StoreOptions<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext = {}> = {
|
|
50
34
|
clientSession: ClientSession
|
|
51
35
|
schema: TSchema
|
|
52
36
|
storeId: string
|
|
53
|
-
|
|
54
|
-
graphQLOptions?: GraphQLOptions<TGraphQLContext>
|
|
37
|
+
context: TContext
|
|
55
38
|
otelOptions: OtelOptions
|
|
56
39
|
disableDevtools?: boolean
|
|
57
40
|
lifetimeScope: Scope.Scope
|
|
58
41
|
runtime: Runtime.Runtime<Scope.Scope>
|
|
42
|
+
confirmUnsavedChanges: boolean
|
|
59
43
|
batchUpdates: (runUpdates: () => void) => void
|
|
60
44
|
// TODO validate whether we still need this
|
|
61
45
|
unsyncedMutationEvents: MutableHashMap.MutableHashMap<EventId.EventId, MutationEvent.ForSchema<TSchema>>
|
|
@@ -86,7 +70,7 @@ export type RefreshReason =
|
|
|
86
70
|
| { _tag: 'manual'; label?: string }
|
|
87
71
|
|
|
88
72
|
export type QueryDebugInfo = {
|
|
89
|
-
_tag:
|
|
73
|
+
_tag: string
|
|
90
74
|
label: string
|
|
91
75
|
query: string
|
|
92
76
|
durationMs: number
|
package/src/store/store.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
} from '@livestore/common'
|
|
9
9
|
import {
|
|
10
10
|
Devtools,
|
|
11
|
+
getDurationMsFromSpan,
|
|
11
12
|
getExecArgsFromMutation,
|
|
12
13
|
getResultSchema,
|
|
13
14
|
IntentionalShutdownCause,
|
|
@@ -41,7 +42,6 @@ import {
|
|
|
41
42
|
} from '@livestore/utils/effect'
|
|
42
43
|
import { nanoid } from '@livestore/utils/nanoid'
|
|
43
44
|
import * as otel from '@opentelemetry/api'
|
|
44
|
-
import { type GraphQLSchema } from 'graphql'
|
|
45
45
|
|
|
46
46
|
import type {
|
|
47
47
|
ILiveQueryRefDef,
|
|
@@ -56,32 +56,20 @@ import { makeExecBeforeFirstRun } from '../row-query-utils.js'
|
|
|
56
56
|
import { SqliteDbWrapper } from '../SqliteDbWrapper.js'
|
|
57
57
|
import { ReferenceCountedSet } from '../utils/data-structures.js'
|
|
58
58
|
import { downloadBlob, exposeDebugUtils } from '../utils/dev.js'
|
|
59
|
-
import { getDurationMsFromSpan } from '../utils/otel.js'
|
|
60
59
|
import type { StackInfo } from '../utils/stack-info.js'
|
|
61
|
-
import type {
|
|
62
|
-
BaseGraphQLContext,
|
|
63
|
-
RefreshReason,
|
|
64
|
-
StoreMutateOptions,
|
|
65
|
-
StoreOptions,
|
|
66
|
-
StoreOtel,
|
|
67
|
-
Unsubscribe,
|
|
68
|
-
} from './store-types.js'
|
|
60
|
+
import type { RefreshReason, StoreMutateOptions, StoreOptions, StoreOtel, Unsubscribe } from './store-types.js'
|
|
69
61
|
|
|
70
62
|
if (isDevEnv()) {
|
|
71
63
|
exposeDebugUtils()
|
|
72
64
|
}
|
|
73
65
|
|
|
74
|
-
export class Store<
|
|
75
|
-
TGraphQLContext extends BaseGraphQLContext = BaseGraphQLContext,
|
|
76
|
-
TSchema extends LiveStoreSchema = LiveStoreSchema,
|
|
77
|
-
> extends Inspectable.Class {
|
|
66
|
+
export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext = {}> extends Inspectable.Class {
|
|
78
67
|
readonly storeId: string
|
|
79
68
|
reactivityGraph: ReactivityGraph
|
|
80
69
|
sqliteDbWrapper: SqliteDbWrapper
|
|
81
70
|
clientSession: ClientSession
|
|
82
71
|
schema: LiveStoreSchema
|
|
83
|
-
|
|
84
|
-
graphQLContext?: TGraphQLContext
|
|
72
|
+
context: TContext
|
|
85
73
|
otel: StoreOtel
|
|
86
74
|
/**
|
|
87
75
|
* Note we're using `Ref<null>` here as we don't care about the value but only about *that* something has changed.
|
|
@@ -106,8 +94,8 @@ export class Store<
|
|
|
106
94
|
constructor({
|
|
107
95
|
clientSession,
|
|
108
96
|
schema,
|
|
109
|
-
graphQLOptions,
|
|
110
97
|
otelOptions,
|
|
98
|
+
context,
|
|
111
99
|
disableDevtools,
|
|
112
100
|
batchUpdates,
|
|
113
101
|
unsyncedMutationEvents,
|
|
@@ -115,7 +103,8 @@ export class Store<
|
|
|
115
103
|
lifetimeScope,
|
|
116
104
|
runtime,
|
|
117
105
|
params,
|
|
118
|
-
|
|
106
|
+
confirmUnsavedChanges,
|
|
107
|
+
}: StoreOptions<TSchema, TContext>) {
|
|
119
108
|
super()
|
|
120
109
|
|
|
121
110
|
this.storeId = storeId
|
|
@@ -124,6 +113,7 @@ export class Store<
|
|
|
124
113
|
this.sqliteDbWrapper = new SqliteDbWrapper({ otel: otelOptions, db: clientSession.sqliteDb })
|
|
125
114
|
this.clientSession = clientSession
|
|
126
115
|
this.schema = schema
|
|
116
|
+
this.context = context
|
|
127
117
|
|
|
128
118
|
this.lifetimeScope = lifetimeScope
|
|
129
119
|
this.runtime = runtime
|
|
@@ -184,6 +174,7 @@ export class Store<
|
|
|
184
174
|
params: {
|
|
185
175
|
leaderPushBatchSize: params.leaderPushBatchSize,
|
|
186
176
|
},
|
|
177
|
+
confirmUnsavedChanges,
|
|
187
178
|
})
|
|
188
179
|
|
|
189
180
|
this.__mutationEventSchema = MutationEvent.makeMutationEventSchemaMemo(schema)
|
|
@@ -200,7 +191,7 @@ export class Store<
|
|
|
200
191
|
|
|
201
192
|
this.reactivityGraph = reactivityGraph
|
|
202
193
|
this.reactivityGraph.context = {
|
|
203
|
-
store: this as unknown as Store<
|
|
194
|
+
store: this as unknown as Store<LiveStoreSchema>,
|
|
204
195
|
defRcMap: new Map(),
|
|
205
196
|
reactivityGraph: new WeakRef(reactivityGraph),
|
|
206
197
|
otelTracer: otelOptions.tracer,
|
|
@@ -237,11 +228,6 @@ export class Store<
|
|
|
237
228
|
this.tableRefs[tableName] = existingTableRefs.get(tableName) ?? this.makeTableRef(tableName)
|
|
238
229
|
}
|
|
239
230
|
|
|
240
|
-
if (graphQLOptions) {
|
|
241
|
-
this.graphQLSchema = graphQLOptions.schema
|
|
242
|
-
this.graphQLContext = graphQLOptions.makeContext(this.sqliteDbWrapper, this.otel.tracer, clientSession.sessionId)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
231
|
this.boot = Effect.gen(this, function* () {
|
|
246
232
|
yield* Effect.addFinalizer(() =>
|
|
247
233
|
Effect.sync(() => {
|
|
@@ -52,7 +52,7 @@ export const makeTodoMvc = ({
|
|
|
52
52
|
otelContext?: otel.Context
|
|
53
53
|
} = {}) =>
|
|
54
54
|
Effect.gen(function* () {
|
|
55
|
-
const store: Store<
|
|
55
|
+
const store: Store<FixtureSchema> = yield* createStore({
|
|
56
56
|
schema,
|
|
57
57
|
storeId: 'default',
|
|
58
58
|
adapter: makeInMemoryAdapter(),
|
package/dist/effect/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/effect/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,IAAI,gBAAgB,EAC3C,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,KAAK,qBAAqB,GAC3B,MAAM,gBAAgB,CAAA"}
|
package/dist/effect/index.js
DELETED
package/dist/effect/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/effect/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,IAAI,gBAAgB,EAC3C,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,GAErB,MAAM,gBAAgB,CAAA"}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAClG,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,GACZ,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAEnH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAEtE,YAAY,EACV,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,IAAI,EACJ,IAAI,EACJ,GAAG,EACH,MAAM,GACP,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACtE,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC/E,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACvE,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,mBAAmB,EACnB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,KAAK,GACX,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,cAAc,0BAA0B,CAAA;AACxC,OAAO,EACL,GAAG,EACH,eAAe,EACf,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,iBAAiB,EACjB,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,GACZ,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhD,cAAc,uBAAuB,CAAA;AAErC,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAA2B,MAAM,yBAAyB,CAAA;AAWlG,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AActE,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACtE,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC/E,OAAO,EAAE,OAAO,EAAqB,MAAM,4BAA4B,CAAA;AACvE,OAAO,EAGL,mBAAmB,GAOpB,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,cAAc,0BAA0B,CAAA;AACxC,OAAO,EACL,GAAG,EACH,eAAe,EAKf,iBAAiB,EAMjB,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,GACZ,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhD,cAAc,uBAAuB,CAAA"}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
2
|
-
import type { QueryInfo } from '@livestore/common';
|
|
3
|
-
import { Schema } from '@livestore/utils/effect';
|
|
4
|
-
import * as otel from '@opentelemetry/api';
|
|
5
|
-
import * as graphql from 'graphql';
|
|
6
|
-
import { type Thunk } from '../reactive.js';
|
|
7
|
-
import type { Store } from '../store/store.js';
|
|
8
|
-
import type { BaseGraphQLContext, RefreshReason } from '../store/store-types.js';
|
|
9
|
-
import type { DepKey, GetAtomResult, LiveQueryDef, ReactivityGraph, ReactivityGraphContext } from './base-class.js';
|
|
10
|
-
import { LiveStoreQueryBase } from './base-class.js';
|
|
11
|
-
export type MapResult<To, From> = ((res: From, get: GetAtomResult) => To) | Schema.Schema<To, From>;
|
|
12
|
-
export declare const queryGraphQL: <TResult extends Record<string, any>, TVariableValues extends Record<string, any>, TResultMapped extends Record<string, any> = TResult>(document: DocumentNode<TResult, TVariableValues>, genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues), options?: {
|
|
13
|
-
label?: string;
|
|
14
|
-
map?: MapResult<TResultMapped, TResult>;
|
|
15
|
-
deps?: DepKey;
|
|
16
|
-
}) => LiveQueryDef<TResultMapped, QueryInfo.None>;
|
|
17
|
-
export declare class LiveStoreGraphQLQuery<TResult extends Record<string, any>, TVariableValues extends Record<string, any>, TContext extends BaseGraphQLContext, TResultMapped extends Record<string, any> = TResult> extends LiveStoreQueryBase<TResultMapped, QueryInfo.None> {
|
|
18
|
-
_tag: 'graphql';
|
|
19
|
-
/** The abstract GraphQL query */
|
|
20
|
-
document: DocumentNode<TResult, TVariableValues>;
|
|
21
|
-
/** A reactive thunk representing the query results */
|
|
22
|
-
results$: Thunk<TResultMapped, ReactivityGraphContext, RefreshReason>;
|
|
23
|
-
variableValues$: Thunk<TVariableValues, ReactivityGraphContext, RefreshReason> | undefined;
|
|
24
|
-
label: string;
|
|
25
|
-
reactivityGraph: ReactivityGraph;
|
|
26
|
-
queryInfo: QueryInfo.None;
|
|
27
|
-
private mapResult;
|
|
28
|
-
constructor({ document, label, genVariableValues, reactivityGraph, map, }: {
|
|
29
|
-
document: DocumentNode<TResult, TVariableValues>;
|
|
30
|
-
genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues);
|
|
31
|
-
label?: string;
|
|
32
|
-
reactivityGraph: ReactivityGraph;
|
|
33
|
-
map?: MapResult<TResultMapped, TResult>;
|
|
34
|
-
});
|
|
35
|
-
queryOnce: ({ document, otelContext, otelTracer, variableValues, store, get, }: {
|
|
36
|
-
document: graphql.DocumentNode;
|
|
37
|
-
otelContext: otel.Context;
|
|
38
|
-
otelTracer: otel.Tracer;
|
|
39
|
-
variableValues: TVariableValues;
|
|
40
|
-
store: Store<TContext>;
|
|
41
|
-
get: GetAtomResult;
|
|
42
|
-
}) => {
|
|
43
|
-
result: TResultMapped;
|
|
44
|
-
queriedTables: string[];
|
|
45
|
-
durationMs: number;
|
|
46
|
-
};
|
|
47
|
-
destroy: () => void;
|
|
48
|
-
}
|
|
49
|
-
//# sourceMappingURL=graphql.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/live-queries/graphql.ts"],"names":[],"mappings":"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"}
|