@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.
Files changed (83) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/SqliteDbWrapper.d.ts.map +1 -1
  3. package/dist/SqliteDbWrapper.js +1 -2
  4. package/dist/SqliteDbWrapper.js.map +1 -1
  5. package/dist/effect/LiveStore.d.ts +6 -38
  6. package/dist/effect/LiveStore.d.ts.map +1 -1
  7. package/dist/effect/LiveStore.js +6 -18
  8. package/dist/effect/LiveStore.js.map +1 -1
  9. package/dist/effect/mod.d.ts +3 -0
  10. package/dist/effect/mod.d.ts.map +1 -0
  11. package/dist/effect/mod.js +3 -0
  12. package/dist/effect/mod.js.map +1 -0
  13. package/dist/internal/mod.d.ts +3 -0
  14. package/dist/internal/mod.d.ts.map +1 -0
  15. package/dist/internal/mod.js +3 -0
  16. package/dist/internal/mod.js.map +1 -0
  17. package/dist/live-queries/base-class.d.ts +10 -6
  18. package/dist/live-queries/base-class.d.ts.map +1 -1
  19. package/dist/live-queries/base-class.js.map +1 -1
  20. package/dist/live-queries/computed.d.ts.map +1 -1
  21. package/dist/live-queries/computed.js +1 -1
  22. package/dist/live-queries/computed.js.map +1 -1
  23. package/dist/live-queries/db-query.d.ts.map +1 -1
  24. package/dist/live-queries/db-query.js +1 -2
  25. package/dist/live-queries/db-query.js.map +1 -1
  26. package/dist/live-queries/db-query.test.js +4 -1
  27. package/dist/live-queries/db-query.test.js.map +1 -1
  28. package/dist/live-queries/mod.d.ts +5 -0
  29. package/dist/live-queries/mod.d.ts.map +1 -0
  30. package/dist/live-queries/mod.js +5 -0
  31. package/dist/live-queries/mod.js.map +1 -0
  32. package/dist/{index.d.ts → mod.d.ts} +3 -8
  33. package/dist/mod.d.ts.map +1 -0
  34. package/dist/{index.js → mod.js} +2 -6
  35. package/dist/mod.js.map +1 -0
  36. package/dist/store/create-store.d.ts +42 -9
  37. package/dist/store/create-store.d.ts.map +1 -1
  38. package/dist/store/create-store.js +14 -5
  39. package/dist/store/create-store.js.map +1 -1
  40. package/dist/store/devtools.d.ts.map +1 -1
  41. package/dist/store/devtools.js +40 -15
  42. package/dist/store/devtools.js.map +1 -1
  43. package/dist/store/store-types.d.ts +4 -14
  44. package/dist/store/store-types.d.ts.map +1 -1
  45. package/dist/store/store.d.ts +4 -6
  46. package/dist/store/store.d.ts.map +1 -1
  47. package/dist/store/store.js +5 -9
  48. package/dist/store/store.js.map +1 -1
  49. package/dist/utils/tests/fixture.d.ts +1 -1
  50. package/dist/utils/tests/fixture.d.ts.map +1 -1
  51. package/dist/utils/tests/fixture.js.map +1 -1
  52. package/package.json +20 -22
  53. package/src/SqliteDbWrapper.ts +8 -2
  54. package/src/effect/LiveStore.ts +22 -70
  55. package/src/effect/{index.ts → mod.ts} +2 -3
  56. package/src/internal/mod.ts +2 -0
  57. package/src/live-queries/base-class.ts +12 -7
  58. package/src/live-queries/computed.ts +1 -1
  59. package/src/live-queries/db-query.test.ts +4 -1
  60. package/src/live-queries/db-query.ts +1 -1
  61. package/src/live-queries/mod.ts +4 -0
  62. package/src/{index.ts → mod.ts} +3 -35
  63. package/src/store/create-store.ts +66 -21
  64. package/src/store/devtools.ts +43 -15
  65. package/src/store/store-types.ts +4 -20
  66. package/src/store/store.ts +10 -24
  67. package/src/utils/tests/fixture.ts +1 -1
  68. package/dist/effect/index.d.ts +0 -2
  69. package/dist/effect/index.d.ts.map +0 -1
  70. package/dist/effect/index.js +0 -2
  71. package/dist/effect/index.js.map +0 -1
  72. package/dist/index.d.ts.map +0 -1
  73. package/dist/index.js.map +0 -1
  74. package/dist/live-queries/graphql.d.ts +0 -49
  75. package/dist/live-queries/graphql.d.ts.map +0 -1
  76. package/dist/live-queries/graphql.js +0 -147
  77. package/dist/live-queries/graphql.js.map +0 -1
  78. package/dist/utils/otel.d.ts +0 -4
  79. package/dist/utils/otel.d.ts.map +0 -1
  80. package/dist/utils/otel.js +0 -6
  81. package/dist/utils/otel.js.map +0 -1
  82. package/src/live-queries/graphql.ts +0 -244
  83. 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 { BaseGraphQLContext, GraphQLOptions, OtelOptions, ShutdownDeferred } from './store-types.js'
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 interface CreateStoreOptions<TGraphQLContext extends BaseGraphQLContext, TSchema extends LiveStoreSchema> {
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
- graphQLOptions?: GraphQLOptions<TGraphQLContext>
86
+ context?: TContext
45
87
  boot?: (
46
- store: Store<TGraphQLContext, TSchema>,
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<TGraphQLContext, TSchema> & {
118
+ }: CreateStoreOptions<TSchema, TContext> & {
73
119
  signal?: AbortSignal
74
120
  otelOptions?: Partial<OtelOptions>
75
- }): Promise<Store<TGraphQLContext, TSchema>> =>
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.pretty),
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
- graphQLOptions,
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
- }: CreateStoreOptions<TGraphQLContext, TSchema>): Effect.Effect<
115
- Store<TGraphQLContext, TSchema>,
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<TGraphQLContext, TSchema>({
246
+ const store = new Store<TSchema, TContext>({
203
247
  clientSession,
204
248
  schema,
205
- graphQLOptions,
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(),
@@ -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(requestId, store.reactivityGraph.subscribeToRefresh(throttledSend))
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(requestId, unsub)
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(requestId)?.()
175
- debugInfoHistorySubscriptions.delete(requestId)
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(requestId)?.()
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(requestId, store.reactivityGraph.subscribeToRefresh(throttledSend))
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(requestId)?.()
239
- liveQueriesSubscriptions.delete(requestId)
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
- requestId,
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
- syncHeadClientSessionSubscriptions.get(requestId)?.()
272
- syncHeadClientSessionSubscriptions.delete(requestId)
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: {
@@ -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
- // TODO remove graphql-related stuff from store and move to GraphQL query directly
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: 'graphql' | 'db' | 'computed' | 'unknown'
73
+ _tag: string
90
74
  label: string
91
75
  query: string
92
76
  durationMs: number
@@ -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
- graphQLSchema?: GraphQLSchema
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
- }: StoreOptions<TGraphQLContext, TSchema>) {
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<BaseGraphQLContext, LiveStoreSchema>,
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<any, FixtureSchema> = yield* createStore({
55
+ const store: Store<FixtureSchema> = yield* createStore({
56
56
  schema,
57
57
  storeId: 'default',
58
58
  adapter: makeInMemoryAdapter(),
@@ -1,2 +0,0 @@
1
- export { LiveStoreContextLayer, LiveStoreContextRunning as LiveStoreContext, LiveStoreContextRunning, LiveStoreContextDeferred, DeferredStoreContext, type LiveStoreContextProps, } from './LiveStore.js';
2
- //# sourceMappingURL=index.d.ts.map
@@ -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"}
@@ -1,2 +0,0 @@
1
- export { LiveStoreContextLayer, LiveStoreContextRunning as LiveStoreContext, LiveStoreContextRunning, LiveStoreContextDeferred, DeferredStoreContext, } from './LiveStore.js';
2
- //# sourceMappingURL=index.js.map
@@ -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"}
@@ -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":"AAAA,OAAO,KAAK,EAAE,iBAAiB,IAAI,YAAY,EAAE,MAAM,mCAAmC,CAAA;AAC1F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAElD,OAAO,EAAE,MAAM,EAAiB,MAAM,yBAAyB,CAAA;AAC/D,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAC1C,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAElC,OAAO,EAAW,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAEhF,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACnH,OAAO,EAAgB,kBAAkB,EAAgC,MAAM,iBAAiB,CAAA;AAEhG,MAAM,MAAM,SAAS,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;AAEnG,eAAO,MAAM,YAAY,GACvB,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACnC,eAAe,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3C,aAAa,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,EAEnD,UAAU,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC,EAChD,mBAAmB,eAAe,GAAG,CAAC,CAAC,GAAG,EAAE,aAAa,KAAK,eAAe,CAAC,EAC9E,UAAS;IACP,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd,GAAG,CAAC,EAAE,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;CACT,KACL,YAAY,CAAC,aAAa,EAAE,SAAS,CAAC,IAAI,CAuB5C,CAAA;AAED,qBAAa,qBAAqB,CAChC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACnC,eAAe,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3C,QAAQ,SAAS,kBAAkB,EACnC,aAAa,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CACnD,SAAQ,kBAAkB,CAAC,aAAa,EAAE,SAAS,CAAC,IAAI,CAAC;IACzD,IAAI,EAAE,SAAS,CAAY;IAE3B,iCAAiC;IACjC,QAAQ,EAAE,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;IAEhD,sDAAsD;IACtD,QAAQ,EAAE,KAAK,CAAC,aAAa,EAAE,sBAAsB,EAAE,aAAa,CAAC,CAAA;IAErE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,sBAAsB,EAAE,aAAa,CAAC,GAAG,SAAS,CAAA;IAE1F,KAAK,EAAE,MAAM,CAAA;IAEb,eAAe,EAAE,eAAe,CAAA;IAEhC,SAAS,EAAE,SAAS,CAAC,IAAI,CAAmB;IAE5C,OAAO,CAAC,SAAS,CAAA;gBAEL,EACV,QAAQ,EACR,KAAK,EACL,iBAAiB,EACjB,eAAe,EACf,GAAG,GACJ,EAAE;QACD,QAAQ,EAAE,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;QAChD,iBAAiB,EAAE,eAAe,GAAG,CAAC,CAAC,GAAG,EAAE,aAAa,KAAK,eAAe,CAAC,CAAA;QAC9E,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,eAAe,EAAE,eAAe,CAAA;QAChC,GAAG,CAAC,EAAE,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;KACxC;IA2ED,SAAS,GAAI,oEAOV;QACD,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAA;QAC9B,WAAW,EAAE,IAAI,CAAC,OAAO,CAAA;QACzB,UAAU,EAAE,IAAI,CAAC,MAAM,CAAA;QACvB,cAAc,EAAE,eAAe,CAAA;QAC/B,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;QACtB,GAAG,EAAE,aAAa,CAAA;KACnB;;;;MAmDA;IAED,OAAO,aAUN;CACF"}