@livestore/common 0.4.0-dev.1 → 0.4.0-dev.11

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 (263) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +8 -3
  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 +135 -52
  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/EventSequenceNumber.d.ts +4 -1
  65. package/dist/schema/EventSequenceNumber.d.ts.map +1 -1
  66. package/dist/schema/EventSequenceNumber.js +4 -1
  67. package/dist/schema/EventSequenceNumber.js.map +1 -1
  68. package/dist/schema/EventSequenceNumber.test.js +2 -2
  69. package/dist/schema/LiveStoreEvent.d.ts +1 -1
  70. package/dist/schema/LiveStoreEvent.d.ts.map +1 -1
  71. package/dist/schema/LiveStoreEvent.js +1 -2
  72. package/dist/schema/LiveStoreEvent.js.map +1 -1
  73. package/dist/schema/mod.d.ts +2 -0
  74. package/dist/schema/mod.d.ts.map +1 -1
  75. package/dist/schema/mod.js +1 -0
  76. package/dist/schema/mod.js.map +1 -1
  77. package/dist/schema/schema.d.ts +15 -0
  78. package/dist/schema/schema.d.ts.map +1 -1
  79. package/dist/schema/schema.js +26 -1
  80. package/dist/schema/schema.js.map +1 -1
  81. package/dist/schema/state/sqlite/client-document-def.d.ts +35 -5
  82. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  83. package/dist/schema/state/sqlite/client-document-def.js +95 -4
  84. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  85. package/dist/schema/state/sqlite/client-document-def.test.js +16 -0
  86. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  87. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  88. package/dist/schema/state/sqlite/column-annotations.js +14 -6
  89. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  90. package/dist/schema/state/sqlite/column-def.d.ts +6 -2
  91. package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
  92. package/dist/schema/state/sqlite/column-def.js +128 -185
  93. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  94. package/dist/schema/state/sqlite/column-def.test.js +116 -73
  95. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  96. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +2 -1
  97. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
  98. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +23 -6
  99. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  100. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  101. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +2 -1
  102. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  103. package/dist/schema/state/sqlite/mod.d.ts +1 -1
  104. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  105. package/dist/schema/state/sqlite/mod.js +1 -1
  106. package/dist/schema/state/sqlite/mod.js.map +1 -1
  107. package/dist/schema/state/sqlite/query-builder/api.d.ts +5 -2
  108. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  109. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  110. package/dist/schema/state/sqlite/query-builder/impl.js +6 -2
  111. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  112. package/dist/schema/state/sqlite/query-builder/impl.test.js +137 -2
  113. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  114. package/dist/schema/state/sqlite/system-tables.d.ts +42 -6
  115. package/dist/schema/state/sqlite/system-tables.d.ts.map +1 -1
  116. package/dist/schema/state/sqlite/system-tables.js +2 -0
  117. package/dist/schema/state/sqlite/system-tables.js.map +1 -1
  118. package/dist/schema/state/sqlite/table-def.d.ts +4 -4
  119. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  120. package/dist/schema/state/sqlite/table-def.js +2 -2
  121. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  122. package/dist/schema/state/sqlite/table-def.test.js +87 -2
  123. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  124. package/dist/schema/unknown-events.d.ts +47 -0
  125. package/dist/schema/unknown-events.d.ts.map +1 -0
  126. package/dist/schema/unknown-events.js +69 -0
  127. package/dist/schema/unknown-events.js.map +1 -0
  128. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  129. package/dist/sql-queries/sql-query-builder.js +2 -1
  130. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  131. package/dist/sync/ClientSessionSyncProcessor.d.ts +9 -11
  132. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  133. package/dist/sync/ClientSessionSyncProcessor.js +36 -33
  134. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  135. package/dist/sync/errors.d.ts +61 -0
  136. package/dist/sync/errors.d.ts.map +1 -0
  137. package/dist/sync/errors.js +36 -0
  138. package/dist/sync/errors.js.map +1 -0
  139. package/dist/sync/index.d.ts +3 -0
  140. package/dist/sync/index.d.ts.map +1 -1
  141. package/dist/sync/index.js +3 -0
  142. package/dist/sync/index.js.map +1 -1
  143. package/dist/sync/mock-sync-backend.d.ts +23 -0
  144. package/dist/sync/mock-sync-backend.d.ts.map +1 -0
  145. package/dist/sync/mock-sync-backend.js +114 -0
  146. package/dist/sync/mock-sync-backend.js.map +1 -0
  147. package/dist/sync/next/compact-events.d.ts.map +1 -1
  148. package/dist/sync/next/compact-events.js +4 -5
  149. package/dist/sync/next/compact-events.js.map +1 -1
  150. package/dist/sync/next/facts.d.ts.map +1 -1
  151. package/dist/sync/next/facts.js +1 -2
  152. package/dist/sync/next/facts.js.map +1 -1
  153. package/dist/sync/next/history-dag-common.d.ts +50 -11
  154. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  155. package/dist/sync/next/history-dag-common.js +193 -4
  156. package/dist/sync/next/history-dag-common.js.map +1 -1
  157. package/dist/sync/next/history-dag.d.ts.map +1 -1
  158. package/dist/sync/next/history-dag.js +3 -1
  159. package/dist/sync/next/history-dag.js.map +1 -1
  160. package/dist/sync/sync-backend-kv.d.ts +7 -0
  161. package/dist/sync/sync-backend-kv.d.ts.map +1 -0
  162. package/dist/sync/sync-backend-kv.js +18 -0
  163. package/dist/sync/sync-backend-kv.js.map +1 -0
  164. package/dist/sync/sync-backend.d.ts +105 -0
  165. package/dist/sync/sync-backend.d.ts.map +1 -0
  166. package/dist/sync/sync-backend.js +61 -0
  167. package/dist/sync/sync-backend.js.map +1 -0
  168. package/dist/sync/sync.d.ts +6 -84
  169. package/dist/sync/sync.d.ts.map +1 -1
  170. package/dist/sync/sync.js +2 -27
  171. package/dist/sync/sync.js.map +1 -1
  172. package/dist/sync/syncstate.test.js +16 -15
  173. package/dist/sync/syncstate.test.js.map +1 -1
  174. package/dist/sync/transport-chunking.d.ts +36 -0
  175. package/dist/sync/transport-chunking.d.ts.map +1 -0
  176. package/dist/sync/transport-chunking.js +56 -0
  177. package/dist/sync/transport-chunking.js.map +1 -0
  178. package/dist/sync/validate-push-payload.d.ts +1 -1
  179. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  180. package/dist/sync/validate-push-payload.js +6 -6
  181. package/dist/sync/validate-push-payload.js.map +1 -1
  182. package/dist/testing/event-factory.d.ts +68 -0
  183. package/dist/testing/event-factory.d.ts.map +1 -0
  184. package/dist/testing/event-factory.js +80 -0
  185. package/dist/testing/event-factory.js.map +1 -0
  186. package/dist/testing/mod.d.ts +2 -0
  187. package/dist/testing/mod.d.ts.map +1 -0
  188. package/dist/testing/mod.js +2 -0
  189. package/dist/testing/mod.js.map +1 -0
  190. package/dist/version.d.ts +2 -2
  191. package/dist/version.d.ts.map +1 -1
  192. package/dist/version.js +2 -2
  193. package/dist/version.js.map +1 -1
  194. package/package.json +7 -8
  195. package/src/ClientSessionLeaderThreadProxy.ts +8 -3
  196. package/src/adapter-types.ts +13 -3
  197. package/src/devtools/devtools-messages-common.ts +1 -8
  198. package/src/errors.ts +33 -4
  199. package/src/leader-thread/LeaderSyncProcessor.ts +204 -63
  200. package/src/leader-thread/eventlog.ts +10 -6
  201. package/src/leader-thread/leader-worker-devtools.ts +6 -2
  202. package/src/leader-thread/make-leader-thread-layer.test.ts +44 -0
  203. package/src/leader-thread/make-leader-thread-layer.ts +137 -26
  204. package/src/leader-thread/materialize-event.ts +34 -9
  205. package/src/leader-thread/recreate-db.ts +11 -3
  206. package/src/leader-thread/shutdown-channel.ts +16 -2
  207. package/src/leader-thread/types.ts +7 -5
  208. package/src/materializer-helper.ts +22 -5
  209. package/src/rematerialize-from-eventlog.ts +33 -23
  210. package/src/schema/EventDef.ts +3 -0
  211. package/src/schema/EventSequenceNumber.test.ts +2 -2
  212. package/src/schema/EventSequenceNumber.ts +5 -2
  213. package/src/schema/LiveStoreEvent.ts +1 -2
  214. package/src/schema/mod.ts +2 -0
  215. package/src/schema/schema.ts +37 -1
  216. package/src/schema/state/sqlite/client-document-def.test.ts +17 -0
  217. package/src/schema/state/sqlite/client-document-def.ts +117 -5
  218. package/src/schema/state/sqlite/column-annotations.ts +16 -6
  219. package/src/schema/state/sqlite/column-def.test.ts +150 -93
  220. package/src/schema/state/sqlite/column-def.ts +136 -203
  221. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +26 -6
  222. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +2 -1
  223. package/src/schema/state/sqlite/mod.ts +1 -0
  224. package/src/schema/state/sqlite/query-builder/api.ts +7 -2
  225. package/src/schema/state/sqlite/query-builder/impl.test.ts +187 -6
  226. package/src/schema/state/sqlite/query-builder/impl.ts +8 -2
  227. package/src/schema/state/sqlite/system-tables.ts +2 -0
  228. package/src/schema/state/sqlite/table-def.test.ts +112 -2
  229. package/src/schema/state/sqlite/table-def.ts +9 -8
  230. package/src/schema/unknown-events.ts +131 -0
  231. package/src/sql-queries/sql-query-builder.ts +2 -1
  232. package/src/sync/ClientSessionSyncProcessor.ts +56 -49
  233. package/src/sync/errors.ts +38 -0
  234. package/src/sync/index.ts +3 -0
  235. package/src/sync/mock-sync-backend.ts +184 -0
  236. package/src/sync/next/compact-events.ts +4 -5
  237. package/src/sync/next/facts.ts +1 -3
  238. package/src/sync/next/history-dag-common.ts +272 -21
  239. package/src/sync/next/history-dag.ts +3 -1
  240. package/src/sync/sync-backend-kv.ts +22 -0
  241. package/src/sync/sync-backend.ts +185 -0
  242. package/src/sync/sync.ts +6 -89
  243. package/src/sync/syncstate.test.ts +17 -15
  244. package/src/sync/transport-chunking.ts +90 -0
  245. package/src/sync/validate-push-payload.ts +6 -7
  246. package/src/testing/event-factory.ts +133 -0
  247. package/src/testing/mod.ts +1 -0
  248. package/src/version.ts +2 -2
  249. package/dist/schema-management/migrations.test.d.ts +0 -2
  250. package/dist/schema-management/migrations.test.d.ts.map +0 -1
  251. package/dist/schema-management/migrations.test.js +0 -52
  252. package/dist/schema-management/migrations.test.js.map +0 -1
  253. package/dist/sync/next/graphology.d.ts +0 -8
  254. package/dist/sync/next/graphology.d.ts.map +0 -1
  255. package/dist/sync/next/graphology.js +0 -30
  256. package/dist/sync/next/graphology.js.map +0 -1
  257. package/dist/sync/next/graphology_.d.ts +0 -3
  258. package/dist/sync/next/graphology_.d.ts.map +0 -1
  259. package/dist/sync/next/graphology_.js +0 -3
  260. package/dist/sync/next/graphology_.js.map +0 -1
  261. package/src/sync/next/ambient.d.ts +0 -3
  262. package/src/sync/next/graphology.ts +0 -41
  263. package/src/sync/next/graphology_.ts +0 -2
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Effect, Schema, Stream } from '@livestore/utils/effect';
1
+ import { Effect, Layer, Schema, Stream } from '@livestore/utils/effect';
2
2
  declare const UnexpectedError_base: Schema.TaggedErrorClass<UnexpectedError, "LiveStore.UnexpectedError", {
3
3
  readonly _tag: Schema.tag<"LiveStore.UnexpectedError">;
4
4
  } & {
@@ -8,14 +8,18 @@ declare const UnexpectedError_base: Schema.TaggedErrorClass<UnexpectedError, "Li
8
8
  }>;
