@livestore/livestore 0.4.0-dev.9 → 0.4.0

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 (129) hide show
  1. package/README.md +0 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/QueryCache.js +1 -1
  4. package/dist/QueryCache.js.map +1 -1
  5. package/dist/SqliteDbWrapper.d.ts +5 -5
  6. package/dist/SqliteDbWrapper.d.ts.map +1 -1
  7. package/dist/SqliteDbWrapper.js +8 -8
  8. package/dist/SqliteDbWrapper.js.map +1 -1
  9. package/dist/SqliteDbWrapper.test.js +4 -3
  10. package/dist/SqliteDbWrapper.test.js.map +1 -1
  11. package/dist/effect/LiveStore.d.ts +133 -5
  12. package/dist/effect/LiveStore.d.ts.map +1 -1
  13. package/dist/effect/LiveStore.js +187 -8
  14. package/dist/effect/LiveStore.js.map +1 -1
  15. package/dist/effect/LiveStore.test.d.ts +2 -0
  16. package/dist/effect/LiveStore.test.d.ts.map +1 -0
  17. package/dist/effect/LiveStore.test.js +42 -0
  18. package/dist/effect/LiveStore.test.js.map +1 -0
  19. package/dist/effect/mod.d.ts +1 -1
  20. package/dist/effect/mod.d.ts.map +1 -1
  21. package/dist/effect/mod.js +3 -1
  22. package/dist/effect/mod.js.map +1 -1
  23. package/dist/live-queries/base-class.d.ts +110 -7
  24. package/dist/live-queries/base-class.d.ts.map +1 -1
  25. package/dist/live-queries/base-class.js +2 -2
  26. package/dist/live-queries/base-class.js.map +1 -1
  27. package/dist/live-queries/client-document-get-query.d.ts +1 -1
  28. package/dist/live-queries/client-document-get-query.d.ts.map +1 -1
  29. package/dist/live-queries/client-document-get-query.js +4 -3
  30. package/dist/live-queries/client-document-get-query.js.map +1 -1
  31. package/dist/live-queries/computed.d.ts +56 -0
  32. package/dist/live-queries/computed.d.ts.map +1 -1
  33. package/dist/live-queries/computed.js +58 -2
  34. package/dist/live-queries/computed.js.map +1 -1
  35. package/dist/live-queries/db-query.d.ts.map +1 -1
  36. package/dist/live-queries/db-query.js +21 -19
  37. package/dist/live-queries/db-query.js.map +1 -1
  38. package/dist/live-queries/db-query.test.js +106 -23
  39. package/dist/live-queries/db-query.test.js.map +1 -1
  40. package/dist/live-queries/signal.d.ts +49 -0
  41. package/dist/live-queries/signal.d.ts.map +1 -1
  42. package/dist/live-queries/signal.js +49 -0
  43. package/dist/live-queries/signal.js.map +1 -1
  44. package/dist/live-queries/signal.test.js +2 -2
  45. package/dist/live-queries/signal.test.js.map +1 -1
  46. package/dist/mod.d.ts +3 -3
  47. package/dist/mod.d.ts.map +1 -1
  48. package/dist/mod.js +3 -2
  49. package/dist/mod.js.map +1 -1
  50. package/dist/reactive.d.ts +9 -9
  51. package/dist/reactive.d.ts.map +1 -1
  52. package/dist/reactive.js +9 -26
  53. package/dist/reactive.js.map +1 -1
  54. package/dist/reactive.test.js +2 -2
  55. package/dist/reactive.test.js.map +1 -1
  56. package/dist/store/StoreRegistry.d.ts +215 -0
  57. package/dist/store/StoreRegistry.d.ts.map +1 -0
  58. package/dist/store/StoreRegistry.js +267 -0
  59. package/dist/store/StoreRegistry.js.map +1 -0
  60. package/dist/store/StoreRegistry.test.d.ts +2 -0
  61. package/dist/store/StoreRegistry.test.d.ts.map +1 -0
  62. package/dist/store/StoreRegistry.test.js +381 -0
  63. package/dist/store/StoreRegistry.test.js.map +1 -0
  64. package/dist/store/create-store.d.ts +98 -18
  65. package/dist/store/create-store.d.ts.map +1 -1
  66. package/dist/store/create-store.js +49 -20
  67. package/dist/store/create-store.js.map +1 -1
  68. package/dist/store/devtools.d.ts +5 -16
  69. package/dist/store/devtools.d.ts.map +1 -1
  70. package/dist/store/devtools.js +59 -18
  71. package/dist/store/devtools.js.map +1 -1
  72. package/dist/store/store-eventstream.test.d.ts +2 -0
  73. package/dist/store/store-eventstream.test.d.ts.map +1 -0
  74. package/dist/store/store-eventstream.test.js +65 -0
  75. package/dist/store/store-eventstream.test.js.map +1 -0
  76. package/dist/store/store-types.d.ts +285 -27
  77. package/dist/store/store-types.d.ts.map +1 -1
  78. package/dist/store/store-types.js +77 -1
  79. package/dist/store/store-types.js.map +1 -1
  80. package/dist/store/store-types.test.d.ts +2 -0
  81. package/dist/store/store-types.test.d.ts.map +1 -0
  82. package/dist/store/store-types.test.js +39 -0
  83. package/dist/store/store-types.test.js.map +1 -0
  84. package/dist/store/store.d.ts +253 -66
  85. package/dist/store/store.d.ts.map +1 -1
  86. package/dist/store/store.js +442 -153
  87. package/dist/store/store.js.map +1 -1
  88. package/dist/utils/dev.d.ts.map +1 -1
  89. package/dist/utils/dev.js.map +1 -1
  90. package/dist/utils/stack-info.js +2 -2
  91. package/dist/utils/stack-info.js.map +1 -1
  92. package/dist/utils/tests/fixture.d.ts +20 -5
  93. package/dist/utils/tests/fixture.d.ts.map +1 -1
  94. package/dist/utils/tests/fixture.js +7 -0
  95. package/dist/utils/tests/fixture.js.map +1 -1
  96. package/dist/utils/tests/otel.d.ts.map +1 -1
  97. package/dist/utils/tests/otel.js +5 -5
  98. package/dist/utils/tests/otel.js.map +1 -1
  99. package/package.json +59 -17
  100. package/src/QueryCache.ts +1 -1
  101. package/src/SqliteDbWrapper.test.ts +5 -3
  102. package/src/SqliteDbWrapper.ts +12 -11
  103. package/src/ambient.d.ts +0 -7
  104. package/src/effect/LiveStore.test.ts +61 -0
  105. package/src/effect/LiveStore.ts +388 -13
  106. package/src/effect/mod.ts +13 -1
  107. package/src/live-queries/__snapshots__/db-query.test.ts.snap +604 -192
  108. package/src/live-queries/base-class.ts +126 -28
  109. package/src/live-queries/client-document-get-query.ts +6 -4
  110. package/src/live-queries/computed.ts +59 -2
  111. package/src/live-queries/db-query.test.ts +162 -24
  112. package/src/live-queries/db-query.ts +23 -20
  113. package/src/live-queries/signal.test.ts +3 -2
  114. package/src/live-queries/signal.ts +49 -0
  115. package/src/mod.ts +19 -2
  116. package/src/reactive.test.ts +3 -2
  117. package/src/reactive.ts +22 -23
  118. package/src/store/StoreRegistry.test.ts +540 -0
  119. package/src/store/StoreRegistry.ts +418 -0
  120. package/src/store/create-store.ts +158 -39
  121. package/src/store/devtools.ts +77 -33
  122. package/src/store/store-eventstream.test.ts +114 -0
  123. package/src/store/store-types.test.ts +52 -0
  124. package/src/store/store-types.ts +360 -40
  125. package/src/store/store.ts +571 -236
  126. package/src/utils/dev.ts +2 -3
  127. package/src/utils/stack-info.ts +2 -2
  128. package/src/utils/tests/fixture.ts +9 -1
  129. package/src/utils/tests/otel.ts +8 -7
