@livestore/common 0.4.0-dev.0 → 0.4.0-dev.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +7 -2
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
  5. package/dist/adapter-types.d.ts +9 -3
  6. package/dist/adapter-types.d.ts.map +1 -1
  7. package/dist/adapter-types.js.map +1 -1
  8. package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
  9. package/dist/devtools/devtools-messages-common.d.ts +7 -14
  10. package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
  11. package/dist/devtools/devtools-messages-common.js +1 -6
  12. package/dist/devtools/devtools-messages-common.js.map +1 -1
  13. package/dist/devtools/devtools-messages-leader.d.ts +27 -25
  14. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  15. package/dist/errors.d.ts +47 -5
  16. package/dist/errors.d.ts.map +1 -1
  17. package/dist/errors.js +22 -3
  18. package/dist/errors.js.map +1 -1
  19. package/dist/leader-thread/LeaderSyncProcessor.d.ts +7 -3
  20. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  21. package/dist/leader-thread/LeaderSyncProcessor.js +122 -49
  22. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  23. package/dist/leader-thread/eventlog.d.ts +4 -10
  24. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  25. package/dist/leader-thread/eventlog.js +4 -6
  26. package/dist/leader-thread/eventlog.js.map +1 -1
  27. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
  28. package/dist/leader-thread/leader-worker-devtools.js +6 -2
  29. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  30. package/dist/leader-thread/make-leader-thread-layer.d.ts +1 -2
  31. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  32. package/dist/leader-thread/make-leader-thread-layer.js +68 -19
  33. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  34. package/dist/leader-thread/make-leader-thread-layer.test.d.ts +2 -0
  35. package/dist/leader-thread/make-leader-thread-layer.test.d.ts.map +1 -0
  36. package/dist/leader-thread/make-leader-thread-layer.test.js +32 -0
  37. package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -0
  38. package/dist/leader-thread/materialize-event.d.ts +2 -2
  39. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  40. package/dist/leader-thread/materialize-event.js +23 -9
  41. package/dist/leader-thread/materialize-event.js.map +1 -1
  42. package/dist/leader-thread/recreate-db.d.ts +2 -3
  43. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  44. package/dist/leader-thread/recreate-db.js +1 -1
  45. package/dist/leader-thread/recreate-db.js.map +1 -1
  46. package/dist/leader-thread/shutdown-channel.d.ts +2 -2
  47. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  48. package/dist/leader-thread/shutdown-channel.js +2 -2
  49. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  50. package/dist/leader-thread/types.d.ts +7 -5
  51. package/dist/leader-thread/types.d.ts.map +1 -1
  52. package/dist/leader-thread/types.js.map +1 -1
  53. package/dist/materializer-helper.d.ts +1 -1
  54. package/dist/materializer-helper.d.ts.map +1 -1
  55. package/dist/materializer-helper.js +20 -4
  56. package/dist/materializer-helper.js.map +1 -1
  57. package/dist/rematerialize-from-eventlog.d.ts +1 -1
  58. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  59. package/dist/rematerialize-from-eventlog.js +25 -16
  60. package/dist/rematerialize-from-eventlog.js.map +1 -1
  61. package/dist/schema/EventDef.d.ts +3 -0
  62. package/dist/schema/EventDef.d.ts.map +1 -1
  63. package/dist/schema/EventDef.js.map +1 -1
  64. package/dist/schema/LiveStoreEvent.d.ts +1 -1
  65. package/dist/schema/LiveStoreEvent.d.ts.map +1 -1
  66. package/dist/schema/LiveStoreEvent.js +1 -2
  67. package/dist/schema/LiveStoreEvent.js.map +1 -1
  68. package/dist/schema/mod.d.ts +2 -0
  69. package/dist/schema/mod.d.ts.map +1 -1
  70. package/dist/schema/mod.js +1 -0
  71. package/dist/schema/mod.js.map +1 -1
  72. package/dist/schema/schema.d.ts +15 -0
  73. package/dist/schema/schema.d.ts.map +1 -1
  74. package/dist/schema/schema.js +26 -1
  75. package/dist/schema/schema.js.map +1 -1
  76. package/dist/schema/state/sqlite/client-document-def.d.ts +35 -5
  77. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  78. package/dist/schema/state/sqlite/client-document-def.js +95 -4
  79. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  80. package/dist/schema/state/sqlite/client-document-def.test.js +16 -0
  81. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  82. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  83. package/dist/schema/state/sqlite/column-annotations.js +14 -6
  84. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  85. package/dist/schema/state/sqlite/column-def.d.ts +19 -0
  86. package/dist/schema/state/sqlite/column-def.d.ts.map +1 -0
  87. package/dist/schema/state/sqlite/column-def.js +179 -0
  88. package/dist/schema/state/sqlite/column-def.js.map +1 -0
  89. package/dist/schema/state/sqlite/column-def.test.d.ts +2 -0
  90. package/dist/schema/state/sqlite/column-def.test.d.ts.map +1 -0
  91. package/dist/schema/state/sqlite/column-def.test.js +572 -0
  92. package/dist/schema/state/sqlite/column-def.test.js.map +1 -0
  93. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +2 -1
  94. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
  95. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +23 -6
  96. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  97. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  98. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +2 -1
  99. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  100. package/dist/schema/state/sqlite/mod.d.ts +1 -1
  101. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  102. package/dist/schema/state/sqlite/mod.js +1 -1
  103. package/dist/schema/state/sqlite/mod.js.map +1 -1
  104. package/dist/schema/state/sqlite/query-builder/api.d.ts +5 -2
  105. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  106. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  107. package/dist/schema/state/sqlite/query-builder/impl.js +6 -2
  108. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  109. package/dist/schema/state/sqlite/query-builder/impl.test.js +137 -2
  110. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  111. package/dist/schema/state/sqlite/system-tables.d.ts +42 -6
  112. package/dist/schema/state/sqlite/system-tables.d.ts.map +1 -1
  113. package/dist/schema/state/sqlite/system-tables.js +2 -0
  114. package/dist/schema/state/sqlite/system-tables.js.map +1 -1
  115. package/dist/schema/state/sqlite/table-def.d.ts +6 -8
  116. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  117. package/dist/schema/state/sqlite/table-def.js +4 -211
  118. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  119. package/dist/schema/state/sqlite/table-def.test.js +59 -453
  120. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  121. package/dist/schema/unknown-events.d.ts +47 -0
  122. package/dist/schema/unknown-events.d.ts.map +1 -0
  123. package/dist/schema/unknown-events.js +69 -0
  124. package/dist/schema/unknown-events.js.map +1 -0
  125. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  126. package/dist/sql-queries/sql-query-builder.js +2 -1
  127. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  128. package/dist/sync/ClientSessionSyncProcessor.d.ts +9 -11
  129. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  130. package/dist/sync/ClientSessionSyncProcessor.js +35 -33
  131. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  132. package/dist/sync/errors.d.ts +61 -0
  133. package/dist/sync/errors.d.ts.map +1 -0
  134. package/dist/sync/errors.js +36 -0
  135. package/dist/sync/errors.js.map +1 -0
  136. package/dist/sync/index.d.ts +3 -0
  137. package/dist/sync/index.d.ts.map +1 -1
  138. package/dist/sync/index.js +3 -0
  139. package/dist/sync/index.js.map +1 -1
  140. package/dist/sync/mock-sync-backend.d.ts +23 -0
  141. package/dist/sync/mock-sync-backend.d.ts.map +1 -0
  142. package/dist/sync/mock-sync-backend.js +114 -0
  143. package/dist/sync/mock-sync-backend.js.map +1 -0
  144. package/dist/sync/next/compact-events.d.ts.map +1 -1
  145. package/dist/sync/next/compact-events.js +4 -5
  146. package/dist/sync/next/compact-events.js.map +1 -1
  147. package/dist/sync/next/facts.d.ts.map +1 -1
  148. package/dist/sync/next/facts.js +1 -2
  149. package/dist/sync/next/facts.js.map +1 -1
  150. package/dist/sync/next/history-dag-common.d.ts +50 -11
  151. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  152. package/dist/sync/next/history-dag-common.js +193 -4
  153. package/dist/sync/next/history-dag-common.js.map +1 -1
  154. package/dist/sync/next/history-dag.d.ts.map +1 -1
  155. package/dist/sync/next/history-dag.js +3 -1
  156. package/dist/sync/next/history-dag.js.map +1 -1
  157. package/dist/sync/sync-backend-kv.d.ts +7 -0
  158. package/dist/sync/sync-backend-kv.d.ts.map +1 -0
  159. package/dist/sync/sync-backend-kv.js +18 -0
  160. package/dist/sync/sync-backend-kv.js.map +1 -0
  161. package/dist/sync/sync-backend.d.ts +105 -0
  162. package/dist/sync/sync-backend.d.ts.map +1 -0
  163. package/dist/sync/sync-backend.js +61 -0
  164. package/dist/sync/sync-backend.js.map +1 -0
  165. package/dist/sync/sync.d.ts +6 -84
  166. package/dist/sync/sync.d.ts.map +1 -1
  167. package/dist/sync/sync.js +2 -27
  168. package/dist/sync/sync.js.map +1 -1
  169. package/dist/sync/transport-chunking.d.ts +36 -0
  170. package/dist/sync/transport-chunking.d.ts.map +1 -0
  171. package/dist/sync/transport-chunking.js +56 -0
  172. package/dist/sync/transport-chunking.js.map +1 -0
  173. package/dist/sync/validate-push-payload.d.ts +1 -1
  174. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  175. package/dist/sync/validate-push-payload.js +6 -6
  176. package/dist/sync/validate-push-payload.js.map +1 -1
  177. package/dist/testing/event-factory.d.ts +68 -0
  178. package/dist/testing/event-factory.d.ts.map +1 -0
  179. package/dist/testing/event-factory.js +80 -0
  180. package/dist/testing/event-factory.js.map +1 -0
  181. package/dist/testing/mod.d.ts +2 -0
  182. package/dist/testing/mod.d.ts.map +1 -0
  183. package/dist/testing/mod.js +2 -0
  184. package/dist/testing/mod.js.map +1 -0
  185. package/dist/version.d.ts +2 -2
  186. package/dist/version.d.ts.map +1 -1
  187. package/dist/version.js +2 -2
  188. package/dist/version.js.map +1 -1
  189. package/package.json +7 -8
  190. package/src/ClientSessionLeaderThreadProxy.ts +7 -2
  191. package/src/adapter-types.ts +13 -3
  192. package/src/devtools/devtools-messages-common.ts +1 -8
  193. package/src/errors.ts +33 -4
  194. package/src/leader-thread/LeaderSyncProcessor.ts +179 -57
  195. package/src/leader-thread/eventlog.ts +10 -6
  196. package/src/leader-thread/leader-worker-devtools.ts +6 -2
  197. package/src/leader-thread/make-leader-thread-layer.test.ts +44 -0
  198. package/src/leader-thread/make-leader-thread-layer.ts +137 -26
  199. package/src/leader-thread/materialize-event.ts +34 -9
  200. package/src/leader-thread/recreate-db.ts +11 -3
  201. package/src/leader-thread/shutdown-channel.ts +16 -2
  202. package/src/leader-thread/types.ts +7 -5
  203. package/src/materializer-helper.ts +22 -5
  204. package/src/rematerialize-from-eventlog.ts +33 -23
  205. package/src/schema/EventDef.ts +3 -0
  206. package/src/schema/LiveStoreEvent.ts +1 -2
  207. package/src/schema/mod.ts +2 -0
  208. package/src/schema/schema.ts +37 -1
  209. package/src/schema/state/sqlite/client-document-def.test.ts +17 -0
  210. package/src/schema/state/sqlite/client-document-def.ts +117 -5
  211. package/src/schema/state/sqlite/column-annotations.ts +16 -6
  212. package/src/schema/state/sqlite/column-def.test.ts +722 -0
  213. package/src/schema/state/sqlite/column-def.ts +215 -0
  214. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +26 -6
  215. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +2 -1
  216. package/src/schema/state/sqlite/mod.ts +1 -0
  217. package/src/schema/state/sqlite/query-builder/api.ts +7 -2
  218. package/src/schema/state/sqlite/query-builder/impl.test.ts +187 -6
  219. package/src/schema/state/sqlite/query-builder/impl.ts +8 -2
  220. package/src/schema/state/sqlite/system-tables.ts +2 -0
  221. package/src/schema/state/sqlite/table-def.test.ts +74 -569
  222. package/src/schema/state/sqlite/table-def.ts +13 -262
  223. package/src/schema/unknown-events.ts +131 -0
  224. package/src/sql-queries/sql-query-builder.ts +2 -1
  225. package/src/sync/ClientSessionSyncProcessor.ts +55 -49
  226. package/src/sync/errors.ts +38 -0
  227. package/src/sync/index.ts +3 -0
  228. package/src/sync/mock-sync-backend.ts +184 -0
  229. package/src/sync/next/compact-events.ts +4 -5
  230. package/src/sync/next/facts.ts +1 -3
  231. package/src/sync/next/history-dag-common.ts +272 -21
  232. package/src/sync/next/history-dag.ts +3 -1
  233. package/src/sync/sync-backend-kv.ts +22 -0
  234. package/src/sync/sync-backend.ts +185 -0
  235. package/src/sync/sync.ts +6 -89
  236. package/src/sync/transport-chunking.ts +90 -0
  237. package/src/sync/validate-push-payload.ts +6 -7
  238. package/src/testing/event-factory.ts +133 -0
  239. package/src/testing/mod.ts +1 -0
  240. package/src/version.ts +2 -2
  241. package/dist/schema-management/migrations.test.d.ts +0 -2
  242. package/dist/schema-management/migrations.test.d.ts.map +0 -1
  243. package/dist/schema-management/migrations.test.js +0 -52
  244. package/dist/schema-management/migrations.test.js.map +0 -1
  245. package/dist/sync/next/graphology.d.ts +0 -8
  246. package/dist/sync/next/graphology.d.ts.map +0 -1
  247. package/dist/sync/next/graphology.js +0 -30
  248. package/dist/sync/next/graphology.js.map +0 -1
  249. package/dist/sync/next/graphology_.d.ts +0 -3
  250. package/dist/sync/next/graphology_.d.ts.map +0 -1
  251. package/dist/sync/next/graphology_.js +0 -3
  252. package/dist/sync/next/graphology_.js.map +0 -1
  253. package/src/sync/next/ambient.d.ts +0 -3
  254. package/src/sync/next/graphology.ts +0 -41
  255. package/src/sync/next/graphology_.ts +0 -2
