@livestore/livestore 0.0.0-snapshot-df546e17f0470b8f4f9bd33aad8c4fca65ec6355 → 0.0.0-snapshot-3b921bf0919e38fd218b5ef2926920c8c4806157

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 (70) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/effect/LiveStore.d.ts +1 -2
  3. package/dist/effect/LiveStore.d.ts.map +1 -1
  4. package/dist/effect/LiveStore.js +1 -1
  5. package/dist/effect/LiveStore.js.map +1 -1
  6. package/dist/index.d.ts +5 -4
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +4 -3
  9. package/dist/index.js.map +1 -1
  10. package/dist/reactiveQueries/base-class.d.ts +4 -3
  11. package/dist/reactiveQueries/base-class.d.ts.map +1 -1
  12. package/dist/reactiveQueries/base-class.js.map +1 -1
  13. package/dist/reactiveQueries/{js.d.ts → computed.d.ts} +3 -3
  14. package/dist/reactiveQueries/computed.d.ts.map +1 -0
  15. package/dist/reactiveQueries/{js.js → computed.js} +3 -3
  16. package/dist/reactiveQueries/computed.js.map +1 -0
  17. package/dist/reactiveQueries/graphql.d.ts +2 -1
  18. package/dist/reactiveQueries/graphql.d.ts.map +1 -1
  19. package/dist/reactiveQueries/graphql.js.map +1 -1
  20. package/dist/reactiveQueries/sql.d.ts +1 -1
  21. package/dist/reactiveQueries/sql.d.ts.map +1 -1
  22. package/dist/reactiveQueries/sql.js +1 -1
  23. package/dist/reactiveQueries/sql.js.map +1 -1
  24. package/dist/row-query.js +1 -1
  25. package/dist/row-query.js.map +1 -1
  26. package/dist/store/create-store.d.ts +28 -0
  27. package/dist/store/create-store.d.ts.map +1 -0
  28. package/dist/store/create-store.js +149 -0
  29. package/dist/store/create-store.js.map +1 -0
  30. package/dist/{store-devtools.d.ts → store/devtools.d.ts} +4 -4
  31. package/dist/store/devtools.d.ts.map +1 -0
  32. package/dist/{store-devtools.js → store/devtools.js} +3 -3
  33. package/dist/store/devtools.js.map +1 -0
  34. package/dist/store/store-types.d.ts +101 -0
  35. package/dist/store/store-types.d.ts.map +1 -0
  36. package/dist/{store-context.js → store/store-types.js} +1 -1
  37. package/dist/store/store-types.js.map +1 -0
  38. package/dist/store/store.d.ts +88 -0
  39. package/dist/store/store.d.ts.map +1 -0
  40. package/dist/{store.js → store/store.js} +13 -155
  41. package/dist/store/store.js.map +1 -0
  42. package/dist/utils/dev.d.ts +1 -0
  43. package/dist/utils/dev.d.ts.map +1 -1
  44. package/dist/utils/dev.js +5 -0
  45. package/dist/utils/dev.js.map +1 -1
  46. package/package.json +6 -5
  47. package/src/ambient.d.ts +3 -1
  48. package/src/effect/LiveStore.ts +2 -3
  49. package/src/index.ts +5 -5
  50. package/src/reactiveQueries/base-class.ts +4 -3
  51. package/src/reactiveQueries/{js.ts → computed.ts} +3 -3
  52. package/src/reactiveQueries/graphql.ts +2 -1
  53. package/src/reactiveQueries/sql.ts +2 -2
  54. package/src/row-query.ts +2 -2
  55. package/src/store/create-store.ts +296 -0
  56. package/src/{store-devtools.ts → store/devtools.ts} +5 -5
  57. package/src/store/store-types.ts +111 -0
  58. package/src/{store.ts → store/store.ts} +18 -385
  59. package/src/utils/dev.ts +6 -0
  60. package/dist/reactiveQueries/js.d.ts.map +0 -1
  61. package/dist/reactiveQueries/js.js.map +0 -1
  62. package/dist/store-context.d.ts +0 -26
  63. package/dist/store-context.d.ts.map +0 -1
  64. package/dist/store-context.js.map +0 -1
  65. package/dist/store-devtools.d.ts.map +0 -1
  66. package/dist/store-devtools.js.map +0 -1
  67. package/dist/store.d.ts +0 -175
  68. package/dist/store.d.ts.map +0 -1
  69. package/dist/store.js.map +0 -1
  70. package/src/store-context.ts +0 -23