@@ -7,15 +7,16 @@ import {
7
7
  QueryBuilderAstSymbol,
8
8
  replaceSessionIdSymbol,
9
9
  SessionIdSymbol,
10
- UnexpectedError,
10
+ UnknownError,
11
11
  } from '@livestore/common'
12
- import { deepEqual, omitUndefineds, shouldNeverHappen } from '@livestore/utils'
12
+ import { deepEqual, objectToString, omitUndefineds, shouldNeverHappen } from '@livestore/utils'
13
13
  import { Equal, Hash, Predicate, Schema, TreeFormatter } from '@livestore/utils/effect'
14
14
  import * as otel from '@opentelemetry/api'
15
15
 
16
16
  import type { Thunk } from '../reactive.ts'
17
17
  import { isThunk, NOT_REFRESHED_YET } from '../reactive.ts'
18
18
  import type { RefreshReason } from '../store/store-types.ts'
19
+ import { StoreInternalsSymbol } from '../store/store-types.ts'
19
20
  import { isValidFunctionString } from '../utils/function-string.ts'
20
21
  import type { DepKey, GetAtomResult, LiveQueryDef, ReactivityGraph, ReactivityGraphContext } from './base-class.ts'
21
22
  import { depsToString, LiveStoreQueryBase, makeGetAtomResult, withRCMap } from './base-class.ts'
