@livestore/common 0.3.0-dev.36 → 0.3.0-dev.38

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 (224) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/adapter-types.d.ts +3 -2
  3. package/dist/adapter-types.d.ts.map +1 -1
  4. package/dist/adapter-types.js.map +1 -1
  5. package/dist/devtools/devtools-messages-client-session.d.ts +29 -29
  6. package/dist/devtools/devtools-messages-common.d.ts +6 -6
  7. package/dist/devtools/devtools-messages-leader.d.ts +24 -24
  8. package/dist/devtools/devtools-sessioninfo.d.ts +2 -0
  9. package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -1
  10. package/dist/devtools/devtools-sessioninfo.js +1 -0
  11. package/dist/devtools/devtools-sessioninfo.js.map +1 -1
  12. package/dist/devtools/mod.d.ts +48 -32
  13. package/dist/devtools/mod.d.ts.map +1 -1
  14. package/dist/devtools/mod.js +27 -21
  15. package/dist/devtools/mod.js.map +1 -1
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/leader-thread/LeaderSyncProcessor.js +10 -10
  21. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  22. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
  23. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  24. package/dist/leader-thread/leader-worker-devtools.js +21 -13
  25. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  26. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  27. package/dist/leader-thread/materialize-event.js +3 -1
  28. package/dist/leader-thread/materialize-event.js.map +1 -1
  29. package/dist/leader-thread/types.d.ts +6 -4
  30. package/dist/leader-thread/types.d.ts.map +1 -1
  31. package/dist/leader-thread/types.js.map +1 -1
  32. package/dist/make-client-session.d.ts +21 -0
  33. package/dist/make-client-session.d.ts.map +1 -0
  34. package/dist/make-client-session.js +51 -0
  35. package/dist/make-client-session.js.map +1 -0
  36. package/dist/materializer-helper.d.ts +5 -5
  37. package/dist/materializer-helper.d.ts.map +1 -1
  38. package/dist/materializer-helper.js +17 -3
  39. package/dist/materializer-helper.js.map +1 -1
  40. package/dist/schema/EventDef.d.ts +13 -3
  41. package/dist/schema/EventDef.d.ts.map +1 -1
  42. package/dist/schema/EventDef.js.map +1 -1
  43. package/dist/schema/LiveStoreEvent.d.ts +6 -6
  44. package/dist/schema/state/sqlite/client-document-def.test.js +5 -5
  45. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  46. package/dist/schema/state/sqlite/query-builder/api.d.ts +4 -3
  47. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  48. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  49. package/dist/schema/state/sqlite/query-builder/impl.js +2 -2
  50. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  51. package/dist/schema/state/sqlite/system-tables.d.ts +2 -2
  52. package/dist/sync/next/test/event-fixtures.d.ts +7 -7
  53. package/dist/sync/syncstate.d.ts +2 -2
  54. package/dist/version.d.ts +1 -1
  55. package/dist/version.js +1 -1
  56. package/package.json +4 -3
  57. package/src/adapter-types.ts +4 -2
  58. package/src/devtools/devtools-sessioninfo.ts +1 -0
  59. package/src/devtools/mod.ts +44 -21
  60. package/src/index.ts +1 -0
  61. package/src/leader-thread/LeaderSyncProcessor.ts +10 -10
  62. package/src/leader-thread/leader-worker-devtools.ts +40 -22
  63. package/src/leader-thread/materialize-event.ts +3 -1
  64. package/src/leader-thread/types.ts +5 -4
  65. package/src/make-client-session.ts +119 -0
  66. package/src/materializer-helper.ts +35 -10
  67. package/src/schema/EventDef.ts +12 -1
  68. package/src/schema/state/sqlite/client-document-def.test.ts +5 -6
  69. package/src/schema/state/sqlite/query-builder/api.ts +4 -3
  70. package/src/schema/state/sqlite/query-builder/impl.ts +3 -2
  71. package/src/version.ts +1 -1
  72. package/dist/derived-mutations.d.ts +0 -77
  73. package/dist/derived-mutations.d.ts.map +0 -1
  74. package/dist/derived-mutations.js +0 -54
  75. package/dist/derived-mutations.js.map +0 -1
  76. package/dist/derived-mutations.test.d.ts +0 -2
  77. package/dist/derived-mutations.test.d.ts.map +0 -1
  78. package/dist/derived-mutations.test.js +0 -93
  79. package/dist/derived-mutations.test.js.map +0 -1
  80. package/dist/devtools/devtools-bridge.d.ts +0 -12
  81. package/dist/devtools/devtools-bridge.d.ts.map +0 -1
  82. package/dist/devtools/devtools-bridge.js +0 -2
  83. package/dist/devtools/devtools-bridge.js.map +0 -1
  84. package/dist/devtools/devtools-window-message.d.ts +0 -29
  85. package/dist/devtools/devtools-window-message.d.ts.map +0 -1
  86. package/dist/devtools/devtools-window-message.js +0 -33
  87. package/dist/devtools/devtools-window-message.js.map +0 -1
  88. package/dist/devtools/index.d.ts +0 -42
  89. package/dist/devtools/index.d.ts.map +0 -1
  90. package/dist/devtools/index.js +0 -49
  91. package/dist/devtools/index.js.map +0 -1
  92. package/dist/init-singleton-tables.d.ts +0 -4
  93. package/dist/init-singleton-tables.d.ts.map +0 -1
  94. package/dist/init-singleton-tables.js +0 -16
  95. package/dist/init-singleton-tables.js.map +0 -1
  96. package/dist/leader-thread/apply-event.d.ts +0 -16
  97. package/dist/leader-thread/apply-event.d.ts.map +0 -1
  98. package/dist/leader-thread/apply-event.js +0 -103
  99. package/dist/leader-thread/apply-event.js.map +0 -1
  100. package/dist/mutation.d.ts +0 -14
  101. package/dist/mutation.d.ts.map +0 -1
  102. package/dist/mutation.js +0 -71
  103. package/dist/mutation.js.map +0 -1
  104. package/dist/query-builder/api.d.ts +0 -293
  105. package/dist/query-builder/api.d.ts.map +0 -1
  106. package/dist/query-builder/api.js +0 -6
  107. package/dist/query-builder/api.js.map +0 -1
  108. package/dist/query-builder/astToSql.d.ts +0 -7
  109. package/dist/query-builder/astToSql.d.ts.map +0 -1
  110. package/dist/query-builder/astToSql.js +0 -190
  111. package/dist/query-builder/astToSql.js.map +0 -1
  112. package/dist/query-builder/impl.d.ts +0 -7
  113. package/dist/query-builder/impl.d.ts.map +0 -1
  114. package/dist/query-builder/impl.js +0 -286
  115. package/dist/query-builder/impl.js.map +0 -1
  116. package/dist/query-builder/impl.test.d.ts +0 -87
  117. package/dist/query-builder/impl.test.d.ts.map +0 -1
  118. package/dist/query-builder/impl.test.js +0 -554
  119. package/dist/query-builder/impl.test.js.map +0 -1
  120. package/dist/query-builder/mod.d.ts +0 -17
  121. package/dist/query-builder/mod.d.ts.map +0 -1
  122. package/dist/query-builder/mod.js +0 -17
  123. package/dist/query-builder/mod.js.map +0 -1
  124. package/dist/query-info.d.ts +0 -38
  125. package/dist/query-info.d.ts.map +0 -1
  126. package/dist/query-info.js +0 -7
  127. package/dist/query-info.js.map +0 -1
  128. package/dist/rehydrate-from-eventlog.d.ts +0 -14
  129. package/dist/rehydrate-from-eventlog.d.ts.map +0 -1
  130. package/dist/rehydrate-from-eventlog.js +0 -64
  131. package/dist/rehydrate-from-eventlog.js.map +0 -1
  132. package/dist/rehydrate-from-mutationlog.d.ts +0 -14
  133. package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
  134. package/dist/rehydrate-from-mutationlog.js +0 -72
  135. package/dist/rehydrate-from-mutationlog.js.map +0 -1
  136. package/dist/schema/client-document-def.d.ts +0 -223
  137. package/dist/schema/client-document-def.d.ts.map +0 -1
  138. package/dist/schema/client-document-def.js +0 -170
  139. package/dist/schema/client-document-def.js.map +0 -1
  140. package/dist/schema/client-document-def.test.d.ts +0 -2
  141. package/dist/schema/client-document-def.test.d.ts.map +0 -1
  142. package/dist/schema/client-document-def.test.js +0 -201
  143. package/dist/schema/client-document-def.test.js.map +0 -1
  144. package/dist/schema/db-schema/ast/sqlite.d.ts +0 -69
  145. package/dist/schema/db-schema/ast/sqlite.d.ts.map +0 -1
  146. package/dist/schema/db-schema/ast/sqlite.js +0 -71
  147. package/dist/schema/db-schema/ast/sqlite.js.map +0 -1
  148. package/dist/schema/db-schema/ast/validate.d.ts +0 -3
  149. package/dist/schema/db-schema/ast/validate.d.ts.map +0 -1
  150. package/dist/schema/db-schema/ast/validate.js +0 -12
  151. package/dist/schema/db-schema/ast/validate.js.map +0 -1
  152. package/dist/schema/db-schema/dsl/field-defs.d.ts +0 -90
  153. package/dist/schema/db-schema/dsl/field-defs.d.ts.map +0 -1
  154. package/dist/schema/db-schema/dsl/field-defs.js +0 -87
  155. package/dist/schema/db-schema/dsl/field-defs.js.map +0 -1
  156. package/dist/schema/db-schema/dsl/field-defs.test.d.ts +0 -2
  157. package/dist/schema/db-schema/dsl/field-defs.test.d.ts.map +0 -1
  158. package/dist/schema/db-schema/dsl/field-defs.test.js +0 -29
  159. package/dist/schema/db-schema/dsl/field-defs.test.js.map +0 -1
  160. package/dist/schema/db-schema/dsl/mod.d.ts +0 -90
  161. package/dist/schema/db-schema/dsl/mod.d.ts.map +0 -1
  162. package/dist/schema/db-schema/dsl/mod.js +0 -41
  163. package/dist/schema/db-schema/dsl/mod.js.map +0 -1
  164. package/dist/schema/db-schema/hash.d.ts +0 -2
  165. package/dist/schema/db-schema/hash.d.ts.map +0 -1
  166. package/dist/schema/db-schema/hash.js +0 -14
  167. package/dist/schema/db-schema/hash.js.map +0 -1
  168. package/dist/schema/db-schema/mod.d.ts +0 -3
  169. package/dist/schema/db-schema/mod.d.ts.map +0 -1
  170. package/dist/schema/db-schema/mod.js +0 -3
  171. package/dist/schema/db-schema/mod.js.map +0 -1
  172. package/dist/schema/index.d.ts +0 -62
  173. package/dist/schema/index.d.ts.map +0 -1
  174. package/dist/schema/index.js +0 -67
  175. package/dist/schema/index.js.map +0 -1
  176. package/dist/schema/mutations.d.ts +0 -227
  177. package/dist/schema/mutations.d.ts.map +0 -1
  178. package/dist/schema/mutations.js +0 -68
  179. package/dist/schema/mutations.js.map +0 -1
  180. package/dist/schema/schema-helpers.d.ts +0 -4
  181. package/dist/schema/schema-helpers.d.ts.map +0 -1
  182. package/dist/schema/schema-helpers.js +0 -30
  183. package/dist/schema/schema-helpers.js.map +0 -1
  184. package/dist/schema/sqlite-state.d.ts +0 -12
  185. package/dist/schema/sqlite-state.d.ts.map +0 -1
  186. package/dist/schema/sqlite-state.js +0 -36
  187. package/dist/schema/sqlite-state.js.map +0 -1
  188. package/dist/schema/state/sqlite/sqlite-state.d.ts +0 -12
  189. package/dist/schema/state/sqlite/sqlite-state.d.ts.map +0 -1
  190. package/dist/schema/state/sqlite/sqlite-state.js +0 -36
  191. package/dist/schema/state/sqlite/sqlite-state.js.map +0 -1
  192. package/dist/schema/state/state.d.ts +0 -3
  193. package/dist/schema/state/state.d.ts.map +0 -1
  194. package/dist/schema/state/state.js +0 -3
  195. package/dist/schema/state/state.js.map +0 -1
  196. package/dist/schema/state.d.ts +0 -3
  197. package/dist/schema/state.d.ts.map +0 -1
  198. package/dist/schema/state.js +0 -3
  199. package/dist/schema/state.js.map +0 -1
  200. package/dist/schema/system-tables.d.ts +0 -27
  201. package/dist/schema/system-tables.d.ts.map +0 -1
  202. package/dist/schema/system-tables.js +0 -86
  203. package/dist/schema/system-tables.js.map +0 -1
  204. package/dist/schema/table-def.d.ts +0 -84
  205. package/dist/schema/table-def.d.ts.map +0 -1
  206. package/dist/schema/table-def.js +0 -36
  207. package/dist/schema/table-def.js.map +0 -1
  208. package/dist/schema/view.d.ts +0 -3
  209. package/dist/schema/view.d.ts.map +0 -1
  210. package/dist/schema/view.js +0 -3
  211. package/dist/schema/view.js.map +0 -1
  212. package/dist/schema-management/validate-mutation-defs.d.ts +0 -8
  213. package/dist/schema-management/validate-mutation-defs.d.ts.map +0 -1
  214. package/dist/schema-management/validate-mutation-defs.js +0 -39
  215. package/dist/schema-management/validate-mutation-defs.js.map +0 -1
  216. package/dist/sync/next/test/mutation-fixtures.d.ts +0 -73
  217. package/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
  218. package/dist/sync/next/test/mutation-fixtures.js +0 -161
  219. package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
  220. package/dist/sync/next-mutation-event-id-pair.d.ts +0 -14
  221. package/dist/sync/next-mutation-event-id-pair.d.ts.map +0 -1
  222. package/dist/sync/next-mutation-event-id-pair.js +0 -13
  223. package/dist/sync/next-mutation-event-id-pair.js.map +0 -1
  224. package/src/devtools/devtools-window-message.ts +0 -27