@@ -1,13 +1,29 @@
1
- import { shouldNeverHappen } from '@livestore/utils'
1
+ import { omitUndefineds, shouldNeverHappen } from '@livestore/utils'
2
2
  import type { HttpClient, Schema, Scope } from '@livestore/utils/effect'
3
- import { Deferred, Effect, Layer, Queue, SubscriptionRef } from '@livestore/utils/effect'
4
-
5
- import type { BootStatus, MakeSqliteDb, SqliteDb, SqliteError } from '../adapter-types.ts'
6
- import { UnexpectedError } from '../adapter-types.ts'
3
+ import {
4
+ Deferred,
5
+ Effect,
6
+ KeyValueStore,
7
+ Layer,
8
+ PlatformError,
9
+ Queue,
10
+ Stream,
11
+ Subscribable,
12
+ SubscriptionRef,
13
+ } from '@livestore/utils/effect'
14
+ import {
15
+ type BootStatus,
16
+ type MakeSqliteDb,
17
+ type MaterializerHashMismatchError,
18
+ type SqliteDb,
19
+ type SqliteError,
20
+ UnexpectedError,
21
+ } from '../adapter-types.ts'
22
+ import type { MigrationsReport } from '../defs.ts'
7
23
  import type * as Devtools from '../devtools/mod.ts'
