@livestore/livestore 0.4.0 → 0.5.0-dev.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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/SqliteDbWrapper.d.ts.map +1 -1
- package/dist/SqliteDbWrapper.js +7 -5
- package/dist/SqliteDbWrapper.js.map +1 -1
- package/dist/SqliteDbWrapper.test.js +20 -3
- package/dist/SqliteDbWrapper.test.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +15 -15
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +17 -17
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/effect/LiveStore.test.js +5 -6
- package/dist/effect/LiveStore.test.js.map +1 -1
- package/dist/live-queries/base-class.d.ts +19 -2
- package/dist/live-queries/base-class.d.ts.map +1 -1
- package/dist/live-queries/base-class.js +28 -2
- package/dist/live-queries/base-class.js.map +1 -1
- package/dist/live-queries/computed.d.ts.map +1 -1
- package/dist/live-queries/computed.js +4 -4
- package/dist/live-queries/computed.js.map +1 -1
- package/dist/live-queries/db-query.d.ts +2 -2
- package/dist/live-queries/db-query.d.ts.map +1 -1
- package/dist/live-queries/db-query.js +26 -17
- package/dist/live-queries/db-query.js.map +1 -1
- package/dist/live-queries/db-query.test.js +9 -9
- package/dist/live-queries/db-query.test.js.map +1 -1
- package/dist/live-queries/signal.d.ts.map +1 -1
- package/dist/live-queries/signal.js +2 -2
- package/dist/live-queries/signal.js.map +1 -1
- package/dist/live-queries/signal.test.js +2 -2
- package/dist/live-queries/signal.test.js.map +1 -1
- package/dist/reactive.d.ts +1 -1
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +20 -1
- package/dist/reactive.js.map +1 -1
- package/dist/store/StoreRegistry.d.ts +12 -12
- package/dist/store/StoreRegistry.d.ts.map +1 -1
- package/dist/store/StoreRegistry.js +24 -24
- package/dist/store/StoreRegistry.js.map +1 -1
- package/dist/store/StoreRegistry.test.js +62 -59
- package/dist/store/StoreRegistry.test.js.map +1 -1
- package/dist/store/create-store.d.ts +12 -15
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +43 -24
- package/dist/store/create-store.js.map +1 -1
- package/dist/store/devtools.d.ts +1 -2
- package/dist/store/devtools.d.ts.map +1 -1
- package/dist/store/devtools.js +3 -2
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-eventstream.test.js +5 -5
- package/dist/store/store-eventstream.test.js.map +1 -1
- package/dist/store/store-types.d.ts +10 -28
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store-types.js +2 -38
- package/dist/store/store-types.js.map +1 -1
- package/dist/store/store-types.test.js +1 -1
- package/dist/store/store.d.ts +2 -2
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +114 -56
- package/dist/store/store.js.map +1 -1
- package/dist/utils/dev.js +1 -1
- package/dist/utils/dev.js.map +1 -1
- package/dist/utils/stack-info.d.ts.map +1 -1
- package/dist/utils/stack-info.js +2 -1
- package/dist/utils/stack-info.js.map +1 -1
- package/dist/utils/tests/fixture.d.ts +26 -34
- package/dist/utils/tests/fixture.d.ts.map +1 -1
- package/package.json +14 -24
- package/src/SqliteDbWrapper.test.ts +25 -3
- package/src/SqliteDbWrapper.ts +12 -9
- package/src/effect/LiveStore.test.ts +16 -16
- package/src/effect/LiveStore.ts +79 -50
- package/src/live-queries/__snapshots__/db-query.test.ts.snap +273 -49
- package/src/live-queries/base-class.ts +38 -6
- package/src/live-queries/computed.ts +5 -5
- package/src/live-queries/db-query.test.ts +9 -9
- package/src/live-queries/db-query.ts +42 -30
- package/src/live-queries/signal.test.ts +2 -2
- package/src/live-queries/signal.ts +3 -3
- package/src/reactive.ts +45 -35
- package/src/store/StoreRegistry.test.ts +62 -59
- package/src/store/StoreRegistry.ts +49 -38
- package/src/store/create-store.ts +85 -51
- package/src/store/devtools.ts +283 -283
- package/src/store/store-eventstream.test.ts +16 -7
- package/src/store/store-types.test.ts +1 -1
- package/src/store/store-types.ts +10 -56
- package/src/store/store.ts +148 -71
- package/src/utils/dev.ts +1 -1
- package/src/utils/stack-info.ts +4 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type * as otel from '@opentelemetry/api';
|
|
2
|
-
import { type
|
|
2
|
+
import { type BackendIdMismatchError, type ClientSession, type ClientSessionSyncProcessor, type IntentionalShutdownCause, type MaterializeError, type QueryBuilder, type StoreInterrupted, type UnknownError } from '@livestore/common';
|
|
3
3
|
import type { StreamEventsOptions } from '@livestore/common/leader-thread';
|
|
4
4
|
import type { LiveStoreEvent, LiveStoreSchema } from '@livestore/common/schema';
|
|
5
|
-
import type
|
|
6
|
-
import { Deferred } from '@livestore/utils/effect';
|
|
5
|
+
import { type Context, Deferred, type Effect, type Schema, type Scope } from '@livestore/utils/effect';
|
|
7
6
|
import type { LiveQuery, LiveQueryDef, ReactivityGraph, ReactivityGraphContext, SignalDef } from '../live-queries/base-class.ts';
|
|
7
|
+
import { isLiveQueryDef } from '../live-queries/base-class.ts';
|
|
8
8
|
import type { DebugRefreshReasonBase, Ref } from '../reactive.ts';
|
|
9
9
|
import type { SqliteDbWrapper } from '../SqliteDbWrapper.ts';
|
|
10
10
|
import type { ReferenceCountedSet } from '../utils/data-structures.ts';
|
|
@@ -63,7 +63,7 @@ export type StoreInternals = {
|
|
|
63
63
|
* Exposed primarily for Devtools (e.g. databrowser) to validate ad‑hoc
|
|
64
64
|
* event payloads. Application code should not depend on it directly.
|
|
65
65
|
*/
|
|
66
|
-
readonly eventSchema: Schema.
|
|
66
|
+
readonly eventSchema: Schema.Codec<LiveStoreEvent.Client.Decoded, LiveStoreEvent.Client.Encoded>;
|
|
67
67
|
/**
|
|
68
68
|
* The active client session backing this Store. Provides access to the
|
|
69
69
|
* leader thread, network status, and shutdown signaling.
|
|
@@ -77,14 +77,14 @@ export type StoreInternals = {
|
|
|
77
77
|
*/
|
|
78
78
|
readonly sqliteDbWrapper: SqliteDbWrapper;
|
|
79
79
|
/**
|
|
80
|
-
* Effect
|
|
80
|
+
* Effect context and scope used to fork background fibers for the Store.
|
|
81
81
|
*
|
|
82
|
-
* - `
|
|
82
|
+
* - `services` provides services when executing effects from imperative Store APIs.
|
|
83
83
|
* - `lifetimeScope` owns forked fibers; closed during Store shutdown.
|
|
84
84
|
*/
|
|
85
85
|
readonly effectContext: {
|
|
86
|
-
/** Effect
|
|
87
|
-
readonly
|
|
86
|
+
/** Effect context used to run Store effects with proper services. */
|
|
87
|
+
readonly services: Context.Context<Scope.Scope>;
|
|
88
88
|
/** Scope that owns all long‑lived fibers spawned by the Store. */
|
|
89
89
|
readonly lifetimeScope: Scope.Scope;
|
|
90
90
|
};
|
|
@@ -143,7 +143,7 @@ export type StoreConstructorParams<TSchema extends LiveStoreSchema = LiveStoreSc
|
|
|
143
143
|
context: TContext;
|
|
144
144
|
otelOptions: OtelOptions;
|
|
145
145
|
effectContext: {
|
|
146
|
-
|
|
146
|
+
services: Context.Context<Scope.Scope>;
|
|
147
147
|
lifetimeScope: Scope.Scope;
|
|
148
148
|
};
|
|
149
149
|
confirmUnsavedChanges: boolean;
|
|
@@ -151,9 +151,6 @@ export type StoreConstructorParams<TSchema extends LiveStoreSchema = LiveStoreSc
|
|
|
151
151
|
params: {
|
|
152
152
|
leaderPushBatchSize: number;
|
|
153
153
|
eventQueryBatchSize?: number;
|
|
154
|
-
simulation?: {
|
|
155
|
-
clientSessionSyncProcessor: typeof ClientSessionSyncProcessorSimulationParams.Type;
|
|
156
|
-
};
|
|
157
154
|
};
|
|
158
155
|
__runningInDevtools: boolean;
|
|
159
156
|
};
|
|
@@ -273,22 +270,7 @@ export declare namespace Queryable {
|
|
|
273
270
|
*/
|
|
274
271
|
type Result<TQueryable extends Queryable<any>> = TQueryable extends Queryable<infer TResult> ? TResult : never;
|
|
275
272
|
}
|
|
276
|
-
|
|
277
|
-
* Type guard that checks if a value is a query or signal definition.
|
|
278
|
-
*
|
|
279
|
-
* Use this to distinguish between definitions (blueprints) and instances (live queries).
|
|
280
|
-
* Definitions are created by `queryDb()`, `computed()`, and `signal()`.
|
|
281
|
-
*
|
|
282
|
-
* @example
|
|
283
|
-
* ```ts
|
|
284
|
-
* const todos$ = queryDb(tables.todos.all())
|
|
285
|
-
*
|
|
286
|
-
* if (isLiveQueryDef(todos$)) {
|
|
287
|
-
* console.log('This is a definition:', todos$.label)
|
|
288
|
-
* }
|
|
289
|
-
* ```
|
|
290
|
-
*/
|
|
291
|
-
export declare const isLiveQueryDef: (value: unknown) => value is LiveQueryDef<any> | SignalDef<any>;
|
|
273
|
+
export { isLiveQueryDef };
|
|
292
274
|
/**
|
|
293
275
|
* Type guard that checks if a value is a live query instance.
|
|
294
276
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-types.d.ts","sourceRoot":"","sources":["../../src/store/store-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAE/C,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,0BAA0B,EAC/B,KAAK,
|
|
1
|
+
{"version":3,"file":"store-types.d.ts","sourceRoot":"","sources":["../../src/store/store-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAE/C,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAE7B,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/E,OAAO,EAAE,KAAK,OAAO,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAa,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAEjH,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,eAAe,EACf,sBAAsB,EACtB,SAAS,EACV,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,cAAc,EAAU,MAAM,+BAA+B,CAAA;AACtE,OAAO,KAAK,EAAE,sBAAsB,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAEvC;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,CAAC,OAAO,SAAS,eAAe,GAAG,eAAe,CAAC,GAAG,IAC9E,uBAAuB,CAAC,OAAO,CAAC,GAChC;IACE,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,EAAE,OAAO,CAAA;CACf,GACD;IACE,KAAK,EAAE,UAAU,CAAA;IACjB,KAAK,EAAE,wBAAwB,GAAG,gBAAgB,GAAG,YAAY,CAAA;CAClE,CAAA;AAEL,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,QAAQ,CAC9C,wBAAwB,EACxB,YAAY,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,sBAAsB,CAC5E,CAAA;AACD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAG9D,CAAA;AAEH;;;;;;;;;GASG;AACH,MAAM,MAAM,uBAAuB,CAAC,OAAO,SAAS,eAAe,GAAG,eAAe,CAAC,GAAG,IAAI;IAC3F,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;IACnB,eAAe,EAAE,IAAI,CAAC,OAAO,CAAA;CAC9B,CAAA;AAED,eAAO,MAAM,oBAAoB,eAAyC,CAAA;AAC1E,MAAM,MAAM,oBAAoB,GAAG,OAAO,oBAAoB,CAAA;AAE9D;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAEhG;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAA;IAErC;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAA;IAEzC;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE;QACtB,qEAAqE;QACrE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC/C,kEAAkE;QAClE,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,KAAK,CAAA;KACpC,CAAA;IAED;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IAExB;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAA;IAEzC;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,sBAAsB,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IAE9F;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IAE3D;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,0BAA0B,CAAA;IAElD;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IAE7D;;;OAGG;IACH,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,CAAC,OAAO,SAAS,eAAe,GAAG,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,EAAE,IAAI;IACzG,aAAa,EAAE,aAAa,CAAA;IAC5B,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,QAAQ,CAAA;IACjB,WAAW,EAAE,WAAW,CAAA;IACxB,aAAa,EAAE;QACb,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACtC,aAAa,EAAE,KAAK,CAAC,KAAK,CAAA;KAC3B,CAAA;IACD,qBAAqB,EAAE,OAAO,CAAA;IAC9B,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,IAAI,KAAK,IAAI,CAAA;IAC9C,MAAM,EAAE;QACN,mBAAmB,EAAE,MAAM,CAAA;QAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAC7B,CAAA;IACD,mBAAmB,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACrB,sBAAsB,GACtB;IACE,IAAI,EAAE,QAAQ,CAAA;IACd,mCAAmC;IACnC,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAEnF,mDAAmD;IACnD,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACnC,GACD;IAEE,IAAI,EAAE,OAAO,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB,GACD;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtC;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAA;IACb,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;IACnB,eAAe,EAAE,IAAI,CAAC,OAAO,CAAA;IAC7B,kBAAkB,EAAE,IAAI,CAAC,OAAO,CAAA;IAChC,kBAAkB,EAAE,IAAI,CAAC,OAAO,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,SAAS,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,CAAA;IACvB,WAAW,CAAC,EAAE,IAAI,CAAC,OAAO,CAAA;CAC3B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,CAAC,OAAO,SAAS,eAAe,IAAI,IAAI,CACpE,mBAAmB,EACnB,QAAQ,GAAG,mBAAmB,CAC/B,GAAG;IACF;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAA;CAC1D,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAA;AAEpC;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,CAAC,OAAO,IAAI;IACtC,+FAA+F;IAC/F,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;IAClD,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,wCAAwC;IACxC,WAAW,CAAC,EAAE,IAAI,CAAC,OAAO,CAAA;IAC1B,0DAA0D;IAC1D,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB,CAAA;AAED,gFAAgF;AAChF,MAAM,MAAM,SAAS,CAAC,OAAO,IACzB,YAAY,CAAC,OAAO,CAAC,GACrB,SAAS,CAAC,OAAO,CAAC,GAClB,SAAS,CAAC,OAAO,CAAC,GAClB,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAEnC;;;;GAIG;AACH,yBAAiB,SAAS,CAAC;IACzB;;;;;;;;OAQG;IACH,KAAY,MAAM,CAAC,UAAU,SAAS,SAAS,CAAC,GAAG,CAAC,IAAI,UAAU,SAAS,SAAS,CAAC,MAAM,OAAO,CAAC,GAAG,OAAO,GAAG,KAAK,CAAA;CACtH;AAED,OAAO,EAAE,cAAc,EAAE,CAAA;AAEzB;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,SAAS,CAAC,GAAG,CAAyC,CAAA;AAEpH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,SAAS,CAAC,OAAO,CACO,CAAA;AAE9E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAA"}
|
|
@@ -1,45 +1,9 @@
|
|
|
1
1
|
import { isQueryBuilder, } from '@livestore/common';
|
|
2
2
|
import { Deferred, Predicate } from '@livestore/utils/effect';
|
|
3
|
-
import { TypeId } from "../live-queries/base-class.js";
|
|
3
|
+
import { isLiveQueryDef, TypeId } from "../live-queries/base-class.js";
|
|
4
4
|
export const makeShutdownDeferred = Deferred.make();
|
|
5
5
|
export const StoreInternalsSymbol = Symbol.for('livestore.StoreInternals');
|
|
6
|
-
|
|
7
|
-
* Type guard that checks if a value is a query or signal definition.
|
|
8
|
-
*
|
|
9
|
-
* Use this to distinguish between definitions (blueprints) and instances (live queries).
|
|
10
|
-
* Definitions are created by `queryDb()`, `computed()`, and `signal()`.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* const todos$ = queryDb(tables.todos.all())
|
|
15
|
-
*
|
|
16
|
-
* if (isLiveQueryDef(todos$)) {
|
|
17
|
-
* console.log('This is a definition:', todos$.label)
|
|
18
|
-
* }
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export const isLiveQueryDef = (value) => {
|
|
22
|
-
if (typeof value !== 'object' || value === null) {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
if (!('_tag' in value)) {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
const tag = value._tag;
|
|
29
|
-
if (tag !== 'def' && tag !== 'signal-def') {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
const candidate = value;
|
|
33
|
-
if (typeof candidate.make !== 'function') {
|
|
34
|
-
// The store calls make() to turn the definition into a live query instance.
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
if (typeof candidate.hash !== 'string' || typeof candidate.label !== 'string') {
|
|
38
|
-
// Both identifiers must be present so the store can cache and log the query.
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
|
-
};
|
|
6
|
+
export { isLiveQueryDef };
|
|
43
7
|
/**
|
|
44
8
|
* Type guard that checks if a value is a live query instance.
|
|
45
9
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-types.js","sourceRoot":"","sources":["../../src/store/store-types.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,cAAc,
|
|
1
|
+
{"version":3,"file":"store-types.js","sourceRoot":"","sources":["../../src/store/store-types.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,cAAc,GAKf,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAAgB,QAAQ,EAAe,SAAS,EAA2B,MAAM,yBAAyB,CAAA;AASjH,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAA;AAgCtE,MAAM,CAAC,MAAM,oBAAoB,GAAoC,QAAQ,CAAC,IAAI,EAG/E,CAAA;AAsBH,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAA;AA2P1E,OAAO,EAAE,cAAc,EAAE,CAAA;AAEzB;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAc,EAA2B,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;AAEpH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAc,EAA+B,EAAE,CACzE,cAAc,CAAC,KAAK,CAAC,IAAI,mBAAmB,CAAC,KAAK,CAAC,IAAI,cAAc,CAAC,KAAK,CAAC,CAAA"}
|
|
@@ -14,7 +14,7 @@ describe('isQueryable', () => {
|
|
|
14
14
|
it('identifies live query definitions', () => {
|
|
15
15
|
const def = queryDb({
|
|
16
16
|
query: 'select 1 as value',
|
|
17
|
-
schema: Schema.Array(Schema.Struct({ value: Schema.
|
|
17
|
+
schema: Schema.Array(Schema.Struct({ value: Schema.Finite })),
|
|
18
18
|
});
|
|
19
19
|
expect(isQueryable(def)).toBe(true);
|
|
20
20
|
});
|
package/dist/store/store.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import * as otel from '@opentelemetry/api';
|
|
1
2
|
import { type Bindable, type ClientSession, MaterializeError, type StorageMode, type SyncState, UnknownError } from '@livestore/common';
|
|
2
3
|
import type { LiveStoreSchema } from '@livestore/common/schema';
|
|
3
4
|
import { LiveStoreEvent } from '@livestore/common/schema';
|
|
4
5
|
import { Cause, Effect, Inspectable, Schema, Stream } from '@livestore/utils/effect';
|
|
5
|
-
import * as otel from '@opentelemetry/api';
|
|
6
6
|
import type { SignalDef } from '../live-queries/base-class.ts';
|
|
7
7
|
import { type Queryable, type RefreshReason, type StoreCommitOptions, type StoreConstructorParams, type StoreEventsOptions, type StoreInternals, StoreInternalsSymbol, type SubscribeOptions, type SyncStatus, type Unsubscribe } from './store-types.ts';
|
|
8
8
|
export type SubscribeFn = {
|
|
@@ -164,7 +164,7 @@ export declare class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any
|
|
|
164
164
|
query: <TResult>(query: Queryable<TResult> | {
|
|
165
165
|
query: string;
|
|
166
166
|
bindValues: Bindable;
|
|
167
|
-
schema?: Schema.
|
|
167
|
+
schema?: Schema.Decoder<TResult>;
|
|
168
168
|
}, options?: {
|
|
169
169
|
otelContext?: otel.Context;
|
|
170
170
|
debugRefreshReason?: RefreshReason;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store/store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,aAAa,EAQlB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store/store.ts"],"names":[],"mappings":"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"}
|
package/dist/store/store.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as otel from '@opentelemetry/api';
|
|
2
|
+
import { Devtools, getExecStatementsFromMaterializer, getResultSchema, hashMaterializerResults, IntentionalShutdownCause, isQueryBuilder, liveStoreVersion, MaterializeError, MaterializerHashMismatchError, makeClientSessionSyncProcessor, prepareBindValues, QueryBuilderAstSymbol, resolveSessionIdSymbolInBindValues, SqliteDbHelper, StateHead, UnknownError, } from '@livestore/common';
|
|
2
3
|
import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } from '@livestore/common/schema';
|
|
3
4
|
import { assertNever, isDevEnv, objectToString, omitUndefineds, shouldNeverHappen } from '@livestore/utils';
|
|
4
|
-
import { Cause, Effect, Exit, Fiber, Inspectable, Option, OtelTracer,
|
|
5
|
+
import { Cause, Effect, Exit, Fiber, Inspectable, Option, OtelTracer, Queue, Result, Schema, Stream, } from '@livestore/utils/effect';
|
|
5
6
|
import { nanoid } from '@livestore/utils/nanoid';
|
|
6
|
-
import * as otel from '@opentelemetry/api';
|
|
7
7
|
import { makeReactivityGraph } from "../live-queries/base-class.js";
|
|
8
8
|
import { makeExecBeforeFirstRun } from "../live-queries/client-document-get-query.js";
|
|
9
9
|
import { queryDb } from "../live-queries/db-query.js";
|
|
@@ -125,12 +125,13 @@ export class Store extends Inspectable.Class {
|
|
|
125
125
|
this.networkStatus = clientSession.leaderThread.networkStatus;
|
|
126
126
|
this.storageMode = clientSession.leaderThread.initialState.storageMode;
|
|
127
127
|
const reactivityGraph = makeReactivityGraph();
|
|
128
|
+
const stateHead = StateHead.make({ dbState: clientSession.sqliteDb });
|
|
128
129
|
const syncProcessor = makeClientSessionSyncProcessor({
|
|
129
130
|
schema,
|
|
130
131
|
clientSession,
|
|
131
|
-
materializeEvent: Effect.fn('client-session-sync-processor:materialize-event')((eventEncoded, {
|
|
132
|
+
materializeEvent: Effect.fn('client-session-sync-processor:materialize-event')((eventEncoded, { materializerHashLeader }) =>
|
|
132
133
|
// We need to use `Effect.gen` (even though we're using `Effect.fn`) so that we can pass `this` to the function
|
|
133
|
-
Effect.gen(this, function* () {
|
|
134
|
+
Effect.gen({ self: this }, function* () {
|
|
134
135
|
const resolution = yield* resolveEventDef(schema, {
|
|
135
136
|
operation: '@livestore/livestore:store:materializeEvent',
|
|
136
137
|
event: eventEncoded,
|
|
@@ -138,6 +139,7 @@ export class Store extends Inspectable.Class {
|
|
|
138
139
|
if (resolution._tag === 'unknown') {
|
|
139
140
|
// Runtime schema doesn't know this event yet; skip materialization but
|
|
140
141
|
// keep the log entry so upgraded clients can replay it later.
|
|
142
|
+
yield* stateHead.set(eventEncoded.seqNum);
|
|
141
143
|
return {
|
|
142
144
|
writeTables: new Set(),
|
|
143
145
|
sessionChangeset: { _tag: 'no-op' },
|
|
@@ -186,15 +188,10 @@ export class Store extends Inspectable.Class {
|
|
|
186
188
|
this[StoreInternalsSymbol].sqliteDbWrapper.debug.head = eventEncoded.seqNum;
|
|
187
189
|
}
|
|
188
190
|
};
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
sessionChangeset = this[StoreInternalsSymbol].sqliteDbWrapper.withChangeset(exec).changeset;
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
exec();
|
|
195
|
-
}
|
|
191
|
+
const sessionChangeset = this[StoreInternalsSymbol].sqliteDbWrapper.withChangeset(exec).changeset;
|
|
192
|
+
yield* stateHead.set(eventEncoded.seqNum);
|
|
196
193
|
return { writeTables: writeTablesForEvent, sessionChangeset, materializerHash };
|
|
197
|
-
}).pipe(Effect.mapError((cause) => MaterializeError.make({ cause })))),
|
|
194
|
+
}).pipe(SqliteDbHelper.withSavepoint(clientSession.sqliteDb), Effect.mapError((cause) => MaterializeError.make({ cause })))),
|
|
198
195
|
rollback: (changeset) => {
|
|
199
196
|
this[StoreInternalsSymbol].sqliteDbWrapper.rollback(changeset);
|
|
200
197
|
},
|
|
@@ -211,12 +208,9 @@ export class Store extends Inspectable.Class {
|
|
|
211
208
|
...omitUndefineds({
|
|
212
209
|
leaderPushBatchSize: params.leaderPushBatchSize,
|
|
213
210
|
}),
|
|
214
|
-
...(params.simulation?.clientSessionSyncProcessor !== undefined
|
|
215
|
-
? { simulation: params.simulation.clientSessionSyncProcessor }
|
|
216
|
-
: {}),
|
|
217
211
|
},
|
|
218
212
|
confirmUnsavedChanges,
|
|
219
|
-
}).pipe(
|
|
213
|
+
}).pipe(Effect.provideService(StateHead.StateHead, stateHead), Effect.runSyncWith(effectContext.services));
|
|
220
214
|
// TODO generalize the `tableRefs` concept to allow finer-grained refs
|
|
221
215
|
const tableRefs = {};
|
|
222
216
|
const activeQueries = new ReferenceCountedSet();
|
|
@@ -257,7 +251,7 @@ export class Store extends Inspectable.Class {
|
|
|
257
251
|
meta: { liveStoreRefType: 'table' },
|
|
258
252
|
});
|
|
259
253
|
}
|
|
260
|
-
const boot = Effect.gen(this, function* () {
|
|
254
|
+
const boot = Effect.gen({ self: this }, function* () {
|
|
261
255
|
yield* Effect.addFinalizer(() => Effect.sync(() => {
|
|
262
256
|
// Remove all table refs from the reactivity graph
|
|
263
257
|
for (const tableRef of Object.values(tableRefs)) {
|
|
@@ -409,12 +403,83 @@ export class Store extends Inspectable.Class {
|
|
|
409
403
|
};
|
|
410
404
|
subscribeAsAsyncIterable = (query, options) => {
|
|
411
405
|
this.checkShutdown('subscribe');
|
|
412
|
-
|
|
406
|
+
// This used to delegate to `Stream.toAsyncIterable(this.subscribeStream(...))`.
|
|
407
|
+
// With Effect v4, the callback-backed stream producer is forked during stream startup, so a caller could request
|
|
408
|
+
// `next()`, commit an update, and race the actual subscription registration. Register directly here so the first
|
|
409
|
+
// pending `next()` observes post-subscription updates. In the future, this should be refactored back toward a shared
|
|
410
|
+
// stream/async-iterable bridge if Effect exposes a primitive with that synchronous registration guarantee.
|
|
411
|
+
return {
|
|
412
|
+
[Symbol.asyncIterator]: () => {
|
|
413
|
+
const services = this[StoreInternalsSymbol].effectContext.services;
|
|
414
|
+
const runSync = Effect.runSyncWith(services);
|
|
415
|
+
const runPromiseExit = Effect.runPromiseExitWith(services);
|
|
416
|
+
let queue;
|
|
417
|
+
let isDone = false;
|
|
418
|
+
let unsubscribe;
|
|
419
|
+
const done = () => ({ done: true, value: undefined });
|
|
420
|
+
const isClosed = () => isDone;
|
|
421
|
+
const isQueueDone = (cause) => {
|
|
422
|
+
const error = Cause.findError(cause);
|
|
423
|
+
return Result.isSuccess(error) && Cause.isDone(error.success);
|
|
424
|
+
};
|
|
425
|
+
const ensureQueue = () => {
|
|
426
|
+
// Lazily allocate the queue so creating an async iterator without consuming it has no subscription-side work.
|
|
427
|
+
queue ??= Queue.unbounded().pipe(runSync);
|
|
428
|
+
return queue;
|
|
429
|
+
};
|
|
430
|
+
const emit = (value) => {
|
|
431
|
+
if (isDone === true)
|
|
432
|
+
return;
|
|
433
|
+
Queue.offerUnsafe(ensureQueue(), value);
|
|
434
|
+
};
|
|
435
|
+
const ensureSubscribed = () => {
|
|
436
|
+
// Subscribe from the first `next()` call so callers that request a value before
|
|
437
|
+
// committing updates don't race the asynchronous Stream-to-iterator startup path.
|
|
438
|
+
unsubscribe ??= this.subscribeWithCallback(query, emit, options);
|
|
439
|
+
};
|
|
440
|
+
const close = () => {
|
|
441
|
+
if (isDone === false) {
|
|
442
|
+
isDone = true;
|
|
443
|
+
unsubscribe?.();
|
|
444
|
+
unsubscribe = undefined;
|
|
445
|
+
if (queue !== undefined) {
|
|
446
|
+
// Wake any pending `next()` call and prevent later callback emissions from being buffered.
|
|
447
|
+
Queue.shutdown(queue).pipe(runSync);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return done();
|
|
451
|
+
};
|
|
452
|
+
return {
|
|
453
|
+
next: async () => {
|
|
454
|
+
if (isDone === true) {
|
|
455
|
+
return done();
|
|
456
|
+
}
|
|
457
|
+
ensureSubscribed();
|
|
458
|
+
// Delegate buffering and pending-consumer wakeups to Effect's queue implementation.
|
|
459
|
+
const exit = await runPromiseExit(Queue.take(ensureQueue()));
|
|
460
|
+
if (Exit.isSuccess(exit) === true) {
|
|
461
|
+
return { done: false, value: exit.value };
|
|
462
|
+
}
|
|
463
|
+
if (isClosed() === true || isQueueDone(exit.cause) === true) {
|
|
464
|
+
return done();
|
|
465
|
+
}
|
|
466
|
+
throw Cause.squash(exit.cause);
|
|
467
|
+
},
|
|
468
|
+
return: () => Promise.resolve(close()),
|
|
469
|
+
throw: (cause) => {
|
|
470
|
+
close();
|
|
471
|
+
return Promise.reject(cause);
|
|
472
|
+
},
|
|
473
|
+
};
|
|
474
|
+
},
|
|
475
|
+
};
|
|
413
476
|
};
|
|
414
|
-
subscribeStream = (query, options) => Stream.
|
|
415
|
-
const otelSpan = yield* OtelTracer.currentOtelSpan.pipe(Effect.catchTag('
|
|
477
|
+
subscribeStream = (query, options) => Stream.callback((emit) => Effect.gen({ self: this }, function* () {
|
|
478
|
+
const otelSpan = yield* OtelTracer.currentOtelSpan.pipe(Effect.catchTag('NoSuchElementError', () => Effect.void));
|
|
416
479
|
const otelContext = otelSpan !== undefined ? otel.trace.setSpan(otel.context.active(), otelSpan) : otel.context.active();
|
|
417
|
-
yield* Effect.acquireRelease(Effect.sync(() => this.subscribe(query, (result) =>
|
|
480
|
+
yield* Effect.acquireRelease(Effect.sync(() => this.subscribe(query, (result) => {
|
|
481
|
+
Queue.offerUnsafe(emit, result);
|
|
482
|
+
}, {
|
|
418
483
|
...options,
|
|
419
484
|
otelContext,
|
|
420
485
|
})), (unsub) => Effect.sync(() => unsub()));
|
|
@@ -440,7 +505,7 @@ export class Store extends Inspectable.Class {
|
|
|
440
505
|
...omitUndefineds({ otelContext: options?.otelContext }),
|
|
441
506
|
});
|
|
442
507
|
if (query.schema !== undefined) {
|
|
443
|
-
return Schema.
|
|
508
|
+
return Schema.decodeUnknownSync(query.schema)(res);
|
|
444
509
|
}
|
|
445
510
|
return res;
|
|
446
511
|
}
|
|
@@ -456,20 +521,21 @@ export class Store extends Inspectable.Class {
|
|
|
456
521
|
}
|
|
457
522
|
const sqlRes = query.asSql();
|
|
458
523
|
const schema = getResultSchema(query);
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
524
|
+
// Query builders preserve SessionIdSymbol so client-document queries can be reused across sessions.
|
|
525
|
+
// SQLite bind values must be concrete primitives, so resolve the symbol only at execution time.
|
|
526
|
+
const resolvedBindValues = sqlRes.bindValues === undefined
|
|
527
|
+
? undefined
|
|
528
|
+
: resolveSessionIdSymbolInBindValues(sqlRes.bindValues, this[StoreInternalsSymbol].clientSession.sessionId);
|
|
529
|
+
const rawRes = this[StoreInternalsSymbol].sqliteDbWrapper.cachedSelect(sqlRes.query, resolvedBindValues === undefined ? undefined : prepareBindValues(resolvedBindValues, sqlRes.query), {
|
|
464
530
|
...omitUndefineds({ otelContext: options?.otelContext }),
|
|
465
531
|
queriedTables: new Set([query[QueryBuilderAstSymbol].tableDef.sqliteDef.name]),
|
|
466
532
|
});
|
|
467
|
-
const decodeResult = Schema.
|
|
468
|
-
if (decodeResult
|
|
469
|
-
return decodeResult.
|
|
533
|
+
const decodeResult = Schema.decodeResult(schema)(rawRes);
|
|
534
|
+
if (Result.isSuccess(decodeResult) === true) {
|
|
535
|
+
return decodeResult.success;
|
|
470
536
|
}
|
|
471
537
|
else {
|
|
472
|
-
return shouldNeverHappen('Failed to decode query result with for schema:', objectToString(schema), 'raw result:', rawRes, 'decode error:', decodeResult.
|
|
538
|
+
return shouldNeverHappen('Failed to decode query result with for schema:', objectToString(schema), 'raw result:', rawRes, 'decode error:', decodeResult.failure);
|
|
473
539
|
}
|
|
474
540
|
}
|
|
475
541
|
else if (query._tag === 'def') {
|
|
@@ -572,24 +638,21 @@ export class Store extends Inspectable.Class {
|
|
|
572
638
|
commit = (firstEventOrTxnFnOrOptions, ...restEvents) => {
|
|
573
639
|
this.checkShutdown('commit');
|
|
574
640
|
const { events, options } = this.getCommitArgs(firstEventOrTxnFnOrOptions, restEvents);
|
|
575
|
-
Effect.gen(this, function* () {
|
|
641
|
+
Effect.gen({ self: this }, function* () {
|
|
576
642
|
const commitsSpan = otel.trace.getSpan(this[StoreInternalsSymbol].otel.commitsSpanContext);
|
|
577
643
|
commitsSpan?.addEvent('commit');
|
|
578
644
|
const currentSpan = yield* OtelTracer.currentOtelSpan.pipe(Effect.orDie);
|
|
579
645
|
commitsSpan?.addLink({ context: currentSpan.spanContext() });
|
|
580
|
-
for (const event of events) {
|
|
581
|
-
replaceSessionIdSymbol(event.args, this[StoreInternalsSymbol].clientSession.sessionId);
|
|
582
|
-
}
|
|
583
646
|
if (events.length === 0)
|
|
584
647
|
return;
|
|
585
|
-
const
|
|
648
|
+
const localServices = yield* Effect.context();
|
|
586
649
|
const encodedEvents = yield* this[StoreInternalsSymbol].syncProcessor.encodeEvents(events);
|
|
587
650
|
const { writeTables } = yield* Effect.try({
|
|
588
651
|
try: () => {
|
|
589
|
-
const materialize = () => this[StoreInternalsSymbol].syncProcessor
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
652
|
+
const materialize = () => this[StoreInternalsSymbol].syncProcessor
|
|
653
|
+
.materializeEvents(encodedEvents)
|
|
654
|
+
.pipe(Effect.runSyncWith(localServices));
|
|
655
|
+
return events.length > 1 ? this[StoreInternalsSymbol].sqliteDbWrapper.txn(materialize) : materialize();
|
|
593
656
|
},
|
|
594
657
|
catch: (cause) => UnknownError.make({ cause }),
|
|
595
658
|
});
|
|
@@ -627,7 +690,7 @@ export class Store extends Inspectable.Class {
|
|
|
627
690
|
// User-provided span links
|
|
628
691
|
...(options?.spanLinks?.map(OtelTracer.makeSpanLink) ?? []),
|
|
629
692
|
],
|
|
630
|
-
}), Effect.
|
|
693
|
+
}), Effect.tapCause(Effect.logError), Effect.catchCause((cause) => Effect.forkChild(this.shutdown(cause))), Effect.runSyncWith(this[StoreInternalsSymbol].effectContext.services));
|
|
631
694
|
};
|
|
632
695
|
//#endregion commit
|
|
633
696
|
/**
|
|
@@ -695,7 +758,7 @@ export class Store extends Inspectable.Class {
|
|
|
695
758
|
filter: options?.filter,
|
|
696
759
|
batchSize: preferredBatchSize,
|
|
697
760
|
};
|
|
698
|
-
return clientSession.leaderThread.events.stream(baseOptions).pipe(Stream.
|
|
761
|
+
return clientSession.leaderThread.events.stream(baseOptions).pipe(Stream.mapEffect((event) => Schema.decodeEffect(eventSchema)(event)), Stream.catchTag('SchemaError', (cause) => Stream.fail(UnknownError.make({ cause }))), Stream.tapError((error) => Effect.logError('Error in eventsStream', error)));
|
|
699
762
|
};
|
|
700
763
|
/**
|
|
701
764
|
* Returns the current synchronization status of the store.
|
|
@@ -771,7 +834,7 @@ export class Store extends Inspectable.Class {
|
|
|
771
834
|
this.checkShutdown('subscribeSyncStatus');
|
|
772
835
|
const fiber = this.syncStatusStream().pipe(Stream.tap((status) => Effect.sync(() => onUpdate(status))), Stream.runDrain, this.runEffectFork);
|
|
773
836
|
return () => {
|
|
774
|
-
Fiber.interrupt(fiber).pipe(
|
|
837
|
+
Fiber.interrupt(fiber).pipe(Effect.runForkWith(this[StoreInternalsSymbol].effectContext.services));
|
|
775
838
|
};
|
|
776
839
|
};
|
|
777
840
|
makeSyncStatus = (syncState) => {
|
|
@@ -822,7 +885,7 @@ export class Store extends Inspectable.Class {
|
|
|
822
885
|
*/
|
|
823
886
|
_dev = {
|
|
824
887
|
downloadDb: (source = 'local') => {
|
|
825
|
-
Effect.gen(this, function* () {
|
|
888
|
+
Effect.gen({ self: this }, function* () {
|
|
826
889
|
const data = source === 'local'
|
|
827
890
|
? this[StoreInternalsSymbol].sqliteDbWrapper.export()
|
|
828
891
|
: yield* this[StoreInternalsSymbol].clientSession.leaderThread.export;
|
|
@@ -830,13 +893,13 @@ export class Store extends Inspectable.Class {
|
|
|
830
893
|
}).pipe(this.runEffectFork);
|
|
831
894
|
},
|
|
832
895
|
downloadEventlogDb: () => {
|
|
833
|
-
Effect.gen(this, function* () {
|
|
896
|
+
Effect.gen({ self: this }, function* () {
|
|
834
897
|
const data = yield* this[StoreInternalsSymbol].clientSession.leaderThread.getEventlogData;
|
|
835
898
|
downloadBlob(data, `livestore-eventlog-${Date.now()}.db`);
|
|
836
899
|
}).pipe(this.runEffectFork);
|
|
837
900
|
},
|
|
838
901
|
hardReset: (mode = 'all-data') => {
|
|
839
|
-
Effect.gen(this, function* () {
|
|
902
|
+
Effect.gen({ self: this }, function* () {
|
|
840
903
|
const clientId = this[StoreInternalsSymbol].clientSession.clientId;
|
|
841
904
|
yield* this[StoreInternalsSymbol].clientSession.leaderThread.sendDevtoolsMessage(Devtools.Leader.ResetAllData.Request.make({ liveStoreVersion, mode, requestId: nanoid(), clientId }));
|
|
842
905
|
}).pipe(this.runEffectFork);
|
|
@@ -853,13 +916,13 @@ export class Store extends Inspectable.Class {
|
|
|
853
916
|
.pipe(this.runEffectFork);
|
|
854
917
|
},
|
|
855
918
|
// NOTE: Explicit return type needed to avoid TS2742 (inferred type references internal path)
|
|
856
|
-
syncStates: () => Effect.gen(this, function* () {
|
|
919
|
+
syncStates: () => Effect.gen({ self: this }, function* () {
|
|
857
920
|
const session = yield* this[StoreInternalsSymbol].syncProcessor.syncState;
|
|
858
921
|
const leader = yield* this[StoreInternalsSymbol].clientSession.leaderThread.syncState;
|
|
859
922
|
return { session, leader };
|
|
860
923
|
}).pipe(this.runEffectPromise),
|
|
861
924
|
printSyncStates: () => {
|
|
862
|
-
Effect.gen(this, function* () {
|
|
925
|
+
Effect.gen({ self: this }, function* () {
|
|
863
926
|
const session = yield* this[StoreInternalsSymbol].syncProcessor.syncState;
|
|
864
927
|
yield* Effect.log(`Session sync state: ${objectToString(session.localHead)} (upstream: ${objectToString(session.upstreamHead)})`, session.toJSON());
|
|
865
928
|
const leader = yield* this[StoreInternalsSymbol].clientSession.leaderThread.syncState;
|
|
@@ -876,8 +939,8 @@ export class Store extends Inspectable.Class {
|
|
|
876
939
|
_tag: 'livestore.Store',
|
|
877
940
|
reactivityGraph: this[StoreInternalsSymbol].reactivityGraph.getSnapshot({ includeResults: true }),
|
|
878
941
|
});
|
|
879
|
-
runEffectFork = (effect) => effect.pipe(Effect.forkIn(this[StoreInternalsSymbol].effectContext.lifetimeScope), Effect.tapCauseLogPretty,
|
|
880
|
-
runEffectPromise = (effect) => effect.pipe(Effect.tapCauseLogPretty,
|
|
942
|
+
runEffectFork = (effect) => effect.pipe(Effect.forkIn(this[StoreInternalsSymbol].effectContext.lifetimeScope), Effect.tapCauseLogPretty, Effect.runForkWith(this[StoreInternalsSymbol].effectContext.services));
|
|
943
|
+
runEffectPromise = (effect) => effect.pipe(Effect.tapCauseLogPretty, Effect.runPromiseWith(this[StoreInternalsSymbol].effectContext.services));
|
|
881
944
|
getCommitArgs = (firstEventOrTxnFnOrOptions, restEvents) => {
|
|
882
945
|
let events;
|
|
883
946
|
let options;
|
|
@@ -899,11 +962,6 @@ export class Store extends Inspectable.Class {
|
|
|
899
962
|
else {
|
|
900
963
|
events = [firstEventOrTxnFnOrOptions, ...restEvents];
|
|
901
964
|
}
|
|
902
|
-
// for (const event of events) {
|
|
903
|
-
// if (event.args.id === SessionIdSymbol) {
|
|
904
|
-
// event.args.id = this.sessionId
|
|
905
|
-
// }
|
|
906
|
-
// }
|
|
907
965
|
return { events, options };
|
|
908
966
|
};
|
|
909
967
|
}
|