@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
|
@@ -5,13 +5,13 @@ import { EventSequenceNumber } from './mod.ts'
|
|
|
5
5
|
|
|
6
6
|
Vitest.describe('EventSequenceNumber', () => {
|
|
7
7
|
Vitest.test('nextPair (no rebase)', () => {
|
|
8
|
-
const e_0_0 = EventSequenceNumber.make({ global: 0, client: 0 })
|
|
9
|
-
expect(EventSequenceNumber.nextPair({ seqNum: e_0_0, isClient: false }).seqNum).toStrictEqual({
|
|
8
|
+
const e_0_0 = EventSequenceNumber.Client.Composite.make({ global: 0, client: 0 })
|
|
9
|
+
expect(EventSequenceNumber.Client.nextPair({ seqNum: e_0_0, isClient: false }).seqNum).toStrictEqual({
|
|
10
10
|
global: 1,
|
|
11
11
|
client: 0,
|
|
12
12
|
rebaseGeneration: 0,
|
|
13
13
|
})
|
|
14
|
-
expect(EventSequenceNumber.nextPair({ seqNum: e_0_0, isClient: true }).seqNum).toStrictEqual({
|
|
14
|
+
expect(EventSequenceNumber.Client.nextPair({ seqNum: e_0_0, isClient: true }).seqNum).toStrictEqual({
|
|
15
15
|
global: 0,
|
|
16
16
|
client: 1,
|
|
17
17
|
rebaseGeneration: 0,
|
|
@@ -19,20 +19,24 @@ Vitest.describe('EventSequenceNumber', () => {
|
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
Vitest.test('nextPair (rebase)', () => {
|
|
22
|
-
const e_0_0 = EventSequenceNumber.make({ global: 0, client: 0 })
|
|
23
|
-
expect(
|
|
22
|
+
const e_0_0 = EventSequenceNumber.Client.Composite.make({ global: 0, client: 0 })
|
|
23
|
+
expect(
|
|
24
|
+
EventSequenceNumber.Client.nextPair({ seqNum: e_0_0, isClient: false, rebaseGeneration: 1 }).seqNum,
|
|
25
|
+
).toStrictEqual({
|
|
24
26
|
global: 1,
|
|
25
27
|
client: 0,
|
|
26
28
|
rebaseGeneration: 1,
|
|
27
29
|
})
|
|
28
|
-
expect(
|
|
30
|
+
expect(
|
|
31
|
+
EventSequenceNumber.Client.nextPair({ seqNum: e_0_0, isClient: true, rebaseGeneration: 1 }).seqNum,
|
|
32
|
+
).toStrictEqual({
|
|
29
33
|
global: 0,
|
|
30
34
|
client: 1,
|
|
31
35
|
rebaseGeneration: 1,
|
|
32
36
|
})
|
|
33
37
|
|
|
34
|
-
const e_0_0_g1 = EventSequenceNumber.make({ global: 0, client: 0, rebaseGeneration: 2 })
|
|
35
|
-
expect(EventSequenceNumber.nextPair({ seqNum: e_0_0_g1, isClient: false }).seqNum).toStrictEqual({
|
|
38
|
+
const e_0_0_g1 = EventSequenceNumber.Client.Composite.make({ global: 0, client: 0, rebaseGeneration: 2 })
|
|
39
|
+
expect(EventSequenceNumber.Client.nextPair({ seqNum: e_0_0_g1, isClient: false }).seqNum).toStrictEqual({
|
|
36
40
|
global: 1,
|
|
37
41
|
client: 0,
|
|
38
42
|
rebaseGeneration: 2,
|
|
@@ -40,44 +44,58 @@ Vitest.describe('EventSequenceNumber', () => {
|
|
|
40
44
|
})
|
|
41
45
|
|
|
42
46
|
Vitest.test('toString', () => {
|
|
43
|
-
expect(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
)
|
|
51
|
-
expect(
|
|
52
|
-
|
|
53
|
-
)
|
|
47
|
+
expect(
|
|
48
|
+
EventSequenceNumber.Client.toString(EventSequenceNumber.Client.Composite.make({ global: 0, client: 0 })),
|
|
49
|
+
).toBe('e0')
|
|
50
|
+
expect(
|
|
51
|
+
EventSequenceNumber.Client.toString(
|
|
52
|
+
EventSequenceNumber.Client.Composite.make({ global: 0, client: 0, rebaseGeneration: 1 }),
|
|
53
|
+
),
|
|
54
|
+
).toBe('e0r1')
|
|
55
|
+
expect(
|
|
56
|
+
EventSequenceNumber.Client.toString(EventSequenceNumber.Client.Composite.make({ global: 0, client: 1 })),
|
|
57
|
+
).toBe('e0.1')
|
|
58
|
+
expect(
|
|
59
|
+
EventSequenceNumber.Client.toString(
|
|
60
|
+
EventSequenceNumber.Client.Composite.make({ global: 0, client: 1, rebaseGeneration: 1 }),
|
|
61
|
+
),
|
|
62
|
+
).toBe('e0.1r1')
|
|
63
|
+
expect(
|
|
64
|
+
EventSequenceNumber.Client.toString(
|
|
65
|
+
EventSequenceNumber.Client.Composite.make({ global: 5, client: 3, rebaseGeneration: 2 }),
|
|
66
|
+
),
|
|
67
|
+
).toBe('e5.3r2')
|
|
54
68
|
})
|
|
55
69
|
|
|
56
70
|
Vitest.test('fromString', () => {
|
|
57
71
|
// Basic cases
|
|
58
|
-
expect(EventSequenceNumber.fromString('e0')).toStrictEqual(
|
|
59
|
-
|
|
60
|
-
|
|
72
|
+
expect(EventSequenceNumber.Client.fromString('e0')).toStrictEqual(
|
|
73
|
+
EventSequenceNumber.Client.Composite.make({ global: 0, client: 0 }),
|
|
74
|
+
)
|
|
75
|
+
expect(EventSequenceNumber.Client.fromString('e0r1')).toStrictEqual(
|
|
76
|
+
EventSequenceNumber.Client.Composite.make({ global: 0, client: 0, rebaseGeneration: 1 }),
|
|
77
|
+
)
|
|
78
|
+
expect(EventSequenceNumber.Client.fromString('e0.1')).toStrictEqual(
|
|
79
|
+
EventSequenceNumber.Client.Composite.make({ global: 0, client: 1 }),
|
|
61
80
|
)
|
|
62
|
-
expect(EventSequenceNumber.fromString('e0.
|
|
63
|
-
|
|
64
|
-
EventSequenceNumber.make({ global: 0, client: 1, rebaseGeneration: 1 }),
|
|
81
|
+
expect(EventSequenceNumber.Client.fromString('e0.1r1')).toStrictEqual(
|
|
82
|
+
EventSequenceNumber.Client.Composite.make({ global: 0, client: 1, rebaseGeneration: 1 }),
|
|
65
83
|
)
|
|
66
|
-
expect(EventSequenceNumber.fromString('e5.3r2')).toStrictEqual(
|
|
67
|
-
EventSequenceNumber.make({ global: 5, client: 3, rebaseGeneration: 2 }),
|
|
84
|
+
expect(EventSequenceNumber.Client.fromString('e5.3r2')).toStrictEqual(
|
|
85
|
+
EventSequenceNumber.Client.Composite.make({ global: 5, client: 3, rebaseGeneration: 2 }),
|
|
68
86
|
)
|
|
69
87
|
|
|
70
88
|
// Error cases
|
|
71
|
-
expect(() => EventSequenceNumber.fromString('0')).toThrow(
|
|
89
|
+
expect(() => EventSequenceNumber.Client.fromString('0')).toThrow(
|
|
72
90
|
'Invalid event sequence number string: must start with "e"',
|
|
73
91
|
)
|
|
74
|
-
expect(() => EventSequenceNumber.fromString('eabc')).toThrow(
|
|
92
|
+
expect(() => EventSequenceNumber.Client.fromString('eabc')).toThrow(
|
|
75
93
|
'Invalid event sequence number string: invalid number format',
|
|
76
94
|
)
|
|
77
|
-
expect(() => EventSequenceNumber.fromString('e0.abc')).toThrow(
|
|
95
|
+
expect(() => EventSequenceNumber.Client.fromString('e0.abc')).toThrow(
|
|
78
96
|
'Invalid event sequence number string: invalid number format',
|
|
79
97
|
)
|
|
80
|
-
expect(() => EventSequenceNumber.fromString('e0rabc')).toThrow(
|
|
98
|
+
expect(() => EventSequenceNumber.Client.fromString('e0rabc')).toThrow(
|
|
81
99
|
'Invalid event sequence number string: invalid number format',
|
|
82
100
|
)
|
|
83
101
|
})
|
|
@@ -93,37 +111,37 @@ Vitest.describe('EventSequenceNumber', () => {
|
|
|
93
111
|
]
|
|
94
112
|
|
|
95
113
|
for (const testCase of testCases) {
|
|
96
|
-
const original = EventSequenceNumber.make(testCase)
|
|
97
|
-
const str = EventSequenceNumber.toString(original)
|
|
98
|
-
const parsed = EventSequenceNumber.fromString(str)
|
|
114
|
+
const original = EventSequenceNumber.Client.Composite.make(testCase)
|
|
115
|
+
const str = EventSequenceNumber.Client.toString(original)
|
|
116
|
+
const parsed = EventSequenceNumber.Client.fromString(str)
|
|
99
117
|
expect(parsed).toStrictEqual(original)
|
|
100
118
|
}
|
|
101
119
|
})
|
|
102
120
|
|
|
103
121
|
Vitest.test('compare', () => {
|
|
104
|
-
const e_0_0_r0 = EventSequenceNumber.make({ global: 0, client: 0, rebaseGeneration: 0 })
|
|
105
|
-
const e_0_0_r1 = EventSequenceNumber.make({ global: 0, client: 0, rebaseGeneration: 1 })
|
|
106
|
-
const e_0_1_r0 = EventSequenceNumber.make({ global: 0, client: 1, rebaseGeneration: 0 })
|
|
107
|
-
const e_0_1_r1 = EventSequenceNumber.make({ global: 0, client: 1, rebaseGeneration: 1 })
|
|
108
|
-
const e_1_0_r0 = EventSequenceNumber.make({ global: 1, client: 0, rebaseGeneration: 0 })
|
|
109
|
-
const e_1_1_r0 = EventSequenceNumber.make({ global: 1, client: 1, rebaseGeneration: 0 })
|
|
122
|
+
const e_0_0_r0 = EventSequenceNumber.Client.Composite.make({ global: 0, client: 0, rebaseGeneration: 0 })
|
|
123
|
+
const e_0_0_r1 = EventSequenceNumber.Client.Composite.make({ global: 0, client: 0, rebaseGeneration: 1 })
|
|
124
|
+
const e_0_1_r0 = EventSequenceNumber.Client.Composite.make({ global: 0, client: 1, rebaseGeneration: 0 })
|
|
125
|
+
const e_0_1_r1 = EventSequenceNumber.Client.Composite.make({ global: 0, client: 1, rebaseGeneration: 1 })
|
|
126
|
+
const e_1_0_r0 = EventSequenceNumber.Client.Composite.make({ global: 1, client: 0, rebaseGeneration: 0 })
|
|
127
|
+
const e_1_1_r0 = EventSequenceNumber.Client.Composite.make({ global: 1, client: 1, rebaseGeneration: 0 })
|
|
110
128
|
|
|
111
129
|
// Global comparison (strongest level)
|
|
112
|
-
expect(EventSequenceNumber.compare(e_0_0_r0, e_1_0_r0)).toBeLessThan(0)
|
|
113
|
-
expect(EventSequenceNumber.compare(e_1_0_r0, e_0_0_r0)).toBeGreaterThan(0)
|
|
114
|
-
expect(EventSequenceNumber.compare(e_0_1_r1, e_1_0_r0)).toBeLessThan(0) // global overrides client and rebase
|
|
130
|
+
expect(EventSequenceNumber.Client.compare(e_0_0_r0, e_1_0_r0)).toBeLessThan(0)
|
|
131
|
+
expect(EventSequenceNumber.Client.compare(e_1_0_r0, e_0_0_r0)).toBeGreaterThan(0)
|
|
132
|
+
expect(EventSequenceNumber.Client.compare(e_0_1_r1, e_1_0_r0)).toBeLessThan(0) // global overrides client and rebase
|
|
115
133
|
|
|
116
134
|
// Client comparison (second level)
|
|
117
|
-
expect(EventSequenceNumber.compare(e_0_0_r0, e_0_1_r0)).toBeLessThan(0)
|
|
118
|
-
expect(EventSequenceNumber.compare(e_0_1_r0, e_0_0_r0)).toBeGreaterThan(0)
|
|
119
|
-
expect(EventSequenceNumber.compare(e_0_0_r1, e_0_1_r0)).toBeLessThan(0) // client overrides rebase
|
|
135
|
+
expect(EventSequenceNumber.Client.compare(e_0_0_r0, e_0_1_r0)).toBeLessThan(0)
|
|
136
|
+
expect(EventSequenceNumber.Client.compare(e_0_1_r0, e_0_0_r0)).toBeGreaterThan(0)
|
|
137
|
+
expect(EventSequenceNumber.Client.compare(e_0_0_r1, e_0_1_r0)).toBeLessThan(0) // client overrides rebase
|
|
120
138
|
|
|
121
139
|
// Rebase generation comparison (weakest level)
|
|
122
|
-
expect(EventSequenceNumber.compare(e_0_0_r0, e_0_0_r1)).toBeLessThan(0)
|
|
123
|
-
expect(EventSequenceNumber.compare(e_0_0_r1, e_0_0_r0)).toBeGreaterThan(0)
|
|
140
|
+
expect(EventSequenceNumber.Client.compare(e_0_0_r0, e_0_0_r1)).toBeLessThan(0)
|
|
141
|
+
expect(EventSequenceNumber.Client.compare(e_0_0_r1, e_0_0_r0)).toBeGreaterThan(0)
|
|
124
142
|
|
|
125
143
|
// Equal comparison
|
|
126
|
-
expect(EventSequenceNumber.compare(e_0_0_r0, e_0_0_r0)).toBe(0)
|
|
127
|
-
expect(EventSequenceNumber.compare(e_1_1_r0, e_1_1_r0)).toBe(0)
|
|
144
|
+
expect(EventSequenceNumber.Client.compare(e_0_0_r0, e_0_0_r0)).toBe(0)
|
|
145
|
+
expect(EventSequenceNumber.Client.compare(e_1_1_r0, e_1_1_r0)).toBe(0)
|
|
128
146
|
})
|
|
129
147
|
})
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { memoizeByRef } from '@livestore/utils'
|
|
2
|
+
import { Option, Schema } from '@livestore/utils/effect'
|
|
3
|
+
|
|
4
|
+
import type { EventDef } from '../EventDef/mod.ts'
|
|
5
|
+
import * as EventSequenceNumber from '../EventSequenceNumber/mod.ts'
|
|
6
|
+
import type { LiveStoreSchema } from '../schema.ts'
|
|
7
|
+
import type * as ForEventDef from './for-event-def.ts'
|
|
8
|
+
import type * as Global from './global.ts'
|
|
9
|
+
|
|
10
|
+
/** Effect Schema for client events with decoded args. */
|
|
11
|
+
export const Decoded = Schema.Struct({
|
|
12
|
+
name: Schema.String,
|
|
13
|
+
args: Schema.Any,
|
|
14
|
+
seqNum: EventSequenceNumber.Client.Composite,
|
|
15
|
+
parentSeqNum: EventSequenceNumber.Client.Composite,
|
|
16
|
+
clientId: Schema.String,
|
|
17
|
+
sessionId: Schema.String,
|
|
18
|
+
}).annotations({ title: 'LiveStoreEvent.Client.Decoded' })
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Effect Schema for client events with encoded args.
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* // Confirmed event (client=0)
|
|
25
|
+
* const event: LiveStoreEvent.Client.Encoded = {
|
|
26
|
+
* name: 'todoCreated-v1',
|
|
27
|
+
* args: { id: 'abc', text: 'Buy milk' },
|
|
28
|
+
* seqNum: { global: 5, client: 0, rebaseGeneration: 0 },
|
|
29
|
+
* parentSeqNum: { global: 4, client: 0, rebaseGeneration: 0 },
|
|
30
|
+
* clientId: 'client-xyz',
|
|
31
|
+
* sessionId: 'session-123'
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* // Pending local event (client=1, not yet synced)
|
|
35
|
+
* const pending: LiveStoreEvent.Client.Encoded = {
|
|
36
|
+
* ...event,
|
|
37
|
+
* seqNum: { global: 5, client: 1, rebaseGeneration: 0 }, // e5.1
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export const Encoded = Schema.Struct({
|
|
42
|
+
name: Schema.String,
|
|
43
|
+
args: Schema.Any,
|
|
44
|
+
seqNum: EventSequenceNumber.Client.Composite,
|
|
45
|
+
parentSeqNum: EventSequenceNumber.Client.Composite,
|
|
46
|
+
clientId: Schema.String,
|
|
47
|
+
sessionId: Schema.String,
|
|
48
|
+
}).annotations({ title: 'LiveStoreEvent.Client.Encoded' })
|
|
49
|
+
|
|
50
|
+
/** Event with composite sequence numbers and decoded (native TypeScript) args. */
|
|
51
|
+
export type Decoded = ForEventDef.Decoded<EventDef.Any>
|
|
52
|
+
|
|
53
|
+
/** Event with composite sequence numbers and encoded (serialized) args. */
|
|
54
|
+
export type Encoded = ForEventDef.Encoded<EventDef.Any>
|
|
55
|
+
|
|
56
|
+
/** Union of all client event types for a given schema (type-safe event discrimination). */
|
|
57
|
+
export type ForSchema<TSchema extends LiveStoreSchema> = {
|
|
58
|
+
[K in keyof TSchema['_EventDefMapType']]: ForEventDef.Decoded<TSchema['_EventDefMapType'][K]>
|
|
59
|
+
}[keyof TSchema['_EventDefMapType']]
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Internal event representation with metadata for sync processing.
|
|
63
|
+
* Includes changeset data and materializer hashes for conflict detection and rebasing.
|
|
64
|
+
*
|
|
65
|
+
* Note: This class is exported for internal use. The preferred access is via `LiveStoreEvent.Client.EncodedWithMeta`.
|
|
66
|
+
*/
|
|
67
|
+
export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('LiveStoreEvent.Client.EncodedWithMeta')({
|
|
68
|
+
name: Schema.String,
|
|
69
|
+
args: Schema.Any,
|
|
70
|
+
seqNum: EventSequenceNumber.Client.Composite,
|
|
71
|
+
parentSeqNum: EventSequenceNumber.Client.Composite,
|
|
72
|
+
clientId: Schema.String,
|
|
73
|
+
sessionId: Schema.String,
|
|
74
|
+
// TODO get rid of `meta` again by cleaning up the usage implementations
|
|
75
|
+
meta: Schema.Struct({
|
|
76
|
+
sessionChangeset: Schema.Union(
|
|
77
|
+
Schema.TaggedStruct('sessionChangeset', {
|
|
78
|
+
data: Schema.Uint8Array as any as Schema.Schema<Uint8Array<ArrayBuffer>>,
|
|
79
|
+
debug: Schema.Any.pipe(Schema.optional),
|
|
80
|
+
}),
|
|
81
|
+
Schema.TaggedStruct('no-op', {}),
|
|
82
|
+
Schema.TaggedStruct('unset', {}),
|
|
83
|
+
),
|
|
84
|
+
syncMetadata: Schema.Option(Schema.JsonValue),
|
|
85
|
+
/** Used to detect if the materializer is side effecting (during dev) */
|
|
86
|
+
materializerHashLeader: Schema.Option(Schema.Number),
|
|
87
|
+
materializerHashSession: Schema.Option(Schema.Number),
|
|
88
|
+
}).pipe(
|
|
89
|
+
Schema.mutable,
|
|
90
|
+
Schema.optional,
|
|
91
|
+
Schema.withDefaults({
|
|
92
|
+
constructor: () => ({
|
|
93
|
+
sessionChangeset: { _tag: 'unset' as const },
|
|
94
|
+
syncMetadata: Option.none(),
|
|
95
|
+
materializerHashLeader: Option.none(),
|
|
96
|
+
materializerHashSession: Option.none(),
|
|
97
|
+
}),
|
|
98
|
+
decoding: () => ({
|
|
99
|
+
sessionChangeset: { _tag: 'unset' as const },
|
|
100
|
+
syncMetadata: Option.none(),
|
|
101
|
+
materializerHashLeader: Option.none(),
|
|
102
|
+
materializerHashSession: Option.none(),
|
|
103
|
+
}),
|
|
104
|
+
}),
|
|
105
|
+
),
|
|
106
|
+
}) {
|
|
107
|
+
toJSON = (): any => {
|
|
108
|
+
// Only used for logging/debugging
|
|
109
|
+
// - More readable way to print the seqNum + parentSeqNum
|
|
110
|
+
// - not including `meta`, `clientId`, `sessionId`
|
|
111
|
+
return {
|
|
112
|
+
seqNum: `${EventSequenceNumber.Client.toString(this.seqNum)} → ${EventSequenceNumber.Client.toString(this.parentSeqNum)} (${this.clientId}, ${this.sessionId})`,
|
|
113
|
+
name: this.name,
|
|
114
|
+
args: this.args,
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Example: (global event)
|
|
120
|
+
* For event e2 → e1 which should be rebased on event e3 → e2
|
|
121
|
+
* the resulting event num will be e4 → e3
|
|
122
|
+
*
|
|
123
|
+
* Example: (client event)
|
|
124
|
+
* For event e2.1 → e2 which should be rebased on event e3 → e2
|
|
125
|
+
* the resulting event num will be e3.1 → e3
|
|
126
|
+
*
|
|
127
|
+
* Syntax: e2.2 → e2.1
|
|
128
|
+
* ^ ^ ^ ^
|
|
129
|
+
* | | | +- client parent number
|
|
130
|
+
* | | +--- global parent number
|
|
131
|
+
* | +-- client number
|
|
132
|
+
* +---- global number
|
|
133
|
+
* Client num is omitted for global events
|
|
134
|
+
*/
|
|
135
|
+
rebase = ({
|
|
136
|
+
parentSeqNum,
|
|
137
|
+
isClient,
|
|
138
|
+
rebaseGeneration,
|
|
139
|
+
}: {
|
|
140
|
+
parentSeqNum: EventSequenceNumber.Client.Composite
|
|
141
|
+
isClient: boolean
|
|
142
|
+
rebaseGeneration: number
|
|
143
|
+
}) =>
|
|
144
|
+
new EncodedWithMeta({
|
|
145
|
+
...this,
|
|
146
|
+
...EventSequenceNumber.Client.nextPair({ seqNum: parentSeqNum, isClient, rebaseGeneration }),
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
static fromGlobal = (
|
|
150
|
+
event: Global.Encoded,
|
|
151
|
+
meta: {
|
|
152
|
+
syncMetadata: Option.Option<Schema.JsonValue>
|
|
153
|
+
materializerHashLeader: Option.Option<number>
|
|
154
|
+
materializerHashSession: Option.Option<number>
|
|
155
|
+
},
|
|
156
|
+
) =>
|
|
157
|
+
new EncodedWithMeta({
|
|
158
|
+
...event,
|
|
159
|
+
seqNum: {
|
|
160
|
+
global: event.seqNum,
|
|
161
|
+
client: EventSequenceNumber.Client.DEFAULT,
|
|
162
|
+
rebaseGeneration: EventSequenceNumber.Client.REBASE_GENERATION_DEFAULT,
|
|
163
|
+
},
|
|
164
|
+
parentSeqNum: {
|
|
165
|
+
global: event.parentSeqNum,
|
|
166
|
+
client: EventSequenceNumber.Client.DEFAULT,
|
|
167
|
+
rebaseGeneration: EventSequenceNumber.Client.REBASE_GENERATION_DEFAULT,
|
|
168
|
+
},
|
|
169
|
+
meta: {
|
|
170
|
+
sessionChangeset: { _tag: 'unset' as const },
|
|
171
|
+
syncMetadata: meta.syncMetadata,
|
|
172
|
+
materializerHashLeader: meta.materializerHashLeader,
|
|
173
|
+
materializerHashSession: meta.materializerHashSession,
|
|
174
|
+
},
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
toGlobal = (): Global.Encoded => ({
|
|
178
|
+
...this,
|
|
179
|
+
seqNum: this.seqNum.global,
|
|
180
|
+
parentSeqNum: this.parentSeqNum.global,
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Structural equality check for client events. Compares seqNum (global + client),
|
|
186
|
+
* name, clientId, sessionId, and args. The `meta` field is ignored.
|
|
187
|
+
*/
|
|
188
|
+
export const isEqualEncoded = (a: Encoded, b: Encoded) =>
|
|
189
|
+
a.seqNum.global === b.seqNum.global &&
|
|
190
|
+
a.seqNum.client === b.seqNum.client &&
|
|
191
|
+
a.name === b.name &&
|
|
192
|
+
a.clientId === b.clientId &&
|
|
193
|
+
a.sessionId === b.sessionId &&
|
|
194
|
+
JSON.stringify(a.args) === JSON.stringify(b.args) // TODO use schema equality here
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Creates an Effect Schema union for all event types in a schema (with composite sequence numbers).
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* const eventSchema = LiveStoreEvent.Client.makeSchema(schema)
|
|
201
|
+
* const event = Schema.decodeUnknownSync(eventSchema)(rawEvent)
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export const makeSchema = <TSchema extends LiveStoreSchema>(
|
|
205
|
+
schema: TSchema,
|
|
206
|
+
): ForEventDef.ForRecord<TSchema['_EventDefMapType']> =>
|
|
207
|
+
Schema.Union(
|
|
208
|
+
...[...schema.eventsDefsMap.values()].map((def) =>
|
|
209
|
+
Schema.Struct({
|
|
210
|
+
name: Schema.Literal(def.name),
|
|
211
|
+
args: def.schema,
|
|
212
|
+
seqNum: EventSequenceNumber.Client.Composite,
|
|
213
|
+
parentSeqNum: EventSequenceNumber.Client.Composite,
|
|
214
|
+
clientId: Schema.String,
|
|
215
|
+
sessionId: Schema.String,
|
|
216
|
+
}),
|
|
217
|
+
),
|
|
218
|
+
).annotations({ title: 'LiveStoreEvent.Client' }) as any
|
|
219
|
+
|
|
220
|
+
/** Memoized `makeSchema` - caches the generated schema by reference. */
|
|
221
|
+
export const makeSchemaMemo = memoizeByRef(makeSchema)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
import type { EventDef, EventDefRecord } from '../EventDef/mod.ts'
|
|
4
|
+
import type * as EventSequenceNumber from '../EventSequenceNumber/mod.ts'
|
|
5
|
+
|
|
6
|
+
/** Event without sequence numbers, with decoded (native TypeScript) args. Used as input to `store.commit()`. */
|
|
7
|
+
export type InputDecoded<TEventDef extends EventDef.Any> = {
|
|
8
|
+
name: TEventDef['name']
|
|
9
|
+
args: Schema.Schema.Type<TEventDef['schema']>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Event without sequence numbers, with encoded (serialized) args. Used as input to `store.commit()`. */
|
|
13
|
+
export type InputEncoded<TEventDef extends EventDef.Any> = {
|
|
14
|
+
name: TEventDef['name']
|
|
15
|
+
args: Schema.Schema.Encoded<TEventDef['schema']>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Full event with composite sequence numbers and decoded args. Includes clientId/sessionId for sync. */
|
|
19
|
+
export type Decoded<TEventDef extends EventDef.Any> = {
|
|
20
|
+
name: TEventDef['name']
|
|
21
|
+
args: Schema.Schema.Type<TEventDef['schema']>
|
|
22
|
+
seqNum: EventSequenceNumber.Client.Composite
|
|
23
|
+
parentSeqNum: EventSequenceNumber.Client.Composite
|
|
24
|
+
clientId: string
|
|
25
|
+
sessionId: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Full event with composite sequence numbers and encoded args. Includes clientId/sessionId for sync. */
|
|
29
|
+
export type Encoded<TEventDef extends EventDef.Any> = {
|
|
30
|
+
name: TEventDef['name']
|
|
31
|
+
args: Schema.Schema.Encoded<TEventDef['schema']>
|
|
32
|
+
seqNum: EventSequenceNumber.Client.Composite
|
|
33
|
+
parentSeqNum: EventSequenceNumber.Client.Composite
|
|
34
|
+
clientId: string
|
|
35
|
+
sessionId: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Effect Schema union of all event types in an EventDefRecord (with composite sequence numbers). */
|
|
39
|
+
export type ForRecord<TEventDefRecord extends EventDefRecord> = Schema.Schema<
|
|
40
|
+
{
|
|
41
|
+
[K in keyof TEventDefRecord]: {
|
|
42
|
+
name: K
|
|
43
|
+
args: Schema.Schema.Type<TEventDefRecord[K]['schema']>
|
|
44
|
+
seqNum: EventSequenceNumber.Client.Composite
|
|
45
|
+
parentSeqNum: EventSequenceNumber.Client.Composite
|
|
46
|
+
clientId: string
|
|
47
|
+
sessionId: string
|
|
48
|
+
}
|
|
49
|
+
}[keyof TEventDefRecord],
|
|
50
|
+
{
|
|
51
|
+
[K in keyof TEventDefRecord]: {
|
|
52
|
+
name: K
|
|
53
|
+
args: Schema.Schema.Encoded<TEventDefRecord[K]['schema']>
|
|
54
|
+
seqNum: EventSequenceNumber.Client.Composite
|
|
55
|
+
parentSeqNum: EventSequenceNumber.Client.Composite
|
|
56
|
+
clientId: string
|
|
57
|
+
sessionId: string
|
|
58
|
+
}
|
|
59
|
+
}[keyof TEventDefRecord]
|
|
60
|
+
>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
import * as EventSequenceNumber from '../EventSequenceNumber/mod.ts'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Effect Schema for global events with integer sequence numbers.
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* const event: LiveStoreEvent.Global.Encoded = {
|
|
10
|
+
* name: 'todoCreated-v1',
|
|
11
|
+
* args: { id: 'abc', text: 'Buy milk' },
|
|
12
|
+
* seqNum: 5, // This event's position in the global log
|
|
13
|
+
* parentSeqNum: 4, // Points to the previous event
|
|
14
|
+
* clientId: 'client-xyz',
|
|
15
|
+
* sessionId: 'session-123'
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export const Encoded = Schema.Struct({
|
|
20
|
+
name: Schema.String,
|
|
21
|
+
args: Schema.Any,
|
|
22
|
+
seqNum: EventSequenceNumber.Global.Schema,
|
|
23
|
+
parentSeqNum: EventSequenceNumber.Global.Schema,
|
|
24
|
+
clientId: Schema.String,
|
|
25
|
+
sessionId: Schema.String,
|
|
26
|
+
}).annotations({ title: 'LiveStoreEvent.Global.Encoded' })
|
|
27
|
+
|
|
28
|
+
/** Event with integer sequence numbers for sync backend wire format. */
|
|
29
|
+
export type Encoded = typeof Encoded.Type
|
|
30
|
+
|
|
31
|
+
/** Converts a Global event to Client format by expanding integer seqNums to composite form. */
|
|
32
|
+
export const toClientEncoded = (
|
|
33
|
+
event: Encoded,
|
|
34
|
+
): {
|
|
35
|
+
name: string
|
|
36
|
+
args: any
|
|
37
|
+
seqNum: EventSequenceNumber.Client.Composite
|
|
38
|
+
parentSeqNum: EventSequenceNumber.Client.Composite
|
|
39
|
+
clientId: string
|
|
40
|
+
sessionId: string
|
|
41
|
+
} => ({
|
|
42
|
+
...event,
|
|
43
|
+
seqNum: EventSequenceNumber.Client.fromGlobal(event.seqNum),
|
|
44
|
+
parentSeqNum: EventSequenceNumber.Client.fromGlobal(event.parentSeqNum),
|
|
45
|
+
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
import type { EventDef, EventDefRecord } from '../EventDef/mod.ts'
|
|
4
|
+
import type { LiveStoreSchema } from '../schema.ts'
|
|
5
|
+
import type * as ForEventDef from './for-event-def.ts'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Effect Schema for validating/decoding input events with encoded args.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { Schema } from '@effect/schema'
|
|
12
|
+
* const decoded = Schema.decodeUnknownSync(LiveStoreEvent.Input.Encoded)(rawEvent)
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export const Encoded = Schema.Struct({
|
|
16
|
+
name: Schema.String,
|
|
17
|
+
args: Schema.Any,
|
|
18
|
+
}).annotations({ title: 'LiveStoreEvent.Input.Encoded' })
|
|
19
|
+
|
|
20
|
+
/** Event without sequence numbers, with decoded (native TypeScript) args. */
|
|
21
|
+
export type Decoded = ForEventDef.InputDecoded<EventDef.Any>
|
|
22
|
+
|
|
23
|
+
/** Event without sequence numbers, with encoded (serialized) args. */
|
|
24
|
+
export type Encoded = ForEventDef.InputEncoded<EventDef.Any>
|
|
25
|
+
|
|
26
|
+
/** Union of all input event types for a given schema (type-safe event discrimination). */
|
|
27
|
+
export type ForSchema<TSchema extends LiveStoreSchema> = {
|
|
28
|
+
[K in keyof TSchema['_EventDefMapType']]: ForEventDef.InputDecoded<TSchema['_EventDefMapType'][K]>
|
|
29
|
+
}[keyof TSchema['_EventDefMapType']]
|
|
30
|
+
|
|
31
|
+
/** Effect Schema union of all event types in an EventDefRecord (input format, no sequence numbers). */
|
|
32
|
+
export type ForRecord<TEventDefRecord extends EventDefRecord> = Schema.Schema<
|
|
33
|
+
{
|
|
34
|
+
[K in keyof TEventDefRecord]: {
|
|
35
|
+
name: K
|
|
36
|
+
args: Schema.Schema.Type<TEventDefRecord[K]['schema']>
|
|
37
|
+
}
|
|
38
|
+
}[keyof TEventDefRecord],
|
|
39
|
+
{
|
|
40
|
+
[K in keyof TEventDefRecord]: {
|
|
41
|
+
name: K
|
|
42
|
+
args: Schema.Schema.Encoded<TEventDefRecord[K]['schema']>
|
|
43
|
+
}
|
|
44
|
+
}[keyof TEventDefRecord]
|
|
45
|
+
>
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Creates an Effect Schema union for all event types in a schema (input format, no sequence numbers).
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const inputSchema = LiveStoreEvent.Input.makeSchema(schema)
|
|
52
|
+
* const event = Schema.decodeUnknownSync(inputSchema)(rawEvent)
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export const makeSchema = <TSchema extends LiveStoreSchema>(schema: TSchema): ForRecord<TSchema['_EventDefMapType']> =>
|
|
56
|
+
Schema.Union(
|
|
57
|
+
...[...schema.eventsDefsMap.values()].map((def) =>
|
|
58
|
+
Schema.Struct({
|
|
59
|
+
name: Schema.Literal(def.name),
|
|
60
|
+
args: def.schema,
|
|
61
|
+
}),
|
|
62
|
+
),
|
|
63
|
+
).annotations({ title: 'LiveStoreEvent.Input' }) as any
|
package/src/schema/events.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { clientOnly, defineEvent, synced } from './EventDef.ts'
|
|
1
|
+
export { clientOnly, defineEvent, synced } from './EventDef/mod.ts'
|
package/src/schema/mod.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from './EventDef.ts'
|
|
2
|
-
export * as EventSequenceNumber from './EventSequenceNumber.ts'
|
|
1
|
+
export * from './EventDef/mod.ts'
|
|
2
|
+
export * as EventSequenceNumber from './EventSequenceNumber/mod.ts'
|
|
3
3
|
export * as Events from './events.ts'
|
|
4
|
-
export * as LiveStoreEvent from './LiveStoreEvent.ts'
|
|
4
|
+
export * as LiveStoreEvent from './LiveStoreEvent/mod.ts'
|
|
5
5
|
export * from './schema.ts'
|
|
6
6
|
export * as State from './state/mod.ts'
|
|
7
7
|
export { SqliteAst, SqliteDsl } from './state/sqlite/db-schema/mod.ts'
|
package/src/schema/schema.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isReadonlyArray, shouldNeverHappen } from '@livestore/utils'
|
|
2
2
|
|
|
3
3
|
import type { MigrationOptions } from '../adapter-types.ts'
|
|
4
|
-
import type { EventDef, EventDefRecord, Materializer } from './EventDef.ts'
|
|
4
|
+
import type { EventDef, EventDefRecord, Materializer } from './EventDef/mod.ts'
|
|
5
5
|
import { tableIsClientDocumentTable } from './state/sqlite/client-document-def.ts'
|
|
6
6
|
import type { SqliteDsl } from './state/sqlite/db-schema/mod.ts'
|
|
7
7
|
import { stateSystemTables } from './state/sqlite/system-tables/state-tables.ts'
|
|
@@ -2,7 +2,7 @@ import { Schema } from '@livestore/utils/effect'
|
|
|
2
2
|
import { describe, expect, test } from 'vitest'
|
|
3
3
|
|
|
4
4
|
import { tables } from '../../../__tests__/fixture.ts'
|
|
5
|
-
import type * as LiveStoreEvent from '../../LiveStoreEvent.ts'
|
|
5
|
+
import type * as LiveStoreEvent from '../../LiveStoreEvent/mod.ts'
|
|
6
6
|
import { ClientDocumentTableDefSymbol, clientDocument, mergeDefaultValues } from './client-document-def.ts'
|
|
7
7
|
|
|
8
8
|
describe('client document table', () => {
|
|
@@ -250,7 +250,7 @@ describe('client document table', () => {
|
|
|
250
250
|
})
|
|
251
251
|
})
|
|
252
252
|
|
|
253
|
-
const patchId = (muationEvent: LiveStoreEvent.
|
|
253
|
+
const patchId = (muationEvent: LiveStoreEvent.Input.Decoded) => {
|
|
254
254
|
// TODO use new id paradigm
|
|
255
255
|
const id = `00000000-0000-0000-0000-000000000000`
|
|
256
256
|
return { ...muationEvent, id }
|
|
@@ -4,8 +4,8 @@ import { Schema } from '@livestore/utils/effect'
|
|
|
4
4
|
|
|
5
5
|
import { SessionIdSymbol } from '../../../adapter-types.ts'
|
|
6
6
|
import { sql } from '../../../util.ts'
|
|
7
|
-
import type { EventDef, Materializer } from '../../EventDef.ts'
|
|
8
|
-
import { defineEvent, defineMaterializer } from '../../EventDef.ts'
|
|
7
|
+
import type { EventDef, Materializer } from '../../EventDef/mod.ts'
|
|
8
|
+
import { defineEvent, defineMaterializer } from '../../EventDef/mod.ts'
|
|
9
9
|
import { SqliteDsl } from './db-schema/mod.ts'
|
|
10
10
|
import type { QueryBuilder, QueryBuilderAst } from './query-builder/mod.ts'
|
|
11
11
|
import { QueryBuilderAstSymbol, QueryBuilderTypeId } from './query-builder/mod.ts'
|
|
@@ -579,5 +579,5 @@ export namespace ClientDocumentTableDef {
|
|
|
579
579
|
) => QueryBuilder<TType, ClientDocumentTableDef.TableDefBase_<TName, TType>, QueryBuilder.ApiFeature>
|
|
580
580
|
}
|
|
581
581
|
|
|
582
|
-
export const ClientDocumentTableDefSymbol = Symbol('ClientDocumentTableDef')
|
|
582
|
+
export const ClientDocumentTableDefSymbol = Symbol.for('livestore.ClientDocumentTableDef')
|
|
583
583
|
export type ClientDocumentTableDefSymbol = typeof ClientDocumentTableDefSymbol
|
|
@@ -299,7 +299,8 @@ describe('getColumnDefForSchema', () => {
|
|
|
299
299
|
describe('binary data', () => {
|
|
300
300
|
it('should handle Uint8Array as blob column', () => {
|
|
301
301
|
const columnDef = State.SQLite.getColumnDefForSchema(Schema.Uint8Array)
|
|
302
|
-
expect(columnDef.columnType).toBe('
|
|
302
|
+
expect(columnDef.columnType).toBe('blob')
|
|
303
|
+
expect(columnDef.schema.toString()).toBe('Uint8ArrayFromSelf')
|
|
303
304
|
})
|
|
304
305
|
})
|
|
305
306
|
|