@rocicorp/zero 0.25.0-canary.1 → 0.25.0-canary.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1504) hide show
  1. package/out/analyze-query/src/bin-analyze.js +268 -257
  2. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  3. package/out/analyze-query/src/bin-transform.js +31 -23
  4. package/out/analyze-query/src/bin-transform.js.map +1 -1
  5. package/out/analyze-query/src/explain-queries.js +13 -16
  6. package/out/analyze-query/src/explain-queries.js.map +1 -1
  7. package/out/analyze-query/src/run-ast.d.ts +3 -2
  8. package/out/analyze-query/src/run-ast.d.ts.map +1 -1
  9. package/out/analyze-query/src/run-ast.js +79 -73
  10. package/out/analyze-query/src/run-ast.js.map +1 -1
  11. package/out/ast-to-zql/src/ast-to-zql.js +146 -180
  12. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  13. package/out/ast-to-zql/src/bin.js +51 -54
  14. package/out/ast-to-zql/src/bin.js.map +1 -1
  15. package/out/ast-to-zql/src/format.js +15 -14
  16. package/out/ast-to-zql/src/format.js.map +1 -1
  17. package/out/datadog/src/datadog-log-sink.js +223 -0
  18. package/out/datadog/src/datadog-log-sink.js.map +1 -0
  19. package/out/otel/src/enabled.js +15 -15
  20. package/out/otel/src/enabled.js.map +1 -1
  21. package/out/otel/src/log-options.js +36 -31
  22. package/out/otel/src/log-options.js.map +1 -1
  23. package/out/otel/src/maybe-time.js +14 -11
  24. package/out/otel/src/maybe-time.js.map +1 -1
  25. package/out/otel/src/span.js +30 -27
  26. package/out/otel/src/span.js.map +1 -1
  27. package/out/otel/src/test-log-config.js +10 -7
  28. package/out/otel/src/test-log-config.js.map +1 -1
  29. package/out/otel/src/version.js +5 -2
  30. package/out/otel/src/version.js.map +1 -1
  31. package/out/replicache/src/async-iterable-to-array.js +11 -0
  32. package/out/replicache/src/async-iterable-to-array.js.map +1 -0
  33. package/out/replicache/src/bg-interval.js +38 -0
  34. package/out/replicache/src/bg-interval.js.map +1 -0
  35. package/out/replicache/src/btree/diff.js +8 -0
  36. package/out/replicache/src/btree/diff.js.map +1 -0
  37. package/out/replicache/src/btree/node.js +400 -0
  38. package/out/replicache/src/btree/node.js.map +1 -0
  39. package/out/replicache/src/btree/read.d.ts +3 -2
  40. package/out/replicache/src/btree/read.d.ts.map +1 -1
  41. package/out/replicache/src/btree/read.js +266 -0
  42. package/out/replicache/src/btree/read.js.map +1 -0
  43. package/out/replicache/src/btree/splice.js +83 -0
  44. package/out/replicache/src/btree/splice.js.map +1 -0
  45. package/out/replicache/src/btree/write.d.ts +1 -1
  46. package/out/replicache/src/btree/write.d.ts.map +1 -1
  47. package/out/replicache/src/btree/write.js +163 -0
  48. package/out/replicache/src/btree/write.js.map +1 -0
  49. package/out/replicache/src/call-default-fetch.js +34 -0
  50. package/out/replicache/src/call-default-fetch.js.map +1 -0
  51. package/out/replicache/src/connection-loop-delegates.js +34 -0
  52. package/out/replicache/src/connection-loop-delegates.js.map +1 -0
  53. package/out/replicache/src/connection-loop.js +251 -0
  54. package/out/replicache/src/connection-loop.js.map +1 -0
  55. package/out/replicache/src/cookies.js +40 -0
  56. package/out/replicache/src/cookies.js.map +1 -0
  57. package/out/replicache/src/dag/chunk.js +59 -0
  58. package/out/replicache/src/dag/chunk.js.map +1 -0
  59. package/out/replicache/src/dag/gc.js +117 -0
  60. package/out/replicache/src/dag/gc.js.map +1 -0
  61. package/out/replicache/src/dag/key.js +20 -0
  62. package/out/replicache/src/dag/key.js.map +1 -0
  63. package/out/replicache/src/dag/lazy-store.d.ts +2 -1
  64. package/out/replicache/src/dag/lazy-store.d.ts.map +1 -1
  65. package/out/replicache/src/dag/lazy-store.js +515 -0
  66. package/out/replicache/src/dag/lazy-store.js.map +1 -0
  67. package/out/replicache/src/dag/store-impl.js +183 -0
  68. package/out/replicache/src/dag/store-impl.js.map +1 -0
  69. package/out/replicache/src/dag/store.js +27 -0
  70. package/out/replicache/src/dag/store.js.map +1 -0
  71. package/out/replicache/src/dag/visitor.js +22 -0
  72. package/out/replicache/src/dag/visitor.js.map +1 -0
  73. package/out/replicache/src/db/commit.js +358 -0
  74. package/out/replicache/src/db/commit.js.map +1 -0
  75. package/out/replicache/src/db/index-operation-enum.js +7 -0
  76. package/out/replicache/src/db/index-operation-enum.js.map +1 -0
  77. package/out/replicache/src/db/index.js +134 -0
  78. package/out/replicache/src/db/index.js.map +1 -0
  79. package/out/replicache/src/db/meta-type-enum.js +7 -0
  80. package/out/replicache/src/db/meta-type-enum.js.map +1 -0
  81. package/out/replicache/src/db/read.d.ts +3 -2
  82. package/out/replicache/src/db/read.d.ts.map +1 -1
  83. package/out/replicache/src/db/read.js +72 -0
  84. package/out/replicache/src/db/read.js.map +1 -0
  85. package/out/replicache/src/db/rebase.d.ts +2 -2
  86. package/out/replicache/src/db/rebase.d.ts.map +1 -1
  87. package/out/replicache/src/db/rebase.js +85 -0
  88. package/out/replicache/src/db/rebase.js.map +1 -0
  89. package/out/replicache/src/db/write.d.ts +2 -1
  90. package/out/replicache/src/db/write.d.ts.map +1 -1
  91. package/out/replicache/src/db/write.js +296 -0
  92. package/out/replicache/src/db/write.js.map +1 -0
  93. package/out/replicache/src/deleted-clients.js +104 -0
  94. package/out/replicache/src/deleted-clients.js.map +1 -0
  95. package/out/replicache/src/error-responses.js +34 -0
  96. package/out/replicache/src/error-responses.js.map +1 -0
  97. package/out/replicache/src/format-version-enum.js +11 -0
  98. package/out/replicache/src/format-version-enum.js.map +1 -0
  99. package/out/{chunk-EZM3XBAB.js → replicache/src/frozen-json.js} +8 -75
  100. package/out/replicache/src/frozen-json.js.map +1 -0
  101. package/out/replicache/src/get-default-puller.js +61 -0
  102. package/out/replicache/src/get-default-puller.js.map +1 -0
  103. package/out/replicache/src/get-default-pusher.js +39 -0
  104. package/out/replicache/src/get-default-pusher.js.map +1 -0
  105. package/out/replicache/src/get-kv-store-provider.js +23 -0
  106. package/out/replicache/src/get-kv-store-provider.js.map +1 -0
  107. package/out/replicache/src/hash.js +38 -0
  108. package/out/replicache/src/hash.js.map +1 -0
  109. package/out/replicache/src/http-request-info.js +10 -0
  110. package/out/replicache/src/http-request-info.js.map +1 -0
  111. package/out/replicache/src/http-status-unauthorized.js +5 -0
  112. package/out/replicache/src/http-status-unauthorized.js.map +1 -0
  113. package/out/replicache/src/index-defs.js +32 -0
  114. package/out/replicache/src/index-defs.js.map +1 -0
  115. package/out/replicache/src/invoke-kind-enum.js +7 -0
  116. package/out/replicache/src/invoke-kind-enum.js.map +1 -0
  117. package/out/{chunk-ZZXMKAAG.js → replicache/src/kv/expo-sqlite/store.js} +8 -16
  118. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -0
  119. package/out/replicache/src/kv/idb-store-with-mem-fallback.js +80 -0
  120. package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +1 -0
  121. package/out/replicache/src/kv/idb-store.js +183 -0
  122. package/out/replicache/src/kv/idb-store.js.map +1 -0
  123. package/out/replicache/src/kv/mem-store.js +51 -0
  124. package/out/replicache/src/kv/mem-store.js.map +1 -0
  125. package/out/{op-sqlite.js → replicache/src/kv/op-sqlite/store.js} +7 -18
  126. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -0
  127. package/out/replicache/src/kv/op-sqlite/types.js +6 -0
  128. package/out/replicache/src/kv/op-sqlite/types.js.map +1 -0
  129. package/out/replicache/src/kv/read-impl.js +27 -0
  130. package/out/replicache/src/kv/read-impl.js.map +1 -0
  131. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  132. package/out/{chunk-ECUMGQGC.js → replicache/src/kv/sqlite-store.js} +27 -21
  133. package/out/replicache/src/kv/sqlite-store.js.map +1 -0
  134. package/out/{chunk-ASRS2LFV.js → replicache/src/kv/throw-if-closed.js} +4 -6
  135. package/out/replicache/src/kv/throw-if-closed.js.map +1 -0
  136. package/out/replicache/src/kv/write-impl-base.js +57 -0
  137. package/out/replicache/src/kv/write-impl-base.js.map +1 -0
  138. package/out/replicache/src/kv/write-impl.js +30 -0
  139. package/out/replicache/src/kv/write-impl.js.map +1 -0
  140. package/out/replicache/src/lazy.js +13 -0
  141. package/out/replicache/src/lazy.js.map +1 -0
  142. package/out/replicache/src/log-options.js +9 -0
  143. package/out/replicache/src/log-options.js.map +1 -0
  144. package/out/replicache/src/make-idb-name.js +13 -0
  145. package/out/replicache/src/make-idb-name.js.map +1 -0
  146. package/out/replicache/src/new-client-channel.js +51 -0
  147. package/out/replicache/src/new-client-channel.js.map +1 -0
  148. package/out/replicache/src/on-persist-channel.js +36 -0
  149. package/out/replicache/src/on-persist-channel.js.map +1 -0
  150. package/out/replicache/src/patch-operation.js +42 -0
  151. package/out/replicache/src/patch-operation.js.map +1 -0
  152. package/out/replicache/src/pending-mutations.js +16 -0
  153. package/out/replicache/src/pending-mutations.js.map +1 -0
  154. package/out/replicache/src/persist/client-gc.js +58 -0
  155. package/out/replicache/src/persist/client-gc.js.map +1 -0
  156. package/out/replicache/src/persist/client-group-gc.js +43 -0
  157. package/out/replicache/src/persist/client-group-gc.js.map +1 -0
  158. package/out/replicache/src/persist/client-groups.js +184 -0
  159. package/out/replicache/src/persist/client-groups.js.map +1 -0
  160. package/out/replicache/src/persist/clients.d.ts +3 -2
  161. package/out/replicache/src/persist/clients.d.ts.map +1 -1
  162. package/out/replicache/src/persist/clients.js +353 -0
  163. package/out/replicache/src/persist/clients.js.map +1 -0
  164. package/out/replicache/src/persist/collect-idb-databases.js +188 -0
  165. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -0
  166. package/out/replicache/src/persist/gather-mem-only-visitor.js +27 -0
  167. package/out/replicache/src/persist/gather-mem-only-visitor.js.map +1 -0
  168. package/out/replicache/src/persist/gather-not-cached-visitor.js +37 -0
  169. package/out/replicache/src/persist/gather-not-cached-visitor.js.map +1 -0
  170. package/out/replicache/src/persist/heartbeat.js +48 -0
  171. package/out/replicache/src/persist/heartbeat.js.map +1 -0
  172. package/out/replicache/src/persist/idb-databases-store-db-name.js +14 -0
  173. package/out/replicache/src/persist/idb-databases-store-db-name.js.map +1 -0
  174. package/out/replicache/src/persist/idb-databases-store.js +92 -0
  175. package/out/replicache/src/persist/idb-databases-store.js.map +1 -0
  176. package/out/replicache/src/persist/make-client-id.js +12 -0
  177. package/out/replicache/src/persist/make-client-id.js.map +1 -0
  178. package/out/replicache/src/persist/persist.d.ts +2 -2
  179. package/out/replicache/src/persist/persist.d.ts.map +1 -1
  180. package/out/replicache/src/persist/persist.js +183 -0
  181. package/out/replicache/src/persist/persist.js.map +1 -0
  182. package/out/replicache/src/persist/refresh.d.ts +4 -3
  183. package/out/replicache/src/persist/refresh.d.ts.map +1 -1
  184. package/out/replicache/src/persist/refresh.js +198 -0
  185. package/out/replicache/src/persist/refresh.js.map +1 -0
  186. package/out/replicache/src/process-scheduler.js +96 -0
  187. package/out/replicache/src/process-scheduler.js.map +1 -0
  188. package/out/replicache/src/pusher.js +33 -0
  189. package/out/replicache/src/pusher.js.map +1 -0
  190. package/out/replicache/src/replicache-impl.d.ts +1 -1
  191. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  192. package/out/replicache/src/replicache-impl.js +1200 -0
  193. package/out/replicache/src/replicache-impl.js.map +1 -0
  194. package/out/replicache/src/replicache-options.d.ts +3 -2
  195. package/out/replicache/src/replicache-options.d.ts.map +1 -1
  196. package/out/replicache/src/report-error.js +6 -0
  197. package/out/replicache/src/report-error.js.map +1 -0
  198. package/out/replicache/src/request-idle.js +13 -0
  199. package/out/replicache/src/request-idle.js.map +1 -0
  200. package/out/replicache/src/scan-iterator.js +146 -0
  201. package/out/replicache/src/scan-iterator.js.map +1 -0
  202. package/out/replicache/src/scan-options.js +45 -0
  203. package/out/replicache/src/scan-options.js.map +1 -0
  204. package/out/replicache/src/set-interval-with-signal.js +12 -0
  205. package/out/replicache/src/set-interval-with-signal.js.map +1 -0
  206. package/out/replicache/src/subscriptions.js +355 -0
  207. package/out/replicache/src/subscriptions.js.map +1 -0
  208. package/out/replicache/src/sync/diff.d.ts +3 -2
  209. package/out/replicache/src/sync/diff.d.ts.map +1 -1
  210. package/out/replicache/src/sync/diff.js +72 -0
  211. package/out/replicache/src/sync/diff.js.map +1 -0
  212. package/out/replicache/src/sync/handle-pull-response-result-type-enum.js +9 -0
  213. package/out/replicache/src/sync/handle-pull-response-result-type-enum.js.map +1 -0
  214. package/out/replicache/src/sync/ids.js +9 -0
  215. package/out/replicache/src/sync/ids.js.map +1 -0
  216. package/out/replicache/src/sync/patch.js +49 -0
  217. package/out/replicache/src/sync/patch.js.map +1 -0
  218. package/out/replicache/src/sync/pull-error.js +16 -0
  219. package/out/replicache/src/sync/pull-error.js.map +1 -0
  220. package/out/replicache/src/sync/pull.d.ts +3 -2
  221. package/out/replicache/src/sync/pull.d.ts.map +1 -1
  222. package/out/replicache/src/sync/pull.js +301 -0
  223. package/out/replicache/src/sync/pull.js.map +1 -0
  224. package/out/replicache/src/sync/push.js +88 -0
  225. package/out/replicache/src/sync/push.js.map +1 -0
  226. package/out/replicache/src/sync/request-id.js +20 -0
  227. package/out/replicache/src/sync/request-id.js.map +1 -0
  228. package/out/replicache/src/sync/sync-head-name.js +5 -0
  229. package/out/replicache/src/sync/sync-head-name.js.map +1 -0
  230. package/out/replicache/src/to-error.js +10 -0
  231. package/out/replicache/src/to-error.js.map +1 -0
  232. package/out/replicache/src/transaction-closed-error.js +19 -0
  233. package/out/replicache/src/transaction-closed-error.js.map +1 -0
  234. package/out/replicache/src/transactions.js +152 -0
  235. package/out/replicache/src/transactions.js.map +1 -0
  236. package/out/replicache/src/version.js +5 -0
  237. package/out/replicache/src/version.js.map +1 -0
  238. package/out/replicache/src/with-transactions.js +28 -0
  239. package/out/replicache/src/with-transactions.js.map +1 -0
  240. package/out/shared/src/abort-error.js +6 -3
  241. package/out/shared/src/abort-error.js.map +1 -1
  242. package/out/shared/src/arrays.js +45 -43
  243. package/out/shared/src/arrays.js.map +1 -1
  244. package/out/shared/src/asserts.js +64 -68
  245. package/out/shared/src/asserts.js.map +1 -1
  246. package/out/shared/src/bigint-json.js +38 -42
  247. package/out/shared/src/bigint-json.js.map +1 -1
  248. package/out/shared/src/binary-search.js +18 -29
  249. package/out/shared/src/binary-search.js.map +1 -1
  250. package/out/shared/src/broadcast-channel.js +24 -0
  251. package/out/shared/src/broadcast-channel.js.map +1 -0
  252. package/out/shared/src/browser-env.js +25 -0
  253. package/out/shared/src/browser-env.js.map +1 -0
  254. package/out/shared/src/btree-set.js +464 -507
  255. package/out/shared/src/btree-set.js.map +1 -1
  256. package/out/shared/src/cache.js +34 -38
  257. package/out/shared/src/cache.js.map +1 -1
  258. package/out/shared/src/centroid.js +24 -24
  259. package/out/shared/src/centroid.js.map +1 -1
  260. package/out/shared/src/config.js +6 -3
  261. package/out/shared/src/config.js.map +1 -1
  262. package/out/shared/src/custom-key-map.js +58 -64
  263. package/out/shared/src/custom-key-map.js.map +1 -1
  264. package/out/shared/src/custom-key-set.js +51 -57
  265. package/out/shared/src/custom-key-set.js.map +1 -1
  266. package/out/shared/src/deep-clone.js +46 -0
  267. package/out/shared/src/deep-clone.js.map +1 -0
  268. package/out/shared/src/deep-merge.d.ts +24 -4
  269. package/out/shared/src/deep-merge.d.ts.map +1 -1
  270. package/out/shared/src/deep-merge.js +27 -0
  271. package/out/shared/src/deep-merge.js.map +1 -0
  272. package/out/shared/src/document-visible.js +74 -0
  273. package/out/shared/src/document-visible.js.map +1 -0
  274. package/out/shared/src/dotenv.js +5 -7
  275. package/out/shared/src/dotenv.js.map +1 -1
  276. package/out/shared/src/error.d.ts +4 -0
  277. package/out/shared/src/error.d.ts.map +1 -0
  278. package/out/shared/src/error.js +71 -0
  279. package/out/shared/src/error.js.map +1 -0
  280. package/out/shared/src/has-own.js +5 -3
  281. package/out/shared/src/has-own.js.map +1 -1
  282. package/out/shared/src/hash.js +15 -14
  283. package/out/shared/src/hash.js.map +1 -1
  284. package/out/shared/src/iterables.js +71 -73
  285. package/out/shared/src/iterables.js.map +1 -1
  286. package/out/shared/src/json-schema.js +30 -33
  287. package/out/shared/src/json-schema.js.map +1 -1
  288. package/out/shared/src/json.js +128 -143
  289. package/out/shared/src/json.js.map +1 -1
  290. package/out/shared/src/logging-test-utils.js +12 -19
  291. package/out/shared/src/logging-test-utils.js.map +1 -1
  292. package/out/shared/src/logging.d.ts.map +1 -1
  293. package/out/shared/src/logging.js +99 -83
  294. package/out/shared/src/logging.js.map +1 -1
  295. package/out/shared/src/must.js +9 -7
  296. package/out/shared/src/must.js.map +1 -1
  297. package/out/shared/src/navigator.js +5 -0
  298. package/out/shared/src/navigator.js.map +1 -0
  299. package/out/shared/src/object-traversal.d.ts +19 -0
  300. package/out/shared/src/object-traversal.d.ts.map +1 -0
  301. package/out/shared/src/object-traversal.js +27 -0
  302. package/out/shared/src/object-traversal.js.map +1 -0
  303. package/out/shared/src/objects.js +21 -22
  304. package/out/shared/src/objects.js.map +1 -1
  305. package/out/shared/src/options.d.ts +2 -0
  306. package/out/shared/src/options.d.ts.map +1 -1
  307. package/out/shared/src/options.js +289 -318
  308. package/out/shared/src/options.js.map +1 -1
  309. package/out/shared/src/parse-big-int.js +12 -10
  310. package/out/shared/src/parse-big-int.js.map +1 -1
  311. package/out/shared/src/promise-race.js +20 -0
  312. package/out/shared/src/promise-race.js.map +1 -0
  313. package/out/shared/src/queue.js +119 -122
  314. package/out/shared/src/queue.js.map +1 -1
  315. package/out/shared/src/rand.js +8 -10
  316. package/out/shared/src/rand.js.map +1 -1
  317. package/out/shared/src/random-uint64.js +9 -0
  318. package/out/shared/src/random-uint64.js.map +1 -0
  319. package/out/shared/src/random-values.js +13 -0
  320. package/out/shared/src/random-values.js.map +1 -0
  321. package/out/shared/src/resolved-promises.js +12 -9
  322. package/out/shared/src/resolved-promises.js.map +1 -1
  323. package/out/shared/src/sentinels.js +13 -6
  324. package/out/shared/src/sentinels.js.map +1 -1
  325. package/out/shared/src/set-utils.js +63 -62
  326. package/out/shared/src/set-utils.js.map +1 -1
  327. package/out/shared/src/size-of-value.js +58 -0
  328. package/out/shared/src/size-of-value.js.map +1 -0
  329. package/out/shared/src/sleep.js +45 -53
  330. package/out/shared/src/sleep.js.map +1 -1
  331. package/out/shared/src/string-compare.js +12 -9
  332. package/out/shared/src/string-compare.js.map +1 -1
  333. package/out/shared/src/subscribable.js +34 -0
  334. package/out/shared/src/subscribable.js.map +1 -0
  335. package/out/shared/src/tdigest-schema.js +7 -7
  336. package/out/shared/src/tdigest-schema.js.map +1 -1
  337. package/out/shared/src/tdigest.js +247 -271
  338. package/out/shared/src/tdigest.js.map +1 -1
  339. package/out/shared/src/valita.js +195 -207
  340. package/out/shared/src/valita.js.map +1 -1
  341. package/out/z2s/src/compiler.d.ts +2 -2
  342. package/out/z2s/src/compiler.d.ts.map +1 -1
  343. package/out/z2s/src/compiler.js +437 -310
  344. package/out/z2s/src/compiler.js.map +1 -1
  345. package/out/z2s/src/sql.d.ts +1 -1
  346. package/out/z2s/src/sql.d.ts.map +1 -1
  347. package/out/z2s/src/sql.js +186 -218
  348. package/out/z2s/src/sql.js.map +1 -1
  349. package/out/zero/package.json.js +9 -0
  350. package/out/zero/package.json.js.map +1 -0
  351. package/out/zero/src/adapters/drizzle.js +5 -2
  352. package/out/zero/src/adapters/drizzle.js.map +1 -1
  353. package/out/zero/src/adapters/pg.js +7 -2
  354. package/out/zero/src/adapters/pg.js.map +1 -1
  355. package/out/zero/src/adapters/postgresjs.js +7 -2
  356. package/out/zero/src/adapters/postgresjs.js.map +1 -1
  357. package/out/zero/src/analyze-query.js +1 -1
  358. package/out/zero/src/analyze-query.js.map +1 -1
  359. package/out/zero/src/ast-to-zql.js +1 -1
  360. package/out/zero/src/ast-to-zql.js.map +1 -1
  361. package/out/zero/src/build-schema.js +3 -5
  362. package/out/zero/src/build-schema.js.map +1 -1
  363. package/out/zero/src/change-protocol/v0.js +5 -3
  364. package/out/zero/src/change-protocol/v0.js.map +1 -1
  365. package/out/zero/src/cli.js +2 -2
  366. package/out/zero/src/cli.js.map +1 -1
  367. package/out/zero/src/deploy-permissions.js +1 -1
  368. package/out/zero/src/deploy-permissions.js.map +1 -1
  369. package/out/zero/src/expo-sqlite.js +5 -0
  370. package/out/zero/src/expo-sqlite.js.map +1 -0
  371. package/out/zero/src/op-sqlite.js +5 -0
  372. package/out/zero/src/op-sqlite.js.map +1 -0
  373. package/out/zero/src/pg.js +29 -3
  374. package/out/zero/src/pg.js.map +1 -1
  375. package/out/zero/src/react-native.js +13 -0
  376. package/out/zero/src/react-native.js.map +1 -0
  377. package/out/zero/src/react.js +17 -0
  378. package/out/zero/src/react.js.map +1 -0
  379. package/out/zero/src/server.js +25 -3
  380. package/out/zero/src/server.js.map +1 -1
  381. package/out/zero/src/solid.js +15 -0
  382. package/out/zero/src/solid.js.map +1 -0
  383. package/out/zero/src/sqlite.js +7 -0
  384. package/out/zero/src/sqlite.js.map +1 -0
  385. package/out/zero/src/transform-query.js +1 -1
  386. package/out/zero/src/transform-query.js.map +1 -1
  387. package/out/zero/src/zero-cache-dev.js +133 -105
  388. package/out/zero/src/zero-cache-dev.js.map +1 -1
  389. package/out/zero/src/zero-out.d.ts +3 -0
  390. package/out/zero/src/zero-out.d.ts.map +1 -0
  391. package/out/zero/src/zero-out.js +13 -0
  392. package/out/zero/src/zero-out.js.map +1 -0
  393. package/out/zero/src/zero.js +67 -0
  394. package/out/zero/src/zero.js.map +1 -0
  395. package/out/zero/src/zqlite.js +11 -3
  396. package/out/zero/src/zqlite.js.map +1 -1
  397. package/out/zero-cache/src/auth/jwt.d.ts +3 -0
  398. package/out/zero-cache/src/auth/jwt.d.ts.map +1 -1
  399. package/out/zero-cache/src/auth/jwt.js +33 -38
  400. package/out/zero-cache/src/auth/jwt.js.map +1 -1
  401. package/out/zero-cache/src/auth/load-permissions.d.ts +1 -1
  402. package/out/zero-cache/src/auth/load-permissions.d.ts.map +1 -1
  403. package/out/zero-cache/src/auth/load-permissions.js +61 -45
  404. package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
  405. package/out/zero-cache/src/auth/read-authorizer.js +79 -91
  406. package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
  407. package/out/zero-cache/src/auth/write-authorizer.d.ts +4 -3
  408. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  409. package/out/zero-cache/src/auth/write-authorizer.js +387 -328
  410. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  411. package/out/zero-cache/src/config/network.js +42 -45
  412. package/out/zero-cache/src/config/network.js.map +1 -1
  413. package/out/zero-cache/src/config/normalize.js +86 -83
  414. package/out/zero-cache/src/config/normalize.js.map +1 -1
  415. package/out/zero-cache/src/config/zero-config.d.ts +27 -0
  416. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  417. package/out/zero-cache/src/config/zero-config.js +704 -682
  418. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  419. package/out/zero-cache/src/custom/fetch.d.ts +5 -5
  420. package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
  421. package/out/zero-cache/src/custom/fetch.js +170 -162
  422. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  423. package/out/zero-cache/src/custom-queries/transform-query.d.ts +10 -3
  424. package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +1 -1
  425. package/out/zero-cache/src/custom-queries/transform-query.js +101 -109
  426. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  427. package/out/zero-cache/src/db/create.js +32 -36
  428. package/out/zero-cache/src/db/create.js.map +1 -1
  429. package/out/zero-cache/src/db/delete-lite-db.js +9 -6
  430. package/out/zero-cache/src/db/delete-lite-db.js.map +1 -1
  431. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  432. package/out/zero-cache/src/db/lite-tables.js +150 -174
  433. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  434. package/out/zero-cache/src/db/migration-lite.js +170 -165
  435. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  436. package/out/zero-cache/src/db/migration.js +157 -137
  437. package/out/zero-cache/src/db/migration.js.map +1 -1
  438. package/out/zero-cache/src/db/mode-enum.d.ts +2 -0
  439. package/out/zero-cache/src/db/mode-enum.d.ts.map +1 -1
  440. package/out/zero-cache/src/db/mode-enum.js +9 -3
  441. package/out/zero-cache/src/db/mode-enum.js.map +1 -1
  442. package/out/zero-cache/src/db/pg-copy.js +51 -90
  443. package/out/zero-cache/src/db/pg-copy.js.map +1 -1
  444. package/out/zero-cache/src/db/pg-to-lite.d.ts +10 -0
  445. package/out/zero-cache/src/db/pg-to-lite.d.ts.map +1 -1
  446. package/out/zero-cache/src/db/pg-to-lite.js +116 -97
  447. package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
  448. package/out/zero-cache/src/db/pg-type-parser.js +27 -39
  449. package/out/zero-cache/src/db/pg-type-parser.js.map +1 -1
  450. package/out/zero-cache/src/db/postgres-replica-identity-enum.js +11 -6
  451. package/out/zero-cache/src/db/postgres-replica-identity-enum.js.map +1 -1
  452. package/out/zero-cache/src/db/postgres-type-class-enum.js +17 -9
  453. package/out/zero-cache/src/db/postgres-type-class-enum.js.map +1 -1
  454. package/out/zero-cache/src/db/specs.d.ts +1 -7
  455. package/out/zero-cache/src/db/specs.d.ts.map +1 -1
  456. package/out/zero-cache/src/db/specs.js +66 -40
  457. package/out/zero-cache/src/db/specs.js.map +1 -1
  458. package/out/zero-cache/src/db/statements.d.ts +1 -1
  459. package/out/zero-cache/src/db/statements.d.ts.map +1 -1
  460. package/out/zero-cache/src/db/statements.js +59 -52
  461. package/out/zero-cache/src/db/statements.js.map +1 -1
  462. package/out/zero-cache/src/db/transaction-pool.d.ts +1 -1
  463. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  464. package/out/zero-cache/src/db/transaction-pool.js +375 -501
  465. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  466. package/out/zero-cache/src/db/warmup.js +25 -12
  467. package/out/zero-cache/src/db/warmup.js.map +1 -1
  468. package/out/zero-cache/src/observability/events.js +71 -82
  469. package/out/zero-cache/src/observability/events.js.map +1 -1
  470. package/out/zero-cache/src/observability/metrics.js +54 -32
  471. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  472. package/out/zero-cache/src/scripts/decommission.d.ts +50 -0
  473. package/out/zero-cache/src/scripts/decommission.d.ts.map +1 -0
  474. package/out/zero-cache/src/scripts/decommission.js +55 -0
  475. package/out/zero-cache/src/scripts/decommission.js.map +1 -0
  476. package/out/zero-cache/src/scripts/deploy-permissions.js +128 -118
  477. package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
  478. package/out/zero-cache/src/scripts/permissions.d.ts +1 -1
  479. package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
  480. package/out/zero-cache/src/scripts/permissions.js +108 -100
  481. package/out/zero-cache/src/scripts/permissions.js.map +1 -1
  482. package/out/zero-cache/src/server/anonymous-otel-start.js +410 -366
  483. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  484. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  485. package/out/zero-cache/src/server/change-streamer.js +105 -64
  486. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  487. package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
  488. package/out/zero-cache/src/server/inspector-delegate.js +112 -108
  489. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  490. package/out/zero-cache/src/server/logging.d.ts +1 -1
  491. package/out/zero-cache/src/server/logging.d.ts.map +1 -1
  492. package/out/zero-cache/src/server/logging.js +26 -19
  493. package/out/zero-cache/src/server/logging.js.map +1 -1
  494. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  495. package/out/zero-cache/src/server/main.js +137 -120
  496. package/out/zero-cache/src/server/main.js.map +1 -1
  497. package/out/zero-cache/src/server/mutator.js +19 -0
  498. package/out/zero-cache/src/server/mutator.js.map +1 -0
  499. package/out/zero-cache/src/server/otel-diag-logger.d.ts +1 -1
  500. package/out/zero-cache/src/server/otel-diag-logger.d.ts.map +1 -1
  501. package/out/zero-cache/src/server/otel-diag-logger.js +67 -70
  502. package/out/zero-cache/src/server/otel-diag-logger.js.map +1 -1
  503. package/out/zero-cache/src/server/otel-log-sink.js +40 -41
  504. package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
  505. package/out/zero-cache/src/server/otel-start.d.ts +1 -1
  506. package/out/zero-cache/src/server/otel-start.d.ts.map +1 -1
  507. package/out/zero-cache/src/server/otel-start.js +57 -68
  508. package/out/zero-cache/src/server/otel-start.js.map +1 -1
  509. package/out/zero-cache/src/server/reaper.js +34 -26
  510. package/out/zero-cache/src/server/reaper.js.map +1 -1
  511. package/out/zero-cache/src/server/replicator.js +53 -31
  512. package/out/zero-cache/src/server/replicator.js.map +1 -1
  513. package/out/zero-cache/src/server/runner/main.js +6 -4
  514. package/out/zero-cache/src/server/runner/main.js.map +1 -1
  515. package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
  516. package/out/zero-cache/src/server/runner/run-worker.js +46 -50
  517. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  518. package/out/zero-cache/src/server/runner/runtime.js +33 -32
  519. package/out/zero-cache/src/server/runner/runtime.js.map +1 -1
  520. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
  521. package/out/zero-cache/src/server/runner/zero-dispatcher.js +28 -22
  522. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  523. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  524. package/out/zero-cache/src/server/syncer.js +124 -63
  525. package/out/zero-cache/src/server/syncer.js.map +1 -1
  526. package/out/zero-cache/src/server/worker-dispatcher.d.ts +1 -1
  527. package/out/zero-cache/src/server/worker-dispatcher.d.ts.map +1 -1
  528. package/out/zero-cache/src/server/worker-dispatcher.js +112 -106
  529. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  530. package/out/zero-cache/src/server/worker-urls.d.ts +7 -0
  531. package/out/zero-cache/src/server/worker-urls.d.ts.map +1 -0
  532. package/out/zero-cache/src/server/worker-urls.js +21 -0
  533. package/out/zero-cache/src/server/worker-urls.js.map +1 -0
  534. package/out/zero-cache/src/services/analyze.d.ts +4 -9
  535. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  536. package/out/zero-cache/src/services/analyze.js +104 -120
  537. package/out/zero-cache/src/services/analyze.js.map +1 -1
  538. package/out/zero-cache/src/services/change-source/column-metadata.d.ts +10 -3
  539. package/out/zero-cache/src/services/change-source/column-metadata.d.ts.map +1 -1
  540. package/out/zero-cache/src/services/change-source/column-metadata.js +154 -144
  541. package/out/zero-cache/src/services/change-source/column-metadata.js.map +1 -1
  542. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +1 -1
  543. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
  544. package/out/zero-cache/src/services/change-source/custom/change-source.js +197 -171
  545. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  546. package/out/zero-cache/src/services/change-source/custom/sync-schema.js +11 -3
  547. package/out/zero-cache/src/services/change-source/custom/sync-schema.js.map +1 -1
  548. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +1 -1
  549. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  550. package/out/zero-cache/src/services/change-source/pg/change-source.js +601 -622
  551. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  552. package/out/zero-cache/src/services/change-source/pg/decommission.js +24 -23
  553. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  554. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +1 -1
  555. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  556. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +327 -284
  557. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  558. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts +2 -3
  559. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts.map +1 -1
  560. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.js +61 -69
  561. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.js.map +1 -1
  562. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js +247 -257
  563. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js.map +1 -1
  564. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +127 -119
  565. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  566. package/out/zero-cache/src/services/change-source/pg/lsn.js +20 -19
  567. package/out/zero-cache/src/services/change-source/pg/lsn.js.map +1 -1
  568. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +5 -5
  569. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +96 -119
  570. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  571. package/out/zero-cache/src/services/change-source/pg/schema/init.js +138 -117
  572. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  573. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +2 -2
  574. package/out/zero-cache/src/services/change-source/pg/schema/published.js +67 -74
  575. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
  576. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +1 -1
  577. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +199 -188
  578. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  579. package/out/zero-cache/src/services/change-source/pg/schema/validation.js +53 -38
  580. package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
  581. package/out/zero-cache/src/services/change-source/pg/sync-schema.js +11 -3
  582. package/out/zero-cache/src/services/change-source/pg/sync-schema.js.map +1 -1
  583. package/out/zero-cache/src/services/change-source/protocol/current/control.js +9 -19
  584. package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
  585. package/out/zero-cache/src/services/change-source/protocol/current/data.js +143 -116
  586. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  587. package/out/zero-cache/src/services/change-source/protocol/current/downstream.js +29 -19
  588. package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -1
  589. package/out/zero-cache/src/services/change-source/protocol/current/path.js +5 -20
  590. package/out/zero-cache/src/services/change-source/protocol/current/path.js.map +1 -1
  591. package/out/zero-cache/src/services/change-source/protocol/current/status.js +12 -13
  592. package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
  593. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +1 -1
  594. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
  595. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js +5 -4
  596. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  597. package/out/zero-cache/src/services/change-source/protocol/current.js +35 -7
  598. package/out/zero-cache/src/services/change-source/protocol/current.js.map +1 -1
  599. package/out/zero-cache/src/services/change-source/replica-schema.d.ts.map +1 -1
  600. package/out/zero-cache/src/services/change-source/replica-schema.js +67 -37
  601. package/out/zero-cache/src/services/change-source/replica-schema.js.map +1 -1
  602. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +1 -1
  603. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
  604. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +139 -157
  605. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  606. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +13 -4
  607. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  608. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +213 -157
  609. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  610. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +1 -1
  611. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  612. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +235 -349
  613. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  614. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +5 -1
  615. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  616. package/out/zero-cache/src/services/change-streamer/change-streamer.js +24 -22
  617. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  618. package/out/zero-cache/src/services/change-streamer/error-type-enum.js +9 -4
  619. package/out/zero-cache/src/services/change-streamer/error-type-enum.js.map +1 -1
  620. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +1 -1
  621. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  622. package/out/zero-cache/src/services/change-streamer/forwarder.js +53 -57
  623. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  624. package/out/zero-cache/src/services/change-streamer/replica-monitor.d.ts +16 -0
  625. package/out/zero-cache/src/services/change-streamer/replica-monitor.d.ts.map +1 -0
  626. package/out/zero-cache/src/services/change-streamer/replica-monitor.js +48 -0
  627. package/out/zero-cache/src/services/change-streamer/replica-monitor.js.map +1 -0
  628. package/out/zero-cache/src/services/change-streamer/schema/init.js +82 -68
  629. package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
  630. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +2 -2
  631. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  632. package/out/zero-cache/src/services/change-streamer/schema/tables.js +93 -78
  633. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  634. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +58 -0
  635. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +1 -1
  636. package/out/zero-cache/src/services/change-streamer/snapshot.js +28 -18
  637. package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
  638. package/out/zero-cache/src/services/change-streamer/storer.d.ts +3 -2
  639. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  640. package/out/zero-cache/src/services/change-streamer/storer.js +309 -353
  641. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  642. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +3 -2
  643. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  644. package/out/zero-cache/src/services/change-streamer/subscriber.js +85 -87
  645. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  646. package/out/zero-cache/src/services/heapz.js +21 -25
  647. package/out/zero-cache/src/services/heapz.js.map +1 -1
  648. package/out/zero-cache/src/services/http-service.d.ts +6 -5
  649. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  650. package/out/zero-cache/src/services/http-service.js +61 -59
  651. package/out/zero-cache/src/services/http-service.js.map +1 -1
  652. package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
  653. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  654. package/out/zero-cache/src/services/life-cycle.js +216 -255
  655. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  656. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js +76 -130
  657. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js.map +1 -1
  658. package/out/zero-cache/src/services/litestream/commands.d.ts +1 -1
  659. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  660. package/out/zero-cache/src/services/litestream/commands.js +201 -154
  661. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  662. package/out/zero-cache/src/services/mutagen/error.js +11 -6
  663. package/out/zero-cache/src/services/mutagen/error.js.map +1 -1
  664. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +2 -1
  665. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  666. package/out/zero-cache/src/services/mutagen/mutagen.js +271 -267
  667. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  668. package/out/zero-cache/src/services/mutagen/pusher.d.ts +217 -21
  669. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  670. package/out/zero-cache/src/services/mutagen/pusher.js +354 -348
  671. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  672. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  673. package/out/zero-cache/src/services/replicator/change-processor.js +483 -497
  674. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  675. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +1 -1
  676. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  677. package/out/zero-cache/src/services/replicator/incremental-sync.js +97 -97
  678. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  679. package/out/zero-cache/src/services/replicator/notifier.js +28 -52
  680. package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
  681. package/out/zero-cache/src/services/replicator/replication-status.js +100 -83
  682. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  683. package/out/zero-cache/src/services/replicator/replicator.d.ts +1 -1
  684. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  685. package/out/zero-cache/src/services/replicator/replicator.js +33 -26
  686. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  687. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +1 -1
  688. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
  689. package/out/zero-cache/src/services/replicator/schema/change-log.js +74 -86
  690. package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
  691. package/out/zero-cache/src/services/replicator/schema/constants.js +5 -7
  692. package/out/zero-cache/src/services/replicator/schema/constants.js.map +1 -1
  693. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts +2 -2
  694. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts.map +1 -1
  695. package/out/zero-cache/src/services/replicator/schema/replication-state.js +70 -74
  696. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  697. package/out/zero-cache/src/services/run-ast.d.ts +9 -3
  698. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  699. package/out/zero-cache/src/services/run-ast.js +87 -78
  700. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  701. package/out/zero-cache/src/services/runner.d.ts +1 -1
  702. package/out/zero-cache/src/services/runner.d.ts.map +1 -1
  703. package/out/zero-cache/src/services/runner.js +40 -40
  704. package/out/zero-cache/src/services/runner.js.map +1 -1
  705. package/out/zero-cache/src/services/running-state.d.ts +1 -1
  706. package/out/zero-cache/src/services/running-state.d.ts.map +1 -1
  707. package/out/zero-cache/src/services/running-state.js +122 -119
  708. package/out/zero-cache/src/services/running-state.js.map +1 -1
  709. package/out/zero-cache/src/services/statz.js +184 -162
  710. package/out/zero-cache/src/services/statz.js.map +1 -1
  711. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +40 -39
  712. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
  713. package/out/zero-cache/src/services/view-syncer/client-handler.js +307 -298
  714. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  715. package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.map +1 -1
  716. package/out/zero-cache/src/services/view-syncer/client-schema.js +80 -82
  717. package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
  718. package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts.map +1 -1
  719. package/out/zero-cache/src/services/view-syncer/cvr-purger.js +84 -94
  720. package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
  721. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +2 -4
  722. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  723. package/out/zero-cache/src/services/view-syncer/cvr-store.js +654 -611
  724. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  725. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +1 -1
  726. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  727. package/out/zero-cache/src/services/view-syncer/cvr.js +633 -695
  728. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  729. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +1 -0
  730. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +1 -1
  731. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +38 -55
  732. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  733. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +2 -1
  734. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
  735. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +175 -85
  736. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  737. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +14 -13
  738. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  739. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +534 -465
  740. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  741. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts +1 -1
  742. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
  743. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +229 -277
  744. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  745. package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts.map +1 -1
  746. package/out/zero-cache/src/services/view-syncer/schema/cvr.js +57 -122
  747. package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
  748. package/out/zero-cache/src/services/view-syncer/schema/init.d.ts.map +1 -1
  749. package/out/zero-cache/src/services/view-syncer/schema/init.js +177 -131
  750. package/out/zero-cache/src/services/view-syncer/schema/init.js.map +1 -1
  751. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +4 -4
  752. package/out/zero-cache/src/services/view-syncer/schema/types.js +265 -257
  753. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  754. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +3 -3
  755. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  756. package/out/zero-cache/src/services/view-syncer/snapshotter.js +295 -338
  757. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  758. package/out/zero-cache/src/services/view-syncer/ttl-clock.js +13 -7
  759. package/out/zero-cache/src/services/view-syncer/ttl-clock.js.map +1 -1
  760. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +10 -3
  761. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  762. package/out/zero-cache/src/services/view-syncer/view-syncer.js +1508 -1284
  763. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  764. package/out/zero-cache/src/types/error-with-level.d.ts.map +1 -1
  765. package/out/zero-cache/src/types/error-with-level.js +30 -21
  766. package/out/zero-cache/src/types/error-with-level.js.map +1 -1
  767. package/out/zero-cache/src/types/http.js +27 -14
  768. package/out/zero-cache/src/types/http.js.map +1 -1
  769. package/out/zero-cache/src/types/lexi-version.js +46 -31
  770. package/out/zero-cache/src/types/lexi-version.js.map +1 -1
  771. package/out/zero-cache/src/types/lite.js +118 -125
  772. package/out/zero-cache/src/types/lite.js.map +1 -1
  773. package/out/zero-cache/src/types/names.js +6 -3
  774. package/out/zero-cache/src/types/names.js.map +1 -1
  775. package/out/zero-cache/src/types/pg-data-type.js +74 -68
  776. package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
  777. package/out/zero-cache/src/types/pg-types.js +17 -72
  778. package/out/zero-cache/src/types/pg-types.js.map +1 -1
  779. package/out/zero-cache/src/types/pg.d.ts +1 -1
  780. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  781. package/out/zero-cache/src/types/pg.js +213 -233
  782. package/out/zero-cache/src/types/pg.js.map +1 -1
  783. package/out/zero-cache/src/types/processes.d.ts +2 -2
  784. package/out/zero-cache/src/types/processes.d.ts.map +1 -1
  785. package/out/zero-cache/src/types/processes.js +95 -143
  786. package/out/zero-cache/src/types/processes.js.map +1 -1
  787. package/out/zero-cache/src/types/profiler.js +29 -30
  788. package/out/zero-cache/src/types/profiler.js.map +1 -1
  789. package/out/zero-cache/src/types/row-key.js +30 -68
  790. package/out/zero-cache/src/types/row-key.js.map +1 -1
  791. package/out/zero-cache/src/types/schema-versions.js +25 -19
  792. package/out/zero-cache/src/types/schema-versions.js.map +1 -1
  793. package/out/zero-cache/src/types/shards.js +50 -36
  794. package/out/zero-cache/src/types/shards.js.map +1 -1
  795. package/out/zero-cache/src/types/sql.js +9 -13
  796. package/out/zero-cache/src/types/sql.js.map +1 -1
  797. package/out/zero-cache/src/types/streams.d.ts +1 -1
  798. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  799. package/out/zero-cache/src/types/streams.js +246 -245
  800. package/out/zero-cache/src/types/streams.js.map +1 -1
  801. package/out/zero-cache/src/types/strings.js +14 -11
  802. package/out/zero-cache/src/types/strings.js.map +1 -1
  803. package/out/zero-cache/src/types/subscription.d.ts +16 -1
  804. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  805. package/out/zero-cache/src/types/subscription.js +202 -225
  806. package/out/zero-cache/src/types/subscription.js.map +1 -1
  807. package/out/zero-cache/src/types/url-params.js +35 -30
  808. package/out/zero-cache/src/types/url-params.js.map +1 -1
  809. package/out/zero-cache/src/types/websocket-handoff.d.ts +5 -4
  810. package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
  811. package/out/zero-cache/src/types/websocket-handoff.js +68 -76
  812. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  813. package/out/zero-cache/src/types/ws.js +56 -59
  814. package/out/zero-cache/src/types/ws.js.map +1 -1
  815. package/out/zero-cache/src/workers/connect-params.js +44 -40
  816. package/out/zero-cache/src/workers/connect-params.js.map +1 -1
  817. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  818. package/out/zero-cache/src/workers/connection.js +282 -243
  819. package/out/zero-cache/src/workers/connection.js.map +1 -1
  820. package/out/zero-cache/src/workers/mutator.js +24 -0
  821. package/out/zero-cache/src/workers/mutator.js.map +1 -0
  822. package/out/zero-cache/src/workers/replicator.d.ts +1 -1
  823. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  824. package/out/zero-cache/src/workers/replicator.js +103 -106
  825. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  826. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +179 -147
  827. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  828. package/out/zero-cache/src/workers/syncer.d.ts +3 -3
  829. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  830. package/out/zero-cache/src/workers/syncer.js +192 -171
  831. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  832. package/out/zero-client/src/client/active-clients-manager.js +199 -0
  833. package/out/zero-client/src/client/active-clients-manager.js.map +1 -0
  834. package/out/zero-client/src/client/bindings.d.ts +43 -0
  835. package/out/zero-client/src/client/bindings.d.ts.map +1 -0
  836. package/out/zero-client/src/client/bindings.js +33 -0
  837. package/out/zero-client/src/client/bindings.js.map +1 -0
  838. package/out/zero-client/src/client/client-error-kind-enum.d.ts +12 -12
  839. package/out/zero-client/src/client/client-error-kind-enum.d.ts.map +1 -1
  840. package/out/zero-client/src/client/client-error-kind-enum.js +29 -0
  841. package/out/zero-client/src/client/client-error-kind-enum.js.map +1 -0
  842. package/out/zero-client/src/client/connection-manager.d.ts +36 -40
  843. package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
  844. package/out/zero-client/src/client/connection-manager.js +310 -0
  845. package/out/zero-client/src/client/connection-manager.js.map +1 -0
  846. package/out/zero-client/src/client/connection-status-enum.d.ts +2 -0
  847. package/out/zero-client/src/client/connection-status-enum.d.ts.map +1 -1
  848. package/out/zero-client/src/client/connection-status-enum.js +15 -0
  849. package/out/zero-client/src/client/connection-status-enum.js.map +1 -0
  850. package/out/zero-client/src/client/connection.d.ts +57 -6
  851. package/out/zero-client/src/client/connection.d.ts.map +1 -1
  852. package/out/zero-client/src/client/connection.js +103 -0
  853. package/out/zero-client/src/client/connection.js.map +1 -0
  854. package/out/zero-client/src/client/context.d.ts +9 -10
  855. package/out/zero-client/src/client/context.d.ts.map +1 -1
  856. package/out/zero-client/src/client/context.js +104 -0
  857. package/out/zero-client/src/client/context.js.map +1 -0
  858. package/out/zero-client/src/client/crud.d.ts +8 -6
  859. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  860. package/out/zero-client/src/client/crud.js +225 -0
  861. package/out/zero-client/src/client/crud.js.map +1 -0
  862. package/out/zero-client/src/client/custom.d.ts +48 -25
  863. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  864. package/out/zero-client/src/client/custom.js +128 -0
  865. package/out/zero-client/src/client/custom.js.map +1 -0
  866. package/out/zero-client/src/client/delete-clients-manager.d.ts +2 -2
  867. package/out/zero-client/src/client/delete-clients-manager.d.ts.map +1 -1
  868. package/out/zero-client/src/client/delete-clients-manager.js +71 -0
  869. package/out/zero-client/src/client/delete-clients-manager.js.map +1 -0
  870. package/out/zero-client/src/client/enable-analytics.js +18 -0
  871. package/out/zero-client/src/client/enable-analytics.js.map +1 -0
  872. package/out/zero-client/src/client/error.d.ts +51 -166
  873. package/out/zero-client/src/client/error.d.ts.map +1 -1
  874. package/out/zero-client/src/client/error.js +148 -0
  875. package/out/zero-client/src/client/error.js.map +1 -0
  876. package/out/zero-client/src/client/http-string.js +11 -0
  877. package/out/zero-client/src/client/http-string.js.map +1 -0
  878. package/out/zero-client/src/client/inspector/client-group.js +27 -0
  879. package/out/zero-client/src/client/inspector/client-group.js.map +1 -0
  880. package/out/zero-client/src/client/inspector/client.js +28 -0
  881. package/out/zero-client/src/client/inspector/client.js.map +1 -0
  882. package/out/zero-client/src/client/inspector/html-dialog-prompt.d.ts.map +1 -1
  883. package/out/zero-client/src/client/inspector/html-dialog-prompt.js +77 -0
  884. package/out/zero-client/src/client/inspector/html-dialog-prompt.js.map +1 -0
  885. package/out/zero-client/src/client/inspector/inspector.d.ts +8 -3
  886. package/out/zero-client/src/client/inspector/inspector.d.ts.map +1 -1
  887. package/out/zero-client/src/client/inspector/inspector.js +54 -0
  888. package/out/zero-client/src/client/inspector/inspector.js.map +1 -0
  889. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts +4 -1
  890. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts.map +1 -1
  891. package/out/zero-client/src/client/inspector/lazy-inspector.js +243 -0
  892. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -0
  893. package/out/zero-client/src/client/inspector/query.d.ts.map +1 -1
  894. package/out/zero-client/src/client/inspector/query.js +82 -0
  895. package/out/zero-client/src/client/inspector/query.js.map +1 -0
  896. package/out/zero-client/src/client/ivm-branch.d.ts +4 -4
  897. package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
  898. package/out/zero-client/src/client/ivm-branch.js +149 -0
  899. package/out/zero-client/src/client/ivm-branch.js.map +1 -0
  900. package/out/zero-client/src/client/keys.js +45 -0
  901. package/out/zero-client/src/client/keys.js.map +1 -0
  902. package/out/zero-client/src/client/log-options.js +60 -0
  903. package/out/zero-client/src/client/log-options.js.map +1 -0
  904. package/out/zero-client/src/client/make-mutate-property.d.ts +43 -0
  905. package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -0
  906. package/out/zero-client/src/client/make-mutate-property.js +38 -0
  907. package/out/zero-client/src/client/make-mutate-property.js.map +1 -0
  908. package/out/zero-client/src/client/make-replicache-mutators.d.ts +34 -0
  909. package/out/zero-client/src/client/make-replicache-mutators.d.ts.map +1 -0
  910. package/out/zero-client/src/client/make-replicache-mutators.js +103 -0
  911. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -0
  912. package/out/zero-client/src/client/metric-name-enum.js +15 -0
  913. package/out/zero-client/src/client/metric-name-enum.js.map +1 -0
  914. package/out/zero-client/src/client/metrics.d.ts +2 -2
  915. package/out/zero-client/src/client/metrics.d.ts.map +1 -1
  916. package/out/zero-client/src/client/metrics.js +249 -0
  917. package/out/zero-client/src/client/metrics.js.map +1 -0
  918. package/out/zero-client/src/client/mutation-tracker.d.ts +12 -4
  919. package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
  920. package/out/zero-client/src/client/mutation-tracker.js +363 -0
  921. package/out/zero-client/src/client/mutation-tracker.js.map +1 -0
  922. package/out/zero-client/src/client/mutator-proxy.d.ts +15 -0
  923. package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -0
  924. package/out/zero-client/src/client/mutator-proxy.js +132 -0
  925. package/out/zero-client/src/client/mutator-proxy.js.map +1 -0
  926. package/out/zero-client/src/client/options.d.ts +77 -24
  927. package/out/zero-client/src/client/options.d.ts.map +1 -1
  928. package/out/zero-client/src/client/options.js +11 -0
  929. package/out/zero-client/src/client/options.js.map +1 -0
  930. package/out/zero-client/src/client/query-manager.d.ts +9 -2
  931. package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
  932. package/out/zero-client/src/client/query-manager.js +377 -0
  933. package/out/zero-client/src/client/query-manager.js.map +1 -0
  934. package/out/zero-client/src/client/reload-error-handler.d.ts +4 -4
  935. package/out/zero-client/src/client/reload-error-handler.d.ts.map +1 -1
  936. package/out/zero-client/src/client/reload-error-handler.js +114 -0
  937. package/out/zero-client/src/client/reload-error-handler.js.map +1 -0
  938. package/out/zero-client/src/client/server-option.js +64 -0
  939. package/out/zero-client/src/client/server-option.js.map +1 -0
  940. package/out/zero-client/src/client/update-needed-reason-type-enum.js +9 -0
  941. package/out/zero-client/src/client/update-needed-reason-type-enum.js.map +1 -0
  942. package/out/zero-client/src/client/version.js +5 -0
  943. package/out/zero-client/src/client/version.js.map +1 -0
  944. package/out/zero-client/src/client/zero-poke-handler.d.ts +4 -4
  945. package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
  946. package/out/zero-client/src/client/zero-poke-handler.js +303 -0
  947. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -0
  948. package/out/zero-client/src/client/zero-rep.d.ts +5 -2
  949. package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
  950. package/out/zero-client/src/client/zero-rep.js +72 -0
  951. package/out/zero-client/src/client/zero-rep.js.map +1 -0
  952. package/out/zero-client/src/client/zero.d.ts +104 -26
  953. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  954. package/out/zero-client/src/client/zero.js +1759 -0
  955. package/out/zero-client/src/client/zero.js.map +1 -0
  956. package/out/zero-client/src/mod.d.ts +24 -18
  957. package/out/zero-client/src/mod.d.ts.map +1 -1
  958. package/out/zero-client/src/types/query-result.d.ts +24 -0
  959. package/out/zero-client/src/types/query-result.d.ts.map +1 -0
  960. package/out/zero-client/src/util/nanoid.js +21 -0
  961. package/out/zero-client/src/util/nanoid.js.map +1 -0
  962. package/out/zero-client/src/util/socket.js +7 -0
  963. package/out/zero-client/src/util/socket.js.map +1 -0
  964. package/out/zero-protocol/src/analyze-query-result.d.ts +237 -0
  965. package/out/zero-protocol/src/analyze-query-result.d.ts.map +1 -1
  966. package/out/zero-protocol/src/analyze-query-result.js +159 -24
  967. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  968. package/out/zero-protocol/src/application-error.d.ts +27 -0
  969. package/out/zero-protocol/src/application-error.d.ts.map +1 -0
  970. package/out/zero-protocol/src/application-error.js +38 -0
  971. package/out/zero-protocol/src/application-error.js.map +1 -0
  972. package/out/zero-protocol/src/ast.d.ts +2 -2
  973. package/out/zero-protocol/src/ast.js +296 -277
  974. package/out/zero-protocol/src/ast.js.map +1 -1
  975. package/out/zero-protocol/src/change-desired-queries.d.ts +2 -2
  976. package/out/zero-protocol/src/change-desired-queries.js +11 -7
  977. package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
  978. package/out/zero-protocol/src/client-schema.d.ts +2 -2
  979. package/out/zero-protocol/src/client-schema.d.ts.map +1 -1
  980. package/out/zero-protocol/src/client-schema.js +40 -26
  981. package/out/zero-protocol/src/client-schema.js.map +1 -1
  982. package/out/zero-protocol/src/close-connection.js +11 -18
  983. package/out/zero-protocol/src/close-connection.js.map +1 -1
  984. package/out/zero-protocol/src/connect.d.ts +4 -4
  985. package/out/zero-protocol/src/connect.d.ts.map +1 -1
  986. package/out/zero-protocol/src/connect.js +50 -51
  987. package/out/zero-protocol/src/connect.js.map +1 -1
  988. package/out/zero-protocol/src/custom-queries.d.ts +31 -99
  989. package/out/zero-protocol/src/custom-queries.d.ts.map +1 -1
  990. package/out/zero-protocol/src/custom-queries.js +61 -54
  991. package/out/zero-protocol/src/custom-queries.js.map +1 -1
  992. package/out/zero-protocol/src/data.js +9 -4
  993. package/out/zero-protocol/src/data.js.map +1 -1
  994. package/out/zero-protocol/src/delete-clients.js +16 -9
  995. package/out/zero-protocol/src/delete-clients.js.map +1 -1
  996. package/out/zero-protocol/src/down.d.ts +113 -15
  997. package/out/zero-protocol/src/down.d.ts.map +1 -1
  998. package/out/zero-protocol/src/down.js +20 -4
  999. package/out/zero-protocol/src/down.js.map +1 -1
  1000. package/out/zero-protocol/src/error-kind-enum.js +41 -23
  1001. package/out/zero-protocol/src/error-kind-enum.js.map +1 -1
  1002. package/out/zero-protocol/src/error-origin-enum.js +9 -4
  1003. package/out/zero-protocol/src/error-origin-enum.js.map +1 -1
  1004. package/out/zero-protocol/src/error-reason-enum.js +17 -8
  1005. package/out/zero-protocol/src/error-reason-enum.js.map +1 -1
  1006. package/out/zero-protocol/src/error.d.ts +59 -17
  1007. package/out/zero-protocol/src/error.d.ts.map +1 -1
  1008. package/out/zero-protocol/src/error.js +151 -82
  1009. package/out/zero-protocol/src/error.js.map +1 -1
  1010. package/out/zero-protocol/src/inspect-down.d.ts +318 -18
  1011. package/out/zero-protocol/src/inspect-down.d.ts.map +1 -1
  1012. package/out/zero-protocol/src/inspect-down.js +72 -54
  1013. package/out/zero-protocol/src/inspect-down.js.map +1 -1
  1014. package/out/zero-protocol/src/inspect-up.d.ts +10 -6
  1015. package/out/zero-protocol/src/inspect-up.d.ts.map +1 -1
  1016. package/out/zero-protocol/src/inspect-up.js +39 -26
  1017. package/out/zero-protocol/src/inspect-up.js.map +1 -1
  1018. package/out/zero-protocol/src/mutation-id.js +9 -5
  1019. package/out/zero-protocol/src/mutation-id.js.map +1 -1
  1020. package/out/zero-protocol/src/mutation-type-enum.js +7 -3
  1021. package/out/zero-protocol/src/mutation-type-enum.js.map +1 -1
  1022. package/out/zero-protocol/src/mutations-patch.d.ts +3 -0
  1023. package/out/zero-protocol/src/mutations-patch.d.ts.map +1 -1
  1024. package/out/zero-protocol/src/mutations-patch.js +16 -17
  1025. package/out/zero-protocol/src/mutations-patch.js.map +1 -1
  1026. package/out/zero-protocol/src/ping.js +9 -4
  1027. package/out/zero-protocol/src/ping.js.map +1 -1
  1028. package/out/zero-protocol/src/poke.d.ts +2 -0
  1029. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  1030. package/out/zero-protocol/src/poke.js +55 -72
  1031. package/out/zero-protocol/src/poke.js.map +1 -1
  1032. package/out/zero-protocol/src/pong.js +9 -4
  1033. package/out/zero-protocol/src/pong.js.map +1 -1
  1034. package/out/zero-protocol/src/primary-key.js +19 -5
  1035. package/out/zero-protocol/src/primary-key.js.map +1 -1
  1036. package/out/zero-protocol/src/protocol-version.d.ts +2 -2
  1037. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  1038. package/out/zero-protocol/src/protocol-version.js +7 -57
  1039. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  1040. package/out/zero-protocol/src/pull.js +26 -19
  1041. package/out/zero-protocol/src/pull.js.map +1 -1
  1042. package/out/zero-protocol/src/push.d.ts +11 -4
  1043. package/out/zero-protocol/src/push.d.ts.map +1 -1
  1044. package/out/zero-protocol/src/push.js +179 -175
  1045. package/out/zero-protocol/src/push.js.map +1 -1
  1046. package/out/zero-protocol/src/queries-patch.d.ts +3 -3
  1047. package/out/zero-protocol/src/queries-patch.js +29 -22
  1048. package/out/zero-protocol/src/queries-patch.js.map +1 -1
  1049. package/out/zero-protocol/src/query-hash.js +18 -14
  1050. package/out/zero-protocol/src/query-hash.js.map +1 -1
  1051. package/out/zero-protocol/src/row-patch.js +29 -20
  1052. package/out/zero-protocol/src/row-patch.js.map +1 -1
  1053. package/out/zero-protocol/src/up.d.ts +6 -5
  1054. package/out/zero-protocol/src/up.d.ts.map +1 -1
  1055. package/out/zero-protocol/src/up.js +18 -4
  1056. package/out/zero-protocol/src/up.js.map +1 -1
  1057. package/out/zero-protocol/src/version.js +9 -4
  1058. package/out/zero-protocol/src/version.js.map +1 -1
  1059. package/out/zero-react/src/components/inspector.d.ts +5 -3
  1060. package/out/zero-react/src/components/inspector.d.ts.map +1 -1
  1061. package/out/{inspector-IU2HG74I.js → zero-react/src/components/inspector.js} +4 -9
  1062. package/out/zero-react/src/components/inspector.js.map +1 -0
  1063. package/out/{chunk-VZOYWIRW.js → zero-react/src/components/mark-icon.js} +3 -5
  1064. package/out/zero-react/src/components/mark-icon.js.map +1 -0
  1065. package/out/zero-react/src/components/zero-inspector.d.ts +5 -3
  1066. package/out/zero-react/src/components/zero-inspector.d.ts.map +1 -1
  1067. package/out/zero-react/src/components/zero-inspector.js +44 -0
  1068. package/out/zero-react/src/components/zero-inspector.js.map +1 -0
  1069. package/out/zero-react/src/mod.d.ts +5 -3
  1070. package/out/zero-react/src/mod.d.ts.map +1 -1
  1071. package/out/zero-react/src/use-query.d.ts +11 -28
  1072. package/out/zero-react/src/use-query.d.ts.map +1 -1
  1073. package/out/zero-react/src/use-query.js +286 -0
  1074. package/out/zero-react/src/use-query.js.map +1 -0
  1075. package/out/zero-react/src/use-zero-connection-state.d.ts +1 -1
  1076. package/out/zero-react/src/use-zero-connection-state.d.ts.map +1 -1
  1077. package/out/zero-react/src/use-zero-connection-state.js +14 -0
  1078. package/out/zero-react/src/use-zero-connection-state.js.map +1 -0
  1079. package/out/zero-react/src/use-zero-online.js +14 -0
  1080. package/out/zero-react/src/use-zero-online.js.map +1 -0
  1081. package/out/zero-react/src/zero-provider.d.ts +21 -7
  1082. package/out/zero-react/src/zero-provider.d.ts.map +1 -1
  1083. package/out/zero-react/src/zero-provider.js +61 -0
  1084. package/out/zero-react/src/zero-provider.js.map +1 -0
  1085. package/out/zero-schema/src/builder/relationship-builder.js +22 -19
  1086. package/out/zero-schema/src/builder/relationship-builder.js.map +1 -1
  1087. package/out/zero-schema/src/builder/schema-builder.d.ts +1 -3
  1088. package/out/zero-schema/src/builder/schema-builder.d.ts.map +1 -1
  1089. package/out/zero-schema/src/builder/schema-builder.js +81 -71
  1090. package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
  1091. package/out/zero-schema/src/builder/table-builder.js +117 -116
  1092. package/out/zero-schema/src/builder/table-builder.js.map +1 -1
  1093. package/out/zero-schema/src/compiled-permissions.js +23 -19
  1094. package/out/zero-schema/src/compiled-permissions.js.map +1 -1
  1095. package/out/zero-schema/src/name-mapper.js +43 -38
  1096. package/out/zero-schema/src/name-mapper.js.map +1 -1
  1097. package/out/zero-schema/src/permissions.d.ts +9 -9
  1098. package/out/zero-schema/src/permissions.d.ts.map +1 -1
  1099. package/out/{chunk-55BOUNXO.js → zero-schema/src/permissions.js} +16 -173
  1100. package/out/zero-schema/src/permissions.js.map +1 -0
  1101. package/out/zero-schema/src/schema-config.d.ts +1 -1
  1102. package/out/zero-schema/src/schema-config.d.ts.map +1 -1
  1103. package/out/zero-schema/src/schema-config.js +35 -51
  1104. package/out/zero-schema/src/schema-config.js.map +1 -1
  1105. package/out/zero-server/src/adapters/drizzle.d.ts +2 -2
  1106. package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
  1107. package/out/zero-server/src/adapters/drizzle.js +84 -97
  1108. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  1109. package/out/zero-server/src/adapters/pg.d.ts +8 -2
  1110. package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
  1111. package/out/zero-server/src/adapters/pg.js +54 -74
  1112. package/out/zero-server/src/adapters/pg.js.map +1 -1
  1113. package/out/zero-server/src/adapters/postgresjs.d.ts +7 -2
  1114. package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
  1115. package/out/zero-server/src/adapters/postgresjs.js +40 -54
  1116. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  1117. package/out/zero-server/src/custom.d.ts +14 -18
  1118. package/out/zero-server/src/custom.d.ts.map +1 -1
  1119. package/out/zero-server/src/custom.js +185 -105
  1120. package/out/zero-server/src/custom.js.map +1 -1
  1121. package/out/zero-server/src/logging.js +7 -4
  1122. package/out/zero-server/src/logging.js.map +1 -1
  1123. package/out/zero-server/src/mod.d.ts +5 -4
  1124. package/out/zero-server/src/mod.d.ts.map +1 -1
  1125. package/out/zero-server/src/pg-query-executor.d.ts +11 -0
  1126. package/out/zero-server/src/pg-query-executor.d.ts.map +1 -0
  1127. package/out/zero-server/src/pg-query-executor.js +20 -0
  1128. package/out/zero-server/src/pg-query-executor.js.map +1 -0
  1129. package/out/zero-server/src/process-mutations.d.ts +11 -15
  1130. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  1131. package/out/zero-server/src/process-mutations.js +341 -163
  1132. package/out/zero-server/src/process-mutations.js.map +1 -1
  1133. package/out/zero-server/src/push-processor.d.ts +5 -3
  1134. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  1135. package/out/zero-server/src/push-processor.js +48 -32
  1136. package/out/zero-server/src/push-processor.js.map +1 -1
  1137. package/out/zero-server/src/queries/process-queries.d.ts +66 -4
  1138. package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
  1139. package/out/zero-server/src/queries/process-queries.js +101 -27
  1140. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  1141. package/out/zero-server/src/schema.d.ts +2 -2
  1142. package/out/zero-server/src/schema.d.ts.map +1 -1
  1143. package/out/zero-server/src/schema.js +136 -124
  1144. package/out/zero-server/src/schema.js.map +1 -1
  1145. package/out/zero-server/src/zql-database.d.ts +9 -6
  1146. package/out/zero-server/src/zql-database.d.ts.map +1 -1
  1147. package/out/zero-server/src/zql-database.js +68 -51
  1148. package/out/zero-server/src/zql-database.js.map +1 -1
  1149. package/out/zero-solid/src/mod.d.ts +7 -0
  1150. package/out/zero-solid/src/mod.d.ts.map +1 -1
  1151. package/out/zero-solid/src/solid-view.d.ts +3 -23
  1152. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  1153. package/out/{solid.js → zero-solid/src/solid-view.js} +54 -180
  1154. package/out/zero-solid/src/solid-view.js.map +1 -0
  1155. package/out/zero-solid/src/use-query.d.ts +7 -6
  1156. package/out/zero-solid/src/use-query.d.ts.map +1 -1
  1157. package/out/zero-solid/src/use-query.js +57 -0
  1158. package/out/zero-solid/src/use-query.js.map +1 -0
  1159. package/out/zero-solid/src/use-zero-connection-state.d.ts +1 -1
  1160. package/out/zero-solid/src/use-zero-connection-state.d.ts.map +1 -1
  1161. package/out/zero-solid/src/use-zero-connection-state.js +17 -0
  1162. package/out/zero-solid/src/use-zero-connection-state.js.map +1 -0
  1163. package/out/zero-solid/src/use-zero-online.d.ts.map +1 -1
  1164. package/out/zero-solid/src/use-zero-online.js +15 -0
  1165. package/out/zero-solid/src/use-zero-online.js.map +1 -0
  1166. package/out/zero-solid/src/use-zero.d.ts +24 -7
  1167. package/out/zero-solid/src/use-zero.d.ts.map +1 -1
  1168. package/out/zero-solid/src/use-zero.js +70 -0
  1169. package/out/zero-solid/src/use-zero.js.map +1 -0
  1170. package/out/zero-types/src/default-types.d.ts +38 -0
  1171. package/out/zero-types/src/default-types.d.ts.map +1 -0
  1172. package/out/zero-types/src/format.js +7 -4
  1173. package/out/zero-types/src/format.js.map +1 -1
  1174. package/out/zero-types/src/name-mapper.js +43 -40
  1175. package/out/zero-types/src/name-mapper.js.map +1 -1
  1176. package/out/zero-types/src/server-schema.d.ts.map +1 -0
  1177. package/out/zql/src/builder/builder.d.ts +10 -2
  1178. package/out/zql/src/builder/builder.d.ts.map +1 -1
  1179. package/out/zql/src/builder/builder.js +486 -427
  1180. package/out/zql/src/builder/builder.js.map +1 -1
  1181. package/out/zql/src/builder/debug-delegate.d.ts +4 -0
  1182. package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
  1183. package/out/zql/src/builder/debug-delegate.js +68 -47
  1184. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  1185. package/out/zql/src/builder/filter.js +132 -138
  1186. package/out/zql/src/builder/filter.js.map +1 -1
  1187. package/out/zql/src/builder/like.js +44 -51
  1188. package/out/zql/src/builder/like.js.map +1 -1
  1189. package/out/zql/src/error.d.ts +5 -0
  1190. package/out/zql/src/error.d.ts.map +1 -1
  1191. package/out/zql/src/error.js +18 -6
  1192. package/out/zql/src/error.js.map +1 -1
  1193. package/out/zql/src/ivm/array-view.js +86 -92
  1194. package/out/zql/src/ivm/array-view.js.map +1 -1
  1195. package/out/zql/src/ivm/constraint.js +74 -127
  1196. package/out/zql/src/ivm/constraint.js.map +1 -1
  1197. package/out/zql/src/ivm/data.js +59 -85
  1198. package/out/zql/src/ivm/data.js.map +1 -1
  1199. package/out/zql/src/ivm/exists.js +236 -243
  1200. package/out/zql/src/ivm/exists.js.map +1 -1
  1201. package/out/zql/src/ivm/fan-in.js +50 -51
  1202. package/out/zql/src/ivm/fan-in.js.map +1 -1
  1203. package/out/zql/src/ivm/fan-out.js +48 -50
  1204. package/out/zql/src/ivm/fan-out.js.map +1 -1
  1205. package/out/zql/src/ivm/filter-operators.js +87 -87
  1206. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  1207. package/out/zql/src/ivm/filter-push.js +26 -23
  1208. package/out/zql/src/ivm/filter-push.js.map +1 -1
  1209. package/out/zql/src/ivm/filter.js +30 -32
  1210. package/out/zql/src/ivm/filter.js.map +1 -1
  1211. package/out/zql/src/ivm/flipped-join.js +343 -326
  1212. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  1213. package/out/zql/src/ivm/join-utils.js +85 -79
  1214. package/out/zql/src/ivm/join-utils.js.map +1 -1
  1215. package/out/zql/src/ivm/join.js +287 -207
  1216. package/out/zql/src/ivm/join.js.map +1 -1
  1217. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +26 -24
  1218. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  1219. package/out/zql/src/ivm/memory-source.d.ts +2 -2
  1220. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  1221. package/out/zql/src/ivm/memory-source.js +471 -489
  1222. package/out/zql/src/ivm/memory-source.js.map +1 -1
  1223. package/out/zql/src/ivm/memory-storage.js +32 -31
  1224. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  1225. package/out/zql/src/ivm/operator.js +8 -9
  1226. package/out/zql/src/ivm/operator.js.map +1 -1
  1227. package/out/zql/src/ivm/push-accumulated.js +236 -305
  1228. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  1229. package/out/zql/src/ivm/skip.js +92 -106
  1230. package/out/zql/src/ivm/skip.js.map +1 -1
  1231. package/out/zql/src/ivm/source.d.ts +3 -1
  1232. package/out/zql/src/ivm/source.d.ts.map +1 -1
  1233. package/out/zql/src/ivm/stream.js +20 -16
  1234. package/out/zql/src/ivm/stream.js.map +1 -1
  1235. package/out/zql/src/ivm/take.js +502 -456
  1236. package/out/zql/src/ivm/take.js.map +1 -1
  1237. package/out/zql/src/ivm/union-fan-in.js +156 -134
  1238. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  1239. package/out/zql/src/ivm/union-fan-out.js +46 -45
  1240. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  1241. package/out/zql/src/ivm/view-apply-change.js +246 -216
  1242. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  1243. package/out/zql/src/ivm/view.d.ts +3 -2
  1244. package/out/zql/src/ivm/view.d.ts.map +1 -1
  1245. package/out/zql/src/mutate/custom.d.ts +26 -11
  1246. package/out/zql/src/mutate/custom.d.ts.map +1 -1
  1247. package/out/zql/src/mutate/custom.js +15 -7
  1248. package/out/zql/src/mutate/custom.js.map +1 -1
  1249. package/out/zql/src/mutate/mutator-registry.d.ts +93 -0
  1250. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -0
  1251. package/out/zql/src/mutate/mutator-registry.js +93 -0
  1252. package/out/zql/src/mutate/mutator-registry.js.map +1 -0
  1253. package/out/zql/src/mutate/mutator.d.ts +79 -0
  1254. package/out/zql/src/mutate/mutator.d.ts.map +1 -0
  1255. package/out/zql/src/mutate/mutator.js +31 -0
  1256. package/out/zql/src/mutate/mutator.js.map +1 -0
  1257. package/out/zql/src/planner/planner-builder.d.ts +2 -1
  1258. package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
  1259. package/out/zql/src/planner/planner-builder.js +237 -146
  1260. package/out/zql/src/planner/planner-builder.js.map +1 -1
  1261. package/out/zql/src/planner/planner-connection.d.ts +19 -14
  1262. package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
  1263. package/out/zql/src/planner/planner-connection.js +205 -291
  1264. package/out/zql/src/planner/planner-connection.js.map +1 -1
  1265. package/out/zql/src/planner/planner-constraint.js +8 -11
  1266. package/out/zql/src/planner/planner-constraint.js.map +1 -1
  1267. package/out/zql/src/planner/planner-debug.d.ts +62 -37
  1268. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  1269. package/out/zql/src/planner/planner-debug.js +234 -117
  1270. package/out/zql/src/planner/planner-debug.js.map +1 -1
  1271. package/out/zql/src/planner/planner-fan-in.d.ts +5 -3
  1272. package/out/zql/src/planner/planner-fan-in.d.ts.map +1 -1
  1273. package/out/zql/src/planner/planner-fan-in.js +157 -141
  1274. package/out/zql/src/planner/planner-fan-in.js.map +1 -1
  1275. package/out/zql/src/planner/planner-fan-out.d.ts +5 -3
  1276. package/out/zql/src/planner/planner-fan-out.d.ts.map +1 -1
  1277. package/out/zql/src/planner/planner-fan-out.js +73 -42
  1278. package/out/zql/src/planner/planner-fan-out.js.map +1 -1
  1279. package/out/zql/src/planner/planner-graph.d.ts +9 -10
  1280. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  1281. package/out/zql/src/planner/planner-graph.js +323 -388
  1282. package/out/zql/src/planner/planner-graph.js.map +1 -1
  1283. package/out/zql/src/planner/planner-join.d.ts +67 -8
  1284. package/out/zql/src/planner/planner-join.d.ts.map +1 -1
  1285. package/out/zql/src/planner/planner-join.js +239 -241
  1286. package/out/zql/src/planner/planner-join.js.map +1 -1
  1287. package/out/zql/src/planner/planner-node.d.ts +35 -3
  1288. package/out/zql/src/planner/planner-node.d.ts.map +1 -1
  1289. package/out/zql/src/planner/planner-node.js +8 -2
  1290. package/out/zql/src/planner/planner-node.js.map +1 -1
  1291. package/out/zql/src/planner/planner-source.d.ts +1 -1
  1292. package/out/zql/src/planner/planner-source.d.ts.map +1 -1
  1293. package/out/zql/src/planner/planner-source.js +23 -12
  1294. package/out/zql/src/planner/planner-source.js.map +1 -1
  1295. package/out/zql/src/planner/planner-terminus.d.ts +4 -3
  1296. package/out/zql/src/planner/planner-terminus.d.ts.map +1 -1
  1297. package/out/zql/src/planner/planner-terminus.js +28 -27
  1298. package/out/zql/src/planner/planner-terminus.js.map +1 -1
  1299. package/out/zql/src/query/complete-ordering.d.ts +5 -0
  1300. package/out/zql/src/query/complete-ordering.d.ts.map +1 -0
  1301. package/out/zql/src/query/complete-ordering.js +71 -0
  1302. package/out/zql/src/query/complete-ordering.js.map +1 -0
  1303. package/out/zql/src/query/create-builder.d.ts +7 -0
  1304. package/out/zql/src/query/create-builder.d.ts.map +1 -0
  1305. package/out/zql/src/query/create-builder.js +44 -0
  1306. package/out/zql/src/query/create-builder.js.map +1 -0
  1307. package/out/zql/src/query/error.d.ts +4 -0
  1308. package/out/zql/src/query/error.d.ts.map +1 -0
  1309. package/out/zql/src/query/error.js +13 -0
  1310. package/out/zql/src/query/error.js.map +1 -0
  1311. package/out/zql/src/query/escape-like.js +7 -0
  1312. package/out/zql/src/query/escape-like.js.map +1 -0
  1313. package/out/zql/src/query/expression.d.ts +5 -5
  1314. package/out/zql/src/query/expression.d.ts.map +1 -1
  1315. package/out/zql/src/query/expression.js +153 -151
  1316. package/out/zql/src/query/expression.js.map +1 -1
  1317. package/out/zql/src/query/measure-push-operator.js +42 -35
  1318. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  1319. package/out/zql/src/query/metrics-delegate.js +9 -5
  1320. package/out/zql/src/query/metrics-delegate.js.map +1 -1
  1321. package/out/zql/src/query/named.d.ts +21 -12
  1322. package/out/zql/src/query/named.d.ts.map +1 -1
  1323. package/out/zql/src/query/named.js +47 -57
  1324. package/out/zql/src/query/named.js.map +1 -1
  1325. package/out/zql/src/query/query-delegate-base.d.ts +114 -0
  1326. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -0
  1327. package/out/zql/src/query/query-delegate-base.js +120 -0
  1328. package/out/zql/src/query/query-delegate-base.js.map +1 -0
  1329. package/out/zql/src/query/query-delegate.d.ts +27 -4
  1330. package/out/zql/src/query/query-delegate.d.ts.map +1 -1
  1331. package/out/zql/src/query/query-impl.d.ts +28 -49
  1332. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  1333. package/out/zql/src/query/query-impl.js +514 -453
  1334. package/out/zql/src/query/query-impl.js.map +1 -1
  1335. package/out/zql/src/query/query-internals.d.ts +68 -0
  1336. package/out/zql/src/query/query-internals.d.ts.map +1 -0
  1337. package/out/zql/src/query/query-internals.js +11 -0
  1338. package/out/zql/src/query/query-internals.js.map +1 -0
  1339. package/out/zql/src/query/query-registry.d.ts +163 -0
  1340. package/out/zql/src/query/query-registry.d.ts.map +1 -0
  1341. package/out/zql/src/query/query-registry.js +123 -0
  1342. package/out/zql/src/query/query-registry.js.map +1 -0
  1343. package/out/zql/src/query/query.d.ts +54 -250
  1344. package/out/zql/src/query/query.d.ts.map +1 -1
  1345. package/out/zql/src/query/schema-query.d.ts +6 -0
  1346. package/out/zql/src/query/schema-query.d.ts.map +1 -0
  1347. package/out/zql/src/query/static-query.d.ts +6 -15
  1348. package/out/zql/src/query/static-query.d.ts.map +1 -1
  1349. package/out/zql/src/query/static-query.js +44 -31
  1350. package/out/zql/src/query/static-query.js.map +1 -1
  1351. package/out/zql/src/query/ttl.js +69 -62
  1352. package/out/zql/src/query/ttl.js.map +1 -1
  1353. package/out/zql/src/query/validate-input.d.ts +15 -0
  1354. package/out/zql/src/query/validate-input.d.ts.map +1 -0
  1355. package/out/zql/src/query/validate-input.js +24 -0
  1356. package/out/zql/src/query/validate-input.js.map +1 -0
  1357. package/out/zqlite/src/database-storage.d.ts +1 -1
  1358. package/out/zqlite/src/database-storage.d.ts.map +1 -1
  1359. package/out/zqlite/src/database-storage.js +99 -102
  1360. package/out/zqlite/src/database-storage.js.map +1 -1
  1361. package/out/zqlite/src/db.d.ts +2 -1
  1362. package/out/zqlite/src/db.d.ts.map +1 -1
  1363. package/out/zqlite/src/db.js +241 -192
  1364. package/out/zqlite/src/db.js.map +1 -1
  1365. package/out/zqlite/src/explain-queries.js +13 -16
  1366. package/out/zqlite/src/explain-queries.js.map +1 -1
  1367. package/out/zqlite/src/internal/sql.js +15 -10
  1368. package/out/zqlite/src/internal/sql.js.map +1 -1
  1369. package/out/zqlite/src/internal/statement-cache.js +86 -110
  1370. package/out/zqlite/src/internal/statement-cache.js.map +1 -1
  1371. package/out/zqlite/src/query-builder.js +172 -143
  1372. package/out/zqlite/src/query-builder.js.map +1 -1
  1373. package/out/zqlite/src/query-delegate.d.ts +5 -19
  1374. package/out/zqlite/src/query-delegate.d.ts.map +1 -1
  1375. package/out/zqlite/src/query-delegate.js +56 -70
  1376. package/out/zqlite/src/query-delegate.js.map +1 -1
  1377. package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
  1378. package/out/zqlite/src/sqlite-cost-model.js +96 -120
  1379. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  1380. package/out/zqlite/src/sqlite-stat-fanout.d.ts +121 -0
  1381. package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -0
  1382. package/out/zqlite/src/sqlite-stat-fanout.js +301 -0
  1383. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -0
  1384. package/out/zqlite/src/table-source.d.ts +9 -4
  1385. package/out/zqlite/src/table-source.d.ts.map +1 -1
  1386. package/out/zqlite/src/table-source.js +424 -311
  1387. package/out/zqlite/src/table-source.js.map +1 -1
  1388. package/package.json +27 -27
  1389. package/out/chunk-424PT5DM.js +0 -23
  1390. package/out/chunk-424PT5DM.js.map +0 -7
  1391. package/out/chunk-55BOUNXO.js.map +0 -7
  1392. package/out/chunk-AFADJQ2O.js +0 -1
  1393. package/out/chunk-AFADJQ2O.js.map +0 -7
  1394. package/out/chunk-AIPM77UE.js +0 -18139
  1395. package/out/chunk-AIPM77UE.js.map +0 -7
  1396. package/out/chunk-ASRS2LFV.js.map +0 -7
  1397. package/out/chunk-ECUMGQGC.js.map +0 -7
  1398. package/out/chunk-EZM3XBAB.js.map +0 -7
  1399. package/out/chunk-TJFNGO7E.js +0 -4126
  1400. package/out/chunk-TJFNGO7E.js.map +0 -7
  1401. package/out/chunk-VZOYWIRW.js.map +0 -7
  1402. package/out/chunk-ZZXMKAAG.js.map +0 -7
  1403. package/out/expo-sqlite.js +0 -11
  1404. package/out/expo-sqlite.js.map +0 -7
  1405. package/out/inspector-IU2HG74I.js.map +0 -7
  1406. package/out/lazy-inspector-OXIFYSSQ.js +0 -574
  1407. package/out/lazy-inspector-OXIFYSSQ.js.map +0 -7
  1408. package/out/op-sqlite.js.map +0 -7
  1409. package/out/react-native.js +0 -25
  1410. package/out/react-native.js.map +0 -7
  1411. package/out/react.js +0 -460
  1412. package/out/react.js.map +0 -7
  1413. package/out/shared/src/enum.js +0 -2
  1414. package/out/shared/src/enum.js.map +0 -1
  1415. package/out/shared/src/expand.js +0 -2
  1416. package/out/shared/src/expand.js.map +0 -1
  1417. package/out/shared/src/immutable.js +0 -2
  1418. package/out/shared/src/immutable.js.map +0 -1
  1419. package/out/shared/src/types.js +0 -2
  1420. package/out/shared/src/types.js.map +0 -1
  1421. package/out/shared/src/writable.js +0 -2
  1422. package/out/shared/src/writable.js.map +0 -1
  1423. package/out/solid.js.map +0 -7
  1424. package/out/sqlite.js +0 -15
  1425. package/out/sqlite.js.map +0 -7
  1426. package/out/zero/package.json +0 -193
  1427. package/out/zero/src/server/change-streamer.js +0 -2
  1428. package/out/zero/src/server/change-streamer.js.map +0 -1
  1429. package/out/zero/src/server/main.js +0 -2
  1430. package/out/zero/src/server/main.js.map +0 -1
  1431. package/out/zero/src/server/reaper.js +0 -2
  1432. package/out/zero/src/server/reaper.js.map +0 -1
  1433. package/out/zero/src/server/replicator.js +0 -2
  1434. package/out/zero/src/server/replicator.js.map +0 -1
  1435. package/out/zero/src/server/runner/main.js +0 -2
  1436. package/out/zero/src/server/runner/main.js.map +0 -1
  1437. package/out/zero/src/server/syncer.js +0 -2
  1438. package/out/zero/src/server/syncer.js.map +0 -1
  1439. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.js +0 -4
  1440. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.js.map +0 -1
  1441. package/out/zero-cache/src/services/change-source/protocol/mod.js +0 -5
  1442. package/out/zero-cache/src/services/change-source/protocol/mod.js.map +0 -1
  1443. package/out/zero-cache/src/services/service.js +0 -2
  1444. package/out/zero-cache/src/services/service.js.map +0 -1
  1445. package/out/zero-cache/src/services/view-syncer/key-columns.d.ts +0 -32
  1446. package/out/zero-cache/src/services/view-syncer/key-columns.d.ts.map +0 -1
  1447. package/out/zero-cache/src/services/view-syncer/key-columns.js +0 -75
  1448. package/out/zero-cache/src/services/view-syncer/key-columns.js.map +0 -1
  1449. package/out/zero-cache/src/types/satisfies.js +0 -2
  1450. package/out/zero-cache/src/types/satisfies.js.map +0 -1
  1451. package/out/zero-client/src/client/on-error.d.ts +0 -15
  1452. package/out/zero-client/src/client/on-error.d.ts.map +0 -1
  1453. package/out/zero-client/src/client/zero-log-context.d.ts +0 -7
  1454. package/out/zero-client/src/client/zero-log-context.d.ts.map +0 -1
  1455. package/out/zero-events/src/index.js +0 -2
  1456. package/out/zero-events/src/index.js.map +0 -1
  1457. package/out/zero-events/src/json.js +0 -2
  1458. package/out/zero-events/src/json.js.map +0 -1
  1459. package/out/zero-events/src/status.js +0 -3
  1460. package/out/zero-events/src/status.js.map +0 -1
  1461. package/out/zero-pg/src/mod.js +0 -6
  1462. package/out/zero-pg/src/mod.js.map +0 -1
  1463. package/out/zero-protocol/src/error-kind.js +0 -3
  1464. package/out/zero-protocol/src/error-kind.js.map +0 -1
  1465. package/out/zero-protocol/src/error-origin.js +0 -3
  1466. package/out/zero-protocol/src/error-origin.js.map +0 -1
  1467. package/out/zero-protocol/src/error-reason.js +0 -3
  1468. package/out/zero-protocol/src/error-reason.js.map +0 -1
  1469. package/out/zero-schema/src/server-schema.d.ts.map +0 -1
  1470. package/out/zero-schema/src/server-schema.js +0 -2
  1471. package/out/zero-schema/src/server-schema.js.map +0 -1
  1472. package/out/zero-schema/src/table-schema.js +0 -7
  1473. package/out/zero-schema/src/table-schema.js.map +0 -1
  1474. package/out/zero-server/src/mod.js +0 -8
  1475. package/out/zero-server/src/mod.js.map +0 -1
  1476. package/out/zero-server/src/query.d.ts +0 -22
  1477. package/out/zero-server/src/query.d.ts.map +0 -1
  1478. package/out/zero-server/src/query.js +0 -61
  1479. package/out/zero-server/src/query.js.map +0 -1
  1480. package/out/zero-types/src/schema-value.js +0 -2
  1481. package/out/zero-types/src/schema-value.js.map +0 -1
  1482. package/out/zero-types/src/schema.js +0 -2
  1483. package/out/zero-types/src/schema.js.map +0 -1
  1484. package/out/zero.js +0 -79
  1485. package/out/zero.js.map +0 -7
  1486. package/out/zql/src/ivm/change.js +0 -2
  1487. package/out/zql/src/ivm/change.js.map +0 -1
  1488. package/out/zql/src/ivm/default-format.js +0 -2
  1489. package/out/zql/src/ivm/default-format.js.map +0 -1
  1490. package/out/zql/src/ivm/schema.js +0 -2
  1491. package/out/zql/src/ivm/schema.js.map +0 -1
  1492. package/out/zql/src/ivm/source.js +0 -2
  1493. package/out/zql/src/ivm/source.js.map +0 -1
  1494. package/out/zql/src/ivm/view.js +0 -2
  1495. package/out/zql/src/ivm/view.js.map +0 -1
  1496. package/out/zql/src/query/query-delegate.js +0 -2
  1497. package/out/zql/src/query/query-delegate.js.map +0 -1
  1498. package/out/zql/src/query/query.js +0 -9
  1499. package/out/zql/src/query/query.js.map +0 -1
  1500. package/out/zql/src/query/typed-view.js +0 -2
  1501. package/out/zql/src/query/typed-view.js.map +0 -1
  1502. package/out/zqlite/src/mod.js +0 -5
  1503. package/out/zqlite/src/mod.js.map +0 -1
  1504. /package/out/{zero-schema → zero-types}/src/server-schema.d.ts +0 -0