8
24
  import type { LiveStoreSchema } from '../schema/mod.ts'
9
25
  import { EventSequenceNumber, LiveStoreEvent, SystemTables } from '../schema/mod.ts'
10
- import type { InvalidPullError, IsOfflineError, SyncOptions } from '../sync/sync.ts'
26
+ import type { InvalidPullError, IsOfflineError, SyncBackend, SyncOptions } from '../sync/sync.ts'
11
27
  import { SyncState } from '../sync/syncstate.ts'
12
28
  import { sql } from '../util.ts'
13
29
  import * as Eventlog from './eventlog.ts'
@@ -17,6 +33,7 @@ import { makeMaterializeEvent } from './materialize-event.ts'
17
33
  import { recreateDb } from './recreate-db.ts'
18
34
  import type { ShutdownChannel } from './shutdown-channel.ts'
19
35
  import type {
36
+ DevtoolsContext,
20
37
  DevtoolsOptions,
21
38
  InitialBlockingSyncContext,
22
39
  InitialSyncOptions,
@@ -71,10 +88,45 @@ export const makeLeaderThreadLayer = ({
71
88
  // Either happens on initial boot or if schema changes
72
89
  const dbStateMissing = !hasStateTables(dbState)
73
90
 
91
+ yield* Eventlog.initEventlogDb(dbEventlog)
92
+
74
93
  const syncBackend =
75
94
  syncOptions?.backend === undefined
76
95
  ? undefined
77
- : yield* syncOptions.backend({ storeId, clientId, payload: syncPayload })
96
+ : yield* syncOptions.backend({ storeId, clientId, payload: syncPayload }).pipe(
97
+ Effect.provide(
98
+ Layer.succeed(
99
+ KeyValueStore.KeyValueStore,
100
+ KeyValueStore.makeStringOnly({
101
+ get: (_key) =>
102
+ Effect.sync(() => Eventlog.getBackendIdFromDb(dbEventlog)).pipe(
103
+ Effect.catchAllDefect((cause) =>
104
+ PlatformError.BadArgument.make({
105
+ method: 'getBackendIdFromDb',
106
+ description: 'Failed to get backendId',
107
+ module: 'KeyValueStore',
108
+ cause,
109
+ }),
110
+ ),
111
+ ),
112
+ set: (_key, value) =>
113
+ Effect.sync(() => Eventlog.updateBackendId(dbEventlog, value)).pipe(
114
+ Effect.catchAllDefect((cause) =>
115
+ PlatformError.BadArgument.make({
116
+ method: 'updateBackendId',
117
+ module: 'KeyValueStore',
118
+ description: 'Failed to update backendId',
119
+ cause,
120
+ }),
121
+ ),
122
+ ),
123
+ clear: Effect.dieMessage(`Not implemented. Should never be used.`),
124
+ remove: () => Effect.dieMessage(`Not implemented. Should never be used.`),
125
+ size: Effect.dieMessage(`Not implemented. Should never be used.`),
126
+ }),
127
+ ),
128
+ ),
129
+ )
78
130
 
79
131
  if (syncBackend !== undefined) {
80
132
  // We're already connecting to the sync backend concurrently
@@ -86,18 +138,29 @@ export const makeLeaderThreadLayer = ({
86
138
  bootStatusQueue,
87
139
  })
88
140
 
141
+ const materializeEvent = yield* makeMaterializeEvent({ schema, dbState, dbEventlog })
142
+
143
+ // Recreate state database if needed BEFORE creating sync processor
144
+ // This ensures all system tables exist before any queries are made
145
+ const { migrationsReport } = dbStateMissing
146
+ ? yield* recreateDb({ dbState, dbEventlog, schema, bootStatusQueue, materializeEvent })
147
+ : { migrationsReport: { migrations: [] } }
148
+
89
149
  const syncProcessor = yield* makeLeaderSyncProcessor({
90
150
  schema,
91
151
  dbState,
92
152
  initialSyncState: getInitialSyncState({ dbEventlog, dbState, dbEventlogMissing }),
93
153
  initialBlockingSyncContext,
94
154
  onError: syncOptions?.onSyncError ?? 'ignore',
155
+ livePull: syncOptions?.livePull ?? true,
95
156
  params: {
96
- localPushBatchSize: params?.localPushBatchSize,
97
- backendPushBatchSize: params?.backendPushBatchSize,
157
+ ...omitUndefineds({
158
+ localPushBatchSize: params?.localPushBatchSize,
159
+ backendPushBatchSize: params?.backendPushBatchSize,
160
+ }),
98
161
  },
99
162
  testing: {
100
- delays: testing?.syncProcessor?.delays,
163
+ ...omitUndefineds({ delays: testing?.syncProcessor?.delays }),
101
164
  },
102
165
  })
103
166
 
@@ -113,7 +176,7 @@ export const makeLeaderThreadLayer = ({
113
176
  }
114
177
  : { enabled: false as const }
115
178
 
116
- const materializeEvent = yield* makeMaterializeEvent({ schema, dbState, dbEventlog })
179
+ const networkStatus = yield* makeNetworkStatusSubscribable({ syncBackend, devtoolsContext })
117
180
 
118
181
  const ctx = {
119
182
  schema,
@@ -131,6 +194,7 @@ export const makeLeaderThreadLayer = ({
131
194
  materializeEvent,
132
195
  extraIncomingMessagesQueue,
133
196
  devtools: devtoolsContext,
197
+ networkStatus,
134
198
  // State will be set during `bootLeaderThread`
135
199
  initialState: {} as any as LeaderThreadCtx['Type']['initialState'],
136
200
  } satisfies typeof LeaderThreadCtx.Service
@@ -141,7 +205,7 @@ export const makeLeaderThreadLayer = ({
141
205
  const layer = Layer.succeed(LeaderThreadCtx, ctx)
142
206
 
143
207
  ctx.initialState = yield* bootLeaderThread({
144
- dbStateMissing,
208
+ migrationsReport,
145
209
  initialBlockingSyncContext,
146
210
  devtoolsOptions,
147
211
  }).pipe(Effect.provide(layer))
@@ -244,12 +308,12 @@ const makeInitialBlockingSyncContext = ({
244
308
 
245
309
  return {
246
310
  blockingDeferred,
247
- update: ({ processed, remaining }) =>
311
+ update: ({ processed, pageInfo }) =>
248
312
  Effect.gen(function* () {
249
313
  if (ctx.isDone === true) return
250
314
 
251
- if (ctx.total === -1) {
252
- ctx.total = remaining + processed
315
+ if (ctx.total === -1 && pageInfo._tag === 'MoreKnown') {
316
+ ctx.total = pageInfo.remaining + processed
253
317
  }
254
318
 
255
319
  ctx.processedEvents += processed
@@ -258,7 +322,7 @@ const makeInitialBlockingSyncContext = ({
258
322
  progress: { done: ctx.processedEvents, total: ctx.total },
259
323
  })
260
324
 
261
- if (remaining === 0 && blockingDeferred !== undefined) {
325
+ if (pageInfo._tag === 'NoMore' && blockingDeferred !== undefined) {
262
326
  yield* Deferred.succeed(blockingDeferred, void 0)
263
327
  ctx.isDone = true
264
328
  }
@@ -271,26 +335,20 @@ const makeInitialBlockingSyncContext = ({
271
335
  * It also starts various background processes (e.g. syncing)
272
336
  */
273
337
  const bootLeaderThread = ({
274
- dbStateMissing,
338
+ migrationsReport,
275
339
  initialBlockingSyncContext,
276
340
  devtoolsOptions,
277
341
  }: {
278
- dbStateMissing: boolean
342
+ migrationsReport: MigrationsReport
279
343
  initialBlockingSyncContext: InitialBlockingSyncContext
280
344
  devtoolsOptions: DevtoolsOptions
281
345
  }): Effect.Effect<
282
346
  LeaderThreadCtx['Type']['initialState'],
283
- UnexpectedError | SqliteError | IsOfflineError | InvalidPullError,
347
+ UnexpectedError | SqliteError | IsOfflineError | InvalidPullError | MaterializerHashMismatchError,
284
348
  LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
285
349
  > =>
286
350
  Effect.gen(function* () {
287
- const { dbEventlog, bootStatusQueue, syncProcessor, schema, materializeEvent, dbState } = yield* LeaderThreadCtx
288
-
289
- yield* Eventlog.initEventlogDb(dbEventlog)
290
-
291
- const { migrationsReport } = dbStateMissing
292
- ? yield* recreateDb({ dbState, dbEventlog, schema, bootStatusQueue, materializeEvent })
293
- : { migrationsReport: { migrations: [] } }
351
+ const { bootStatusQueue, syncProcessor } = yield* LeaderThreadCtx
294
352
 
295
353
  // NOTE the sync processor depends on the dbs being initialized properly
296
354
  const { initialLeaderHead } = yield* syncProcessor.boot
@@ -313,3 +371,56 @@ const bootLeaderThread = ({
313
371
 
314
372
  return { migrationsReport, leaderHead: initialLeaderHead }
315
373
  })
374
+
375
+ /** @internal */
376
+ export const makeNetworkStatusSubscribable = ({
377
+ syncBackend,
378
+ devtoolsContext,
379
+ }: {
380
+ syncBackend: SyncBackend.SyncBackend | undefined
381
+ devtoolsContext: DevtoolsContext
382
+ }): Effect.Effect<Subscribable.Subscribable<SyncBackend.NetworkStatus>, never, Scope.Scope> =>
383
+ Effect.gen(function* () {
384
+ const initialIsConnected = syncBackend !== undefined ? yield* SubscriptionRef.get(syncBackend.isConnected) : false
385
+ const initialLatchClosed =
386
+ devtoolsContext.enabled === true
387
+ ? (yield* SubscriptionRef.get(devtoolsContext.syncBackendLatchState)).latchClosed
388
+ : false
389
+
390
+ const networkStatusRef = yield* SubscriptionRef.make<SyncBackend.NetworkStatus>({
391
+ isConnected: initialIsConnected,
392
+ timestampMs: Date.now(),
393
+ devtools: { latchClosed: initialLatchClosed },
394
+ })
395
+
396
+ const updateNetworkStatus = (patch: { isConnected?: boolean; latchClosed?: boolean }) =>
397
+ SubscriptionRef.update(networkStatusRef, (previous) => ({
398
+ isConnected: patch.isConnected ?? previous.isConnected,
399
+ timestampMs: Date.now(),
400
+ devtools: {
401
+ latchClosed: patch.latchClosed ?? previous.devtools.latchClosed,
402
+ },
403
+ }))
404
+
405
+ if (syncBackend !== undefined) {
406
+ yield* syncBackend.isConnected.changes.pipe(
407
+ Stream.tap((isConnected) => updateNetworkStatus({ isConnected })),
408
+ Stream.runDrain,
409
+ Effect.interruptible,
410
+ Effect.tapCauseLogPretty,
411
+ Effect.forkScoped,
412
+ )
413
+ }
414
+
415
+ if (devtoolsContext.enabled === true) {
416
+ yield* devtoolsContext.syncBackendLatchState.changes.pipe(
417
+ Stream.tap(({ latchClosed }) => updateNetworkStatus({ latchClosed })),
418
+ Stream.runDrain,
419
+ Effect.interruptible,
420
+ Effect.tapCauseLogPretty,
421
+ Effect.forkScoped,
422
+ )
423
+ }
424
+
425
+ return Subscribable.fromSubscriptionRef(networkStatusRef)
426
+ })
@@ -1,16 +1,17 @@
1
1
  import { isDevEnv, LS_DEV, shouldNeverHappen } from '@livestore/utils'
2
2
  import { Effect, Option, ReadonlyArray, Schema } from '@livestore/utils/effect'
3
3
 
4
- import { type SqliteDb, UnexpectedError } from '../adapter-types.ts'
4
+ import { MaterializeError, MaterializerHashMismatchError, type SqliteDb } from '../adapter-types.ts'
5
5
  import { getExecStatementsFromMaterializer, hashMaterializerResults } from '../materializer-helper.ts'
6
6
  import type { LiveStoreSchema } from '../schema/mod.ts'
7
- import { EventSequenceNumber, getEventDef, SystemTables } from '../schema/mod.ts'
7
+ import { EventSequenceNumber, resolveEventDef, SystemTables, UNKNOWN_EVENT_SCHEMA_HASH } from '../schema/mod.ts'
8
8
  import { insertRow } from '../sql-queries/index.ts'
9
9
  import { sql } from '../util.ts'
10
10
  import { execSql, execSqlPrepared } from './connection.ts'
11
11
  import * as Eventlog from './eventlog.ts'
12
12
  import type { MaterializeEvent } from './types.ts'
13
13
 
14
+ // TODO refactor `makeMaterializeEvent` to not return an Effect for the constructor as it's not needed
14
15
  export const makeMaterializeEvent = ({
15
16
  schema,
16
17
  dbState,
@@ -19,7 +20,7 @@ export const makeMaterializeEvent = ({
19
20
  schema: LiveStoreSchema
20
21
  dbState: SqliteDb
21
22
  dbEventlog: SqliteDb
22
- }): Effect.Effect<MaterializeEvent, UnexpectedError> =>
23
+ }): Effect.Effect<MaterializeEvent> =>
23
24
  Effect.gen(function* () {
24
25
  const eventDefSchemaHashMap = new Map(
25
26
  // TODO Running `Schema.hash` can be a bottleneck for larger schemas. There is an opportunity to run this
@@ -32,8 +33,34 @@ export const makeMaterializeEvent = ({
32
33
  Effect.gen(function* () {
33
34
  const skipEventlog = options?.skipEventlog ?? false
34
35
 
35
- const eventName = eventEncoded.name
36
- const { eventDef, materializer } = getEventDef(schema, eventName)
36
+ const resolution = yield* resolveEventDef(schema, {
37
+ operation: '@livestore/common:leader-thread:materializeEvent',
38
+ event: eventEncoded,
39
+ })
40
+
41
+ if (resolution._tag === 'unknown') {
42
+ // Unknown events still enter the eventlog so newer clients can replay
43
+ // them once they learn the schema. We skip materialization to keep the
44
+ // local state consistent with the knowledge of the current client.
45
+ if (skipEventlog === false) {
46
+ yield* Eventlog.insertIntoEventlog(
47
+ eventEncoded,
48
+ dbEventlog,
49
+ UNKNOWN_EVENT_SCHEMA_HASH,
50
+ eventEncoded.clientId,
51
+ eventEncoded.sessionId,
52
+ )
53
+ }
54
+
55
+ dbState.debug.head = eventEncoded.seqNum
56
+
57
+ return {
58
+ sessionChangeset: { _tag: 'no-op' as const },
59
+ hash: Option.none(),
60
+ }
61
+ }
62
+
63
+ const { eventDef, materializer } = resolution
37
64
 
38
65
  const execArgsArr = getExecStatementsFromMaterializer({
39
66
  eventDef,
@@ -49,10 +76,7 @@ export const makeMaterializeEvent = ({
49
76
  eventEncoded.meta.materializerHashSession._tag === 'Some' &&
50
77
  eventEncoded.meta.materializerHashSession.value !== materializerHash.value
51
78
  ) {
52
- yield* UnexpectedError.make({
53
- cause: `Materializer hash mismatch detected for event "${eventEncoded.name}".`,
54
- note: `Please make sure your event materializer is a pure function without side effects.`,
55
- })
79
+ return yield* MaterializerHashMismatchError.make({ eventName: eventEncoded.name })
56
80
  }
57
81
 
58
82
  // NOTE we might want to bring this back if we want to debug no-op events
@@ -126,6 +150,7 @@ export const makeMaterializeEvent = ({
126
150
  hash: materializerHash,
127
151
  }
128
152
  }).pipe(
153
+ Effect.mapError((cause) => MaterializeError.make({ cause })),
129
154
  Effect.withSpan(`@livestore/common:leader-thread:materializeEvent`, {
130
155
  attributes: {
131
156
  eventName: eventEncoded.name,
@@ -2,8 +2,16 @@ import { casesHandled } from '@livestore/utils'
2
2
  import { Effect, Queue } from '@livestore/utils/effect'
3
3
 
4
4
  import type { MigrationsReport } from '../defs.ts'
5
- import type { BootStatus, MigrationHooks, SqliteDb, SqliteError } from '../index.ts'
6
- import { migrateDb, rematerializeFromEventlog, UnexpectedError } from '../index.ts'
5
+ import {
6
+ type BootStatus,
7
+ type MaterializeError,
8
+ type MigrationHooks,
9
+ migrateDb,
10
+ rematerializeFromEventlog,
11
+ type SqliteDb,
12
+ type SqliteError,
13
+ UnexpectedError,
14
+ } from '../index.ts'
7
15
  import type { LiveStoreSchema } from '../schema/mod.ts'
8
16
  import { configureConnection } from './connection.ts'
9
17
  import type { MaterializeEvent } from './types.ts'
@@ -20,7 +28,7 @@ export const recreateDb = ({
20
28
  schema: LiveStoreSchema
21
29
  bootStatusQueue: Queue.Queue<BootStatus>
22
30
  materializeEvent: MaterializeEvent
23
- }): Effect.Effect<{ migrationsReport: MigrationsReport }, UnexpectedError | SqliteError> =>
31
+ }): Effect.Effect<{ migrationsReport: MigrationsReport }, UnexpectedError | MaterializeError | SqliteError> =>
24
32
  Effect.gen(function* () {
25
33
  const migrationOptions = schema.state.sqlite.migrations
26
34
  let migrationsReport: MigrationsReport
@@ -1,9 +1,23 @@
1
1
  import type { WebChannel } from '@livestore/utils/effect'
2
2
  import { Schema } from '@livestore/utils/effect'
3
3
 
4
- import { IntentionalShutdownCause, SyncError, UnexpectedError } from '../index.ts'
4
+ import {
5
+ IntentionalShutdownCause,
6
+ InvalidPullError,
7
+ InvalidPushError,
8
+ IsOfflineError,
9
+ MaterializeError,
10
+ UnexpectedError,
11
+ } from '../index.ts'
5
12
 
6
- export class All extends Schema.Union(IntentionalShutdownCause, UnexpectedError, SyncError) {}
13
+ export class All extends Schema.Union(
14
+ IntentionalShutdownCause,
15
+ UnexpectedError,
16
+ IsOfflineError,
17
+ InvalidPushError,
18
+ InvalidPullError,
19
+ MaterializeError,
20
+ ) {}
7
21
 
8
22
  /**
9
23
  * Used internally by an adapter to shutdown gracefully.
@@ -13,7 +13,7 @@ import { Context, Schema } from '@livestore/utils/effect'
13
13
  import type { MeshNode } from '@livestore/webmesh'
14
14
 
15
15
  import type { MigrationsReport } from '../defs.ts'
16
- import type { SqliteError } from '../errors.ts'
16
+ import type { MaterializeError } from '../errors.ts'
17
17
  import type {
18
18
  BootStatus,
19
19
  Devtools,
@@ -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
- cursor: EventSequenceNumber.EventSequenceNumber
46
+ eventSequenceNumber: EventSequenceNumber.GlobalEventSequenceNumber
47
47
  metadata: Option.Option<Schema.JsonValue>
48
48
  }>
49
49
 
@@ -98,7 +98,7 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
98
98
  shutdownChannel: ShutdownChannel
99
99
  eventSchema: LiveStoreEvent.ForEventDefRecord<any>
100
100
  devtools: DevtoolsContext
101
- syncBackend: SyncBackend | undefined
101
+ syncBackend: SyncBackend.SyncBackend | undefined
102
102
  syncProcessor: LeaderSyncProcessor
103
103
  materializeEvent: MaterializeEvent
104
104
  initialState: {
@@ -111,6 +111,7 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
111
111
  * This is currently separated from `.devtools` as it also needs to work when devtools are disabled
112
112
  */
113
113
  extraIncomingMessagesQueue: Queue.Queue<Devtools.Leader.MessageToApp>
114
+ networkStatus: Subscribable.Subscribable<SyncBackend.NetworkStatus>
114
115
  }
115
116
  >() {}
116
117
 
@@ -125,12 +126,12 @@ export type MaterializeEvent = (
125
126
  sessionChangeset: { _tag: 'sessionChangeset'; data: Uint8Array<ArrayBuffer>; debug: any } | { _tag: 'no-op' }
126
127
  hash: Option.Option<number>
127
128
  },
128
- SqliteError | UnexpectedError
129
+ MaterializeError
129
130
  >
130
131
 
131
132
  export type InitialBlockingSyncContext = {
132
133
  blockingDeferred: Deferred.Deferred<void> | undefined
133
- update: (_: { remaining: number; processed: number }) => Effect.Effect<void>
134
+ update: (_: { pageInfo: SyncBackend.PullResPageInfo; processed: number }) => Effect.Effect<void>
134
135
  }
135
136
 
136
137
  export interface LeaderSyncProcessor {
@@ -150,6 +151,7 @@ export interface LeaderSyncProcessor {
150
151
  options?: {
151
152
  /**
152
153
  * If true, the effect will only finish when the local push has been processed (i.e. succeeded or was rejected).
154
+ * `true` doesn't mean the events have been pushed to the sync backend.
153
155
  * @default false
154
156
  */
155
157
  waitForProcessing?: boolean
@@ -5,7 +5,7 @@ import type { SqliteDb } from './adapter-types.ts'
5
5
  import { SessionIdSymbol } from './adapter-types.ts'
6
6
  import type { EventDef, Materializer, MaterializerContextQuery, MaterializerResult } from './schema/EventDef.ts'
7
7
  import type * as LiveStoreEvent from './schema/LiveStoreEvent.ts'
8
- import { getEventDef, type LiveStoreSchema } from './schema/schema.ts'
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'
11
11
  import { getResultSchema } from './schema/state/sqlite/query-builder/impl.ts'
@@ -31,8 +31,13 @@ export const getExecStatementsFromMaterializer = ({
31
31
  bindValues: PreparedBindValues
32
32
  writeTables: ReadonlySet<string> | undefined
33
33
  }> => {
34
- const eventArgsDecoded =
35
- event.decoded === undefined ? Schema.decodeUnknownSync(eventDef.schema)(event.encoded!.args) : event.decoded.args
34
+ const eventDecoded =
35
+ event.decoded === undefined
36
+ ? {
37
+ ...event.encoded!,
38
+ args: Schema.decodeUnknownSync(eventDef.schema)(event.encoded!.args),
39
+ }
40
+ : event.decoded
36
41
 
37
42
  const eventArgsEncoded = isNil(event.decoded?.args)
38
43
  ? undefined
@@ -58,11 +63,12 @@ export const getExecStatementsFromMaterializer = ({
58
63
  }
59
64
 
60
65
  const statementResults = fromMaterializerResult(
61
- materializer(eventArgsDecoded, {
66
+ materializer(eventDecoded.args, {
62
67
  eventDef,
63
68
  query,
64
69
  // TODO properly implement this
65
70
  currentFacts: new Map(),
71
+ event: eventDecoded,
66
72
  }),
67
73
  )
68
74
 
@@ -81,7 +87,18 @@ export const makeMaterializerHash =
81
87
  ({ schema, dbState }: { schema: LiveStoreSchema; dbState: SqliteDb }) =>
82
88
  (event: LiveStoreEvent.AnyEncoded): Option.Option<number> => {
83
89
  if (isDevEnv()) {
84
- const { eventDef, materializer } = getEventDef(schema, event.name)
90
+ // Hashing is only needed during dev-mode diagnostics. Skip work entirely for
91
+ // unknown events (no definition/materializer) so we do not introduce noisy
92
+ // warnings while still returning `Option.none()` to disable hash checks.
93
+ const eventDef = schema.eventsDefsMap.get(event.name)
94
+ const materializer = schema.state.materializers.get(event.name)
95
+ if (eventDef === undefined || materializer === undefined) {
96
+ return Option.none()
97
+ }
98
+ // For known events we replay the materializer with the encoded payload and
99
+ // hash the resulting SQL statements. This lets us cheaply detect
100
+ // side-effects or logic drift between leader/client materializers without
101
+ // mutating the underlying state.
85
102
  const materializerResults = getExecStatementsFromMaterializer({
86
103
  eventDef,
87
104
  materializer,
@@ -4,7 +4,7 @@ import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
4
4
  import { type SqliteDb, UnexpectedError } 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
- import { EventSequenceNumber, getEventDef, LiveStoreEvent, SystemTables } from './schema/mod.ts'
7
+ import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } from './schema/mod.ts'
8
8
  import type { PreparedBindValues } from './util.ts'
9
9
  import { sql } from './util.ts'
10
10
 
@@ -31,18 +31,45 @@ export const rematerializeFromEventlog = ({
31
31
 
32
32
  const processEvent = (row: SystemTables.EventlogMetaRow) =>
33
33
  Effect.gen(function* () {
34
- const eventDef = getEventDef(schema, row.name)
34
+ const args = JSON.parse(row.argsJson)
35
+ const eventEncoded = LiveStoreEvent.EncodedWithMeta.make({
36
+ name: row.name,
37
+ args,
38
+ seqNum: {
39
+ global: row.seqNumGlobal,
40
+ client: row.seqNumClient,
41
+ rebaseGeneration: row.seqNumRebaseGeneration,
42
+ },
43
+ parentSeqNum: {
44
+ global: row.parentSeqNumGlobal,
45
+ client: row.parentSeqNumClient,
46
+ rebaseGeneration: row.parentSeqNumRebaseGeneration,
47
+ },
48
+ clientId: row.clientId,
49
+ sessionId: row.sessionId,
50
+ })
51
+
52
+ const resolution = yield* resolveEventDef(schema, {
53
+ operation: '@livestore/common:rematerializeFromEventlog:processEvent',
54
+ event: eventEncoded,
55
+ }).pipe(UnexpectedError.mapToUnexpectedError)
56
+
57
+ if (resolution._tag === 'unknown') {
58
+ // Old snapshots can contain newer events. Skip until the runtime has
59
+ // been updated; the event stays in the log for future replays.
60
+ return
61
+ }
35
62
 
36
- if (hashEventDef(eventDef.eventDef) !== row.schemaHash) {
63
+ const { eventDef } = resolution
64
+
65
+ if (hashEventDef(eventDef) !== row.schemaHash) {
37
66
  yield* Effect.logWarning(
38
67
  `Schema hash mismatch for event definition ${row.name}. Trying to materialize event anyway.`,
39
68
  )
40
69
  }
41
70
 
42
- const args = JSON.parse(row.argsJson)
43
-
44
71
  // Checking whether the schema has changed in an incompatible way
45
- yield* Schema.decodeUnknown(eventDef.eventDef.schema)(args).pipe(
72
+ yield* Schema.decodeUnknown(eventDef.schema)(args).pipe(
46
73
  Effect.mapError((cause) =>
47
74
  UnexpectedError.make({
48
75
  cause,
@@ -55,23 +82,6 @@ This likely means the schema has changed in an incompatible way.
55
82
  ),
56
83
  )
57
84
 
58
- const eventEncoded = LiveStoreEvent.EncodedWithMeta.make({
59
- seqNum: {
60
- global: row.seqNumGlobal,
61
- client: row.seqNumClient,
62
- rebaseGeneration: row.seqNumRebaseGeneration,
63
- },
64
- parentSeqNum: {
65
- global: row.parentSeqNumGlobal,
66
- client: row.parentSeqNumClient,
67
- rebaseGeneration: row.parentSeqNumRebaseGeneration,
68
- },
69
- name: row.name,
70
- args,
71
- clientId: row.clientId,
72
- sessionId: row.sessionId,
73
- })
74
-
75
85
  yield* materializeEvent(eventEncoded, { skipEventlog: true })
76
86
  }).pipe(Effect.withSpan(`@livestore/common:rematerializeFromEventlog:processEvent`))
77
87
 
@@ -4,6 +4,7 @@ import { Schema } from '@livestore/utils/effect'
4
4
 
5
5
  import type { BindValues } from '../sql-queries/sql-queries.ts'
6
6
  import type { ParamsObject } from '../util.ts'
7
+ import type * as LiveStoreEvent from './LiveStoreEvent.ts'
7
8
  import type { QueryBuilder } from './state/sqlite/query-builder/mod.ts'
8
9
 
9
10
  export type EventDefMap = {
@@ -191,6 +192,8 @@ export type Materializer<TEventDef extends EventDef.AnyWithoutFn = EventDef.AnyW
191
192
  eventDef: TEventDef
192
193
  /** Can be used to query the current state */
193
194
  query: MaterializerContextQuery
195
+ /** The full LiveStore event with clientId, sessionId, etc. */
196
+ event: LiveStoreEvent.AnyDecoded
194
197
  },
195
198
  ) => SingleOrReadonlyArray<MaterializerResult>
196
199
 
@@ -283,5 +283,4 @@ export const isEqualEncoded = (a: AnyEncoded, b: AnyEncoded) =>
283
283
  a.name === b.name &&
284
284
  a.clientId === b.clientId &&
285
285
  a.sessionId === b.sessionId &&
286
- // TODO use schema equality here
287
- JSON.stringify(a.args) === JSON.stringify(b.args)
286
+ JSON.stringify(a.args) === JSON.stringify(b.args) // TODO use schema equality here
package/src/schema/mod.ts CHANGED
@@ -7,3 +7,5 @@ export * as State from './state/mod.ts'
7
7
  export { SqliteAst, SqliteDsl } from './state/sqlite/db-schema/mod.ts'
8
8
  export * from './state/sqlite/schema-helpers.ts'
9
9
  export * as SystemTables from './state/sqlite/system-tables.ts'
10
+ export type { UnknownEvents } from './unknown-events.ts'
11
+ export { normalizeUnknownEventHandling, resolveEventDef } from './unknown-events.ts'