@rocicorp/zero 1.3.0 → 1.4.0-canary.1

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 (332) hide show
  1. package/out/analyze-query/src/analyze-cli.d.ts +24 -0
  2. package/out/analyze-query/src/analyze-cli.d.ts.map +1 -0
  3. package/out/analyze-query/src/analyze-cli.js +289 -0
  4. package/out/analyze-query/src/analyze-cli.js.map +1 -0
  5. package/out/analyze-query/src/bin-analyze.js +6 -6
  6. package/out/analyze-query/src/bin-transform.js +2 -2
  7. package/out/ast-to-zql/src/bin.js +1 -1
  8. package/out/shared/src/logging.d.ts.map +1 -1
  9. package/out/shared/src/logging.js +1 -1
  10. package/out/shared/src/logging.js.map +1 -1
  11. package/out/shared/src/options.d.ts.map +1 -1
  12. package/out/shared/src/options.js +1 -1
  13. package/out/shared/src/options.js.map +1 -1
  14. package/out/z2s/src/compiler.d.ts.map +1 -1
  15. package/out/z2s/src/compiler.js +4 -1
  16. package/out/z2s/src/compiler.js.map +1 -1
  17. package/out/z2s/src/sql.d.ts.map +1 -1
  18. package/out/z2s/src/sql.js +1 -0
  19. package/out/z2s/src/sql.js.map +1 -1
  20. package/out/zero/package.js +95 -89
  21. package/out/zero/package.js.map +1 -1
  22. package/out/zero/src/analyze.d.ts +2 -0
  23. package/out/zero/src/analyze.d.ts.map +1 -0
  24. package/out/zero/src/analyze.js +2 -0
  25. package/out/zero/src/bindings.js +1 -1
  26. package/out/zero/src/zero-cache-dev.js +1 -1
  27. package/out/zero/src/zero-cache-dev.js.map +1 -1
  28. package/out/zero/src/zero-out.js +1 -1
  29. package/out/zero-cache/src/auth/auth.d.ts.map +1 -1
  30. package/out/zero-cache/src/auth/auth.js.map +1 -1
  31. package/out/zero-cache/src/auth/load-permissions.js +2 -2
  32. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  33. package/out/zero-cache/src/auth/write-authorizer.js +5 -14
  34. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  35. package/out/zero-cache/src/config/network.d.ts +1 -1
  36. package/out/zero-cache/src/config/network.d.ts.map +1 -1
  37. package/out/zero-cache/src/config/network.js +1 -1
  38. package/out/zero-cache/src/config/network.js.map +1 -1
  39. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  40. package/out/zero-cache/src/config/normalize.js.map +1 -1
  41. package/out/zero-cache/src/config/zero-config.d.ts +5 -0
  42. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  43. package/out/zero-cache/src/config/zero-config.js +16 -3
  44. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  45. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  46. package/out/zero-cache/src/db/lite-tables.js +3 -3
  47. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  48. package/out/zero-cache/src/db/transaction-pool.d.ts +43 -40
  49. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  50. package/out/zero-cache/src/db/transaction-pool.js +76 -56
  51. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  52. package/out/zero-cache/src/observability/events.d.ts.map +1 -1
  53. package/out/zero-cache/src/observability/events.js +1 -1
  54. package/out/zero-cache/src/observability/events.js.map +1 -1
  55. package/out/zero-cache/src/scripts/decommission.js +1 -1
  56. package/out/zero-cache/src/scripts/deploy-permissions.js +2 -2
  57. package/out/zero-cache/src/scripts/permissions.js +1 -1
  58. package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
  59. package/out/zero-cache/src/server/anonymous-otel-start.js +4 -4
  60. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  61. package/out/zero-cache/src/server/change-streamer.d.ts +1 -1
  62. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  63. package/out/zero-cache/src/server/change-streamer.js +27 -12
  64. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  65. package/out/zero-cache/src/server/logging.d.ts +1 -3
  66. package/out/zero-cache/src/server/logging.d.ts.map +1 -1
  67. package/out/zero-cache/src/server/logging.js +6 -3
  68. package/out/zero-cache/src/server/logging.js.map +1 -1
  69. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  70. package/out/zero-cache/src/server/main.js +26 -26
  71. package/out/zero-cache/src/server/main.js.map +1 -1
  72. package/out/zero-cache/src/server/mutator.js +4 -2
  73. package/out/zero-cache/src/server/mutator.js.map +1 -1
  74. package/out/zero-cache/src/server/otel-log-sink.d.ts.map +1 -1
  75. package/out/zero-cache/src/server/otel-log-sink.js +0 -2
  76. package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
  77. package/out/zero-cache/src/server/otel-start.d.ts +1 -1
  78. package/out/zero-cache/src/server/otel-start.d.ts.map +1 -1
  79. package/out/zero-cache/src/server/otel-start.js +7 -3
  80. package/out/zero-cache/src/server/otel-start.js.map +1 -1
  81. package/out/zero-cache/src/server/reaper.js +6 -6
  82. package/out/zero-cache/src/server/reaper.js.map +1 -1
  83. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  84. package/out/zero-cache/src/server/replicator.js +5 -3
  85. package/out/zero-cache/src/server/replicator.js.map +1 -1
  86. package/out/zero-cache/src/server/runner/run-worker.js +2 -2
  87. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  88. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  89. package/out/zero-cache/src/server/syncer.js +13 -12
  90. package/out/zero-cache/src/server/syncer.js.map +1 -1
  91. package/out/zero-cache/src/server/worker-dispatcher.js +1 -1
  92. package/out/zero-cache/src/services/analyze.js +1 -1
  93. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +1 -1
  94. package/out/zero-cache/src/services/change-source/common/replica-schema.js +1 -1
  95. package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -2
  96. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +4 -1
  97. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  98. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  99. package/out/zero-cache/src/services/change-source/pg/change-source.js +19 -23
  100. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  101. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +58 -3
  102. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  103. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +209 -52
  104. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  105. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +2 -2
  106. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +24 -15
  107. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  108. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +35 -58
  109. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  110. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  111. package/out/zero-cache/src/services/change-source/pg/schema/init.js +2 -2
  112. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  113. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +1 -2
  114. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
  115. package/out/zero-cache/src/services/change-source/pg/schema/published.js +15 -18
  116. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
  117. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -1
  118. package/out/zero-cache/src/services/change-source/protocol/current/data.js +1 -1
  119. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +1 -1
  120. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +1 -1
  121. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  122. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +1 -1
  123. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  124. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +5 -1
  125. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  126. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +10 -7
  127. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  128. package/out/zero-cache/src/services/change-streamer/replica-monitor.js +2 -2
  129. package/out/zero-cache/src/services/change-streamer/storer.d.ts +19 -2
  130. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  131. package/out/zero-cache/src/services/change-streamer/storer.js +70 -6
  132. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  133. package/out/zero-cache/src/services/heapz.d.ts.map +1 -1
  134. package/out/zero-cache/src/services/heapz.js +1 -1
  135. package/out/zero-cache/src/services/heapz.js.map +1 -1
  136. package/out/zero-cache/src/services/life-cycle.d.ts +2 -1
  137. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  138. package/out/zero-cache/src/services/life-cycle.js +10 -7
  139. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  140. package/out/zero-cache/src/services/litestream/commands.d.ts +15 -4
  141. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  142. package/out/zero-cache/src/services/litestream/commands.js +40 -34
  143. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  144. package/out/zero-cache/src/services/mutagen/mutagen.js +3 -3
  145. package/out/zero-cache/src/services/mutagen/pusher.d.ts +28 -28
  146. package/out/zero-cache/src/services/replicator/change-processor.js +2 -2
  147. package/out/zero-cache/src/services/replicator/incremental-sync.js +1 -1
  148. package/out/zero-cache/src/services/replicator/schema/replication-state.js +1 -1
  149. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  150. package/out/zero-cache/src/services/replicator/write-worker.js +3 -3
  151. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  152. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  153. package/out/zero-cache/src/services/run-ast.js +3 -3
  154. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  155. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  156. package/out/zero-cache/src/services/statz.js +3 -3
  157. package/out/zero-cache/src/services/statz.js.map +1 -1
  158. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +1 -1
  159. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +2 -2
  160. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -1
  161. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  162. package/out/zero-cache/src/services/view-syncer/cvr-purger.js +1 -1
  163. package/out/zero-cache/src/services/view-syncer/cvr-store.js +3 -3
  164. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  165. package/out/zero-cache/src/services/view-syncer/cvr.js +1 -1
  166. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +2 -2
  167. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +6 -16
  168. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  169. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +31 -39
  170. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  171. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
  172. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +4 -4
  173. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  174. package/out/zero-cache/src/services/view-syncer/snapshotter.js +2 -2
  175. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  176. package/out/zero-cache/src/services/view-syncer/view-syncer.js +6 -6
  177. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  178. package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
  179. package/out/zero-cache/src/types/profiler.js.map +1 -1
  180. package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
  181. package/out/zero-cache/src/types/row-key.js.map +1 -1
  182. package/out/zero-cache/src/types/streams.d.ts +1 -1
  183. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  184. package/out/zero-cache/src/types/streams.js.map +1 -1
  185. package/out/zero-cache/src/types/websocket-handoff.d.ts +1 -1
  186. package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
  187. package/out/zero-cache/src/types/websocket-handoff.js +1 -1
  188. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  189. package/out/zero-cache/src/workers/connection.d.ts +1 -1
  190. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  191. package/out/zero-cache/src/workers/connection.js.map +1 -1
  192. package/out/zero-cache/src/workers/mutator.js.map +1 -1
  193. package/out/zero-cache/src/workers/syncer.d.ts +1 -1
  194. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  195. package/out/zero-cache/src/workers/syncer.js +3 -3
  196. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  197. package/out/zero-client/src/client/bindings.js +1 -1
  198. package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
  199. package/out/zero-client/src/client/crud-impl.js +4 -13
  200. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  201. package/out/zero-client/src/client/inspector/inspector.d.ts +24 -0
  202. package/out/zero-client/src/client/inspector/inspector.d.ts.map +1 -1
  203. package/out/zero-client/src/client/inspector/inspector.js +28 -0
  204. package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
  205. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts +9 -0
  206. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts.map +1 -1
  207. package/out/zero-client/src/client/inspector/lazy-inspector.js +28 -1
  208. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  209. package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
  210. package/out/zero-client/src/client/ivm-branch.js +4 -13
  211. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  212. package/out/zero-client/src/client/log-options.d.ts +1 -0
  213. package/out/zero-client/src/client/log-options.d.ts.map +1 -1
  214. package/out/zero-client/src/client/log-options.js +3 -2
  215. package/out/zero-client/src/client/log-options.js.map +1 -1
  216. package/out/zero-client/src/client/options.d.ts +13 -1
  217. package/out/zero-client/src/client/options.d.ts.map +1 -1
  218. package/out/zero-client/src/client/options.js.map +1 -1
  219. package/out/zero-client/src/client/version.js +1 -1
  220. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  221. package/out/zero-client/src/client/zero.js +2 -1
  222. package/out/zero-client/src/client/zero.js.map +1 -1
  223. package/out/zero-protocol/src/error.d.ts.map +1 -1
  224. package/out/zero-protocol/src/error.js +1 -1
  225. package/out/zero-protocol/src/error.js.map +1 -1
  226. package/out/zero-react/src/bindings.js +1 -1
  227. package/out/zero-solid/src/bindings.js +1 -1
  228. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  229. package/out/zero-solid/src/solid-view.js +14 -14
  230. package/out/zero-solid/src/solid-view.js.map +1 -1
  231. package/out/zql/src/builder/builder.d.ts.map +1 -1
  232. package/out/zql/src/builder/builder.js.map +1 -1
  233. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  234. package/out/zql/src/ivm/array-view.js +27 -2
  235. package/out/zql/src/ivm/array-view.js.map +1 -1
  236. package/out/zql/src/ivm/change-index-enum.d.ts +9 -0
  237. package/out/zql/src/ivm/change-index-enum.d.ts.map +1 -0
  238. package/out/zql/src/ivm/change-index.d.ts +5 -0
  239. package/out/zql/src/ivm/change-index.d.ts.map +1 -0
  240. package/out/zql/src/ivm/change-type-enum.d.ts +9 -0
  241. package/out/zql/src/ivm/change-type-enum.d.ts.map +1 -0
  242. package/out/zql/src/ivm/change-type.d.ts +5 -0
  243. package/out/zql/src/ivm/change-type.d.ts.map +1 -0
  244. package/out/zql/src/ivm/change.d.ts +20 -22
  245. package/out/zql/src/ivm/change.d.ts.map +1 -1
  246. package/out/zql/src/ivm/change.js +33 -0
  247. package/out/zql/src/ivm/change.js.map +1 -0
  248. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  249. package/out/zql/src/ivm/exists.js +27 -38
  250. package/out/zql/src/ivm/exists.js.map +1 -1
  251. package/out/zql/src/ivm/fan-in.d.ts +3 -2
  252. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  253. package/out/zql/src/ivm/fan-in.js.map +1 -1
  254. package/out/zql/src/ivm/fan-out.d.ts +1 -1
  255. package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
  256. package/out/zql/src/ivm/fan-out.js +1 -1
  257. package/out/zql/src/ivm/fan-out.js.map +1 -1
  258. package/out/zql/src/ivm/filter-operators.d.ts +3 -3
  259. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  260. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  261. package/out/zql/src/ivm/filter-push.d.ts.map +1 -1
  262. package/out/zql/src/ivm/filter-push.js +7 -7
  263. package/out/zql/src/ivm/filter-push.js.map +1 -1
  264. package/out/zql/src/ivm/filter.d.ts +1 -1
  265. package/out/zql/src/ivm/filter.d.ts.map +1 -1
  266. package/out/zql/src/ivm/filter.js.map +1 -1
  267. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  268. package/out/zql/src/ivm/flipped-join.js +49 -58
  269. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  270. package/out/zql/src/ivm/join-utils.d.ts +2 -6
  271. package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
  272. package/out/zql/src/ivm/join-utils.js +25 -25
  273. package/out/zql/src/ivm/join-utils.js.map +1 -1
  274. package/out/zql/src/ivm/join.d.ts.map +1 -1
  275. package/out/zql/src/ivm/join.js +32 -51
  276. package/out/zql/src/ivm/join.js.map +1 -1
  277. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
  278. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
  279. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +5 -10
  280. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  281. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  282. package/out/zql/src/ivm/memory-source.js +52 -60
  283. package/out/zql/src/ivm/memory-source.js.map +1 -1
  284. package/out/zql/src/ivm/operator.d.ts +1 -1
  285. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  286. package/out/zql/src/ivm/operator.js +2 -4
  287. package/out/zql/src/ivm/operator.js.map +1 -1
  288. package/out/zql/src/ivm/push-accumulated.d.ts +3 -2
  289. package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
  290. package/out/zql/src/ivm/push-accumulated.js +98 -122
  291. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  292. package/out/zql/src/ivm/skip-yields.d.ts +4 -0
  293. package/out/zql/src/ivm/skip-yields.d.ts.map +1 -0
  294. package/out/zql/src/ivm/skip-yields.js +33 -0
  295. package/out/zql/src/ivm/skip-yields.js.map +1 -0
  296. package/out/zql/src/ivm/skip.d.ts +1 -1
  297. package/out/zql/src/ivm/skip.d.ts.map +1 -1
  298. package/out/zql/src/ivm/skip.js +2 -2
  299. package/out/zql/src/ivm/skip.js.map +1 -1
  300. package/out/zql/src/ivm/source-change-index-enum.d.ts +7 -0
  301. package/out/zql/src/ivm/source-change-index-enum.d.ts.map +1 -0
  302. package/out/zql/src/ivm/source-change-index.d.ts +5 -0
  303. package/out/zql/src/ivm/source-change-index.d.ts.map +1 -0
  304. package/out/zql/src/ivm/source.d.ts +11 -13
  305. package/out/zql/src/ivm/source.d.ts.map +1 -1
  306. package/out/zql/src/ivm/source.js +26 -0
  307. package/out/zql/src/ivm/source.js.map +1 -0
  308. package/out/zql/src/ivm/take.d.ts.map +1 -1
  309. package/out/zql/src/ivm/take.js +27 -50
  310. package/out/zql/src/ivm/take.js.map +1 -1
  311. package/out/zql/src/ivm/union-fan-in.d.ts +2 -1
  312. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  313. package/out/zql/src/ivm/union-fan-in.js +3 -3
  314. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  315. package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
  316. package/out/zql/src/ivm/union-fan-out.js +1 -1
  317. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  318. package/out/zql/src/ivm/view-apply-change.js +1 -1
  319. package/out/zql/src/planner/planner-debug.d.ts +2 -2
  320. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  321. package/out/zql/src/planner/planner-debug.js.map +1 -1
  322. package/out/zql/src/planner/planner-graph.d.ts +1 -1
  323. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  324. package/out/zql/src/planner/planner-graph.js.map +1 -1
  325. package/out/zqlite/src/internal/sql-inline.d.ts.map +1 -1
  326. package/out/zqlite/src/internal/sql-inline.js.map +1 -1
  327. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  328. package/out/zqlite/src/query-builder.js.map +1 -1
  329. package/out/zqlite/src/table-source.d.ts.map +1 -1
  330. package/out/zqlite/src/table-source.js +11 -11
  331. package/out/zqlite/src/table-source.js.map +1 -1
  332. package/package.json +99 -93