@@ -1,1371 +1,1595 @@
1
- import { trace } from '@opentelemetry/api';
2
- import { Lock } from '@rocicorp/lock';
3
- import { resolver } from '@rocicorp/resolver';
4
- import { manualSpan, startAsyncSpan, startSpan, } from "../../../../otel/src/span.js";
1
+ import { trace } from "@opentelemetry/api";
2
+ import { Lock } from "@rocicorp/lock";
3
+ import { resolver } from "@rocicorp/resolver";
4
+ import { startSpan, startAsyncSpan, manualSpan } from "../../../../otel/src/span.js";
5
5
  import { version } from "../../../../otel/src/version.js";
6
6
  import { assert, unreachable } from "../../../../shared/src/asserts.js";
7
7
  import { stringify } from "../../../../shared/src/bigint-json.js";
8
8
  import { CustomKeyMap } from "../../../../shared/src/custom-key-map.js";
9
- import { wrapIterable } from "../../../../shared/src/iterables.js";
10
9
  import { must } from "../../../../shared/src/must.js";
11
10
  import { randInt } from "../../../../shared/src/rand.js";
12
- import { ErrorKind } from "../../../../zero-protocol/src/error-kind.js";
13
- import { ErrorOrigin } from "../../../../zero-protocol/src/error-origin.js";
14
- import { ProtocolError, } from "../../../../zero-protocol/src/error.js";
11
+ import { Rehome, ClientNotFound, InvalidConnectionRequest, TransformFailed, Unauthorized, InvalidConnectionRequestBaseCookie } from "../../../../zero-protocol/src/error-kind-enum.js";
12
+ import { ZeroCache } from "../../../../zero-protocol/src/error-origin-enum.js";
13
+ import { ProtocolError } from "../../../../zero-protocol/src/error.js";
15
14
  import { clampTTL, MAX_TTL_MS } from "../../../../zql/src/query/ttl.js";
