@livestore/common 0.4.0-dev.22 → 0.4.0-dev.23

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 (313) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +9 -9
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/WorkerTransportError.d.ts +11 -0
  5. package/dist/WorkerTransportError.d.ts.map +1 -0
  6. package/dist/WorkerTransportError.js +11 -0
  7. package/dist/WorkerTransportError.js.map +1 -0
  8. package/dist/adapter-types.d.ts +3 -3
  9. package/dist/adapter-types.d.ts.map +1 -1
  10. package/dist/adapter-types.js.map +1 -1
  11. package/dist/bounded-collections.d.ts.map +1 -1
  12. package/dist/bounded-collections.js +6 -4
  13. package/dist/bounded-collections.js.map +1 -1
  14. package/dist/debug-info.js +4 -4
  15. package/dist/debug-info.js.map +1 -1
  16. package/dist/devtools/devtools-messages-common.js +1 -1
  17. package/dist/devtools/devtools-messages-common.js.map +1 -1
  18. package/dist/devtools/mod.js +1 -1
  19. package/dist/devtools/mod.js.map +1 -1
  20. package/dist/errors.d.ts +15 -15
  21. package/dist/errors.d.ts.map +1 -1
  22. package/dist/errors.js +11 -11
  23. package/dist/errors.js.map +1 -1
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/leader-thread/LeaderSyncProcessor.d.ts +20 -6
  29. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  30. package/dist/leader-thread/LeaderSyncProcessor.js +287 -257
  31. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  32. package/dist/leader-thread/RejectedPushError.d.ts +107 -0
  33. package/dist/leader-thread/RejectedPushError.d.ts.map +1 -0
  34. package/dist/leader-thread/RejectedPushError.js +78 -0
  35. package/dist/leader-thread/RejectedPushError.js.map +1 -0
  36. package/dist/leader-thread/connection.js +1 -1
  37. package/dist/leader-thread/connection.js.map +1 -1
  38. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  39. package/dist/leader-thread/eventlog.js +12 -11
  40. package/dist/leader-thread/eventlog.js.map +1 -1
  41. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -2
  42. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  43. package/dist/leader-thread/leader-worker-devtools.js +25 -14
  44. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  45. package/dist/leader-thread/make-leader-thread-layer.d.ts +8 -3
  46. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  47. package/dist/leader-thread/make-leader-thread-layer.js +7 -10
  48. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  49. package/dist/leader-thread/make-leader-thread-layer.test.js +1 -1
  50. package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -1
  51. package/dist/leader-thread/materialize-event.js +4 -4
  52. package/dist/leader-thread/materialize-event.js.map +1 -1
  53. package/dist/leader-thread/recreate-db.js +1 -1
  54. package/dist/leader-thread/recreate-db.js.map +1 -1
  55. package/dist/leader-thread/shutdown-channel.d.ts +2 -2
  56. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  57. package/dist/leader-thread/shutdown-channel.js +2 -2
  58. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  59. package/dist/leader-thread/stream-events.d.ts.map +1 -1
  60. package/dist/leader-thread/stream-events.js +4 -3
  61. package/dist/leader-thread/stream-events.js.map +1 -1
  62. package/dist/leader-thread/types.d.ts +7 -6
  63. package/dist/leader-thread/types.d.ts.map +1 -1
  64. package/dist/leader-thread/types.js.map +1 -1
  65. package/dist/logging.js +4 -4
  66. package/dist/logging.js.map +1 -1
  67. package/dist/make-client-session.js +2 -2
  68. package/dist/make-client-session.js.map +1 -1
  69. package/dist/materializer-helper.js +6 -6
  70. package/dist/materializer-helper.js.map +1 -1
  71. package/dist/otel.d.ts +1 -1
  72. package/dist/otel.d.ts.map +1 -1
  73. package/dist/otel.js +2 -2
  74. package/dist/otel.js.map +1 -1
  75. package/dist/rematerialize-from-eventlog.d.ts +1 -1
  76. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  77. package/dist/rematerialize-from-eventlog.js +11 -9
  78. package/dist/rematerialize-from-eventlog.js.map +1 -1
  79. package/dist/schema/EventDef/define.d.ts +2 -2
  80. package/dist/schema/EventDef/define.d.ts.map +1 -1
  81. package/dist/schema/EventDef/define.js +4 -4
  82. package/dist/schema/EventDef/define.js.map +1 -1
  83. package/dist/schema/EventDef/deprecated.js +3 -3
  84. package/dist/schema/EventDef/deprecated.js.map +1 -1
  85. package/dist/schema/EventDef/deprecated.test.js +1 -1
  86. package/dist/schema/EventDef/deprecated.test.js.map +1 -1
  87. package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -1
  88. package/dist/schema/EventSequenceNumber/client.js +11 -11
  89. package/dist/schema/EventSequenceNumber/client.js.map +1 -1
  90. package/dist/schema/EventSequenceNumber.test.js +1 -1
  91. package/dist/schema/EventSequenceNumber.test.js.map +1 -1
  92. package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -1
  93. package/dist/schema/LiveStoreEvent/client.js +6 -3
  94. package/dist/schema/LiveStoreEvent/client.js.map +1 -1
  95. package/dist/schema/LiveStoreEvent/client.test.d.ts +2 -0
  96. package/dist/schema/LiveStoreEvent/client.test.d.ts.map +1 -0
  97. package/dist/schema/LiveStoreEvent/client.test.js +83 -0
  98. package/dist/schema/LiveStoreEvent/client.test.js.map +1 -0
  99. package/dist/schema/schema.d.ts.map +1 -1
  100. package/dist/schema/schema.js +7 -4
  101. package/dist/schema/schema.js.map +1 -1
  102. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  103. package/dist/schema/state/sqlite/client-document-def.js +18 -6
  104. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  105. package/dist/schema/state/sqlite/client-document-def.test.js +1 -1
  106. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  107. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  108. package/dist/schema/state/sqlite/column-annotations.js +1 -1
  109. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  110. package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
  111. package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
  112. package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
  113. package/dist/schema/state/sqlite/column-def.js +36 -34
  114. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  115. package/dist/schema/state/sqlite/column-def.test.js +7 -6
  116. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  117. package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
  118. package/dist/schema/state/sqlite/column-spec.js +8 -8
  119. package/dist/schema/state/sqlite/column-spec.js.map +1 -1
  120. package/dist/schema/state/sqlite/column-spec.test.js +1 -1
  121. package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
  122. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +2 -2
  123. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  124. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +2 -2
  125. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
  126. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +11 -2
  127. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
  128. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +1 -1
  129. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -1
  130. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +1 -1
  131. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  132. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +1 -1
  133. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  134. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  135. package/dist/schema/state/sqlite/mod.js +3 -5
  136. package/dist/schema/state/sqlite/mod.js.map +1 -1
  137. package/dist/schema/state/sqlite/query-builder/api.d.ts +10 -2
  138. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  139. package/dist/schema/state/sqlite/query-builder/astToSql.js +11 -11
  140. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
  141. package/dist/schema/state/sqlite/query-builder/impl.d.ts +1 -1
  142. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  143. package/dist/schema/state/sqlite/query-builder/impl.js +28 -14
  144. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  145. package/dist/schema/state/sqlite/query-builder/impl.test.js +3 -2
  146. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  147. package/dist/schema/state/sqlite/schema-helpers.js +2 -2
  148. package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
  149. package/dist/schema/state/sqlite/table-def.d.ts +5 -3
  150. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  151. package/dist/schema/state/sqlite/table-def.js +1 -1
  152. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  153. package/dist/schema/state/sqlite/table-def.test.js +57 -4
  154. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  155. package/dist/schema/unknown-events.d.ts +1 -1
  156. package/dist/schema/unknown-events.d.ts.map +1 -1
  157. package/dist/schema/unknown-events.js +1 -1
  158. package/dist/schema/unknown-events.js.map +1 -1
  159. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +1 -1
  160. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -1
  161. package/dist/schema-management/common.js +2 -2
  162. package/dist/schema-management/common.js.map +1 -1
  163. package/dist/schema-management/migrations.js +1 -1
  164. package/dist/schema-management/migrations.js.map +1 -1
  165. package/dist/sql-queries/sql-queries.js +8 -6
  166. package/dist/sql-queries/sql-queries.js.map +1 -1
  167. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  168. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  169. package/dist/sqlite-db-helper.js +3 -3
  170. package/dist/sqlite-db-helper.js.map +1 -1
  171. package/dist/sqlite-types.d.ts +2 -2
  172. package/dist/sqlite-types.d.ts.map +1 -1
  173. package/dist/sqlite-types.js.map +1 -1
  174. package/dist/sync/ClientSessionSyncProcessor.d.ts +8 -9
  175. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  176. package/dist/sync/ClientSessionSyncProcessor.js +95 -113
  177. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  178. package/dist/sync/errors.d.ts +0 -38
  179. package/dist/sync/errors.d.ts.map +1 -1
  180. package/dist/sync/errors.js +3 -20
  181. package/dist/sync/errors.js.map +1 -1
  182. package/dist/sync/mock-sync-backend.d.ts +5 -3
  183. package/dist/sync/mock-sync-backend.d.ts.map +1 -1
  184. package/dist/sync/mock-sync-backend.js +70 -68
  185. package/dist/sync/mock-sync-backend.js.map +1 -1
  186. package/dist/sync/next/compact-events.js +6 -6
  187. package/dist/sync/next/compact-events.js.map +1 -1
  188. package/dist/sync/next/facts.d.ts.map +1 -1
  189. package/dist/sync/next/facts.js +6 -6
  190. package/dist/sync/next/facts.js.map +1 -1
  191. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  192. package/dist/sync/next/history-dag-common.js +6 -6
  193. package/dist/sync/next/history-dag-common.js.map +1 -1
  194. package/dist/sync/next/history-dag.js +3 -3
  195. package/dist/sync/next/history-dag.js.map +1 -1
  196. package/dist/sync/next/rebase-events.js +1 -1
  197. package/dist/sync/next/rebase-events.js.map +1 -1
  198. package/dist/sync/next/test/compact-events.calculator.test.js +2 -2
  199. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  200. package/dist/sync/next/test/compact-events.test.d.ts.map +1 -1
  201. package/dist/sync/next/test/compact-events.test.js +2 -2
  202. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  203. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  204. package/dist/sync/next/test/event-fixtures.js +2 -2
  205. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  206. package/dist/sync/sync-backend-kv.d.ts.map +1 -1
  207. package/dist/sync/sync-backend-kv.js.map +1 -1
  208. package/dist/sync/sync-backend.d.ts +3 -3
  209. package/dist/sync/sync-backend.d.ts.map +1 -1
  210. package/dist/sync/sync-backend.js +1 -1
  211. package/dist/sync/sync-backend.js.map +1 -1
  212. package/dist/sync/sync.d.ts +20 -0
  213. package/dist/sync/sync.d.ts.map +1 -1
  214. package/dist/sync/syncstate.d.ts +4 -17
  215. package/dist/sync/syncstate.d.ts.map +1 -1
  216. package/dist/sync/syncstate.js +51 -74
  217. package/dist/sync/syncstate.js.map +1 -1
  218. package/dist/sync/syncstate.test.js +112 -96
  219. package/dist/sync/syncstate.test.js.map +1 -1
  220. package/dist/sync/transport-chunking.js +3 -3
  221. package/dist/sync/transport-chunking.js.map +1 -1
  222. package/dist/sync/validate-push-payload.d.ts +2 -2
  223. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  224. package/dist/sync/validate-push-payload.js +4 -6
  225. package/dist/sync/validate-push-payload.js.map +1 -1
  226. package/dist/util.js +2 -2
  227. package/dist/util.js.map +1 -1
  228. package/dist/version.d.ts.map +1 -1
  229. package/dist/version.js +2 -5
  230. package/dist/version.js.map +1 -1
  231. package/package.json +66 -12
  232. package/src/ClientSessionLeaderThreadProxy.ts +9 -9
  233. package/src/WorkerTransportError.ts +12 -0
  234. package/src/adapter-types.ts +9 -3
  235. package/src/bounded-collections.ts +6 -5
  236. package/src/debug-info.ts +4 -4
  237. package/src/devtools/devtools-messages-common.ts +1 -1
  238. package/src/devtools/mod.ts +1 -1
  239. package/src/errors.ts +18 -17
  240. package/src/index.ts +2 -0
  241. package/src/leader-thread/LeaderSyncProcessor.ts +421 -392
  242. package/src/leader-thread/RejectedPushError.ts +106 -0
  243. package/src/leader-thread/connection.ts +1 -1
  244. package/src/leader-thread/eventlog.ts +16 -14
  245. package/src/leader-thread/leader-worker-devtools.ts +96 -66
  246. package/src/leader-thread/make-leader-thread-layer.test.ts +1 -1
  247. package/src/leader-thread/make-leader-thread-layer.ts +33 -31
  248. package/src/leader-thread/materialize-event.ts +4 -4
  249. package/src/leader-thread/recreate-db.ts +1 -1
  250. package/src/leader-thread/shutdown-channel.ts +2 -6
  251. package/src/leader-thread/stream-events.ts +10 -5
  252. package/src/leader-thread/types.ts +7 -6
  253. package/src/logging.ts +4 -4
  254. package/src/make-client-session.ts +2 -2
  255. package/src/materializer-helper.ts +9 -9
  256. package/src/otel.ts +3 -2
  257. package/src/rematerialize-from-eventlog.ts +60 -60
  258. package/src/schema/EventDef/define.ts +6 -6
  259. package/src/schema/EventDef/deprecated.test.ts +2 -1
  260. package/src/schema/EventDef/deprecated.ts +3 -3
  261. package/src/schema/EventSequenceNumber/client.ts +11 -11
  262. package/src/schema/EventSequenceNumber.test.ts +2 -1
  263. package/src/schema/LiveStoreEvent/client.test.ts +97 -0
  264. package/src/schema/LiveStoreEvent/client.ts +6 -3
  265. package/src/schema/schema.ts +9 -4
  266. package/src/schema/state/sqlite/client-document-def.test.ts +2 -1
  267. package/src/schema/state/sqlite/client-document-def.ts +20 -6
  268. package/src/schema/state/sqlite/column-annotations.test.ts +2 -1
  269. package/src/schema/state/sqlite/column-annotations.ts +2 -1
  270. package/src/schema/state/sqlite/column-def.test.ts +8 -6
  271. package/src/schema/state/sqlite/column-def.ts +41 -36
  272. package/src/schema/state/sqlite/column-spec.test.ts +3 -1
  273. package/src/schema/state/sqlite/column-spec.ts +9 -8
  274. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +2 -2
  275. package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +2 -1
  276. package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +13 -4
  277. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +3 -3
  278. package/src/schema/state/sqlite/mod.ts +4 -5
  279. package/src/schema/state/sqlite/query-builder/api.ts +12 -5
  280. package/src/schema/state/sqlite/query-builder/astToSql.ts +11 -11
  281. package/src/schema/state/sqlite/query-builder/impl.test.ts +4 -2
  282. package/src/schema/state/sqlite/query-builder/impl.ts +26 -12
  283. package/src/schema/state/sqlite/schema-helpers.ts +2 -2
  284. package/src/schema/state/sqlite/table-def.test.ts +67 -4
  285. package/src/schema/state/sqlite/table-def.ts +8 -15
  286. package/src/schema/unknown-events.ts +2 -2
  287. package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +3 -1
  288. package/src/schema-management/common.ts +2 -2
  289. package/src/schema-management/migrations.ts +1 -1
  290. package/src/sql-queries/sql-queries.ts +10 -6
  291. package/src/sql-queries/sql-query-builder.ts +1 -0
  292. package/src/sqlite-db-helper.ts +3 -3
  293. package/src/sqlite-types.ts +3 -2
  294. package/src/sync/ClientSessionSyncProcessor.ts +148 -152
  295. package/src/sync/errors.ts +10 -22
  296. package/src/sync/mock-sync-backend.ts +139 -97
  297. package/src/sync/next/compact-events.ts +5 -5
  298. package/src/sync/next/facts.ts +7 -6
  299. package/src/sync/next/history-dag-common.ts +9 -6
  300. package/src/sync/next/history-dag.ts +3 -3
  301. package/src/sync/next/rebase-events.ts +1 -1
  302. package/src/sync/next/test/compact-events.calculator.test.ts +3 -2
  303. package/src/sync/next/test/compact-events.test.ts +4 -3
  304. package/src/sync/next/test/event-fixtures.ts +2 -2
  305. package/src/sync/sync-backend-kv.ts +1 -0
  306. package/src/sync/sync-backend.ts +5 -4
  307. package/src/sync/sync.ts +21 -0
  308. package/src/sync/syncstate.test.ts +513 -435
  309. package/src/sync/syncstate.ts +80 -86
  310. package/src/sync/transport-chunking.ts +3 -3
  311. package/src/sync/validate-push-payload.ts +4 -6
  312. package/src/util.ts +2 -2
  313. package/src/version.ts +2 -6