@@ -1 +1 @@
1
- {"version":3,"file":"statz.js","names":[],"sources":["../../../../../zero-cache/src/services/statz.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport auth from 'basic-auth';\nimport type {FastifyReply, FastifyRequest} from 'fastify';\nimport fs from 'fs';\nimport os from 'os';\nimport {BigIntJSON} from '../../../shared/src/bigint-json.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport type {NormalizedZeroConfig as ZeroConfig} from '../config/normalize.ts';\nimport {isAdminPasswordValid} from '../config/zero-config.ts';\nimport {StatementRunner} from '../db/statements.ts';\nimport {pgClient} from '../types/pg.ts';\nimport {getShardID, upstreamSchema} from '../types/shards.ts';\nimport {fromStateVersionString} from './change-source/pg/lsn.ts';\nimport {getReplicationState} from './replicator/schema/replication-state.ts';\n\nasync function upstreamStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config));\n const sql = pgClient(lc, config.upstream.db);\n try {\n return await getPgStats([\n [\n 'numReplicas',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"replicas\"`,\n ],\n [\n 'numClientsWithMutations',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"clients\"`,\n ],\n [\n 'numMutationsProcessed',\n sql`SELECT SUM(\"lastMutationID\") as \"c\" FROM ${sql(schema)}.\"clients\"`,\n ],\n ]);\n } finally {\n await sql.end();\n }\n}\n\nasync function cvrStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config)) + '/cvr';\n const sql = pgClient(lc, config.cvr.db);\n\n function numQueriesPerClientGroup(\n active: boolean,\n ): ReturnType<ReturnType<typeof pgClient>> {\n const filter = active\n ? sql`WHERE \"inactivatedAt\" IS NULL AND deleted = false`\n : sql`WHERE \"inactivatedAt\" IS NOT NULL AND (\"inactivatedAt\" + \"ttl\") > NOW()`;\n return sql`WITH\n group_counts AS (\n SELECT\n \"clientGroupID\",\n COUNT(*) AS num_queries\n FROM ${sql(schema)}.\"desires\"\n ${filter}\n GROUP BY \"clientGroupID\"\n ),\n -- Count distinct clientIDs per clientGroupID\n client_per_group_counts AS (\n SELECT\n \"clientGroupID\",\n COUNT(DISTINCT \"clientID\") AS num_clients\n FROM ${sql(schema)}.\"desires\"\n ${filter}\n GROUP BY \"clientGroupID\"\n )\n -- Combine all the information\n SELECT\n g.\"clientGroupID\",\n cpg.num_clients,\n g.num_queries\n FROM group_counts g\n JOIN client_per_group_counts cpg ON g.\"clientGroupID\" = cpg.\"clientGroupID\"\n ORDER BY g.num_queries DESC;`;\n }\n\n try {\n return await getPgStats([\n [\n 'totalNumQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\"`,\n ],\n [\n 'numUniqueQueryHashes',\n sql`SELECT COUNT(DISTINCT \"queryHash\") as \"c\" FROM ${sql(\n schema,\n )}.\"desires\"`,\n ],\n [\n 'numActiveQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"inactivatedAt\" IS NULL AND \"deleted\" = false`,\n ],\n [\n 'numInactiveQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"inactivatedAt\" IS NOT NULL AND (\"inactivatedAt\" + \"ttl\") > NOW()`,\n ],\n [\n 'numDeletedQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"deleted\" = true`,\n ],\n [\n 'freshQueriesPercentiles',\n sql`WITH client_group_counts AS (\n -- Count inactive desires per clientGroupID\n SELECT\n \"clientGroupID\",\n COUNT(*) AS fresh_count\n FROM ${sql(schema)}.\"desires\"\n WHERE\n (\"inactivatedAt\" IS NOT NULL\n AND (\"inactivatedAt\" + \"ttl\") > NOW()) OR (\"inactivatedAt\" IS NULL\n AND deleted = false)\n GROUP BY \"clientGroupID\"\n )\n\n SELECT\n percentile_cont(0.50) WITHIN GROUP (ORDER BY fresh_count) AS \"p50\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY fresh_count) AS \"p75\",\n percentile_cont(0.90) WITHIN GROUP (ORDER BY fresh_count) AS \"p90\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY fresh_count) AS \"p95\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY fresh_count) AS \"p99\",\n MIN(fresh_count) AS \"min\",\n MAX(fresh_count) AS \"max\",\n AVG(fresh_count) AS \"avg\"\n FROM client_group_counts;`,\n ],\n [\n 'rowsPerClientGroupPercentiles',\n sql`WITH client_group_counts AS (\n -- Count inactive desires per clientGroupID\n SELECT\n \"clientGroupID\",\n COUNT(*) AS row_count\n FROM ${sql(schema)}.\"rows\"\n GROUP BY \"clientGroupID\"\n )\n SELECT\n percentile_cont(0.50) WITHIN GROUP (ORDER BY row_count) AS \"p50\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY row_count) AS \"p75\",\n percentile_cont(0.90) WITHIN GROUP (ORDER BY row_count) AS \"p90\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY row_count) AS \"p95\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY row_count) AS \"p99\",\n MIN(row_count) AS \"min\",\n MAX(row_count) AS \"max\",\n AVG(row_count) AS \"avg\"\n FROM client_group_counts;`,\n ],\n [\n // check for AST blowup due to DNF conversion.\n 'astSizes',\n sql`SELECT\n percentile_cont(0.25) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"25th_percentile\",\n percentile_cont(0.5) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"50th_percentile\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"75th_percentile\",\n percentile_cont(0.9) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"90th_percentile\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"95th_percentile\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"99th_percentile\",\n MIN(length(\"clientAST\"::text)) AS \"minimum_length\",\n MAX(length(\"clientAST\"::text)) AS \"maximum_length\",\n AVG(length(\"clientAST\"::text))::integer AS \"average_length\",\n COUNT(*) AS \"total_records\"\n FROM ${sql(schema)}.\"queries\";`,\n ],\n [\n // output the hash of the largest AST\n 'biggestAstHash',\n sql`SELECT \"queryHash\", length(\"clientAST\"::text) AS \"ast_length\"\n FROM ${sql(schema)}.\"queries\"\n ORDER BY length(\"clientAST\"::text) DESC\n LIMIT 1;`,\n ],\n [\n 'totalActiveQueriesPerClientAndClientGroup',\n numQueriesPerClientGroup(true),\n ],\n [\n 'totalInactiveQueriesPerClientAndClientGroup',\n numQueriesPerClientGroup(false),\n ],\n [\n 'totalRowsPerClientGroup',\n sql`SELECT \"clientGroupID\", COUNT(*) as \"c\" FROM ${sql(\n schema,\n )}.\"rows\" GROUP BY \"clientGroupID\" ORDER BY \"c\" DESC`,\n ],\n [\n 'numRowsPerQuery',\n sql`SELECT\n k.key AS \"queryHash\",\n COUNT(*) AS row_count\n FROM ${sql(schema)}.\"rows\" r,\n LATERAL jsonb_each(r.\"refCounts\") k\n GROUP BY k.key\n ORDER BY row_count DESC;`,\n ],\n ] satisfies [\n name: string,\n query: ReturnType<ReturnType<typeof pgClient>>,\n ][]);\n } finally {\n await sql.end();\n }\n}\n\nasync function changeLogStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config)) + '/cdc';\n const sql = pgClient(lc, config.change.db);\n\n try {\n return await getPgStats([\n [\n 'changeLogSize',\n sql`SELECT COUNT(*) as \"change_log_size\" FROM ${sql(schema)}.\"changeLog\"`,\n ],\n ]);\n } finally {\n await sql.end();\n }\n}\n\nfunction replicaStats(lc: LogContext, config: ZeroConfig) {\n const db = new Database(lc, config.replica.file);\n try {\n return Object.fromEntries([\n ['wal checkpoint', pick(first(db.pragma('WAL_CHECKPOINT')))],\n ['page count', pick(first(db.pragma('PAGE_COUNT')))],\n ['page size', pick(first(db.pragma('PAGE_SIZE')))],\n ['journal mode', pick(first(db.pragma('JOURNAL_MODE')))],\n ['synchronous', pick(first(db.pragma('SYNCHRONOUS')))],\n ['cache size', pick(first(db.pragma('CACHE_SIZE')))],\n ['auto vacuum', pick(first(db.pragma('AUTO_VACUUM')))],\n ['freelist count', pick(first(db.pragma('FREELIST_COUNT')))],\n ['wal autocheckpoint', pick(first(db.pragma('WAL_AUTOCHECKPOINT')))],\n ['db file stats', fs.statSync(config.replica.file)],\n ] as const);\n } finally {\n db.close();\n }\n}\n\nfunction replicationStats(lc: LogContext, config: ZeroConfig) {\n const db = new Database(lc, config.replica.file);\n try {\n return getReplicationStats(db);\n } finally {\n db.close();\n }\n}\n\nfunction getReplicationStats(db: Database) {\n const {stateVersion} = getReplicationState(new StatementRunner(db));\n const lsn = fromStateVersionString(stateVersion);\n return {lsn};\n}\n\nfunction osStats() {\n return Object.fromEntries([\n ['load avg', os.loadavg()],\n ['uptime', os.uptime()],\n ['total mem', os.totalmem()],\n ['free mem', os.freemem()],\n ['cpus', os.cpus().length],\n ['available parallelism', os.availableParallelism()],\n ['platform', os.platform()],\n ['arch', os.arch()],\n ['release', os.release()],\n ] as const);\n}\n\nasync function getPgStats(\n pendingQueries: [\n name: string,\n query: ReturnType<ReturnType<typeof pgClient>>,\n ][],\n) {\n const results = await Promise.all(\n pendingQueries.map(async ([name, query]) => [name, await query] as const),\n );\n return Object.fromEntries(results);\n}\n\ntype StatsObject = Record<string, unknown>;\n\nfunction printStats(group: string, statsObject: StatsObject): string {\n const lines: string[] = ['\\n' + header(group)];\n for (const [name, result] of Object.entries(statsObject)) {\n lines.push('\\n' + name + ': ' + BigIntJSON.stringify(result, null, 2));\n }\n lines.push('\\n');\n return lines.join('');\n}\n\n/**\n * HTTP query parameters:\n * * `group`: restricts the groups for which stats are computed\n * * `format=json`: returns the stats as a JSON object\n * * `pretty`: formats the JSON object with indentation\n */\nexport async function handleStatzRequest(\n lc: LogContext,\n config: ZeroConfig,\n req: FastifyRequest,\n res: FastifyReply,\n) {\n const credentials = auth(req);\n if (!isAdminPasswordValid(lc, config, credentials?.pass)) {\n void res\n .code(401)\n .header('WWW-Authenticate', 'Basic realm=\"Statz Protected Area\"')\n .send('Unauthorized');\n return;\n }\n\n const statsFns: Record<string, () => Promise<StatsObject> | StatsObject> = {\n upstream: () => upstreamStats(lc, config),\n cvr: () => cvrStats(lc, config),\n changeLog: () => changeLogStats(lc, config),\n replica: () => replicaStats(lc, config),\n replication: () => replicationStats(lc, config),\n os: () => osStats(),\n };\n\n async function computeStats(group: string): Promise<[string, StatsObject]> {\n try {\n return [group, await statsFns[group]()];\n } catch (e) {\n lc.error?.(`error computing ${group} stats`, e);\n return [group, {error: String(e)}];\n }\n }\n\n const query = req.query as Record<string, unknown>;\n const groups =\n typeof query.group === 'string'\n ? query.group.split(',')\n : Array.isArray(query.group)\n ? query.group\n : undefined;\n\n const stats = await Promise.all(\n groups\n ? groups.filter(g => g in statsFns).map(computeStats)\n : Object.keys(statsFns).map(computeStats),\n );\n\n if (query.format === 'json') {\n const indent = query.pretty !== undefined ? 2 : undefined;\n await res\n .header('Content-Type', 'application/json')\n .send(BigIntJSON.stringify(Object.fromEntries(stats), null, indent));\n return;\n } else {\n const body = stats\n .map(([group, statsObject]) => printStats(group, statsObject))\n .join('');\n await res.header('Content-Type', 'text/plain; charset=utf-8').send(body);\n }\n}\n\nfunction first(x: object[]): object {\n return x[0];\n}\n\nfunction pick(x: object): unknown {\n return Object.values(x)[0];\n}\n\nfunction header(name: string): string {\n return `=== ${name} ===\\n`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"statz.js","names":[],"sources":["../../../../../zero-cache/src/services/statz.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport type {LogContext} from '@rocicorp/logger';\nimport auth from 'basic-auth';\nimport type {FastifyReply, FastifyRequest} from 'fastify';\nimport {BigIntJSON} from '../../../shared/src/bigint-json.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport type {NormalizedZeroConfig as ZeroConfig} from '../config/normalize.ts';\nimport {isAdminPasswordValid} from '../config/zero-config.ts';\nimport {StatementRunner} from '../db/statements.ts';\nimport {pgClient} from '../types/pg.ts';\nimport {getShardID, upstreamSchema} from '../types/shards.ts';\nimport {fromStateVersionString} from './change-source/pg/lsn.ts';\nimport {getReplicationState} from './replicator/schema/replication-state.ts';\n\nasync function upstreamStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config));\n const sql = pgClient(lc, config.upstream.db);\n try {\n return await getPgStats([\n [\n 'numReplicas',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"replicas\"`,\n ],\n [\n 'numClientsWithMutations',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"clients\"`,\n ],\n [\n 'numMutationsProcessed',\n sql`SELECT SUM(\"lastMutationID\") as \"c\" FROM ${sql(schema)}.\"clients\"`,\n ],\n ]);\n } finally {\n await sql.end();\n }\n}\n\nasync function cvrStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config)) + '/cvr';\n const sql = pgClient(lc, config.cvr.db);\n\n function numQueriesPerClientGroup(\n active: boolean,\n ): ReturnType<ReturnType<typeof pgClient>> {\n const filter = active\n ? sql`WHERE \"inactivatedAt\" IS NULL AND deleted = false`\n : sql`WHERE \"inactivatedAt\" IS NOT NULL AND (\"inactivatedAt\" + \"ttl\") > NOW()`;\n return sql`WITH\n group_counts AS (\n SELECT\n \"clientGroupID\",\n COUNT(*) AS num_queries\n FROM ${sql(schema)}.\"desires\"\n ${filter}\n GROUP BY \"clientGroupID\"\n ),\n -- Count distinct clientIDs per clientGroupID\n client_per_group_counts AS (\n SELECT\n \"clientGroupID\",\n COUNT(DISTINCT \"clientID\") AS num_clients\n FROM ${sql(schema)}.\"desires\"\n ${filter}\n GROUP BY \"clientGroupID\"\n )\n -- Combine all the information\n SELECT\n g.\"clientGroupID\",\n cpg.num_clients,\n g.num_queries\n FROM group_counts g\n JOIN client_per_group_counts cpg ON g.\"clientGroupID\" = cpg.\"clientGroupID\"\n ORDER BY g.num_queries DESC;`;\n }\n\n try {\n return await getPgStats([\n [\n 'totalNumQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\"`,\n ],\n [\n 'numUniqueQueryHashes',\n sql`SELECT COUNT(DISTINCT \"queryHash\") as \"c\" FROM ${sql(\n schema,\n )}.\"desires\"`,\n ],\n [\n 'numActiveQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"inactivatedAt\" IS NULL AND \"deleted\" = false`,\n ],\n [\n 'numInactiveQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"inactivatedAt\" IS NOT NULL AND (\"inactivatedAt\" + \"ttl\") > NOW()`,\n ],\n [\n 'numDeletedQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"deleted\" = true`,\n ],\n [\n 'freshQueriesPercentiles',\n sql`WITH client_group_counts AS (\n -- Count inactive desires per clientGroupID\n SELECT\n \"clientGroupID\",\n COUNT(*) AS fresh_count\n FROM ${sql(schema)}.\"desires\"\n WHERE\n (\"inactivatedAt\" IS NOT NULL\n AND (\"inactivatedAt\" + \"ttl\") > NOW()) OR (\"inactivatedAt\" IS NULL\n AND deleted = false)\n GROUP BY \"clientGroupID\"\n )\n\n SELECT\n percentile_cont(0.50) WITHIN GROUP (ORDER BY fresh_count) AS \"p50\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY fresh_count) AS \"p75\",\n percentile_cont(0.90) WITHIN GROUP (ORDER BY fresh_count) AS \"p90\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY fresh_count) AS \"p95\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY fresh_count) AS \"p99\",\n MIN(fresh_count) AS \"min\",\n MAX(fresh_count) AS \"max\",\n AVG(fresh_count) AS \"avg\"\n FROM client_group_counts;`,\n ],\n [\n 'rowsPerClientGroupPercentiles',\n sql`WITH client_group_counts AS (\n -- Count inactive desires per clientGroupID\n SELECT\n \"clientGroupID\",\n COUNT(*) AS row_count\n FROM ${sql(schema)}.\"rows\"\n GROUP BY \"clientGroupID\"\n )\n SELECT\n percentile_cont(0.50) WITHIN GROUP (ORDER BY row_count) AS \"p50\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY row_count) AS \"p75\",\n percentile_cont(0.90) WITHIN GROUP (ORDER BY row_count) AS \"p90\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY row_count) AS \"p95\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY row_count) AS \"p99\",\n MIN(row_count) AS \"min\",\n MAX(row_count) AS \"max\",\n AVG(row_count) AS \"avg\"\n FROM client_group_counts;`,\n ],\n [\n // check for AST blowup due to DNF conversion.\n 'astSizes',\n sql`SELECT\n percentile_cont(0.25) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"25th_percentile\",\n percentile_cont(0.5) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"50th_percentile\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"75th_percentile\",\n percentile_cont(0.9) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"90th_percentile\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"95th_percentile\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"99th_percentile\",\n MIN(length(\"clientAST\"::text)) AS \"minimum_length\",\n MAX(length(\"clientAST\"::text)) AS \"maximum_length\",\n AVG(length(\"clientAST\"::text))::integer AS \"average_length\",\n COUNT(*) AS \"total_records\"\n FROM ${sql(schema)}.\"queries\";`,\n ],\n [\n // output the hash of the largest AST\n 'biggestAstHash',\n sql`SELECT \"queryHash\", length(\"clientAST\"::text) AS \"ast_length\"\n FROM ${sql(schema)}.\"queries\"\n ORDER BY length(\"clientAST\"::text) DESC\n LIMIT 1;`,\n ],\n [\n 'totalActiveQueriesPerClientAndClientGroup',\n numQueriesPerClientGroup(true),\n ],\n [\n 'totalInactiveQueriesPerClientAndClientGroup',\n numQueriesPerClientGroup(false),\n ],\n [\n 'totalRowsPerClientGroup',\n sql`SELECT \"clientGroupID\", COUNT(*) as \"c\" FROM ${sql(\n schema,\n )}.\"rows\" GROUP BY \"clientGroupID\" ORDER BY \"c\" DESC`,\n ],\n [\n 'numRowsPerQuery',\n sql`SELECT\n k.key AS \"queryHash\",\n COUNT(*) AS row_count\n FROM ${sql(schema)}.\"rows\" r,\n LATERAL jsonb_each(r.\"refCounts\") k\n GROUP BY k.key\n ORDER BY row_count DESC;`,\n ],\n ] satisfies [\n name: string,\n query: ReturnType<ReturnType<typeof pgClient>>,\n ][]);\n } finally {\n await sql.end();\n }\n}\n\nasync function changeLogStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config)) + '/cdc';\n const sql = pgClient(lc, config.change.db);\n\n try {\n return await getPgStats([\n [\n 'changeLogSize',\n sql`SELECT COUNT(*) as \"change_log_size\" FROM ${sql(schema)}.\"changeLog\"`,\n ],\n ]);\n } finally {\n await sql.end();\n }\n}\n\nfunction replicaStats(lc: LogContext, config: ZeroConfig) {\n const db = new Database(lc, config.replica.file);\n try {\n return Object.fromEntries([\n ['wal checkpoint', pick(first(db.pragma('WAL_CHECKPOINT')))],\n ['page count', pick(first(db.pragma('PAGE_COUNT')))],\n ['page size', pick(first(db.pragma('PAGE_SIZE')))],\n ['journal mode', pick(first(db.pragma('JOURNAL_MODE')))],\n ['synchronous', pick(first(db.pragma('SYNCHRONOUS')))],\n ['cache size', pick(first(db.pragma('CACHE_SIZE')))],\n ['auto vacuum', pick(first(db.pragma('AUTO_VACUUM')))],\n ['freelist count', pick(first(db.pragma('FREELIST_COUNT')))],\n ['wal autocheckpoint', pick(first(db.pragma('WAL_AUTOCHECKPOINT')))],\n ['db file stats', fs.statSync(config.replica.file)],\n ] as const);\n } finally {\n db.close();\n }\n}\n\nfunction replicationStats(lc: LogContext, config: ZeroConfig) {\n const db = new Database(lc, config.replica.file);\n try {\n return getReplicationStats(db);\n } finally {\n db.close();\n }\n}\n\nfunction getReplicationStats(db: Database) {\n const {stateVersion} = getReplicationState(new StatementRunner(db));\n const lsn = fromStateVersionString(stateVersion);\n return {lsn};\n}\n\nfunction osStats() {\n return Object.fromEntries([\n ['load avg', os.loadavg()],\n ['uptime', os.uptime()],\n ['total mem', os.totalmem()],\n ['free mem', os.freemem()],\n ['cpus', os.cpus().length],\n ['available parallelism', os.availableParallelism()],\n ['platform', os.platform()],\n ['arch', os.arch()],\n ['release', os.release()],\n ] as const);\n}\n\nasync function getPgStats(\n pendingQueries: [\n name: string,\n query: ReturnType<ReturnType<typeof pgClient>>,\n ][],\n) {\n const results = await Promise.all(\n pendingQueries.map(async ([name, query]) => [name, await query] as const),\n );\n return Object.fromEntries(results);\n}\n\ntype StatsObject = Record<string, unknown>;\n\nfunction printStats(group: string, statsObject: StatsObject): string {\n const lines: string[] = ['\\n' + header(group)];\n for (const [name, result] of Object.entries(statsObject)) {\n lines.push('\\n' + name + ': ' + BigIntJSON.stringify(result, null, 2));\n }\n lines.push('\\n');\n return lines.join('');\n}\n\n/**\n * HTTP query parameters:\n * * `group`: restricts the groups for which stats are computed\n * * `format=json`: returns the stats as a JSON object\n * * `pretty`: formats the JSON object with indentation\n */\nexport async function handleStatzRequest(\n lc: LogContext,\n config: ZeroConfig,\n req: FastifyRequest,\n res: FastifyReply,\n) {\n const credentials = auth(req);\n if (!isAdminPasswordValid(lc, config, credentials?.pass)) {\n void res\n .code(401)\n .header('WWW-Authenticate', 'Basic realm=\"Statz Protected Area\"')\n .send('Unauthorized');\n return;\n }\n\n const statsFns: Record<string, () => Promise<StatsObject> | StatsObject> = {\n upstream: () => upstreamStats(lc, config),\n cvr: () => cvrStats(lc, config),\n changeLog: () => changeLogStats(lc, config),\n replica: () => replicaStats(lc, config),\n replication: () => replicationStats(lc, config),\n os: () => osStats(),\n };\n\n async function computeStats(group: string): Promise<[string, StatsObject]> {\n try {\n return [group, await statsFns[group]()];\n } catch (e) {\n lc.error?.(`error computing ${group} stats`, e);\n return [group, {error: String(e)}];\n }\n }\n\n const query = req.query as Record<string, unknown>;\n const groups =\n typeof query.group === 'string'\n ? query.group.split(',')\n : Array.isArray(query.group)\n ? query.group\n : undefined;\n\n const stats = await Promise.all(\n groups\n ? groups.filter(g => g in statsFns).map(computeStats)\n : Object.keys(statsFns).map(computeStats),\n );\n\n if (query.format === 'json') {\n const indent = query.pretty !== undefined ? 2 : undefined;\n await res\n .header('Content-Type', 'application/json')\n .send(BigIntJSON.stringify(Object.fromEntries(stats), null, indent));\n return;\n } else {\n const body = stats\n .map(([group, statsObject]) => printStats(group, statsObject))\n .join('');\n await res.header('Content-Type', 'text/plain; charset=utf-8').send(body);\n }\n}\n\nfunction first(x: object[]): object {\n return x[0];\n}\n\nfunction pick(x: object): unknown {\n return Object.values(x)[0];\n}\n\nfunction header(name: string): string {\n return `=== ${name} ===\\n`;\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { must } from "../../../../shared/src/must.js";
2
2
  import { mapValues } from "../../../../shared/src/objects.js";
3
- import { RunningState } from "../running-state.js";
4
3
  import { cvrSchema } from "../../types/shards.js";
4
+ import { RunningState } from "../running-state.js";
5
5
  import { setActiveUsersGetter } from "../../server/anonymous-otel-start.js";
6
6
  //#region ../zero-cache/src/services/view-syncer/active-users-gauge.ts
7
7
  var DAY = 1440 * (60 * 1e3);
@@ -1,9 +1,9 @@
1
1
  import type { LogContext } from '@rocicorp/logger';
2
2
  import type { InitConnectionBody } from '../../../../zero-protocol/src/connect.ts';
3
- import { type Auth, type ValidateLegacyJWT } from '../../auth/auth.ts';
4
- import type { ConnectParams } from '../../workers/connect-params.ts';
5
3
  import type { UpdateAuthBody } from '../../../../zero-protocol/src/update-auth.ts';
4
+ import { type Auth, type ValidateLegacyJWT } from '../../auth/auth.ts';
6
5
  import type { ZeroConfig } from '../../config/zero-config.ts';
6
+ import type { ConnectParams } from '../../workers/connect-params.ts';
7
7
  export type ConnectionState = 'provisional' | 'validated';
8
8
  /**
9
9
  * Identifies one live websocket for a client slot.
@@ -1 +1 @@
1
- {"version":3,"file":"connection-context-manager.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/connection-context-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0CAA0C,CAAC;AAGjF,OAAO,EAGL,KAAK,IAAI,EACT,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8CAA8C,CAAC;AACjF,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,6BAA6B,CAAC;AAE5D,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,WAAW,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;AAEvC,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACnD,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACrD,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,kBAAkB,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IAC7C,aAAa,EAAE,aAAa,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,eAAe,CAAC;IAEvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAEpC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC;IAEvB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAEjC,QAAQ,EAAE,MAAM,CAAC;IAEjB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAEjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;IAC9C,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;CAC9C,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IAEnB,oBAAoB,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACrD,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAElC,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,kBAAkB,CAChB,QAAQ,EAAE,kBAAkB,EAC5B,aAAa,EAAE,aAAa,EAC5B,IAAI,CAAC,EAAE,IAAI,GACV,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAE/B,cAAc,CACZ,QAAQ,EAAE,kBAAkB,EAC5B,IAAI,EAAE,kBAAkB,GACvB,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAE/B,UAAU,CACR,QAAQ,EAAE,kBAAkB,EAC5B,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAExC,kBAAkB,CAChB,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,GAEd,QAAQ,CAAC;QACP,UAAU,EAAE,iBAAiB,CAAC;QAC9B,KAAK,EAAE,cAAc,CAAC;KACvB,CAAC,GACF,SAAS,CAAC;IAEd,cAAc,CACZ,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,GACf,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;IAC3C,eAAe,CACb,QAAQ,EAAE,kBAAkB,GAC3B,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;IAE3C,gCAAgC,CAC9B,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,GACf,IAAI,CAAC;IAER,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,GAAG,IAAI,CAAC;IAE3D,oBAAoB,CAClB,QAAQ,EAAE,kBAAkB,GAC3B,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;IAC3C,wBAAwB,CACtB,QAAQ,EAAE,kBAAkB,GAC3B,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAE/B,8BAA8B,IAAI,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;IAC1E,kCAAkC,IAAI,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAElE,aAAa,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC;IAE1C,eAAe,IAAI;QACjB,gBAAgB,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAChD,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;KACxC,CAAC;CACH,CAAC;AAEF;;;;;;;;;GASG;AACH,qBAAa,4BAA6B,YAAW,wBAAwB;;gBAuBzE,EAAE,EAAE,UAAU,EACd,yBAAyB,CAAC,EAAE,MAAM,EAClC,0BAA0B,CAAC,EAAE,MAAM,EACnC,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,CAAC,EAAE,WAAW,EACxB,iBAAiB,CAAC,EAAE,iBAAiB,EACrC,GAAG,CAAC,EAAE,MAAM,MAAM;IAiBpB;;;;;OAKG;IACH,kBAAkB,CAChB,QAAQ,EAAE,kBAAkB,EAC5B,aAAa,EAAE,aAAa,EAC5B,IAAI,CAAC,EAAE,IAAI,GACV,QAAQ,CAAC,iBAAiB,CAAC;IA0D9B;;;;;OAKG;IACH,cAAc,CACZ,QAAQ,EAAE,kBAAkB,EAC5B,IAAI,EAAE,kBAAkB,GACvB,QAAQ,CAAC,iBAAiB,CAAC;IAuB9B;;;OAGG;IACG,UAAU,CACd,QAAQ,EAAE,kBAAkB,EAC5B,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAqBvC;;;;;;;;OAQG;IACH,kBAAkB,CAChB,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,GAEd,QAAQ,CAAC;QACP,UAAU,EAAE,iBAAiB,CAAC;QAC9B,KAAK,EAAE,cAAc,CAAC;KACvB,CAAC,GACF,SAAS;IA2Cb,mGAAmG;IACnG,cAAc,CACZ,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,GACf,iBAAiB,GAAG,SAAS;IAIhC,6FAA6F;IAC7F,eAAe,CAAC,QAAQ,EAAE,kBAAkB,GAAG,iBAAiB,GAAG,SAAS;IAI5E;;;;OAIG;IACH,gCAAgC,CAC9B,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,GACf,IAAI;IAgBP,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,GAAG,IAAI;IAc1D,iEAAiE;IACjE,oBAAoB,CAClB,QAAQ,EAAE,kBAAkB,GAC3B,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS;IAI1C,gFAAgF;IAChF,wBAAwB,CACtB,QAAQ,EAAE,kBAAkB,GAC3B,QAAQ,CAAC,iBAAiB,CAAC;IAI9B,gEAAgE;IAChE,8BAA8B,IAAI,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS;IAIzE,kCAAkC,IAAI,QAAQ,CAAC,iBAAiB,CAAC;IAgBjE,2CAA2C;IAC3C,aAAa,IAAI,QAAQ,CAAC,cAAc,CAAC;IAIzC;;;;;;;OAOG;IACH,eAAe,IAAI;QACjB,gBAAgB,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAChD,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;KACxC;CAiNF"}
1
+ {"version":3,"file":"connection-context-manager.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/connection-context-manager.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"connection-context-manager.js","names":["#lc","#connections","#group","#validateLegacyJWT","#now","#revalidateIntervalMs","#retransformIntervalMs","#queryConfig","#pushConfig","#removeConnection","#nextInsertionOrder","#refreshBackgroundConnectionContext","#updateBackgroundRetransformDeadline","#mustGetConnectionContext","#demoteConnection","#getConnectionContext","#nextRevalidateAt","#getBackgroundConnectionContext"],"sources":["../../../../../../zero-cache/src/services/view-syncer/connection-context-manager.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {InitConnectionBody} from '../../../../zero-protocol/src/connect.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport {\n authEquals,\n resolveAuth,\n type Auth,\n type ValidateLegacyJWT,\n} from '../../auth/auth.ts';\nimport {compileUrlPattern} from '../../custom/fetch.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {ConnectParams} from '../../workers/connect-params.ts';\nimport type {UpdateAuthBody} from '../../../../zero-protocol/src/update-auth.ts';\nimport type {ZeroConfig} from '../../config/zero-config.ts';\n\nexport type ConnectionState = 'provisional' | 'validated';\n\n/**\n * Identifies one live websocket for a client slot.\n */\nexport type ConnectionSelector = {\n readonly clientID: string;\n readonly wsID: string;\n};\n\ntype FetchConfig = ZeroConfig['query'];\n\nexport type HeaderOptions = {\n apiKey?: string | undefined;\n customHeaders?: Record<string, string> | undefined;\n allowedClientHeaders?: readonly string[] | undefined;\n cookie?: string | undefined;\n origin?: string | undefined;\n};\n\nexport type ConnectionFetchContext = {\n url: string | undefined;\n allowedUrlPatterns: URLPattern[] | undefined;\n headerOptions: HeaderOptions;\n};\n\n/**\n * A snapshot of one live connection tracked by the manager.\n *\n * `revalidateAt` is only populated while the connection is `validated`.\n */\nexport type ConnectionContext = {\n state: ConnectionState;\n\n readonly clientID: string;\n readonly wsID: string;\n readonly userID: string | undefined;\n\n auth: Auth | undefined;\n\n readonly profileID: string | null;\n readonly baseCookie: string | null;\n readonly protocolVersion: number;\n\n revision: number;\n\n revalidateAt: number | undefined;\n\n readonly insertionOrder: number;\n\n readonly queryContext: ConnectionFetchContext;\n readonly pushContext: ConnectionFetchContext;\n};\n\n/**\n * Group-scoped auth state shared across the live connections.\n *\n * The background connection is the validated connection currently used for\n * shared background work. Retransform happens on a group level, and uses\n * the background connection's credential to refetch the latest queries.\n *\n * Since auth can be pinned to logged-out users, `userID` can be undefined\n * even after validation.\n */\nexport type GroupAuthState = {\n userID: string | undefined;\n validated: boolean;\n\n backgroundConnection: ConnectionSelector | undefined;\n retransformAt: number | undefined;\n // Defer all maintenance in case a transient failure occurs.\n maintenanceNotBeforeAt: number | undefined;\n};\n\nexport type ConnectionContextManager = {\n registerConnection(\n selector: ConnectionSelector,\n connectParams: ConnectParams,\n auth?: Auth,\n ): Readonly<ConnectionContext>;\n\n initConnection(\n selector: ConnectionSelector,\n body: InitConnectionBody,\n ): Readonly<ConnectionContext>;\n\n updateAuth(\n selector: ConnectionSelector,\n body: UpdateAuthBody,\n ): Promise<Readonly<ConnectionContext>>;\n\n validateConnection(\n selector: ConnectionSelector,\n revision: number,\n ):\n | Readonly<{\n connection: ConnectionContext;\n group: GroupAuthState;\n }>\n | undefined;\n\n failConnection(\n selector: ConnectionSelector,\n revision: number,\n ): Readonly<ConnectionContext> | undefined;\n closeConnection(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined;\n\n markBackgroundRetransformSuccess(\n selector: ConnectionSelector,\n revision: number,\n ): void;\n\n deferMaintenance(kind: 'revalidate' | 'retransform'): void;\n\n getConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined;\n mustGetConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext>;\n\n getBackgroundConnectionContext(): Readonly<ConnectionContext> | undefined;\n mustGetBackgroundConnectionContext(): Readonly<ConnectionContext>;\n\n getGroupState(): Readonly<GroupAuthState>;\n\n planMaintenance(): {\n dueRevalidations: Readonly<ConnectionContext>[];\n dueRetransform: boolean;\n earliestDeadlineAt: number | undefined;\n };\n};\n\n/**\n * State machine for the auth state of a single `ViewSyncerService`.\n *\n * Connections are registered as `provisional`, optionally backfilled with\n * `initConnection` metadata, and then promoted to `validated` once their\n * stored `userID` is confirmed as valid. The manager also tracks which\n * validated connection currently serves as the group's background connection.\n *\n * This is intentionally side-effect free.\n */\nexport class ConnectionContextManagerImpl implements ConnectionContextManager {\n readonly #lc: LogContext;\n\n // The live connection records, keyed by clientID\n readonly #connections = new Map<string, ConnectionContext>();\n readonly #group: GroupAuthState = {\n userID: undefined,\n backgroundConnection: undefined,\n retransformAt: undefined,\n maintenanceNotBeforeAt: undefined,\n validated: false,\n };\n\n readonly #validateLegacyJWT: ValidateLegacyJWT | undefined;\n\n readonly #now: () => number;\n readonly #revalidateIntervalMs: number | undefined;\n readonly #retransformIntervalMs: number | undefined;\n readonly #queryConfig: FetchConfig | undefined;\n readonly #pushConfig: FetchConfig | undefined;\n #nextInsertionOrder = 0;\n\n constructor(\n lc: LogContext,\n revalidateIntervalSeconds?: number,\n retransformIntervalSeconds?: number,\n queryConfig?: FetchConfig,\n pushConfig?: FetchConfig,\n validateLegacyJWT?: ValidateLegacyJWT,\n now?: () => number,\n ) {\n this.#lc = lc;\n this.#now = now ?? Date.now;\n this.#revalidateIntervalMs =\n revalidateIntervalSeconds === undefined\n ? undefined\n : revalidateIntervalSeconds * 1000;\n this.#retransformIntervalMs =\n retransformIntervalSeconds === undefined\n ? undefined\n : retransformIntervalSeconds * 1000;\n this.#queryConfig = queryConfig;\n this.#pushConfig = pushConfig;\n this.#validateLegacyJWT = validateLegacyJWT;\n }\n\n /**\n * Creates or replaces the live record for a websocket connection.\n *\n * Re-registering the same `clientID` drops the old socket record and starts\n * the replacement back in `provisional` state.\n */\n registerConnection(\n selector: ConnectionSelector,\n connectParams: ConnectParams,\n auth?: Auth,\n ): Readonly<ConnectionContext> {\n this.#removeConnection(selector);\n\n const sharedHeaders = {\n customHeaders: undefined,\n token: auth?.raw,\n origin: connectParams.origin,\n userID: connectParams.userID,\n };\n\n const connection: ConnectionContext = {\n state: 'provisional',\n\n clientID: connectParams.clientID,\n wsID: connectParams.wsID,\n revision: 0,\n userID: connectParams.userID,\n auth,\n\n profileID: connectParams.profileID,\n baseCookie: connectParams.baseCookie,\n protocolVersion: connectParams.protocolVersion,\n\n revalidateAt: undefined,\n\n queryContext: {\n url: this.#queryConfig?.url?.[0],\n allowedUrlPatterns: this.#queryConfig?.url?.map(compileUrlPattern),\n headerOptions: {\n ...sharedHeaders,\n apiKey: this.#queryConfig?.apiKey,\n allowedClientHeaders: this.#queryConfig?.allowedClientHeaders,\n cookie: this.#queryConfig?.forwardCookies\n ? connectParams.httpCookie\n : undefined,\n },\n },\n pushContext: {\n url: this.#pushConfig?.url?.[0],\n allowedUrlPatterns: this.#pushConfig?.url?.map(compileUrlPattern),\n headerOptions: {\n ...sharedHeaders,\n apiKey: this.#pushConfig?.apiKey,\n allowedClientHeaders: this.#pushConfig?.allowedClientHeaders,\n cookie: this.#pushConfig?.forwardCookies\n ? connectParams.httpCookie\n : undefined,\n },\n },\n\n insertionOrder: ++this.#nextInsertionOrder,\n };\n this.#connections.set(connection.clientID, connection);\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n return snapshotConnection(connection);\n }\n\n /**\n * Backfills `initConnection` data for sockets that were registered before the\n * client could send its full init payload.\n *\n * This updates metadata only; it does not validate the connection.\n */\n initConnection(\n selector: ConnectionSelector,\n body: InitConnectionBody,\n ): Readonly<ConnectionContext> {\n const connection = this.#mustGetConnectionContext(selector);\n\n if (body.userQueryURL) {\n connection.queryContext.url = body.userQueryURL;\n }\n if (body.userQueryHeaders) {\n connection.queryContext.headerOptions.customHeaders =\n body.userQueryHeaders;\n }\n if (body.userPushURL) {\n connection.pushContext.url = body.userPushURL;\n }\n if (body.userPushHeaders) {\n connection.pushContext.headerOptions.customHeaders = body.userPushHeaders;\n }\n\n connection.revision++;\n this.#demoteConnection(connection);\n\n return snapshotConnection(connection);\n }\n\n /**\n * A material auth change demotes the connection back to provisional until it\n * is validated again.\n */\n async updateAuth(\n selector: ConnectionSelector,\n body: UpdateAuthBody,\n ): Promise<Readonly<ConnectionContext>> {\n const connection = this.#mustGetConnectionContext(selector);\n\n const nextAuth = await resolveAuth(\n this.#lc,\n connection.auth,\n connection.userID,\n body.auth,\n this.#validateLegacyJWT,\n );\n\n const authChanged = !authEquals(connection.auth, nextAuth);\n connection.auth = nextAuth;\n if (authChanged) {\n connection.revision++;\n this.#demoteConnection(connection);\n }\n\n return snapshotConnection(connection);\n }\n\n /**\n * Validates one connection against the group's pinned `userID`.\n *\n * The first successful validation binds the group `userID`. Later\n * validations must match it. Validation also refreshes the connection's\n * revalidation deadline and may pick the connection as the group\n * background connection if none is currently available. If the websocket is\n * gone by the time async validation finishes, this becomes a no-op.\n */\n validateConnection(\n selector: ConnectionSelector,\n revision: number,\n ):\n | Readonly<{\n connection: ConnectionContext;\n group: GroupAuthState;\n }>\n | undefined {\n const connection = this.#getConnectionContext(selector);\n if (!connection) {\n return undefined;\n }\n\n if (connection.revision !== revision) {\n this.#lc.debug?.('Skipping validateConnection for stale revision', {\n clientID: selector.clientID,\n attemptedRevision: revision,\n currentRevision: connection.revision,\n });\n return undefined;\n }\n\n if (this.#group.validated && this.#group.userID !== connection.userID) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Unauthorized,\n message:\n 'Client groups are pinned to a single userID. Connection userID does not match existing client group userID.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n\n if (!this.#group.validated) {\n this.#group.validated = true;\n this.#group.userID = connection.userID;\n }\n\n connection.state = 'validated';\n connection.revalidateAt = this.#nextRevalidateAt();\n this.#refreshBackgroundConnectionContext(connection);\n this.#updateBackgroundRetransformDeadline(false);\n\n return {\n connection: snapshotConnection(connection),\n group: this.getGroupState(),\n };\n }\n\n /** Removes one connection due to failed auth and updates all derived background/deadline state. */\n failConnection(\n selector: ConnectionSelector,\n revision: number,\n ): ConnectionContext | undefined {\n return this.#removeConnection(selector, revision);\n }\n\n /** Removes one disconnected connection and updates all derived background/deadline state. */\n closeConnection(selector: ConnectionSelector): ConnectionContext | undefined {\n return this.#removeConnection(selector);\n }\n\n /**\n * Records a successful background retransform. This starts a fresh interval\n * from the manager clock when shared retransform is schedulable, or\n * clears the deadline if it is not.\n */\n markBackgroundRetransformSuccess(\n selector: ConnectionSelector,\n revision: number,\n ): void {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection) {\n return;\n }\n if (\n selector !== undefined &&\n (backgroundConnection.clientID !== selector.clientID ||\n backgroundConnection.wsID !== selector.wsID ||\n backgroundConnection.revision !== revision)\n ) {\n return;\n }\n this.#updateBackgroundRetransformDeadline(true);\n }\n\n deferMaintenance(kind: 'revalidate' | 'retransform'): void {\n const intervalMs =\n kind === 'revalidate'\n ? this.#revalidateIntervalMs\n : this.#retransformIntervalMs;\n if (intervalMs === undefined) {\n return;\n }\n this.#group.maintenanceNotBeforeAt = Math.max(\n this.#group.maintenanceNotBeforeAt ?? 0,\n this.#now() + intervalMs,\n );\n }\n\n /** Returns the current live record for a client slot, if any. */\n getConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined {\n return snapshotConnection(this.#getConnectionContext(selector));\n }\n\n /** Returns the live record for one websocket or throws if it is unavailable. */\n mustGetConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> {\n return snapshotConnection(this.#mustGetConnectionContext(selector));\n }\n\n /** Returns the current background connection, if one exists. */\n getBackgroundConnectionContext(): Readonly<ConnectionContext> | undefined {\n return snapshotConnection(this.#getBackgroundConnectionContext());\n }\n\n mustGetBackgroundConnectionContext(): Readonly<ConnectionContext> {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.InvalidConnectionRequest,\n message:\n 'No validated connection is available for shared query work.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n return backgroundConnection;\n }\n\n /** Returns the shared group auth state. */\n getGroupState(): Readonly<GroupAuthState> {\n return snapshotGroup(this.#group);\n }\n\n /**\n * Reports which maintenance work is currently due.\n *\n * The result is a pure snapshot: callers decide which actions to run and\n * when to wake up next. `earliestDeadlineAt` is the earliest outstanding\n * maintenance deadline, including overdue work, unless a transient failure\n * has deferred all scheduled maintenance until `maintenanceNotBeforeAt`.\n */\n planMaintenance(): {\n dueRevalidations: Readonly<ConnectionContext>[];\n dueRetransform: boolean;\n earliestDeadlineAt: number | undefined;\n } {\n const dueRevalidations: Readonly<ConnectionContext>[] = [];\n const now = this.#now();\n let earliestDeadlineAt = this.#group.retransformAt;\n\n for (const connection of this.#connections.values()) {\n if (\n connection.state !== 'validated' ||\n connection.revalidateAt === undefined\n ) {\n continue;\n }\n if (connection.revalidateAt <= now) {\n dueRevalidations.push(snapshotConnection(connection));\n }\n earliestDeadlineAt = minDefined(\n earliestDeadlineAt,\n connection.revalidateAt,\n );\n }\n\n const dueRetransform =\n this.#group.retransformAt !== undefined &&\n this.#group.retransformAt <= now;\n const maintenanceNotBeforeAt = this.#group.maintenanceNotBeforeAt;\n\n if (\n maintenanceNotBeforeAt !== undefined &&\n maintenanceNotBeforeAt > now &&\n earliestDeadlineAt !== undefined\n ) {\n return {\n dueRevalidations: [],\n dueRetransform: false,\n earliestDeadlineAt: Math.max(\n earliestDeadlineAt,\n maintenanceNotBeforeAt,\n ),\n };\n }\n\n return {\n dueRevalidations: dueRevalidations.sort(compareByInsertionOrder),\n dueRetransform,\n earliestDeadlineAt,\n };\n }\n\n #removeConnection(\n selector: ConnectionSelector,\n revision?: number,\n ): Readonly<ConnectionContext> | undefined {\n const connection = this.#getConnectionContext(selector);\n\n if (!connection) {\n return undefined;\n }\n\n // If the revision has changed, we should not remove the connection\n if (revision !== undefined && connection.revision !== revision) {\n this.#lc.debug?.('Ignoring failConnection for stale revision', {\n clientID: selector.clientID,\n wsID: selector.wsID,\n attemptedRevision: revision,\n currentRevision: connection.revision,\n });\n return undefined;\n }\n\n const snapshot = snapshotConnection(connection);\n\n this.#connections.delete(connection.clientID);\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n\n return snapshot;\n }\n\n #demoteConnection(connection: ConnectionContext): void {\n connection.state = 'provisional';\n connection.revalidateAt = undefined;\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n }\n\n /**\n * Keeps the background connection sticky while it remains validated.\n *\n * When a newly validated `preferred` connection is provided, it is promoted\n * only if there is no current validated background connection. Otherwise the\n * existing background connection stays in place until it disappears or is\n * demoted, at which point the newest validated connection is selected.\n */\n #refreshBackgroundConnectionContext(preferred?: ConnectionContext): void {\n if (preferred?.state === 'validated') {\n const currentBackgroundConnection =\n this.#getBackgroundConnectionContext();\n if (\n currentBackgroundConnection?.clientID === preferred.clientID &&\n currentBackgroundConnection.wsID === preferred.wsID\n ) {\n return;\n }\n if (currentBackgroundConnection !== undefined) {\n return;\n }\n this.#group.backgroundConnection = {\n clientID: preferred.clientID,\n wsID: preferred.wsID,\n };\n this.#lc.debug?.('Selected background connection for shared auth work', {\n clientID: preferred.clientID,\n wsID: preferred.wsID,\n revision: preferred.revision,\n reason: 'preferred-validated',\n });\n return;\n }\n\n const currentBackgroundConnection = this.#getBackgroundConnectionContext();\n if (currentBackgroundConnection?.state === 'validated') {\n return;\n }\n\n const nextBackgroundConnection = [...this.#connections.values()]\n .filter(connection => connection.state === 'validated')\n .sort(comparePreferredValidatedConnection)\n .at(0);\n this.#group.backgroundConnection = nextBackgroundConnection\n ? {\n clientID: nextBackgroundConnection.clientID,\n wsID: nextBackgroundConnection.wsID,\n }\n : undefined;\n if (nextBackgroundConnection) {\n this.#lc.debug?.('Selected background connection for shared auth work', {\n clientID: nextBackgroundConnection.clientID,\n wsID: nextBackgroundConnection.wsID,\n revision: nextBackgroundConnection.revision,\n reason: 'fallback-validated',\n });\n }\n }\n\n #getBackgroundConnectionContext(): ConnectionContext | undefined {\n const backgroundConnection = this.#group.backgroundConnection;\n if (!backgroundConnection) {\n return undefined;\n }\n return this.#getConnectionContext(backgroundConnection);\n }\n\n #getConnectionContext(\n selector: ConnectionSelector,\n ): ConnectionContext | undefined {\n const connection = this.#connections.get(selector.clientID);\n if (!connection) {\n return undefined;\n }\n if (connection.wsID !== selector.wsID) {\n return undefined;\n }\n return connection;\n }\n\n #mustGetConnectionContext(selector: ConnectionSelector): ConnectionContext {\n const connection = this.#getConnectionContext(selector);\n\n if (!connection) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.InvalidConnectionRequest,\n message:\n 'Connection auth state was not available for this websocket.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n\n return connection;\n }\n\n /**\n * Keeps the group background retransform deadline coherent with current\n * schedulability.\n *\n * When `reset` is false, this seeds a deadline only when shared retransform\n * is now possible and no deadline exists yet, preserving any existing\n * cadence. When `reset` is true, it starts a fresh interval from `#now()` if\n * retransform is schedulable, or clears the deadline if it is not.\n */\n #updateBackgroundRetransformDeadline(reset: boolean) {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection || this.#retransformIntervalMs === undefined) {\n this.#group.retransformAt = undefined;\n return;\n }\n\n if (reset || this.#group.retransformAt === undefined) {\n this.#group.retransformAt = this.#now() + this.#retransformIntervalMs;\n }\n }\n\n #nextRevalidateAt() {\n return this.#revalidateIntervalMs === undefined\n ? undefined\n : this.#now() + this.#revalidateIntervalMs;\n }\n}\n\nfunction snapshotConnection<T extends ConnectionContext | undefined>(\n connection: T,\n): T extends undefined ? T | undefined : Readonly<T> {\n if (!connection) {\n return undefined as T extends undefined ? T | undefined : Readonly<T>;\n }\n return {\n ...connection,\n queryContext: {\n ...connection.queryContext,\n headerOptions: {\n ...connection.queryContext.headerOptions,\n customHeaders: connection.queryContext.headerOptions.customHeaders\n ? {...connection.queryContext.headerOptions.customHeaders}\n : undefined,\n },\n },\n pushContext: {\n ...connection.pushContext,\n headerOptions: {\n ...connection.pushContext.headerOptions,\n customHeaders: connection.pushContext.headerOptions.customHeaders\n ? {...connection.pushContext.headerOptions.customHeaders}\n : undefined,\n },\n },\n } as T extends undefined ? T | undefined : Readonly<T>;\n}\n\nfunction snapshotGroup(group: GroupAuthState): Readonly<GroupAuthState> {\n return {\n ...group,\n backgroundConnection: group.backgroundConnection\n ? {...group.backgroundConnection}\n : undefined,\n };\n}\n\nfunction compareByInsertionOrder(\n a: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n b: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n) {\n return a.insertionOrder - b.insertionOrder || a.wsID.localeCompare(b.wsID);\n}\n\nfunction comparePreferredValidatedConnection(\n a: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n b: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n) {\n return b.insertionOrder - a.insertionOrder || b.wsID.localeCompare(a.wsID);\n}\n\nfunction minDefined(a: number | undefined, b: number | undefined) {\n if (a === undefined) {\n return b;\n }\n if (b === undefined) {\n return a;\n }\n return Math.min(a, b);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"connection-context-manager.js","names":["#lc","#connections","#group","#validateLegacyJWT","#now","#revalidateIntervalMs","#retransformIntervalMs","#queryConfig","#pushConfig","#removeConnection","#nextInsertionOrder","#refreshBackgroundConnectionContext","#updateBackgroundRetransformDeadline","#mustGetConnectionContext","#demoteConnection","#getConnectionContext","#nextRevalidateAt","#getBackgroundConnectionContext"],"sources":["../../../../../../zero-cache/src/services/view-syncer/connection-context-manager.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {InitConnectionBody} from '../../../../zero-protocol/src/connect.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport type {UpdateAuthBody} from '../../../../zero-protocol/src/update-auth.ts';\nimport {\n authEquals,\n resolveAuth,\n type Auth,\n type ValidateLegacyJWT,\n} from '../../auth/auth.ts';\nimport type {ZeroConfig} from '../../config/zero-config.ts';\nimport {compileUrlPattern} from '../../custom/fetch.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {ConnectParams} from '../../workers/connect-params.ts';\n\nexport type ConnectionState = 'provisional' | 'validated';\n\n/**\n * Identifies one live websocket for a client slot.\n */\nexport type ConnectionSelector = {\n readonly clientID: string;\n readonly wsID: string;\n};\n\ntype FetchConfig = ZeroConfig['query'];\n\nexport type HeaderOptions = {\n apiKey?: string | undefined;\n customHeaders?: Record<string, string> | undefined;\n allowedClientHeaders?: readonly string[] | undefined;\n cookie?: string | undefined;\n origin?: string | undefined;\n};\n\nexport type ConnectionFetchContext = {\n url: string | undefined;\n allowedUrlPatterns: URLPattern[] | undefined;\n headerOptions: HeaderOptions;\n};\n\n/**\n * A snapshot of one live connection tracked by the manager.\n *\n * `revalidateAt` is only populated while the connection is `validated`.\n */\nexport type ConnectionContext = {\n state: ConnectionState;\n\n readonly clientID: string;\n readonly wsID: string;\n readonly userID: string | undefined;\n\n auth: Auth | undefined;\n\n readonly profileID: string | null;\n readonly baseCookie: string | null;\n readonly protocolVersion: number;\n\n revision: number;\n\n revalidateAt: number | undefined;\n\n readonly insertionOrder: number;\n\n readonly queryContext: ConnectionFetchContext;\n readonly pushContext: ConnectionFetchContext;\n};\n\n/**\n * Group-scoped auth state shared across the live connections.\n *\n * The background connection is the validated connection currently used for\n * shared background work. Retransform happens on a group level, and uses\n * the background connection's credential to refetch the latest queries.\n *\n * Since auth can be pinned to logged-out users, `userID` can be undefined\n * even after validation.\n */\nexport type GroupAuthState = {\n userID: string | undefined;\n validated: boolean;\n\n backgroundConnection: ConnectionSelector | undefined;\n retransformAt: number | undefined;\n // Defer all maintenance in case a transient failure occurs.\n maintenanceNotBeforeAt: number | undefined;\n};\n\nexport type ConnectionContextManager = {\n registerConnection(\n selector: ConnectionSelector,\n connectParams: ConnectParams,\n auth?: Auth,\n ): Readonly<ConnectionContext>;\n\n initConnection(\n selector: ConnectionSelector,\n body: InitConnectionBody,\n ): Readonly<ConnectionContext>;\n\n updateAuth(\n selector: ConnectionSelector,\n body: UpdateAuthBody,\n ): Promise<Readonly<ConnectionContext>>;\n\n validateConnection(\n selector: ConnectionSelector,\n revision: number,\n ):\n | Readonly<{\n connection: ConnectionContext;\n group: GroupAuthState;\n }>\n | undefined;\n\n failConnection(\n selector: ConnectionSelector,\n revision: number,\n ): Readonly<ConnectionContext> | undefined;\n closeConnection(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined;\n\n markBackgroundRetransformSuccess(\n selector: ConnectionSelector,\n revision: number,\n ): void;\n\n deferMaintenance(kind: 'revalidate' | 'retransform'): void;\n\n getConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined;\n mustGetConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext>;\n\n getBackgroundConnectionContext(): Readonly<ConnectionContext> | undefined;\n mustGetBackgroundConnectionContext(): Readonly<ConnectionContext>;\n\n getGroupState(): Readonly<GroupAuthState>;\n\n planMaintenance(): {\n dueRevalidations: Readonly<ConnectionContext>[];\n dueRetransform: boolean;\n earliestDeadlineAt: number | undefined;\n };\n};\n\n/**\n * State machine for the auth state of a single `ViewSyncerService`.\n *\n * Connections are registered as `provisional`, optionally backfilled with\n * `initConnection` metadata, and then promoted to `validated` once their\n * stored `userID` is confirmed as valid. The manager also tracks which\n * validated connection currently serves as the group's background connection.\n *\n * This is intentionally side-effect free.\n */\nexport class ConnectionContextManagerImpl implements ConnectionContextManager {\n readonly #lc: LogContext;\n\n // The live connection records, keyed by clientID\n readonly #connections = new Map<string, ConnectionContext>();\n readonly #group: GroupAuthState = {\n userID: undefined,\n backgroundConnection: undefined,\n retransformAt: undefined,\n maintenanceNotBeforeAt: undefined,\n validated: false,\n };\n\n readonly #validateLegacyJWT: ValidateLegacyJWT | undefined;\n\n readonly #now: () => number;\n readonly #revalidateIntervalMs: number | undefined;\n readonly #retransformIntervalMs: number | undefined;\n readonly #queryConfig: FetchConfig | undefined;\n readonly #pushConfig: FetchConfig | undefined;\n #nextInsertionOrder = 0;\n\n constructor(\n lc: LogContext,\n revalidateIntervalSeconds?: number,\n retransformIntervalSeconds?: number,\n queryConfig?: FetchConfig,\n pushConfig?: FetchConfig,\n validateLegacyJWT?: ValidateLegacyJWT,\n now?: () => number,\n ) {\n this.#lc = lc;\n this.#now = now ?? Date.now;\n this.#revalidateIntervalMs =\n revalidateIntervalSeconds === undefined\n ? undefined\n : revalidateIntervalSeconds * 1000;\n this.#retransformIntervalMs =\n retransformIntervalSeconds === undefined\n ? undefined\n : retransformIntervalSeconds * 1000;\n this.#queryConfig = queryConfig;\n this.#pushConfig = pushConfig;\n this.#validateLegacyJWT = validateLegacyJWT;\n }\n\n /**\n * Creates or replaces the live record for a websocket connection.\n *\n * Re-registering the same `clientID` drops the old socket record and starts\n * the replacement back in `provisional` state.\n */\n registerConnection(\n selector: ConnectionSelector,\n connectParams: ConnectParams,\n auth?: Auth,\n ): Readonly<ConnectionContext> {\n this.#removeConnection(selector);\n\n const sharedHeaders = {\n customHeaders: undefined,\n token: auth?.raw,\n origin: connectParams.origin,\n userID: connectParams.userID,\n };\n\n const connection: ConnectionContext = {\n state: 'provisional',\n\n clientID: connectParams.clientID,\n wsID: connectParams.wsID,\n revision: 0,\n userID: connectParams.userID,\n auth,\n\n profileID: connectParams.profileID,\n baseCookie: connectParams.baseCookie,\n protocolVersion: connectParams.protocolVersion,\n\n revalidateAt: undefined,\n\n queryContext: {\n url: this.#queryConfig?.url?.[0],\n allowedUrlPatterns: this.#queryConfig?.url?.map(compileUrlPattern),\n headerOptions: {\n ...sharedHeaders,\n apiKey: this.#queryConfig?.apiKey,\n allowedClientHeaders: this.#queryConfig?.allowedClientHeaders,\n cookie: this.#queryConfig?.forwardCookies\n ? connectParams.httpCookie\n : undefined,\n },\n },\n pushContext: {\n url: this.#pushConfig?.url?.[0],\n allowedUrlPatterns: this.#pushConfig?.url?.map(compileUrlPattern),\n headerOptions: {\n ...sharedHeaders,\n apiKey: this.#pushConfig?.apiKey,\n allowedClientHeaders: this.#pushConfig?.allowedClientHeaders,\n cookie: this.#pushConfig?.forwardCookies\n ? connectParams.httpCookie\n : undefined,\n },\n },\n\n insertionOrder: ++this.#nextInsertionOrder,\n };\n this.#connections.set(connection.clientID, connection);\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n return snapshotConnection(connection);\n }\n\n /**\n * Backfills `initConnection` data for sockets that were registered before the\n * client could send its full init payload.\n *\n * This updates metadata only; it does not validate the connection.\n */\n initConnection(\n selector: ConnectionSelector,\n body: InitConnectionBody,\n ): Readonly<ConnectionContext> {\n const connection = this.#mustGetConnectionContext(selector);\n\n if (body.userQueryURL) {\n connection.queryContext.url = body.userQueryURL;\n }\n if (body.userQueryHeaders) {\n connection.queryContext.headerOptions.customHeaders =\n body.userQueryHeaders;\n }\n if (body.userPushURL) {\n connection.pushContext.url = body.userPushURL;\n }\n if (body.userPushHeaders) {\n connection.pushContext.headerOptions.customHeaders = body.userPushHeaders;\n }\n\n connection.revision++;\n this.#demoteConnection(connection);\n\n return snapshotConnection(connection);\n }\n\n /**\n * A material auth change demotes the connection back to provisional until it\n * is validated again.\n */\n async updateAuth(\n selector: ConnectionSelector,\n body: UpdateAuthBody,\n ): Promise<Readonly<ConnectionContext>> {\n const connection = this.#mustGetConnectionContext(selector);\n\n const nextAuth = await resolveAuth(\n this.#lc,\n connection.auth,\n connection.userID,\n body.auth,\n this.#validateLegacyJWT,\n );\n\n const authChanged = !authEquals(connection.auth, nextAuth);\n connection.auth = nextAuth;\n if (authChanged) {\n connection.revision++;\n this.#demoteConnection(connection);\n }\n\n return snapshotConnection(connection);\n }\n\n /**\n * Validates one connection against the group's pinned `userID`.\n *\n * The first successful validation binds the group `userID`. Later\n * validations must match it. Validation also refreshes the connection's\n * revalidation deadline and may pick the connection as the group\n * background connection if none is currently available. If the websocket is\n * gone by the time async validation finishes, this becomes a no-op.\n */\n validateConnection(\n selector: ConnectionSelector,\n revision: number,\n ):\n | Readonly<{\n connection: ConnectionContext;\n group: GroupAuthState;\n }>\n | undefined {\n const connection = this.#getConnectionContext(selector);\n if (!connection) {\n return undefined;\n }\n\n if (connection.revision !== revision) {\n this.#lc.debug?.('Skipping validateConnection for stale revision', {\n clientID: selector.clientID,\n attemptedRevision: revision,\n currentRevision: connection.revision,\n });\n return undefined;\n }\n\n if (this.#group.validated && this.#group.userID !== connection.userID) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Unauthorized,\n message:\n 'Client groups are pinned to a single userID. Connection userID does not match existing client group userID.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n\n if (!this.#group.validated) {\n this.#group.validated = true;\n this.#group.userID = connection.userID;\n }\n\n connection.state = 'validated';\n connection.revalidateAt = this.#nextRevalidateAt();\n this.#refreshBackgroundConnectionContext(connection);\n this.#updateBackgroundRetransformDeadline(false);\n\n return {\n connection: snapshotConnection(connection),\n group: this.getGroupState(),\n };\n }\n\n /** Removes one connection due to failed auth and updates all derived background/deadline state. */\n failConnection(\n selector: ConnectionSelector,\n revision: number,\n ): ConnectionContext | undefined {\n return this.#removeConnection(selector, revision);\n }\n\n /** Removes one disconnected connection and updates all derived background/deadline state. */\n closeConnection(selector: ConnectionSelector): ConnectionContext | undefined {\n return this.#removeConnection(selector);\n }\n\n /**\n * Records a successful background retransform. This starts a fresh interval\n * from the manager clock when shared retransform is schedulable, or\n * clears the deadline if it is not.\n */\n markBackgroundRetransformSuccess(\n selector: ConnectionSelector,\n revision: number,\n ): void {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection) {\n return;\n }\n if (\n selector !== undefined &&\n (backgroundConnection.clientID !== selector.clientID ||\n backgroundConnection.wsID !== selector.wsID ||\n backgroundConnection.revision !== revision)\n ) {\n return;\n }\n this.#updateBackgroundRetransformDeadline(true);\n }\n\n deferMaintenance(kind: 'revalidate' | 'retransform'): void {\n const intervalMs =\n kind === 'revalidate'\n ? this.#revalidateIntervalMs\n : this.#retransformIntervalMs;\n if (intervalMs === undefined) {\n return;\n }\n this.#group.maintenanceNotBeforeAt = Math.max(\n this.#group.maintenanceNotBeforeAt ?? 0,\n this.#now() + intervalMs,\n );\n }\n\n /** Returns the current live record for a client slot, if any. */\n getConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined {\n return snapshotConnection(this.#getConnectionContext(selector));\n }\n\n /** Returns the live record for one websocket or throws if it is unavailable. */\n mustGetConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> {\n return snapshotConnection(this.#mustGetConnectionContext(selector));\n }\n\n /** Returns the current background connection, if one exists. */\n getBackgroundConnectionContext(): Readonly<ConnectionContext> | undefined {\n return snapshotConnection(this.#getBackgroundConnectionContext());\n }\n\n mustGetBackgroundConnectionContext(): Readonly<ConnectionContext> {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.InvalidConnectionRequest,\n message:\n 'No validated connection is available for shared query work.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n return backgroundConnection;\n }\n\n /** Returns the shared group auth state. */\n getGroupState(): Readonly<GroupAuthState> {\n return snapshotGroup(this.#group);\n }\n\n /**\n * Reports which maintenance work is currently due.\n *\n * The result is a pure snapshot: callers decide which actions to run and\n * when to wake up next. `earliestDeadlineAt` is the earliest outstanding\n * maintenance deadline, including overdue work, unless a transient failure\n * has deferred all scheduled maintenance until `maintenanceNotBeforeAt`.\n */\n planMaintenance(): {\n dueRevalidations: Readonly<ConnectionContext>[];\n dueRetransform: boolean;\n earliestDeadlineAt: number | undefined;\n } {\n const dueRevalidations: Readonly<ConnectionContext>[] = [];\n const now = this.#now();\n let earliestDeadlineAt = this.#group.retransformAt;\n\n for (const connection of this.#connections.values()) {\n if (\n connection.state !== 'validated' ||\n connection.revalidateAt === undefined\n ) {\n continue;\n }\n if (connection.revalidateAt <= now) {\n dueRevalidations.push(snapshotConnection(connection));\n }\n earliestDeadlineAt = minDefined(\n earliestDeadlineAt,\n connection.revalidateAt,\n );\n }\n\n const dueRetransform =\n this.#group.retransformAt !== undefined &&\n this.#group.retransformAt <= now;\n const maintenanceNotBeforeAt = this.#group.maintenanceNotBeforeAt;\n\n if (\n maintenanceNotBeforeAt !== undefined &&\n maintenanceNotBeforeAt > now &&\n earliestDeadlineAt !== undefined\n ) {\n return {\n dueRevalidations: [],\n dueRetransform: false,\n earliestDeadlineAt: Math.max(\n earliestDeadlineAt,\n maintenanceNotBeforeAt,\n ),\n };\n }\n\n return {\n dueRevalidations: dueRevalidations.sort(compareByInsertionOrder),\n dueRetransform,\n earliestDeadlineAt,\n };\n }\n\n #removeConnection(\n selector: ConnectionSelector,\n revision?: number,\n ): Readonly<ConnectionContext> | undefined {\n const connection = this.#getConnectionContext(selector);\n\n if (!connection) {\n return undefined;\n }\n\n // If the revision has changed, we should not remove the connection\n if (revision !== undefined && connection.revision !== revision) {\n this.#lc.debug?.('Ignoring failConnection for stale revision', {\n clientID: selector.clientID,\n wsID: selector.wsID,\n attemptedRevision: revision,\n currentRevision: connection.revision,\n });\n return undefined;\n }\n\n const snapshot = snapshotConnection(connection);\n\n this.#connections.delete(connection.clientID);\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n\n return snapshot;\n }\n\n #demoteConnection(connection: ConnectionContext): void {\n connection.state = 'provisional';\n connection.revalidateAt = undefined;\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n }\n\n /**\n * Keeps the background connection sticky while it remains validated.\n *\n * When a newly validated `preferred` connection is provided, it is promoted\n * only if there is no current validated background connection. Otherwise the\n * existing background connection stays in place until it disappears or is\n * demoted, at which point the newest validated connection is selected.\n */\n #refreshBackgroundConnectionContext(preferred?: ConnectionContext): void {\n if (preferred?.state === 'validated') {\n const currentBackgroundConnection =\n this.#getBackgroundConnectionContext();\n if (\n currentBackgroundConnection?.clientID === preferred.clientID &&\n currentBackgroundConnection.wsID === preferred.wsID\n ) {\n return;\n }\n if (currentBackgroundConnection !== undefined) {\n return;\n }\n this.#group.backgroundConnection = {\n clientID: preferred.clientID,\n wsID: preferred.wsID,\n };\n this.#lc.debug?.('Selected background connection for shared auth work', {\n clientID: preferred.clientID,\n wsID: preferred.wsID,\n revision: preferred.revision,\n reason: 'preferred-validated',\n });\n return;\n }\n\n const currentBackgroundConnection = this.#getBackgroundConnectionContext();\n if (currentBackgroundConnection?.state === 'validated') {\n return;\n }\n\n const nextBackgroundConnection = [...this.#connections.values()]\n .filter(connection => connection.state === 'validated')\n .sort(comparePreferredValidatedConnection)\n .at(0);\n this.#group.backgroundConnection = nextBackgroundConnection\n ? {\n clientID: nextBackgroundConnection.clientID,\n wsID: nextBackgroundConnection.wsID,\n }\n : undefined;\n if (nextBackgroundConnection) {\n this.#lc.debug?.('Selected background connection for shared auth work', {\n clientID: nextBackgroundConnection.clientID,\n wsID: nextBackgroundConnection.wsID,\n revision: nextBackgroundConnection.revision,\n reason: 'fallback-validated',\n });\n }\n }\n\n #getBackgroundConnectionContext(): ConnectionContext | undefined {\n const backgroundConnection = this.#group.backgroundConnection;\n if (!backgroundConnection) {\n return undefined;\n }\n return this.#getConnectionContext(backgroundConnection);\n }\n\n #getConnectionContext(\n selector: ConnectionSelector,\n ): ConnectionContext | undefined {\n const connection = this.#connections.get(selector.clientID);\n if (!connection) {\n return undefined;\n }\n if (connection.wsID !== selector.wsID) {\n return undefined;\n }\n return connection;\n }\n\n #mustGetConnectionContext(selector: ConnectionSelector): ConnectionContext {\n const connection = this.#getConnectionContext(selector);\n\n if (!connection) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.InvalidConnectionRequest,\n message:\n 'Connection auth state was not available for this websocket.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n\n return connection;\n }\n\n /**\n * Keeps the group background retransform deadline coherent with current\n * schedulability.\n *\n * When `reset` is false, this seeds a deadline only when shared retransform\n * is now possible and no deadline exists yet, preserving any existing\n * cadence. When `reset` is true, it starts a fresh interval from `#now()` if\n * retransform is schedulable, or clears the deadline if it is not.\n */\n #updateBackgroundRetransformDeadline(reset: boolean) {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection || this.#retransformIntervalMs === undefined) {\n this.#group.retransformAt = undefined;\n return;\n }\n\n if (reset || this.#group.retransformAt === undefined) {\n this.#group.retransformAt = this.#now() + this.#retransformIntervalMs;\n }\n }\n\n #nextRevalidateAt() {\n return this.#revalidateIntervalMs === undefined\n ? undefined\n : this.#now() + this.#revalidateIntervalMs;\n }\n}\n\nfunction snapshotConnection<T extends ConnectionContext | undefined>(\n connection: T,\n): T extends undefined ? T | undefined : Readonly<T> {\n if (!connection) {\n return undefined as T extends undefined ? T | undefined : Readonly<T>;\n }\n return {\n ...connection,\n queryContext: {\n ...connection.queryContext,\n headerOptions: {\n ...connection.queryContext.headerOptions,\n customHeaders: connection.queryContext.headerOptions.customHeaders\n ? {...connection.queryContext.headerOptions.customHeaders}\n : undefined,\n },\n },\n pushContext: {\n ...connection.pushContext,\n headerOptions: {\n ...connection.pushContext.headerOptions,\n customHeaders: connection.pushContext.headerOptions.customHeaders\n ? {...connection.pushContext.headerOptions.customHeaders}\n : undefined,\n },\n },\n } as T extends undefined ? T | undefined : Readonly<T>;\n}\n\nfunction snapshotGroup(group: GroupAuthState): Readonly<GroupAuthState> {\n return {\n ...group,\n backgroundConnection: group.backgroundConnection\n ? {...group.backgroundConnection}\n : undefined,\n };\n}\n\nfunction compareByInsertionOrder(\n a: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n b: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n) {\n return a.insertionOrder - b.insertionOrder || a.wsID.localeCompare(b.wsID);\n}\n\nfunction comparePreferredValidatedConnection(\n a: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n b: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n) {\n return b.insertionOrder - a.insertionOrder || b.wsID.localeCompare(a.wsID);\n}\n\nfunction minDefined(a: number | undefined, b: number | undefined) {\n if (a === undefined) {\n return b;\n }\n if (b === undefined) {\n return a;\n }\n return Math.min(a, b);\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { promiseVoid } from "../../../../shared/src/resolved-promises.js";
2
- import { RunningState } from "../running-state.js";
3
2
  import { cvrSchema } from "../../types/shards.js";
4
3
  import "../../types/pg.js";
4
+ import { RunningState } from "../running-state.js";
5
5
  import { READ_COMMITTED } from "../../db/mode-enum.js";
6
6
  import { runTx } from "../../db/run-transaction.js";
7
7
  //#region ../zero-cache/src/services/view-syncer/cvr-purger.ts
@@ -7,9 +7,9 @@ import { ClientNotFound, Internal, Rehome, SchemaVersionNotSupported } from "../
7
7
  import { ZeroCache } from "../../../../zero-protocol/src/error-origin-enum.js";
8
8
  import { clientSchemaSchema } from "../../../../zero-protocol/src/client-schema.js";
9
9
  import { DEFAULT_TTL_MS, clampTTL } from "../../../../zql/src/query/ttl.js";
10
+ import { cvrSchema } from "../../types/shards.js";
10
11
  import { startAsyncSpan } from "../../../../otel/src/span.js";
11
12
  import { version } from "../../../../otel/src/version.js";
12
- import { cvrSchema } from "../../types/shards.js";
13
13
  import { rowIDString } from "../../types/row-key.js";
14
14
  import { READONLY, READ_COMMITTED } from "../../db/mode-enum.js";
15
15
  import { runTx } from "../../db/run-transaction.js";
@@ -363,7 +363,7 @@ var CVRStore = class {
363
363
  const start = afterVersion ? versionString(afterVersion) : "";
364
364
  const end = versionString(upToCVR.version);
365
365
  lc.debug?.(`scanning config patches for clients from ${start}`);
366
- const reader = new TransactionPool(lc, READONLY).run(this.#db);
366
+ const reader = new TransactionPool(lc, { mode: READONLY }).run(this.#db);
367
367
  try {
368
368
  await reader.processReadTask((tx) => checkVersion(tx, this.#schema, this.#id, current));
369
369
  const [allDesires, queryRows] = await reader.processReadTask((tx) => Promise.all([tx`
@@ -724,7 +724,7 @@ var CVRStore = class {
724
724
  async inspectQueries(lc, ttlClock, clientID) {
725
725
  const db = this.#db;
726
726
  const clientGroupID = this.#id;
727
- const reader = new TransactionPool(lc, READONLY).run(db);
727
+ const reader = new TransactionPool(lc, { mode: READONLY }).run(db);
728
728
  try {
729
729
  return await reader.processReadTask((tx) => tx`
730
730
  SELECT DISTINCT ON (d."clientID", d."queryHash")