16
- import { transformAndHashQuery, } from "../../auth/read-authorizer.js";
17
- import { CustomQueryTransformer } from "../../custom-queries/transform-query.js";
18
- import { getOrCreateCounter, getOrCreateHistogram, getOrCreateUpDownCounter, } from "../../observability/metrics.js";
19
- import { InspectorDelegate } from "../../server/inspector-delegate.js";
20
- import { getLogLevel, ProtocolErrorWithLevel, } from "../../types/error-with-level.js";
15
+ import { transformAndHashQuery } from "../../auth/read-authorizer.js";
16
+ import { getOrCreateUpDownCounter, getOrCreateCounter, getOrCreateHistogram } from "../../observability/metrics.js";
17
+ import { ProtocolErrorWithLevel, getLogLevel } from "../../types/error-with-level.js";
21
18
  import { rowIDString } from "../../types/row-key.js";
22
19
  import { Subscription } from "../../types/subscription.js";
23
- import { ZERO_VERSION_COLUMN_NAME } from "../replicator/schema/replication-state.js";
24
- import { ClientHandler, startPoke, } from "./client-handler.js";
20
+ import "../replicator/schema/replication-state.js";
21
+ import { startPoke, ClientHandler } from "./client-handler.js";
25
22
  import { CVRStore } from "./cvr-store.js";
