@livestore/livestore 0.3.0-dev.4 → 0.3.0-dev.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/live-queries/db.js +1 -1
- package/dist/live-queries/db.js.map +1 -1
- package/dist/row-query-utils.d.ts.map +1 -1
- package/dist/row-query-utils.js +0 -1
- package/dist/row-query-utils.js.map +1 -1
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +1 -1
- package/dist/store/create-store.js.map +1 -1
- package/dist/store/devtools.d.ts.map +1 -1
- package/dist/store/devtools.js +13 -9
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-types.d.ts +1 -1
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store.d.ts +1 -7
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +15 -75
- package/dist/store/store.js.map +1 -1
- package/package.json +5 -5
- package/src/live-queries/db.ts +1 -1
- package/src/row-query-utils.ts +0 -1
- package/src/store/create-store.ts +5 -1
- package/src/store/devtools.ts +14 -10
- package/src/store/store-types.ts +1 -1
- package/src/store/store.ts +18 -90
package/src/row-query-utils.ts
CHANGED
@@ -61,6 +61,5 @@ export const makeExecBeforeFirstRun =
|
|
61
61
|
|
62
62
|
// NOTE It's important that we only mutate and don't refresh here, as this function is called during a render
|
63
63
|
store.mutate({ otelContext, skipRefresh: true }, table.insert({ id, ...insertValues }))
|
64
|
-
// store.mutateWithoutRefresh(table.insert({ id, ...insertValues }), { otelContext, coordinatorMode: 'default' })
|
65
64
|
}
|
66
65
|
}
|
@@ -140,9 +140,13 @@ export const createStore = <
|
|
140
140
|
|
141
141
|
const shutdown = (cause: Cause.Cause<UnexpectedError | IntentionalShutdownCause>) =>
|
142
142
|
Scope.close(lifetimeScope, Exit.failCause(cause)).pipe(
|
143
|
+
Effect.logWarnIfTakesLongerThan({ label: '@livestore/livestore:shutdown', duration: 500 }),
|
144
|
+
Effect.timeout(1000),
|
145
|
+
Effect.catchTag('TimeoutException', () =>
|
146
|
+
Effect.logError('@livestore/livestore:shutdown: Timed out after 1 second'),
|
147
|
+
),
|
143
148
|
Effect.tap(() => (shutdownDeferred ? Deferred.failCause(shutdownDeferred, cause) : Effect.void)),
|
144
149
|
Effect.tap(() => Effect.logDebug('LiveStore shutdown complete')),
|
145
|
-
Effect.logWarnIfTakesLongerThan({ label: '@livestore/livestore:shutdown', duration: 500 }),
|
146
150
|
Effect.withSpan('livestore:shutdown'),
|
147
151
|
)
|
148
152
|
|
package/src/store/devtools.ts
CHANGED
@@ -38,12 +38,12 @@ export const connectDevtoolsToStore = ({
|
|
38
38
|
store: IStore
|
39
39
|
}) =>
|
40
40
|
Effect.gen(function* () {
|
41
|
-
const appHostId = store.clientSession.coordinator.devtools.appHostId
|
42
|
-
|
43
41
|
const reactivityGraphSubcriptions: SubMap = new Map()
|
44
42
|
const liveQueriesSubscriptions: SubMap = new Map()
|
45
43
|
const debugInfoHistorySubscriptions: SubMap = new Map()
|
46
44
|
|
45
|
+
const { clientId, sessionId } = store.clientSession
|
46
|
+
|
47
47
|
yield* Effect.addFinalizer(() =>
|
48
48
|
Effect.sync(() => {
|
49
49
|
reactivityGraphSubcriptions.forEach((unsub) => unsub())
|
@@ -58,13 +58,13 @@ export const connectDevtoolsToStore = ({
|
|
58
58
|
const onMessage = (decodedMessage: typeof Devtools.MessageToAppClientSession.Type) => {
|
59
59
|
// console.debug('@livestore/livestore:store:devtools:onMessage', decodedMessage)
|
60
60
|
|
61
|
-
if (decodedMessage.
|
61
|
+
if (decodedMessage.clientId !== clientId || decodedMessage.sessionId !== sessionId) {
|
62
62
|
// console.log(`Unknown message`, event)
|
63
63
|
return
|
64
64
|
}
|
65
65
|
|
66
66
|
if (decodedMessage._tag === 'LSD.Disconnect') {
|
67
|
-
console.error('TODO handle disconnect properly in store')
|
67
|
+
// console.error('TODO handle disconnect properly in store')
|
68
68
|
return
|
69
69
|
}
|
70
70
|
|
@@ -85,7 +85,8 @@ export const connectDevtoolsToStore = ({
|
|
85
85
|
Devtools.ReactivityGraphRes.make({
|
86
86
|
reactivityGraph: store.reactivityGraph.getSnapshot({ includeResults }),
|
87
87
|
requestId,
|
88
|
-
|
88
|
+
clientId,
|
89
|
+
sessionId,
|
89
90
|
liveStoreVersion,
|
90
91
|
}),
|
91
92
|
),
|
@@ -108,7 +109,8 @@ export const connectDevtoolsToStore = ({
|
|
108
109
|
Devtools.DebugInfoRes.make({
|
109
110
|
debugInfo: store.syncDbWrapper.debugInfo,
|
110
111
|
requestId,
|
111
|
-
|
112
|
+
clientId,
|
113
|
+
sessionId,
|
112
114
|
liveStoreVersion,
|
113
115
|
}),
|
114
116
|
)
|
@@ -133,7 +135,8 @@ export const connectDevtoolsToStore = ({
|
|
133
135
|
Devtools.DebugInfoHistoryRes.make({
|
134
136
|
debugInfoHistory: buffer,
|
135
137
|
requestId,
|
136
|
-
|
138
|
+
clientId,
|
139
|
+
sessionId,
|
137
140
|
liveStoreVersion,
|
138
141
|
}),
|
139
142
|
)
|
@@ -168,13 +171,13 @@ export const connectDevtoolsToStore = ({
|
|
168
171
|
}
|
169
172
|
case 'LSD.DebugInfoResetReq': {
|
170
173
|
store.syncDbWrapper.debugInfo.slowQueries.clear()
|
171
|
-
sendToDevtools(Devtools.DebugInfoResetRes.make({ requestId,
|
174
|
+
sendToDevtools(Devtools.DebugInfoResetRes.make({ requestId, clientId, sessionId, liveStoreVersion }))
|
172
175
|
break
|
173
176
|
}
|
174
177
|
case 'LSD.DebugInfoRerunQueryReq': {
|
175
178
|
const { queryStr, bindValues, queriedTables } = decodedMessage
|
176
179
|
store.syncDbWrapper.select(queryStr, { bindValues, queriedTables, skipCache: true })
|
177
|
-
sendToDevtools(Devtools.DebugInfoRerunQueryRes.make({ requestId,
|
180
|
+
sendToDevtools(Devtools.DebugInfoRerunQueryRes.make({ requestId, clientId, sessionId, liveStoreVersion }))
|
178
181
|
break
|
179
182
|
}
|
180
183
|
case 'LSD.ReactivityGraphUnsubscribe': {
|
@@ -203,7 +206,8 @@ export const connectDevtoolsToStore = ({
|
|
203
206
|
})),
|
204
207
|
requestId,
|
205
208
|
liveStoreVersion,
|
206
|
-
|
209
|
+
clientId,
|
210
|
+
sessionId,
|
207
211
|
}),
|
208
212
|
),
|
209
213
|
{ timeout: 500 },
|
package/src/store/store-types.ts
CHANGED
@@ -75,7 +75,7 @@ export type RefreshReason =
|
|
75
75
|
| {
|
76
76
|
_tag: 'mutate'
|
77
77
|
/** The mutations that were applied */
|
78
|
-
mutations: ReadonlyArray<MutationEvent.
|
78
|
+
mutations: ReadonlyArray<MutationEvent.AnyDecoded | MutationEvent.PartialAny>
|
79
79
|
|
80
80
|
/** The tables that were written to by the event */
|
81
81
|
writeTables: ReadonlyArray<string>
|
package/src/store/store.ts
CHANGED
@@ -7,10 +7,12 @@ import type {
|
|
7
7
|
UnexpectedError,
|
8
8
|
} from '@livestore/common'
|
9
9
|
import {
|
10
|
+
Devtools,
|
10
11
|
getExecArgsFromMutation,
|
11
12
|
getResultSchema,
|
12
13
|
IntentionalShutdownCause,
|
13
14
|
isQueryBuilder,
|
15
|
+
liveStoreVersion,
|
14
16
|
makeClientSessionSyncProcessor,
|
15
17
|
prepareBindValues,
|
16
18
|
QueryBuilderAstSymbol,
|
@@ -26,6 +28,7 @@ import {
|
|
26
28
|
import { assertNever, isDevEnv } from '@livestore/utils'
|
27
29
|
import type { Scope } from '@livestore/utils/effect'
|
28
30
|
import { Cause, Data, Effect, Inspectable, MutableHashMap, Runtime, Schema } from '@livestore/utils/effect'
|
31
|
+
import { nanoid } from '@livestore/utils/nanoid'
|
29
32
|
import * as otel from '@opentelemetry/api'
|
30
33
|
import { type GraphQLSchema } from 'graphql'
|
31
34
|
|
@@ -101,15 +104,15 @@ export class Store<
|
|
101
104
|
|
102
105
|
this.syncProcessor = makeClientSessionSyncProcessor({
|
103
106
|
schema,
|
104
|
-
initialLeaderHead: clientSession.
|
107
|
+
initialLeaderHead: clientSession.leaderThread.mutations.initialMutationEventId,
|
105
108
|
// rebaseBehaviour: 'auto-rebase',
|
106
109
|
pushToLeader: (batch) =>
|
107
|
-
clientSession.
|
110
|
+
clientSession.leaderThread.mutations.push(batch).pipe(
|
108
111
|
// NOTE we don't want to shutdown in case of an invalid push error, since it will be retried
|
109
112
|
Effect.catchTag('InvalidPushError', Effect.ignoreLogged),
|
110
113
|
this.runEffectFork,
|
111
114
|
),
|
112
|
-
pullFromLeader: clientSession.
|
115
|
+
pullFromLeader: clientSession.leaderThread.mutations.pull,
|
113
116
|
applyMutation: (mutationEventDecoded, { otelContext, withChangeset }) => {
|
114
117
|
const mutationDef = schema.mutations.get(mutationEventDecoded.mutation)!
|
115
118
|
const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
|
@@ -204,11 +207,7 @@ export class Store<
|
|
204
207
|
|
205
208
|
if (graphQLOptions) {
|
206
209
|
this.graphQLSchema = graphQLOptions.schema
|
207
|
-
this.graphQLContext = graphQLOptions.makeContext(
|
208
|
-
this.syncDbWrapper,
|
209
|
-
this.otel.tracer,
|
210
|
-
clientSession.coordinator.sessionId,
|
211
|
-
)
|
210
|
+
this.graphQLContext = graphQLOptions.makeContext(this.syncDbWrapper, this.otel.tracer, clientSession.sessionId)
|
212
211
|
}
|
213
212
|
|
214
213
|
Effect.gen(this, function* () {
|
@@ -248,7 +247,7 @@ export class Store<
|
|
248
247
|
}
|
249
248
|
|
250
249
|
get sessionId(): string {
|
251
|
-
return this.clientSession.
|
250
|
+
return this.clientSession.sessionId
|
252
251
|
}
|
253
252
|
|
254
253
|
/**
|
@@ -363,7 +362,7 @@ export class Store<
|
|
363
362
|
const { mutationsEvents, options } = this.getMutateArgs(firstMutationOrTxnFnOrOptions, restMutations)
|
364
363
|
|
365
364
|
for (const mutationEvent of mutationsEvents) {
|
366
|
-
replaceSessionIdSymbol(mutationEvent.args, this.clientSession.
|
365
|
+
replaceSessionIdSymbol(mutationEvent.args, this.clientSession.sessionId)
|
367
366
|
}
|
368
367
|
|
369
368
|
if (mutationsEvents.length === 0) return
|
@@ -400,7 +399,7 @@ export class Store<
|
|
400
399
|
const applyMutations = () => this.syncProcessor.push(mutationsEvents, { otelContext })
|
401
400
|
|
402
401
|
if (mutationsEvents.length > 1) {
|
403
|
-
// TODO: what to do about
|
402
|
+
// TODO: what to do about leader transaction here?
|
404
403
|
return this.syncDbWrapper.txn(applyMutations)
|
405
404
|
} else {
|
406
405
|
return applyMutations()
|
@@ -464,79 +463,6 @@ export class Store<
|
|
464
463
|
)
|
465
464
|
}
|
466
465
|
|
467
|
-
// #region mutateWithoutRefresh
|
468
|
-
/**
|
469
|
-
* Apply a mutation to the store.
|
470
|
-
* Returns the tables that were affected by the event.
|
471
|
-
* This is an internal method that doesn't trigger a refresh;
|
472
|
-
* the caller must refresh queries after calling this method.
|
473
|
-
*/
|
474
|
-
// private mutateWithoutRefresh = (
|
475
|
-
// mutationEventDecoded: MutationEvent.ForSchema<TSchema> | MutationEvent.PartialForSchema<TSchema>,
|
476
|
-
// options: {
|
477
|
-
// otelContext: otel.Context
|
478
|
-
// },
|
479
|
-
// ): { writeTables: ReadonlySet<string>; durationMs: number } => {
|
480
|
-
// // const mutationDef =
|
481
|
-
// // this.schema.mutations.get(mutationEventDecoded.mutation) ??
|
482
|
-
// // shouldNeverHappen(`Unknown mutation type: ${mutationEventDecoded.mutation}`)
|
483
|
-
|
484
|
-
// // // const mutationEventDecoded: MutationEvent.ForSchema<TSchema> = isPartialMutationEvent(mutationEventDecoded_)
|
485
|
-
// // // ? { ...mutationEventDecoded_, ...nextMutationEventId() }
|
486
|
-
// // // : mutationEventDecoded_
|
487
|
-
|
488
|
-
// // // NOTE we also need this temporary workaround here since some code-paths use `mutateWithoutRefresh` directly
|
489
|
-
// // // e.g. the row-query functionality
|
490
|
-
// // if (Predicate.hasProperty(mutationEventDecoded, 'id')) {
|
491
|
-
// // if (MutableHashMap.has(this.unsyncedMutationEvents, Data.struct(mutationEventDecoded.id))) {
|
492
|
-
// // // NOTE this data should never be used
|
493
|
-
// // return { writeTables: new Set(), durationMs: 0 }
|
494
|
-
// // } else {
|
495
|
-
// // MutableHashMap.set(this.unsyncedMutationEvents, Data.struct(mutationEventDecoded.id), mutationEventDecoded)
|
496
|
-
// // }
|
497
|
-
// // }
|
498
|
-
|
499
|
-
// const { otelContext } = options
|
500
|
-
|
501
|
-
// return this.otel.tracer.startActiveSpan(
|
502
|
-
// 'LiveStore:mutateWithoutRefresh',
|
503
|
-
// {
|
504
|
-
// attributes: {
|
505
|
-
// 'livestore.mutation': mutationEventDecoded.mutation,
|
506
|
-
// // TODO(performance) add flag to disable this
|
507
|
-
// 'livestore.args': JSON.stringify(mutationEventDecoded.args, null, 2),
|
508
|
-
// },
|
509
|
-
// },
|
510
|
-
// otelContext,
|
511
|
-
// (span) => {
|
512
|
-
// const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
513
|
-
|
514
|
-
// const allWriteTables = new Set<string>()
|
515
|
-
// let durationMsTotal = 0
|
516
|
-
|
517
|
-
// replaceSessionIdSymbol(mutationEventDecoded.args, this.clientSession.coordinator.sessionId)
|
518
|
-
|
519
|
-
// const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
|
520
|
-
|
521
|
-
// for (const {
|
522
|
-
// statementSql,
|
523
|
-
// bindValues,
|
524
|
-
// writeTables = this.syncDbWrapper.getTablesUsed(statementSql),
|
525
|
-
// } of execArgsArr) {
|
526
|
-
// const { durationMs } = this.syncDbWrapper.execute(statementSql, bindValues, writeTables, { otelContext })
|
527
|
-
|
528
|
-
// durationMsTotal += durationMs
|
529
|
-
// writeTables.forEach((table) => allWriteTables.add(table))
|
530
|
-
// }
|
531
|
-
|
532
|
-
// span.end()
|
533
|
-
|
534
|
-
// return { writeTables: allWriteTables, durationMs: durationMsTotal }
|
535
|
-
// },
|
536
|
-
// )
|
537
|
-
// }
|
538
|
-
// #endregion mutateWithoutRefresh
|
539
|
-
|
540
466
|
private makeTableRef = (tableName: string) =>
|
541
467
|
this.reactivityGraph.makeRef(null, {
|
542
468
|
equal: () => false,
|
@@ -546,21 +472,23 @@ export class Store<
|
|
546
472
|
|
547
473
|
__devDownloadDb = (source: 'local' | 'leader' = 'local') => {
|
548
474
|
Effect.gen(this, function* () {
|
549
|
-
const data = source === 'local' ? this.syncDbWrapper.export() : yield* this.clientSession.
|
475
|
+
const data = source === 'local' ? this.syncDbWrapper.export() : yield* this.clientSession.leaderThread.export
|
550
476
|
downloadBlob(data, `livestore-${Date.now()}.db`)
|
551
477
|
}).pipe(this.runEffectFork)
|
552
478
|
}
|
553
479
|
|
554
480
|
__devDownloadMutationLogDb = () => {
|
555
481
|
Effect.gen(this, function* () {
|
556
|
-
const data = yield* this.clientSession.
|
482
|
+
const data = yield* this.clientSession.leaderThread.getMutationLogData
|
557
483
|
downloadBlob(data, `livestore-mutationlog-${Date.now()}.db`)
|
558
484
|
}).pipe(this.runEffectFork)
|
559
485
|
}
|
560
486
|
|
561
|
-
__devHardReset = () => {
|
487
|
+
__devHardReset = (mode: 'all-data' | 'only-app-db' = 'all-data') => {
|
562
488
|
Effect.gen(this, function* () {
|
563
|
-
|
489
|
+
yield* this.clientSession.leaderThread.sendDevtoolsMessage(
|
490
|
+
Devtools.ResetAllDataReq.make({ liveStoreVersion, mode, requestId: nanoid() }),
|
491
|
+
)
|
564
492
|
}).pipe(this.runEffectFork)
|
565
493
|
}
|
566
494
|
|
@@ -568,13 +496,13 @@ export class Store<
|
|
568
496
|
Effect.gen(this, function* () {
|
569
497
|
const session = this.syncProcessor.syncStateRef.current
|
570
498
|
console.log('Session sync state:', session)
|
571
|
-
const leader = yield* this.clientSession.
|
499
|
+
const leader = yield* this.clientSession.leaderThread.getSyncState
|
572
500
|
console.log('Leader sync state:', leader)
|
573
501
|
}).pipe(this.runEffectFork)
|
574
502
|
}
|
575
503
|
|
576
504
|
__devShutdown = (cause?: Cause.Cause<UnexpectedError>) => {
|
577
|
-
this.clientSession
|
505
|
+
this.clientSession
|
578
506
|
.shutdown(cause ?? Cause.fail(IntentionalShutdownCause.make({ reason: 'manual' })))
|
579
507
|
.pipe(Effect.tapCauseLogPretty, Effect.provide(this.runtime), Effect.runFork)
|
580
508
|
}
|