@livestore/common 0.4.0-dev.18 → 0.4.0-dev.19
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/ClientSessionLeaderThreadProxy.d.ts +10 -10
- package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
- package/dist/adapter-types.d.ts +5 -5
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +28 -23
- package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-client-session.js +2 -2
- package/dist/devtools/devtools-messages-client-session.js.map +1 -1
- package/dist/devtools/devtools-messages-common.d.ts +6 -6
- package/dist/devtools/devtools-messages-leader.d.ts +33 -28
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +8 -8
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/errors.d.ts +6 -6
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +7 -7
- package/dist/errors.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +2 -2
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +28 -28
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts +13 -13
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +12 -11
- package/dist/leader-thread/eventlog.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +2 -2
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +3 -3
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +2 -2
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +10 -8
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/materialize-event.d.ts +1 -1
- package/dist/leader-thread/materialize-event.d.ts.map +1 -1
- package/dist/leader-thread/materialize-event.js +2 -2
- package/dist/leader-thread/materialize-event.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts +2 -2
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +5 -5
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.d.ts +2 -2
- package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +2 -2
- package/dist/leader-thread/shutdown-channel.js.map +1 -1
- package/dist/leader-thread/types.d.ts +15 -15
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/make-client-session.d.ts +2 -2
- package/dist/make-client-session.d.ts.map +1 -1
- package/dist/materializer-helper.d.ts +5 -5
- package/dist/materializer-helper.d.ts.map +1 -1
- package/dist/materializer-helper.js.map +1 -1
- package/dist/rematerialize-from-eventlog.d.ts +2 -2
- package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
- package/dist/rematerialize-from-eventlog.js +6 -6
- package/dist/rematerialize-from-eventlog.js.map +1 -1
- package/dist/schema/EventDef/define.d.ts +147 -0
- package/dist/schema/EventDef/define.d.ts.map +1 -0
- package/dist/schema/EventDef/define.js +139 -0
- package/dist/schema/EventDef/define.js.map +1 -0
- package/dist/schema/EventDef/event-def.d.ts +106 -0
- package/dist/schema/EventDef/event-def.d.ts.map +1 -0
- package/dist/schema/EventDef/event-def.js +2 -0
- package/dist/schema/EventDef/event-def.js.map +1 -0
- package/dist/schema/EventDef/facts.d.ts +118 -0
- package/dist/schema/EventDef/facts.d.ts.map +1 -0
- package/dist/schema/EventDef/facts.js +53 -0
- package/dist/schema/EventDef/facts.js.map +1 -0
- package/dist/schema/EventDef/materializer.d.ts +155 -0
- package/dist/schema/EventDef/materializer.d.ts.map +1 -0
- package/dist/schema/EventDef/materializer.js +83 -0
- package/dist/schema/EventDef/materializer.js.map +1 -0
- package/dist/schema/EventDef/mod.d.ts +5 -0
- package/dist/schema/EventDef/mod.d.ts.map +1 -0
- package/dist/schema/EventDef/mod.js +5 -0
- package/dist/schema/EventDef/mod.js.map +1 -0
- package/dist/schema/EventSequenceNumber/client.d.ts +136 -0
- package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -0
- package/dist/schema/{EventSequenceNumber.js → EventSequenceNumber/client.js} +86 -39
- package/dist/schema/EventSequenceNumber/client.js.map +1 -0
- package/dist/schema/EventSequenceNumber/global.d.ts +15 -0
- package/dist/schema/EventSequenceNumber/global.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber/global.js +14 -0
- package/dist/schema/EventSequenceNumber/global.js.map +1 -0
- package/dist/schema/EventSequenceNumber/mod.d.ts +37 -0
- package/dist/schema/EventSequenceNumber/mod.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber/mod.js +37 -0
- package/dist/schema/EventSequenceNumber/mod.js.map +1 -0
- package/dist/schema/EventSequenceNumber.test.js +41 -41
- package/dist/schema/EventSequenceNumber.test.js.map +1 -1
- package/dist/schema/{LiveStoreEvent.d.ts → LiveStoreEvent/client.d.ts} +84 -101
- package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -0
- package/dist/schema/{LiveStoreEvent.js → LiveStoreEvent/client.js} +69 -52
- package/dist/schema/LiveStoreEvent/client.js.map +1 -0
- package/dist/schema/LiveStoreEvent/for-event-def.d.ts +52 -0
- package/dist/schema/LiveStoreEvent/for-event-def.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/for-event-def.js +2 -0
- package/dist/schema/LiveStoreEvent/for-event-def.js.map +1 -0
- package/dist/schema/LiveStoreEvent/global.d.ts +36 -0
- package/dist/schema/LiveStoreEvent/global.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/global.js +31 -0
- package/dist/schema/LiveStoreEvent/global.js.map +1 -0
- package/dist/schema/LiveStoreEvent/input.d.ts +46 -0
- package/dist/schema/LiveStoreEvent/input.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/input.js +26 -0
- package/dist/schema/LiveStoreEvent/input.js.map +1 -0
- package/dist/schema/LiveStoreEvent/mod.d.ts +5 -0
- package/dist/schema/LiveStoreEvent/mod.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/mod.js +5 -0
- package/dist/schema/LiveStoreEvent/mod.js.map +1 -0
- package/dist/schema/events.d.ts +1 -1
- package/dist/schema/events.d.ts.map +1 -1
- package/dist/schema/events.js +1 -1
- package/dist/schema/events.js.map +1 -1
- package/dist/schema/mod.d.ts +3 -3
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +3 -3
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/schema.d.ts +1 -1
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.d.ts +1 -1
- package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.js +2 -2
- package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.js +13 -0
- package/dist/schema/state/sqlite/column-def.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.test.js +2 -1
- package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/mod.d.ts +2 -2
- package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/mod.js +1 -1
- package/dist/schema/state/sqlite/mod.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/api.d.ts +12 -8
- package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.js +18 -11
- package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.test.js +119 -90
- package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.js +5 -5
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.js.map +1 -1
- package/dist/schema/state/sqlite/system-tables/state-tables.js +3 -3
- package/dist/schema/state/sqlite/system-tables/state-tables.js.map +1 -1
- package/dist/schema/unknown-events.d.ts +3 -3
- package/dist/schema/unknown-events.d.ts.map +1 -1
- package/dist/schema-management/migrations.d.ts +2 -2
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-schema.d.ts +3 -3
- package/dist/schema-management/validate-schema.d.ts.map +1 -1
- package/dist/schema-management/validate-schema.js +2 -2
- package/dist/schema-management/validate-schema.js.map +1 -1
- package/dist/sqlite-types.d.ts +3 -3
- package/dist/sqlite-types.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +5 -5
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +12 -12
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/errors.d.ts +9 -4
- package/dist/sync/errors.d.ts.map +1 -1
- package/dist/sync/errors.js +6 -6
- package/dist/sync/errors.js.map +1 -1
- package/dist/sync/mock-sync-backend.d.ts +6 -6
- package/dist/sync/mock-sync-backend.d.ts.map +1 -1
- package/dist/sync/mock-sync-backend.js +4 -4
- package/dist/sync/mock-sync-backend.js.map +1 -1
- package/dist/sync/next/compact-events.js +2 -2
- package/dist/sync/next/compact-events.js.map +1 -1
- package/dist/sync/next/facts.d.ts +5 -5
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +5 -5
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +5 -5
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/history-dag.d.ts.map +1 -1
- package/dist/sync/next/history-dag.js +8 -8
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +5 -5
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +5 -5
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/event-fixtures.d.ts +2 -2
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/event-fixtures.js +9 -9
- package/dist/sync/next/test/event-fixtures.js.map +1 -1
- package/dist/sync/sync-backend-kv.d.ts +3 -3
- package/dist/sync/sync-backend-kv.d.ts.map +1 -1
- package/dist/sync/sync-backend-kv.js +3 -3
- package/dist/sync/sync-backend-kv.js.map +1 -1
- package/dist/sync/sync-backend.d.ts +9 -9
- package/dist/sync/sync-backend.d.ts.map +1 -1
- package/dist/sync/syncstate.d.ts +55 -42
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +42 -42
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +40 -40
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/sync/validate-push-payload.d.ts +1 -1
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js +2 -2
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/testing/event-factory.d.ts +3 -3
- package/dist/testing/event-factory.d.ts.map +1 -1
- package/dist/testing/event-factory.js +5 -7
- package/dist/testing/event-factory.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/src/ClientSessionLeaderThreadProxy.ts +10 -10
- package/src/adapter-types.ts +5 -5
- package/src/devtools/devtools-messages-client-session.ts +2 -2
- package/src/devtools/devtools-messages-leader.ts +8 -8
- package/src/errors.ts +11 -13
- package/src/leader-thread/LeaderSyncProcessor.ts +54 -56
- package/src/leader-thread/eventlog.ts +21 -26
- package/src/leader-thread/leader-worker-devtools.ts +3 -3
- package/src/leader-thread/make-leader-thread-layer.ts +12 -10
- package/src/leader-thread/materialize-event.ts +3 -3
- package/src/leader-thread/recreate-db.ts +6 -6
- package/src/leader-thread/shutdown-channel.ts +2 -2
- package/src/leader-thread/types.ts +15 -15
- package/src/make-client-session.ts +2 -2
- package/src/materializer-helper.ts +5 -5
- package/src/rematerialize-from-eventlog.ts +6 -6
- package/src/schema/EventDef/define.ts +201 -0
- package/src/schema/EventDef/event-def.ts +120 -0
- package/src/schema/EventDef/facts.ts +135 -0
- package/src/schema/EventDef/materializer.ts +172 -0
- package/src/schema/EventDef/mod.ts +4 -0
- package/src/schema/EventSequenceNumber/client.ts +257 -0
- package/src/schema/EventSequenceNumber/global.ts +19 -0
- package/src/schema/EventSequenceNumber/mod.ts +37 -0
- package/src/schema/EventSequenceNumber.test.ts +68 -50
- package/src/schema/LiveStoreEvent/client.ts +221 -0
- package/src/schema/LiveStoreEvent/for-event-def.ts +60 -0
- package/src/schema/LiveStoreEvent/global.ts +45 -0
- package/src/schema/LiveStoreEvent/input.ts +63 -0
- package/src/schema/LiveStoreEvent/mod.ts +4 -0
- package/src/schema/events.ts +1 -1
- package/src/schema/mod.ts +3 -3
- package/src/schema/schema.ts +1 -1
- package/src/schema/state/sqlite/client-document-def.test.ts +2 -2
- package/src/schema/state/sqlite/client-document-def.ts +3 -3
- package/src/schema/state/sqlite/column-def.test.ts +2 -1
- package/src/schema/state/sqlite/column-def.ts +17 -0
- package/src/schema/state/sqlite/mod.ts +2 -2
- package/src/schema/state/sqlite/query-builder/api.ts +12 -8
- package/src/schema/state/sqlite/query-builder/astToSql.ts +20 -11
- package/src/schema/state/sqlite/query-builder/impl.test.ts +122 -90
- package/src/schema/state/sqlite/system-tables/eventlog-tables.ts +5 -5
- package/src/schema/state/sqlite/system-tables/state-tables.ts +3 -3
- package/src/schema/unknown-events.ts +3 -3
- package/src/schema-management/migrations.ts +2 -2
- package/src/schema-management/validate-schema.ts +3 -3
- package/src/sqlite-types.ts +3 -3
- package/src/sync/ClientSessionSyncProcessor.ts +17 -17
- package/src/sync/errors.ts +6 -6
- package/src/sync/mock-sync-backend.ts +16 -16
- package/src/sync/next/compact-events.ts +2 -2
- package/src/sync/next/facts.ts +6 -6
- package/src/sync/next/history-dag-common.ts +8 -8
- package/src/sync/next/history-dag.ts +14 -10
- package/src/sync/next/rebase-events.ts +11 -11
- package/src/sync/next/test/event-fixtures.ts +11 -11
- package/src/sync/sync-backend-kv.ts +3 -3
- package/src/sync/sync-backend.ts +9 -9
- package/src/sync/syncstate.test.ts +46 -46
- package/src/sync/syncstate.ts +59 -55
- package/src/sync/validate-push-payload.ts +4 -4
- package/src/testing/event-factory.ts +10 -12
- package/src/version.ts +1 -1
- package/dist/schema/EventDef.d.ts +0 -126
- package/dist/schema/EventDef.d.ts.map +0 -1
- package/dist/schema/EventDef.js +0 -46
- package/dist/schema/EventDef.js.map +0 -1
- package/dist/schema/EventSequenceNumber.d.ts +0 -89
- package/dist/schema/EventSequenceNumber.d.ts.map +0 -1
- package/dist/schema/EventSequenceNumber.js.map +0 -1
- package/dist/schema/LiveStoreEvent.d.ts.map +0 -1
- package/dist/schema/LiveStoreEvent.js.map +0 -1
- package/src/schema/EventDef.ts +0 -222
- package/src/schema/EventSequenceNumber.ts +0 -208
- package/src/schema/LiveStoreEvent.ts +0 -286
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
type MaterializerHashMismatchError,
|
|
19
19
|
type SqliteDb,
|
|
20
20
|
type SqliteError,
|
|
21
|
-
|
|
21
|
+
UnknownError,
|
|
22
22
|
} from '../adapter-types.ts'
|
|
23
23
|
import type { MigrationsReport } from '../defs.ts'
|
|
24
24
|
import type * as Devtools from '../devtools/mod.ts'
|
|
@@ -82,7 +82,7 @@ export const makeLeaderThreadLayer = ({
|
|
|
82
82
|
shutdownChannel,
|
|
83
83
|
params,
|
|
84
84
|
testing,
|
|
85
|
-
}: MakeLeaderThreadLayerParams): Layer.Layer<LeaderThreadCtx,
|
|
85
|
+
}: MakeLeaderThreadLayerParams): Layer.Layer<LeaderThreadCtx, UnknownError, Scope.Scope | HttpClient.HttpClient> =>
|
|
86
86
|
Effect.gen(function* () {
|
|
87
87
|
const syncPayloadDecoded =
|
|
88
88
|
syncPayloadEncoded === undefined ? undefined : yield* Schema.decodeUnknown(syncPayloadSchema)(syncPayloadEncoded)
|
|
@@ -192,7 +192,7 @@ export const makeLeaderThreadLayer = ({
|
|
|
192
192
|
dbState,
|
|
193
193
|
dbEventlog,
|
|
194
194
|
makeSqliteDb,
|
|
195
|
-
eventSchema: LiveStoreEvent.
|
|
195
|
+
eventSchema: LiveStoreEvent.Client.makeSchema(schema),
|
|
196
196
|
shutdownStateSubRef: yield* SubscriptionRef.make<ShutdownState>('running'),
|
|
197
197
|
shutdownChannel,
|
|
198
198
|
syncBackend,
|
|
@@ -220,7 +220,7 @@ export const makeLeaderThreadLayer = ({
|
|
|
220
220
|
}).pipe(
|
|
221
221
|
Effect.withSpan('@livestore/common:leader-thread:boot'),
|
|
222
222
|
Effect.withSpanScoped('@livestore/common:leader-thread'),
|
|
223
|
-
|
|
223
|
+
UnknownError.mapToUnknownError,
|
|
224
224
|
Effect.tapCauseLogPretty,
|
|
225
225
|
Layer.unwrapScoped,
|
|
226
226
|
)
|
|
@@ -257,10 +257,12 @@ const getInitialSyncState = ({
|
|
|
257
257
|
dbEventlogMissing: boolean
|
|
258
258
|
}) => {
|
|
259
259
|
const initialBackendHead = dbEventlogMissing
|
|
260
|
-
? EventSequenceNumber.ROOT.global
|
|
260
|
+
? EventSequenceNumber.Client.ROOT.global
|
|
261
261
|
: Eventlog.getBackendHeadFromDb(dbEventlog)
|
|
262
262
|
|
|
263
|
-
const initialLocalHead = dbEventlogMissing
|
|
263
|
+
const initialLocalHead = dbEventlogMissing
|
|
264
|
+
? EventSequenceNumber.Client.ROOT
|
|
265
|
+
: Eventlog.getClientHeadFromDb(dbEventlog)
|
|
264
266
|
|
|
265
267
|
if (initialBackendHead > initialLocalHead.global) {
|
|
266
268
|
return shouldNeverHappen(
|
|
@@ -272,8 +274,8 @@ const getInitialSyncState = ({
|
|
|
272
274
|
localHead: initialLocalHead,
|
|
273
275
|
upstreamHead: {
|
|
274
276
|
global: initialBackendHead,
|
|
275
|
-
client: EventSequenceNumber.
|
|
276
|
-
rebaseGeneration: EventSequenceNumber.
|
|
277
|
+
client: EventSequenceNumber.Client.DEFAULT,
|
|
278
|
+
rebaseGeneration: EventSequenceNumber.Client.REBASE_GENERATION_DEFAULT,
|
|
277
279
|
},
|
|
278
280
|
pending: dbEventlogMissing
|
|
279
281
|
? []
|
|
@@ -282,7 +284,7 @@ const getInitialSyncState = ({
|
|
|
282
284
|
dbState,
|
|
283
285
|
since: {
|
|
284
286
|
global: initialBackendHead,
|
|
285
|
-
client: EventSequenceNumber.
|
|
287
|
+
client: EventSequenceNumber.Client.DEFAULT,
|
|
286
288
|
rebaseGeneration: initialLocalHead.rebaseGeneration,
|
|
287
289
|
},
|
|
288
290
|
}),
|
|
@@ -350,7 +352,7 @@ const bootLeaderThread = ({
|
|
|
350
352
|
devtoolsOptions: DevtoolsOptions
|
|
351
353
|
}): Effect.Effect<
|
|
352
354
|
LeaderThreadCtx['Type']['initialState'],
|
|
353
|
-
|
|
355
|
+
UnknownError | SqliteError | IsOfflineError | InvalidPullError | MaterializerHashMismatchError,
|
|
354
356
|
LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
|
|
355
357
|
> =>
|
|
356
358
|
Effect.gen(function* () {
|
|
@@ -155,7 +155,7 @@ export const makeMaterializeEvent = ({
|
|
|
155
155
|
attributes: {
|
|
156
156
|
eventName: eventEncoded.name,
|
|
157
157
|
eventNum: eventEncoded.seqNum,
|
|
158
|
-
'span.label': `${EventSequenceNumber.toString(eventEncoded.seqNum)} ${eventEncoded.name}`,
|
|
158
|
+
'span.label': `${EventSequenceNumber.Client.toString(eventEncoded.seqNum)} ${eventEncoded.name}`,
|
|
159
159
|
},
|
|
160
160
|
}),
|
|
161
161
|
// Effect.logDuration('@livestore/common:leader-thread:materializeEvent'),
|
|
@@ -169,7 +169,7 @@ export const rollback = ({
|
|
|
169
169
|
}: {
|
|
170
170
|
dbState: SqliteDb
|
|
171
171
|
dbEventlog: SqliteDb
|
|
172
|
-
eventNumsToRollback: EventSequenceNumber.
|
|
172
|
+
eventNumsToRollback: EventSequenceNumber.Client.Composite[]
|
|
173
173
|
}) =>
|
|
174
174
|
Effect.gen(function* () {
|
|
175
175
|
const rollbackEvents = dbState
|
|
@@ -185,7 +185,7 @@ export const rollback = ({
|
|
|
185
185
|
changeset: _.changeset,
|
|
186
186
|
debug: _.debug,
|
|
187
187
|
}))
|
|
188
|
-
.toSorted((a, b) => EventSequenceNumber.compare(a.seqNum, b.seqNum))
|
|
188
|
+
.toSorted((a, b) => EventSequenceNumber.Client.compare(a.seqNum, b.seqNum))
|
|
189
189
|
|
|
190
190
|
// Apply changesets in reverse order
|
|
191
191
|
for (let i = rollbackEvents.length - 1; i >= 0; i--) {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
rematerializeFromEventlog,
|
|
11
11
|
type SqliteDb,
|
|
12
12
|
type SqliteError,
|
|
13
|
-
|
|
13
|
+
UnknownError,
|
|
14
14
|
} from '../index.ts'
|
|
15
15
|
import type { LiveStoreSchema } from '../schema/mod.ts'
|
|
16
16
|
import { configureConnection } from './connection.ts'
|
|
@@ -28,7 +28,7 @@ export const recreateDb = ({
|
|
|
28
28
|
schema: LiveStoreSchema
|
|
29
29
|
bootStatusQueue: Queue.Queue<BootStatus>
|
|
30
30
|
materializeEvent: MaterializeEvent
|
|
31
|
-
}): Effect.Effect<{ migrationsReport: MigrationsReport },
|
|
31
|
+
}): Effect.Effect<{ migrationsReport: MigrationsReport }, UnknownError | MaterializeError | SqliteError> =>
|
|
32
32
|
Effect.gen(function* () {
|
|
33
33
|
const migrationOptions = schema.state.sqlite.migrations
|
|
34
34
|
let migrationsReport: MigrationsReport
|
|
@@ -48,7 +48,7 @@ export const recreateDb = ({
|
|
|
48
48
|
|
|
49
49
|
const initDb = (hooks: Partial<MigrationHooks> | undefined) =>
|
|
50
50
|
Effect.gen(function* () {
|
|
51
|
-
yield* Effect.tryAll(() => hooks?.init?.(tmpDb)).pipe(
|
|
51
|
+
yield* Effect.tryAll(() => hooks?.init?.(tmpDb)).pipe(UnknownError.mapToUnknownError)
|
|
52
52
|
|
|
53
53
|
const migrationsReport = yield* migrateDb({
|
|
54
54
|
db: tmpDb,
|
|
@@ -57,7 +57,7 @@ export const recreateDb = ({
|
|
|
57
57
|
Queue.offer(bootStatusQueue, { stage: 'migrating', progress: { done, total } }),
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
-
yield* Effect.tryAll(() => hooks?.pre?.(tmpDb)).pipe(
|
|
60
|
+
yield* Effect.tryAll(() => hooks?.pre?.(tmpDb)).pipe(UnknownError.mapToUnknownError)
|
|
61
61
|
|
|
62
62
|
return { migrationsReport, tmpDb }
|
|
63
63
|
})
|
|
@@ -78,7 +78,7 @@ export const recreateDb = ({
|
|
|
78
78
|
Queue.offer(bootStatusQueue, { stage: 'rehydrating', progress: { done, total } }),
|
|
79
79
|
})
|
|
80
80
|
|
|
81
|
-
yield* Effect.tryAll(() => hooks?.post?.(initResult.tmpDb)).pipe(
|
|
81
|
+
yield* Effect.tryAll(() => hooks?.post?.(initResult.tmpDb)).pipe(UnknownError.mapToUnknownError)
|
|
82
82
|
|
|
83
83
|
break
|
|
84
84
|
}
|
|
@@ -88,7 +88,7 @@ export const recreateDb = ({
|
|
|
88
88
|
migrationsReport = { migrations: [] }
|
|
89
89
|
|
|
90
90
|
const newDbData = yield* Effect.tryAll(() => migrationOptions.migrate(oldDbData)).pipe(
|
|
91
|
-
|
|
91
|
+
UnknownError.mapToUnknownError,
|
|
92
92
|
)
|
|
93
93
|
|
|
94
94
|
tmpDb.import(newDbData)
|
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
InvalidPushError,
|
|
8
8
|
IsOfflineError,
|
|
9
9
|
MaterializeError,
|
|
10
|
-
|
|
10
|
+
UnknownError,
|
|
11
11
|
} from '../index.ts'
|
|
12
12
|
|
|
13
13
|
export class All extends Schema.Union(
|
|
14
14
|
IntentionalShutdownCause,
|
|
15
|
-
|
|
15
|
+
UnknownError,
|
|
16
16
|
IsOfflineError,
|
|
17
17
|
InvalidPushError,
|
|
18
18
|
InvalidPullError,
|
|
@@ -22,7 +22,7 @@ import type {
|
|
|
22
22
|
PersistenceInfo,
|
|
23
23
|
SqliteDb,
|
|
24
24
|
SyncBackend,
|
|
25
|
-
|
|
25
|
+
UnknownError,
|
|
26
26
|
} from '../index.ts'
|
|
27
27
|
import type { EventSequenceNumber, LiveStoreEvent, LiveStoreSchema } from '../schema/mod.ts'
|
|
28
28
|
import type * as SyncState from '../sync/syncstate.ts'
|
|
@@ -43,7 +43,7 @@ export const InitialSyncOptions = Schema.Union(InitialSyncOptionsSkip, InitialSy
|
|
|
43
43
|
export type InitialSyncOptions = typeof InitialSyncOptions.Type
|
|
44
44
|
|
|
45
45
|
export type InitialSyncInfo = Option.Option<{
|
|
46
|
-
eventSequenceNumber: EventSequenceNumber.
|
|
46
|
+
eventSequenceNumber: EventSequenceNumber.Global.Type
|
|
47
47
|
metadata: Option.Option<Schema.JsonValue>
|
|
48
48
|
}>
|
|
49
49
|
|
|
@@ -66,7 +66,7 @@ export type DevtoolsOptions =
|
|
|
66
66
|
persistenceInfo: PersistenceInfoPair
|
|
67
67
|
mode: 'proxy' | 'direct'
|
|
68
68
|
},
|
|
69
|
-
|
|
69
|
+
UnknownError,
|
|
70
70
|
Scope.Scope | HttpClient.HttpClient | LeaderThreadCtx
|
|
71
71
|
>
|
|
72
72
|
}
|
|
@@ -96,13 +96,13 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
|
|
|
96
96
|
// TODO we should find a more elegant way to handle cases which need this ref for their implementation
|
|
97
97
|
shutdownStateSubRef: SubscriptionRef.SubscriptionRef<ShutdownState>
|
|
98
98
|
shutdownChannel: ShutdownChannel
|
|
99
|
-
eventSchema: LiveStoreEvent.
|
|
99
|
+
eventSchema: LiveStoreEvent.ForEventDef.ForRecord<any>
|
|
100
100
|
devtools: DevtoolsContext
|
|
101
101
|
syncBackend: SyncBackend.SyncBackend | undefined
|
|
102
102
|
syncProcessor: LeaderSyncProcessor
|
|
103
103
|
materializeEvent: MaterializeEvent
|
|
104
104
|
initialState: {
|
|
105
|
-
leaderHead: EventSequenceNumber.
|
|
105
|
+
leaderHead: EventSequenceNumber.Client.Composite
|
|
106
106
|
migrationsReport: MigrationsReport
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
@@ -116,7 +116,7 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
|
|
|
116
116
|
>() {}
|
|
117
117
|
|
|
118
118
|
export type MaterializeEvent = (
|
|
119
|
-
eventEncoded: LiveStoreEvent.EncodedWithMeta,
|
|
119
|
+
eventEncoded: LiveStoreEvent.Client.EncodedWithMeta,
|
|
120
120
|
options?: {
|
|
121
121
|
/** Needed for rematerializeFromEventlog */
|
|
122
122
|
skipEventlog?: boolean
|
|
@@ -137,17 +137,17 @@ export type InitialBlockingSyncContext = {
|
|
|
137
137
|
export interface LeaderSyncProcessor {
|
|
138
138
|
/** Used by client sessions to subscribe to upstream sync state changes */
|
|
139
139
|
pull: (args: {
|
|
140
|
-
cursor: EventSequenceNumber.
|
|
141
|
-
}) => Stream.Stream<{ payload: typeof SyncState.PayloadUpstream.Type },
|
|
140
|
+
cursor: EventSequenceNumber.Client.Composite
|
|
141
|
+
}) => Stream.Stream<{ payload: typeof SyncState.PayloadUpstream.Type }, UnknownError>
|
|
142
142
|
/** The `pullQueue` API can be used instead of `pull` when more convenient */
|
|
143
143
|
pullQueue: (args: {
|
|
144
|
-
cursor: EventSequenceNumber.
|
|
145
|
-
}) => Effect.Effect<Queue.Queue<{ payload: typeof SyncState.PayloadUpstream.Type }>,
|
|
144
|
+
cursor: EventSequenceNumber.Client.Composite
|
|
145
|
+
}) => Effect.Effect<Queue.Queue<{ payload: typeof SyncState.PayloadUpstream.Type }>, UnknownError, Scope.Scope>
|
|
146
146
|
|
|
147
147
|
/** Used by client sessions to push events to the leader thread */
|
|
148
148
|
push: (
|
|
149
149
|
/** `batch` needs to follow the same rules as `batch` in `SyncBackend.push` */
|
|
150
|
-
batch: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>,
|
|
150
|
+
batch: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>,
|
|
151
151
|
options?: {
|
|
152
152
|
/**
|
|
153
153
|
* If true, the effect will only finish when the local push has been processed (i.e. succeeded or was rejected).
|
|
@@ -160,14 +160,14 @@ export interface LeaderSyncProcessor {
|
|
|
160
160
|
|
|
161
161
|
/** Currently only used by devtools which don't provide their own event numbers */
|
|
162
162
|
pushPartial: (args: {
|
|
163
|
-
event: LiveStoreEvent.
|
|
163
|
+
event: LiveStoreEvent.Input.Encoded
|
|
164
164
|
clientId: string
|
|
165
165
|
sessionId: string
|
|
166
|
-
}) => Effect.Effect<void,
|
|
166
|
+
}) => Effect.Effect<void, UnknownError>
|
|
167
167
|
|
|
168
168
|
boot: Effect.Effect<
|
|
169
|
-
{ initialLeaderHead: EventSequenceNumber.
|
|
170
|
-
|
|
169
|
+
{ initialLeaderHead: EventSequenceNumber.Client.Composite },
|
|
170
|
+
UnknownError,
|
|
171
171
|
LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
|
|
172
172
|
>
|
|
173
173
|
syncState: Subscribable.Subscribable<SyncState.SyncState>
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
ClientSessionLeaderThreadProxy,
|
|
9
9
|
LockStatus,
|
|
10
10
|
SqliteDb,
|
|
11
|
-
|
|
11
|
+
UnknownError,
|
|
12
12
|
} from './adapter-types.ts'
|
|
13
13
|
import * as Devtools from './devtools/mod.ts'
|
|
14
14
|
import { liveStoreVersion } from './version.ts'
|
|
@@ -44,7 +44,7 @@ export const makeClientSession = <R>({
|
|
|
44
44
|
connectWebmeshNode: (args: {
|
|
45
45
|
webmeshNode: Webmesh.MeshNode
|
|
46
46
|
sessionInfo: Devtools.SessionInfo.SessionInfo
|
|
47
|
-
}) => Effect.Effect<void,
|
|
47
|
+
}) => Effect.Effect<void, UnknownError, Scope.Scope | R>
|
|
48
48
|
webmeshMode: 'direct' | 'proxy'
|
|
49
49
|
registerBeforeUnload: (onBeforeUnload: () => void) => () => void
|
|
50
50
|
/** Browser origin of the client session; used for origin-scoped DevTools mesh channels */
|
|
@@ -3,8 +3,8 @@ import { Hash, Option, Schema } from '@livestore/utils/effect'
|
|
|
3
3
|
|
|
4
4
|
import type { SqliteDb } from './adapter-types.ts'
|
|
5
5
|
import { SessionIdSymbol } from './adapter-types.ts'
|
|
6
|
-
import type { EventDef, Materializer, MaterializerContextQuery, MaterializerResult } from './schema/EventDef.ts'
|
|
7
|
-
import type * as LiveStoreEvent from './schema/LiveStoreEvent.ts'
|
|
6
|
+
import type { EventDef, Materializer, MaterializerContextQuery, MaterializerResult } from './schema/EventDef/mod.ts'
|
|
7
|
+
import type * as LiveStoreEvent from './schema/LiveStoreEvent/mod.ts'
|
|
8
8
|
import type { LiveStoreSchema } from './schema/schema.ts'
|
|
9
9
|
import type { QueryBuilder } from './schema/state/sqlite/query-builder/api.ts'
|
|
10
10
|
import { isQueryBuilder } from './schema/state/sqlite/query-builder/api.ts'
|
|
@@ -24,8 +24,8 @@ export const getExecStatementsFromMaterializer = ({
|
|
|
24
24
|
dbState: SqliteDb
|
|
25
25
|
/** Both encoded and decoded events are supported to reduce the number of times we need to decode/encode */
|
|
26
26
|
event:
|
|
27
|
-
| { decoded: LiveStoreEvent.
|
|
28
|
-
| { decoded: undefined; encoded: LiveStoreEvent.
|
|
27
|
+
| { decoded: LiveStoreEvent.Client.Decoded; encoded: undefined }
|
|
28
|
+
| { decoded: undefined; encoded: LiveStoreEvent.Client.Encoded }
|
|
29
29
|
}): ReadonlyArray<{
|
|
30
30
|
statementSql: string
|
|
31
31
|
bindValues: PreparedBindValues
|
|
@@ -85,7 +85,7 @@ export const getExecStatementsFromMaterializer = ({
|
|
|
85
85
|
|
|
86
86
|
export const makeMaterializerHash =
|
|
87
87
|
({ schema, dbState }: { schema: LiveStoreSchema; dbState: SqliteDb }) =>
|
|
88
|
-
(event: LiveStoreEvent.
|
|
88
|
+
(event: LiveStoreEvent.Client.Encoded): Option.Option<number> => {
|
|
89
89
|
if (isDevEnv()) {
|
|
90
90
|
// Hashing is only needed during dev-mode diagnostics. Skip work entirely for
|
|
91
91
|
// unknown events (no definition/materializer) so we do not introduce noisy
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { memoizeByRef } from '@livestore/utils'
|
|
2
2
|
import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
|
|
3
3
|
|
|
4
|
-
import { type SqliteDb,
|
|
4
|
+
import { type SqliteDb, UnknownError } from './adapter-types.ts'
|
|
5
5
|
import type { MaterializeEvent } from './leader-thread/mod.ts'
|
|
6
6
|
import type { EventDef, LiveStoreSchema } from './schema/mod.ts'
|
|
7
7
|
import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } from './schema/mod.ts'
|
|
@@ -32,7 +32,7 @@ export const rematerializeFromEventlog = ({
|
|
|
32
32
|
const processEvent = (row: SystemTables.EventlogMetaRow) =>
|
|
33
33
|
Effect.gen(function* () {
|
|
34
34
|
const args = JSON.parse(row.argsJson)
|
|
35
|
-
const eventEncoded = LiveStoreEvent.EncodedWithMeta.make({
|
|
35
|
+
const eventEncoded = LiveStoreEvent.Client.EncodedWithMeta.make({
|
|
36
36
|
name: row.name,
|
|
37
37
|
args,
|
|
38
38
|
seqNum: {
|
|
@@ -52,7 +52,7 @@ export const rematerializeFromEventlog = ({
|
|
|
52
52
|
const resolution = yield* resolveEventDef(schema, {
|
|
53
53
|
operation: '@livestore/common:rematerializeFromEventlog:processEvent',
|
|
54
54
|
event: eventEncoded,
|
|
55
|
-
}).pipe(
|
|
55
|
+
}).pipe(UnknownError.mapToUnknownError)
|
|
56
56
|
|
|
57
57
|
if (resolution._tag === 'unknown') {
|
|
58
58
|
// Old snapshots can contain newer events. Skip until the runtime has
|
|
@@ -71,7 +71,7 @@ export const rematerializeFromEventlog = ({
|
|
|
71
71
|
// Checking whether the schema has changed in an incompatible way
|
|
72
72
|
yield* Schema.decodeUnknown(eventDef.schema)(args).pipe(
|
|
73
73
|
Effect.mapError((cause) =>
|
|
74
|
-
|
|
74
|
+
UnknownError.make({
|
|
75
75
|
cause,
|
|
76
76
|
note: `\
|
|
77
77
|
There was an error during rematerializing from the eventlog while decoding
|
|
@@ -106,9 +106,9 @@ LIMIT ${CHUNK_SIZE}
|
|
|
106
106
|
const lastId = Chunk.isChunk(item)
|
|
107
107
|
? Chunk.last(item).pipe(
|
|
108
108
|
Option.map((_) => ({ global: _.seqNumGlobal, client: _.seqNumClient })),
|
|
109
|
-
Option.getOrElse(() => EventSequenceNumber.ROOT),
|
|
109
|
+
Option.getOrElse(() => EventSequenceNumber.Client.ROOT),
|
|
110
110
|
)
|
|
111
|
-
: EventSequenceNumber.ROOT
|
|
111
|
+
: EventSequenceNumber.Client.ROOT
|
|
112
112
|
const nextItem = Chunk.fromIterable(
|
|
113
113
|
stmt.select<SystemTables.EventlogMetaRow>({
|
|
114
114
|
$seqNumGlobal: lastId?.global,
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Definition Functions
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions for creating event definitions in LiveStore.
|
|
5
|
+
* Events are the core unit of state change - all mutations to the database
|
|
6
|
+
* happen through events that are committed to the eventlog.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { Events } from '@livestore/livestore'
|
|
11
|
+
* import { Schema } from 'effect'
|
|
12
|
+
*
|
|
13
|
+
* // Define events for your application
|
|
14
|
+
* export const events = {
|
|
15
|
+
* // Synced events are sent to the sync backend
|
|
16
|
+
* todoCreated: Events.synced({
|
|
17
|
+
* name: 'v1.TodoCreated',
|
|
18
|
+
* schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
|
|
19
|
+
* }),
|
|
20
|
+
*
|
|
21
|
+
* // Client-only events stay local (useful for UI state)
|
|
22
|
+
* uiStateSet: Events.clientOnly({
|
|
23
|
+
* name: 'UiStateSet',
|
|
24
|
+
* schema: Schema.Struct({ selectedId: Schema.NullOr(Schema.String) }),
|
|
25
|
+
* }),
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
* @module
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { shouldNeverHappen } from '@livestore/utils'
|
|
32
|
+
import { Schema } from '@livestore/utils/effect'
|
|
33
|
+
|
|
34
|
+
import type { EventDef } from './event-def.ts'
|
|
35
|
+
import type { EventDefFactInput, EventDefFacts } from './facts.ts'
|
|
36
|
+
|
|
37
|
+
/** Options for defining an event. */
|
|
38
|
+
export type DefineEventOptions<TTo, TDerived extends boolean = false> = {
|
|
39
|
+
/**
|
|
40
|
+
* Callback defining fact constraints for this event.
|
|
41
|
+
* @experimental This feature is not fully implemented yet.
|
|
42
|
+
*/
|
|
43
|
+
facts?: (
|
|
44
|
+
args: TTo,
|
|
45
|
+
currentFacts: EventDefFacts,
|
|
46
|
+
) => {
|
|
47
|
+
modify?: {
|
|
48
|
+
/** Facts to set (create or update). */
|
|
49
|
+
set?: Iterable<EventDefFactInput>
|
|
50
|
+
/** Facts to unset (remove). */
|
|
51
|
+
unset?: Iterable<EventDefFactInput>
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Facts that must exist for this event to be valid.
|
|
55
|
+
* Used for history constraints and compaction rules.
|
|
56
|
+
*/
|
|
57
|
+
require?: Iterable<EventDefFactInput>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* When true, the event is only synced within the same client's sessions
|
|
62
|
+
* but never sent to the sync backend. Useful for UI state.
|
|
63
|
+
* @default false
|
|
64
|
+
*/
|
|
65
|
+
clientOnly?: boolean
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* When true, marks this as a derived event that cannot have materializers.
|
|
69
|
+
* @default false
|
|
70
|
+
*/
|
|
71
|
+
derived?: TDerived
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates an event definition with full control over all options.
|
|
76
|
+
*
|
|
77
|
+
* This is the low-level function for creating events. For most cases,
|
|
78
|
+
* prefer using `synced()` or `clientOnly()` which provide simpler APIs.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const customEvent = defineEvent({
|
|
83
|
+
* name: 'v1.CustomEvent',
|
|
84
|
+
* schema: Schema.Struct({ data: Schema.String }),
|
|
85
|
+
* clientOnly: false,
|
|
86
|
+
* derived: false,
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export const defineEvent = <TName extends string, TType, TEncoded = TType, TDerived extends boolean = false>(
|
|
91
|
+
args: {
|
|
92
|
+
name: TName
|
|
93
|
+
schema: Schema.Schema<TType, TEncoded>
|
|
94
|
+
} & DefineEventOptions<TType, TDerived>,
|
|
95
|
+
): EventDef<TName, TType, TEncoded, TDerived> => {
|
|
96
|
+
const { name, schema, ...options } = args
|
|
97
|
+
|
|
98
|
+
const makePartialEvent = (args: TType) => {
|
|
99
|
+
const res = Schema.validateEither(schema)(args)
|
|
100
|
+
if (res._tag === 'Left') {
|
|
101
|
+
shouldNeverHappen(`Invalid event args for event '${name}':`, res.left.message, '\n')
|
|
102
|
+
}
|
|
103
|
+
return { name: name, args }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
Object.defineProperty(makePartialEvent, 'name', { value: name })
|
|
107
|
+
Object.defineProperty(makePartialEvent, 'schema', { value: schema })
|
|
108
|
+
Object.defineProperty(makePartialEvent, 'encoded', {
|
|
109
|
+
value: (args: TEncoded) => ({ name: name, args }),
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
Object.defineProperty(makePartialEvent, 'options', {
|
|
113
|
+
value: {
|
|
114
|
+
clientOnly: options?.clientOnly ?? false,
|
|
115
|
+
facts: options?.facts
|
|
116
|
+
? (args, currentFacts) => {
|
|
117
|
+
const res = options.facts!(args, currentFacts)
|
|
118
|
+
return {
|
|
119
|
+
modify: {
|
|
120
|
+
set: res.modify?.set ? new Set(res.modify.set) : new Set(),
|
|
121
|
+
unset: res.modify?.unset ? new Set(res.modify.unset) : new Set(),
|
|
122
|
+
},
|
|
123
|
+
require: res.require ? new Set(res.require) : new Set(),
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
: undefined,
|
|
127
|
+
derived: options?.derived ?? false,
|
|
128
|
+
} satisfies EventDef.Any['options'],
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
return makePartialEvent as EventDef<TName, TType, TEncoded, TDerived>
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Creates a synced event definition.
|
|
136
|
+
*
|
|
137
|
+
* Synced events are sent to the sync backend and distributed to all connected
|
|
138
|
+
* clients. Use this for collaborative data that should be shared across users
|
|
139
|
+
* and devices.
|
|
140
|
+
*
|
|
141
|
+
* Event names should be versioned (e.g., `v1.TodoCreated`) to support
|
|
142
|
+
* schema evolution over time.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* import { Events } from '@livestore/livestore'
|
|
147
|
+
* import { Schema } from 'effect'
|
|
148
|
+
*
|
|
149
|
+
* const todoCreated = Events.synced({
|
|
150
|
+
* name: 'v1.TodoCreated',
|
|
151
|
+
* schema: Schema.Struct({
|
|
152
|
+
* id: Schema.String,
|
|
153
|
+
* text: Schema.String,
|
|
154
|
+
* completed: Schema.Boolean,
|
|
155
|
+
* }),
|
|
156
|
+
* })
|
|
157
|
+
*
|
|
158
|
+
* // Commit the event
|
|
159
|
+
* store.commit(todoCreated({ id: 'abc', text: 'Buy milk', completed: false }))
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export const synced = <TName extends string, TType, TEncoded = TType>(
|
|
163
|
+
args: {
|
|
164
|
+
name: TName
|
|
165
|
+
schema: Schema.Schema<TType, TEncoded>
|
|
166
|
+
} & Omit<DefineEventOptions<TType, false>, 'derived' | 'clientOnly'>,
|
|
167
|
+
): EventDef<TName, TType, TEncoded> => defineEvent({ ...args, clientOnly: false })
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Creates a client-only event definition.
|
|
171
|
+
*
|
|
172
|
+
* Client-only events are synced within the same client's sessions (e.g., across
|
|
173
|
+
* browser tabs) but are never sent to the sync backend. Use this for local UI
|
|
174
|
+
* state like selected items, filter settings, or draft content.
|
|
175
|
+
*
|
|
176
|
+
* Note: Client-only events still require materializers and are stored in the
|
|
177
|
+
* local eventlog, they just don't participate in server-side sync.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* import { Events } from '@livestore/livestore'
|
|
182
|
+
* import { Schema } from 'effect'
|
|
183
|
+
*
|
|
184
|
+
* const uiStateSet = Events.clientOnly({
|
|
185
|
+
* name: 'UiStateSet',
|
|
186
|
+
* schema: Schema.Struct({
|
|
187
|
+
* selectedTodoId: Schema.NullOr(Schema.String),
|
|
188
|
+
* filterMode: Schema.Literal('all', 'active', 'completed'),
|
|
189
|
+
* }),
|
|
190
|
+
* })
|
|
191
|
+
*
|
|
192
|
+
* // Update local UI state
|
|
193
|
+
* store.commit(uiStateSet({ selectedTodoId: 'abc', filterMode: 'active' }))
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export const clientOnly = <TName extends string, TType, TEncoded = TType>(
|
|
197
|
+
args: {
|
|
198
|
+
name: TName
|
|
199
|
+
schema: Schema.Schema<TType, TEncoded>
|
|
200
|
+
} & Omit<DefineEventOptions<TType, false>, 'derived' | 'clientOnly'>,
|
|
201
|
+
): EventDef<TName, TType, TEncoded> => defineEvent({ ...args, clientOnly: true })
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
import type { FactsCallback } from './facts.ts'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Core type representing an event definition in LiveStore.
|
|
7
|
+
*
|
|
8
|
+
* An EventDef defines the structure and behavior of an event type, including:
|
|
9
|
+
* - A unique name identifying the event type (conventionally versioned, e.g., `v1.TodoCreated`)
|
|
10
|
+
* - A schema for validating and encoding/decoding event arguments
|
|
11
|
+
* - Options controlling sync behavior and constraints
|
|
12
|
+
*
|
|
13
|
+
* EventDefs are callable - invoking them creates a partial event object suitable for `store.commit()`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { Events } from '@livestore/livestore'
|
|
18
|
+
* import { Schema } from 'effect'
|
|
19
|
+
*
|
|
20
|
+
* const todoCreated = Events.synced({
|
|
21
|
+
* name: 'v1.TodoCreated',
|
|
22
|
+
* schema: Schema.Struct({
|
|
23
|
+
* id: Schema.String,
|
|
24
|
+
* text: Schema.String,
|
|
25
|
+
* }),
|
|
26
|
+
* })
|
|
27
|
+
*
|
|
28
|
+
* // Use the EventDef as a constructor
|
|
29
|
+
* store.commit(todoCreated({ id: 'abc', text: 'Buy milk' }))
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export type EventDef<TName extends string, TType, TEncoded = TType, TDerived extends boolean = false> = {
|
|
33
|
+
/** Unique identifier for this event type. Conventionally versioned (e.g., `v1.TodoCreated`). */
|
|
34
|
+
name: TName
|
|
35
|
+
|
|
36
|
+
/** Effect Schema used for validating and encoding/decoding event arguments. */
|
|
37
|
+
schema: Schema.Schema<TType, TEncoded>
|
|
38
|
+
|
|
39
|
+
options: {
|
|
40
|
+
/**
|
|
41
|
+
* When true, the event is only synced within the same client's sessions (e.g., across tabs)
|
|
42
|
+
* but never sent to the sync backend. Useful for UI state like selected items or filters.
|
|
43
|
+
*/
|
|
44
|
+
clientOnly: boolean
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Callback defining fact constraints for this event.
|
|
48
|
+
* @experimental This feature is not fully implemented yet.
|
|
49
|
+
*/
|
|
50
|
+
facts: FactsCallback<TType> | undefined
|
|
51
|
+
|
|
52
|
+
/** Whether this is a derived event. Derived events cannot have materializers. */
|
|
53
|
+
derived: TDerived
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Callable signature - creates a partial event with decoded arguments.
|
|
58
|
+
* The returned object can be passed directly to `store.commit()`.
|
|
59
|
+
*/
|
|
60
|
+
(
|
|
61
|
+
args: TType,
|
|
62
|
+
): {
|
|
63
|
+
name: TName
|
|
64
|
+
args: TType
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Creates a partial event with pre-encoded arguments.
|
|
69
|
+
* Useful when working with already-serialized data.
|
|
70
|
+
*/
|
|
71
|
+
encoded: (args: TEncoded) => {
|
|
72
|
+
name: TName
|
|
73
|
+
args: TEncoded
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Type helper for accessing the event's shape with name and decoded args. */
|
|
77
|
+
readonly Event: {
|
|
78
|
+
name: TName
|
|
79
|
+
args: TType
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export namespace EventDef {
|
|
84
|
+
/**
|
|
85
|
+
* Wildcard type matching any EventDef regardless of type parameters.
|
|
86
|
+
* Used as a type constraint in generic functions and collections.
|
|
87
|
+
*/
|
|
88
|
+
export type Any = EventDef<string, any, any, boolean>
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* EventDef without the callable function signature.
|
|
92
|
+
* Used in contexts where only the metadata (name, schema, options) is needed,
|
|
93
|
+
* such as materializer definitions.
|
|
94
|
+
*/
|
|
95
|
+
export type AnyWithoutFn = Pick<Any, 'name' | 'schema' | 'options'>
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Container holding a Map of event definitions keyed by name.
|
|
100
|
+
* Used internally by LiveStoreSchema.
|
|
101
|
+
*/
|
|
102
|
+
export type EventDefMap = {
|
|
103
|
+
map: Map<string, EventDef.Any>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Plain object record of event definitions keyed by name.
|
|
108
|
+
* This is the typical shape when defining events in user code.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* const events = {
|
|
113
|
+
* todoCreated: Events.synced({ name: 'v1.TodoCreated', schema: ... }),
|
|
114
|
+
* todoDeleted: Events.synced({ name: 'v1.TodoDeleted', schema: ... }),
|
|
115
|
+
* } satisfies EventDefRecord
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export type EventDefRecord = {
|
|
119
|
+
[name: string]: EventDef.Any
|
|
120
|
+
}
|