26
- import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, CVRUpdater, nextEvictionTime, } from "./cvr.js";
23
+ import { CVRConfigDrivenUpdater, nextEvictionTime, CVRQueryDrivenUpdater } from "./cvr.js";
27
24
  import { handleInspect } from "./inspect-handler.js";
28
- import { PipelineDriver } from "./pipeline-driver.js";
29
- import { cmpVersions, EMPTY_CVR_VERSION, versionFromString, versionString, versionToCookie, } from "./schema/types.js";
25
+ import "../../../../shared/src/config.js";
26
+ import "compare-utf8";
27
+ import "../../../../zero-protocol/src/ast.js";
28
+ import "../../../../zero-protocol/src/data.js";
29
+ import "@rocicorp/zero-sqlite3";
30
+ import "../../../../zqlite/src/internal/sql.js";
31
+ import "../../../../shared/src/btree-set.js";
32
+ import "../../../../shared/src/valita.js";
33
+ import "../../../../zero-schema/src/compiled-permissions.js";
34
+ import "../../../../zero-protocol/src/primary-key.js";
35
+ import { ZERO_VERSION_COLUMN_NAME } from "../replicator/schema/constants.js";
36
+ import "../../types/pg-data-type.js";
37
+ import "../../db/specs.js";
30
38
  import { ResetPipelinesSignal } from "./snapshotter.js";
31
- import { ttlClockAsNumber, ttlClockFromNumber, } from "./ttl-clock.js";
32
- const tracer = trace.getTracer('view-syncer', version);
33
- const PROTOCOL_VERSION_ATTR = 'protocol.version';
34
- const DEFAULT_KEEPALIVE_MS = 5_000;
39
+ import { versionString, cmpVersions, EMPTY_CVR_VERSION, versionToCookie, versionFromString } from "./schema/types.js";
40
+ import { ttlClockFromNumber, ttlClockAsNumber } from "./ttl-clock.js";
41
+ const tracer = trace.getTracer("view-syncer", version);
42
+ const PROTOCOL_VERSION_ATTR = "protocol.version";
43
+ const DEFAULT_KEEPALIVE_MS = 5e3;
35
44
  function randomID() {
36
- return randInt(1, Number.MAX_SAFE_INTEGER).toString(36);
45
+ return randInt(1, Number.MAX_SAFE_INTEGER).toString(36);
37
46
  }
38
- /**
39
- * We update the ttlClock in flush that writes to the CVR but
40
- * some flushes do not write to the CVR and in those cases we
41
- * use a timer to update the ttlClock every minute.
42
- */
43
- export const TTL_CLOCK_INTERVAL = 60_000;
44
- /**
45
- * This is some extra time we delay the TTL timer to allow for some
46
- * slack in the timing of the timer. This is to allow multiple evictions
47
- * to happen in a short period of time without having to wait for the
48
- * next tick of the timer.
49
- */
50
- export const TTL_TIMER_HYSTERESIS = 50; // ms
51
- export class ViewSyncerService {
52
- id;
53
- #shard;
54
- #lc;
55
- #pipelines;
56
- #stateChanges;
57
- #drainCoordinator;
58
- #keepaliveMs;
59
- #slowHydrateThreshold;
60
- #queryConfig;
61
- userQueryURL;
62
- // The ViewSyncerService is only started in response to a connection,
63
- // so #lastConnectTime is always initialized to now(). This is necessary
64
- // to handle race conditions in which, e.g. the replica is ready and the
65
- // CVR is accessed before the first connection sends a request.
66
- //
67
- // Note: It is fine to update this variable outside of the lock.
68
- #lastConnectTime = Date.now();
69
- /**
70
- * The TTL clock is used to determine the time at which queries are considered
71
- * expired.
72
- */
73
- #ttlClock;
74
- /**
75
- * The base time for the TTL clock. This is used to compute the current TTL
76
- * clock value. The first time a connection is made, this is set to the
77
- * current time. On subsequent connections, the TTL clock is computed as the
78
- * difference between the current time and this base time.
79
- *
80
- * Every time we write the ttlClock this is update to the current time. That
81
- * way we can compute how much time has passed since the last time we set the
82
- * ttlClock. When we set the ttlClock we just increment it by the amount of
83
- * time that has passed since the last time we set it.
84
- */
85
- #ttlClockBase = Date.now();
86
- /**
87
- * We update the ttlClock every minute to ensure that it is not too much
88
- * out of sync with the current time.
89
- */
90
- #ttlClockInterval = 0;
91
- // Note: It is okay to add/remove clients without acquiring the lock.
92
- #clients = new Map();
93
- // Serialize on this lock for:
94
- // (1) storage or database-dependent operations
95
- // (2) updating member variables.
96
- #lock = new Lock();
97
- #cvrStore;
98
- #stopped = resolver();
99
- #cvr;
100
- #pipelinesSynced = false;
101
- // DEPRECATED: remove `authData` in favor of forwarding
102
- // auth and cookie headers directly
103
- #authData;
104
- // Not sure why lint can't see that this is used?
105
- // oxlint-disable-next-line no-unused-private-class-members
106
- #httpCookie;
107
- #expiredQueriesTimer = 0;
108
- #setTimeout;
109
- #customQueryTransformer;
110
- #activeClients = getOrCreateUpDownCounter('sync', 'active-clients', 'Number of active sync clients');
111
- #hydrations = getOrCreateCounter('sync', 'hydration', 'Number of query hydrations');
112
- #hydrationTime = getOrCreateHistogram('sync', 'hydration-time', {
113
- description: 'Time to hydrate a query.',
114
- unit: 's',
115
- });
116
- #transactionAdvanceTime = getOrCreateHistogram('sync', 'advance-time', {
117
- description: 'Time to advance all queries for a given client group after applying a new transaction to the replica.',
118
- unit: 's',
119
- });
120
- #inspectorDelegate;
121
- #config;
122
- constructor(config, lc, shard, taskID, clientGroupID, cvrDb, upstreamDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate, customQueryTransformer, keepaliveMs = DEFAULT_KEEPALIVE_MS, setTimeoutFn = setTimeout.bind(globalThis)) {
123
- const { getQueries: pullConfig } = config;
124
- this.#config = config;
125
- this.id = clientGroupID;
126
- this.#shard = shard;
127
- this.#queryConfig = pullConfig;
128
- this.#lc = lc;
129
- this.#pipelines = pipelineDriver;
130
- this.#stateChanges = versionChanges;
131
- this.#drainCoordinator = drainCoordinator;
132
- this.#keepaliveMs = keepaliveMs;
133
- this.#slowHydrateThreshold = slowHydrateThreshold;
134
- this.#inspectorDelegate = inspectorDelegate;
135
- this.#customQueryTransformer = customQueryTransformer;
136
- this.#cvrStore = new CVRStore(lc, cvrDb, upstreamDb, shard, taskID, clientGroupID,
137
- // On failure, cancel the #stateChanges subscription. The run()
138
- // loop will then await #cvrStore.flushed() which rejects if necessary.
139
- () => this.#stateChanges.cancel());
140
- this.#setTimeout = setTimeoutFn;
141
- // Wait for the first connection to init.
142
- this.keepalive();
47
+ const TTL_CLOCK_INTERVAL = 6e4;
48
+ const TTL_TIMER_HYSTERESIS = 50;
49
+ class ViewSyncerService {
50
+ id;
51
+ #shard;
52
+ #lc;
53
+ #pipelines;
54
+ #stateChanges;
55
+ #drainCoordinator;
56
+ #keepaliveMs;
57
+ #slowHydrateThreshold;
58
+ #queryConfig;
59
+ userQueryURL;
60
+ // The ViewSyncerService is only started in response to a connection,
61
+ // so #lastConnectTime is always initialized to now(). This is necessary
62
+ // to handle race conditions in which, e.g. the replica is ready and the
63
+ // CVR is accessed before the first connection sends a request.
64
+ //
65
+ // Note: It is fine to update this variable outside of the lock.
66
+ #lastConnectTime = Date.now();
67
+ /**
68
+ * The TTL clock is used to determine the time at which queries are considered
69
+ * expired.
70
+ */
71
+ #ttlClock;
72
+ /**
73
+ * The base time for the TTL clock. This is used to compute the current TTL
74
+ * clock value. The first time a connection is made, this is set to the
75
+ * current time. On subsequent connections, the TTL clock is computed as the
76
+ * difference between the current time and this base time.
77
+ *
78
+ * Every time we write the ttlClock this is update to the current time. That
79
+ * way we can compute how much time has passed since the last time we set the
80
+ * ttlClock. When we set the ttlClock we just increment it by the amount of
81
+ * time that has passed since the last time we set it.
82
+ */
83
+ #ttlClockBase = Date.now();
84
+ /**
85
+ * We update the ttlClock every minute to ensure that it is not too much
86
+ * out of sync with the current time.
87
+ */
88
+ #ttlClockInterval = 0;
89
+ // Note: It is okay to add/remove clients without acquiring the lock.
90
+ #clients = /* @__PURE__ */ new Map();
91
+ // Serialize on this lock for:
92
+ // (1) storage or database-dependent operations
93
+ // (2) updating member variables.
94
+ #lock = new Lock();
95
+ #cvrStore;
96
+ #stopped = resolver();
97
+ #initialized = resolver();
98
+ #cvr;
99
+ #pipelinesSynced = false;
100
+ // DEPRECATED: remove `authData` in favor of forwarding
101
+ // auth and cookie headers directly
102
+ #authData;
103
+ // Not sure why lint can't see that this is used?
104
+ // oxlint-disable-next-line no-unused-private-class-members
105
+ #httpCookie;
106
+ #expiredQueriesTimer = 0;
107
+ #setTimeout;
108
+ #customQueryTransformer;
109
+ // Track query replacements for thrashing detection
110
+ #queryReplacements = /* @__PURE__ */ new Map();
111
+ #activeClients = getOrCreateUpDownCounter(
112
+ "sync",
113
+ "active-clients",
114
+ "Number of active sync clients"
115
+ );
116
+ #hydrations = getOrCreateCounter(
117
+ "sync",
118
+ "hydration",
119
+ "Number of query hydrations"
120
+ );
121
+ #hydrationTime = getOrCreateHistogram("sync", "hydration-time", {
122
+ description: "Time to hydrate a query.",
123
+ unit: "s"
124
+ });
125
+ #transactionAdvanceTime = getOrCreateHistogram(
126
+ "sync",
127
+ "advance-time",
128
+ {
129
+ description: "Time to advance all queries for a given client group after applying a new transaction to the replica.",
130
+ unit: "s"
143
131
  }
144
- #getHeaderOptions(forwardCookie) {
145
- return {
146
- apiKey: this.#queryConfig.apiKey,
147
- token: this.#authData?.raw,
148
- cookie: forwardCookie ? this.#httpCookie : undefined,
149
- };
132
+ );
133
+ #queryTransformations = getOrCreateCounter(
134
+ "sync",
135
+ "query.transformations",
136
+ "Number of query transformations performed"
137
+ );
138
+ #queryTransformationTime = getOrCreateHistogram(
139
+ "sync",
140
+ "query.transformation-time",
141
+ {
142
+ description: "Time to transform custom queries via API server",
143
+ unit: "s"
150
144
  }