9
9
  export declare class UnexpectedError extends UnexpectedError_base {
10
10
  static mapToUnexpectedError: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, UnexpectedError, R>;
11
+ static mapToUnexpectedErrorLayer: <A, E, R>(layer: Layer.Layer<A, E, R>) => Layer.Layer<A, UnexpectedError, R>;
11
12
  static mapToUnexpectedErrorStream: <A, E, R>(stream: Stream.Stream<A, E, R>) => Stream.Stream<A, UnexpectedError, R>;
12
13
  }
13
- declare const SyncError_base: Schema.TaggedErrorClass<SyncError, "LiveStore.SyncError", {
14
- readonly _tag: Schema.tag<"LiveStore.SyncError">;
14
+ declare const MaterializerHashMismatchError_base: Schema.TaggedErrorClass<MaterializerHashMismatchError, "LiveStore.MaterializerHashMismatchError", {
15
+ readonly _tag: Schema.tag<"LiveStore.MaterializerHashMismatchError">;
15
16
  } & {
16
- cause: typeof Schema.Defect;
17
+ eventName: typeof Schema.String;
18
+ note: Schema.optionalWith<typeof Schema.String, {
19
+ default: () => string;
20
+ }>;
17
21
  }>;
18
- export declare class SyncError extends SyncError_base {
22
+ export declare class MaterializerHashMismatchError extends MaterializerHashMismatchError_base {
19
23
  }
20
24
  declare const IntentionalShutdownCause_base: Schema.TaggedErrorClass<IntentionalShutdownCause, "LiveStore.IntentionalShutdownCause", {
21
25
  readonly _tag: Schema.tag<"LiveStore.IntentionalShutdownCause">;
@@ -46,5 +50,43 @@ declare const SqliteError_base: Schema.TaggedErrorClass<SqliteError, "LiveStore.
46
50
  }>;
47
51
  export declare class SqliteError extends SqliteError_base {
48
52
  }
53
+ declare const UnknownEventError_base: Schema.TaggedErrorClass<UnknownEventError, "LiveStore.UnknownEventError", {
54
+ readonly _tag: Schema.tag<"LiveStore.UnknownEventError">;
55
+ } & {
56
+ event: Schema.SchemaClass<{
57
+ readonly clientId: string;
58
+ readonly sessionId: string;
59
+ readonly name: string;
60
+ readonly seqNum: {
61
+ readonly global: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">;
62
+ readonly client: number & import("effect/Brand").Brand<"ClientEventSequenceNumber">;
63
+ readonly rebaseGeneration: number;
64
+ };
65
+ readonly args: any;
66
+ }, {
67
+ readonly clientId: string;
68
+ readonly sessionId: string;
69
+ readonly name: string;
70
+ readonly seqNum: {
71
+ readonly global: number;
72
+ readonly client: number;
73
+ readonly rebaseGeneration: number;
74
+ };
75
+ readonly args: any;
76
+ }, never>;
77
+ reason: Schema.Literal<["event-definition-missing", "materializer-missing"]>;
78
+ operation: typeof Schema.String;
79
+ note: Schema.optional<typeof Schema.String>;
80
+ }>;
81
+ export declare class UnknownEventError extends UnknownEventError_base {
82
+ }
83
+ declare const MaterializeError_base: Schema.TaggedErrorClass<MaterializeError, "LiveStore.MaterializeError", {
84
+ readonly _tag: Schema.tag<"LiveStore.MaterializeError">;
85
+ } & {
86
+ cause: Schema.Union<[typeof MaterializerHashMismatchError, typeof SqliteError, typeof UnknownEventError]>;
87
+ note: Schema.optional<typeof Schema.String>;
88
+ }>;
89
+ export declare class MaterializeError extends MaterializeError_base {
90
+ }
49
91
  export {};
50
92
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;;;;;;;;AAEhE,qBAAa,eAAgB,SAAQ,oBAInC;IACA,MAAM,CAAC,oBAAoB,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,0CAInE;IAEH,MAAM,CAAC,0BAA0B,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,0CAGzE;CACJ;;;;;;AAED,qBAAa,SAAU,SAAQ,cAE7B;CAAG;;;;;;AAEL,qBAAa,wBAAyB,SAAQ,6BAK7C;CAAG;;;;;;AAEJ,qBAAa,gBAAiB,SAAQ,qBAEpC;CAAG;;;;;;;;IASH,6BAA6B;;IAI7B,iCAAiC;;;;AAXnC,qBAAa,WAAY,SAAQ,gBAc/B;CAAG"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;;;;;;;;AAI9E,qBAAa,eAAgB,SAAQ,oBAInC;IACA,MAAM,CAAC,oBAAoB,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,0CAInE;IAEH,MAAM,CAAC,yBAAyB,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,wCAOrE;IAEH,MAAM,CAAC,0BAA0B,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,0CAGzE;CACJ;;;;;;;;;AAED,qBAAa,6BAA8B,SAAQ,kCAQlD;CAAG;;;;;;AAEJ,qBAAa,wBAAyB,SAAQ,6BAK7C;CAAG;;;;;;AAEJ,qBAAa,gBAAiB,SAAQ,qBAEpC;CAAG;;;;;;;;IASH,6BAA6B;;IAI7B,iCAAiC;;;;AAXnC,qBAAa,WAAY,SAAQ,gBAc/B;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEL,qBAAa,iBAAkB,SAAQ,sBAKrC;CAAG;;;;;;;AAEL,qBAAa,gBAAiB,SAAQ,qBAGpC;CAAG"}
package/dist/errors.js CHANGED
@@ -1,14 +1,21 @@
1
- import { Effect, Schema, Stream } from '@livestore/utils/effect';
1
+ import { Cause, Effect, Layer, Schema, Stream } from '@livestore/utils/effect';
2
+ import * as LiveStoreEvent from "./schema/LiveStoreEvent.js";
2
3
  export class UnexpectedError extends Schema.TaggedError()('LiveStore.UnexpectedError', {
3
4
  cause: Schema.Defect,
4
5
  note: Schema.optional(Schema.String),
5
6
  payload: Schema.optional(Schema.Any),
6
7
  }) {
7
8
  static mapToUnexpectedError = (effect) => effect.pipe(Effect.mapError((cause) => (Schema.is(UnexpectedError)(cause) ? cause : new UnexpectedError({ cause }))), Effect.catchAllDefect((cause) => new UnexpectedError({ cause })));
9
+ static mapToUnexpectedErrorLayer = (layer) => layer.pipe(Layer.catchAllCause((cause) => Cause.isFailType(cause) && Schema.is(UnexpectedError)(cause.error)
10
+ ? Layer.fail(cause.error)
11
+ : Layer.fail(new UnexpectedError({ cause: cause }))));
8
12
  static mapToUnexpectedErrorStream = (stream) => stream.pipe(Stream.mapError((cause) => (Schema.is(UnexpectedError)(cause) ? cause : new UnexpectedError({ cause }))));
9
13
  }
10
- export class SyncError extends Schema.TaggedError()('LiveStore.SyncError', {
11
- cause: Schema.Defect,
14
+ export class MaterializerHashMismatchError extends Schema.TaggedError()('LiveStore.MaterializerHashMismatchError', {
15
+ eventName: Schema.String,
16
+ note: Schema.optionalWith(Schema.String, {
17
+ default: () => 'Please make sure your event materializer is a pure function without side effects.',
18
+ }),
12
19
  }) {
13
20
  }
14
21
  export class IntentionalShutdownCause extends Schema.TaggedError()('LiveStore.IntentionalShutdownCause', {
@@ -33,4 +40,16 @@ export class SqliteError extends Schema.TaggedError()('LiveStore.SqliteError', {
33
40
  note: Schema.optional(Schema.String),
34
41
  }) {
35
42
  }
43
+ export class UnknownEventError extends Schema.TaggedError()('LiveStore.UnknownEventError', {
44
+ event: LiveStoreEvent.AnyEncoded.pipe(Schema.pick('name', 'args', 'seqNum', 'clientId', 'sessionId')),
45
+ reason: Schema.Literal('event-definition-missing', 'materializer-missing'),
46
+ operation: Schema.String,
47
+ note: Schema.optional(Schema.String),
48
+ }) {
49
+ }
50
+ export class MaterializeError extends Schema.TaggedError()('LiveStore.MaterializeError', {
51
+ cause: Schema.Union(MaterializerHashMismatchError, SqliteError, UnknownEventError),
52
+ note: Schema.optional(Schema.String),
53
+ }) {
54
+ }
36
55
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhE,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,WAAW,EAAmB,CAAC,2BAA2B,EAAE;IACtG,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC;CACrC,CAAC;IACA,MAAM,CAAC,oBAAoB,GAAG,CAAU,MAA8B,EAAE,EAAE,CACxE,MAAM,CAAC,IAAI,CACT,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EACxG,MAAM,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CACjE,CAAA;IAEH,MAAM,CAAC,0BAA0B,GAAG,CAAU,MAA8B,EAAE,EAAE,CAC9E,MAAM,CAAC,IAAI,CACT,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CACzG,CAAA;;AAGL,MAAM,OAAO,SAAU,SAAQ,MAAM,CAAC,WAAW,EAAa,CAAC,qBAAqB,EAAE;IACpF,KAAK,EAAE,MAAM,CAAC,MAAM;CACrB,CAAC;CAAG;AAEL,MAAM,OAAO,wBAAyB,SAAQ,MAAM,CAAC,WAAW,EAA4B,CAC1F,oCAAoC,EACpC;IACE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAE,QAAQ,CAAC;CACvF,CACF;CAAG;AAEJ,MAAM,OAAO,gBAAiB,SAAQ,MAAM,CAAC,WAAW,EAAoB,CAAC,4BAA4B,EAAE;IACzG,MAAM,EAAE,MAAM,CAAC,MAAM;CACtB,CAAC;CAAG;AAEL,MAAM,OAAO,WAAY,SAAQ,MAAM,CAAC,WAAW,EAAe,CAAC,uBAAuB,EAAE;IAC1F,KAAK,EAAE,MAAM,CAAC,QAAQ,CACpB,MAAM,CAAC,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC,MAAM;QAClB,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KAC7G,CAAC,CACH;IACD,6BAA6B;IAC7B,wCAAwC;IACxC,8FAA8F;IAC9F,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACjE,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;CACrC,CAAC;CAAG"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import type { Scope } from '@livestore/utils/effect';
2
2
  import { Effect } from '@livestore/utils/effect';
3
- import type { SqliteDb } from '../adapter-types.ts';
4
- import { UnexpectedError } from '../adapter-types.ts';
3
+ import { type SqliteDb, UnexpectedError } from '../adapter-types.ts';
5
4
  import type { LiveStoreSchema } from '../schema/mod.ts';
6
5
  import * as SyncState from '../sync/syncstate.ts';
7
6
  import type { InitialBlockingSyncContext, LeaderSyncProcessor } from './types.ts';
@@ -35,7 +34,7 @@ import type { InitialBlockingSyncContext, LeaderSyncProcessor } from './types.ts
35
34
  *
36
35
  * See ClientSessionSyncProcessor for how the leader and session sync processors are similar/different.
37
36
  */
38
- export declare const makeLeaderSyncProcessor: ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, params, testing, }: {
37
+ export declare const makeLeaderSyncProcessor: ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, livePull, params, testing, }: {
39
38
  schema: LiveStoreSchema;
40
39
  dbState: SqliteDb;
41
40
  initialBlockingSyncContext: InitialBlockingSyncContext;
@@ -52,6 +51,11 @@ export declare const makeLeaderSyncProcessor: ({ schema, dbState, initialBlockin
52
51
  */
53
52
  backendPushBatchSize?: number;
54
53
  };
54
+ /**
55
+ * Whether the sync backend should reactively pull new events from the sync backend
56
+ * When `false`, the sync processor will only do an initial pull
57
+ */
58
+ livePull: boolean;
55
59
  testing: {
56
60
  delays?: {
57
61
  localPushProcessing?: Effect.Effect<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"LeaderSyncProcessor.d.ts","sourceRoot":"","sources":["../../src/leader-thread/LeaderSyncProcessor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuB,KAAK,EAAU,MAAM,yBAAyB,CAAA;AACjF,OAAO,EAGL,MAAM,EAWP,MAAM,yBAAyB,CAAA;AAGhC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAa,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAEhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAIjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAQjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,uBAAuB,GAAI,8FAQrC;IACD,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,QAAQ,CAAA;IACjB,0BAA0B,EAAE,0BAA0B,CAAA;IACtD,sFAAsF;IACtF,gBAAgB,EAAE,SAAS,CAAC,SAAS,CAAA;IACrC,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAA;IAC9B,MAAM,EAAE;QACN;;WAEG;QACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B;;WAEG;QACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAC9B,CAAA;IACD,OAAO,EAAE;QACP,MAAM,CAAC,EAAE;YACP,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;SAC1C,CAAA;KACF,CAAA;CACF,KAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,eAAe,EAAE,KAAK,CAAC,KAAK,CA0O/D,CAAA"}
1
+ {"version":3,"file":"LeaderSyncProcessor.d.ts","sourceRoot":"","sources":["../../src/leader-thread/LeaderSyncProcessor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuB,KAAK,EAAU,MAAM,yBAAyB,CAAA;AACjF,OAAO,EAKL,MAAM,EAYP,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAGL,KAAK,QAAQ,EACb,eAAe,EAChB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AASvD,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAIjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAQjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,uBAAuB,GAAI,wGASrC;IACD,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,QAAQ,CAAA;IACjB,0BAA0B,EAAE,0BAA0B,CAAA;IACtD,sFAAsF;IACtF,gBAAgB,EAAE,SAAS,CAAC,SAAS,CAAA;IACrC,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAA;IAC9B,MAAM,EAAE;QACN;;WAEG;QACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B;;WAEG;QACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAC9B,CAAA;IACD;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE;QACP,MAAM,CAAC,EAAE;YACP,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;SAC1C,CAAA;KACF,CAAA;CACF,KAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,eAAe,EAAE,KAAK,CAAC,KAAK,CAuR/D,CAAA"}
@@ -1,9 +1,9 @@
1
1
  import { casesHandled, isNotUndefined, LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils';
2
- import { BucketQueue, Deferred, Effect, Exit, FiberHandle, Option, OtelTracer, pipe, Queue, ReadonlyArray, Stream, Subscribable, SubscriptionRef, } from '@livestore/utils/effect';
3
- import { SyncError, UnexpectedError } from "../adapter-types.js";
2
+ import { BucketQueue, Cause, Deferred, Duration, Effect, Exit, FiberHandle, Layer, Option, OtelTracer, Queue, ReadonlyArray, Schedule, Stream, Subscribable, SubscriptionRef, } from '@livestore/utils/effect';
3
+ import { UnexpectedError, } from "../adapter-types.js";
4
4
  import { makeMaterializerHash } from "../materializer-helper.js";
5
- import { EventSequenceNumber, getEventDef, LiveStoreEvent, SystemTables } from "../schema/mod.js";
6
- import { LeaderAheadError } from "../sync/sync.js";
5
+ import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } from "../schema/mod.js";
6
+ import { LeaderAheadError, } from "../sync/sync.js";
7
7
  import * as SyncState from "../sync/syncstate.js";
8
8
  import { sql } from "../util.js";
9
9
  import * as Eventlog from "./eventlog.js";
@@ -39,15 +39,12 @@ import { LeaderThreadCtx } from "./types.js";
39
39
  *
40
40
  * See ClientSessionSyncProcessor for how the leader and session sync processors are similar/different.
41
41
  */
42
- export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, params, testing, }) => Effect.gen(function* () {
42
+ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, livePull, params, testing, }) => Effect.gen(function* () {
43
43
  const syncBackendPushQueue = yield* BucketQueue.make();
44
44
  const localPushBatchSize = params.localPushBatchSize ?? 1;
45
45
  const backendPushBatchSize = params.backendPushBatchSize ?? 2;
46
46
  const syncStateSref = yield* SubscriptionRef.make(undefined);
47
- const isClientEvent = (eventEncoded) => {
48
- const { eventDef } = getEventDef(schema, eventEncoded.name);
49
- return eventDef.options.clientOnly;
50
- };
47
+ const isClientEvent = (eventEncoded) => schema.eventsDefsMap.get(eventEncoded.name)?.options.clientOnly ?? false;
51
48
  const connectedClientSessionPullQueues = yield* makePullQueueSet;
52
49
  // This context depends on data from `boot`, we should find a better implementation to avoid this ref indirection.
53
50
  const ctxRef = {
@@ -98,13 +95,30 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
98
95
  const syncState = yield* syncStateSref;
99
96
  if (syncState === undefined)
100
97
  return shouldNeverHappen('Not initialized');
101
- const { eventDef } = getEventDef(schema, name);
98
+ const resolution = yield* resolveEventDef(schema, {
99
+ operation: '@livestore/common:LeaderSyncProcessor:pushPartial',
100
+ event: {
101
+ name,
102
+ args,
103
+ clientId,
104
+ sessionId,
105
+ seqNum: syncState.localHead,
106
+ },
107
+ }).pipe(UnexpectedError.mapToUnexpectedError);
108
+ if (resolution._tag === 'unknown') {
109
+ // Ignore partial pushes for unrecognised events – they are still
110
+ // persisted server-side once a schema update ships.
111
+ return;
112
+ }
102
113
  const eventEncoded = new LiveStoreEvent.EncodedWithMeta({
103
114
  name,
104
115
  args,
105
116
  clientId,
106
117
  sessionId,
107
- ...EventSequenceNumber.nextPair({ seqNum: syncState.localHead, isClient: eventDef.options.clientOnly }),
118
+ ...EventSequenceNumber.nextPair({
119
+ seqNum: syncState.localHead,
120
+ isClient: resolution.eventDef.options.clientOnly,
121
+ }),
108
122
  });
109
123
  yield* push([eventEncoded]);
110
124
  }).pipe(Effect.catchTag('LeaderAheadError', Effect.orDie));
@@ -127,18 +141,23 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
127
141
  const globalPendingEvents = initialSyncState.pending
128
142
  // Don't sync clientOnly events
129
143
  .filter((eventEncoded) => {
130
- const { eventDef } = getEventDef(schema, eventEncoded.name);
131
- return eventDef.options.clientOnly === false;
144
+ const eventDef = schema.eventsDefsMap.get(eventEncoded.name);
145
+ return eventDef === undefined ? true : eventDef.options.clientOnly === false;
132
146
  });
133
147
  if (globalPendingEvents.length > 0) {
134
148
  yield* BucketQueue.offerAll(syncBackendPushQueue, globalPendingEvents);
135
149
  }
136
150
  }
137
- const shutdownOnError = (cause) => Effect.gen(function* () {
138
- if (onError === 'shutdown') {
139
- yield* shutdownChannel.send(UnexpectedError.make({ cause }));
140
- yield* Effect.die(cause);
151
+ const maybeShutdownOnError = (cause) => Effect.gen(function* () {
152
+ if (onError === 'ignore') {
153
+ if (LS_DEV) {
154
+ yield* Effect.logDebug(`Ignoring sync error (${cause._tag === 'Fail' ? cause.error._tag : cause._tag})`, Cause.pretty(cause));
155
+ }
156
+ return;
141
157
  }
158
+ const errorToSend = Cause.isFailType(cause) ? cause.error : UnexpectedError.make({ cause });
159
+ yield* shutdownChannel.send(errorToSend).pipe(Effect.orDie);
160
+ return yield* Effect.die(cause);
142
161
  });
143
162
  yield* backgroundApplyLocalPushes({
144
163
  localPushesLatch,
@@ -154,17 +173,16 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
154
173
  testing: {
155
174
  delay: testing?.delays?.localPushProcessing,
156
175
  },
157
- }).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(shutdownOnError), Effect.forkScoped);
176
+ }).pipe(Effect.catchAllCause(maybeShutdownOnError), Effect.forkScoped);
158
177
  const backendPushingFiberHandle = yield* FiberHandle.make();
159
178
  const backendPushingEffect = backgroundBackendPushing({
160
179
  syncBackendPushQueue,
161
180
  otelSpan,
162
181
  devtoolsLatch: ctxRef.current?.devtoolsLatch,
163
182
  backendPushBatchSize,
164
- }).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(shutdownOnError));
183
+ }).pipe(Effect.catchAllCause(maybeShutdownOnError));
165
184
  yield* FiberHandle.run(backendPushingFiberHandle, backendPushingEffect);
166
185
  yield* backgroundBackendPulling({
167
- initialBackendHead: initialSyncState.upstreamHead.global,
168
186
  isClientEvent,
169
187
  restartBackendPushing: (filteredRebasedPending) => Effect.gen(function* () {
170
188
  // Stop current pushing fiber
@@ -178,13 +196,20 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
178
196
  syncStateSref,
179
197
  localPushesLatch,
180
198
  pullLatch,
199
+ livePull,
181
200
  dbState,
182
201
  otelSpan,
183
202
  initialBlockingSyncContext,
184
203
  devtoolsLatch: ctxRef.current?.devtoolsLatch,
185
204
  connectedClientSessionPullQueues,
186
205
  advancePushHead,
187
- }).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(shutdownOnError), Effect.forkScoped);
206
+ }).pipe(Effect.retry({
207
+ // We want to retry pulling if we've lost connection to the sync backend
208
+ while: (cause) => cause._tag === 'IsOfflineError',
209
+ }), Effect.catchAllCause(maybeShutdownOnError),
210
+ // Needed to avoid `Fiber terminated with an unhandled error` logs which seem to happen because of the `Effect.retry` above.
211
+ // This might be a bug in Effect. Only seems to happen in the browser.
212
+ Effect.provide(Layer.setUnhandledErrorLogLevel(Option.none())), Effect.forkScoped);
188
213
  return { initialLeaderHead: initialSyncState.localHead };
189
214
  }).pipe(Effect.withSpanScoped('@livestore/common:LeaderSyncProcessor:boot'));
190
215
  const pull = ({ cursor }) => Effect.gen(function* () {
@@ -243,13 +268,26 @@ const backgroundApplyLocalPushes = ({ localPushesLatch, localPushesQueue, pullLa
243
268
  const currentRebaseGeneration = syncState.localHead.rebaseGeneration;
244
269
  // Since the rebase generation might have changed since enqueuing, we need to filter out items with older generation
245
270
  // It's important that we filter after we got localPushesLatch, otherwise we might filter with the old generation
246
- const [newEvents, deferreds] = pipe(batchItems, ReadonlyArray.filter(([eventEncoded]) => eventEncoded.seqNum.rebaseGeneration === currentRebaseGeneration), ReadonlyArray.unzip);
247
- if (newEvents.length === 0) {
248
- // console.log('dropping old-gen batch', currentLocalPushGenerationRef.current)
249
- // Allow the backend pulling to start
271
+ const [droppedItems, filteredItems] = ReadonlyArray.partition(batchItems, ([eventEncoded]) => eventEncoded.seqNum.rebaseGeneration >= currentRebaseGeneration);
272
+ if (droppedItems.length > 0) {
273
+ otelSpan?.addEvent(`push:drop-old-generation`, {
274
+ droppedCount: droppedItems.length,
275
+ currentRebaseGeneration,
276
+ });
277
+ /**
278
+ * Dropped pushes may still have a deferred awaiting completion.
279
+ * Fail it so the caller learns the leader advanced and resubmits with the updated generation.
280
+ */
281
+ yield* Effect.forEach(droppedItems.filter((item) => item[1] !== undefined), ([eventEncoded, deferred]) => Deferred.fail(deferred, LeaderAheadError.make({
282
+ minimumExpectedNum: syncState.localHead,
283
+ providedNum: eventEncoded.seqNum,
284
+ })));
285
+ }
286
+ if (filteredItems.length === 0) {
250
287
  yield* pullLatch.open;
251
288
  continue;
252
289
  }
290
+ const [newEvents, deferreds] = ReadonlyArray.unzip(filteredItems);
253
291
  const mergeResult = SyncState.merge({
254
292
  syncState,
255
293
  payload: { _tag: 'local-push', newEvents },
@@ -262,7 +300,7 @@ const backgroundApplyLocalPushes = ({ localPushesLatch, localPushesQueue, pullLa
262
300
  batchSize: newEvents.length,
263
301
  newEvents: TRACE_VERBOSE ? JSON.stringify(newEvents) : undefined,
264
302
  });
265
- return yield* new SyncError({ cause: mergeResult.message });
303
+ return yield* new UnexpectedError({ cause: mergeResult.message });
266
304
  }
267
305
  case 'rebase': {
268
306
  return shouldNeverHappen('The leader thread should never have to rebase due to a local push');
@@ -314,8 +352,8 @@ const backgroundApplyLocalPushes = ({ localPushesLatch, localPushesQueue, pullLa
314
352
  });
315
353
  // Don't sync clientOnly events
316
354
  const filteredBatch = mergeResult.newEvents.filter((eventEncoded) => {
317
- const { eventDef } = getEventDef(schema, eventEncoded.name);
318
- return eventDef.options.clientOnly === false;
355
+ const eventDef = schema.eventsDefsMap.get(eventEncoded.name);
356
+ return eventDef === undefined ? true : eventDef.options.clientOnly === false;
319
357
  });
320
358
  yield* BucketQueue.offerAll(syncBackendPushQueue, filteredBatch);
321
359
  yield* materializeEventsBatch({ batchItems: mergeResult.newEvents, deferreds });
@@ -348,12 +386,12 @@ const materializeEventsBatch = ({ batchItems, deferreds }) => Effect.gen(functio
348
386
  dbEventlog.execute('COMMIT', undefined); // Commit the transaction
349
387
  }).pipe(Effect.uninterruptible, Effect.scoped, Effect.withSpan('@livestore/common:LeaderSyncProcessor:materializeEventItems', {
350
388
  attributes: { batchSize: batchItems.length },
351
- }), Effect.tapCauseLogPretty, UnexpectedError.mapToUnexpectedError);
352
- const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBackendPushing, otelSpan, dbState, syncStateSref, localPushesLatch, pullLatch, devtoolsLatch, initialBlockingSyncContext, connectedClientSessionPullQueues, advancePushHead, }) => Effect.gen(function* () {
389
+ }), Effect.tapCauseLogPretty);
390
+ const backgroundBackendPulling = ({ isClientEvent, restartBackendPushing, otelSpan, dbState, syncStateSref, localPushesLatch, livePull, pullLatch, devtoolsLatch, initialBlockingSyncContext, connectedClientSessionPullQueues, advancePushHead, }) => Effect.gen(function* () {
353
391
  const { syncBackend, dbState: db, dbEventlog, schema } = yield* LeaderThreadCtx;
354
392
  if (syncBackend === undefined)
355
393
  return;
356
- const onNewPullChunk = (newEvents, remaining) => Effect.gen(function* () {
394
+ const onNewPullChunk = (newEvents, pageInfo) => Effect.gen(function* () {
357
395
  if (newEvents.length === 0)
358
396
  return;
359
397
  if (devtoolsLatch !== undefined) {
@@ -381,7 +419,7 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
381
419
  newEventsCount: newEvents.length,
382
420
  newEvents: TRACE_VERBOSE ? JSON.stringify(newEvents) : undefined,
383
421
  });
384
- return yield* new SyncError({ cause: mergeResult.message });
422
+ return yield* new UnexpectedError({ cause: mergeResult.message });
385
423
  }
386
424
  const newBackendHead = newEvents.at(-1).seqNum;
387
425
  Eventlog.updateBackendHead(dbEventlog, newBackendHead);
@@ -393,8 +431,8 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
393
431
  mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
394
432
  });
395
433
  const globalRebasedPendingEvents = mergeResult.newSyncState.pending.filter((event) => {
396
- const { eventDef } = getEventDef(schema, event.name);
397
- return eventDef.options.clientOnly === false;
434
+ const eventDef = schema.eventsDefsMap.get(event.name);
435
+ return eventDef === undefined ? true : eventDef.options.clientOnly === false;
398
436
  });
399
437
  yield* restartBackendPushing(globalRebasedPendingEvents);
400
438
  if (mergeResult.rollbackEvents.length > 0) {
@@ -414,6 +452,12 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
414
452
  newEventsCount: newEvents.length,
415
453
  mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
416
454
  });
455
+ // Ensure push fiber is active after advance by restarting with current pending (non-client) events
456
+ const globalPendingEvents = mergeResult.newSyncState.pending.filter((event) => {
457
+ const eventDef = schema.eventsDefsMap.get(event.name);
458
+ return eventDef === undefined ? true : eventDef.options.clientOnly === false;
459
+ });
460
+ yield* restartBackendPushing(globalPendingEvents);
417
461
  yield* connectedClientSessionPullQueues.offer({
418
462
  payload: SyncState.payloadFromMergeResult(mergeResult),
419
463
  leaderHead: mergeResult.newSyncState.localHead,
@@ -422,7 +466,7 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
422
466
  // `mergeResult.confirmedEvents` don't contain the correct sync metadata, so we need to use
423
467
  // `newEvents` instead which we filter via `mergeResult.confirmedEvents`
424
468
  const confirmedNewEvents = newEvents.filter((event) => mergeResult.confirmedEvents.some((confirmedEvent) => EventSequenceNumber.isEqual(event.seqNum, confirmedEvent.seqNum)));
425
- yield* Eventlog.updateSyncMetadata(confirmedNewEvents);
469
+ yield* Eventlog.updateSyncMetadata(confirmedNewEvents).pipe(UnexpectedError.mapToUnexpectedError);
426
470
  }
427
471
  }
428
472
  // Removes the changeset rows which are no longer needed as we'll never have to rollback beyond this point
@@ -431,15 +475,18 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
431
475
  yield* materializeEventsBatch({ batchItems: mergeResult.newEvents, deferreds: undefined });
432
476
  yield* SubscriptionRef.set(syncStateSref, mergeResult.newSyncState);
433
477
  // Allow local pushes to be processed again
434
- if (remaining === 0) {
478
+ if (pageInfo._tag === 'NoMore') {
435
479
  yield* localPushesLatch.open;
436
480
  }
437
481
  });
438
- const cursorInfo = yield* Eventlog.getSyncBackendCursorInfo({ remoteHead: initialBackendHead });
482
+ const syncState = yield* syncStateSref;
483
+ if (syncState === undefined)
484
+ return shouldNeverHappen('Not initialized');
485
+ const cursorInfo = yield* Eventlog.getSyncBackendCursorInfo({ remoteHead: syncState.upstreamHead.global });
439
486
  const hashMaterializerResult = makeMaterializerHash({ schema, dbState });
440
- yield* syncBackend.pull(cursorInfo).pipe(
487
+ yield* syncBackend.pull(cursorInfo, { live: livePull }).pipe(
441
488
  // TODO only take from queue while connected
442
- Stream.tap(({ batch, remaining }) => Effect.gen(function* () {
489
+ Stream.tap(({ batch, pageInfo }) => Effect.gen(function* () {
443
490
  // yield* Effect.spanEvent('batch', {
444
491
  // attributes: {
445
492
  // batchSize: batch.length,
@@ -456,9 +503,11 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
456
503
  // This is a bug and needs to be fixed https://github.com/livestorejs/livestore/issues/503#issuecomment-3114533165
457
504
  materializerHashLeader: hashMaterializerResult(LiveStoreEvent.encodedFromGlobal(_.eventEncoded)),
458
505
  materializerHashSession: Option.none(),
459
- })), remaining);
460
- yield* initialBlockingSyncContext.update({ processed: batch.length, remaining });
506
+ })), pageInfo);
507
+ yield* initialBlockingSyncContext.update({ processed: batch.length, pageInfo });
461
508
  })), Stream.runDrain, Effect.interruptible);