@@ -2,7 +2,8 @@ import type { QueryInfo, QueryInfoNone } from '@livestore/common'
2
2
  import type * as otel from '@opentelemetry/api'
3
3
 
4
4
  import { type Atom, type GetAtom, ReactiveGraph, throwContextNotSetError, type Thunk } from '../reactive.js'
5
- import type { QueryDebugInfo, RefreshReason, Store } from '../store.js'
5
+ import type { Store } from '../store/store.js'
6
+ import type { QueryDebugInfo, RefreshReason } from '../store/store-types.js'
6
7
  import type { StackInfo } from '../utils/stack-info.js'
7
8
 
8
9
  export type ReactivityGraph = ReactiveGraph<RefreshReason, QueryDebugInfo, QueryContext>
@@ -28,7 +29,7 @@ export type LiveQueryAny = LiveQuery<any, QueryInfo>
28
29
 
29
30
  export interface LiveQuery<TResult, TQueryInfo extends QueryInfo = QueryInfoNone> {
30
31
  id: number
31
- _tag: 'js' | 'sql' | 'graphql'
32
+ _tag: 'computed' | 'sql' | 'graphql'
32
33
 
33
34
  /** This should only be used on a type-level and doesn't hold any value during runtime */
34
35
  '__result!': TResult
@@ -64,7 +65,7 @@ export abstract class LiveStoreQueryBase<TResult, TQueryInfo extends QueryInfo>
64
65
  {
65
66
  '__result!'!: TResult
66
67
  id = queryIdCounter++
67
- abstract _tag: 'js' | 'sql' | 'graphql'
68
+ abstract _tag: 'computed' | 'sql' | 'graphql'
68
69
 
69
70
  /** Human-readable label for the query for debugging */
70
71
  abstract label: string
@@ -3,7 +3,7 @@ import * as otel from '@opentelemetry/api'
3
3
 
4
4
  import { globalReactivityGraph } from '../global-state.js'
5
5
  import type { Thunk } from '../reactive.js'
6
- import type { RefreshReason } from '../store.js'
6
+ import type { RefreshReason } from '../store/store-types.js'
7
7
  import { getDurationMsFromSpan } from '../utils/otel.js'
8
8
  import type { GetAtomResult, LiveQuery, QueryContext, ReactivityGraph } from './base-class.js'
9
9
  import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
@@ -27,7 +27,7 @@ export class LiveStoreJSQuery<TResult, TQueryInfo extends QueryInfo = QueryInfoN
27
27
  TResult,
28
28
  TQueryInfo
29
29
  > {
30
- _tag: 'js' = 'js'
30
+ _tag: 'computed' = 'computed'
31
31
 
32
32
  /** A reactive thunk representing the query results */
33
33
  results$: Thunk<TResult, QueryContext, RefreshReason>
@@ -82,7 +82,7 @@ export class LiveStoreJSQuery<TResult, TQueryInfo extends QueryInfo = QueryInfoN
82
82
 
83
83
  this.executionTimes.push(durationMs)
84
84
 
85
- setDebugInfo({ _tag: 'js', label, query: fn.toString(), durationMs })
85
+ setDebugInfo({ _tag: 'computed', label, query: fn.toString(), durationMs })
86
86
 
87
87
  return res
88
88
  }),
@@ -7,7 +7,8 @@ import * as graphql from 'graphql'
7
7
 
8
8
  import { globalReactivityGraph } from '../global-state.js'
9
9
  import { isThunk, type Thunk } from '../reactive.js'
10
- import type { BaseGraphQLContext, RefreshReason, Store } from '../store.js'
10
+ import type { Store } from '../store/store.js'
11
+ import type { BaseGraphQLContext, RefreshReason } from '../store/store-types.js'
11
12
  import { getDurationMsFromSpan } from '../utils/otel.js'
12
13
  import type { GetAtomResult, LiveQuery, QueryContext, ReactivityGraph } from './base-class.js'
13
14
  import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
@@ -6,7 +6,7 @@ import * as otel from '@opentelemetry/api'
6
6
  import { globalReactivityGraph } from '../global-state.js'
7
7
  import type { Thunk } from '../reactive.js'
8
8
  import { NOT_REFRESHED_YET } from '../reactive.js'
9
- import type { RefreshReason } from '../store.js'
9
+ import type { RefreshReason } from '../store/store-types.js'
10
10
  import { getDurationMsFromSpan } from '../utils/otel.js'
11
11
  import type { GetAtomResult, LiveQuery, QueryContext, ReactivityGraph } from './base-class.js'
12
12
  import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
@@ -105,7 +105,7 @@ export class LiveStoreSQLQuery<
105
105
  const startMs = performance.now()
106
106
  const queryString = genQueryString(makeGetAtomResult(get, otelContext ?? ctx.rootOtelContext), ctx)
107
107
  const durationMs = performance.now() - startMs
108
- setDebugInfo({ _tag: 'js', label: `${label}:queryString`, query: queryString, durationMs })
108
+ setDebugInfo({ _tag: 'computed', label: `${label}:queryString`, query: queryString, durationMs })
109
109
  return queryString
110
110
  },