151
- #runInLockWithCVR(fn) {
152
- const rid = randomID();
153
- this.#lc.debug?.('about to acquire lock for cvr ', rid);
154
- return this.#lock.withLock(async () => {
155
- this.#lc.debug?.('acquired lock in #runInLockWithCVR ', rid);
156
- const lc = this.#lc.withContext('lock', rid);
157
- if (!this.#stateChanges.active) {
158
- // view-syncer has been shutdown. this can be a backlog of tasks
159
- // queued on the lock, or it can be a race condition in which a
160
- // client connects before the ViewSyncer has been deleted from the
161
- // ServiceRunner.
162
- this.#lc.debug?.('state changes are inactive');
163
- clearTimeout(this.#expiredQueriesTimer);
164
- throw new ProtocolErrorWithLevel({
165
- kind: ErrorKind.Rehome,
166
- message: 'Reconnect required',
167
- }, 'warn');
168
- }
169
- // If all clients have disconnected, cancel all pending work.
170
- if (await this.#checkForShutdownConditionsInLock()) {
171
- this.#lc.info?.(`closing clientGroupID=${this.id}`);
172
- this.#stateChanges.cancel(); // Note: #stateChanges.active becomes false.
173
- return;
174
- }
175
- if (!this.#cvr) {
176
- this.#lc.debug?.('loading CVR');
177
- this.#cvr = await this.#cvrStore.load(lc, this.#lastConnectTime);
178
- this.#ttlClock = this.#cvr.ttlClock;
179
- this.#ttlClockBase = Date.now();
180
- }
181
- else {
182
- // Make sure the CVR ttlClock is up to date.
183
- const now = Date.now();
184
- this.#cvr = {
185
- ...this.#cvr,
186
- ttlClock: this.#getTTLClock(now),
187
- };
188
- }
189
- try {
190
- await fn(lc, this.#cvr);
191
- }
192
- catch (e) {
193
- // Clear cached state if an error is encountered.
194
- this.#cvr = undefined;
195
- throw e;
145
+ );
146
+ #queryTransformationHashChanges = getOrCreateCounter(
147
+ "sync",
148
+ "query.transformation-hash-changes",
149
+ "Number of times query transformation hash changed"
150
+ );
151
+ #queryTransformationNoOps = getOrCreateCounter(
152
+ "sync",
153
+ "query.transformation-no-ops",
154
+ "Number of times query transformation resulted in no-op (hash unchanged)"
155
+ );
156
+ #inspectorDelegate;
157
+ #config;
158
+ constructor(config, lc, shard, taskID, clientGroupID, cvrDb, upstreamDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate, customQueryTransformer, keepaliveMs = DEFAULT_KEEPALIVE_MS, setTimeoutFn = setTimeout.bind(globalThis)) {
159
+ const queryConfig = config.query?.url ? config.query : config.getQueries;
160
+ this.#config = config;
161
+ this.id = clientGroupID;
162
+ this.#shard = shard;
163
+ this.#queryConfig = queryConfig;
164
+ this.#lc = lc;
165
+ this.#pipelines = pipelineDriver;
166
+ this.#stateChanges = versionChanges;
167
+ this.#drainCoordinator = drainCoordinator;
168
+ this.#keepaliveMs = keepaliveMs;
169
+ this.#slowHydrateThreshold = slowHydrateThreshold;
170
+ this.#inspectorDelegate = inspectorDelegate;
171
+ this.#customQueryTransformer = customQueryTransformer;
172
+ this.#cvrStore = new CVRStore(
173
+ lc,
174
+ cvrDb,
175
+ upstreamDb,
176
+ shard,
177
+ taskID,
178
+ clientGroupID,
179
+ // On failure, cancel the #stateChanges subscription. The run()
180
+ // loop will then await #cvrStore.flushed() which rejects if necessary.
181
+ () => this.#stateChanges.cancel()
182
+ );
183
+ this.#setTimeout = setTimeoutFn;
184
+ this.keepalive();
185
+ }
186
+ #getHeaderOptions(forwardCookie) {
187
+ return {
188
+ apiKey: this.#queryConfig.apiKey,
189
+ token: this.#authData?.raw,
190
+ cookie: forwardCookie ? this.#httpCookie : void 0
191
+ };
192
+ }
193
+ #runInLockWithCVR(fn) {
194
+ const rid = randomID();
195
+ this.#lc.debug?.("about to acquire lock for cvr ", rid);
196
+ return this.#lock.withLock(async () => {
197
+ this.#lc.debug?.("acquired lock in #runInLockWithCVR ", rid);
198
+ const lc = this.#lc.withContext("lock", rid);
199
+ if (!this.#stateChanges.active) {
200
+ this.#lc.debug?.("state changes are inactive");
201
+ clearTimeout(this.#expiredQueriesTimer);
202
+ throw new ProtocolErrorWithLevel({
203
+ kind: Rehome,
204
+ message: "Reconnect required",
205
+ origin: ZeroCache
206
+ });
207
+ }
208
+ if (await this.#checkForShutdownConditionsInLock()) {
209
+ this.#lc.info?.(`closing clientGroupID=${this.id}`);
210
+ this.#stateChanges.cancel();
211
+ return;
212
+ }
213
+ if (!this.#cvr) {
214
+ this.#lc.debug?.("loading CVR");
215
+ this.#cvr = await this.#cvrStore.load(lc, this.#lastConnectTime);
216
+ this.#ttlClock = this.#cvr.ttlClock;
217
+ this.#ttlClockBase = Date.now();
218
+ } else {
219
+ const now = Date.now();
220
+ this.#cvr = {
221
+ ...this.#cvr,
222
+ ttlClock: this.#getTTLClock(now)
223
+ };
224
+ }
225
+ try {
226
+ await fn(lc, this.#cvr);
227
+ } catch (e) {
228
+ this.#cvr = void 0;
229
+ throw e;
230
+ }
231
+ });
232
+ }
233
+ readyState() {
234
+ return Promise.race([
235
+ this.#initialized.promise,
236
+ this.#drainCoordinator.draining
237
+ ]);
238
+ }
239
+ async run() {
240
+ try {
241
+ if (await this.readyState() === "draining") {
242
+ this.#lc.debug?.(`draining view-syncer ${this.id} before running`);
243
+ void this.stop();
244
+ }
245
+ for await (const { state } of this.#stateChanges) {
246
+ if (this.#drainCoordinator.shouldDrain()) {
247
+ this.#lc.debug?.(`draining view-syncer ${this.id} (elective)`);
248
+ break;
249
+ }
250
+ assert(state === "version-ready", "state should be version-ready");
251
+ await this.#runInLockWithCVR(async (lc, cvr) => {
252
+ const clientSchema = must(
253
+ cvr.clientSchema,
254
+ "cvr.clientSchema missing after initialization"
255
+ );
256
+ if (!this.#pipelines.initialized()) {
257
+ this.#pipelines.init(clientSchema);
258
+ }
259
+ if (cvr.replicaVersion !== null && cvr.version.stateVersion !== "00" && this.#pipelines.replicaVersion < cvr.replicaVersion) {
260
+ const message = `Cannot sync from older replica: CVR=${cvr.replicaVersion}, DB=${this.#pipelines.replicaVersion}`;
261
+ lc.info?.(`resetting CVR: ${message}`);
262
+ throw new ProtocolErrorWithLevel({
263
+ kind: ClientNotFound,
264
+ message,
265
+ origin: ZeroCache
266
+ });
267
+ }
268
+ if (this.#pipelinesSynced) {
269
+ const result = await this.#advancePipelines(lc, cvr);
270
+ if (result === "success") {
271
+ return;
196
272
  }
273
+ lc.info?.(`resetting pipelines: ${result.message}`);
274
+ this.#pipelines.reset(clientSchema);
275
+ }
276
+ const version2 = this.#pipelines.advanceWithoutDiff();
277
+ const cvrVer = versionString(cvr.version);
278
+ if (version2 < cvr.version.stateVersion) {
279
+ lc.debug?.(`replica@${version2} is behind cvr@${cvrVer}`);
280
+ return;
281
+ }
282
+ lc.info?.(`init pipelines@${version2} (cvr@${cvrVer})`);
283
+ await this.#hydrateUnchangedQueries(lc, cvr);
284
+ await this.#syncQueryPipelineSet(lc, cvr);
285
+ this.#pipelinesSynced = true;
197
286
  });
287
+ }
288
+ if (this.#drainCoordinator.shouldDrain()) {
289
+ this.#drainCoordinator.drainNextIn(this.#totalHydrationTimeMs());
290
+ }
291
+ this.#cleanup();
292
+ } catch (e) {
293
+ this.#lc[getLogLevel(e)]?.(
294
+ `stopping view-syncer ${this.id}: ${String(e)}`,
295
+ e
296
+ );
297
+ this.#cleanup(e);
298
+ } finally {
299
+ await this.#cvrStore.flushed(this.#lc).catch((e) => this.#lc[getLogLevel(e)]?.(e));
300
+ this.#lc.info?.(`view-syncer ${this.id} finished`);
301
+ this.#stopped.resolve();
198
302
  }
199
- async run() {
200
- try {
201
- for await (const { state } of this.#stateChanges) {
202
- if (this.#drainCoordinator.shouldDrain()) {
203
- this.#lc.debug?.(`draining view-syncer ${this.id} (elective)`);
204
- break;
205
- }
206
- assert(state === 'version-ready', 'state should be version-ready'); // This is the only state change used.
207
- await this.#runInLockWithCVR(async (lc, cvr) => {
208
- if (!this.#pipelines.initialized()) {
209
- // On the first version-ready signal, connect to the replica.
210
- this.#pipelines.init(cvr.clientSchema);
211
- }
212
- if (cvr.replicaVersion !== null &&
213
- cvr.version.stateVersion !== '00' &&
214
- this.#pipelines.replicaVersion < cvr.replicaVersion) {
215
- const message = `Cannot sync from older replica: CVR=${cvr.replicaVersion}, DB=${this.#pipelines.replicaVersion}`;
216
- lc.info?.(`resetting CVR: ${message}`);
217
- throw new ProtocolError({
218
- kind: ErrorKind.ClientNotFound,
219
- message,
220
- origin: ErrorOrigin.ZeroCache,
221
- });
222
- }
223
- if (this.#pipelinesSynced) {
224
- const result = await this.#advancePipelines(lc, cvr);
225
- if (result === 'success') {
226
- return;
227
- }
228
- lc.info?.(`resetting pipelines: ${result.message}`);
229
- this.#pipelines.reset(cvr.clientSchema);
230
- }
231
- // Advance the snapshot to the current version.
232
- const version = this.#pipelines.advanceWithoutDiff();
233
- const cvrVer = versionString(cvr.version);
234
- if (version < cvr.version.stateVersion) {
235
- lc.debug?.(`replica@${version} is behind cvr@${cvrVer}`);
236
- return; // Wait for the next advancement.
237
- }
238
- // stateVersion is at or beyond CVR version for the first time.
239
- lc.info?.(`init pipelines@${version} (cvr@${cvrVer})`);
240
- await this.#hydrateUnchangedQueries(lc, cvr);
241
- await this.#syncQueryPipelineSet(lc, cvr);
242
- this.#pipelinesSynced = true;
243
- });
244
- }
245
- // If this view-syncer exited due to an elective or forced drain,
246
- // set the next drain timeout.
247
- if (this.#drainCoordinator.shouldDrain()) {
248
- this.#drainCoordinator.drainNextIn(this.#totalHydrationTimeMs());
249
- }
250
- this.#cleanup();
251
- }
252
- catch (e) {
253
- this.#lc[getLogLevel(e)]?.(`stopping view-syncer: ${String(e)}`, e);
254
- this.#cleanup(e);
255
- }
256
- finally {
257
- // Always wait for the cvrStore to flush, regardless of how the service
258
- // was stopped.
259
- await this.#cvrStore
260
- .flushed(this.#lc)
261
- .catch(e => this.#lc[getLogLevel(e)]?.(e));
262
- this.#lc.info?.('view-syncer stopped');
263
- this.#stopped.resolve();
264
- }
303
+ }
304
+ // must be called from within #lock
305
+ #removeExpiredQueries = async (lc, cvr) => {
306
+ if (hasExpiredQueries(cvr)) {
307
+ lc = lc.withContext("method", "#removeExpiredQueries");
308
+ lc.debug?.("Queries have expired");
309
+ await this.#syncQueryPipelineSet(lc, cvr);
310
+ this.#pipelinesSynced = true;
265
311
  }
266
- // must be called from within #lock
267
- #removeExpiredQueries = async (lc, cvr) => {
268
- if (hasExpiredQueries(cvr)) {
269
- lc = lc.withContext('method', '#removeExpiredQueries');
270
- lc.debug?.('Queries have expired');
271
- // #syncQueryPipelineSet() will remove the expired queries.
272
- await this.#syncQueryPipelineSet(lc, cvr);
273
- this.#pipelinesSynced = true;
274
- }
275
- // Even if we have expired queries, we still need to schedule next eviction
276
- // since there might be inactivated queries that need to be expired queries
277
- // in the future.
278
- this.#scheduleExpireEviction(lc, cvr);
279
- };
280
- #totalHydrationTimeMs() {
281
- return this.#pipelines.totalHydrationTimeMs();
312
+ this.#scheduleExpireEviction(lc, cvr);
313
+ };
314
+ #totalHydrationTimeMs() {
315
+ return this.#pipelines.totalHydrationTimeMs();
316
+ }
317
+ #keepAliveUntil = 0;
318
+ /**
319
+ * Guarantees that the ViewSyncer will remain running for at least
320
+ * its configured `keepaliveMs`. This is called when establishing a
321
+ * new connection to ensure that its associated ViewSyncer isn't
322
+ * shutdown before it receives the connection.
323
+ *
324
+ * @return `true` if the ViewSyncer will stay alive, `false` if the
325
+ * ViewSyncer is shutting down.
326
+ */
327
+ keepalive() {
328
+ if (!this.#stateChanges.active) {
329
+ return false;
282
330
  }
283
- #keepAliveUntil = 0;
284
- /**
285
- * Guarantees that the ViewSyncer will remain running for at least
286
- * its configured `keepaliveMs`. This is called when establishing a
287
- * new connection to ensure that its associated ViewSyncer isn't
288
- * shutdown before it receives the connection.
289
- *
290
- * @return `true` if the ViewSyncer will stay alive, `false` if the
291
- * ViewSyncer is shutting down.
292
- */
293
- keepalive() {
294
- if (!this.#stateChanges.active) {
295
- return false;
296
- }
297
- this.#keepAliveUntil = Date.now() + this.#keepaliveMs;
298
- return true;
331
+ this.#keepAliveUntil = Date.now() + this.#keepaliveMs;
332
+ return true;
333
+ }
334
+ // oxlint-disable-next-line no-unused-private-class-members -- False positive, used in #scheduleShutdown
335
+ #shutdownTimer = null;
336
+ #scheduleShutdown(delayMs = 0) {
337
+ this.#shutdownTimer ??= this.#setTimeout(() => {
338
+ this.#shutdownTimer = null;
339
+ void this.#runInLockWithCVR(() => {
340
+ }).catch(
341
+ (e) => (
342
+ // If an error occurs (e.g. ownership change), propagate the error
343
+ // to the main run() loop via the #stateChanges Subscription.
344
+ this.#stateChanges.fail(e)
345
+ )
346
+ );
347
+ }, delayMs);
348
+ }
349
+ async #checkForShutdownConditionsInLock() {
350
+ if (this.#clients.size > 0) {
351
+ return false;
299
352
  }
300
- // oxlint-disable-next-line no-unused-private-class-members -- False positive, used in #scheduleShutdown
301
- #shutdownTimer = null;
302
- #scheduleShutdown(delayMs = 0) {
303
- this.#shutdownTimer ??= this.#setTimeout(() => {
304
- this.#shutdownTimer = null;
305
- // All lock tasks check for shutdown so that queued work is immediately
306
- // canceled when clients disconnect. Queue an empty task to ensure that
307
- // this check happens.
308
- void this.#runInLockWithCVR(() => { }).catch(e =>
309
- // If an error occurs (e.g. ownership change), propagate the error
310
- // to the main run() loop via the #stateChanges Subscription.
311
- this.#stateChanges.fail(e));
312
- }, delayMs);
353
+ await this.#cvrStore.flushed(this.#lc);
354
+ if (Date.now() <= this.#keepAliveUntil) {
355
+ this.#scheduleShutdown(this.#keepaliveMs);
356
+ return false;
313
357
  }
314
- async #checkForShutdownConditionsInLock() {
315
- if (this.#clients.size > 0) {
316
- return false; // common case.
317
- }
318
- // Keep the view-syncer alive if there are pending rows being flushed.
319
- // It's better to do this before shutting down since it may take a
320
- // while, during which new connections may come in.
321
- await this.#cvrStore.flushed(this.#lc);
322
- if (Date.now() <= this.#keepAliveUntil) {
323
- this.#scheduleShutdown(this.#keepaliveMs); // check again later
324
- return false;
358
+ return this.#clients.size === 0;
359
+ }
360
+ #deleteClientDueToDisconnect(clientID, client) {
361
+ const c = this.#clients.get(clientID);
362
+ if (c === client) {
363
+ this.#clients.delete(clientID);
364
+ if (this.#clients.size === 0) {
365
+ if (this.#ttlClock !== void 0) {
366
+ this.#updateTTLClockInCVRWithoutLock(this.#lc);
325
367
  }
326
- // If no clients have connected while waiting for the row flush, shutdown.
327
- return this.#clients.size === 0;
368
+ this.#stopExpireTimer();
369
+ this.#scheduleShutdown();
370
+ }
328
371
  }
329
- #deleteClientDueToDisconnect(clientID, client) {
330
- // Note: It is okay to delete / cleanup clients without acquiring the lock.
331
- // In fact, it is important to do so in order to guarantee that idle cleanup
332
- // is performed in a timely manner, regardless of the amount of work
333
- // queued on the lock.
334
- const c = this.#clients.get(clientID);
335
- if (c === client) {
336
- this.#clients.delete(clientID);
337
- if (this.#clients.size === 0) {
338
- // It is possible to delete a client before we read the ttl clock from
339
- // the CVR.
340
- if (this.#ttlClock !== undefined) {
341
- this.#updateTTLClockInCVRWithoutLock(this.#lc);
342
- }
343
- this.#stopExpireTimer();
344
- this.#scheduleShutdown();
372
+ }
373
+ #stopExpireTimer() {
374
+ this.#lc.debug?.("Stopping expired queries timer");
375
+ clearTimeout(this.#expiredQueriesTimer);
376
+ this.#expiredQueriesTimer = 0;
377
+ }
378
+ initConnection(ctx, initConnectionMessage) {
379
+ this.#lc.debug?.("viewSyncer.initConnection");
380
+ return startSpan(tracer, "vs.initConnection", () => {
381
+ const {
382
+ clientID,
383
+ wsID,
384
+ baseCookie,
385
+ schemaVersion,
386
+ tokenData,
387
+ httpCookie,
388
+ protocolVersion
389
+ } = ctx;
390
+ this.#authData = pickToken(this.#lc, this.#authData, tokenData);
391
+ this.#lc.debug?.(
392
+ `Picked auth token: ${JSON.stringify(this.#authData?.decoded)}`
393
+ );
394
+ this.#httpCookie = httpCookie;
395
+ const [, { userQueryURL }] = initConnectionMessage;
396
+ if (this.userQueryURL === void 0) {
397
+ this.userQueryURL = userQueryURL;
398
+ } else {
399
+ if (this.userQueryURL !== userQueryURL) {
400
+ this.#lc.warn?.(
401
+ "Client provided different query parameters than client group",
402
+ {
403
+ clientID,
404
+ clientURL: userQueryURL,
405
+ clientGroupURL: this.userQueryURL
345
406
  }
407
+ );
408
+ }
409
+ }
410
+ const lc = this.#lc.withContext("clientID", clientID).withContext("wsID", wsID);
411
+ const downstream = Subscription.create({
412
+ cleanup: (_, err) => {
413
+ err ? lc[getLogLevel(err)]?.(`client closed with error`, err) : lc.info?.("client closed");
414
+ this.#deleteClientDueToDisconnect(clientID, newClient);
415
+ this.#activeClients.add(-1, {
416
+ [PROTOCOL_VERSION_ATTR]: protocolVersion
417
+ });
346
418
  }
419
+ });
420
+ this.#activeClients.add(1, {
421
+ [PROTOCOL_VERSION_ATTR]: protocolVersion
422
+ });
423
+ if (this.#clients.size === 0) {
424
+ const now = Date.now();
425
+ this.#ttlClockBase = now;
426
+ }
427
+ const newClient = new ClientHandler(
428
+ lc,
429
+ this.id,
430
+ clientID,
431
+ wsID,
432
+ this.#shard,
433
+ baseCookie,
434
+ schemaVersion,
435
+ downstream
436
+ );
437
+ this.#clients.get(clientID)?.close(`replaced by wsID: ${wsID}`);
438
+ this.#clients.set(clientID, newClient);
439
+ void this.#runInLockForClient(
440
+ ctx,
441
+ initConnectionMessage,
442
+ async (lc2, clientID2, msg, cvr) => {
443
+ if (cvr.clientSchema === null && !msg.clientSchema) {
444
+ throw new ProtocolErrorWithLevel({
445
+ kind: InvalidConnectionRequest,
446
+ message: "The initConnection message for a new client group must include client schema.",
447
+ origin: ZeroCache
448
+ });
449
+ }
450
+ await this.#handleConfigUpdate(lc2, clientID2, msg, cvr);
451
+ this.#initialized.resolve("initialized");
452
+ },
453
+ newClient
454
+ ).catch((e) => newClient.fail(e));
455
+ return downstream;
456
+ });
457
+ }
458
+ async changeDesiredQueries(ctx, msg) {
459
+ await this.#runInLockForClient(ctx, msg, this.#handleConfigUpdate);
460
+ }
461
+ async deleteClients(ctx, msg) {
462
+ await this.#runInLockForClient(
463
+ ctx,
464
+ [msg[0], { deleted: msg[1] }],
465
+ this.#handleConfigUpdate
466
+ );
467
+ }
468
+ #getTTLClock(now) {
469
+ const delta = now - this.#ttlClockBase;
470
+ assert(this.#ttlClock !== void 0, "ttlClock should be defined");
471
+ const ttlClock = ttlClockFromNumber(
472
+ ttlClockAsNumber(this.#ttlClock) + delta
473
+ );
474
+ assert(
475
+ ttlClockAsNumber(ttlClock) <= now,
476
+ "ttlClock should be less than or equal to now"
477
+ );
478
+ this.#ttlClock = ttlClock;
479
+ this.#ttlClockBase = now;
480
+ return ttlClock;
481
+ }
482
+ async #flushUpdater(lc, updater) {
483
+ const now = Date.now();
484
+ const ttlClock = this.#getTTLClock(now);
485
+ const { cvr, flushed } = await updater.flush(
486
+ lc,
487
+ this.#lastConnectTime,
488
+ now,
489
+ ttlClock
490
+ );
491
+ if (flushed) {
492
+ this.#startTTLClockInterval(lc);
347
493
  }
348
- #stopExpireTimer() {
349
- this.#lc.debug?.('Stopping expired queries timer');
350
- clearTimeout(this.#expiredQueriesTimer);
351
- this.#expiredQueriesTimer = 0;
494
+ return cvr;
495
+ }
496
+ #startTTLClockInterval(lc) {
497
+ this.#stopTTLClockInterval();
498
+ this.#ttlClockInterval = this.#setTimeout(() => {
499
+ this.#updateTTLClockInCVRWithoutLock(lc);
500
+ this.#startTTLClockInterval(lc);
501
+ }, TTL_CLOCK_INTERVAL);
502
+ }
503
+ #stopTTLClockInterval() {
504
+ clearTimeout(this.#ttlClockInterval);
505
+ this.#ttlClockInterval = 0;
506
+ }
507
+ #updateTTLClockInCVRWithoutLock(lc) {
508
+ lc.debug?.("Syncing ttlClock");
509
+ const now = Date.now();
510
+ const ttlClock = this.#getTTLClock(now);
511
+ this.#cvrStore.updateTTLClock(ttlClock, now).catch((e) => {
512
+ lc.error?.("failed to update TTL clock", e);
513
+ });
514
+ }
515
+ async #updateCVRConfig(lc, cvr, clientID, fn) {
516
+ const updater = new CVRConfigDrivenUpdater(
517
+ this.#cvrStore,
518
+ cvr,
519
+ this.#shard
520
+ );
521
+ updater.ensureClient(clientID);
522
+ const patches = fn(updater);
523
+ this.#cvr = await this.#flushUpdater(lc, updater);
524
+ if (cmpVersions(cvr.version, this.#cvr.version) < 0) {
525
+ const newCVR = this.#cvr;
526
+ const pokers = startPoke(this.#getClients(cvr.version), newCVR.version);
527
+ for (const patch of patches) {
528
+ await pokers.addPatch(patch);
529
+ }
530
+ await pokers.end(newCVR.version);
352
531
  }
353
- initConnection(ctx, initConnectionMessage) {
354
- this.#lc.debug?.('viewSyncer.initConnection');
355
- return startSpan(tracer, 'vs.initConnection', () => {
356
- const { clientID, wsID, baseCookie, schemaVersion, tokenData, httpCookie, protocolVersion, } = ctx;
357
- this.#authData = pickToken(this.#lc, this.#authData, tokenData);
358
- this.#lc.debug?.(`Picked auth token: ${JSON.stringify(this.#authData?.decoded)}`);
359
- this.#httpCookie = httpCookie;
360
- // Handle custom query URL
361
- const [, { userQueryURL }] = initConnectionMessage;
362
- if (this.userQueryURL === undefined) {
363
- // First client in the group - store its parameters
364
- this.userQueryURL = userQueryURL;
365
- }
366
- else {
367
- // Validate that subsequent clients have compatible parameters
368
- if (this.userQueryURL !== userQueryURL) {
369
- this.#lc.error?.('Client provided different query parameters than client group', {
370
- clientID,
371
- clientURL: userQueryURL,
372
- clientGroupURL: this.userQueryURL,
373
- });
374
- }
375
- }
376
- const lc = this.#lc
377
- .withContext('clientID', clientID)
378
- .withContext('wsID', wsID);
379
- // Setup the downstream connection.
380
- const downstream = Subscription.create({
381
- cleanup: (_, err) => {
382
- err
383
- ? lc[getLogLevel(err)]?.(`client closed with error`, err)
384
- : lc.info?.('client closed');
385
- this.#deleteClientDueToDisconnect(clientID, newClient);
386
- this.#activeClients.add(-1, {
387
- [PROTOCOL_VERSION_ATTR]: protocolVersion,
388
- });
389
- },
390
- });
391
- this.#activeClients.add(1, {
392
- [PROTOCOL_VERSION_ATTR]: protocolVersion,
393
- });
394
- if (this.#clients.size === 0) {
395
- // First connection to this ViewSyncerService.
396
- // initConnection must be synchronous so that the downstream
397
- // subscription is returned immediately.
398
- const now = Date.now();
399
- this.#ttlClockBase = now;
400
- }
401
- const newClient = new ClientHandler(lc, this.id, clientID, wsID, this.#shard, baseCookie, schemaVersion, downstream);
402
- this.#clients.get(clientID)?.close(`replaced by wsID: ${wsID}`);
403
- this.#clients.set(clientID, newClient);
404
- // Note: initConnection() must be synchronous so that `downstream` is
405
- // immediately returned to the caller (connection.ts). This ensures
406
- // that if the connection is subsequently closed, the `downstream`
407
- // subscription can be properly canceled even if #runInLockForClient()
408
- // has not had a chance to run.
409
- void this.#runInLockForClient(ctx, initConnectionMessage, this.#handleConfigUpdate, newClient).catch(e => newClient.fail(e));
410
- return downstream;
411
- });
532
+ if (this.#pipelinesSynced) {
533
+ await this.#syncQueryPipelineSet(lc, this.#cvr);
412
534
  }
413
- async changeDesiredQueries(ctx, msg) {
414
- await this.#runInLockForClient(ctx, msg, this.#handleConfigUpdate);
535
+ return this.#cvr;
536
+ }
537
+ /**
538
+ * Runs the given `fn` to process the `msg` from within the `#lock`,
539
+ * optionally adding the `newClient` if supplied.
540
+ */
541
+ #runInLockForClient(ctx, msg, fn, newClient) {
542
+ this.#lc.debug?.("viewSyncer.#runInLockForClient");
543
+ const { clientID, wsID } = ctx;
544
+ const [cmd, body] = msg;
545
+ if (newClient || !this.#clients.has(clientID)) {
546
+ this.#lastConnectTime = Date.now();
415
547
  }
416
- async deleteClients(ctx, msg) {
548
+ return startAsyncSpan(
549
+ tracer,
550
+ `vs.#runInLockForClient(${cmd})`,
551
+ async () => {
552
+ let client;
417
553
  try {
418
- await this.#runInLockForClient(ctx, [msg[0], { deleted: msg[1] }], this.#handleConfigUpdate);
554
+ await this.#runInLockWithCVR((lc, cvr) => {
555
+ lc = lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd);
556
+ lc.debug?.("acquired lock for cvr");
557
+ client = this.#clients.get(clientID);
558
+ if (client?.wsID !== wsID) {
559
+ lc.debug?.("mismatched wsID", client?.wsID, wsID);
560
+ return;
561
+ }
562
+ if (newClient) {
563
+ assert(
564
+ newClient === client,
565
+ "newClient must match existing client"
566
+ );
567
+ checkClientAndCVRVersions(client.version(), cvr.version);
568
+ } else if (!this.#clients.has(clientID)) {
569
+ lc.warn?.(`Processing ${cmd} before initConnection was received`);
570
+ }
571
+ lc.debug?.(cmd, body);
572
+ return fn(lc, clientID, body, cvr);
573
+ });
574
+ } catch (e) {
575
+ const lc = this.#lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd);
576
+ lc[getLogLevel(e)]?.(`closing connection with error`, e);
577
+ if (client) {
578
+ client.fail(e);
579
+ } else {
580
+ throw e;
581
+ }
419
582
  }