509
+ // Should only ever happen when livePull is false
510
+ yield* Effect.logDebug('backend-pulling finished', { livePull });
462
511
  }).pipe(Effect.withSpan('@livestore/common:LeaderSyncProcessor:backend-pulling'));
463
512
  const backgroundBackendPushing = ({ syncBackendPushQueue, otelSpan, devtoolsLatch, backendPushBatchSize, }) => Effect.gen(function* () {
464
513
  const { syncBackend } = yield* LeaderThreadCtx;
@@ -475,16 +524,39 @@ const backgroundBackendPushing = ({ syncBackendPushQueue, otelSpan, devtoolsLatc
475
524
  batchSize: queueItems.length,
476
525
  batch: TRACE_VERBOSE ? JSON.stringify(queueItems) : undefined,
477
526
  });
478
- // TODO handle push errors (should only happen during concurrent pull+push)
479
- const pushResult = yield* syncBackend.push(queueItems.map((_) => _.toGlobal())).pipe(Effect.either);
480
- if (pushResult._tag === 'Left') {
481
- if (LS_DEV) {
482
- yield* Effect.logDebug('handled backend-push-error', { error: pushResult.left.toString() });
527
+ // Push with declarative retry/backoff using Effect schedules
528
+ // - Exponential backoff starting at 1s and doubling (1s, 2s, 4s, 8s, 16s, 30s ...)
529
+ // - Delay clamped at 30s (continues retrying at 30s)
530
+ // - Resets automatically after successful push
531
+ // TODO(metrics): expose counters/gauges for retry attempts and queue health via devtools/metrics
532
+ // Only retry for transient UnexpectedError cases
533
+ const isRetryable = (err) => err._tag === 'InvalidPushError' && err.cause._tag === 'LiveStore.UnexpectedError';
534
+ // Input: InvalidPushError | IsOfflineError, Output: Duration
535
+ const retrySchedule = Schedule.exponential(Duration.seconds(1)).pipe(Schedule.andThenEither(Schedule.spaced(Duration.seconds(30))), // clamp at 30 second intervals
536
+ Schedule.compose(Schedule.elapsed), Schedule.whileInput(isRetryable));
537
+ yield* Effect.gen(function* () {
538
+ const iteration = yield* Schedule.CurrentIterationMetadata;
539
+ const pushResult = yield* syncBackend.push(queueItems.map((_) => _.toGlobal())).pipe(Effect.either);
540
+ const retries = iteration.recurrence;
541
+ if (retries > 0 && pushResult._tag === 'Right') {
542
+ otelSpan?.addEvent('backend-push-retry-success', { retries, batchSize: queueItems.length });
483
543
  }
484
- otelSpan?.addEvent('backend-push-error', { error: pushResult.left.toString() });
485
- // wait for interrupt caused by background pulling which will then restart pushing
486
- return yield* Effect.never;
487
- }
544
+ if (pushResult._tag === 'Left') {
545
+ otelSpan?.addEvent('backend-push-error', {
546
+ error: pushResult.left.toString(),
547
+ retries,
548
+ batchSize: queueItems.length,
549
+ });
550
+ const error = pushResult.left;
551
+ if (error._tag === 'IsOfflineError' ||
552
+ (error._tag === 'InvalidPushError' && error.cause._tag === 'ServerAheadError')) {
553
+ // It's a core part of the sync protocol that the sync backend will emit a new pull chunk alongside the ServerAheadError
554
+ yield* Effect.logDebug('handled backend-push-error (waiting for interupt caused by pull)', { error });
555
+ return yield* Effect.never;
556
+ }
557
+ return yield* error;
558
+ }
559
+ }).pipe(Effect.retry(retrySchedule));
488
560
  }
489
561
  }).pipe(Effect.interruptible, Effect.withSpan('@livestore/common:LeaderSyncProcessor:backend-pushing'));