@@ -1,36 +1,59 @@
1
+ import type { Effect, Scope, WebChannel } from '@livestore/utils/effect'
1
2
  import { Schema } from '@livestore/utils/effect'
3
+ import { nanoid } from '@livestore/utils/nanoid'
4
+ import type { MeshNode } from '@livestore/webmesh'
5
+
6
+ import * as SessionInfo from './devtools-sessioninfo.js'
2
7
 
3
8
  export * from './devtools-messages.js'
4
- export * from './devtools-window-message.js'
5
9
  export * as SessionInfo from './devtools-sessioninfo.js'
6
- export const ClientSessionInfo = Schema.Struct({
7
- storeId: Schema.String,
8
- clientId: Schema.String,
9
- sessionId: Schema.String,
10
- })
11
10
 
12
11
  export const DevtoolsMode = Schema.Union(
13
- Schema.TaggedStruct('expo', {
14
- // TODO get rid of embedded `clientSessionInfo`
15
- clientSessionInfo: Schema.optional(ClientSessionInfo),
16
- }),
17
- // TODO add storeId, clientId and sessionId for Node
18
12
  Schema.TaggedStruct('node', {
19
- // TODO get rid of embedded `clientSessionInfo`
20
- clientSessionInfo: Schema.UndefinedOr(ClientSessionInfo),
13
+ /** WebSocket URL */
21
14
  url: Schema.String,
22
15
  }),
23
- Schema.TaggedStruct('web', {
24
- // TODO get rid of embedded `clientSessionInfo`
25
- clientSessionInfo: Schema.UndefinedOr(ClientSessionInfo),
26
- }),
27
- Schema.TaggedStruct('browser-extension', {
28
- // TODO get rid of embedded `clientSessionInfo`
29
- clientSessionInfo: Schema.UndefinedOr(ClientSessionInfo),
30
- }),
16
+ Schema.TaggedStruct('web', {}),
17
+ Schema.TaggedStruct('browser-extension', {}),
31
18
  )