420
- catch (e) {
421
- this.#lc.error?.('deleteClients failed', e);
583
+ }
584
+ );
585
+ }
586
+ #getClients(atVersion) {
587
+ const clients = [...this.#clients.values()];
588
+ return atVersion ? clients.filter(
589
+ (c) => cmpVersions(c.version() ?? EMPTY_CVR_VERSION, atVersion) === 0
590
+ ) : clients;
591
+ }
592
+ // Must be called from within #lock.
593
+ #handleConfigUpdate = (lc, clientID, {
594
+ clientSchema,
595
+ deleted,
596
+ desiredQueriesPatch,
597
+ activeClients
598
+ }, cvr) => startAsyncSpan(tracer, "vs.#patchQueries", async () => {
599
+ const deletedClientIDs = [];
600
+ const deletedClientGroupIDs = [];
601
+ cvr = await this.#updateCVRConfig(lc, cvr, clientID, (updater) => {
602
+ const { ttlClock } = cvr;
603
+ const patches = [];
604
+ if (clientSchema) {
605
+ updater.setClientSchema(lc, clientSchema);
606
+ }
607
+ lc.debug?.(`applying ${desiredQueriesPatch?.length} query patches`);
608
+ if (desiredQueriesPatch?.length) {
609
+ for (const patch of desiredQueriesPatch) {
610
+ switch (patch.op) {
611
+ case "put":
612
+ patches.push(...updater.putDesiredQueries(clientID, [patch]));
613
+ break;
614
+ case "del":
615
+ patches.push(
616
+ ...updater.markDesiredQueriesAsInactive(
617
+ clientID,
618
+ [patch.hash],
619
+ ttlClock
620
+ )
621
+ );
622
+ break;
623
+ case "clear":
624
+ patches.push(...updater.clearDesiredQueries(clientID));
625
+ break;
626
+ }
422
627
  }
628
+ }
629
+ const clientIDsToDelete = /* @__PURE__ */ new Set();
630
+ if (activeClients) {
631
+ const allClientIDs = Object.keys(cvr.clients);
632
+ const activeClientsSet = new Set(activeClients);
633
+ for (const id of allClientIDs) {
634
+ if (!activeClientsSet.has(id)) {
635
+ clientIDsToDelete.add(id);
636
+ }
637
+ }
638
+ }
639
+ if (deleted?.clientIDs?.length) {
640
+ for (const cid of deleted.clientIDs) {
641
+ assert(cid !== clientID, "cannot delete self");
642
+ clientIDsToDelete.add(cid);
643
+ }
644
+ }
645
+ for (const cid of clientIDsToDelete) {
646
+ const patchesDueToClient = updater.deleteClient(cid, ttlClock);
647
+ patches.push(...patchesDueToClient);
648
+ deletedClientIDs.push(cid);
649
+ }
650
+ if (deleted?.clientGroupIDs?.length) {
651
+ lc.debug?.(
652
+ `ignoring ${deleted.clientGroupIDs.length} deprecated client group deletes`
653
+ );
654
+ }
655
+ return patches;
656
+ });
657
+ if (deletedClientIDs.length && deleted?.clientIDs?.length || deletedClientGroupIDs.length) {
658
+ const clients = this.#getClients();
659
+ await Promise.allSettled(
660
+ clients.map(
661
+ (client) => client.sendDeleteClients(
662
+ lc,
663
+ deletedClientIDs,
664
+ deletedClientGroupIDs
665
+ )
666
+ )
667
+ );
423
668
  }
424
- #getTTLClock(now) {
425
- // We will update ttlClock with delta from the ttlClockBase to the current time.
426
- const delta = now - this.#ttlClockBase;
427
- assert(this.#ttlClock !== undefined, 'ttlClock should be defined');
428
- const ttlClock = ttlClockFromNumber(ttlClockAsNumber(this.#ttlClock) + delta);
429
- assert(ttlClockAsNumber(ttlClock) <= now, 'ttlClock should be less than or equal to now');
430
- this.#ttlClock = ttlClock;
431
- this.#ttlClockBase = now;
432
- return ttlClock;
669
+ this.#scheduleExpireEviction(lc, cvr);
670
+ });
671
+ #scheduleExpireEviction(lc, cvr) {
672
+ const { ttlClock } = cvr;
673
+ this.#stopExpireTimer();
674
+ const next = nextEvictionTime(cvr);
675
+ if (next === void 0) {
676
+ lc.debug?.("no inactive queries with ttl");
677
+ return;
433
678
  }
434
- async #flushUpdater(lc, updater) {
435
- const now = Date.now();
436
- const ttlClock = this.#getTTLClock(now);
437
- const { cvr, flushed } = await updater.flush(lc, this.#lastConnectTime, now, ttlClock);
438
- if (flushed) {
439
- // If the CVR was flushed, we restart the ttlClock interval.
440
- this.#startTTLClockInterval(lc);
441
- }
442
- return cvr;
679
+ const delay = Math.max(
680
+ TTL_TIMER_HYSTERESIS,
681
+ Math.min(
682
+ ttlClockAsNumber(next) - ttlClockAsNumber(ttlClock) + TTL_TIMER_HYSTERESIS,
683
+ MAX_TTL_MS
684
+ )
685
+ );
686
+ lc.debug?.("Scheduling eviction timer to run in ", delay, "ms");
687
+ this.#expiredQueriesTimer = this.#setTimeout(() => {
688
+ this.#expiredQueriesTimer = 0;
689
+ this.#runInLockWithCVR(
690
+ (lc2, cvr2) => this.#removeExpiredQueries(lc2, cvr2)
691
+ ).catch(
692
+ (e) => (
693
+ // If an error occurs (e.g. ownership change), propagate the error
694
+ // to the main run() loop via the #stateChanges Subscription.
695
+ this.#stateChanges.fail(e)
696
+ )
697
+ );
698
+ }, delay);
699
+ }
700
+ /**
701
+ * Adds and hydrates pipelines for queries whose results are already
702
+ * recorded in the CVR. Namely:
703
+ *
704
+ * 1. The CVR state version and database version are the same.
705
+ * 2. The transformation hash of the queries equal those in the CVR.
706
+ *
707
+ * Note that by definition, only "got" queries can satisfy condition (2),
708
+ * as desired queries do not have a transformation hash.
709
+ *
710
+ * This is an initialization step that sets up pipeline state without
711
+ * the expensive of loading and diffing CVR row state.
712
+ *
713
+ * This must be called from within the #lock.
714
+ */
715
+ async #hydrateUnchangedQueries(lc, cvr) {
716
+ assert(this.#pipelines.initialized(), "pipelines must be initialized");
717
+ const dbVersion = this.#pipelines.currentVersion();
718
+ const cvrVersion = cvr.version;
719
+ if (cvrVersion.stateVersion !== dbVersion) {
720
+ lc.info?.(
721
+ `CVR (${versionToCookie(cvrVersion)}) is behind db ${dbVersion}`
722
+ );
723
+ return;
443
724
  }
444
- #startTTLClockInterval(lc) {
445
- this.#stopTTLClockInterval();
446
- this.#ttlClockInterval = this.#setTimeout(() => {
447
- this.#updateTTLClockInCVRWithoutLock(lc);
448
- this.#startTTLClockInterval(lc);
449
- }, TTL_CLOCK_INTERVAL);
725
+ const gotQueries = Object.entries(cvr.queries).filter(
726
+ ([_, state]) => state.transformationHash !== void 0
727
+ );
728
+ const customQueries = /* @__PURE__ */ new Map();
729
+ const otherQueries = [];
730
+ for (const [, query] of gotQueries) {
731
+ if (query.type !== "internal" && Object.values(query.clientState).every(
732
+ ({ inactivatedAt }) => inactivatedAt !== void 0
733
+ )) {
734
+ continue;
735
+ }
736
+ if (query.type === "custom") {
737
+ customQueries.set(query.id, query);
738
+ } else {
739
+ otherQueries.push(query);
740
+ }
450
741
  }
451
- #stopTTLClockInterval() {
452
- clearTimeout(this.#ttlClockInterval);
453
- this.#ttlClockInterval = 0;
742
+ const transformedQueries = [];
743
+ if (customQueries.size > 0 && !this.#customQueryTransformer) {
744
+ lc.warn?.(
745
+ "Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache."
746
+ );
454
747
  }
455
- #updateTTLClockInCVRWithoutLock(lc) {
456
- lc.debug?.('Syncing ttlClock');
457
- const now = Date.now();
458
- const ttlClock = this.#getTTLClock(now);
459
- this.#cvrStore.updateTTLClock(ttlClock, now).catch(e => {
460
- lc.error?.('failed to update TTL clock', e);
461
- });
748
+ if (this.#customQueryTransformer && customQueries.size > 0) {
749
+ const transformedCustomQueries = await this.#customQueryTransformer.transform(
750
+ this.#getHeaderOptions(this.#queryConfig.forwardCookies),
751
+ customQueries.values(),
752
+ this.userQueryURL
753
+ );
754
+ this.#processTransformedCustomQueries(
755
+ lc,
756
+ transformedCustomQueries,
757
+ (q) => transformedQueries.push(q),
758
+ customQueries
759
+ );
462
760
  }
463
- async #updateCVRConfig(lc, cvr, clientID, fn) {
464
- const updater = new CVRConfigDrivenUpdater(this.#cvrStore, cvr, this.#shard);
465
- updater.ensureClient(clientID);
466
- const patches = fn(updater);
467
- this.#cvr = await this.#flushUpdater(lc, updater);
468
- if (cmpVersions(cvr.version, this.#cvr.version) < 0) {
469
- // Send pokes to catch up clients that are up to date.
470
- // (Clients that are behind the cvr.version need to be caught up in
471
- // #syncQueryPipelineSet(), as row data may be needed for catchup)
472
- const newCVR = this.#cvr;
473
- const pokers = startPoke(this.#getClients(cvr.version), newCVR.version);
474
- for (const patch of patches) {
475
- await pokers.addPatch(patch);
761
+ for (const q of otherQueries) {
762
+ const transformed = transformAndHashQuery(
763
+ lc,
764
+ q.id,
765
+ q.ast,
766
+ must(this.#pipelines.currentPermissions()).permissions ?? {
767
+ tables: {}
768
+ },
769
+ this.#authData?.decoded,
770
+ q.type === "internal"
771
+ );
772
+ if (transformed.transformationHash === q.transformationHash) {
773
+ transformedQueries.push(transformed);
774
+ }
775
+ }
776
+ for (const {
777
+ id: queryID,
778
+ transformationHash,
779
+ transformedAst
780
+ } of transformedQueries) {
781
+ const timer = new TimeSliceTimer();
782
+ let count = 0;
783
+ await startAsyncSpan(
784
+ tracer,
785
+ "vs.#hydrateUnchangedQueries.addQuery",
786
+ async (span) => {
787
+ span.setAttribute("queryHash", queryID);
788
+ span.setAttribute("transformationHash", transformationHash);
789
+ span.setAttribute("table", transformedAst.table);
790
+ for (const _ of this.#pipelines.addQuery(
791
+ transformationHash,
792
+ queryID,
793
+ transformedAst,
794
+ await timer.start()
795
+ )) {
796
+ if (++count % TIME_SLICE_CHECK_SIZE === 0) {
797
+ if (timer.elapsedLap() > TIME_SLICE_MS) {
798
+ await timer.yieldProcess();
799
+ }
476
800
  }
477
- await pokers.end(newCVR.version);
478
- }
479
- if (this.#pipelinesSynced) {
480
- await this.#syncQueryPipelineSet(lc, this.#cvr);
801
+ }
481
802
  }
482
- return this.#cvr;
803
+ );
804
+ const elapsed = timer.totalElapsed();
805
+ this.#hydrations.add(1);
806
+ this.#hydrationTime.record(elapsed / 1e3);
807
+ this.#addQueryMaterializationServerMetric(transformationHash, elapsed);
808
+ lc.debug?.(`hydrated ${count} rows for ${queryID} (${elapsed} ms)`);
483
809
  }
484
- /**
485
- * Runs the given `fn` to process the `msg` from within the `#lock`,
486
- * optionally adding the `newClient` if supplied.
487
- */
488
- #runInLockForClient(ctx, msg, fn, newClient) {
489
- this.#lc.debug?.('viewSyncer.#runInLockForClient');
490
- const { clientID, wsID } = ctx;
491
- const [cmd, body] = msg;
492
- if (newClient || !this.#clients.has(clientID)) {
493
- this.#lastConnectTime = Date.now();
494
- }
495
- return startAsyncSpan(tracer, `vs.#runInLockForClient(${cmd})`, async () => {
496
- let client;
497
- try {
498
- await this.#runInLockWithCVR((lc, cvr) => {
499
- lc = lc
500
- .withContext('clientID', clientID)
501
- .withContext('wsID', wsID)
502
- .withContext('cmd', cmd);
503
- lc.debug?.('acquired lock for cvr');
504
- client = this.#clients.get(clientID);
505
- if (client?.wsID !== wsID) {
506
- lc.debug?.('mismatched wsID', client?.wsID, wsID);
507
- // Only respond to messages of the currently connected client.
508
- // Connections may have been drained or dropped due to an error.
509
- return;
510
- }
511
- if (newClient) {
512
- assert(newClient === client, 'newClient must match existing client');
513
- checkClientAndCVRVersions(client.version(), cvr.version);
514
- }
515
- else if (!this.#clients.has(clientID)) {
516
- lc.warn?.(`Processing ${cmd} before initConnection was received`);
517
- }
518
- lc.debug?.(cmd, body);
519
- return fn(lc, clientID, body, cvr);
520
- });
521
- }
522
- catch (e) {
523
- const lc = this.#lc
524
- .withContext('clientID', clientID)
525
- .withContext('wsID', wsID)
526
- .withContext('cmd', cmd);
527
- lc[getLogLevel(e)]?.(`closing connection with error`, e);
528
- if (client) {
529
- // Ideally, propagate the exception to the client's downstream subscription ...
530
- client.fail(e);
531
- }
532
- else {
533
- // unless the exception happened before the client could be looked up.
534
- throw e;
535
- }
536
- }
537
- });
810
+ }
811
+ #processTransformedCustomQueries(lc, transformedCustomQueries, cb, customQueryMap) {
812
+ if ("kind" in transformedCustomQueries) {
813
+ this.#sendQueryTransformErrorToClients(
814
+ customQueryMap,
815
+ transformedCustomQueries
816
+ );
817
+ return transformedCustomQueries.queryIDs;
538
818
  }