490
562
  const trimChangesetRows = (db, newHead) => {
@@ -575,14 +647,25 @@ const makePullQueueSet = Effect.gen(function* () {
575
647
  offer,
576
648
  };
577
649
  });
650
+ /**
651
+ * Validate a client-provided batch before it is admitted to the leader queue.
652
+ * Ensures the numbers form a strictly increasing chain and that the first
653
+ * event sits ahead of the current push head.
654
+ */
578
655
  const validatePushBatch = (batch, pushHead) => Effect.gen(function* () {
579
656
  if (batch.length === 0) {
580
657
  return;
581
658
  }
582
- // Make sure batch is monotonically increasing
659
+ // Example: session A already enqueued e1…e6 while session B (same client, different
660
+ // session) still believes the head is e1 and submits [e2, e7, e8]. The numbers look
661
+ // monotonic from B’s perspective, but we must reject and force B to rebase locally
662
+ // so the leader never regresses.
583
663
  for (let i = 1; i < batch.length; i++) {
584
664
  if (EventSequenceNumber.isGreaterThanOrEqual(batch[i - 1].seqNum, batch[i].seqNum)) {
585
- shouldNeverHappen(`Events must be ordered in monotonically ascending order by eventNum. Received: [${batch.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`);
665
+ return yield* LeaderAheadError.make({
666
+ minimumExpectedNum: batch[i - 1].seqNum,
667
+ providedNum: batch[i].seqNum,
668
+ });
586
669
  }
587
670
  }
588
671
  // Make sure smallest sequence number is > pushHead