111
111
  {
package/src/row-query.ts CHANGED
@@ -14,9 +14,9 @@ import type {
14
14
  QueryContext,
15
15
  ReactivityGraph,
16
16
  } from './reactiveQueries/base-class.js'
17
- import { computed } from './reactiveQueries/js.js'
17
+ import { computed } from './reactiveQueries/computed.js'
18
18
  import { LiveStoreSQLQuery } from './reactiveQueries/sql.js'
19
- import type { Store } from './store.js'
19
+ import type { Store } from './store/store.js'
20
20
 
21
21
  export type RowQueryOptions<TTableDef extends DbSchema.TableDef, TResult = RowResult<TTableDef>> = {
22
22
  otelContext?: otel.Context
@@ -0,0 +1,296 @@
1
+ import type {
2
+ Adapter,
3
+ BootDb,
4
+ BootStatus,
5
+ ClientSession,
6
+ EventId,
7
+ IntentionalShutdownCause,
8
+ PreparedBindValues,
9
+ StoreDevtoolsChannel,
10
+ } from '@livestore/common'
11
+ import { getExecArgsFromMutation, replaceSessionIdSymbol, UnexpectedError } from '@livestore/common'
12
+ import type { LiveStoreSchema, MutationEvent } from '@livestore/common/schema'
13
+ import { makeMutationEventSchemaMemo } from '@livestore/common/schema'
14
+ import { makeNoopTracer, shouldNeverHappen } from '@livestore/utils'
15
+ import {
16
+ Cause,
17
+ Data,
18
+ Deferred,
19
+ Duration,
20
+ Effect,
21
+ Exit,
22
+ FiberSet,
23
+ Layer,
24
+ Logger,
25
+ LogLevel,
26
+ MutableHashMap,
27
+ OtelTracer,
28
+ Queue,
29
+ Runtime,
30
+ Schema,
31
+ Scope,
32
+ } from '@livestore/utils/effect'
33
+ import * as otel from '@opentelemetry/api'
34
+
35
+ import { globalReactivityGraph } from '../global-state.js'
36
+ import type { ReactivityGraph } from '../reactiveQueries/base-class.js'
37
+ import { connectDevtoolsToStore } from './devtools.js'
38
+ import { Store } from './store.js'
39
+ import type { BaseGraphQLContext, GraphQLOptions, OtelOptions } from './store-types.js'
40
+
41
+ export type CreateStoreOptions<TGraphQLContext extends BaseGraphQLContext, TSchema extends LiveStoreSchema> = {
42
+ schema: TSchema
43
+ adapter: Adapter
44
+ storeId: string
45
+ reactivityGraph?: ReactivityGraph
46
+ graphQLOptions?: GraphQLOptions<TGraphQLContext>
47
+ otelOptions?: Partial<OtelOptions>
48
+ boot?: (db: BootDb, parentSpan: otel.Span) => void | Promise<void> | Effect.Effect<void, unknown, otel.Tracer>
49
+ batchUpdates?: (run: () => void) => void
50
+ disableDevtools?: boolean
51
+ onBootStatus?: (status: BootStatus) => void
52
+ }
53
+
54
+ /** Create a new LiveStore Store */
55
+ export const createStorePromise = async <
56
+ TGraphQLContext extends BaseGraphQLContext,
57
+ TSchema extends LiveStoreSchema = LiveStoreSchema,
58
+ >({
59
+ signal,
60
+ ...options
61
+ }: CreateStoreOptions<TGraphQLContext, TSchema> & { signal?: AbortSignal }): Promise<Store<TGraphQLContext, TSchema>> =>
62
+ Effect.gen(function* () {
63
+ const scope = yield* Scope.make()
64
+ const runtime = yield* Effect.runtime()
65
+
66
+ if (signal !== undefined) {
67
+ signal.addEventListener('abort', () => {
68
+ Scope.close(scope, Exit.void).pipe(Effect.tapCauseLogPretty, Runtime.runFork(runtime))
69
+ })
70
+ }
71
+
72
+ return yield* FiberSet.make().pipe(
73
+ Effect.andThen((fiberSet) => createStore({ ...options, fiberSet })),
74
+ Scope.extend(scope),
75
+ )
76
+ }).pipe(
77
+ Effect.withSpan('createStore'),
78
+ Effect.tapCauseLogPretty,
79
+ Effect.annotateLogs({ thread: 'window' }),
80
+ Effect.provide(Logger.pretty),
81
+ Logger.withMinimumLogLevel(LogLevel.Debug),
82
+ Effect.runPromise,
83
+ )
84
+
85
+ // #region createStore
86
+ export const createStore = <
87
+ TGraphQLContext extends BaseGraphQLContext,
88
+ TSchema extends LiveStoreSchema = LiveStoreSchema,
89
+ >({
90
+ schema,
91
+ adapter,
92
+ storeId,
93
+ graphQLOptions,
94
+ otelOptions,
95
+ boot,
96
+ reactivityGraph = globalReactivityGraph,
97
+ batchUpdates,
98
+ disableDevtools,
99
+ onBootStatus,
100
+ fiberSet,
101
+ }: CreateStoreOptions<TGraphQLContext, TSchema> & { fiberSet: FiberSet.FiberSet }): Effect.Effect<
102
+ Store<TGraphQLContext, TSchema>,
103
+ UnexpectedError,
104
+ Scope.Scope
105
+ > => {
106
+ const otelTracer = otelOptions?.tracer ?? makeNoopTracer()
107
+ const otelRootSpanContext = otelOptions?.rootSpanContext ?? otel.context.active()
108
+
109
+ const TracingLive = Layer.unwrapEffect(Effect.map(OtelTracer.make, Layer.setTracer)).pipe(
110
+ Layer.provide(Layer.sync(OtelTracer.Tracer, () => otelTracer)),
111
+ )
112
+
113
+ return Effect.gen(function* () {
114
+ const span = yield* OtelTracer.currentOtelSpan.pipe(Effect.orDie)
115
+
116
+ const bootStatusQueue = yield* Queue.unbounded<BootStatus>().pipe(Effect.acquireRelease(Queue.shutdown))
117
+
118
+ yield* Queue.take(bootStatusQueue).pipe(
119
+ Effect.tapSync((status) => onBootStatus?.(status)),
120
+ Effect.tap((status) => (status.stage === 'done' ? Queue.shutdown(bootStatusQueue) : Effect.void)),
121
+ Effect.forever,
122
+ Effect.tapCauseLogPretty,
123
+ Effect.forkScoped,
124
+ )
125
+
126
+ const storeDeferred = yield* Deferred.make<Store>()
127
+
128
+ const connectDevtoolsToStore_ = (storeDevtoolsChannel: StoreDevtoolsChannel) =>
129
+ Effect.gen(function* () {
130
+ const store = yield* Deferred.await(storeDeferred)
131
+ yield* connectDevtoolsToStore({ storeDevtoolsChannel, store })
132
+ })
133
+
134
+ const runtime = yield* Effect.runtime<Scope.Scope>()
135
+
136
+ const runEffectFork = (effect: Effect.Effect<any, any, never>) =>
137
+ effect.pipe(Effect.tapCauseLogPretty, FiberSet.run(fiberSet), Runtime.runFork(runtime))
138
+
139
+ // TODO close parent scope? (Needs refactor with Mike A)
140
+ const shutdown = (cause: Cause.Cause<UnexpectedError | IntentionalShutdownCause>) =>
141
+ Effect.gen(function* () {
142
+ // NOTE we're calling `cause.toString()` here to avoid triggering a `console.error` in the grouped log
143
+ const logCause =
144
+ Cause.isFailType(cause) && cause.error._tag === 'LiveStore.IntentionalShutdownCause'
145
+ ? cause.toString()
146
+ : cause
147
+ yield* Effect.logDebug(`Shutting down LiveStore`, logCause)
148
+
149
+ FiberSet.clear(fiberSet).pipe(
150
+ Effect.andThen(() => FiberSet.run(fiberSet, Effect.failCause(cause))),
151
+ Effect.timeout(Duration.seconds(1)),
152
+ Effect.logWarnIfTakesLongerThan({ label: '@livestore/livestore:shutdown:clear-fiber-set', duration: 500 }),
153
+ Effect.catchTag('TimeoutException', (err) =>
154
+ Effect.logError('Store shutdown timed out. Forcing shutdown.', err).pipe(
155
+ Effect.andThen(FiberSet.run(fiberSet, Effect.failCause(cause))),
156
+ ),
157
+ ),
158
+ Runtime.runFork(runtime), // NOTE we need to fork this separately otherwise it will also be interrupted
159
+ )
160
+ }).pipe(Effect.withSpan('livestore:shutdown'))
161
+
162
+ const clientSession: ClientSession = yield* adapter({
163
+ schema,
164
+ storeId,
165
+ devtoolsEnabled: disableDevtools !== true,
166
+ bootStatusQueue,
167
+ shutdown,
168
+ connectDevtoolsToStore: connectDevtoolsToStore_,
169
+ }).pipe(Effect.withPerformanceMeasure('livestore:makeAdapter'), Effect.withSpan('createStore:makeAdapter'))
170
+
171
+ const mutationEventSchema = makeMutationEventSchemaMemo(schema)
172
+
173
+ // TODO get rid of this
174
+ // const __processedMutationIds = new Set<number>()
175
+
176
+ const currentMutationEventIdRef = { current: yield* clientSession.coordinator.getCurrentMutationEventId }
177
+
178
+ // TODO fill up with unsynced mutation events from the coordinator
179
+ const unsyncedMutationEvents = MutableHashMap.empty<EventId, MutationEvent.ForSchema<TSchema>>()
180
+
181
+ // TODO consider moving booting into the clientSession
182
+ if (boot !== undefined) {
183
+ let isInTxn = false
184
+ let txnExecuteStmnts: [string, PreparedBindValues | undefined][] = []
185
+
186
+ const bootDbImpl: BootDb = {
187
+ _tag: 'BootDb',
188
+ execute: (queryStr, bindValues) => {
189
+ const stmt = clientSession.syncDb.prepare(queryStr)
190
+ stmt.execute(bindValues)
191
+
192
+ if (isInTxn === true) {
193
+ txnExecuteStmnts.push([queryStr, bindValues])
194
+ } else {
195
+ clientSession.coordinator.execute(queryStr, bindValues).pipe(runEffectFork)
196
+ }
197
+ },
198
+ mutate: (...list) => {
199
+ for (const mutationEventDecoded_ of list) {
200
+ const mutationDef =
201
+ schema.mutations.get(mutationEventDecoded_.mutation) ??
202
+ shouldNeverHappen(`Unknown mutation type: ${mutationEventDecoded_.mutation}`)
203
+
204
+ const { id, parentId } = clientSession.coordinator
205
+ .nextMutationEventIdPair({ localOnly: mutationDef.options.localOnly })
206
+ .pipe(Effect.runSync)
207
+
208
+ currentMutationEventIdRef.current = id
209
+
210
+ const mutationEventDecoded = { ...mutationEventDecoded_, id, parentId }
211
+
212
+ replaceSessionIdSymbol(mutationEventDecoded.args, clientSession.coordinator.sessionId)
213
+
214
+ MutableHashMap.set(unsyncedMutationEvents, Data.struct(mutationEventDecoded.id), mutationEventDecoded)
215
+
216
+ // __processedMutationIds.add(mutationEventDecoded.id.global)
217
+
218
+ const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
219
+ // const { bindValues, statementSql } = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
220
+
221
+ for (const { statementSql, bindValues } of execArgsArr) {
222
+ clientSession.syncDb.execute(statementSql, bindValues)
223
+ }
224
+
225
+ const mutationEventEncoded = Schema.encodeUnknownSync(mutationEventSchema)(mutationEventDecoded)
226
+
227
+ clientSession.coordinator
228
+ .mutate(mutationEventEncoded as MutationEvent.AnyEncoded, { persisted: true })
229
+ .pipe(runEffectFork)
230
+ }
231
+ },
232
+ select: (queryStr, bindValues) => {
233
+ const stmt = clientSession.syncDb.prepare(queryStr)
234
+ return stmt.select(bindValues)
235
+ },
236
+ txn: (callback) => {
237
+ try {
238
+ isInTxn = true
239
+ // clientSession.syncDb.execute('BEGIN TRANSACTION', undefined)
240
+
241
+ callback()
242
+
243
+ // clientSession.syncDb.execute('COMMIT', undefined)
244
+
245
+ // clientSession.coordinator.execute('BEGIN', undefined, undefined)
246
+ for (const [queryStr, bindValues] of txnExecuteStmnts) {
247
+ clientSession.coordinator.execute(queryStr, bindValues).pipe(runEffectFork)
248
+ }
249
+ // clientSession.coordinator.execute('COMMIT', undefined, undefined)
250
+ } catch (e: any) {
251
+ // clientSession.syncDb.execute('ROLLBACK', undefined)
252
+ throw e
253
+ } finally {
254
+ isInTxn = false
255
+ txnExecuteStmnts = []
256
+ }
257
+ },
258
+ }
259
+
260
+ yield* Effect.tryAll(() => boot(bootDbImpl, span)).pipe(
261
+ UnexpectedError.mapToUnexpectedError,
262
+ Effect.withSpan('createStore:boot'),
263
+ )
264
+ }
265
+
266
+ const store = Store.createStore<TGraphQLContext, TSchema>(
267
+ {
268
+ clientSession,
269
+ schema,
270
+ graphQLOptions,
271
+ otelOptions: { tracer: otelTracer, rootSpanContext: otelRootSpanContext },
272
+ reactivityGraph,
273
+ disableDevtools,
274
+ currentMutationEventIdRef,
275
+ unsyncedMutationEvents,
276
+ fiberSet,
277
+ runtime,
278
+ batchUpdates: batchUpdates ?? ((run) => run()),
279
+ storeId,
280
+ },
281
+ span,
282
+ )
283
+
284
+ yield* Deferred.succeed(storeDeferred, store as any as Store)
285
+
286
+ return store
287
+ }).pipe(
288
+ Effect.withSpan('createStore', {
289
+ parent: otelOptions?.rootSpanContext
290
+ ? OtelTracer.makeExternalSpan(otel.trace.getSpanContext(otelOptions.rootSpanContext)!)
291
+ : undefined,
292
+ }),
293
+ Effect.provide(TracingLive),
294
+ )
295
+ }
296
+ // #endregion createStore
@@ -4,11 +4,11 @@ import { throttle } from '@livestore/utils'
4
4
  import type { WebChannel } from '@livestore/utils/effect'
5
5
  import { Effect, Stream } from '@livestore/utils/effect'
6
6
 
7
- import { NOT_REFRESHED_YET } from './reactive.js'
8
- import type { LiveQuery, ReactivityGraph } from './reactiveQueries/base-class.js'
9
- import type { SynchronousDatabaseWrapper } from './SynchronousDatabaseWrapper.js'
10
- import { emptyDebugInfo as makeEmptyDebugInfo } from './SynchronousDatabaseWrapper.js'
11
- import type { ReferenceCountedSet } from './utils/data-structures.js'
7
+ import { NOT_REFRESHED_YET } from '../reactive.js'
8
+ import type { LiveQuery, ReactivityGraph } from '../reactiveQueries/base-class.js'
9
+ import type { SynchronousDatabaseWrapper } from '../SynchronousDatabaseWrapper.js'
10
+ import { emptyDebugInfo as makeEmptyDebugInfo } from '../SynchronousDatabaseWrapper.js'
11
+ import type { ReferenceCountedSet } from '../utils/data-structures.js'
12
12
 
13
13
  type IStore = {
14
14
  clientSession: ClientSession
@@ -0,0 +1,111 @@
1
+ import type { ClientSession, EventId, IntentionalShutdownCause, UnexpectedError } from '@livestore/common'
2
+ import type { LiveStoreSchema, MutationEvent } from '@livestore/common/schema'
3
+ import type { FiberSet, MutableHashMap, Runtime, Scope } from '@livestore/utils/effect'
4
+ import { Schema } from '@livestore/utils/effect'
5
+ import type * as otel from '@opentelemetry/api'
6
+ import type { GraphQLSchema } from 'graphql'
7
+
8
+ import type { DebugRefreshReasonBase } from '../reactive.js'
9
+ import type { ReactivityGraph } from '../reactiveQueries/base-class.js'
10
+ import type { SynchronousDatabaseWrapper } from '../SynchronousDatabaseWrapper.js'
11
+ import type { StackInfo } from '../utils/stack-info.js'
12
+ import type { Store } from './store.js'
13
+
14
+ export type LiveStoreContext =
15
+ | LiveStoreContextRunning
16
+ | {
17
+ stage: 'error'
18
+ error: UnexpectedError | unknown
19
+ }
20
+ | {
21
+ stage: 'shutdown'
22
+ cause: IntentionalShutdownCause | StoreAbort
23
+ }
24
+
25
+ export class StoreAbort extends Schema.TaggedError<StoreAbort>()('LiveStore.StoreAbort', {}) {}
26
+ export class StoreInterrupted extends Schema.TaggedError<StoreInterrupted>()('LiveStore.StoreInterrupted', {}) {}
27
+
28
+ export type LiveStoreContextRunning = {
29
+ stage: 'running'
30
+ store: Store
31
+ }
32
+
33
+ export type BaseGraphQLContext = {
34
+ queriedTables: Set<string>
35
+ /** Needed by Pothos Otel plugin for resolver tracing to work */
36
+ otelContext?: otel.Context
37
+ }
38
+
39
+ export type GraphQLOptions<TContext> = {
40
+ schema: GraphQLSchema
41
+ makeContext: (db: SynchronousDatabaseWrapper, tracer: otel.Tracer, sessionId: string) => TContext
42
+ }
43
+
44
+ export type OtelOptions = {
45
+ tracer: otel.Tracer
46
+ rootSpanContext: otel.Context
47
+ }
48
+
49
+ export type StoreOptions<
50
+ TGraphQLContext extends BaseGraphQLContext,
51
+ TSchema extends LiveStoreSchema = LiveStoreSchema,
52
+ > = {
53
+ clientSession: ClientSession
54
+ schema: TSchema
55
+ storeId: string
56
+ // TODO remove graphql-related stuff from store and move to GraphQL query directly
57
+ graphQLOptions?: GraphQLOptions<TGraphQLContext>
58
+ otelOptions: OtelOptions
59
+ reactivityGraph: ReactivityGraph
60
+ disableDevtools?: boolean
61
+ fiberSet: FiberSet.FiberSet
62
+ runtime: Runtime.Runtime<Scope.Scope>
63
+ batchUpdates: (runUpdates: () => void) => void
64
+ currentMutationEventIdRef: { current: EventId }
65
+ unsyncedMutationEvents: MutableHashMap.MutableHashMap<EventId, MutationEvent.ForSchema<TSchema>>
66
+ }
67
+
68
+ export type RefreshReason =
69
+ | DebugRefreshReasonBase
70
+ | {
71
+ _tag: 'mutate'
72
+ /** The mutations that were applied */
73
+ mutations: ReadonlyArray<MutationEvent.Any>
74
+
75
+ /** The tables that were written to by the event */
76
+ writeTables: ReadonlyArray<string>
77
+ }
78
+ | {
79
+ // TODO rename to a more appropriate name which is framework-agnostic
80
+ _tag: 'react'
81
+ api: string
82
+ label?: string
83
+ stackInfo?: StackInfo
84
+ }
85
+ | { _tag: 'manual'; label?: string }
86
+
87
+ export type QueryDebugInfo = {
88
+ _tag: 'graphql' | 'sql' | 'computed' | 'unknown'
89
+ label: string
90
+ query: string
91
+ durationMs: number
92
+ }
93
+
94
+ export type StoreOtel = {
95
+ tracer: otel.Tracer
96
+ mutationsSpanContext: otel.Context
97
+ queriesSpanContext: otel.Context
98
+ }
99
+
100
+ export type StoreMutateOptions = {
101
+ label?: string
102
+ skipRefresh?: boolean
103
+ wasSyncMessage?: boolean
104
+ /**
105
+ * When set to `false` the mutation won't be persisted in the mutation log and sync server (but still synced).
106
+ * This can be useful e.g. for fine-granular update events (e.g. position updates during drag & drop)
107
+ *
108
+ * @default true
109
+ */
110
+ persisted?: boolean
111
+ }