539
- #getClients(atVersion) {
540
- const clients = [...this.#clients.values()];
541
- return atVersion
542
- ? clients.filter(c => cmpVersions(c.version() ?? EMPTY_CVR_VERSION, atVersion) === 0)
543
- : clients;
819
+ const appQueryErrors = [];
820
+ for (const q of transformedCustomQueries) {
821
+ if ("error" in q) {
822
+ const errorMessage = `Error transforming custom query ${q.name}: ${q.error}${q.details ? ` ${JSON.stringify(q.details)}` : ""}`;
823
+ lc.warn?.(errorMessage, q);
824
+ appQueryErrors.push(q);
825
+ continue;
826
+ }
827
+ cb(q);
544
828
  }
545
- // Must be called from within #lock.
546
- #handleConfigUpdate = (lc, clientID, { clientSchema, deleted, desiredQueriesPatch, activeClients, }, cvr) => startAsyncSpan(tracer, 'vs.#patchQueries', async () => {
547
- const deletedClientIDs = [];
548
- const deletedClientGroupIDs = [];
549
- cvr = await this.#updateCVRConfig(lc, cvr, clientID, updater => {
550
- const { ttlClock } = cvr;
551
- const patches = [];
552
- if (clientSchema) {
553
- updater.setClientSchema(lc, clientSchema);
554
- }
555
- // Apply requested patches.
556
- lc.debug?.(`applying ${desiredQueriesPatch?.length} query patches`);
557
- if (desiredQueriesPatch?.length) {
558
- for (const patch of desiredQueriesPatch) {
559
- switch (patch.op) {
560
- case 'put':
561
- patches.push(...updater.putDesiredQueries(clientID, [patch]));
562
- break;
563
- case 'del':
564
- patches.push(...updater.markDesiredQueriesAsInactive(clientID, [patch.hash], ttlClock));
565
- break;
566
- case 'clear':
567
- patches.push(...updater.clearDesiredQueries(clientID));
568
- break;
569
- }
570
- }
571
- }
572
- const clientIDsToDelete = new Set();
573
- if (activeClients) {
574
- // We find all the clients in this client group that are not active.
575
- const allClientIDs = Object.keys(cvr.clients);
576
- const activeClientsSet = new Set(activeClients);
577
- for (const id of allClientIDs) {
578
- if (!activeClientsSet.has(id)) {
579
- clientIDsToDelete.add(id);
580
- }
581
- }
582
- }
583
- if (deleted?.clientIDs?.length) {
584
- for (const cid of deleted.clientIDs) {
585
- assert(cid !== clientID, 'cannot delete self');
586
- clientIDsToDelete.add(cid);
587
- }
588
- }
589
- for (const cid of clientIDsToDelete) {
590
- const patchesDueToClient = updater.deleteClient(cid, ttlClock);
591
- patches.push(...patchesDueToClient);
592
- deletedClientIDs.push(cid);
593
- }
594
- if (deleted?.clientGroupIDs?.length) {
595
- lc.debug?.(`ignoring ${deleted.clientGroupIDs.length} deprecated client group deletes`);
596
- }
597
- return patches;
598
- });
599
- // Send 'deleteClients' ack to the clients.
600
- if ((deletedClientIDs.length && deleted?.clientIDs?.length) ||
601
- deletedClientGroupIDs.length) {
602
- const clients = this.#getClients();
603
- await Promise.allSettled(clients.map(client => client.sendDeleteClients(lc, deletedClientIDs, deletedClientGroupIDs)));
829
+ this.#sendQueryTransformErrorToClients(customQueryMap, appQueryErrors);
830
+ return appQueryErrors.map((q) => q.id);
831
+ }
832
+ #sendQueryTransformErrorToClients(customQueryMap, errorOrErrors) {
833
+ const getAffectedClientIDs = (queryIDs) => {
834
+ const clientIds = /* @__PURE__ */ new Set();
835
+ for (const queryID of queryIDs) {
836
+ const q = customQueryMap.get(queryID);
837
+ assert(
838
+ q,
839
+ `got an error for query ${queryID} that does not map back to a custom query`
840
+ );
841
+ Object.keys(q.clientState).forEach((id) => clientIds.add(id));
842
+ }
843
+ return clientIds;
844
+ };
845
+ if ("queryIDs" in errorOrErrors) {
846
+ for (const clientId of getAffectedClientIDs(errorOrErrors.queryIDs)) {
847
+ this.#clients.get(clientId)?.sendQueryTransformFailedError(errorOrErrors);
848
+ }
849
+ return;
850
+ }
851
+ const appErrorGroups = /* @__PURE__ */ new Map();
852
+ for (const err of errorOrErrors) {
853
+ for (const clientId of getAffectedClientIDs([err.id])) {
854
+ const group = appErrorGroups.get(clientId) ?? [];
855
+ group.push(err);
856
+ appErrorGroups.set(clientId, group);
857
+ }
858
+ }
859
+ for (const [clientId, errors] of appErrorGroups) {
860
+ this.#clients.get(clientId)?.sendQueryTransformApplicationErrors(errors);
861
+ }
862
+ }
863
+ #addQueryMaterializationServerMetric(transformationHash, elapsed) {
864
+ this.#inspectorDelegate.addMetric(
865
+ "query-materialization-server",
866
+ elapsed,
867
+ transformationHash
868
+ );
869
+ }
870
+ /**
871
+ * Adds and/or removes queries to/from the PipelineDriver to bring it
872
+ * in sync with the set of queries in the CVR (both got and desired).
873
+ * If queries are added, removed, or queried due to a new state version,
874
+ * a new CVR version is created and pokes sent to connected clients.
875
+ *
876
+ * This must be called from within the #lock.
877
+ */
878
+ #syncQueryPipelineSet(lc, cvr) {
879
+ return startAsyncSpan(tracer, "vs.#syncQueryPipelineSet", async () => {
880
+ assert(
881
+ this.#pipelines.initialized(),
882
+ "pipelines must be initialized (syncQueryPipelineSet)"
883
+ );
884
+ const [hydratedQueries, byOriginalHash] = this.#pipelines.addedQueries();
885
+ const hashToIDs = /* @__PURE__ */ new Map();
886
+ if (this.#ttlClock === void 0) {
887
+ this.#ttlClock = cvr.ttlClock;
888
+ }
889
+ const now = Date.now();
890
+ const ttlClock = this.#getTTLClock(now);
891
+ const cvrQueryEntires = Object.entries(cvr.queries);
892
+ const customQueries = /* @__PURE__ */ new Map();
893
+ const otherQueries = [];
894
+ const transformedQueries = [];
895
+ for (const [id, query] of cvrQueryEntires) {
896
+ if (query.type === "custom") {
897
+ assert(id === query.id, "custom query id mismatch");
898
+ customQueries.set(id, query);
899
+ } else {
900
+ otherQueries.push({ id, query });
604
901
  }
605
- this.#scheduleExpireEviction(lc, cvr);
606
- });
607
- #scheduleExpireEviction(lc, cvr) {
608
- const { ttlClock } = cvr;
609
- this.#stopExpireTimer();
610
- // first see if there is any inactive query with a ttl.
611
- const next = nextEvictionTime(cvr);
612
- if (next === undefined) {
613
- lc.debug?.('no inactive queries with ttl');
614
- // no inactive queries with a ttl. Cancel existing timeout if any.
615
- return;
902
+ }
903
+ for (const { id, query: origQuery } of otherQueries) {
904
+ assert(id === origQuery.id, "query id mismatch");
905
+ const transformed = transformAndHashQuery(
906
+ lc,
907
+ origQuery.id,
908
+ origQuery.ast,
909
+ must(this.#pipelines.currentPermissions()).permissions ?? {
910
+ tables: {}
911
+ },
912
+ this.#authData?.decoded,
913
+ origQuery.type === "internal"
914
+ );
915
+ transformedQueries.push({
916
+ id,
917
+ origQuery,
918
+ transformed
919
+ });
920
+ }
921
+ if (customQueries.size > 0 && !this.#customQueryTransformer) {
922
+ lc.warn?.(
923
+ "Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache."
924
+ );
925
+ }
926
+ let erroredQueryIDs;
927
+ if (this.#customQueryTransformer && customQueries.size > 0) {
928
+ const transformStart = performance.now();
929
+ let transformedCustomQueries;
930
+ try {
931
+ transformedCustomQueries = await this.#customQueryTransformer.transform(
932
+ this.#getHeaderOptions(true),
933
+ customQueries.values(),
934
+ this.userQueryURL
935
+ );
936
+ this.#queryTransformations.add(1, { result: "success" });
937
+ } catch (e) {
938
+ this.#queryTransformations.add(1, { result: "error" });
939
+ throw e;
940
+ } finally {
941
+ const transformDuration = (performance.now() - transformStart) / 1e3;
942
+ this.#queryTransformationTime.record(transformDuration);
616
943
  }
617
- // It is common for many queries to be evicted close to the same time, so
618
- // we add a small delay so we can collapse multiple evictions into a
619
- // single timer. However, don't add the delay if we're already at the
620
- // maximum timer limit, as that's not about collapsing.
621
- const delay = Math.max(TTL_TIMER_HYSTERESIS, Math.min(ttlClockAsNumber(next) -
622
- ttlClockAsNumber(ttlClock) +
623
- TTL_TIMER_HYSTERESIS, MAX_TTL_MS));
624
- lc.debug?.('Scheduling eviction timer to run in ', delay, 'ms');
625
- this.#expiredQueriesTimer = this.#setTimeout(() => {
626
- this.#expiredQueriesTimer = 0;
627
- this.#runInLockWithCVR((lc, cvr) => this.#removeExpiredQueries(lc, cvr)).catch(e =>
628
- // If an error occurs (e.g. ownership change), propagate the error
629
- // to the main run() loop via the #stateChanges Subscription.
630
- this.#stateChanges.fail(e));
631
- }, delay);
632
- }
633
- /**
634
- * Adds and hydrates pipelines for queries whose results are already
635
- * recorded in the CVR. Namely:
636
- *
637
- * 1. The CVR state version and database version are the same.
638
- * 2. The transformation hash of the queries equal those in the CVR.
639
- *
640
- * Note that by definition, only "got" queries can satisfy condition (2),
641
- * as desired queries do not have a transformation hash.
642
- *
643
- * This is an initialization step that sets up pipeline state without
644
- * the expensive of loading and diffing CVR row state.
645
- *
646
- * This must be called from within the #lock.
647
- */
648
- async #hydrateUnchangedQueries(lc, cvr) {
649
- assert(this.#pipelines.initialized(), 'pipelines must be initialized');
650
- const dbVersion = this.#pipelines.currentVersion();
651
- const cvrVersion = cvr.version;
652
- if (cvrVersion.stateVersion !== dbVersion) {
653
- lc.info?.(`CVR (${versionToCookie(cvrVersion)}) is behind db ${dbVersion}`);
654
- return; // hydration needs to be run with the CVR updater.
944
+ if (!Array.isArray(transformedCustomQueries) && transformedCustomQueries.kind === TransformFailed) {
945
+ throw new ProtocolErrorWithLevel(
946
+ transformedCustomQueries,
947
+ getLogLevel(transformedCustomQueries.kind)
948
+ );
655
949
  }
656
- const gotQueries = Object.entries(cvr.queries).filter(([_, state]) => state.transformationHash !== undefined);
657
- const customQueries = new Map();
658
- const otherQueries = [];
659
- for (const [, query] of gotQueries) {
660
- if (query.type !== 'internal' &&
661
- Object.values(query.clientState).every(({ inactivatedAt }) => inactivatedAt !== undefined)) {
662
- continue; // No longer desired.
663
- }
664
- if (query.type === 'custom') {
665
- customQueries.set(query.id, query);
666
- }
667
- else {
668
- otherQueries.push(query);
950
+ const successfullyTransformed = /* @__PURE__ */ new Map();
951
+ erroredQueryIDs = this.#processTransformedCustomQueries(
952
+ lc,
953
+ transformedCustomQueries,
954
+ (q) => {
955
+ successfullyTransformed.set(q.id, q);
956
+ transformedQueries.push({
957
+ id: q.id,
958
+ origQuery: must(customQueries.get(q.id)),
959
+ transformed: q
960
+ });
961
+ },
962
+ customQueries
963
+ );
964
+ for (const [queryID, newTransform] of successfullyTransformed) {
965
+ const existingTransforms = byOriginalHash.get(queryID);
966
+ if (existingTransforms && existingTransforms.length > 0) {
967
+ const oldHash = existingTransforms[0].transformationHash;
968
+ const newHash = newTransform.transformationHash;
969
+ if (oldHash !== newHash) {
970
+ lc.info?.(
971
+ `Query ${queryID} transformation changed: ${oldHash} -> ${newHash}`
972
+ );
973
+ this.#checkForThrashing(queryID);
974
+ this.#queryTransformationHashChanges.add(1);
975
+ } else {
976
+ this.#queryTransformationNoOps.add(1);
669
977
  }
978
+ }
670
979
  }
671
- const transformedQueries = [];
672
- if (customQueries.size > 0 && !this.#customQueryTransformer) {
673
- lc.error?.('Custom/named queries were requested but no `ZERO_GET_QUERIES_URL` is configured for Zero Cache.');
980
+ }
981
+ const serverQueries = transformedQueries.map(
982
+ ({ id, origQuery, transformed }) => {
983
+ const ids = hashToIDs.get(transformed.transformationHash);
984
+ if (ids) {
985
+ ids.push(id);
986
+ } else {
987
+ hashToIDs.set(transformed.transformationHash, [id]);
988
+ }
989
+ return {
990
+ id,
991
+ ast: transformed.transformedAst,
992
+ transformationHash: transformed.transformationHash,
993
+ remove: expired(ttlClock, origQuery)
994
+ };
674
995
  }
675
- const [_, byOriginalHash] = this.#pipelines.addedQueries();
676
- if (this.#customQueryTransformer && customQueries.size > 0) {
677
- const filteredCustomQueries = this.#filterCustomQueries(customQueries.values(), byOriginalHash, undefined);
678
- const transformedCustomQueries = await this.#customQueryTransformer.transform(this.#getHeaderOptions(this.#queryConfig.forwardCookies), filteredCustomQueries, this.userQueryURL);
679
- this.#processTransformedCustomQueries(lc, transformedCustomQueries, (q) => transformedQueries.push(q), customQueries);
996
+ );
997
+ const addQueries = serverQueries.filter(
998
+ (q) => !q.remove && !hydratedQueries.has(q.transformationHash)
999
+ );
1000
+ const removeQueries = serverQueries.filter((q) => q.remove);
1001
+ const desiredQueries = new Set(
1002
+ serverQueries.filter((q) => !q.remove).map((q) => q.transformationHash)
1003
+ );
1004
+ const unhydrateQueries = [...hydratedQueries].filter(
1005
+ (transformationHash) => !desiredQueries.has(transformationHash)
1006
+ );
1007
+ for (const q of addQueries) {
1008
+ const orig = cvr.queries[q.id];
1009
+ lc.debug?.(
1010
+ "ViewSyncer adding query",
1011
+ q.ast,
1012
+ "transformed from",
1013
+ orig.type === "custom" ? orig.name : orig.ast
1014
+ );
1015
+ }
1016
+ if (erroredQueryIDs) {
1017
+ const successfulHashes = new Set(
1018
+ transformedQueries.map(
1019
+ ({ transformed }) => transformed.transformationHash
1020
+ )
1021
+ );
1022
+ for (const queryID of erroredQueryIDs) {
1023
+ let lastKnownHash;
1024
+ const cvrQuery = cvr.queries[queryID];
1025
+ if (cvrQuery?.transformationHash) {
1026
+ lastKnownHash = cvrQuery.transformationHash;
1027
+ }
1028
+ const transformationHash = lastKnownHash && successfulHashes.has(lastKnownHash) ? void 0 : lastKnownHash;
1029
+ removeQueries.push({
1030
+ id: queryID,
1031
+ transformationHash
1032
+ });
680
1033
  }
681
- for (const q of otherQueries) {
682
- const transformed = transformAndHashQuery(lc, q.id, q.ast, must(this.#pipelines.currentPermissions()).permissions ?? {
683
- tables: {},
684
- }, this.#authData?.decoded, q.type === 'internal');
685
- if (transformed.transformationHash === q.transformationHash) {
686
- // only processing unchanged queries here
687
- transformedQueries.push(transformed);
688
- }
1034
+ }
1035
+ if (addQueries.length > 0 || removeQueries.length > 0 || unhydrateQueries.length > 0) {
1036
+ await this.#addAndRemoveQueries(
1037
+ lc,
1038
+ cvr,
1039
+ addQueries,
1040
+ removeQueries,
1041
+ unhydrateQueries,
1042
+ hashToIDs
1043
+ );
1044
+ } else {
1045
+ await this.#catchupClients(lc, cvr);
1046
+ }
1047
+ });
1048
+ }
1049
+ /**
1050
+ * Check if a query is being replaced too frequently (thrashing).
1051
+ * Logs a warning if the query has been replaced more than 3 times in 60 seconds.
1052
+ */
1053
+ #checkForThrashing(queryID) {
1054
+ const THRASH_WINDOW_MS = 6e4;
1055
+ const THRASH_THRESHOLD = 3;
1056
+ const now = Date.now();
1057
+ let record = this.#queryReplacements.get(queryID);
1058
+ if (!record) {
1059
+ record = { count: 1, windowStart: now };
1060
+ this.#queryReplacements.set(queryID, record);
1061
+ return;
1062
+ }
1063
+ if (now - record.windowStart > THRASH_WINDOW_MS) {
1064
+ this.#queryReplacements.delete(queryID);
1065
+ this.#queryReplacements.set(queryID, { count: 1, windowStart: now });
1066
+ return;
1067
+ }
1068
+ record.count++;
1069
+ if (record.count >= THRASH_THRESHOLD) {
1070
+ this.#lc.warn?.(
1071
+ `Query thrashing detected for query ${queryID}. ${record.count} replacements in 60s. This may indicate clients with different auth contexts connecting to the same client group.`
1072
+ );
1073
+ }
1074
+ }
1075
+ // This must be called from within the #lock.
1076
+ #addAndRemoveQueries(lc, cvr, addQueries, removeQueries, unhydrateQueries, hashToIDs) {
1077
+ return startAsyncSpan(tracer, "vs.#addAndRemoveQueries", async () => {
1078
+ assert(
1079
+ addQueries.length > 0 || removeQueries.length > 0 || unhydrateQueries.length > 0,
1080
+ "Must have queries to add or remove"
1081
+ );
1082
+ const start = performance.now();
1083
+ const stateVersion = this.#pipelines.currentVersion();
1084
+ lc = lc.withContext("stateVersion", stateVersion);
1085
+ lc.info?.(`hydrating ${addQueries.length} queries`);
1086
+ const updater = new CVRQueryDrivenUpdater(
1087
+ this.#cvrStore,
1088
+ cvr,
1089
+ stateVersion,
1090
+ this.#pipelines.replicaVersion
1091
+ );
1092
+ const { newVersion, queryPatches } = updater.trackQueries(
1093
+ lc,
1094
+ addQueries,
1095
+ removeQueries
1096
+ );
1097
+ const clients = this.#getClients();
1098
+ const pokers = startPoke(
1099
+ clients,
1100
+ newVersion,
1101
+ this.#pipelines.currentSchemaVersions()
1102
+ );
1103
+ for (const patch of queryPatches) {
1104
+ await pokers.addPatch(patch);
1105
+ }
1106
+ for (const q of removeQueries) {
1107
+ if (q.transformationHash) {
1108
+ this.#pipelines.removeQuery(q.transformationHash);
689
1109
  }
690
- for (const { id: queryID, transformationHash, transformedAst, } of transformedQueries) {
691
- const timer = new TimeSliceTimer();
692
- let count = 0;
693
- await startAsyncSpan(tracer, 'vs.#hydrateUnchangedQueries.addQuery', async (span) => {
694
- span.setAttribute('queryHash', queryID);
695
- span.setAttribute('transformationHash', transformationHash);
696
- span.setAttribute('table', transformedAst.table);
697
- for (const _ of this.#pipelines.addQuery(transformationHash, queryID, transformedAst, await timer.start())) {
698
- if (++count % TIME_SLICE_CHECK_SIZE === 0) {
699
- if (timer.elapsedLap() > TIME_SLICE_MS) {
700
- await timer.yieldProcess();
701
- }
702
- }
703
- }
704
- });
705
- const elapsed = timer.totalElapsed();
706
- this.#hydrations.add(1);
707
- this.#hydrationTime.record(elapsed / 1000);
708
- this.#addQueryMaterializationServerMetric(transformationHash, elapsed);
709
- lc.debug?.(`hydrated ${count} rows for ${queryID} (${elapsed} ms)`);
1110
+ this.#inspectorDelegate.removeQuery(q.id);
1111
+ this.#queryReplacements.delete(q.id);
1112
+ }
1113
+ for (const hash of unhydrateQueries) {
1114
+ this.#pipelines.removeQuery(hash);
1115
+ const ids = hashToIDs.get(hash);
1116
+ if (ids) {
1117
+ for (const id of ids) {
1118
+ this.#inspectorDelegate.removeQuery(id);
1119
+ this.#queryReplacements.delete(id);
1120
+ }
710
1121
  }
711
- }
712
- #processTransformedCustomQueries(lc, transformedCustomQueries, cb, customQueryMap) {
713
- if ('kind' in transformedCustomQueries) {
714
- this.#sendQueryTransformErrorToClients(customQueryMap, transformedCustomQueries);
715
- return transformedCustomQueries.queryIDs;
1122
+ }
1123
+ let totalProcessTime = 0;
1124
+ const timer = new TimeSliceTimer();
1125
+ const pipelines = this.#pipelines;
1126
+ const hydrations = this.#hydrations;
1127
+ const hydrationTime = this.#hydrationTime;
1128
+ const self = this;
1129
+ await yieldProcess();
1130
+ function* generateRowChanges(slowHydrateThreshold) {
1131
+ for (const q of addQueries) {
1132
+ lc = lc.withContext("hash", q.id).withContext("transformationHash", q.transformationHash);
1133
+ lc.debug?.(`adding pipeline for query`, q.ast);
1134
+ yield* pipelines.addQuery(
1135
+ q.transformationHash,
1136
+ q.id,
1137
+ q.ast,
1138
+ timer.startWithoutYielding()
1139
+ );
1140
+ const elapsed = timer.stop();
1141
+ totalProcessTime += elapsed;
1142
+ self.#addQueryMaterializationServerMetric(
1143
+ q.transformationHash,
1144
+ elapsed
1145
+ );
1146
+ if (elapsed > slowHydrateThreshold) {
1147
+ lc.warn?.("Slow query materialization", elapsed, q.ast);
1148
+ }
1149
+ manualSpan(tracer, "vs.addAndConsumeQuery", elapsed, {
1150
+ hash: q.id,
1151
+ transformationHash: q.transformationHash
1152
+ });
716
1153
  }
717
- const appQueryErrors = [];
718
- for (const q of transformedCustomQueries) {
719
- if ('error' in q) {
720
- lc.error?.(`Error transforming custom query ${q.name}: ${q.error} ${q.details}`);
721
- appQueryErrors.push(q);
722
- continue;
723
- }
724
- cb(q);
1154
+ hydrations.add(1);
1155
+ hydrationTime.record(totalProcessTime / 1e3);
1156
+ }
1157
+ await this.#processChanges(
1158
+ lc,
1159
+ timer,
1160
+ generateRowChanges(this.#slowHydrateThreshold),
1161
+ updater,
1162
+ pokers,
1163
+ hashToIDs
1164
+ );
1165
+ for (const patch of await updater.deleteUnreferencedRows(lc)) {
1166
+ await pokers.addPatch(patch);
1167
+ }
1168
+ this.#cvr = await this.#flushUpdater(lc, updater);
1169
+ const finalVersion = this.#cvr.version;
1170
+ await this.#catchupClients(
1171
+ lc,
1172
+ cvr,
1173
+ finalVersion,
1174
+ addQueries.map((q) => q.id),
1175
+ pokers
1176
+ );
1177
+ await pokers.end(finalVersion);
1178
+ const wallTime = performance.now() - start;
1179
+ lc.info?.(
1180
+ `finished processing queries (process: ${totalProcessTime} ms, wall: ${wallTime} ms)`
1181
+ );
1182
+ });
1183
+ }
1184
+ /**
1185
+ * @param cvr The CVR to which clients should be caught up to. This does
1186
+ * not necessarily need to be the current CVR.
1187
+ * @param current The expected current CVR version. Before performing
1188
+ * catchup, the snapshot read will verify that the CVR has not been
1189
+ * concurrently modified. Note that this only needs to be done for
1190
+ * catchup because it is the only time data from the CVR DB is
1191
+ * "exported" without being gated by a CVR flush (which provides
1192
+ * concurrency protection in all other cases).
1193
+ *
1194
+ * If unspecified, the version of the `cvr` is used.
1195
+ * @param excludeQueryHashes Exclude patches from rows associated with
1196
+ * the specified queries.
1197
+ * @param usePokers If specified, sends pokes on existing PokeHandlers,
1198
+ * in which case the caller is responsible for sending the `pokeEnd`
1199
+ * messages. If unspecified, the pokes will be started and ended
1200
+ * using the version from the supplied `cvr`.
1201
+ */
1202
+ // Must be called within #lock
1203
+ #catchupClients(lc, cvr, current, excludeQueryHashes = [], usePokers) {
1204
+ return startAsyncSpan(tracer, "vs.#catchupClients", async (span) => {
1205
+ current ??= cvr.version;
1206
+ const clients = this.#getClients();
1207
+ const pokers = usePokers ?? startPoke(
1208
+ clients,
1209
+ cvr.version,
1210
+ this.#pipelines.currentSchemaVersions()
1211
+ );
1212
+ span.setAttribute("numClients", clients.length);
1213
+ const catchupFrom = clients.map((c) => c.version()).reduce((a, b) => cmpVersions(a, b) < 0 ? a : b, cvr.version);
1214
+ const rowPatches = this.#cvrStore.catchupRowPatches(
1215
+ lc,
1216
+ catchupFrom,
1217
+ cvr,
1218
+ current,
1219
+ excludeQueryHashes
1220
+ );
1221
+ const configPatches = this.#cvrStore.catchupConfigPatches(
1222
+ lc,
1223
+ catchupFrom,
1224
+ cvr,
1225
+ current
1226
+ );
1227
+ let rowPatchCount = 0;
1228
+ for await (const rows of rowPatches) {
1229
+ for (const row of rows) {
1230
+ const { schema, table } = row;
1231
+ const rowKey = row.rowKey;
1232
+ const toVersion = versionFromString(row.patchVersion);
1233
+ const id = { schema, table, rowKey };
1234
+ let patch;
1235
+ if (!row.refCounts) {
1236
+ patch = { type: "row", op: "del", id };
1237
+ } else {
1238
+ const row2 = must(
1239
+ this.#pipelines.getRow(table, rowKey),
1240
+ `Missing row ${table}:${stringify(rowKey)}`
1241
+ );
1242
+ const { contents } = contentsAndVersion(row2);
1243
+ patch = { type: "row", op: "put", id, contents };
1244
+ }
1245
+ const patchToVersion = { patch, toVersion };
1246
+ await pokers.addPatch(patchToVersion);
1247
+ rowPatchCount++;
725
1248
  }
726
- this.#sendQueryTransformErrorToClients(customQueryMap, appQueryErrors);
727
- return appQueryErrors.map(q => q.id);
728
- }
729
- #sendQueryTransformErrorToClients(customQueryMap, errorOrErrors) {
730
- const getAffectedClientIDs = (queryIDs) => {
731
- const clientIds = new Set();
732
- for (const queryID of queryIDs) {
733
- const q = customQueryMap.get(queryID);
734
- assert(q, `got an error for query ${queryID} that does not map back to a custom query`);
735
- Object.keys(q.clientState).forEach(id => clientIds.add(id));
736
- }
737
- return clientIds;
738
- };
739
- // send the transform failed error to each affected client
740
- if ('queryIDs' in errorOrErrors) {
741
- for (const clientId of getAffectedClientIDs(errorOrErrors.queryIDs)) {
742
- this.#clients
743
- .get(clientId)
744
- ?.sendQueryTransformFailedError(errorOrErrors);
745
- }
746
- return;
1249
+ }
1250
+ span.setAttribute("rowPatchCount", rowPatchCount);
1251
+ if (rowPatchCount) {
1252
+ lc.debug?.(`sent ${rowPatchCount} row patches`);
1253
+ }
1254
+ for (const patch of await configPatches) {
1255
+ await pokers.addPatch(patch);
1256
+ }
1257
+ if (!usePokers) {
1258
+ await pokers.end(cvr.version);
1259
+ }
1260
+ });
1261
+ }
1262
+ #processChanges(lc, timer, changes, updater, pokers, hashToIDs) {
1263
+ return startAsyncSpan(tracer, "vs.#processChanges", async () => {
1264
+ const start = performance.now();
1265
+ const rows = new CustomKeyMap(rowIDString);
1266
+ let total = 0;
1267
+ const processBatch = () => startAsyncSpan(tracer, "processBatch", async () => {
1268
+ const wallElapsed = performance.now() - start;
1269
+ total += rows.size;
1270
+ lc.debug?.(
1271
+ `processing ${rows.size} (of ${total}) rows (${wallElapsed} ms)`
1272
+ );
1273
+ const patches = await updater.received(lc, rows);
1274
+ for (const patch of patches) {
1275
+ await pokers.addPatch(patch);
747
1276
  }
748
- // Group and send application errors to each affected client
749
- const appErrorGroups = new Map();
750
- for (const err of errorOrErrors) {
751
- // Application errors need to be grouped by client
752
- for (const clientId of getAffectedClientIDs([err.id])) {
753
- const group = appErrorGroups.get(clientId) ?? [];
754
- group.push(err);
755
- appErrorGroups.set(clientId, group);
1277
+ rows.clear();
1278
+ });
1279
+ await startAsyncSpan(tracer, "loopingChanges", async (span) => {
1280
+ for (const change of changes) {
1281
+ const {
1282
+ type,
1283
+ queryHash: transformationHash,
1284
+ table,
1285
+ rowKey,
1286
+ row
1287
+ } = change;
1288
+ const queryIDs = must(
1289
+ hashToIDs.get(transformationHash),
1290
+ "could not find the original hash for the transformation hash"
1291
+ );
1292
+ const rowID = { schema: "", table, rowKey };
1293
+ let parsedRow = rows.get(rowID);
1294
+ if (!parsedRow) {
1295
+ parsedRow = { refCounts: {} };
1296
+ rows.set(rowID, parsedRow);
1297
+ }
1298
+ queryIDs.forEach((hash) => parsedRow.refCounts[hash] ??= 0);
1299
+ const updateVersion = (row2) => {
1300
+ const { version: version2, contents } = contentsAndVersion(row2);
1301
+ parsedRow.version = version2;
1302
+ parsedRow.contents = contents;
1303
+ };
1304
+ switch (type) {
1305
+ case "add":
1306
+ updateVersion(row);
1307
+ queryIDs.forEach((hash) => parsedRow.refCounts[hash]++);
1308
+ break;
1309
+ case "edit":
1310
+ updateVersion(row);
1311
+ break;
1312
+ case "remove":
1313
+ queryIDs.forEach((hash) => parsedRow.refCounts[hash]--);
1314
+ break;
1315
+ default:
1316
+ unreachable(type);
1317
+ }
1318
+ if (rows.size % CURSOR_PAGE_SIZE === 0) {
1319
+ await processBatch();
1320
+ }
1321
+ if (rows.size % TIME_SLICE_CHECK_SIZE === 0) {
1322
+ if (timer.elapsedLap() > TIME_SLICE_MS) {
1323
+ await timer.yieldProcess();
756
1324
  }
1325
+ }
757
1326
  }
758
- for (const [clientId, errors] of appErrorGroups) {
759
- this.#clients.get(clientId)?.sendQueryTransformApplicationErrors(errors);
1327
+ if (rows.size) {
1328
+ await processBatch();
760
1329
  }
761
- }
762
- #addQueryMaterializationServerMetric(transformationHash, elapsed) {
763
- this.#inspectorDelegate.addMetric('query-materialization-server', elapsed, transformationHash);
764
- }
765
- /**
766
- * Adds and/or removes queries to/from the PipelineDriver to bring it
767
- * in sync with the set of queries in the CVR (both got and desired).
768
- * If queries are added, removed, or queried due to a new state version,
769
- * a new CVR version is created and pokes sent to connected clients.
770
- *
771
- * This must be called from within the #lock.
772
- */
773
- #syncQueryPipelineSet(lc, cvr) {
774
- return startAsyncSpan(tracer, 'vs.#syncQueryPipelineSet', async () => {
775
- assert(this.#pipelines.initialized(), 'pipelines must be initialized (syncQueryPipelineSet)');
776
- const [hydratedQueries, byOriginalHash] = this.#pipelines.addedQueries();
777
- // Convert queries to their transformed ast's and hashes
778
- const hashToIDs = new Map();
779
- if (this.#ttlClock === undefined) {
780
- // Get it from the CVR or initialize it to now.
781
- this.#ttlClock = cvr.ttlClock;
782
- }
783
- const now = Date.now();
784
- const ttlClock = this.#getTTLClock(now);
785
- // group cvr queries into:
786
- // 1. custom queries
787
- // 2. everything else
788
- // Handle transformation appropriately
789
- // Then hydrate as `serverQueries`
790
- const cvrQueryEntires = Object.entries(cvr.queries);
791
- const customQueries = new Map();
792
- const otherQueries = [];
793
- const transformedQueries = [];
794
- for (const [id, query] of cvrQueryEntires) {
795
- if (query.type === 'custom') {
796
- // This should always match, no?
797
- assert(id === query.id, 'custom query id mismatch');
798
- customQueries.set(id, query);
799
- }
800
- else {
801
- otherQueries.push({ id, query });
802
- }
803
- }
804
- for (const { id, query: origQuery } of otherQueries) {
805
- // This should always match, no?
806
- assert(id === origQuery.id, 'query id mismatch');
807
- const transformed = transformAndHashQuery(lc, origQuery.id, origQuery.ast, must(this.#pipelines.currentPermissions()).permissions ?? {
808
- tables: {},
809
- }, this.#authData?.decoded, origQuery.type === 'internal');
810
- transformedQueries.push({
811
- id,
812
- origQuery,
813
- transformed,
814
- });
815
- }
816
- if (customQueries.size > 0 && !this.#customQueryTransformer) {
817
- lc.error?.('Custom/named queries were requested but no `ZERO_GET_QUERIES_URL` is configured for Zero Cache.');
818
- }
819
- let erroredQueryIDs;
820
- if (this.#customQueryTransformer && customQueries.size > 0) {
821
- const filteredCustomQueries = this.#filterCustomQueries(customQueries.values(), byOriginalHash, (origQuery, existing) => {
822
- for (const transformed of existing) {
823
- transformedQueries.push({
824
- id: origQuery.id,
825
- origQuery,
826
- transformed: {
827
- id: origQuery.id,
828
- transformationHash: transformed.transformationHash,
829
- transformedAst: transformed.transformedAst,
830
- },
831
- });
832
- }
833
- });
834
- const transformedCustomQueries = await this.#customQueryTransformer.transform(this.#getHeaderOptions(true), filteredCustomQueries, this.userQueryURL);
835
- erroredQueryIDs = this.#processTransformedCustomQueries(lc, transformedCustomQueries, (q) => transformedQueries.push({
836
- id: q.id,
837
- origQuery: must(customQueries.get(q.id)),
838
- transformed: q,
839
- }), customQueries);
840
- }
841
- const serverQueries = transformedQueries.map(({ id, origQuery, transformed }) => {
842
- const ids = hashToIDs.get(transformed.transformationHash);
843
- if (ids) {
844
- ids.push(id);
845
- }
846
- else {
847
- hashToIDs.set(transformed.transformationHash, [id]);
848
- }
849
- return {
850
- id,
851
- ast: transformed.transformedAst,
852
- transformationHash: transformed.transformationHash,
853
- remove: expired(ttlClock, origQuery),
854
- };
855
- });
856
- const addQueries = serverQueries.filter(q => !q.remove && !hydratedQueries.has(q.transformationHash));
857
- const removeQueries = serverQueries.filter(q => q.remove);
858
- const desiredQueries = new Set(serverQueries.filter(q => !q.remove).map(q => q.transformationHash));
859
- const unhydrateQueries = [...hydratedQueries].filter(transformationHash => !desiredQueries.has(transformationHash));
860
- for (const q of addQueries) {
861
- const orig = cvr.queries[q.id];
862
- lc.debug?.('ViewSyncer adding query', q.ast, 'transformed from', orig.type === 'custom' ? orig.name : orig.ast);
863
- }
864
- // These are queries we need to remove from `desired`, not `got`, because they never transformed.
865
- if (erroredQueryIDs) {
866
- for (const queryID of erroredQueryIDs) {
867
- removeQueries.push({
868
- id: queryID,
869
- transformationHash: undefined,
870
- });
871
- }
872
- }
873
- if (addQueries.length > 0 ||
874
- removeQueries.length > 0 ||
875
- unhydrateQueries.length > 0) {
876
- await this.#addAndRemoveQueries(lc, cvr, addQueries, removeQueries, unhydrateQueries, hashToIDs);
877
- }
878
- else {
879
- await this.#catchupClients(lc, cvr);
880
- }
881
- });
882
- }
883
- // Removes queries from `customQueries` that are already
884
- // transformed and in the pipelines. We do not want to re-transform
885
- // a query that has already been transformed. The reason is that
886
- // we do not want a query that is already running to suddenly flip
887
- // to error due to re-calling transform.
888
- #filterCustomQueries(customQueries, byOriginalHash, onExisting) {
889
- return wrapIterable(customQueries).filter(origQuery => {
890
- const existing = byOriginalHash.get(origQuery.id);
891
- if (existing) {
892
- onExisting?.(origQuery, existing);
893
- return false;
894
- }
895
- return true;
896
- });
897
- }
898
- // This must be called from within the #lock.
899
- #addAndRemoveQueries(lc, cvr, addQueries, removeQueries, unhydrateQueries, hashToIDs) {
900
- return startAsyncSpan(tracer, 'vs.#addAndRemoveQueries', async () => {
901
- assert(addQueries.length > 0 ||
902
- removeQueries.length > 0 ||
903
- unhydrateQueries.length > 0, 'Must have queries to add or remove');
904
- const start = performance.now();
905
- const stateVersion = this.#pipelines.currentVersion();
906
- lc = lc.withContext('stateVersion', stateVersion);
907
- lc.info?.(`hydrating ${addQueries.length} queries`);
908
- const updater = new CVRQueryDrivenUpdater(this.#cvrStore, cvr, stateVersion, this.#pipelines.replicaVersion);
909
- // Note: This kicks off background PG queries for CVR data associated with the
910
- // executed and removed queries.
911
- const { newVersion, queryPatches } = updater.trackQueries(lc, addQueries, removeQueries);
912
- const clients = this.#getClients();
913
- const pokers = startPoke(clients, newVersion, this.#pipelines.currentSchemaVersions());
914
- for (const patch of queryPatches) {
915
- await pokers.addPatch(patch);
916
- }
917
- // Removing queries is easy. The pipelines are dropped, and the CVR
918
- // updater handles the updates and pokes.
919
- for (const q of removeQueries) {
920
- if (q.transformationHash) {
921
- this.#pipelines.removeQuery(q.transformationHash);
922
- }
923
- // Remove per-query server metrics when query is deleted
924
- this.#inspectorDelegate.removeQuery(q.id);
925
- }
926
- for (const hash of unhydrateQueries) {
927
- this.#pipelines.removeQuery(hash);
928
- // Remove per-query server metrics for unhydrated queries
929
- const ids = hashToIDs.get(hash);
930
- if (ids) {
931
- for (const id of ids) {
932
- this.#inspectorDelegate.removeQuery(id);
933
- }
934
- }
935
- }
936
- let totalProcessTime = 0;
937
- const timer = new TimeSliceTimer();
938
- const pipelines = this.#pipelines;
939
- const hydrations = this.#hydrations;
940
- const hydrationTime = this.#hydrationTime;
941
- // oxlint-disable-next-line @typescript-eslint/no-this-alias
942
- const self = this;
943
- // yield at the very beginning so that the first time slice
944
- // is properly processed by the time-slice queue.
945
- await yieldProcess();
946
- function* generateRowChanges(slowHydrateThreshold) {
947
- for (const q of addQueries) {
948
- lc = lc
949
- .withContext('hash', q.id)
950
- .withContext('transformationHash', q.transformationHash);
951
- lc.debug?.(`adding pipeline for query`, q.ast);
952
- yield* pipelines.addQuery(q.transformationHash, q.id, q.ast, timer.startWithoutYielding());
953
- const elapsed = timer.stop();
954
- totalProcessTime += elapsed;
955
- self.#addQueryMaterializationServerMetric(q.transformationHash, elapsed);
956
- if (elapsed > slowHydrateThreshold) {
957
- lc.warn?.('Slow query materialization', elapsed, q.ast);
958
- }
959
- manualSpan(tracer, 'vs.addAndConsumeQuery', elapsed, {
960
- hash: q.id,
961
- transformationHash: q.transformationHash,
962
- });
963
- }
964
- hydrations.add(1);
965
- hydrationTime.record(totalProcessTime / 1000);
966
- }
967
- // #processChanges does batched de-duping of rows. Wrap all pipelines in
968
- // a single generator in order to maximize de-duping.
969
- await this.#processChanges(lc, timer, generateRowChanges(this.#slowHydrateThreshold), updater, pokers, hashToIDs);
970
- for (const patch of await updater.deleteUnreferencedRows(lc)) {
971
- await pokers.addPatch(patch);
972
- }
973
- // Commit the changes and update the CVR snapshot.
974
- this.#cvr = await this.#flushUpdater(lc, updater);
975
- const finalVersion = this.#cvr.version;
976
- // Before ending the poke, catch up clients that were behind the old CVR.
977
- await this.#catchupClients(lc, cvr, finalVersion, addQueries.map(q => q.id), pokers);
978
- // Signal clients to commit.
979
- await pokers.end(finalVersion);
980
- const wallTime = performance.now() - start;
981
- lc.info?.(`finished processing queries (process: ${totalProcessTime} ms, wall: ${wallTime} ms)`);
982
- });
983
- }
984
- /**
985
- * @param cvr The CVR to which clients should be caught up to. This does
986
- * not necessarily need to be the current CVR.
987
- * @param current The expected current CVR version. Before performing
988
- * catchup, the snapshot read will verify that the CVR has not been
989
- * concurrently modified. Note that this only needs to be done for
990
- * catchup because it is the only time data from the CVR DB is
991
- * "exported" without being gated by a CVR flush (which provides
992
- * concurrency protection in all other cases).
993
- *
994
- * If unspecified, the version of the `cvr` is used.
995
- * @param excludeQueryHashes Exclude patches from rows associated with
996
- * the specified queries.
997
- * @param usePokers If specified, sends pokes on existing PokeHandlers,
998
- * in which case the caller is responsible for sending the `pokeEnd`
999
- * messages. If unspecified, the pokes will be started and ended
1000
- * using the version from the supplied `cvr`.
1001
- */
1002
- // Must be called within #lock
1003
- #catchupClients(lc, cvr, current, excludeQueryHashes = [], usePokers) {
1004
- return startAsyncSpan(tracer, 'vs.#catchupClients', async (span) => {
1005
- current ??= cvr.version;
1006
- const clients = this.#getClients();
1007
- const pokers = usePokers ??
1008
- startPoke(clients, cvr.version, this.#pipelines.currentSchemaVersions());
1009
- span.setAttribute('numClients', clients.length);
1010
- const catchupFrom = clients
1011
- .map(c => c.version())
1012
- .reduce((a, b) => (cmpVersions(a, b) < 0 ? a : b), cvr.version);
1013
- // This is an AsyncGenerator which won't execute until awaited.
1014
- const rowPatches = this.#cvrStore.catchupRowPatches(lc, catchupFrom, cvr, current, excludeQueryHashes);
1015
- // This is a plain async function that kicks off immediately.
1016
- const configPatches = this.#cvrStore.catchupConfigPatches(lc, catchupFrom, cvr, current);
1017
- // await the rowPatches first so that the AsyncGenerator kicks off.
1018
- let rowPatchCount = 0;
1019
- for await (const rows of rowPatches) {
1020
- for (const row of rows) {
1021
- const { schema, table } = row;
1022
- const rowKey = row.rowKey;
1023
- const toVersion = versionFromString(row.patchVersion);
1024
- const id = { schema, table, rowKey };
1025
- let patch;
1026
- if (!row.refCounts) {
1027
- patch = { type: 'row', op: 'del', id };
1028
- }
1029
- else {
1030
- const row = must(this.#pipelines.getRow(table, rowKey), `Missing row ${table}:${stringify(rowKey)}`);
1031
- const { contents } = contentsAndVersion(row);
1032
- patch = { type: 'row', op: 'put', id, contents };
1033
- }
1034
- const patchToVersion = { patch, toVersion };
1035
- await pokers.addPatch(patchToVersion);
1036
- rowPatchCount++;
1037
- }
1038
- }
1039
- span.setAttribute('rowPatchCount', rowPatchCount);
1040
- if (rowPatchCount) {
1041
- lc.debug?.(`sent ${rowPatchCount} row patches`);
1042
- }
1043
- // Then await the config patches which were fetched in parallel.
1044
- for (const patch of await configPatches) {
1045
- await pokers.addPatch(patch);
1046
- }
1047
- if (!usePokers) {
1048
- await pokers.end(cvr.version);
1049
- }
1050
- });
1051
- }
1052
- #processChanges(lc, timer, changes, updater, pokers, hashToIDs) {
1053
- return startAsyncSpan(tracer, 'vs.#processChanges', async () => {
1054
- const start = performance.now();
1055
- const rows = new CustomKeyMap(rowIDString);
1056
- let total = 0;
1057
- const processBatch = () => startAsyncSpan(tracer, 'processBatch', async () => {
1058
- const wallElapsed = performance.now() - start;
1059
- total += rows.size;
1060
- lc.debug?.(`processing ${rows.size} (of ${total}) rows (${wallElapsed} ms)`);
1061
- const patches = await updater.received(lc, rows);
1062
- for (const patch of patches) {
1063
- await pokers.addPatch(patch);
1064
- }
1065
- rows.clear();
1066
- });
1067
- await startAsyncSpan(tracer, 'loopingChanges', async (span) => {
1068
- for (const change of changes) {
1069
- const { type, queryHash: transformationHash, table, rowKey, row, } = change;
1070
- const queryIDs = must(hashToIDs.get(transformationHash), 'could not find the original hash for the transformation hash');
1071
- const rowID = { schema: '', table, rowKey: rowKey };
1072
- let parsedRow = rows.get(rowID);
1073
- if (!parsedRow) {
1074
- parsedRow = { refCounts: {} };
1075
- rows.set(rowID, parsedRow);
1076
- }
1077
- queryIDs.forEach(hash => (parsedRow.refCounts[hash] ??= 0));
1078
- const updateVersion = (row) => {
1079
- // IVM can output multiple versions of a row as it goes through its
1080
- // intermediate stages. Always update the version and contents;
1081
- // the last version will reflect the final state.
1082
- const { version, contents } = contentsAndVersion(row);
1083
- parsedRow.version = version;
1084
- parsedRow.contents = contents;
1085
- };
1086
- switch (type) {
1087
- case 'add':
1088
- updateVersion(row);
1089
- queryIDs.forEach(hash => parsedRow.refCounts[hash]++);
1090
- break;
1091
- case 'edit':
1092
- updateVersion(row);
1093
- // No update to refCounts.
1094
- break;
1095
- case 'remove':
1096
- queryIDs.forEach(hash => parsedRow.refCounts[hash]--);
1097
- break;
1098
- default:
1099
- unreachable(type);
1100
- }
1101
- if (rows.size % CURSOR_PAGE_SIZE === 0) {
1102
- await processBatch();
1103
- }
1104
- if (rows.size % TIME_SLICE_CHECK_SIZE === 0) {
1105
- if (timer.elapsedLap() > TIME_SLICE_MS) {
1106
- await timer.yieldProcess();
1107
- }
1108
- }
1109
- }
1110
- if (rows.size) {
1111
- await processBatch();
1112
- }
1113
- span.setAttribute('totalRows', total);
1114
- });
1115
- });
1116
- }
1117
- /**
1118
- * Advance to the current snapshot of the replica and apply / send
1119
- * changes.
1120
- *
1121
- * Must be called from within the #lock.
1122
- *
1123
- * Returns false if the advancement failed due to a schema change.
1124
- */
1125
- #advancePipelines(lc, cvr) {
1126
- return startAsyncSpan(tracer, 'vs.#advancePipelines', async () => {
1127
- assert(this.#pipelines.initialized(), 'pipelines must be initialized (advancePipelines');
1128
- const start = performance.now();
1129
- const timer = new TimeSliceTimer();
1130
- const { version, numChanges, changes } = this.#pipelines.advance(timer);
1131
- lc = lc.withContext('newVersion', version);
1132
- // Probably need a new updater type. CVRAdvancementUpdater?
1133
- const updater = new CVRQueryDrivenUpdater(this.#cvrStore, cvr, version, this.#pipelines.replicaVersion);
1134
- // Only poke clients that are at the cvr.version. New clients that
1135
- // are behind need to first be caught up when their initConnection
1136
- // message is processed (and #syncQueryPipelines is called).
1137
- const pokers = startPoke(this.#getClients(cvr.version), updater.updatedVersion(), this.#pipelines.currentSchemaVersions());
1138
- lc.debug?.(`applying ${numChanges} to advance to ${version}`);
1139
- const hashToIDs = createHashToIDs(cvr);
1140
- try {
1141
- await this.#processChanges(lc, await timer.start(), changes, updater, pokers, hashToIDs);
1142
- }
1143
- catch (e) {
1144
- if (e instanceof ResetPipelinesSignal) {
1145
- await pokers.cancel();
1146
- return e;
1147
- }
1148
- throw e;
1149
- }
1150
- // Commit the changes and update the CVR snapshot.
1151
- this.#cvr = await this.#flushUpdater(lc, updater);
1152
- const finalVersion = this.#cvr.version;
1153
- // Signal clients to commit.
1154
- await pokers.end(finalVersion);
1155
- const elapsed = performance.now() - start;
1156
- lc.info?.(`finished processing advancement of ${numChanges} changes (${elapsed} ms)`);
1157
- this.#transactionAdvanceTime.record(elapsed / 1000);
1158
- return 'success';
1159
- });
1160
- }
1161
- inspect(context, msg) {
1162
- return this.#runInLockForClient(context, msg, this.#handleInspect);
1163
- }
1164
- // oxlint-disable-next-line require-await
1165
- #handleInspect = async (lc, clientID, body, cvr) => {
1166
- const client = must(this.#clients.get(clientID));
1167
- return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config, this.#getHeaderOptions(this.#queryConfig.forwardCookies ?? false), this.userQueryURL);
1168
- };
1169
- stop() {
1170
- this.#lc.info?.('stopping view syncer');
1171
- this.#stateChanges.cancel();
1172
- return this.#stopped.promise;
1173
- }
1174
- #cleanup(err) {
1175
- this.#stopTTLClockInterval();
1176
- this.#stopExpireTimer();
1177
- this.#pipelines.destroy();
1178
- for (const client of this.#clients.values()) {
1179
- if (err) {
1180
- client.fail(err);
1181
- }
1182
- else {
1183
- client.close(`closed clientGroupID=${this.id}`);
1184
- }
1330
+ span.setAttribute("totalRows", total);
1331
+ });
1332
+ });
1333
+ }
1334
+ /**
1335
+ * Advance to the current snapshot of the replica and apply / send
1336
+ * changes.
1337
+ *
1338
+ * Must be called from within the #lock.
1339
+ *
1340
+ * Returns false if the advancement failed due to a schema change.
1341
+ */
1342
+ #advancePipelines(lc, cvr) {
1343
+ return startAsyncSpan(tracer, "vs.#advancePipelines", async () => {
1344
+ assert(
1345
+ this.#pipelines.initialized(),
1346
+ "pipelines must be initialized (advancePipelines"
1347
+ );
1348
+ const start = performance.now();
1349
+ const timer = new TimeSliceTimer();
1350
+ const { version: version2, numChanges, changes } = this.#pipelines.advance(timer);
1351
+ lc = lc.withContext("newVersion", version2);
1352
+ const updater = new CVRQueryDrivenUpdater(
1353
+ this.#cvrStore,
1354
+ cvr,
1355
+ version2,
1356
+ this.#pipelines.replicaVersion
1357
+ );
1358
+ const pokers = startPoke(
1359
+ this.#getClients(cvr.version),
1360
+ updater.updatedVersion(),
1361
+ this.#pipelines.currentSchemaVersions()
1362
+ );
1363
+ lc.debug?.(`applying ${numChanges} to advance to ${version2}`);
1364
+ const hashToIDs = createHashToIDs(cvr);
1365
+ try {
1366
+ await this.#processChanges(
1367
+ lc,
1368
+ await timer.start(),
1369
+ changes,
1370
+ updater,
1371
+ pokers,
1372
+ hashToIDs
1373
+ );
1374
+ } catch (e) {
1375
+ if (e instanceof ResetPipelinesSignal) {
1376
+ await pokers.cancel();
1377
+ return e;
1185
1378
  }
1379
+ throw e;
1380
+ }
1381
+ this.#cvr = await this.#flushUpdater(lc, updater);
1382
+ const finalVersion = this.#cvr.version;
1383
+ await pokers.end(finalVersion);
1384
+ const elapsed = performance.now() - start;
1385
+ lc.info?.(
1386
+ `finished processing advancement of ${numChanges} changes (${elapsed} ms)`
1387
+ );
1388
+ this.#transactionAdvanceTime.record(elapsed / 1e3);
1389
+ return "success";
1390
+ });
1391
+ }
1392
+ inspect(context, msg) {
1393
+ return this.#runInLockForClient(context, msg, this.#handleInspect);
1394
+ }
1395
+ // oxlint-disable-next-line require-await
1396
+ #handleInspect = async (lc, clientID, body, cvr) => {
1397
+ const client = must(this.#clients.get(clientID));
1398
+ return handleInspect(
1399
+ lc,
1400
+ body,
1401
+ cvr,
1402
+ client,
1403
+ this.#inspectorDelegate,
1404
+ this.id,
1405
+ this.#cvrStore,
1406
+ this.#config,
1407
+ this.#getHeaderOptions(this.#queryConfig.forwardCookies ?? false),
1408
+ this.userQueryURL,
1409
+ this.#authData
1410
+ );
1411
+ };
1412
+ stop() {
1413
+ this.#lc.info?.("stopping view syncer");
1414
+ this.#initialized.reject("shut down before initialization completed");
1415
+ this.#stateChanges.cancel();
1416
+ return this.#stopped.promise;
1417
+ }
1418
+ #cleanup(err) {
1419
+ this.#stopTTLClockInterval();
1420
+ this.#stopExpireTimer();
1421
+ this.#pipelines.destroy();
1422
+ for (const client of this.#clients.values()) {
1423
+ if (err) {
1424
+ client.fail(err);
1425
+ } else {
1426
+ client.close(`closed clientGroupID=${this.id}`);
1427
+ }
1186
1428
  }