@@ -1,4 +1,4 @@
1
- import { memoizeByRef } from '@livestore/utils'
1
+ import { deepEqual, memoizeByRef } from '@livestore/utils'
2
2
  import { Option, Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import type { EventDef } from '../EventDef/mod.ts'
@@ -175,9 +175,12 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('LiveStoreEve
175
175
  })
176
176
 
177
177
  toGlobal = (): Global.Encoded => ({
178
- ...this,
178
+ name: this.name,
179
+ args: this.args,
179
180
  seqNum: this.seqNum.global,
180
181
  parentSeqNum: this.parentSeqNum.global,
182
+ clientId: this.clientId,
183
+ sessionId: this.sessionId,
181
184
  })
182
185
  }
183
186
 
@@ -191,7 +194,7 @@ export const isEqualEncoded = (a: Encoded, b: Encoded) =>
191
194
  a.name === b.name &&
192
195
  a.clientId === b.clientId &&
193
196
  a.sessionId === b.sessionId &&
194
- JSON.stringify(a.args) === JSON.stringify(b.args) // TODO use schema equality here
197
+ deepEqual(a.args, b.args) // TODO use schema equality here
195
198
 
196
199
  /**
197
200
  * Creates an Effect Schema union for all event types in a schema (with composite sequence numbers).
@@ -58,7 +58,12 @@ export const isLiveStoreSchema = (value: unknown): value is LiveStoreSchema<any,
58
58
  const hasStateMaterializers = v.state?.materializers instanceof Map
59
59
  const hasDevtoolsAlias = typeof v.devtools?.alias === 'string'
60
60
 
61
- return hasEventsMap && hasStateSqliteTables && hasStateMaterializers && hasDevtoolsAlias
61
+ return (
62
+ hasEventsMap === true &&
63
+ hasStateSqliteTables === true &&
64
+ hasStateMaterializers === true &&
65
+ hasDevtoolsAlias === true
66
+ )
62
67
  }
63
68
 
64
69
  // TODO abstract this further away from sqlite/tables
@@ -103,13 +108,13 @@ export const makeSchema = <TInputSchema extends InputSchema>(
103
108
 
104
109
  const eventsDefsMap = new Map<string, EventDef.AnyWithoutFn>()
105
110
 
106
- if (isReadonlyArray(inputSchema.events)) {
111
+ if (isReadonlyArray(inputSchema.events) === true) {
107
112
  for (const eventDef of inputSchema.events) {
108
113
  eventsDefsMap.set(eventDef.name, eventDef)
109
114
  }
110
115
  } else {
111
116
  for (const eventDef of Object.values(inputSchema.events ?? {})) {
112
- if (eventsDefsMap.has(eventDef.name)) {
117
+ if (eventsDefsMap.has(eventDef.name) === true) {
113
118
  shouldNeverHappen(`Duplicate event name: ${eventDef.name}. Please use unique names for events.`)
114
119
  }
115
120
  eventsDefsMap.set(eventDef.name, eventDef)
@@ -117,7 +122,7 @@ export const makeSchema = <TInputSchema extends InputSchema>(
117
122
  }
118
123
 
119
124
  for (const tableDef of tables.values()) {
120
- if (tableIsClientDocumentTable(tableDef) && eventsDefsMap.has(tableDef.set.name) === false) {
125
+ if (tableIsClientDocumentTable(tableDef) === true && eventsDefsMap.has(tableDef.set.name) === false) {
121
126
  eventsDefsMap.set(tableDef.set.name, tableDef.set)
122
127
  }
123
128
  }
@@ -1,6 +1,7 @@
1
- import { Schema } from '@livestore/utils/effect'
2
1
  import { describe, expect, test } from 'vitest'
3
2
 
3
+ import { Schema } from '@livestore/utils/effect'
4
+
4
5
  import { tables } from '../../../__tests__/fixture.ts'
5
6
  import type * as LiveStoreEvent from '../../LiveStoreEvent/mod.ts'
6
7
  import {
@@ -95,7 +95,7 @@ export const clientDocument = <
95
95
  Object.defineProperty(setEventDef, 'schema', {
96
96
  value: Schema.Struct({
97
97
  id: Schema.String,
98
- value: options.partialSet ? Schema.partial(valueSchema) : valueSchema,
98
+ value: options.partialSet === true ? Schema.partial(valueSchema) : valueSchema,
99
99
  }).annotations({ title: `${name}Set:Args` }),
100
100
  })
101
101
  Object.defineProperty(setEventDef, 'options', {
@@ -108,20 +108,26 @@ export const clientDocument = <
108
108
  TEncoded,
109
109
  ClientDocumentTableOptions<TType>
110
110
  > = {
111
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- dynamic table def composition; type safety ensured by ClientDocumentTableDef.Trait
111
112
  get: makeGetQueryBuilder(() => clientDocumentTableDef) as any,
113
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- dynamic table def composition; type safety ensured by SetEventDefLike signature
112
114
  set: setEventDef as any,
115
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- phantom type field for generic inference only
113
116
  Value: 'only-for-type-inference' as any,
114
117
  default: options.default,
115
118
  valueSchema,
116
119
  [ClientDocumentTableDefSymbol]: {
117
120
  derived: {
121
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- dynamic event def composition; type checked at usage sites
118
122
  setEventDef: derivedSetEventDef as any,
123
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- dynamic materializer composition; type checked at usage sites
119
124
  setMaterializer: derivedSetMaterializer as any,
120
125
  },
121
126
  options,
122
127
  },
123
128
  }
124
129
 
130
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- composing tableDef + clientDocumentTableDefTrait into final type; validated by satisfies above
125
131
  const clientDocumentTableDef = {
126
132
  ...tableDef,
127
133
  ...clientDocumentTableDefTrait,
@@ -141,11 +147,14 @@ export const mergeDefaultValues = <T>(defaultValues: T, explicitDefaultValues: T
141
147
  }
142
148
 
143
149
  // Get all unique keys from both objects
150
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Object.keys requires indexable type; T is constrained to object by preceding typeof checks
144
151
  const allKeys = new Set([...Object.keys(defaultValues as any), ...Object.keys(explicitDefaultValues as any)])
145
152
 
146
153
  return Array.from(allKeys).reduce((acc, key) => {
154
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- dynamic key access on generic object; keys validated from Object.keys above
147
155
  acc[key] = (explicitDefaultValues as any)[key] ?? (defaultValues as any)[key]
148
156
  return acc
157
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- reduce accumulator type; result type is T
149
158
  }, {} as any)
150
159
  }
151
160
 
@@ -177,7 +186,7 @@ export const createOptimisticEventSchema = ({
177
186
  defaultValue: any
178
187
  partialSet: boolean
179
188
  }) => {
180
- const targetSchema = partialSet ? Schema.partial(valueSchema) : valueSchema
189
+ const targetSchema = partialSet === true ? Schema.partial(valueSchema) : valueSchema
181
190
  // The transform decode must yield values in the target schema's ENCODED shape.
182
191
  // This keeps JSON columns consistent when Encoded != Type (e.g. Option).
183
192
  const encodeTarget = Schema.encodeSync(targetSchema)
@@ -197,11 +206,13 @@ export const createOptimisticEventSchema = ({
197
206
 
198
207
  // Handle null/undefined/non-object cases
199
208
  if (typeof eventValue !== 'object' || eventValue === null) {
200
- console.warn(`Client document: Non-object event value, using ${partialSet ? 'empty partial' : 'defaults'}`)
201
- return encodeTarget(partialSet ? {} : defaultValue)
209
+ console.warn(
210
+ `Client document: Non-object event value, using ${partialSet === true ? 'empty partial' : 'defaults'}`,
211
+ )
212
+ return encodeTarget(partialSet === true ? {} : defaultValue)
202
213
  }
203
214
 
204
- if (partialSet) {
215
+ if (partialSet === true) {
205
216
  // For partial sets: only preserve fields that exist in new schema
206
217
  const partialResult: Record<string, unknown> = {}
207
218
  let hasValidFields = false
@@ -214,7 +225,7 @@ export const createOptimisticEventSchema = ({
214
225
  // Drop fields that don't exist in new schema
215
226
  }
216
227
 
217
- if (hasValidFields) {
228
+ if (hasValidFields === true) {
218
229
  try {
219
230
  const decoded = Schema.decodeUnknownSync(targetSchema)(partialResult)
220
231
  return encodeTarget(decoded)
@@ -366,11 +377,14 @@ const makeGetQueryBuilder = <TTableDef extends ClientDocumentTableDef<any, any,
366
377
  return {
367
378
  [QueryBuilderTypeId]: QueryBuilderTypeId,
368
379
  [QueryBuilderAstSymbol]: ast,
380
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- phantom type field for generic inference only
369
381
  ResultType: 'only-for-type-inference' as any,
370
382
  asSql: () => ({ query, bindValues: [id] }),
371
383
  toString: () => query.toString(),
384
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- spreading empty object to satisfy QueryBuilder interface requirements
372
385
  ...({} as any), // Needed for type cast
373
386
  }
387
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- makeGetQueryBuilder return type uses complex conditional generics
374
388
  }) as any
375
389
  }
376
390
 
@@ -1,6 +1,7 @@
1
- import { Schema, SchemaAST } from '@livestore/utils/effect'
2
1
  import { describe, expect, test } from 'vitest'
3
2
 
3
+ import { Schema, SchemaAST } from '@livestore/utils/effect'
4
+
4
5
  import { withColumnType, withPrimaryKey } from './column-annotations.ts'
5
6
 
6
7
  describe.concurrent('annotations', () => {
@@ -1,5 +1,6 @@
1
1
  import type { Schema } from '@livestore/utils/effect'
2
2
  import { dual, Option, SchemaAST } from '@livestore/utils/effect'
3
+
3
4
  import type { SqliteDsl } from './db-schema/mod.ts'
4
5
 
5
6
  export const PrimaryKeyId = Symbol.for('livestore/state/sqlite/annotations/primary-key')
@@ -79,7 +80,7 @@ const validateSchemaColumnTypeCompatibility = (
79
80
  const applyAnnotations = <T extends Schema.Schema.All>(schema: T, overrides: Record<PropertyKey, unknown>): T => {
80
81
  const identifier = SchemaAST.getIdentifierAnnotation(schema.ast)
81
82
  const shouldPreserveIdentifier = Option.isSome(identifier) && !(SchemaAST.IdentifierAnnotationId in overrides)
82
- const annotations: Record<PropertyKey, unknown> = shouldPreserveIdentifier
83
+ const annotations: Record<PropertyKey, unknown> = shouldPreserveIdentifier === true
83
84
  ? { ...overrides, [SchemaAST.IdentifierAnnotationId]: identifier.value }
84
85
  : overrides
85
86
 
@@ -1,6 +1,8 @@
1
- import { Schema } from '@livestore/utils/effect'
2
1
  import { assert, describe, expect, it } from 'vitest'
3
2
 
3
+ import { Schema } from '@livestore/utils/effect'
4
+ import { objectToString } from '@livestore/utils'
5
+
4
6
  import * as State from '../mod.ts'
5
7
  import { withAutoIncrement, withColumnType, withDefault, withPrimaryKey, withUnique } from './column-annotations.ts'
6
8
 
@@ -299,7 +301,7 @@ describe('getColumnDefForSchema', () => {
299
301
  it('should handle Uint8Array as blob column', () => {
300
302
  const columnDef = State.SQLite.getColumnDefForSchema(Schema.Uint8Array)
301
303
  expect(columnDef.columnType).toBe('blob')
302
- expect(columnDef.schema.toString()).toBe('Uint8ArrayFromSelf')
304
+ expect(objectToString(columnDef.schema)).toBe('Uint8ArrayFromSelf')
303
305
  })
304
306
  })
305
307
 
@@ -356,8 +358,8 @@ describe('getColumnDefForSchema', () => {
356
358
 
357
359
  expect(table.sqliteDef.columns.active.nullable).toBe(true)
358
360
  expect(table.sqliteDef.columns.active.columnType).toBe('integer')
359
- expect(table.sqliteDef.columns.active.schema.toString()).toBe('(number <-> boolean) | null')
360
- expect((table.rowSchema as any).fields.active.toString()).toBe('(number <-> boolean) | null')
361
+ expect(objectToString(table.sqliteDef.columns.active.schema)).toBe('(number <-> boolean) | null')
362
+ expect(String((table.rowSchema as any).fields.active)).toBe('(number <-> boolean) | null')
361
363
  })
362
364
 
363
365
  it('should handle optional complex types with JSON encoding', () => {
@@ -406,8 +408,8 @@ describe('getColumnDefForSchema', () => {
406
408
  const table = State.SQLite.table({ name: 'timers', schema })
407
409
 
408
410
  expect(table.sqliteDef.columns.status.columnType).toBe('text')
409
- expect(table.sqliteDef.columns.status.schema.toString()).toBe('"idle" | "running" | "stopped"')
410
- expect((table.rowSchema as any).fields.status.toString()).toBe('"idle" | "running" | "stopped"')
411
+ expect(objectToString(table.sqliteDef.columns.status.schema)).toBe('"idle" | "running" | "stopped"')
412
+ expect(String((table.rowSchema as any).fields.status)).toBe('"idle" | "running" | "stopped"')
411
413
  })
412
414
 
413
415
  it('should handle Schema.NullOr with complex types', () => {
@@ -20,19 +20,20 @@ export const getColumnDefForSchema = (
20
20
 
21
21
  // Extract annotations
22
22
  const getAnnotation = <T>(annotationId: symbol): Option.Option<T> =>
23
- propertySignature
23
+ propertySignature !== undefined
24
24
  ? hasPropertyAnnotation<T>(propertySignature, annotationId)
25
25
  : SchemaAST.getAnnotation<T>(annotationId)(ast)
26
26
 
27
27
  const columnType = SchemaAST.getAnnotation<SqliteDsl.FieldColumnType>(ColumnType)(ast)
28
28
 
29
29
  // Check if schema has null (e.g., Schema.NullOr) or undefined or if it's forced nullable (optional field)
30
- const isNullable = forceNullable || hasNull(ast) || hasUndefined(ast)
30
+ const isNullable = forceNullable === true || hasNull(ast) === true || hasUndefined(ast) === true
31
31
 
32
32
  // Get base column definition with nullable flag
33
- const baseColumn = Option.isSome(columnType)
34
- ? getColumnForType(columnType.value, isNullable)
35
- : getColumnForSchema(schema, isNullable)
33
+ const baseColumn =
34
+ Option.isSome(columnType) === true
35
+ ? getColumnForType(columnType.value, isNullable)
36
+ : getColumnForSchema(schema, isNullable)
36
37
 
37
38
  // Apply annotations
38
39
  const primaryKey = getAnnotation<boolean>(PrimaryKeyId).pipe(Option.getOrElse(() => false))
@@ -41,9 +42,9 @@ export const getColumnDefForSchema = (
41
42
 
42
43
  return {
43
44
  ...baseColumn,
44
- ...(primaryKey && { primaryKey: true }),
45
- ...(autoIncrement && { autoIncrement: true }),
46
- ...(Option.isSome(defaultValue) && { default: Option.some(defaultValue.value) }),
45
+ ...(primaryKey === true ? { primaryKey: true } : {}),
46
+ ...(autoIncrement === true ? { autoIncrement: true } : {}),
47
+ ...(Option.isSome(defaultValue) === true ? { default: Option.some(defaultValue.value) } : {}),
47
48
  }
48
49
  }
49
50
 
@@ -51,9 +52,9 @@ const hasPropertyAnnotation = <T>(
51
52
  propertySignature: SchemaAST.PropertySignature,
52
53
  annotationId: symbol,
53
54
  ): Option.Option<T> => {
54
- if ('annotations' in propertySignature && propertySignature.annotations) {
55
+ if ('annotations' in propertySignature && propertySignature.annotations !== undefined) {
55
56
  const annotation = SchemaAST.getAnnotation<T>(annotationId)(propertySignature as any)
56
- if (Option.isSome(annotation)) return annotation
57
+ if (Option.isSome(annotation) === true) return annotation
57
58
  }
58
59
  return SchemaAST.getAnnotation<T>(annotationId)(propertySignature.type)
59
60
  }
@@ -74,15 +75,15 @@ export const schemaFieldsToColumns = (
74
75
  const fieldSchema = Schema.make(prop.type)
75
76
 
76
77
  // Warn about lossy conversion for fields with both null and undefined
77
- if (prop.isOptional) {
78
+ if (prop.isOptional === true) {
78
79
  const { hasNull, hasUndefined } = checkNullUndefined(fieldSchema.ast)
79
- if (hasNull && hasUndefined) {
80
+ if (hasNull === true && hasUndefined === true) {
80
81
  console.warn(`Field '${prop.name}' has both null and undefined - treating | undefined as | null`)
81
82
  }
82
83
  }
83
84
 
84
85
  // Get column definition - pass nullable flag for optional fields
85
- const columnDef = getColumnDefForSchema(fieldSchema, prop, prop.isOptional)
86
+ const columnDef = getColumnDefForSchema(fieldSchema, prop, prop.isOptional === true)
86
87
 
87
88
  // Check for primary key and unique annotations
88
89
  const hasPrimaryKey = hasPropertyAnnotation<boolean>(prop, PrimaryKeyId).pipe(Option.getOrElse(() => false))
@@ -91,16 +92,16 @@ export const schemaFieldsToColumns = (
91
92
  // Build final column
92
93
  columns[prop.name] = {
93
94
  ...columnDef,
94
- ...(hasPrimaryKey && { primaryKey: true }),
95
+ ...(hasPrimaryKey === true ? { primaryKey: true } : {}),
95
96
  }
96
97
 
97
98
  // Validate primary key + nullable
98
99
  const column = columns[prop.name]
99
- if (column?.primaryKey && column.nullable) {
100
+ if (column?.primaryKey === true && column.nullable === true) {
100
101
  throw new Error('Primary key columns cannot be nullable')
101
102
  }
102
103
 
103
- if (hasUnique) uniqueColumns.push(prop.name)
104
+ if (hasUnique === true) uniqueColumns.push(prop.name)
104
105
  }
105
106
 
106
107
  return { columns, uniqueColumns }
@@ -111,9 +112,9 @@ const checkNullUndefined = (ast: SchemaAST.AST): { hasNull: boolean; hasUndefine
111
112
  let hasUndefined = false
112
113
 
113
114
  const visit = (type: SchemaAST.AST): void => {
114
- if (SchemaAST.isUndefinedKeyword(type)) hasUndefined = true
115
- else if (SchemaAST.isLiteral(type) && type.literal === null) hasNull = true
116
- else if (SchemaAST.isUnion(type)) type.types.forEach(visit)
115
+ if (SchemaAST.isUndefinedKeyword(type) === true) hasUndefined = true
116
+ else if (SchemaAST.isLiteral(type) === true && type.literal === null) hasNull = true
117
+ else if (SchemaAST.isUnion(type) === true) type.types.forEach(visit)
117
118
  }
118
119
 
119
120
  visit(ast)
@@ -121,16 +122,16 @@ const checkNullUndefined = (ast: SchemaAST.AST): { hasNull: boolean; hasUndefine
121
122
  }
122
123
 
123
124
  const hasNull = (ast: SchemaAST.AST): boolean => {
124
- if (SchemaAST.isLiteral(ast) && ast.literal === null) return true
125
- if (SchemaAST.isUnion(ast)) {
125
+ if (SchemaAST.isLiteral(ast) === true && ast.literal === null) return true
126
+ if (SchemaAST.isUnion(ast) === true) {
126
127
  return ast.types.some((type) => hasNull(type))
127
128
  }
128
129
  return false
129
130
  }
130
131
 
131
132
  const hasUndefined = (ast: SchemaAST.AST): boolean => {
132
- if (SchemaAST.isUndefinedKeyword(ast)) return true
133
- if (SchemaAST.isUnion(ast)) {
133
+ if (SchemaAST.isUndefinedKeyword(ast) === true) return true
134
+ if (SchemaAST.isUnion(ast) === true) {
134
135
  return ast.types.some((type) => hasUndefined(type))
135
136
  }
136
137
  return false
@@ -158,7 +159,7 @@ const getColumnForSchema = (schema: Schema.Schema.AnyNoContext, nullable = false
158
159
  const coreSchema = stripNullable(ast) === ast ? schema : Schema.make(coreAst)
159
160
 
160
161
  // Special case: Boolean is transformed to integer in SQLite
161
- if (SchemaAST.isBooleanKeyword(coreAst)) {
162
+ if (SchemaAST.isBooleanKeyword(coreAst) === true) {
162
163
  return SqliteDsl.boolean({ nullable })
163
164
  }
164
165
 
@@ -166,11 +167,11 @@ const getColumnForSchema = (schema: Schema.Schema.AnyNoContext, nullable = false
166
167
  const encodedAst = Schema.encodedSchema(coreSchema).ast
167
168
 
168
169
  // Check if the encoded type matches SQLite native types
169
- if (SchemaAST.isStringKeyword(encodedAst)) {
170
+ if (SchemaAST.isStringKeyword(encodedAst) === true) {
170
171
  return SqliteDsl.text({ schema: coreSchema, nullable })
171
172
  }
172
173
 
173
- if (SchemaAST.isNumberKeyword(encodedAst)) {
174
+ if (SchemaAST.isNumberKeyword(encodedAst) === true) {
174
175
  // Special cases for integer columns
175
176
  const id = SchemaAST.getIdentifierAnnotation(coreAst).pipe(Option.getOrElse(() => ''))
176
177
  if (id === 'Int' || id === 'DateFromNumber') {
@@ -179,23 +180,23 @@ const getColumnForSchema = (schema: Schema.Schema.AnyNoContext, nullable = false
179
180
  return SqliteDsl.real({ schema: coreSchema, nullable })
180
181
  }
181
182
 
182
- if (isUint8ArraySchema(coreAst) || isUint8ArraySchema(encodedAst)) {
183
+ if (isUint8ArraySchema(coreAst) === true || isUint8ArraySchema(encodedAst) === true) {
183
184
  return SqliteDsl.blob({ schema: Schema.Uint8ArrayFromSelf as Schema.Schema<Uint8Array<ArrayBuffer>>, nullable })
184
185
  }
185
186
 
186
187
  const literalColumn = getLiteralColumnDefinition(encodedAst, coreSchema, nullable, coreAst)
187
- if (literalColumn) return literalColumn
188
+ if (literalColumn !== null) return literalColumn
188
189
 
189
190
  // Fallback to checking the original AST in case the encoded schema differs
190
191
  const coreLiteralColumn = getLiteralColumnDefinition(coreAst, coreSchema, nullable, coreAst)
191
- if (coreLiteralColumn) return coreLiteralColumn
192
+ if (coreLiteralColumn !== null) return coreLiteralColumn
192
193
 
193
194
  // Everything else needs JSON encoding
194
195
  return SqliteDsl.json({ schema: coreSchema, nullable })
195
196
  }
196
197
 
197
198
  const stripNullable = (ast: SchemaAST.AST): SchemaAST.AST => {
198
- if (!SchemaAST.isUnion(ast)) return ast
199
+ if (SchemaAST.isUnion(ast) === false) return ast
199
200
 
200
201
  // Filter out null/undefined members while preserving any annotations on the union
201
202
  const coreTypes = ast.types.filter(
@@ -220,7 +221,7 @@ const getLiteralColumnDefinition = (
220
221
  sourceAst: SchemaAST.AST,
221
222
  ): SqliteDsl.ColumnDefinition.Any | null => {
222
223
  const literalValues = extractLiteralValues(ast)
223
- if (!literalValues) return null
224
+ if (literalValues == null) return null
224
225
 
225
226
  const literalType = getLiteralValueType(literalValues)
226
227
  switch (literalType) {
@@ -235,7 +236,7 @@ const getLiteralColumnDefinition = (
235
236
  const useIntegerColumn =
236
237
  literalValues.length > 1 && literalValues.every((value) => typeof value === 'number' && Number.isInteger(value))
237
238
 
238
- return useIntegerColumn ? SqliteDsl.integer({ schema, nullable }) : SqliteDsl.real({ schema, nullable })
239
+ return useIntegerColumn === true ? SqliteDsl.integer({ schema, nullable }) : SqliteDsl.real({ schema, nullable })
239
240
  }
240
241
  case 'boolean':
241
242
  return SqliteDsl.boolean({ nullable })
@@ -247,9 +248,13 @@ const getLiteralColumnDefinition = (
247
248
  }
248
249
 
249
250
  const extractLiteralValues = (ast: SchemaAST.AST): ReadonlyArray<SchemaAST.LiteralValue> | null => {
250
- if (SchemaAST.isLiteral(ast)) return [ast.literal]
251
+ if (SchemaAST.isLiteral(ast) === true) return [ast.literal]
251
252
 
252
- if (SchemaAST.isUnion(ast) && ast.types.length > 0 && ast.types.every((type) => SchemaAST.isLiteral(type))) {
253
+ if (
254
+ SchemaAST.isUnion(ast) === true &&
255
+ ast.types.length > 0 &&
256
+ ast.types.every((type) => SchemaAST.isLiteral(type)) === true
257
+ ) {
253
258
  return ast.types.map((type) => (type as SchemaAST.Literal).literal)
254
259
  }
255
260
 
@@ -270,11 +275,11 @@ const getLiteralValueType = (
270
275
 
271
276
  const isUint8ArraySchema = (ast: SchemaAST.AST): boolean => {
272
277
  const identifier = SchemaAST.getIdentifierAnnotation(ast)
273
- if (Option.isSome(identifier) && identifier.value.includes('Uint8Array')) {
278
+ if (Option.isSome(identifier) === true && identifier.value.includes('Uint8Array') === true) {
274
279
  return true
275
280
  }
276
281
 
277
- if (SchemaAST.isTupleType(ast)) {
282
+ if (SchemaAST.isTupleType(ast) === true) {
278
283
  return ast.elements.length === 0 && ast.rest.length === 1 && SchemaAST.isNumberKeyword(ast.rest[0]!.type)
279
284
  }
280
285
 
@@ -1,5 +1,7 @@
1
- import { Option, Schema } from '@livestore/utils/effect'
2
1
  import { describe, expect, it } from 'vitest'
2
+
3
+ import { Option, Schema } from '@livestore/utils/effect'
4
+
3
5
  import { makeColumnSpec } from './column-spec.ts'
4
6
  import { SqliteAst } from './db-schema/mod.ts'
5
7
 
@@ -1,4 +1,5 @@
1
1
  import { Schema } from '@livestore/utils/effect'
2
+
2
3
  import { type SqliteAst, SqliteDsl } from './db-schema/mod.ts'
3
4
 
4
5
  /**
@@ -12,13 +13,13 @@ import { type SqliteAst, SqliteDsl } from './db-schema/mod.ts'
12
13
  export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
13
14
  const pkColumns = tableAst.columns.filter((_) => _.primaryKey)
14
15
  const hasSinglePk = pkColumns.length === 1
15
- const pkColumn = hasSinglePk ? pkColumns[0] : undefined
16
+ const pkColumn = hasSinglePk === true ? pkColumns[0] : undefined
16
17
 
17
18
  // Build column definitions, handling the special SQLite rule that AUTOINCREMENT
18
19
  // is only valid on a single column declared as INTEGER PRIMARY KEY (column-level).
19
20
  const columnDefStrs = tableAst.columns.map((column) =>
20
21
  toSqliteColumnSpec(column, {
21
- inlinePrimaryKey: hasSinglePk && column === pkColumn && column.primaryKey === true,
22
+ inlinePrimaryKey: hasSinglePk && column === pkColumn && column.primaryKey,
22
23
  }),
23
24
  )
24
25
 
@@ -36,24 +37,24 @@ const toSqliteColumnSpec = (column: SqliteAst.Column, opts: { inlinePrimaryKey:
36
37
  const columnTypeStr = column.type._tag
37
38
  // When PRIMARY KEY is declared inline, NOT NULL is implied and should not be emitted,
38
39
  // and AUTOINCREMENT must immediately follow PRIMARY KEY within the same constraint.
39
- const nullableStr = opts.inlinePrimaryKey ? '' : column.nullable === false ? 'not null' : ''
40
+ const nullableStr = opts.inlinePrimaryKey === true ? '' : column.nullable === false ? 'not null' : ''
40
41
 
41
42
  // Only include AUTOINCREMENT when it's valid: single-column INTEGER PRIMARY KEY
42
- const includeAutoIncrement = opts.inlinePrimaryKey && column.type._tag === 'integer' && column.autoIncrement === true
43
+ const includeAutoIncrement = opts.inlinePrimaryKey === true && column.type._tag === 'integer' && column.autoIncrement === true
43
44
 
44
- const pkStr = opts.inlinePrimaryKey ? 'primary key' : ''
45
- const autoIncrementStr = includeAutoIncrement ? 'autoincrement' : ''
45
+ const pkStr = opts.inlinePrimaryKey === true ? 'primary key' : ''
46
+ const autoIncrementStr = includeAutoIncrement === true ? 'autoincrement' : ''
46
47
 
47
48
  const defaultValueStr = (() => {
48
49
  if (column.default._tag === 'None') return ''
49
50
 
50
51
  const defaultValue = column.default.value
51
- if (SqliteDsl.isDefaultThunk(defaultValue)) return ''
52
+ if (SqliteDsl.isDefaultThunk(defaultValue) === true) return ''
52
53
 
53
54
  const resolvedDefault = SqliteDsl.resolveColumnDefault(defaultValue)
54
55
 
55
56
  if (resolvedDefault === null) return 'default null'
56
- if (SqliteDsl.isSqlDefaultValue(resolvedDefault)) return `default ${resolvedDefault.sql}`
57
+ if (SqliteDsl.isSqlDefaultValue(resolvedDefault) === true) return `default ${resolvedDefault.sql}`
57
58
 
58
59
  const encodeValue = Schema.encodeSync(column.schema)
59
60
  const encodedDefaultValue = encodeValue(resolvedDefault)
@@ -124,7 +124,7 @@ const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema):
124
124
 
125
125
  // NEW: Include schema hash for JSON columns
126
126
  // This ensures that changes to the JSON schema are detected
127
- if (isJsonColumn(obj) && obj.schema) {
127
+ if (isJsonColumn(obj) === true && obj.schema !== undefined) {
128
128
  // Use Effect's Schema.hash for consistent hashing
129
129
  baseInfo.jsonSchemaHash = Schema.hash(obj.schema)
130
130
  }
@@ -155,7 +155,7 @@ const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema):
155
155
  }
156
156
  }
157
157
  default: {
158
- throw new Error(`Unreachable: ${obj}`)
158
+ throw new Error(`Unreachable: ${String(obj)}`)
159
159
  }
160
160
  }
161
161
  }
@@ -1,6 +1,7 @@
1
- import { Schema } from '@livestore/utils/effect'
2
1
  import { describe, expect, test } from 'vitest'
3
2
 
3
+ import { Schema } from '@livestore/utils/effect'
4
+
4
5
  import * as F from './field-defs.ts'
5
6
 
6
7
  describe.concurrent('FieldDefs', () => {
@@ -6,6 +6,7 @@ export type SqlDefaultValue = {
6
6
  }
7
7
 
8
8
  export const isSqlDefaultValue = (value: unknown): value is SqlDefaultValue => {
9
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- type guard property access after structural check
9
10
  return typeof value === 'object' && value !== null && 'sql' in value && typeof (value as any).sql === 'string'
10
11
  }
11
12
 
@@ -16,14 +17,14 @@ export const isDefaultThunk = (value: unknown): value is ColumnDefaultThunk<unkn
16
17
  export type ColumnDefaultValue<T> = T | null | ColumnDefaultThunk<T | null> | SqlDefaultValue
17
18
 
18
19
  export const resolveColumnDefault = <T>(value: ColumnDefaultValue<T>): T | null | SqlDefaultValue =>
19
- isDefaultThunk(value) ? (value as ColumnDefaultThunk<T | null>)() : value
20
+ isDefaultThunk(value) === true ? value() : value
20
21
 
21
- export type ColumnDefinition<TEncoded, TDecoded> = {
22
+ export type ColumnDefinition<TEncoded, TDecoded, TNullable extends boolean = boolean> = {
22
23
  readonly columnType: FieldColumnType
23
24
  readonly schema: Schema.Schema<TDecoded, TEncoded>
24
25
  readonly default: Option.Option<ColumnDefaultValue<TDecoded>>
25
26
  /** @default false */
