@livestore/livestore 0.4.0-dev.15 → 0.4.0-dev.17

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 (40) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/SqliteDbWrapper.test.js +2 -1
  3. package/dist/SqliteDbWrapper.test.js.map +1 -1
  4. package/dist/live-queries/client-document-get-query.js +3 -2
  5. package/dist/live-queries/client-document-get-query.js.map +1 -1
  6. package/dist/live-queries/db-query.d.ts.map +1 -1
  7. package/dist/live-queries/db-query.js +6 -4
  8. package/dist/live-queries/db-query.js.map +1 -1
  9. package/dist/live-queries/db-query.test.js +5 -4
  10. package/dist/live-queries/db-query.test.js.map +1 -1
  11. package/dist/mod.d.ts +1 -2
  12. package/dist/mod.d.ts.map +1 -1
  13. package/dist/mod.js +1 -1
  14. package/dist/mod.js.map +1 -1
  15. package/dist/store/create-store.d.ts +2 -2
  16. package/dist/store/create-store.d.ts.map +1 -1
  17. package/dist/store/create-store.js +6 -5
  18. package/dist/store/create-store.js.map +1 -1
  19. package/dist/store/devtools.d.ts +2 -13
  20. package/dist/store/devtools.d.ts.map +1 -1
  21. package/dist/store/devtools.js +34 -13
  22. package/dist/store/devtools.js.map +1 -1
  23. package/dist/store/store-types.d.ts +89 -4
  24. package/dist/store/store-types.d.ts.map +1 -1
  25. package/dist/store/store-types.js +1 -0
  26. package/dist/store/store-types.js.map +1 -1
  27. package/dist/store/store.d.ts +20 -26
  28. package/dist/store/store.d.ts.map +1 -1
  29. package/dist/store/store.js +106 -86
  30. package/dist/store/store.js.map +1 -1
  31. package/package.json +5 -5
  32. package/src/SqliteDbWrapper.test.ts +2 -2
  33. package/src/live-queries/client-document-get-query.ts +3 -3
  34. package/src/live-queries/db-query.test.ts +5 -4
  35. package/src/live-queries/db-query.ts +7 -4
  36. package/src/mod.ts +8 -8
  37. package/src/store/create-store.ts +6 -7
  38. package/src/store/devtools.ts +40 -26
  39. package/src/store/store-types.ts +107 -4
  40. package/src/store/store.ts +143 -117
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  type Bindable,
3
3
  type ClientSession,
4
- type ClientSessionSyncProcessor,
5
4
  Devtools,
6
5
  getExecStatementsFromMaterializer,
7
6
  getResultSchema,