32
19
 
33
20
  export type DevtoolsMode = typeof DevtoolsMode.Type
34
21
 
35
22
  export const DevtoolsModeTag = DevtoolsMode.pipe(Schema.pluck('_tag'), Schema.typeSchema)
36
23
  export type DevtoolsModeTag = typeof DevtoolsModeTag.Type
24
+
25
+ export const makeNodeName = {
26
+ devtools: {
27
+ random: () => `devtools-session-info-${nanoid()}`,
28
+ },
29
+ client: {
30
+ session: ({ storeId, clientId, sessionId }: { storeId: string; clientId: string; sessionId: string }) =>
31
+ `client-session-${storeId}-${clientId}-${sessionId}`,
32
+ leader: ({ storeId, clientId }: { storeId: string; clientId: string }) => `client-leader-${storeId}-${clientId}`,
33
+ },
34
+ }
35
+
36
+ export const makeChannelName = {
37
+ sessionInfo: () => `session-info`,
38
+ devtoolsClientSession: ({ storeId, clientId, sessionId }: { storeId: string; clientId: string; sessionId: string }) =>
39
+ `devtools-channel(client-session-${storeId}-${clientId}-${sessionId})`,
40
+ devtoolsClientLeader: ({ storeId, clientId, sessionId }: { storeId: string; clientId: string; sessionId: string }) =>
41
+ `devtools-channel(client-leader-${storeId}-${clientId}-${sessionId})`,
42
+ }
43
+
44
+ export const isChannelName = {
45
+ devtoolsClientSession: (
46
+ channelName: string,
47
+ { storeId, clientId, sessionId }: { storeId: string; clientId: string; sessionId: string },
48
+ ) => channelName === makeChannelName.devtoolsClientSession({ storeId, clientId, sessionId }),
49
+ devtoolsClientLeader: (channelName: string, { storeId, clientId }: { storeId: string; clientId: string }) =>
50
+ channelName.startsWith(`devtools-channel(client-leader-${storeId}-${clientId}`),
51
+ }
52
+
53
+ export const makeSessionInfoBroadcastChannel = (
54
+ webmeshNode: MeshNode,
55
+ ): Effect.Effect<WebChannel.WebChannel<SessionInfo.Message, SessionInfo.Message>, never, Scope.Scope> =>
56
+ webmeshNode.makeBroadcastChannel({
57
+ channelName: makeChannelName.sessionInfo(),
58
+ schema: SessionInfo.Message,
59
+ })
package/src/index.ts CHANGED
@@ -12,3 +12,4 @@ export * from './version.js'
12
12
  export * from './schema/state/sqlite/query-builder/mod.js'