@@ -102,7 +103,7 @@ export const queryDb: {
102
103
  } = (queryInput, options) => {
103
104
  const { queryString, extraDeps } = getQueryStringAndExtraDeps(queryInput)
104
105
 
105
- const hash = [queryString, options?.deps ? depsToString(options.deps) : undefined, depsToString(extraDeps)]
106
+ const hash = [queryString, options?.deps !== undefined ? depsToString(options.deps) : undefined, depsToString(extraDeps)]
106
107
  .filter(Boolean)
107
108
  .join('-')
108
109
 
@@ -111,7 +112,7 @@ export const queryDb: {
111
112
  }
112
113
 
113
114
  if (hash.trim() === '') {
114
- return shouldNeverHappen(`Invalid query hash for query: ${queryInput}`)
115
+ return shouldNeverHappen('Invalid query hash for query:', objectToString(queryInput))
115
116
  }
116
117
 
117
118
  const label = options?.label ?? queryString
@@ -154,12 +155,12 @@ const bindValuesToDepKey = (bindValues: Bindable | undefined): DepKey => {
154
155
  const getQueryStringAndExtraDeps = (
155
156
  queryInput: QueryInput<any, any> | ((get: GetAtomResult) => QueryInput<any, any>),
156
157
  ): { queryString: string; extraDeps: DepKey } => {
157
- if (isQueryBuilder(queryInput)) {
158
+ if (isQueryBuilder(queryInput) === true) {
158
159
  const { query, bindValues } = queryInput.asSql()
159
160
  return { queryString: query, extraDeps: bindValuesToDepKey(bindValues) }
160
161
  }
161
162
 
162
- if (isQueryInputRaw(queryInput)) {
163
+ if (isQueryInputRaw(queryInput) === true) {
163
164
  return { queryString: queryInput.query, extraDeps: bindValuesToDepKey(queryInput.bindValues) }
164
165
  }
165
166
 
@@ -167,7 +168,7 @@ const getQueryStringAndExtraDeps = (
167
168
  return { queryString: queryInput.toString(), extraDeps: [] }
168
169
  }
169
170
 
170
- return shouldNeverHappen(`Invalid query input: ${queryInput}`)
171
+ return shouldNeverHappen(`Invalid query input: ${String(queryInput)}`)
171
172
  }
172
173
 
173
174
  /* An object encapsulating a reactive SQL query */
@@ -215,7 +216,7 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
215
216
 
216
217
  const schemaRef: { current: Schema.Schema<any, any> | undefined } = {
217
218
  current:
218
- typeof queryInput === 'function' ? undefined : isQueryBuilder(queryInput) ? undefined : queryInput.schema,
219
+ typeof queryInput === 'function' ? undefined : isQueryBuilder(queryInput) === true ? undefined : queryInput.schema,
219
220
  }
220
221
 
221
222
  const execBeforeFirstRunRef: {
@@ -253,7 +254,7 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
253
254
  : undefined,
254
255
  }
255
256
  } catch (cause) {
256
- throw new UnexpectedError({ cause, note: `Error building query for ${qb.toString()}`, payload: { qb } })
257
+ throw new UnknownError({ cause, note: `Error building query for ${qb.toString()}`, payload: { qb } })
257
258
  }
258
259
  }
259
260
 
@@ -269,7 +270,7 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
269
270
 
270
271
  let queryInputRaw: TQueryInputRaw
271
272
 
272
- if (isQueryBuilder(queryInputResult)) {
273
+ if (isQueryBuilder(queryInputResult) === true) {
273
274
  const res = fromQueryBuilder(queryInputResult, otelContext)
274
275
  queryInputRaw = res.queryInputRaw
275
276
  // setting label dynamically here
@@ -296,7 +297,7 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
296
297
  this.queryInput$ = queryInputRaw$OrQueryInputRaw
297
298
  } else {
298
299
  let queryInputRaw: TQueryInputRaw
299
- if (isQueryBuilder(queryInput)) {
300
+ if (isQueryBuilder(queryInput) === true) {
300
301
  const res = fromQueryBuilder(queryInput, otelContext)
301
302
  queryInputRaw = res.queryInputRaw
302
303
  label = res.label
@@ -309,7 +310,7 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
309
310
  queryInputRaw$OrQueryInputRaw = queryInputRaw
310
311
 
311
312
  // this.label = inputLabel ? this.label : `db(${})`
312
- if (inputLabel === undefined && isQueryBuilder(queryInput)) {
313
+ if (inputLabel === undefined && isQueryBuilder(queryInput) === true) {
313
314
  const ast = queryInput[QueryBuilderAstSymbol]
314
315
  if (ast._tag === 'RowQuery') {
315
316
  label = `db(${rowQueryLabel(ast.tableDef, ast.id)})`
@@ -341,7 +342,7 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
341
342
  'db:...', // NOTE span name will be overridden further down
342
343
  {
343
344
  attributes: {
344
- 'livestore.debugRefreshReason': Predicate.hasProperty(debugRefreshReason, 'label')
345
+ 'livestore.debugRefreshReason': Predicate.hasProperty(debugRefreshReason, 'label') === true
345
346
  ? (debugRefreshReason.label as string)
346
347
  : debugRefreshReason?._tag,
347
348
  },
@@ -356,7 +357,7 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
356
357
  execBeforeFirstRunRef.current = undefined
357
358
  }
358
359
 
359
- const queryInputResult = isThunk(queryInputRaw$OrQueryInputRaw)
360
+ const queryInputResult = isThunk(queryInputRaw$OrQueryInputRaw) === true
360
361
  ? (get(queryInputRaw$OrQueryInputRaw, otelContext, debugRefreshReason) as TQueryInputRaw)
361
362
  : (queryInputRaw$OrQueryInputRaw as TQueryInputRaw)
362
363
 
@@ -364,28 +365,30 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
364
365
  const bindValues = queryInputResult.bindValues
365
366
 
366
367
  if (queriedTablesRef.current === undefined) {
367
- queriedTablesRef.current = store.sqliteDbWrapper.getTablesUsed(sqlString)
368
+ queriedTablesRef.current = store[StoreInternalsSymbol].sqliteDbWrapper.getTablesUsed(sqlString)
368
369
  }
369
370
 
370
371
  if (bindValues !== undefined) {
371
- replaceSessionIdSymbol(bindValues, store.clientSession.sessionId)
372
+ replaceSessionIdSymbol(bindValues, store.sessionId)
372
373
  }
373
374
 
374
375
  // Establish a reactive dependency on the tables used in the query
375
376
  for (const tableName of queriedTablesRef.current) {
376
- const tableRef = store.tableRefs[tableName] ?? shouldNeverHappen(`No table ref found for ${tableName}`)
377
+ const tableRef =
378
+ store[StoreInternalsSymbol].tableRefs[tableName] ??
379
+ shouldNeverHappen(`No table ref found for ${tableName}`)
377
380
  get(tableRef, otelContext, debugRefreshReason)
378
381
  }
379
382
 
380
383
  span.setAttribute('sql.query', sqlString)
381
384
  span.updateName(`db:${sqlString.slice(0, 50)}`)
382
385
 
383
- const rawDbResults = store.sqliteDbWrapper.cachedSelect<any>(
386
+ const rawDbResults = store[StoreInternalsSymbol].sqliteDbWrapper.cachedSelect(
384
387
  sqlString,
385
- bindValues ? prepareBindValues(bindValues, sqlString) : undefined,
388
+ bindValues !== undefined ? prepareBindValues(bindValues, sqlString) : undefined,
386
389
  {
387
- queriedTables: queriedTablesRef.current,
388
390
  otelContext,
391
+ ...(queriedTablesRef.current !== undefined ? { queriedTables: queriedTablesRef.current } : {}),
389
392
  },
390
393
  )
391
394
 
@@ -1,7 +1,8 @@
1
- import { Effect } from '@livestore/utils/effect'
2
- import { Vitest } from '@livestore/utils-dev/node-vitest'
3
1
  import { expect } from 'vitest'
4
2
 
3
+ import { Vitest } from '@livestore/utils-dev/node-vitest'
4
+ import { Effect } from '@livestore/utils/effect'
5
+
5
6
  import { makeTodoMvc } from '../utils/tests/fixture.ts'
6
7
  import { computed } from './computed.ts'
7
8
  import { signal } from './signal.ts'
@@ -6,6 +6,48 @@ import type { RefreshReason } from '../store/store-types.ts'
6
6
  import type { ISignal, ReactivityGraph, ReactivityGraphContext, SignalDef } from './base-class.ts'
7
7
  import { LiveStoreQueryBase, withRCMap } from './base-class.ts'
8
8
 
9
+ /**
10
+ * Creates a reactive signal for ephemeral, local-only state that isn't persisted to the database.
11
+ *
12
+ * Signals are useful for UI state that needs to trigger query re-evaluation but shouldn't be
13
+ * synced across clients or stored permanently—such as search filters, selected items, or
14
+ * temporary form values.
15
+ *
16
+ * Unlike database-backed state (via events), signals:
17
+ * - Are not persisted or synced
18
+ * - Exist only for the lifetime of the Store
19
+ * - Can hold any value type (primitives, objects, functions)
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * // Create a signal for search text
24
+ * const searchText$ = signal('', { label: 'searchText' })
25
+ *
26
+ * // Create a query that depends on the signal
27
+ * const filteredTodos$ = queryDb(
28
+ * (get) => tables.todos.where({ text: { $like: `%${get(searchText$)}%` } }),
29
+ * { deps: [searchText$] }
30
+ * )
31
+ *
32
+ * // Update the signal (triggers query re-evaluation)
33
+ * store.setSignal(searchText$, 'buy')
34
+ *
35
+ * // Read the current value
36
+ * const results = store.query(filteredTodos$)
37
+ * ```
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * // Counter with functional updates
42
+ * const count$ = signal(0, { label: 'count' })
43
+ *
44
+ * store.setSignal(count$, (prev) => prev + 1)
45
+ * ```
46
+ *
47
+ * @param defaultValue - Initial value of the signal
48
+ * @param options.label - Human-readable label for debugging and devtools
49
+ * @returns A signal definition that can be used with `store.query()`, `store.setSignal()`, and as a dependency in other queries
50
+ */
9
51
  export const signal = <T>(
10
52
  defaultValue: T,
11
53
  options?: {
@@ -39,6 +81,13 @@ export const signal = <T>(
39
81
  return def
40
82
  }
41
83
 
84
+ /**
85
+ * A live signal instance bound to a specific Store.
86
+ *
87
+ * Signal instances are created internally when you use a `SignalDef` with the Store.
88
+ * You typically don't construct these directly—use {@link signal} to create definitions
89
+ * and `store.setSignal()` / `store.query()` to interact with them.
90
+ */
42
91
  export class Signal<T> extends LiveStoreQueryBase<T> implements ISignal<T> {
43
92
  _tag = 'signal' as const
44
93
  readonly ref: RG.Ref<T, ReactivityGraphContext, RefreshReason>
package/src/mod.ts CHANGED
@@ -35,14 +35,31 @@ export {
35
35
  signal,
36
36
  } from './live-queries/mod.ts'
37
37
  export { emptyDebugInfo, SqliteDbWrapper } from './SqliteDbWrapper.ts'
38
- export { type CreateStoreOptions, createStore, createStorePromise } from './store/create-store.ts'
38
+ export {
39
+ type CreateStoreOptions,
40
+ type CreateStoreOptionsPromise,
41
+ createStore,
42
+ createStorePromise,
43
+ } from './store/create-store.ts'
44
+ export { type RegistryStoreOptions, StoreRegistry, storeOptions } from './store/StoreRegistry.ts'
39
45
  export { Store } from './store/store.ts'
40
- export type { OtelOptions, QueryDebugInfo, RefreshReason, Unsubscribe } from './store/store-types.ts'
41
46
  export {
47
+ isLiveQueryDef,
48
+ isLiveQueryInstance,
49
+ isQueryable,
42
50
  type LiveStoreContext,
43
51
  type LiveStoreContextRunning,
44
52
  makeShutdownDeferred,
53
+ type OtelOptions,
54
+ type Queryable,
55
+ type QueryDebugInfo,
56
+ type RefreshReason,
45
57
  type ShutdownDeferred,
58
+ type StoreInternals,
59
+ StoreInternalsSymbol,
60
+ type SubscribeOptions,
61
+ type SyncStatus,
62
+ type Unsubscribe,
46
63
  } from './store/store-types.ts'
47
64
  export { exposeDebugUtils } from './utils/dev.ts'
48
65
  export * from './utils/stack-info.ts'
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest'
2
+
2
3
  import type { DebugRefreshReasonBase, DebugThunkInfo } from './reactive.ts'
3
4
  import { ReactiveGraph } from './reactive.ts'
4
5
 
@@ -142,7 +143,7 @@ describe('a trivial graph', () => {
142
143
  expect(numberOfEffectRuns).toBe(0)
143
144
  const effect = graph.makeEffect((get) => {
144
145
  // establish a dependency on thunk c and mutate an outside value
145
- expect(get(c)).toBe(aHasChanged ? 3 : 4)
146
+ expect(get(c)).toBe(aHasChanged === true ? 3 : 4)
146
147
  numberOfEffectRuns++
147
148
  })
148
149
 
@@ -562,7 +563,7 @@ describe('bug fix: node corruption protection', () => {
562
563
 
563
564
  let firstRun = true
564
565
  const effect = graph.makeEffect((get) => {
565
- if (firstRun) {
566
+ if (firstRun !== undefined) {
566
567
  firstRun = false
567
568
  graph.destroyNode(thunk1) // Destroy dependency mid-execution
568
569
  }
package/src/reactive.ts CHANGED
@@ -21,10 +21,11 @@
21
21
  // is maintained eagerly as edges are added and removed.)
22
22
  // - At every thunk we check value equality with the previous value and cutoff propagation if possible.
23
23
 
24
+ import type * as otel from '@opentelemetry/api'
25
+
24
26
  import { BoundArray } from '@livestore/common'
25
27
  import { deepEqual, omitUndefineds, shouldNeverHappen } from '@livestore/utils'
26
28
  import type { Types } from '@livestore/utils/effect'
27
- import type * as otel from '@opentelemetry/api'
28
29
  // import { getDurationMsFromSpan } from './otel.ts'
29
30
 
30
31
  export const NOT_REFRESHED_YET = Symbol.for('NOT_REFRESHED_YET')
@@ -32,8 +33,8 @@ export type NOT_REFRESHED_YET = typeof NOT_REFRESHED_YET
32
33
 
33
34
  export type GetAtom = <T>(
34
35
  atom: Atom<T, any, any>,
35
- otelContext?: otel.Context | undefined,
36
- debugRefreshReason?: TODO | undefined,
36
+ otelContext?: otel.Context ,
37
+ debugRefreshReason?: TODO ,
37
38
  ) => T
38
39
 
39
40
  export type Ref<T, TContext, TDebugRefreshReason extends DebugRefreshReason> = {
@@ -47,7 +48,7 @@ export type Ref<T, TContext, TDebugRefreshReason extends DebugRefreshReason> = {
47
48
  super: Set<Thunk<any, TContext, TDebugRefreshReason> | Effect<TDebugRefreshReason>>
48
49
  label?: string | undefined
49
50
  /** Container for meta information (e.g. the LiveStore Store) */
50
- meta?: any | undefined
51
+ meta?: unknown
51
52
  equal: (a: T, b: T) => boolean
52
53
  refreshes: number
53
54
  }
@@ -63,7 +64,7 @@ export type Thunk<TResult, TContext, TDebugRefreshReason extends DebugRefreshRea
63
64
  super: Set<Thunk<any, TContext, TDebugRefreshReason> | Effect<TDebugRefreshReason>>
64
65
  label?: string | undefined
65
66
  /** Container for meta information (e.g. the LiveStore Store) */
66
- meta?: any | undefined
67
+ meta?: unknown
67
68
  equal: (a: TResult, b: TResult) => boolean
68
69
  recomputations: number
69
70
 
@@ -78,7 +79,7 @@ export type Effect<TDebugRefreshReason extends DebugRefreshReason> = {
78
79
  _tag: 'effect'
79
80
  id: string
80
81
  isDestroyed: boolean
81
- doEffect: (otelContext?: otel.Context | undefined, debugRefreshReason?: TDebugRefreshReason | undefined) => void
82
+ doEffect: (otelContext?: otel.Context , debugRefreshReason?: TDebugRefreshReason ) => void
82
83
  sub: Set<Atom<any, TODO, TODO>>
83
84
  label?: string | undefined
84
85
  invocations: number
@@ -91,7 +92,7 @@ export type Node<T, TContext, TDebugRefreshReason extends DebugRefreshReason> =
91
92
  export const isThunk = <T, TContext, TDebugRefreshReason extends DebugRefreshReason>(
92
93
  obj: unknown,
93
94
  ): obj is Thunk<T, TContext, TDebugRefreshReason> => {
94
- return typeof obj === 'object' && obj !== null && '_tag' in obj && (obj as any)._tag === 'thunk'
95
+ return typeof obj === 'object' && obj !== null && '_tag' in obj && (obj as { _tag: unknown })._tag === 'thunk'
95
96
  }
96
97
 
97
98
  export type DebugThunkInfo<T extends string = string> = {
@@ -203,9 +204,7 @@ export class ReactiveGraph<
203
204
 
204
205
  debugRefreshInfos: BoundArray<RefreshDebugInfo<TDebugRefreshReason, TDebugThunkInfo>> = new BoundArray(200)
205
206
 
206
- private currentDebugRefresh:
207
- | { refreshedAtoms: AtomDebugInfo<TDebugThunkInfo>[]; startMs: DOMHighResTimeStamp }
208
- | undefined
207
+ private currentDebugRefresh: { refreshedAtoms: AtomDebugInfo<TDebugThunkInfo>[]; startMs: number } | undefined
209
208
 
210
209
  private deferredEffects: Map<Effect<TDebugRefreshReason>, Set<TDebugRefreshReason>> = new Map()
211
210
 
@@ -253,7 +252,7 @@ export class ReactiveGraph<
253
252
  meta?: any
254
253
  equal?: (a: T, b: T) => boolean
255
254
  }
256
- | undefined,
255
+ ,
257
256
  ): Thunk<T, TContext, TDebugRefreshReason> {
258
257
  const thunk: Thunk<T, TContext, TDebugRefreshReason> = {
259
258
  _tag: 'thunk',
@@ -262,10 +261,10 @@ export class ReactiveGraph<
262
261
  isDirty: true,
263
262
  isDestroyed: false,
264
263
  computeResult: (otelContext, debugRefreshReason) => {
265
- if (thunk.isDirty) {
264
+ if (thunk.isDirty === true) {
266
265
  const neededCurrentRefresh = this.currentDebugRefresh === undefined
267
266
  let localDebugRefresh: { refreshedAtoms: any[]; startMs: number } | undefined
268
- if (neededCurrentRefresh) {
267
+ if (neededCurrentRefresh === true) {
269
268
  // Use local variable to prevent corruption from nested computations
270
269
  localDebugRefresh = { refreshedAtoms: [], startMs: performance.now() }
271
270
  this.currentDebugRefresh = localDebugRefresh
@@ -292,7 +291,7 @@ export class ReactiveGraph<
292
291
  debugRefreshReason,
293
292
  )
294
293
 
295
- const resultChanged = thunk.equal(thunk.previousResult as T, result) === false
294
+ const resultChanged = ! thunk.equal(thunk.previousResult as T, result)
296
295
 
297
296
  const debugInfoForAtom = {
298
297
  atom: serializeAtom(thunk, false),
@@ -302,7 +301,7 @@ export class ReactiveGraph<
302
301
 
303
302
  // Use currentDebugRefresh if available (could be from parent or local)
304
303
  const debugRefresh = localDebugRefresh ?? this.currentDebugRefresh
305
- if (debugRefresh) {
304
+ if (debugRefresh !== undefined) {
306
305
  debugRefresh.refreshedAtoms.push(debugInfoForAtom)
307
306
  }
308
307
 
@@ -310,7 +309,7 @@ export class ReactiveGraph<
310
309
  thunk.previousResult = result
311
310
  thunk.recomputations++
312
311
 
313
- if (neededCurrentRefresh && localDebugRefresh) {
312
+ if (neededCurrentRefresh === true && localDebugRefresh !== undefined) {
314
313
  // Use local reference which can't be corrupted by nested calls
315
314
  const refreshedAtoms = localDebugRefresh.refreshedAtoms
316
315
  const durationMs = performance.now() - localDebugRefresh.startMs
@@ -385,7 +384,7 @@ export class ReactiveGraph<
385
384
  otelContext: otel.Context | undefined,
386
385
  debugRefreshReason: DebugRefreshReason | undefined,
387
386
  ) => void,
388
- options?: { label?: string } | undefined,
387
+ options?: { label?: string } ,
389
388
  ): Effect<TDebugRefreshReason> {
390
389
  const effect: Effect<TDebugRefreshReason> = {
391
390
  _tag: 'effect',
@@ -429,7 +428,7 @@ export class ReactiveGraph<
429
428
  debugRefreshReason?: TDebugRefreshReason
430
429
  otelContext?: otel.Context
431
430
  }
432
- | undefined,
431
+ ,
433
432
  ) {
434
433
  this.setRefs([[ref, val]], options)
435
434
  }
@@ -442,7 +441,7 @@ export class ReactiveGraph<
442
441
  debugRefreshReason?: TDebugRefreshReason
443
442
  otelContext?: otel.Context
444
443
  }
445
- | undefined,
444
+ ,
446
445
  ) {
447
446
  const effectsToRefresh = new Set<Effect<TDebugRefreshReason>>()
448
447
  for (const [ref, val] of refs) {
@@ -452,7 +451,7 @@ export class ReactiveGraph<
452
451
  markSuperCompDirtyRec(ref, effectsToRefresh)
453
452
  }
454
453
 
455
- if (options?.skipRefresh) {
454
+ if (options?.skipRefresh === true) {
456
455
  for (const effect of effectsToRefresh) {
457
456
  if (this.deferredEffects.has(effect) === false) {
458
457
  this.deferredEffects.set(effect, new Set())
@@ -598,11 +597,11 @@ const compute = <T>(
598
597
  debugRefreshReason: DebugRefreshReason | undefined,
599
598
  ): T => {
600
599
  // const __getResult = atom._tag === 'thunk' ? atom.__getResult.toString() : ''
601
- if (atom.isDestroyed) {
600
+ if (atom.isDestroyed === true) {
602
601
  shouldNeverHappen(`LiveStore Error: Attempted to compute destroyed ${atom._tag} (${atom.id}): ${atom.label ?? ''}`)
603
602
  }
604
603
 
605
- if (atom.isDirty) {
604
+ if (atom.isDirty === true) {
606
605
  // console.log('atom is dirty', atom.id, atom.label ?? '', atom._tag, __getResult)
607
606
  const result = atom.computeResult(otelContext, debugRefreshReason)
608
607
  atom.isDirty = false
@@ -641,7 +640,7 @@ const serializeAtom = (atom: Atom<any, unknown, any>, includeResult: boolean): S
641
640
  super_.push(a.id)
642
641
  }
643
642
 
644
- const previousResult: EncodedOption<string> = includeResult
643
+ const previousResult: EncodedOption<string> = includeResult === true
645
644
  ? encodedOptionSome(
646
645
  atom.previousResult === NOT_REFRESHED_YET ? '"SYMBOL_NOT_REFRESHED_YET"' : JSON.stringify(atom.previousResult),
647
646
  )