@@ -37,7 +36,7 @@ import {
37
36
  import { nanoid } from '@livestore/utils/nanoid'
38
37
  import * as otel from '@opentelemetry/api'
39
38
 
40
- import type { LiveQuery, ReactivityGraph, ReactivityGraphContext, SignalDef } from '../live-queries/base-class.ts'
39
+ import type { LiveQuery, ReactivityGraphContext, SignalDef } from '../live-queries/base-class.ts'
41
40
  import { makeReactivityGraph } from '../live-queries/base-class.ts'
42
41
  import { makeExecBeforeFirstRun } from '../live-queries/client-document-get-query.ts'
43
42
  import { queryDb } from '../live-queries/db-query.ts'
@@ -45,18 +44,20 @@ import type { Ref } from '../reactive.ts'
45
44
  import { SqliteDbWrapper } from '../SqliteDbWrapper.ts'
46
45
  import { ReferenceCountedSet } from '../utils/data-structures.ts'
47
46
  import { downloadBlob, exposeDebugUtils } from '../utils/dev.ts'
48
- import type {
49
- Queryable,
50
- RefreshReason,
51
- StoreCommitOptions,
52
- StoreEventsOptions,
53
- StoreOptions,
54
- StoreOtel,
55
- SubscribeOptions,
56
- Unsubscribe,
47
+ import {
48
+ type Queryable,
49
+ type RefreshReason,
50
+ type StoreCommitOptions,
51
+ type StoreEventsOptions,
52
+ type StoreInternals,
53
+ StoreInternalsSymbol,
54
+ type StoreOptions,
55
+ type StoreOtel,
56
+ type SubscribeOptions,
57
+ type Unsubscribe,
57
58
  } from './store-types.ts'
58
59
 
59
- type SubscribeFn = {
60
+ export type SubscribeFn = {
60
61
  <TResult>(
61
62
  query: Queryable<TResult>,
62
63
  onUpdate: (value: TResult) => void,
@@ -71,12 +72,8 @@ if (isDevEnv()) {
71
72
 
72
73
  export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TContext = {}> extends Inspectable.Class {
73
74
  readonly storeId: string
74
- reactivityGraph: ReactivityGraph
75
- sqliteDbWrapper: SqliteDbWrapper
76
- clientSession: ClientSession
77
75
  schema: LiveStoreSchema
78
76
  context: TContext
79
- otel: StoreOtel
80
77
  /**
81
78
  * Reactive connectivity updates emitted by the backing sync backend.
82
79
  *
@@ -94,29 +91,16 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
94
91
  * )
95
92
  * ```
96
93
  */
97
- readonly networkStatus: ClientSession['leaderThread']['networkStatus']
98
- /**
99
- * Note we're using `Ref<null>` here as we don't care about the value but only about *that* something has changed.
100
- * This only works in combination with `equal: () => false` which will always trigger a refresh.
101
- */
102
- tableRefs: { [key: string]: Ref<null, ReactivityGraphContext, RefreshReason> }
103
-
104
- /** Tracks whether the store has been shut down */
105
- private isShutdown = false
94
+ readonly networkStatus: ClientSession['leaderThread']['networkStatus'];
106
95
 
107
- private effectContext: {
108
- runtime: Runtime.Runtime<Scope.Scope>
109
- lifetimeScope: Scope.Scope
110
- }
96
+ /** Tracks whether the store has been shut down is kept in internals */
111
97
 
112
98
  /** RC-based set to see which queries are currently subscribed to */
113
- activeQueries: ReferenceCountedSet<LiveQuery<any>>
114
-
115
- // NOTE this is currently exposed for the Devtools databrowser to commit events
116
- readonly __eventSchema
117
- readonly syncProcessor: ClientSessionSyncProcessor
118
99
 
119
- readonly boot: Effect.Effect<void, UnexpectedError, Scope.Scope>
100
+ /**
101
+ * Store internals. Shouldn't be used directly in application code.
102
+ */
103
+ [StoreInternalsSymbol]: StoreInternals
120
104
 
121
105
  // #region constructor
122
106
  constructor({
@@ -134,20 +118,14 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
134
118
  super()
135
119
 
136
120
  this.storeId = storeId
137
-
138
- this.sqliteDbWrapper = new SqliteDbWrapper({ otel: otelOptions, db: clientSession.sqliteDb })
139
- this.clientSession = clientSession
140
121
  this.schema = schema
141
122
  this.context = context
142
- this.networkStatus = clientSession.leaderThread.networkStatus
143
-
144
- this.effectContext = effectContext
145
123
 
146
124
  const reactivityGraph = makeReactivityGraph()
147
125
 
148
126
  const syncSpan = otelOptions.tracer.startSpan('LiveStore:sync', {}, otelOptions.rootSpanContext)
149
127
 
150
- this.syncProcessor = makeClientSessionSyncProcessor({
128
+ const syncProcessor = makeClientSessionSyncProcessor({
151
129
  schema,
152
130
  clientSession,
153
131
  runtime: effectContext.runtime,
@@ -175,7 +153,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
175
153
  const execArgsArr = getExecStatementsFromMaterializer({
176
154
  eventDef,
177
155
  materializer,
178
- dbState: this.sqliteDbWrapper,
156
+ dbState: this[StoreInternalsSymbol].sqliteDbWrapper,
179
157
  event: { decoded: undefined, encoded: eventEncoded },
180
158
  })
181
159
 
@@ -202,10 +180,13 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
202
180
  for (const {
203
181
  statementSql,
204
182
  bindValues,
205
- writeTables = this.sqliteDbWrapper.getTablesUsed(statementSql),
183
+ writeTables = this[StoreInternalsSymbol].sqliteDbWrapper.getTablesUsed(statementSql),
206
184
  } of execArgsArr) {
207
185
  try {
208
- this.sqliteDbWrapper.cachedExecute(statementSql, bindValues, { otelContext, writeTables })
186
+ this[StoreInternalsSymbol].sqliteDbWrapper.cachedExecute(statementSql, bindValues, {
187
+ otelContext,
188
+ writeTables,
189
+ })
209
190
  } catch (cause) {
210
191
  // TOOD refactor with `SqliteError`
211
192
  throw UnexpectedError.make({
@@ -219,7 +200,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
219
200
  writeTablesForEvent.add(table)
220
201
  }
221
202
 
222
- this.sqliteDbWrapper.debug.head = eventEncoded.seqNum
203
+ this[StoreInternalsSymbol].sqliteDbWrapper.debug.head = eventEncoded.seqNum
223
204
  }
224
205
  }
225
206
 
@@ -228,7 +209,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
228
209
  | { _tag: 'no-op' }
229
210
  | { _tag: 'unset' } = { _tag: 'unset' }
230
211
  if (withChangeset === true) {
231
- sessionChangeset = this.sqliteDbWrapper.withChangeset(exec).changeset
212
+ sessionChangeset = this[StoreInternalsSymbol].sqliteDbWrapper.withChangeset(exec).changeset
232
213
  } else {
233
214
  exec()
234
215
  }
@@ -237,12 +218,12 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
237
218
  }).pipe(Effect.mapError((cause) => MaterializeError.make({ cause }))),
238
219
  ),
239
220
  rollback: (changeset) => {
240
- this.sqliteDbWrapper.rollback(changeset)
221
+ this[StoreInternalsSymbol].sqliteDbWrapper.rollback(changeset)
241
222
  },
242
223
  refreshTables: (tables) => {
243
224
  const tablesToUpdate = [] as [Ref<null, ReactivityGraphContext, RefreshReason>, null][]
244
225
  for (const tableName of tables) {
245
- const tableRef = this.tableRefs[tableName]
226
+ const tableRef = this[StoreInternalsSymbol].tableRefs[tableName]
246
227
  assertNever(tableRef !== undefined, `No table ref found for ${tableName}`)
247
228
  tablesToUpdate.push([tableRef!, null])
248
229
  }
@@ -260,11 +241,9 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
260
241
  confirmUnsavedChanges,
261
242
  })
262
243
 
263
- this.__eventSchema = LiveStoreEvent.makeEventDefSchemaMemo(schema)
264
-
265
244
  // TODO generalize the `tableRefs` concept to allow finer-grained refs
266
- this.tableRefs = {}
267
- this.activeQueries = new ReferenceCountedSet()
245
+ const tableRefs: { [key: string]: Ref<null, ReactivityGraphContext, RefreshReason> } = {}
246
+ const activeQueries = new ReferenceCountedSet<LiveQuery<any>>()
268
247
 
269
248
  const commitsSpan = otelOptions.tracer.startSpan('LiveStore:commits', {}, otelOptions.rootSpanContext)
270
249
  const otelMuationsSpanContext = otel.trace.setSpan(otel.context.active(), commitsSpan)
@@ -272,8 +251,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
272
251
  const queriesSpan = otelOptions.tracer.startSpan('LiveStore:queries', {}, otelOptions.rootSpanContext)
273
252
  const otelQueriesSpanContext = otel.trace.setSpan(otel.context.active(), queriesSpan)
274
253
 
275
- this.reactivityGraph = reactivityGraph
276
- this.reactivityGraph.context = {
254
+ reactivityGraph.context = {
277
255
  store: this as unknown as Store<LiveStoreSchema>,
278
256
  defRcMap: new Map(),
279
257
  reactivityGraph: new WeakRef(reactivityGraph),
@@ -281,8 +259,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
281
259
  rootOtelContext: otelQueriesSpanContext,
282
260
  effectsWrapper: batchUpdates,
283
261
  }
284
-
285
- this.otel = {
262
+ const otelObj: StoreOtel = {
286
263
  tracer: otelOptions.tracer,
287
264
  rootSpanContext: otelOptions.rootSpanContext,
288
265
  commitsSpanContext: otelMuationsSpanContext,
@@ -298,27 +275,27 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
298
275
  : Array.from(this.schema.state.sqlite.tables.keys()).filter((_) => !SystemTables.isStateSystemTable(_)),
299
276
  )
300
277
  const existingTableRefs = new Map(
301
- Array.from(this.reactivityGraph.atoms.values())
278
+ Array.from(reactivityGraph.atoms.values())
302
279
  .filter((_): _ is Ref<any, any, any> => _._tag === 'ref' && _.label?.startsWith('tableRef:') === true)
303
280
  .map((_) => [_.label!.slice('tableRef:'.length), _] as const),
304
281
  )
305
282
  for (const tableName of allTableNames) {
306
- this.tableRefs[tableName] =
283
+ tableRefs[tableName] =
307
284
  existingTableRefs.get(tableName) ??
308
- this.reactivityGraph.makeRef(null, {
285
+ reactivityGraph.makeRef(null, {
309
286
  equal: () => false,
310
287
  label: `tableRef:${tableName}`,
311
288
  meta: { liveStoreRefType: 'table' },
312
289
  })
313
290
  }
314
291
 
315
- this.boot = Effect.gen(this, function* () {
292
+ const boot = Effect.gen(this, function* () {
316
293
  yield* Effect.addFinalizer(() =>
317
294
  Effect.sync(() => {
318
295
  // Remove all table refs from the reactivity graph
319
- for (const tableRef of Object.values(this.tableRefs)) {
296
+ for (const tableRef of Object.values(tableRefs)) {
320
297
  for (const superComp of tableRef.super) {
321
- this.reactivityGraph.removeEdge(superComp, tableRef)
298
+ this[StoreInternalsSymbol].reactivityGraph.removeEdge(superComp, tableRef)
322
299
  }
323
300
  }
324
301
 
@@ -329,21 +306,57 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
329
306
  }),
330
307
  )
331
308
 
332
- yield* this.syncProcessor.boot
309
+ yield* syncProcessor.boot
333
310
  })
311
+
312
+ // Build Sqlite wrapper last to avoid using getters before internals are set
313
+ const sqliteDbWrapper = new SqliteDbWrapper({ otel: otelOptions, db: clientSession.sqliteDb })
314
+
315
+ // Initialize internals bag
316
+ this[StoreInternalsSymbol] = {
317
+ eventSchema: LiveStoreEvent.makeEventDefSchemaMemo(schema) as Schema.Schema<
318
+ LiveStoreEvent.AnyDecoded,
319
+ LiveStoreEvent.AnyEncoded
320
+ >,
321
+ clientSession,
322
+ sqliteDbWrapper,
323
+ effectContext,
324
+ otel: otelObj,
325
+ reactivityGraph,
326
+ tableRefs,
327
+ activeQueries,
328
+ syncProcessor,
329
+ boot,
330
+ isShutdown: false,
331
+ }
332
+
333
+ // Initialize stable network status property from client session
334
+ this.networkStatus = clientSession.leaderThread.networkStatus
334
335
  }
335
336
  // #endregion constructor
336
337
 
338
+ /**
339
+ * Current session identifier for this Store instance.
340
+ *
341
+ * - Stable for the lifetime of the Store
342
+ * - Useful for correlating events or scoping per-session data
343
+ */
337
344
  get sessionId(): string {
338
- return this.clientSession.sessionId
345
+ return this[StoreInternalsSymbol].clientSession.sessionId
339
346
  }
340
347
 
348
+ /**
349
+ * Stable client identifier for the process/device using this Store.
350
+ *
351
+ * - Shared across Store instances created by the same client
352
+ * - Useful for diagnostics and multi-client correlation
353
+ */
341
354
  get clientId(): string {
342
- return this.clientSession.clientId
355
+ return this[StoreInternalsSymbol].clientSession.clientId
343
356
  }
344
357
 
345
358
  private checkShutdown = (operation: string): void => {
346
- if (this.isShutdown) {
359
+ if (this[StoreInternalsSymbol].isShutdown) {
347
360
  throw new UnexpectedError({
348
361
  cause: `Store has been shut down (while performing "${operation}").`,
349
362
  note: `You cannot perform this operation after the store has been shut down.`,
@@ -388,17 +401,17 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
388
401
  ): Unsubscribe => {
389
402
  this.checkShutdown('subscribe')
390
403
 
391
- return this.otel.tracer.startActiveSpan(
404
+ return this[StoreInternalsSymbol].otel.tracer.startActiveSpan(
392
405
  `LiveStore.subscribe`,
393
406
  { attributes: { label: options?.label, queryLabel: isQueryBuilder(query) ? query.toString() : query.label } },
394
- options?.otelContext ?? this.otel.queriesSpanContext,
407
+ options?.otelContext ?? this[StoreInternalsSymbol].otel.queriesSpanContext,
395
408
  (span) => {
396
409
  const otelContext = otel.trace.setSpan(otel.context.active(), span)
397
410
 
398
411
  const queryRcRef = isQueryBuilder(query)
399
- ? queryDb(query).make(this.reactivityGraph.context!)
412
+ ? queryDb(query).make(this[StoreInternalsSymbol].reactivityGraph.context!)
400
413
  : query._tag === 'def' || query._tag === 'signal-def'
401
- ? query.make(this.reactivityGraph.context!)
414
+ ? query.make(this[StoreInternalsSymbol].reactivityGraph.context!)
402
415
  : {
403
416
  value: query as LiveQuery<TResult>,
404
417
  deref: () => {},
@@ -406,7 +419,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
406
419
  const query$ = queryRcRef.value
407
420
 
408
421
  const label = `subscribe:${options?.label}`
409
- const effect = this.reactivityGraph.makeEffect(
422
+ const effect = this[StoreInternalsSymbol].reactivityGraph.makeEffect(
410
423
  (get, _otelContext, debugRefreshReason) => onUpdate(get(query$.results$, otelContext, debugRefreshReason)),
411
424
  { label },
412
425
  )
@@ -417,7 +430,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
417
430
 
418
431
  options?.onSubscribe?.(query$)
419
432
 
420
- this.activeQueries.add(query$ as LiveQuery<TResult>)
433
+ this[StoreInternalsSymbol].activeQueries.add(query$ as LiveQuery<TResult>)
421
434
 
422
435
  if (options?.skipInitialRun !== true && !query$.isDestroyed) {
423
436
  effect.doEffect(otelContext, {
@@ -428,8 +441,8 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
428
441
 
429
442
  const unsubscribe = () => {
430
443
  try {
431
- this.reactivityGraph.destroyNode(effect)
432
- this.activeQueries.remove(query$ as LiveQuery<TResult>)
444
+ this[StoreInternalsSymbol].reactivityGraph.destroyNode(effect)
445
+ this[StoreInternalsSymbol].activeQueries.remove(query$ as LiveQuery<TResult>)
433
446
 
434
447
  if (options?.stackInfo) {
435
448
  query$.activeSubscriptions.delete(options.stackInfo)
@@ -498,9 +511,13 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
498
511
  this.checkShutdown('query')
499
512
 
500
513
  if (typeof query === 'object' && 'query' in query && 'bindValues' in query) {
501
- const res = this.sqliteDbWrapper.cachedSelect(query.query, prepareBindValues(query.bindValues, query.query), {
502
- ...omitUndefineds({ otelContext: options?.otelContext }),
503
- }) as any
514
+ const res = this[StoreInternalsSymbol].sqliteDbWrapper.cachedSelect(
515
+ query.query,
516
+ prepareBindValues(query.bindValues, query.query),
517
+ {
518
+ ...omitUndefineds({ otelContext: options?.otelContext }),
519
+ },
520
+ ) as any
504
521
  if (query.schema) {
505
522
  return Schema.decodeSync(query.schema)(res)
506
523
  }
@@ -513,7 +530,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
513
530
  id: ast.id,
514
531
  explicitDefaultValues: ast.explicitDefaultValues,
515
532
  otelContext: options?.otelContext,
516
- })(this.reactivityGraph.context!)
533
+ })(this[StoreInternalsSymbol].reactivityGraph.context!)
517
534
  }
518
535
 
519
536
  const sqlRes = query.asSql()
@@ -521,13 +538,17 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
521
538
 
522
539
  // Replace SessionIdSymbol in bind values before executing the query
523
540
  if (sqlRes.bindValues) {
524
- replaceSessionIdSymbol(sqlRes.bindValues, this.clientSession.sessionId)
541
+ replaceSessionIdSymbol(sqlRes.bindValues, this[StoreInternalsSymbol].clientSession.sessionId)
525
542
  }
526
543
 
527
- const rawRes = this.sqliteDbWrapper.cachedSelect(sqlRes.query, sqlRes.bindValues as any as PreparedBindValues, {
528
- ...omitUndefineds({ otelContext: options?.otelContext }),
529
- queriedTables: new Set([query[QueryBuilderAstSymbol].tableDef.sqliteDef.name]),
530
- })
544
+ const rawRes = this[StoreInternalsSymbol].sqliteDbWrapper.cachedSelect(
545
+ sqlRes.query,
546
+ sqlRes.bindValues as any as PreparedBindValues,
547
+ {
548
+ ...omitUndefineds({ otelContext: options?.otelContext }),
549
+ queriedTables: new Set([query[QueryBuilderAstSymbol].tableDef.sqliteDef.name]),
550
+ },
551
+ )
531
552
 
532
553
  const decodeResult = Schema.decodeEither(schema)(rawRes)
533
554
  if (decodeResult._tag === 'Right') {
@@ -543,12 +564,12 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
543
564
  )
544
565
  }
545
566
  } else if (query._tag === 'def') {
546
- const query$ = query.make(this.reactivityGraph.context!)
567
+ const query$ = query.make(this[StoreInternalsSymbol].reactivityGraph.context!)
547
568
  const result = this.query(query$.value, options)
548
569
  query$.deref()
549
570
  return result
550
571
  } else if (query._tag === 'signal-def') {
551
- const signal$ = query.make(this.reactivityGraph.context!)
572
+ const signal$ = query.make(this[StoreInternalsSymbol].reactivityGraph.context!)
552
573
  return signal$.value.get()
553
574
  } else {
554
575
  return query.run({
@@ -575,7 +596,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
575
596
  setSignal = <T>(signalDef: SignalDef<T>, value: T | ((prev: T) => T)): void => {
576
597
  this.checkShutdown('setSignal')
577
598
 
578
- const signalRef = signalDef.make(this.reactivityGraph.context!)
599
+ const signalRef = signalDef.make(this[StoreInternalsSymbol].reactivityGraph.context!)
579
600
  const newValue: T = typeof value === 'function' ? (value as any)(signalRef.value.get()) : value
580
601
  signalRef.value.set(newValue)
581
602
 
@@ -664,13 +685,13 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
664
685
  const { events, options } = this.getCommitArgs(firstEventOrTxnFnOrOptions, restEvents)
665
686
 
666
687
  Effect.gen(this, function* () {
667
- const commitsSpan = otel.trace.getSpan(this.otel.commitsSpanContext)
688
+ const commitsSpan = otel.trace.getSpan(this[StoreInternalsSymbol].otel.commitsSpanContext)
668
689
  commitsSpan?.addEvent('commit')
669
690
  const currentSpan = yield* OtelTracer.currentOtelSpan.pipe(Effect.orDie)
670
691
  commitsSpan?.addLink({ context: currentSpan.spanContext() })
671
692
 
672
693
  for (const event of events) {
673
- replaceSessionIdSymbol(event.args, this.clientSession.sessionId)
694
+ replaceSessionIdSymbol(event.args, this[StoreInternalsSymbol].clientSession.sessionId)
674
695
  }
675
696
 
676
697
  if (events.length === 0) return
@@ -680,11 +701,11 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
680
701
  const materializeEventsTx = Effect.try({
681
702
  try: () => {
682
703
  const runMaterializeEvents = () => {
683
- return this.syncProcessor.push(events).pipe(Runtime.runSync(localRuntime))
704
+ return this[StoreInternalsSymbol].syncProcessor.push(events).pipe(Runtime.runSync(localRuntime))
684
705
  }
685
706
 
686
707
  if (events.length > 1) {
687
- return this.sqliteDbWrapper.txn(runMaterializeEvents)
708
+ return this[StoreInternalsSymbol].sqliteDbWrapper.txn(runMaterializeEvents)
688
709
  } else {
689
710
  return runMaterializeEvents()
690
711
  }
@@ -697,7 +718,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
697
718
 
698
719
  const tablesToUpdate: [Ref<null, ReactivityGraphContext, RefreshReason>, null][] = []
699
720
  for (const tableName of writeTables) {
700
- const tableRef = this.tableRefs[tableName]
721
+ const tableRef = this[StoreInternalsSymbol].tableRefs[tableName]
701
722
  assertNever(tableRef !== undefined, `No table ref found for ${tableName}`)
702
723
  tablesToUpdate.push([tableRef!, null])
703
724
  }
@@ -710,7 +731,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
710
731
  const skipRefresh = options?.skipRefresh ?? false
711
732
 
712
733
  // Update all table refs together in a batch, to only trigger one reactive update
713
- this.reactivityGraph.setRefs(tablesToUpdate, {
734
+ this[StoreInternalsSymbol].reactivityGraph.setRefs(tablesToUpdate, {
714
735
  debugRefreshReason,
715
736
  skipRefresh,
716
737
  otelContext: otel.trace.setSpan(otel.context.active(), currentSpan),
@@ -725,14 +746,16 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
725
746
  },
726
747
  links: [
727
748
  // Span link to LiveStore:commits
728
- OtelTracer.makeSpanLink({ context: otel.trace.getSpanContext(this.otel.commitsSpanContext)! }),
749
+ OtelTracer.makeSpanLink({
750
+ context: otel.trace.getSpanContext(this[StoreInternalsSymbol].otel.commitsSpanContext)!,
751
+ }),
729
752
  // User-provided span links
730
753
  ...(options?.spanLinks?.map(OtelTracer.makeSpanLink) ?? []),
731
754
  ],
732
755
  }),
733
756
  Effect.tapErrorCause(Effect.logError),
734
757
  Effect.catchAllCause((cause) => Effect.fork(this.shutdown(cause))),
735
- Runtime.runSync(this.effectContext.runtime),
758
+ Runtime.runSync(this[StoreInternalsSymbol].effectContext.runtime),
736
759
  )
737
760
  }
738
761
  // #endregion commit
@@ -775,13 +798,13 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
775
798
  this.checkShutdown('manualRefresh')
776
799
 
777
800
  const { label } = options ?? {}
778
- this.otel.tracer.startActiveSpan(
801
+ this[StoreInternalsSymbol].otel.tracer.startActiveSpan(
779
802
  'LiveStore:manualRefresh',
780
803
  { attributes: { 'livestore.manualRefreshLabel': label } },
781
- this.otel.commitsSpanContext,
804
+ this[StoreInternalsSymbol].otel.commitsSpanContext,
782
805
  (span) => {
783
806
  const otelContext = otel.trace.setSpan(otel.context.active(), span)
784
- this.reactivityGraph.runDeferredEffects({ otelContext })
807
+ this[StoreInternalsSymbol].reactivityGraph.runDeferredEffects({ otelContext })
785
808
  span.end()
786
809
  },
787
810
  )
@@ -795,7 +818,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
795
818
  shutdownPromise = async (cause?: UnexpectedError) => {
796
819
  this.checkShutdown('shutdownPromise')
797
820
 
798
- this.isShutdown = true
821
+ this[StoreInternalsSymbol].isShutdown = true
799
822
  await this.shutdown(cause ? Cause.fail(cause) : undefined).pipe(this.runEffectFork, Fiber.join, Effect.runPromise)
800
823
  }
801
824
 
@@ -805,8 +828,8 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
805
828
  * This is called automatically when the store was created using the React or Effect API.
806
829
  */
807
830
  shutdown = (cause?: Cause.Cause<UnexpectedError | MaterializeError>): Effect.Effect<void> => {
808
- this.isShutdown = true
809
- return this.clientSession.shutdown(
831
+ this[StoreInternalsSymbol].isShutdown = true
832
+ return this[StoreInternalsSymbol].clientSession.shutdown(
810
833
  cause ? Exit.failCause(cause) : Exit.succeed(IntentionalShutdownCause.make({ reason: 'manual' })),
811
834
  )
812
835
  }
@@ -819,30 +842,33 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
819
842
  _dev = {
820
843
  downloadDb: (source: 'local' | 'leader' = 'local') => {
821
844
  Effect.gen(this, function* () {
822
- const data = source === 'local' ? this.sqliteDbWrapper.export() : yield* this.clientSession.leaderThread.export
845
+ const data =
846
+ source === 'local'
847
+ ? this[StoreInternalsSymbol].sqliteDbWrapper.export()
848
+ : yield* this[StoreInternalsSymbol].clientSession.leaderThread.export
823
849
  downloadBlob(data, `livestore-${Date.now()}.db`)
824
850
  }).pipe(this.runEffectFork)
825
851
  },
826
852
 
827
853
  downloadEventlogDb: () => {
828
854
  Effect.gen(this, function* () {
829
- const data = yield* this.clientSession.leaderThread.getEventlogData
855
+ const data = yield* this[StoreInternalsSymbol].clientSession.leaderThread.getEventlogData
830
856
  downloadBlob(data, `livestore-eventlog-${Date.now()}.db`)
831
857
  }).pipe(this.runEffectFork)
832
858
  },
833
859
 
834
860
  hardReset: (mode: 'all-data' | 'only-app-db' = 'all-data') => {
835
861
  Effect.gen(this, function* () {
836
- const clientId = this.clientSession.clientId
837
- yield* this.clientSession.leaderThread.sendDevtoolsMessage(
862
+ const clientId = this[StoreInternalsSymbol].clientSession.clientId
863
+ yield* this[StoreInternalsSymbol].clientSession.leaderThread.sendDevtoolsMessage(
838
864
  Devtools.Leader.ResetAllData.Request.make({ liveStoreVersion, mode, requestId: nanoid(), clientId }),
839
865
  )
840
866
  }).pipe(this.runEffectFork)
841
867
  },
842
868
 
843
869
  overrideNetworkStatus: (status: 'online' | 'offline') => {
844
- const clientId = this.clientSession.clientId
845
- this.clientSession.leaderThread
870
+ const clientId = this[StoreInternalsSymbol].clientSession.clientId
871
+ this[StoreInternalsSymbol].clientSession.leaderThread
846
872
  .sendDevtoolsMessage(
847
873
  Devtools.Leader.SetSyncLatch.Request.make({
848
874
  clientId,
@@ -856,19 +882,19 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
856
882
 
857
883
  syncStates: () =>
858
884
  Effect.gen(this, function* () {
859
- const session = yield* this.syncProcessor.syncState
860
- const leader = yield* this.clientSession.leaderThread.syncState
885
+ const session = yield* this[StoreInternalsSymbol].syncProcessor.syncState
886
+ const leader = yield* this[StoreInternalsSymbol].clientSession.leaderThread.syncState
861
887
  return { session, leader }
862
888
  }).pipe(this.runEffectPromise),
863
889
 
864
890
  printSyncStates: () => {
865
891
  Effect.gen(this, function* () {
866
- const session = yield* this.syncProcessor.syncState
892
+ const session = yield* this[StoreInternalsSymbol].syncProcessor.syncState
867
893
  yield* Effect.log(
868
894
  `Session sync state: ${session.localHead} (upstream: ${session.upstreamHead})`,
869
895
  session.toJSON(),
870
896
  )
871
- const leader = yield* this.clientSession.leaderThread.syncState
897
+ const leader = yield* this[StoreInternalsSymbol].clientSession.leaderThread.syncState
872
898
  yield* Effect.log(`Leader sync state: ${leader.localHead} (upstream: ${leader.upstreamHead})`, leader.toJSON())
873
899
  }).pipe(this.runEffectFork)
874
900
  },
@@ -876,25 +902,25 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
876
902
  version: liveStoreVersion,
877
903
 
878
904
  otel: {
879
- rootSpanContext: () => otel.trace.getSpan(this.otel.rootSpanContext)?.spanContext(),
905
+ rootSpanContext: () => otel.trace.getSpan(this[StoreInternalsSymbol].otel.rootSpanContext)?.spanContext(),
880
906
  },
881
907
  }
882
908
 
883
909
  // NOTE This is needed because when booting a Store via Effect it seems to call `toJSON` in the error path
884
910
  toJSON = () => ({
885
911
  _tag: 'livestore.Store',
886
- reactivityGraph: this.reactivityGraph.getSnapshot({ includeResults: true }),
912
+ reactivityGraph: this[StoreInternalsSymbol].reactivityGraph.getSnapshot({ includeResults: true }),
887
913
  })
888
914
 
889
915
  private runEffectFork = <A, E>(effect: Effect.Effect<A, E, Scope.Scope>) =>
890
916
  effect.pipe(
891
- Effect.forkIn(this.effectContext.lifetimeScope),
917
+ Effect.forkIn(this[StoreInternalsSymbol].effectContext.lifetimeScope),
892
918
  Effect.tapCauseLogPretty,
893
- Runtime.runFork(this.effectContext.runtime),
919
+ Runtime.runFork(this[StoreInternalsSymbol].effectContext.runtime),
894
920
  )
895
921
 
896
922
  private runEffectPromise = <A, E>(effect: Effect.Effect<A, E, Scope.Scope>) =>
897
- effect.pipe(Effect.tapCauseLogPretty, Runtime.runPromise(this.effectContext.runtime))
923
+ effect.pipe(Effect.tapCauseLogPretty, Runtime.runPromise(this[StoreInternalsSymbol].effectContext.runtime))
898
924
 
899
925
  private getCommitArgs = (
900
926
  firstEventOrTxnFnOrOptions: any,
@@ -926,7 +952,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
926
952
 
927
953
  // for (const event of events) {
928
954
  // if (event.args.id === SessionIdSymbol) {
929
- // event.args.id = this.clientSession.sessionId
955
+ // event.args.id = this.sessionId
930
956
  // }
931
957
  // }
932
958