1429
+ }
1430
+ /**
1431
+ * Test helper: Manually mark initialization as complete.
1432
+ * This should only be used in tests that don't call initConnection().
1433
+ */
1434
+ markInitialized() {
1435
+ this.#initialized.resolve("initialized");
1436
+ }
1187
1437
  }
1188
- // Update CVR after every 10000 rows.
1189
- const CURSOR_PAGE_SIZE = 10000;
1190
- // Check the elapsed time every 100 rows.
1438
+ const CURSOR_PAGE_SIZE = 1e4;
1191
1439
  const TIME_SLICE_CHECK_SIZE = 100;
1192
- // Yield the process after churning for > 500ms.
1193
1440
  const TIME_SLICE_MS = 500;
1194
1441
  function createHashToIDs(cvr) {
1195
- const hashToIDs = new Map();
1196
- for (const { id, transformationHash } of Object.values(cvr.queries)) {
1197
- if (!transformationHash) {
1198
- continue;
1199
- }
1200
- if (hashToIDs.has(transformationHash)) {
1201
- must(hashToIDs.get(transformationHash)).push(id);
1202
- }
1203
- else {
1204
- hashToIDs.set(transformationHash, [id]);
1205
- }
1442
+ const hashToIDs = /* @__PURE__ */ new Map();
1443
+ for (const { id, transformationHash } of Object.values(cvr.queries)) {
1444
+ if (!transformationHash) {
1445
+ continue;
1446
+ }
1447
+ if (hashToIDs.has(transformationHash)) {
1448
+ must(hashToIDs.get(transformationHash)).push(id);
1449
+ } else {
1450
+ hashToIDs.set(transformationHash, [id]);
1206
1451
  }
1207
- return hashToIDs;
1452
+ }
1453
+ return hashToIDs;
1208
1454
  }
1209
- // A global Lock acts as a queue to run a single IVM time slice per iteration
1210
- // of the node event loop, thus bounding I/O delay to the duration of a single
1211
- // time slice.
1212
- //
1213
- // Refresher:
1214
- // https://nodejs.org/en/learn/asynchronous-work/event-loop-timers-and-nexttick#phases-overview
1215
- //
1216
- // Note that recursive use of setImmediate() (i.e. calling setImmediate() from
1217
- // within a setImmediate() callback), results in enqueuing the latter
1218
- // callback in the *next* event loop iteration, as documented in:
1219
- // https://nodejs.org/api/timers.html#setimmediatecallback-args
1220
- //
1221
- // This effectively achieves the desired one-per-event-loop-iteration behavior.
1222
1455
  const timeSliceQueue = new Lock();
1223
1456
  function yieldProcess() {
1224
- return timeSliceQueue.withLock(() => new Promise(setImmediate));
1457
+ return timeSliceQueue.withLock(() => new Promise(setImmediate));
1225
1458
  }
1226
1459
  function contentsAndVersion(row) {
1227
- const { [ZERO_VERSION_COLUMN_NAME]: version, ...contents } = row;
1228
- if (typeof version !== 'string' || version.length === 0) {
1229
- throw new Error(`Invalid _0_version in ${stringify(row)}`);
1230
- }
1231
- return { contents, version };
1460
+ const { [ZERO_VERSION_COLUMN_NAME]: version2, ...contents } = row;
1461
+ if (typeof version2 !== "string" || version2.length === 0) {
1462
+ throw new Error(`Invalid _0_version in ${stringify(row)}`);
1463
+ }
1464
+ return { contents, version: version2 };
1232
1465
  }
1233
- const NEW_CVR_VERSION = { stateVersion: '00' };
1466
+ const NEW_CVR_VERSION = { stateVersion: "00" };
1234
1467
  function checkClientAndCVRVersions(client, cvr) {
1235
- if (cmpVersions(cvr, NEW_CVR_VERSION) === 0 &&
1236
- cmpVersions(client, NEW_CVR_VERSION) > 0) {
1237
- // CVR is empty but client is not.
1238
- throw new ProtocolError({
1239
- kind: ErrorKind.ClientNotFound,
1240
- message: 'Client not found',
1241
- origin: ErrorOrigin.ZeroCache,
1242
- });
1468
+ if (cmpVersions(cvr, NEW_CVR_VERSION) === 0 && cmpVersions(client, NEW_CVR_VERSION) > 0) {
1469
+ throw new ProtocolErrorWithLevel({
1470
+ kind: ClientNotFound,
1471
+ message: "Client not found",
1472
+ origin: ZeroCache
1473
+ });
1474
+ }
1475
+ if (cmpVersions(client, cvr) > 0) {
1476
+ throw new ProtocolError({
1477
+ kind: InvalidConnectionRequestBaseCookie,
1478
+ message: `CVR is at version ${versionString(cvr)}`,
1479
+ origin: ZeroCache
1480
+ });
1481
+ }
1482
+ }
1483
+ function pickToken(lc, previousToken, newToken) {
1484
+ if (previousToken === void 0) {
1485
+ lc.debug?.(`No previous token, using new token`);
1486
+ return newToken;
1487
+ }
1488
+ if (newToken) {
1489
+ if (previousToken.decoded.sub !== newToken.decoded.sub) {
1490
+ throw new ProtocolError({
1491
+ kind: Unauthorized,
1492
+ message: "The user id in the new token does not match the previous token. Client groups are pinned to a single user.",
1493
+ origin: ZeroCache
1494
+ });
1243
1495
  }
1244
- if (cmpVersions(client, cvr) > 0) {
1245
- // Client is ahead of a non-empty CVR.
1246
- throw new ProtocolError({
1247
- kind: ErrorKind.InvalidConnectionRequestBaseCookie,
1248
- message: `CVR is at version ${versionString(cvr)}`,
1249
- origin: ErrorOrigin.ZeroCache,
1250
- });
1496
+ if (previousToken.decoded.iat === void 0) {
1497
+ lc.debug?.(`No issued at time for the existing token, using new token`);
1498
+ return newToken;
1251
1499
  }
1252
- }
1253
- export function pickToken(lc, previousToken, newToken) {
1254
- if (previousToken === undefined) {
1255
- lc.debug?.(`No previous token, using new token`);
1256
- return newToken;
1500
+ if (newToken.decoded.iat === void 0) {
1501
+ throw new ProtocolError({
1502
+ kind: Unauthorized,
1503
+ message: "The new token does not have an issued at time but the prior token does. Tokens for a client group must either all have issued at times or all not have issued at times",
1504
+ origin: ZeroCache
1505
+ });
1257
1506
  }
1258
- if (newToken) {
1259
- if (previousToken.decoded.sub !== newToken.decoded.sub) {
1260
- throw new ProtocolError({
1261
- kind: ErrorKind.Unauthorized,
1262
- message: 'The user id in the new token does not match the previous token. Client groups are pinned to a single user.',
1263
- origin: ErrorOrigin.ZeroCache,
1264
- });
1265
- }
1266
- if (previousToken.decoded.iat === undefined) {
1267
- lc.debug?.(`No issued at time for the existing token, using new token`);
1268
- // No issued at time for the existing token? We take the most recently received token.
1269
- return newToken;
1270
- }
1271
- if (newToken.decoded.iat === undefined) {
1272
- throw new ProtocolError({
1273
- kind: ErrorKind.Unauthorized,
1274
- message: 'The new token does not have an issued at time but the prior token does. Tokens for a client group must either all have issued at times or all not have issued at times',
1275
- origin: ErrorOrigin.ZeroCache,
1276
- });
1277
- }
1278
- // The new token is newer, so we take it.
1279
- if (previousToken.decoded.iat < newToken.decoded.iat) {
1280
- lc.debug?.(`New token is newer, using it`);
1281
- return newToken;
1282
- }
1283
- // if the new token is older or the same, we keep the existing token.
1284
- lc.debug?.(`New token is older or the same, using existing token`);
1285
- return previousToken;
1507
+ if (previousToken.decoded.iat < newToken.decoded.iat) {
1508
+ lc.debug?.(`New token is newer, using it`);
1509
+ return newToken;
1286
1510
  }
1287
- // previousToken !== undefined but newToken is undefined
1288
- throw new ProtocolError({
1289
- kind: ErrorKind.Unauthorized,
1290
- message: 'No token provided. An unauthenticated client cannot connect to an authenticated client group.',
1291
- origin: ErrorOrigin.ZeroCache,
1292
- });
1511
+ lc.debug?.(`New token is older or the same, using existing token`);
1512
+ return previousToken;
1513
+ }
1514
+ throw new ProtocolError({
1515
+ kind: Unauthorized,
1516
+ message: "No token provided. An unauthenticated client cannot connect to an authenticated client group.",
1517
+ origin: ZeroCache
1518
+ });
1293
1519
  }
1294
- /**
1295
- * A query must be expired for all clients in order to be considered
1296
- * expired.
1297
- */
1298
1520
  function expired(ttlClock, q) {
1299
- if (q.type === 'internal') {
1300
- return false;
1521
+ if (q.type === "internal") {
1522
+ return false;
1523
+ }
1524
+ for (const clientState of Object.values(q.clientState)) {
1525
+ const { ttl, inactivatedAt } = clientState;
1526
+ if (inactivatedAt === void 0) {
1527
+ return false;
1301
1528
  }
1302
- for (const clientState of Object.values(q.clientState)) {
1303
- const { ttl, inactivatedAt } = clientState;
1304
- if (inactivatedAt === undefined) {
1305
- return false;
1306
- }
1307
- const clampedTTL = clampTTL(ttl);
1308
- if (ttlClockAsNumber(inactivatedAt) + clampedTTL >
1309
- ttlClockAsNumber(ttlClock)) {
1310
- return false;
1311
- }
1529
+ const clampedTTL = clampTTL(ttl);
1530
+ if (ttlClockAsNumber(inactivatedAt) + clampedTTL > ttlClockAsNumber(ttlClock)) {
1531
+ return false;
1312
1532
  }
1313
- return true;
1533
+ }
1534
+ return true;
1314
1535
  }
1315
1536
  function hasExpiredQueries(cvr) {
1316
- const { ttlClock } = cvr;
1317
- for (const q of Object.values(cvr.queries)) {
1318
- if (expired(ttlClock, q)) {
1319
- return true;
1320
- }
1537
+ const { ttlClock } = cvr;
1538
+ for (const q of Object.values(cvr.queries)) {
1539
+ if (expired(ttlClock, q)) {
1540
+ return true;
1321
1541
  }
1322
- return false;
1542
+ }
1543
+ return false;
1323
1544
  }
1324
- export class TimeSliceTimer {
1325
- #total = 0;
1326
- #start = 0;
1327
- async start() {
1328
- // yield at the very beginning so that the first time slice
1329
- // is properly processed by the time-slice queue.
1330
- await yieldProcess();
1331
- return this.startWithoutYielding();
1332
- }
1333
- startWithoutYielding() {
1334
- this.#total = 0;
1335
- this.#startLap();
1336
- return this;
1337
- }
1338
- async yieldProcess() {
1339
- this.#stopLap();
1340
- await yieldProcess();
1341
- this.#startLap();
1342
- }
1343
- #startLap() {
1344
- assert(this.#start === 0, 'already running');
1345
- this.#start = performance.now();
1346
- }
1347
- elapsedLap() {
1348
- assert(this.#start !== 0, 'not running');
1349
- return performance.now() - this.#start;
1350
- }
1351
- #stopLap() {
1352
- assert(this.#start !== 0, 'not running');
1353
- this.#total += performance.now() - this.#start;
1354
- this.#start = 0;
1355
- }
1356
- /** @returns the total elapsed time */
1357
- stop() {
1358
- this.#stopLap();
1359
- return this.#total;
1360
- }
1361
- /**
1362
- * @returns the elapsed time. This can be called while the Timer is running
1363
- * or after it has been stopped.
1364
- */
1365
- totalElapsed() {
1366
- return this.#start === 0
1367
- ? this.#total
1368
- : this.#total + performance.now() - this.#start;
1369
- }
1545
+ class TimeSliceTimer {
1546
+ #total = 0;
1547
+ #start = 0;
1548
+ async start() {
1549
+ await yieldProcess();
1550
+ return this.startWithoutYielding();
1551
+ }
1552
+ startWithoutYielding() {
1553
+ this.#total = 0;
1554
+ this.#startLap();
1555
+ return this;
1556
+ }
1557
+ async yieldProcess() {
1558
+ this.#stopLap();
1559
+ await yieldProcess();
1560
+ this.#startLap();
1561
+ }
1562
+ #startLap() {
1563
+ assert(this.#start === 0, "already running");
1564
+ this.#start = performance.now();
1565
+ }
1566
+ elapsedLap() {
1567
+ assert(this.#start !== 0, "not running");
1568
+ return performance.now() - this.#start;
1569
+ }
1570
+ #stopLap() {
1571
+ assert(this.#start !== 0, "not running");
1572
+ this.#total += performance.now() - this.#start;
1573
+ this.#start = 0;
1574
+ }
1575
+ /** @returns the total elapsed time */
1576
+ stop() {
1577
+ this.#stopLap();
1578
+ return this.#total;
1579
+ }
1580
+ /**
1581
+ * @returns the elapsed time. This can be called while the Timer is running
1582
+ * or after it has been stopped.
1583
+ */
1584
+ totalElapsed() {
1585
+ return this.#start === 0 ? this.#total : this.#total + performance.now() - this.#start;
1586
+ }
1370
1587
  }
1371
- //# sourceMappingURL=view-syncer.js.map
1588
+ export {
1589
+ TTL_CLOCK_INTERVAL,
1590
+ TTL_TIMER_HYSTERESIS,
1591
+ TimeSliceTimer,
1592
+ ViewSyncerService,
1593
+ pickToken
1594
+ };
1595
+ //# sourceMappingURL=view-syncer.js.map