26
- readonly nullable: boolean
27
+ readonly nullable: TNullable
27
28
  /** @default false */
28
29
  readonly primaryKey: boolean
29
30
  /** @default false */
@@ -40,6 +41,7 @@ export const isColumnDefinition = (value: unknown): value is ColumnDefinition.An
40
41
  typeof value === 'object' &&
41
42
  value !== null &&
42
43
  'columnType' in value &&
44
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- type guard narrowing; columnType checked to be in valid set
43
45
  validColumnTypes.includes(value.columnType as any)
44
46
  )
45
47
  }
@@ -105,6 +107,7 @@ const makeColDef =
105
107
  const schema = nullable === true ? Schema.NullOr(schemaWithoutNull) : schemaWithoutNull
106
108
  const default_ = def?.default === undefined || def.default === NoDefault ? Option.none() : Option.some(def.default)
107
109
 
110
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- column factory return type uses complex conditional generics; consumer type safety enforced by ColDefFn signature
108
111
  return {
109
112
  columnType,
110
113
  schema,
@@ -200,10 +203,12 @@ type MakeSpecializedColDefFn = {
200
203
 
201
204
  const makeSpecializedColDef: MakeSpecializedColDefFn = (columnType, opts) => (def?: ColumnDefinitionInput) => {
202
205
  const nullable = def?.nullable ?? false
206
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- schema type variance; custom schema compatibility checked at call site
203
207
  const schemaWithoutNull = opts._tag === 'baseSchemaFn' ? opts.baseSchemaFn(def?.schema as any) : opts.baseSchema
204
208
  const schema = nullable === true ? Schema.NullOr(schemaWithoutNull) : schemaWithoutNull
205
209
  const default_ = def?.default === undefined || def.default === NoDefault ? Option.none() : Option.some(def.default)
206
210
 
211
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- specialized column factory return type uses complex conditional generics; consumer type safety enforced by SpecializedColDefFn signature
207
212
  return {
208
213
  columnType,
209
214
  schema,
@@ -236,7 +241,7 @@ export const boolean: SpecializedColDefFn<'integer', false, boolean> = makeSpeci
236
241
  _tag: 'baseSchema',
237
242
  baseSchema: Schema.transform(Schema.Number, Schema.Boolean, {
238
243
  decode: (_) => _ === 1,
239
- encode: (_) => (_ ? 1 : 0),
244
+ encode: (_) => (_ === true ? 1 : 0),
240
245
  }),
241
246
  })
242
247
 
@@ -259,15 +264,19 @@ export const defaultSchemaForColumnType = <TColumnType extends FieldColumnType>(
259
264
 
260
265
  switch (columnType) {
261
266
  case 'text': {
267
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- switch-based type narrowing for column type to schema mapping; each case is correct for its branch
262
268
  return Schema.String as any as Schema.Schema<T>
263
269
  }
264
270
  case 'integer': {
271
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- switch-based type narrowing for column type to schema mapping; each case is correct for its branch
265
272
  return Schema.Number as any as Schema.Schema<T>
266
273
  }
267
274
  case 'real': {
275
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- switch-based type narrowing for column type to schema mapping; each case is correct for its branch
268
276
  return Schema.Number as any as Schema.Schema<T>
269
277
  }
270
278
  case 'blob': {
279
+ // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- switch-based type narrowing for column type to schema mapping; each case is correct for its branch
271
280
  return Schema.Uint8ArrayFromSelf as any as Schema.Schema<T>
272
281
  }
273
282
  default: {