13
13
  export * as SyncState from './sync/syncstate.js'
14
14
  export * from './otel.js'
15
+ export * from './make-client-session.js'
@@ -107,8 +107,8 @@ export const makeLeaderSyncProcessor = ({
107
107
  const syncStateSref = yield* SubscriptionRef.make<SyncState.SyncState | undefined>(undefined)
108
108
 
109
109
  const isClientEvent = (eventEncoded: LiveStoreEvent.EncodedWithMeta) => {
110
- const eventDef = getEventDef(schema, eventEncoded.name)
111
- return eventDef.eventDef.options.clientOnly
110
+ const { eventDef } = getEventDef(schema, eventEncoded.name)
111
+ return eventDef.options.clientOnly
112
112
  }
113
113
 
114
114
  const connectedClientSessionPullQueues = yield* makePullQueueSet
@@ -196,14 +196,14 @@ export const makeLeaderSyncProcessor = ({
196
196
  const syncState = yield* syncStateSref
197
197
  if (syncState === undefined) return shouldNeverHappen('Not initialized')
198
198
 
199
- const eventDef = getEventDef(schema, name)
199
+ const { eventDef } = getEventDef(schema, name)
200
200
 
201
201
  const eventEncoded = new LiveStoreEvent.EncodedWithMeta({
202
202
  name,
203
203
  args,
204
204
  clientId,
205
205
  sessionId,
206
- ...EventId.nextPair(syncState.localHead, eventDef.eventDef.options.clientOnly),
206
+ ...EventId.nextPair(syncState.localHead, eventDef.options.clientOnly),
207
207
  })
208
208
 
209
209
  yield* push([eventEncoded])
@@ -251,8 +251,8 @@ export const makeLeaderSyncProcessor = ({
251
251
  const globalPendingEvents = pendingEvents
252
252
  // Don't sync clientOnly events
253
253
  .filter((eventEncoded) => {
254
- const eventDef = getEventDef(schema, eventEncoded.name)
255
- return eventDef.eventDef.options.clientOnly === false
254
+ const { eventDef } = getEventDef(schema, eventEncoded.name)
255
+ return eventDef.options.clientOnly === false
256
256
  })
257
257
 
258
258
  if (globalPendingEvents.length > 0) {
@@ -540,8 +540,8 @@ const backgroundApplyLocalPushes = ({
540
540
 
541
541
  // Don't sync clientOnly events
542
542
  const filteredBatch = mergeResult.newEvents.filter((eventEncoded) => {
543
- const eventDef = getEventDef(schema, eventEncoded.name)
544
- return eventDef.eventDef.options.clientOnly === false
543
+ const { eventDef } = getEventDef(schema, eventEncoded.name)
544
+ return eventDef.options.clientOnly === false
545
545
  })
546
546
 
547
547
  yield* BucketQueue.offerAll(syncBackendPushQueue, filteredBatch)
@@ -688,8 +688,8 @@ const backgroundBackendPulling = ({
688
688
  })
689
689
 
690
690
  const globalRebasedPendingEvents = mergeResult.newSyncState.pending.filter((event) => {
691
- const eventDef = getEventDef(schema, event.name)
692
- return eventDef.eventDef.options.clientOnly === false
691
+ const { eventDef } = getEventDef(schema, event.name)
692
+ return eventDef.options.clientOnly === false
693
693
  })
694
694
  yield* restartBackendPushing(globalRebasedPendingEvents)
695
695
 
@@ -15,38 +15,56 @@ export const bootDevtools = (options: DevtoolsOptions) =>
15
15
  return
16
16
  }
17
17
 
18
- const { syncProcessor, extraIncomingMessagesQueue } = yield* LeaderThreadCtx
18
+ const { syncProcessor, extraIncomingMessagesQueue, clientId, storeId } = yield* LeaderThreadCtx
19
19
 
20
20
  yield* listenToDevtools({
21
21
  incomingMessages: Stream.fromQueue(extraIncomingMessagesQueue),
22
22
  sendMessage: () => Effect.void,
23
23
  }).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
24
24
 
25
- const { persistenceInfo, devtoolsWebChannel } = yield* options.makeBootContext
25
+ const { node, persistenceInfo, mode } = yield* options.boot
26
26
 
27
- const sendMessage: SendMessageToDevtools = (message) =>
28
- devtoolsWebChannel
29
- .send(message)
30
- .pipe(
31
- Effect.withSpan('@livestore/common:leader-thread:devtools:sendToDevtools'),
32
- Effect.interruptible,
33
- Effect.ignoreLogged,
34
- )
35
-
36
- const syncState = yield* syncProcessor.syncState
37
- const mergeCounter = syncProcessor.getMergeCounter()
27
+ yield* node.listenForChannel.pipe(
28
+ Stream.filter(
29
+ (res) =>
30
+ Devtools.isChannelName.devtoolsClientLeader(res.channelName, { storeId, clientId }) && res.mode === mode,
31
+ ),
32
+ Stream.tap(({ channelName, source }) =>
33
+ Effect.gen(function* () {
34
+ const channel = yield* node.makeChannel({
35
+ target: source,
36
+ channelName,
37
+ schema: { listen: Devtools.Leader.MessageToApp, send: Devtools.Leader.MessageFromApp },
38
+ mode,
39
+ })
40
+
41
+ const sendMessage: SendMessageToDevtools = (message) =>
42
+ channel
43
+ .send(message)
44
+ .pipe(
45
+ Effect.withSpan('@livestore/common:leader-thread:devtools:sendToDevtools'),
46
+ Effect.interruptible,
47
+ Effect.ignoreLogged,
48
+ )
38
49
 
39
- yield* syncProcessor.pull({ cursor: { mergeCounter, eventId: syncState.localHead } }).pipe(
40
- Stream.tap(({ payload }) => sendMessage(Devtools.Leader.SyncPull.make({ payload, liveStoreVersion }))),
50
+ const syncState = yield* syncProcessor.syncState
51
+ const mergeCounter = syncProcessor.getMergeCounter()
52
+
53
+ yield* syncProcessor.pull({ cursor: { mergeCounter, eventId: syncState.localHead } }).pipe(
54
+ Stream.tap(({ payload }) => sendMessage(Devtools.Leader.SyncPull.make({ payload, liveStoreVersion }))),
55
+ Stream.runDrain,
56
+ Effect.forkScoped,
57
+ )
58
+
59
+ yield* listenToDevtools({
60
+ incomingMessages: channel.listen.pipe(Stream.flatten(), Stream.orDie),
61
+ sendMessage,
62
+ persistenceInfo,
63
+ })
64
+ }).pipe(Effect.tapCauseLogPretty, Effect.forkScoped),
65
+ ),
41
66
  Stream.runDrain,
42
- Effect.forkScoped,
43
67
  )
44
-
45
- yield* listenToDevtools({
46
- incomingMessages: devtoolsWebChannel.listen.pipe(Stream.flatten(), Stream.orDie),
47
- sendMessage,
48
- persistenceInfo,
49
- }).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
50
68
  }).pipe(Effect.withSpan('@livestore/common:leader-thread:devtools:boot'))
51
69
 
52
70
  const listenToDevtools = ({
@@ -33,10 +33,12 @@ export const makeMaterializeEvent = ({
33
33
  const skipEventlog = options?.skipEventlog ?? false
34
34
 
35
35
  const eventName = eventEncoded.name
36
- const eventDef = getEventDef(schema, eventName)
36
+ const { eventDef, materializer } = getEventDef(schema, eventName)
37
37
 
38
38
  const execArgsArr = getExecArgsFromEvent({
39
39
  eventDef,
40
+ materializer,
41
+ db,
40
42
  event: { decoded: undefined, encoded: eventEncoded },
41
43
  })
42
44
 
@@ -8,9 +8,9 @@ import type {
8
8
  Stream,
9
9
  Subscribable,
10
10
  SubscriptionRef,
11
- WebChannel,
12
11
  } from '@livestore/utils/effect'
13
12
  import { Context, Schema } from '@livestore/utils/effect'
13
+ import type { MeshNode } from '@livestore/webmesh'
14
14
 
15
15
  import type { LeaderPullCursor, SqliteError } from '../adapter-types.js'
16
16
  import type {
@@ -60,13 +60,14 @@ export type DevtoolsOptions =
60
60
  }
61
61
  | {
62
62
  enabled: true
63
- makeBootContext: Effect.Effect<
63
+ boot: Effect.Effect<
64
64
  {
65
- devtoolsWebChannel: WebChannel.WebChannel<Devtools.Leader.MessageToApp, Devtools.Leader.MessageFromApp>
65
+ node: MeshNode
66
66
  persistenceInfo: PersistenceInfoPair
67
+ mode: 'proxy' | 'direct'
67
68
  },
68
69
  UnexpectedError,
69
- Scope.Scope
70
+ Scope.Scope | HttpClient.HttpClient | LeaderThreadCtx
70
71
  >
71
72
  }
72
73
 
@@ -0,0 +1,119 @@
1
+ import type { Scope, SubscriptionRef } from '@livestore/utils/effect'
2
+ import { Effect, Stream } from '@livestore/utils/effect'
3
+ import * as Webmesh from '@livestore/webmesh'
4
+
5
+ import type {
6
+ AdapterArgs,
7
+ ClientSession,
8
+ ClientSessionLeaderThreadProxy,
9
+ LockStatus,
10
+ SqliteDb,
11
+ UnexpectedError,
12
+ } from './adapter-types.js'
13
+ import * as Devtools from './devtools/mod.js'
14
+
15
+ declare global {
16
+ // eslint-disable-next-line no-var
17
+ var __debugWebmeshNode: any
18
+ }
19
+
20
+ export const makeClientSession = <R>({
21
+ storeId,
22
+ clientId,
23
+ sessionId,
24
+ devtoolsEnabled,
25
+ connectDevtoolsToStore,
26
+ lockStatus,
27
+ leaderThread,
28
+ schema,
29
+ sqliteDb,
30
+ shutdown,
31
+ connectWebmeshNode,
32
+ webmeshMode,
33
+ }: AdapterArgs & {
34
+ clientId: string
35
+ sessionId: string
36
+ lockStatus: SubscriptionRef.SubscriptionRef<LockStatus>
37
+ leaderThread: ClientSessionLeaderThreadProxy
38
+ sqliteDb: SqliteDb
39
+ connectWebmeshNode: (args: {
40
+ webmeshNode: Webmesh.MeshNode
41
+ sessionInfo: Devtools.SessionInfo.SessionInfo
42
+ }) => Effect.Effect<void, UnexpectedError, Scope.Scope | R>
43
+ webmeshMode: 'direct' | 'proxy'
44
+ }): Effect.Effect<ClientSession, never, Scope.Scope | R> =>
45
+ Effect.gen(function* () {
46
+ const devtools: ClientSession['devtools'] = devtoolsEnabled
47
+ ? { enabled: true, pullLatch: yield* Effect.makeLatch(true), pushLatch: yield* Effect.makeLatch(true) }
48
+ : { enabled: false }
49
+
50
+ if (devtoolsEnabled) {
51
+ yield* Effect.gen(function* () {
52
+ const webmeshNode = yield* Webmesh.makeMeshNode(
53
+ Devtools.makeNodeName.client.session({ storeId, clientId, sessionId }),
54
+ )
55
+
56
+ globalThis.__debugWebmeshNode = webmeshNode
57
+
58
+ const schemaAlias = schema.devtools.alias
59
+ const sessionInfo = Devtools.SessionInfo.SessionInfo.make({
60
+ storeId,
61
+ clientId,
62
+ sessionId,
63
+ schemaAlias,
64
+ isLeader: true, // TODO actually check if we are leader
65
+ })
66
+
67
+ yield* connectWebmeshNode({ webmeshNode, sessionInfo })
68
+
69
+ const sessionInfoBroadcastChannel = yield* Devtools.makeSessionInfoBroadcastChannel(webmeshNode)
70
+
71
+ yield* Devtools.SessionInfo.provideSessionInfo({
72
+ webChannel: sessionInfoBroadcastChannel,
73
+ sessionInfo,
74
+ }).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
75
+
76
+ yield* webmeshNode.listenForChannel.pipe(
77
+ Stream.filter(
78
+ (res) =>
79
+ Devtools.isChannelName.devtoolsClientSession(res.channelName, { storeId, clientId, sessionId }) &&
80
+ res.mode === webmeshMode,
81
+ ),
82
+ Stream.tap(
83
+ Effect.fnUntraced(
84
+ function* ({ channelName, source }) {
85
+ const clientSessionDevtoolsChannel = yield* webmeshNode.makeChannel({
86
+ target: source,
87
+ channelName,
88
+ schema: {
89
+ listen: Devtools.ClientSession.MessageToApp,
90
+ send: Devtools.ClientSession.MessageFromApp,
91
+ },
92
+ mode: webmeshMode,
93
+ })
94
+
95
+ yield* connectDevtoolsToStore(clientSessionDevtoolsChannel)
96
+ },
97
+ Effect.tapCauseLogPretty,
98
+ Effect.forkScoped,
99
+ ),
100
+ ),
101
+ Stream.runDrain,
102
+ )
103
+ }).pipe(
104
+ Effect.withSpan('@livestore/common:make-client-session:devtools'),
105
+ Effect.tapCauseLogPretty,
106
+ Effect.forkScoped,
107
+ )
108
+ }
109
+
110
+ return {
111
+ sqliteDb,
112
+ leaderThread,
113
+ devtools,
114
+ lockStatus,
115
+ clientId,
116
+ sessionId,
117
+ shutdown,
118
+ } satisfies ClientSession
119
+ })
@@ -1,22 +1,26 @@
1
1
  import { isReadonlyArray } from '@livestore/utils'
2
2
  import { Schema } from '@livestore/utils/effect'
3
3
 
4
+ import type { SqliteDb } from './adapter-types.js'
4
5
  import { SessionIdSymbol } from './adapter-types.js'
5
- import type { EventDef, Materializer, MaterializerResult } from './schema/EventDef.js'
6
+ import type { EventDef, Materializer, MaterializerContextQuery, MaterializerResult } from './schema/EventDef.js'
6
7
  import type * as LiveStoreEvent from './schema/LiveStoreEvent.js'
8
+ import type { QueryBuilder } from './schema/state/sqlite/query-builder/api.js'
7
9
  import { isQueryBuilder } from './schema/state/sqlite/query-builder/api.js'
8
- import type { BindValues } from './sql-queries/sql-queries.js'
9
- import type { PreparedBindValues } from './util.js'
10
+ import { getResultSchema } from './schema/state/sqlite/query-builder/impl.js'
11
+ import { type BindValues } from './sql-queries/sql-queries.js'
12
+ import type { ParamsObject, PreparedBindValues } from './util.js'
10
13
  import { prepareBindValues } from './util.js'
11
14
 
12
15
  export const getExecArgsFromEvent = ({
13
- eventDef: { eventDef, materializer },
16
+ eventDef,
17
+ materializer,
18
+ db,
14
19
  event,
15
20
  }: {
16
- eventDef: {
17
- eventDef: EventDef.AnyWithoutFn
18
- materializer: Materializer
19
- }
21
+ eventDef: EventDef.AnyWithoutFn
22
+ materializer: Materializer
23
+ db: SqliteDb
20
24
  /** Both encoded and decoded events are supported to reduce the number of times we need to decode/encode */
21
25
  event:
22
26
  | {
@@ -32,10 +36,31 @@ export const getExecArgsFromEvent = ({
32
36
  bindValues: PreparedBindValues
33
37
  writeTables: ReadonlySet<string> | undefined
34
38
  }> => {
35
- const eventArgsDecoded = event.decoded?.args ?? Schema.decodeUnknownSync(eventDef.schema)(event.encoded!.args)
39
+ const eventArgsDecoded =
40
+ event.decoded === undefined ? Schema.decodeUnknownSync(eventDef.schema)(event.encoded!.args) : event.decoded.args
41
+
42
+ const query: MaterializerContextQuery = (
43
+ rawQueryOrQueryBuilder:
44
+ | {
45
+ query: string
46
+ bindValues: ParamsObject
47
+ }
48
+ | QueryBuilder.Any,
49
+ ) => {
50
+ if (isQueryBuilder(rawQueryOrQueryBuilder)) {
51
+ const { query, bindValues } = rawQueryOrQueryBuilder.asSql()
52
+ const rawResults = db.select(query, prepareBindValues(bindValues, query))
53
+ const resultSchema = getResultSchema(rawQueryOrQueryBuilder)
54
+ return Schema.decodeSync(resultSchema)(rawResults)
55
+ } else {
56
+ const { query, bindValues } = rawQueryOrQueryBuilder
57
+ return db.select(query, prepareBindValues(bindValues, query))
58
+ }
59
+ }
36
60
 
37
61
  const res = materializer(eventArgsDecoded, {
38
- clientOnly: eventDef.options.clientOnly,
62
+ eventDef,
63
+ query,
39
64
  // TODO properly implement this
40
65
  currentFacts: new Map(),
41
66
  })
@@ -3,6 +3,7 @@ import { shouldNeverHappen } from '@livestore/utils'
3
3
  import { Schema } from '@livestore/utils/effect'
4
4
 
5
5
  import type { BindValues } from '../sql-queries/sql-queries.js'
6
+ import type { ParamsObject } from '../util.js'
6
7
  import type { QueryBuilder } from './state/sqlite/query-builder/mod.js'
7
8
 
8
9
  export type EventDefMap = {
@@ -167,9 +168,19 @@ export type MaterializerResult =
167
168
  | QueryBuilder.Any
168
169
  | string
169
170
 
171
+ export type MaterializerContextQuery = {
172
+ (args: { query: string; bindValues: ParamsObject }): ReadonlyArray<unknown>
173
+ <TResult>(qb: QueryBuilder<TResult, any, any>): TResult
174
+ }
175
+
170
176
  export type Materializer<TEventDef extends EventDef.AnyWithoutFn = EventDef.AnyWithoutFn> = (
171
177
  event: TEventDef['schema']['Type'],
172
- context: { currentFacts: EventDefFacts; clientOnly: boolean },
178
+ context: {
179
+ currentFacts: EventDefFacts
180
+ eventDef: TEventDef
181
+ /** Can be used to query the current state */
182
+ query: MaterializerContextQuery
183
+ },
173
184
  ) => SingleOrReadonlyArray<MaterializerResult>
174
185
 
175
186
  export const defineMaterializer = <TEventDef extends EventDef.AnyWithoutFn>(
@@ -5,11 +5,6 @@ import { tables } from '../../../__tests__/fixture.js'
5
5
  import type * as LiveStoreEvent from '../../LiveStoreEvent.js'
6
6
  import { clientDocument, ClientDocumentTableDefSymbol } from './client-document-def.js'
7
7
 
8
- const materializerContext = {
9
- currentFacts: new Map(),
10
- clientOnly: false,
11
- }
12
-
13
8
  describe('client document table', () => {
14
9
  test('set event', () => {
15
10
  expect(patchId(tables.UiState.set({ showSidebar: false }, 'session-1'))).toMatchInlineSnapshot(`
@@ -51,7 +46,11 @@ describe('client document table', () => {
51
46
 
52
47
  const materializer = Doc[ClientDocumentTableDefSymbol].derived.setMaterializer
53
48
 
54
- return materializer(Doc.set(value, id as any).args, materializerContext)
49
+ return materializer(Doc.set(value, id as any).args, {
50
+ currentFacts: new Map(),
51
+ query: {} as any, // unused
52
+ eventDef: Doc[ClientDocumentTableDefSymbol].derived.setEventDef,
53
+ })
55
54
  }
56
55
 
57
56
  test('string value', () => {
@@ -19,7 +19,7 @@ export namespace QueryBuilderAst {
19
19
  export interface SelectQuery {
20
20
  readonly _tag: 'SelectQuery'
21
21
  readonly columns: string[]
22
- readonly pickFirst: false | { fallback: () => any } | 'no-fallback'
22
+ readonly pickFirst: false | { fallback: () => any } | 'throws'
23
23
  readonly select: {
24
24
  columns: ReadonlyArray<string>
25
25
  }
@@ -288,10 +288,11 @@ export namespace QueryBuilder {
288
288
  * db.todos.where('id', '123').first()
289
289
  * ```
290
290
  *
291
- * Query will fail if no rows are returned and no fallback is provided.
291
+ * Query will throw if no rows are returned and no fallback is provided.
292
292
  */
293
293
  readonly first: <TFallback = never>(options?: {
294
- fallback?: () => TFallback | GetSingle<TResult>
294
+ /** @default 'throws' */
295
+ fallback?: (() => TFallback | GetSingle<TResult>) | 'throws'
295
296
  }) => QueryBuilder<
296
297
  TFallback | GetSingle<TResult>,
297
298
  TTableDef,
@@ -143,7 +143,8 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
143
143
  return makeQueryBuilder(tableDef, {
144
144
  ...ast,
145
145
  limit: Option.some(1),
146
- pickFirst: options?.fallback ? { fallback: options.fallback } : 'no-fallback',
146
+ pickFirst:
147
+ options?.fallback !== undefined && options.fallback !== 'throws' ? { fallback: options.fallback } : 'throws',
147
148
  })
148
149
  },
149
150
  // // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
@@ -309,7 +310,7 @@ export const getResultSchema = (qb: QueryBuilder<any, any, any>): Schema.Schema<
309
310
  const arraySchema = Schema.Array(queryAst.resultSchemaSingle)
310
311
  if (queryAst.pickFirst === false) {
311
312
  return arraySchema
312
- } else if (queryAst.pickFirst === 'no-fallback') {
313
+ } else if (queryAst.pickFirst === 'throws') {
313
314
  // Will throw if the array is empty
314
315
  return arraySchema.pipe(Schema.headOrElse())
315
316
  } else {
package/src/version.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // import packageJson from '../package.json' with { type: 'json' }
3
3
  // export const liveStoreVersion = packageJson.version
4
4
 
5
- export const liveStoreVersion = '0.3.0-dev.36' as const
5
+ export const liveStoreVersion = '0.3.0-dev.38' as const
6
6
 
7
7
  /**
8
8
  * This version number is incremented whenever the internal storage format changes in a breaking way.
@@ -1,77 +0,0 @@
1
- import type { SqliteDsl } from '@livestore/db-schema';
2
- import type { GetValForKey } from '@livestore/utils';
3
- import type { MutationEvent } from './schema/mutations.js';
4
- import type * as DbSchema from './schema/table-def.js';
5
- export declare const makeDerivedMutationDefsForTable: <TTableDef extends DbSchema.TableDefBase<DbSchema.DefaultSqliteTableDefConstrained, DbSchema.TableOptions & {
6
- deriveMutations: {
7
- enabled: true;
8
- };
9
- }>>(table: TTableDef) => {
10
- insert: import("./schema/mutations.js").MutationDef<`_Derived_Create_${any}`, {
11
- readonly [x: string]: any;
12
- } & {
13
- readonly [x: string]: any;
14
- }, any>;
15
- update: import("./schema/mutations.js").MutationDef<`_Derived_Update_${any}`, {
16
- readonly values: {};
17
- readonly where: {};
18
- }, {
19
- readonly values: {};
20
- readonly where: {};
21
- }>;
22
- delete: import("./schema/mutations.js").MutationDef<`_Derived_Delete_${any}`, {
23
- readonly where: {};
24
- }, {
25
- readonly where: {};
26
- }>;
27
- };
28
- export declare const deriveCreateMutationDef: <TTableDef extends DbSchema.TableDefBase<DbSchema.DefaultSqliteTableDefConstrained, DbSchema.TableOptions & {
29
- deriveMutations: {
30
- enabled: true;
31
- };
32
- }>>(table: TTableDef) => import("./schema/mutations.js").MutationDef<`_Derived_Create_${any}`, {
33
- readonly [x: string]: any;
34
- } & {
35
- readonly [x: string]: any;
36
- }, any>;
37
- export declare const deriveUpdateMutationDef: <TTableDef extends DbSchema.TableDefBase<DbSchema.DefaultSqliteTableDefConstrained, DbSchema.TableOptions & {
38
- deriveMutations: {
39
- enabled: true;
40
- };
41
- }>>(table: TTableDef) => import("./schema/mutations.js").MutationDef<`_Derived_Update_${any}`, {
42
- readonly values: {};
43
- readonly where: {};
44
- }, {
45
- readonly values: {};
46
- readonly where: {};
47
- }>;
48
- export declare const deriveDeleteMutationDef: <TTableDef extends DbSchema.TableDefBase<DbSchema.DefaultSqliteTableDefConstrained, DbSchema.TableOptions & {
49
- deriveMutations: {
50
- enabled: true;
51
- };
52
- }>>(table: TTableDef) => import("./schema/mutations.js").MutationDef<`_Derived_Delete_${any}`, {
53
- readonly where: {};
54
- }, {
55
- readonly where: {};
56
- }>;
57
- /**
58
- * Convenience helper functions on top of the derived mutation definitions.
59
- */
60
- export type DerivedMutationHelperFns<TColumns extends SqliteDsl.ConstraintColumns, TOptions extends DbSchema.TableOptions> = {
61
- insert: DerivedMutationHelperFns.InsertMutationFn<TColumns, TOptions>;
62
- update: DerivedMutationHelperFns.UpdateMutationFn<TColumns, TOptions>;
63
- delete: DerivedMutationHelperFns.DeleteMutationFn<TColumns, TOptions>;
64
- };
65
- export declare namespace DerivedMutationHelperFns {
66
- export type InsertMutationFn<TColumns extends SqliteDsl.ConstraintColumns, TOptions extends DbSchema.TableOptions> = SqliteDsl.AnyIfConstained<TColumns, UseShortcut<TOptions> extends true ? (values?: GetValForKey<SqliteDsl.FromColumns.InsertRowDecoded<TColumns>, 'value'>) => MutationEvent.PartialAny : (values: SqliteDsl.FromColumns.InsertRowDecoded<TColumns>) => MutationEvent.PartialAny>;
67
- export type UpdateMutationFn<TColumns extends SqliteDsl.ConstraintColumns, TOptions extends DbSchema.TableOptions> = SqliteDsl.AnyIfConstained<TColumns, UseShortcut<TOptions> extends true ? (values: Partial<GetValForKey<SqliteDsl.FromColumns.RowDecoded<TColumns>, 'value'>>) => MutationEvent.PartialAny : (args: {
68
- where: Partial<SqliteDsl.FromColumns.RowDecoded<TColumns>>;
69
- values: Partial<SqliteDsl.FromColumns.RowDecoded<TColumns>>;
70
- }) => MutationEvent.PartialAny>;
71
- export type DeleteMutationFn<TColumns extends SqliteDsl.ConstraintColumns, _TOptions extends DbSchema.TableOptions> = (args: {
72
- where: Partial<SqliteDsl.FromColumns.RowDecoded<TColumns>>;
73
- }) => MutationEvent.PartialAny;
74
- type UseShortcut<TOptions extends DbSchema.TableOptions> = TOptions['isSingleColumn'] extends true ? TOptions['isSingleton'] extends true ? true : false : false;
75
- export {};
76
- }
77
- //# sourceMappingURL=derived-mutations.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"derived-mutations.d.ts","sourceRoot":"","sources":["../src/derived-mutations.ts"],"names":[],"mappings":"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"}