@rocicorp/zero 0.25.0-canary.8 → 0.25.0-canary.9

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 (272) hide show
  1. package/out/shared/src/deep-merge.d.ts +20 -3
  2. package/out/shared/src/deep-merge.d.ts.map +1 -1
  3. package/out/shared/src/deep-merge.js +27 -0
  4. package/out/shared/src/deep-merge.js.map +1 -0
  5. package/out/shared/src/logging.d.ts.map +1 -1
  6. package/out/shared/src/logging.js +25 -9
  7. package/out/shared/src/logging.js.map +1 -1
  8. package/out/shared/src/object-traversal.d.ts +19 -0
  9. package/out/shared/src/object-traversal.d.ts.map +1 -0
  10. package/out/shared/src/object-traversal.js +27 -0
  11. package/out/shared/src/object-traversal.js.map +1 -0
  12. package/out/zero/package.json.js +1 -1
  13. package/out/zero/src/pg.js +0 -2
  14. package/out/zero/src/pg.js.map +1 -1
  15. package/out/zero/src/server.js +0 -2
  16. package/out/zero/src/server.js.map +1 -1
  17. package/out/zero/src/zero.js +19 -3
  18. package/out/zero/src/zero.js.map +1 -1
  19. package/out/zero-cache/src/auth/jwt.d.ts +3 -0
  20. package/out/zero-cache/src/auth/jwt.d.ts.map +1 -1
  21. package/out/zero-cache/src/auth/jwt.js.map +1 -1
  22. package/out/zero-cache/src/auth/write-authorizer.d.ts +2 -1
  23. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  24. package/out/zero-cache/src/auth/write-authorizer.js +1 -11
  25. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  26. package/out/zero-cache/src/config/zero-config.d.ts +27 -0
  27. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  28. package/out/zero-cache/src/config/zero-config.js +35 -7
  29. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  30. package/out/zero-cache/src/custom/fetch.d.ts +5 -5
  31. package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
  32. package/out/zero-cache/src/custom/fetch.js +14 -11
  33. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  34. package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +1 -1
  35. package/out/zero-cache/src/custom-queries/transform-query.js +2 -4
  36. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  37. package/out/zero-cache/src/db/specs.d.ts +1 -1
  38. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  39. package/out/zero-cache/src/server/change-streamer.js +9 -9
  40. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  41. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  42. package/out/zero-cache/src/server/syncer.js +20 -8
  43. package/out/zero-cache/src/server/syncer.js.map +1 -1
  44. package/out/zero-cache/src/services/analyze.d.ts +1 -1
  45. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  46. package/out/zero-cache/src/services/analyze.js +10 -1
  47. package/out/zero-cache/src/services/analyze.js.map +1 -1
  48. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +5 -5
  49. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +2 -2
  50. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +1 -1
  51. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +11 -2
  52. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  53. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +36 -0
  54. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  55. package/out/zero-cache/src/services/http-service.d.ts +5 -4
  56. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  57. package/out/zero-cache/src/services/http-service.js +15 -10
  58. package/out/zero-cache/src/services/http-service.js.map +1 -1
  59. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +2 -1
  60. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  61. package/out/zero-cache/src/services/mutagen/mutagen.js +3 -2
  62. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  63. package/out/zero-cache/src/services/mutagen/pusher.d.ts +198 -0
  64. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  65. package/out/zero-cache/src/services/mutagen/pusher.js +5 -5
  66. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  67. package/out/zero-cache/src/services/run-ast.d.ts +4 -0
  68. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  69. package/out/zero-cache/src/services/run-ast.js +8 -1
  70. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  71. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
  72. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +2 -1
  73. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  74. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  75. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +15 -8
  76. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  77. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +4 -4
  78. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  79. package/out/zero-cache/src/services/view-syncer/view-syncer.js +48 -25
  80. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  81. package/out/zero-cache/src/workers/connection.js +20 -15
  82. package/out/zero-cache/src/workers/connection.js.map +1 -1
  83. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  84. package/out/zero-cache/src/workers/syncer.js +3 -3
  85. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  86. package/out/zero-client/src/client/bindings.d.ts +4 -4
  87. package/out/zero-client/src/client/bindings.d.ts.map +1 -1
  88. package/out/zero-client/src/client/bindings.js.map +1 -1
  89. package/out/zero-client/src/client/connection.d.ts +1 -1
  90. package/out/zero-client/src/client/connection.d.ts.map +1 -1
  91. package/out/zero-client/src/client/connection.js +1 -1
  92. package/out/zero-client/src/client/connection.js.map +1 -1
  93. package/out/zero-client/src/client/crud.d.ts +7 -5
  94. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  95. package/out/zero-client/src/client/crud.js +7 -7
  96. package/out/zero-client/src/client/crud.js.map +1 -1
  97. package/out/zero-client/src/client/custom.d.ts +7 -5
  98. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  99. package/out/zero-client/src/client/custom.js +12 -7
  100. package/out/zero-client/src/client/custom.js.map +1 -1
  101. package/out/zero-client/src/client/inspector/inspector.d.ts +5 -1
  102. package/out/zero-client/src/client/inspector/inspector.d.ts.map +1 -1
  103. package/out/zero-client/src/client/inspector/inspector.js +7 -0
  104. package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
  105. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts.map +1 -1
  106. package/out/zero-client/src/client/inspector/lazy-inspector.js +13 -13
  107. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  108. package/out/zero-client/src/client/make-mutate-property.d.ts +43 -0
  109. package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -0
  110. package/out/zero-client/src/client/make-mutate-property.js +38 -0
  111. package/out/zero-client/src/client/make-mutate-property.js.map +1 -0
  112. package/out/zero-client/src/client/make-replicache-mutators.d.ts +34 -0
  113. package/out/zero-client/src/client/make-replicache-mutators.d.ts.map +1 -0
  114. package/out/zero-client/src/client/make-replicache-mutators.js +103 -0
  115. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -0
  116. package/out/zero-client/src/client/options.d.ts +39 -27
  117. package/out/zero-client/src/client/options.d.ts.map +1 -1
  118. package/out/zero-client/src/client/options.js.map +1 -1
  119. package/out/zero-client/src/client/version.js +1 -1
  120. package/out/zero-client/src/client/zero.d.ts +23 -33
  121. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  122. package/out/zero-client/src/client/zero.js +52 -118
  123. package/out/zero-client/src/client/zero.js.map +1 -1
  124. package/out/zero-client/src/mod.d.ts +12 -7
  125. package/out/zero-client/src/mod.d.ts.map +1 -1
  126. package/out/zero-protocol/src/analyze-query-result.d.ts +236 -0
  127. package/out/zero-protocol/src/analyze-query-result.d.ts.map +1 -1
  128. package/out/zero-protocol/src/analyze-query-result.js +128 -2
  129. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  130. package/out/zero-protocol/src/ast.d.ts +1 -1
  131. package/out/zero-protocol/src/connect.d.ts.map +1 -1
  132. package/out/zero-protocol/src/connect.js +4 -0
  133. package/out/zero-protocol/src/connect.js.map +1 -1
  134. package/out/zero-protocol/src/custom-queries.d.ts +1 -1
  135. package/out/zero-protocol/src/down.d.ts +99 -0
  136. package/out/zero-protocol/src/down.d.ts.map +1 -1
  137. package/out/zero-protocol/src/error.d.ts +4 -4
  138. package/out/zero-protocol/src/inspect-down.d.ts +297 -0
  139. package/out/zero-protocol/src/inspect-down.d.ts.map +1 -1
  140. package/out/zero-protocol/src/inspect-up.d.ts +4 -0
  141. package/out/zero-protocol/src/inspect-up.d.ts.map +1 -1
  142. package/out/zero-protocol/src/inspect-up.js +2 -1
  143. package/out/zero-protocol/src/inspect-up.js.map +1 -1
  144. package/out/zero-protocol/src/protocol-version.d.ts +1 -1
  145. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  146. package/out/zero-protocol/src/protocol-version.js +1 -1
  147. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  148. package/out/zero-protocol/src/push.d.ts +1 -1
  149. package/out/zero-protocol/src/up.d.ts +1 -0
  150. package/out/zero-protocol/src/up.d.ts.map +1 -1
  151. package/out/zero-react/src/components/inspector.d.ts +3 -2
  152. package/out/zero-react/src/components/inspector.d.ts.map +1 -1
  153. package/out/zero-react/src/components/inspector.js.map +1 -1
  154. package/out/zero-react/src/components/zero-inspector.d.ts +3 -2
  155. package/out/zero-react/src/components/zero-inspector.d.ts.map +1 -1
  156. package/out/zero-react/src/components/zero-inspector.js.map +1 -1
  157. package/out/zero-react/src/use-query.d.ts +5 -4
  158. package/out/zero-react/src/use-query.d.ts.map +1 -1
  159. package/out/zero-react/src/use-query.js +4 -3
  160. package/out/zero-react/src/use-query.js.map +1 -1
  161. package/out/zero-react/src/zero-provider.d.ts +7 -7
  162. package/out/zero-react/src/zero-provider.d.ts.map +1 -1
  163. package/out/zero-react/src/zero-provider.js.map +1 -1
  164. package/out/zero-schema/src/builder/schema-builder.js +1 -1
  165. package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
  166. package/out/zero-server/src/custom.d.ts +4 -5
  167. package/out/zero-server/src/custom.d.ts.map +1 -1
  168. package/out/zero-server/src/custom.js.map +1 -1
  169. package/out/zero-server/src/mod.d.ts +0 -1
  170. package/out/zero-server/src/mod.d.ts.map +1 -1
  171. package/out/zero-server/src/process-mutations.d.ts +9 -14
  172. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  173. package/out/zero-server/src/process-mutations.js +151 -105
  174. package/out/zero-server/src/process-mutations.js.map +1 -1
  175. package/out/zero-server/src/push-processor.d.ts +5 -3
  176. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  177. package/out/zero-server/src/push-processor.js +17 -25
  178. package/out/zero-server/src/push-processor.js.map +1 -1
  179. package/out/zero-server/src/queries/process-queries.js +1 -1
  180. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  181. package/out/zero-server/src/zql-database.d.ts.map +1 -1
  182. package/out/zero-server/src/zql-database.js +1 -1
  183. package/out/zero-server/src/zql-database.js.map +1 -1
  184. package/out/zero-solid/src/use-query.d.ts +3 -3
  185. package/out/zero-solid/src/use-query.d.ts.map +1 -1
  186. package/out/zero-solid/src/use-query.js +27 -38
  187. package/out/zero-solid/src/use-query.js.map +1 -1
  188. package/out/zero-solid/src/use-zero-connection-state.d.ts.map +1 -1
  189. package/out/zero-solid/src/use-zero-connection-state.js +7 -5
  190. package/out/zero-solid/src/use-zero-connection-state.js.map +1 -1
  191. package/out/zero-solid/src/use-zero-online.d.ts.map +1 -1
  192. package/out/zero-solid/src/use-zero-online.js +7 -5
  193. package/out/zero-solid/src/use-zero-online.js.map +1 -1
  194. package/out/zero-solid/src/use-zero.d.ts +6 -5
  195. package/out/zero-solid/src/use-zero.d.ts.map +1 -1
  196. package/out/zero-solid/src/use-zero.js +2 -6
  197. package/out/zero-solid/src/use-zero.js.map +1 -1
  198. package/out/zql/src/builder/builder.d.ts +2 -1
  199. package/out/zql/src/builder/builder.d.ts.map +1 -1
  200. package/out/zql/src/builder/builder.js +4 -3
  201. package/out/zql/src/builder/builder.js.map +1 -1
  202. package/out/zql/src/mutate/custom.d.ts +15 -6
  203. package/out/zql/src/mutate/custom.d.ts.map +1 -1
  204. package/out/zql/src/mutate/custom.js +6 -6
  205. package/out/zql/src/mutate/custom.js.map +1 -1
  206. package/out/zql/src/mutate/mutator-registry.d.ts +142 -0
  207. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -0
  208. package/out/zql/src/mutate/mutator-registry.js +97 -0
  209. package/out/zql/src/mutate/mutator-registry.js.map +1 -0
  210. package/out/zql/src/mutate/mutator.d.ts +98 -0
  211. package/out/zql/src/mutate/mutator.d.ts.map +1 -0
  212. package/out/zql/src/mutate/mutator.js +35 -0
  213. package/out/zql/src/mutate/mutator.js.map +1 -0
  214. package/out/zql/src/planner/planner-connection.d.ts +7 -15
  215. package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
  216. package/out/zql/src/planner/planner-connection.js +30 -24
  217. package/out/zql/src/planner/planner-connection.js.map +1 -1
  218. package/out/zql/src/planner/planner-debug.d.ts +37 -43
  219. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  220. package/out/zql/src/planner/planner-debug.js +242 -0
  221. package/out/zql/src/planner/planner-debug.js.map +1 -0
  222. package/out/zql/src/planner/planner-fan-in.d.ts.map +1 -1
  223. package/out/zql/src/planner/planner-fan-in.js +11 -8
  224. package/out/zql/src/planner/planner-fan-in.js.map +1 -1
  225. package/out/zql/src/planner/planner-fan-out.d.ts.map +1 -1
  226. package/out/zql/src/planner/planner-fan-out.js +11 -8
  227. package/out/zql/src/planner/planner-fan-out.js.map +1 -1
  228. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  229. package/out/zql/src/planner/planner-graph.js +13 -5
  230. package/out/zql/src/planner/planner-graph.js.map +1 -1
  231. package/out/zql/src/planner/planner-join.d.ts.map +1 -1
  232. package/out/zql/src/planner/planner-join.js +12 -9
  233. package/out/zql/src/planner/planner-join.js.map +1 -1
  234. package/out/zql/src/planner/planner-node.d.ts +4 -0
  235. package/out/zql/src/planner/planner-node.d.ts.map +1 -1
  236. package/out/zql/src/planner/planner-node.js +8 -0
  237. package/out/zql/src/planner/planner-node.js.map +1 -0
  238. package/out/zql/src/query/create-builder.d.ts +7 -0
  239. package/out/zql/src/query/create-builder.d.ts.map +1 -0
  240. package/out/zql/src/query/create-builder.js +44 -0
  241. package/out/zql/src/query/create-builder.js.map +1 -0
  242. package/out/zql/src/query/named.d.ts +1 -7
  243. package/out/zql/src/query/named.d.ts.map +1 -1
  244. package/out/zql/src/query/named.js +0 -21
  245. package/out/zql/src/query/named.js.map +1 -1
  246. package/out/zql/src/query/query-impl.d.ts +4 -3
  247. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  248. package/out/zql/src/query/query-impl.js +3 -0
  249. package/out/zql/src/query/query-impl.js.map +1 -1
  250. package/out/zql/src/query/query-internals.js +0 -4
  251. package/out/zql/src/query/query-internals.js.map +1 -1
  252. package/out/zql/src/query/query-registry.d.ts +253 -0
  253. package/out/zql/src/query/query-registry.d.ts.map +1 -0
  254. package/out/zql/src/query/query-registry.js +131 -0
  255. package/out/zql/src/query/query-registry.js.map +1 -0
  256. package/out/zql/src/query/query.d.ts +16 -1
  257. package/out/zql/src/query/query.d.ts.map +1 -1
  258. package/out/zql/src/query/schema-query.d.ts +6 -0
  259. package/out/zql/src/query/schema-query.d.ts.map +1 -0
  260. package/out/zql/src/query/validate-input.js +12 -13
  261. package/out/zql/src/query/validate-input.js.map +1 -1
  262. package/package.json +2 -1
  263. package/out/zero-server/src/query-registry.d.ts +0 -10
  264. package/out/zero-server/src/query-registry.d.ts.map +0 -1
  265. package/out/zero-server/src/query-registry.js +0 -35
  266. package/out/zero-server/src/query-registry.js.map +0 -1
  267. package/out/zql/src/query/define-query.d.ts +0 -75
  268. package/out/zql/src/query/define-query.d.ts.map +0 -1
  269. package/out/zql/src/query/define-query.js +0 -47
  270. package/out/zql/src/query/define-query.js.map +0 -1
  271. package/out/zql/src/query/query-definitions.d.ts +0 -32
  272. package/out/zql/src/query/query-definitions.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"http-service.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/services/http-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAgB,EAAC,KAAK,eAAe,EAAC,MAAM,SAAS,CAAC;AAGtD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AAE1C,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,qBAAa,WAAY,YAAW,OAAO;;IACzC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;gBAQjC,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,UAAU,EACd,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1D,4DAA4D;IAC5D,SAAS,CAAC,qBAAqB,IAAI,OAAO;IAI1C,qEAAqE;IACrE,SAAS,CAAC,mBAAmB,IAAI,OAAO;IAMlC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAexB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAKpB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B"}
1
+ {"version":3,"file":"http-service.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/services/http-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAgB,EAAC,KAAK,eAAe,EAAC,MAAM,SAAS,CAAC;AAGtD,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AAE1C,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,qBAAa,WAAY,YAAW,OAAO;;IACzC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IAGnC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;gBAKtC,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,UAAU,EACd,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAY1D,SAAS,CAAC,QAAQ;IAClB,SAAS,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAGlC,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM;IAI/B,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAmBxB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAKpB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAO5B"}
@@ -1,4 +1,5 @@
1
1
  import Fastify from "fastify";
2
+ import { promiseVoid } from "../../../shared/src/resolved-promises.js";
2
3
  import { HeartbeatMonitor } from "./life-cycle.js";
3
4
  import { RunningState } from "./running-state.js";
4
5
  class HttpService {
@@ -6,7 +7,7 @@ class HttpService {
6
7
  _lc;
7
8
  #fastify;
8
9
  #port;
9
- #state;
10
+ _state;
10
11
  #heartbeatMonitor;
11
12
  #init;
12
13
  constructor(id, lc, opts, init) {
@@ -15,23 +16,25 @@ class HttpService {
15
16
  this.#fastify = Fastify();
16
17
  this.#port = opts.port;
17
18
  this.#init = init;
18
- this.#state = new RunningState(id);
19
+ this._state = new RunningState(id);
19
20
  this.#heartbeatMonitor = new HeartbeatMonitor(this._lc);
20
21
  }
21
- /** Override to delay responding to health checks on "/". */
22
- _respondToHealthCheck() {
23
- return true;
22
+ // Life-cycle hooks for subclass implementations
23
+ _onStart() {
24
24
  }
25
- /** Override to delay responding to health checks on "/keepalive". */
26
- _respondToKeepalive() {
27
- return true;
25
+ _onStop() {
26
+ return promiseVoid;
27
+ }
28
+ _onHeartbeat(_count) {
28
29
  }
29
30
  // start() is used in unit tests.
30
31
  // run() is the lifecycle method called by the ServiceRunner.
31
32
  async start() {
33
+ let heartbeats = 0;
32
34
  this.#fastify.get("/", (_req, res) => res.send("OK"));
33
35
  this.#fastify.get("/keepalive", ({ headers }, res) => {
34
36
  this.#heartbeatMonitor.onHeartbeat(headers);
37
+ this._onHeartbeat(++heartbeats);
35
38
  return res.send("OK");
36
39
  });
37
40
  await this.#init(this.#fastify);
@@ -40,17 +43,19 @@ class HttpService {
40
43
  port: this.#port
41
44
  });
42
45
  this._lc.info?.(`${this.id} listening at ${address}`);
46
+ this._onStart();
43
47
  return address;
44
48
  }
45
49
  async run() {
46
50
  await this.start();
47
- await this.#state.stopped();
51
+ await this._state.stopped();
48
52
  }
49
53
  async stop() {
50
54
  this._lc.info?.(`${this.id}: no longer accepting connections`);
51
55
  this.#heartbeatMonitor.stop();
56
+ this._state.stop(this._lc);
52
57
  await this.#fastify.close();
53
- this.#state.stop(this._lc);
58
+ await this._onStop();
54
59
  }
55
60
  }
56
61
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"http-service.js","sources":["../../../../../zero-cache/src/services/http-service.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport Fastify, {type FastifyInstance} from 'fastify';\nimport {HeartbeatMonitor} from './life-cycle.ts';\nimport {RunningState} from './running-state.ts';\nimport type {Service} from './service.ts';\n\nexport type Options = {\n port: number;\n};\n\n/**\n * Common functionality for all HttpServices. These include:\n * * Responding to health checks at \"/\"\n * * Tracking optional heartbeats at \"/keepalive\" and draining when they stop.\n */\nexport class HttpService implements Service {\n readonly id: string;\n protected readonly _lc: LogContext;\n readonly #fastify: FastifyInstance;\n readonly #port: number;\n readonly #state: RunningState;\n readonly #heartbeatMonitor: HeartbeatMonitor;\n readonly #init: (fastify: FastifyInstance) => void | Promise<void>;\n\n constructor(\n id: string,\n lc: LogContext,\n opts: Options,\n init: (fastify: FastifyInstance) => void | Promise<void>,\n ) {\n this.id = id;\n this._lc = lc.withContext('component', this.id);\n this.#fastify = Fastify();\n this.#port = opts.port;\n this.#init = init;\n this.#state = new RunningState(id);\n this.#heartbeatMonitor = new HeartbeatMonitor(this._lc);\n }\n\n /** Override to delay responding to health checks on \"/\". */\n protected _respondToHealthCheck(): boolean {\n return true;\n }\n\n /** Override to delay responding to health checks on \"/keepalive\". */\n protected _respondToKeepalive(): boolean {\n return true;\n }\n\n // start() is used in unit tests.\n // run() is the lifecycle method called by the ServiceRunner.\n async start(): Promise<string> {\n this.#fastify.get('/', (_req, res) => res.send('OK'));\n this.#fastify.get('/keepalive', ({headers}, res) => {\n this.#heartbeatMonitor.onHeartbeat(headers);\n return res.send('OK');\n });\n await this.#init(this.#fastify);\n const address = await this.#fastify.listen({\n host: '::',\n port: this.#port,\n });\n this._lc.info?.(`${this.id} listening at ${address}`);\n return address;\n }\n\n async run(): Promise<void> {\n await this.start();\n await this.#state.stopped();\n }\n\n async stop(): Promise<void> {\n this._lc.info?.(`${this.id}: no longer accepting connections`);\n this.#heartbeatMonitor.stop();\n await this.#fastify.close();\n this.#state.stop(this._lc);\n }\n}\n"],"names":[],"mappings":";;;AAeO,MAAM,YAA+B;AAAA,EACjC;AAAA,EACU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YACE,IACA,IACA,MACA,MACA;AACA,SAAK,KAAK;AACV,SAAK,MAAM,GAAG,YAAY,aAAa,KAAK,EAAE;AAC9C,SAAK,WAAW,QAAA;AAChB,SAAK,QAAQ,KAAK;AAClB,SAAK,QAAQ;AACb,SAAK,SAAS,IAAI,aAAa,EAAE;AACjC,SAAK,oBAAoB,IAAI,iBAAiB,KAAK,GAAG;AAAA,EACxD;AAAA;AAAA,EAGU,wBAAiC;AACzC,WAAO;AAAA,EACT;AAAA;AAAA,EAGU,sBAA+B;AACvC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAIA,MAAM,QAAyB;AAC7B,SAAK,SAAS,IAAI,KAAK,CAAC,MAAM,QAAQ,IAAI,KAAK,IAAI,CAAC;AACpD,SAAK,SAAS,IAAI,cAAc,CAAC,EAAC,QAAA,GAAU,QAAQ;AAClD,WAAK,kBAAkB,YAAY,OAAO;AAC1C,aAAO,IAAI,KAAK,IAAI;AAAA,IACtB,CAAC;AACD,UAAM,KAAK,MAAM,KAAK,QAAQ;AAC9B,UAAM,UAAU,MAAM,KAAK,SAAS,OAAO;AAAA,MACzC,MAAM;AAAA,MACN,MAAM,KAAK;AAAA,IAAA,CACZ;AACD,SAAK,IAAI,OAAO,GAAG,KAAK,EAAE,iBAAiB,OAAO,EAAE;AACpD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,KAAK,MAAA;AACX,UAAM,KAAK,OAAO,QAAA;AAAA,EACpB;AAAA,EAEA,MAAM,OAAsB;AAC1B,SAAK,IAAI,OAAO,GAAG,KAAK,EAAE,mCAAmC;AAC7D,SAAK,kBAAkB,KAAA;AACvB,UAAM,KAAK,SAAS,MAAA;AACpB,SAAK,OAAO,KAAK,KAAK,GAAG;AAAA,EAC3B;AACF;"}
1
+ {"version":3,"file":"http-service.js","sources":["../../../../../zero-cache/src/services/http-service.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport Fastify, {type FastifyInstance} from 'fastify';\nimport {promiseVoid} from '../../../shared/src/resolved-promises.ts';\nimport {HeartbeatMonitor} from './life-cycle.ts';\nimport {RunningState} from './running-state.ts';\nimport type {Service} from './service.ts';\n\nexport type Options = {\n port: number;\n};\n\n/**\n * Common functionality for all HttpServices. These include:\n * * Responding to health checks at \"/\"\n * * Tracking optional heartbeats at \"/keepalive\" and draining when they stop.\n */\nexport class HttpService implements Service {\n readonly id: string;\n protected readonly _lc: LogContext;\n readonly #fastify: FastifyInstance;\n readonly #port: number;\n protected readonly _state: RunningState;\n readonly #heartbeatMonitor: HeartbeatMonitor;\n readonly #init: (fastify: FastifyInstance) => void | Promise<void>;\n\n constructor(\n id: string,\n lc: LogContext,\n opts: Options,\n init: (fastify: FastifyInstance) => void | Promise<void>,\n ) {\n this.id = id;\n this._lc = lc.withContext('component', this.id);\n this.#fastify = Fastify();\n this.#port = opts.port;\n this.#init = init;\n this._state = new RunningState(id);\n this.#heartbeatMonitor = new HeartbeatMonitor(this._lc);\n }\n\n // Life-cycle hooks for subclass implementations\n protected _onStart() {}\n protected _onStop(): Promise<void> {\n return promiseVoid;\n }\n protected _onHeartbeat(_count: number) {}\n\n // start() is used in unit tests.\n // run() is the lifecycle method called by the ServiceRunner.\n async start(): Promise<string> {\n let heartbeats = 0;\n\n this.#fastify.get('/', (_req, res) => res.send('OK'));\n this.#fastify.get('/keepalive', ({headers}, res) => {\n this.#heartbeatMonitor.onHeartbeat(headers);\n this._onHeartbeat(++heartbeats);\n return res.send('OK');\n });\n await this.#init(this.#fastify);\n const address = await this.#fastify.listen({\n host: '::',\n port: this.#port,\n });\n this._lc.info?.(`${this.id} listening at ${address}`);\n this._onStart();\n return address;\n }\n\n async run(): Promise<void> {\n await this.start();\n await this._state.stopped();\n }\n\n async stop(): Promise<void> {\n this._lc.info?.(`${this.id}: no longer accepting connections`);\n this.#heartbeatMonitor.stop();\n this._state.stop(this._lc);\n await this.#fastify.close();\n await this._onStop();\n }\n}\n"],"names":[],"mappings":";;;;AAgBO,MAAM,YAA+B;AAAA,EACjC;AAAA,EACU;AAAA,EACV;AAAA,EACA;AAAA,EACU;AAAA,EACV;AAAA,EACA;AAAA,EAET,YACE,IACA,IACA,MACA,MACA;AACA,SAAK,KAAK;AACV,SAAK,MAAM,GAAG,YAAY,aAAa,KAAK,EAAE;AAC9C,SAAK,WAAW,QAAA;AAChB,SAAK,QAAQ,KAAK;AAClB,SAAK,QAAQ;AACb,SAAK,SAAS,IAAI,aAAa,EAAE;AACjC,SAAK,oBAAoB,IAAI,iBAAiB,KAAK,GAAG;AAAA,EACxD;AAAA;AAAA,EAGU,WAAW;AAAA,EAAC;AAAA,EACZ,UAAyB;AACjC,WAAO;AAAA,EACT;AAAA,EACU,aAAa,QAAgB;AAAA,EAAC;AAAA;AAAA;AAAA,EAIxC,MAAM,QAAyB;AAC7B,QAAI,aAAa;AAEjB,SAAK,SAAS,IAAI,KAAK,CAAC,MAAM,QAAQ,IAAI,KAAK,IAAI,CAAC;AACpD,SAAK,SAAS,IAAI,cAAc,CAAC,EAAC,QAAA,GAAU,QAAQ;AAClD,WAAK,kBAAkB,YAAY,OAAO;AAC1C,WAAK,aAAa,EAAE,UAAU;AAC9B,aAAO,IAAI,KAAK,IAAI;AAAA,IACtB,CAAC;AACD,UAAM,KAAK,MAAM,KAAK,QAAQ;AAC9B,UAAM,UAAU,MAAM,KAAK,SAAS,OAAO;AAAA,MACzC,MAAM;AAAA,MACN,MAAM,KAAK;AAAA,IAAA,CACZ;AACD,SAAK,IAAI,OAAO,GAAG,KAAK,EAAE,iBAAiB,OAAO,EAAE;AACpD,SAAK,SAAA;AACL,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,KAAK,MAAA;AACX,UAAM,KAAK,OAAO,QAAA;AAAA,EACpB;AAAA,EAEA,MAAM,OAAsB;AAC1B,SAAK,IAAI,OAAO,GAAG,KAAK,EAAE,mCAAmC;AAC7D,SAAK,kBAAkB,KAAA;AACvB,SAAK,OAAO,KAAK,KAAK,GAAG;AACzB,UAAM,KAAK,SAAS,MAAA;AACpB,UAAM,KAAK,QAAA;AAAA,EACb;AACF;"}
@@ -3,6 +3,7 @@ import type { JWTPayload } from 'jose';
3
3
  import postgres from 'postgres';
4
4
  import { ErrorKind } from '../../../../zero-protocol/src/error-kind.ts';
5
5
  import { type CRUDMutation, type InsertOp, type Mutation, type UpsertOp } from '../../../../zero-protocol/src/push.ts';
6
+ import type { DatabaseStorage } from '../../../../zqlite/src/database-storage.ts';
6
7
  import { type WriteAuthorizer } from '../../auth/write-authorizer.ts';
7
8
  import { type ZeroConfig } from '../../config/zero-config.ts';
8
9
  import type { PostgresDB, PostgresTransaction } from '../../types/pg.ts';
@@ -18,7 +19,7 @@ export interface Mutagen extends RefCountedService {
18
19
  export declare class MutagenService implements Mutagen, Service {
19
20
  #private;
20
21
  readonly id: string;
21
- constructor(lc: LogContext, shard: ShardID, clientGroupID: string, upstream: PostgresDB, config: ZeroConfig);
22
+ constructor(lc: LogContext, shard: ShardID, clientGroupID: string, upstream: PostgresDB, config: ZeroConfig, writeAuthzStorage: DatabaseStorage);
22
23
  ref(): void;
23
24
  unref(): void;
24
25
  hasRefs(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"mutagen.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/mutagen/mutagen.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mutagen.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/mutagen/mutagen.ts"],"names":[],"mappings":"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"}
@@ -35,7 +35,7 @@ class MutagenService {
35
35
  "crud",
36
36
  "Number of CRUD mutations processed"
37
37
  );
38
- constructor(lc, shard, clientGroupID, upstream, config) {
38
+ constructor(lc, shard, clientGroupID, upstream, config, writeAuthzStorage) {
39
39
  this.id = clientGroupID;
40
40
  this.#lc = lc;
41
41
  this.#upstream = upstream;
@@ -48,7 +48,8 @@ class MutagenService {
48
48
  config,
49
49
  this.#replica,
50
50
  shard.appID,
51
- clientGroupID
51
+ clientGroupID,
52
+ writeAuthzStorage
52
53
  );
53
54
  if (config.perUserMutationLimit.max !== void 0) {
54
55
  this.#limiter = new SlidingWindowLimiter(
@@ -1 +1 @@
1
- {"version":3,"file":"mutagen.js","sources":["../../../../../../zero-cache/src/services/mutagen/mutagen.ts"],"sourcesContent":["import {PG_SERIALIZATION_FAILURE} from '@drdgvhbh/postgres-error-codes';\nimport type {LogContext} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport type {JWTPayload} from 'jose';\nimport postgres from 'postgres';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport * as MutationType from '../../../../zero-protocol/src/mutation-type-enum.ts';\nimport {\n primaryKeyValueSchema,\n type PrimaryKeyValue,\n} from '../../../../zero-protocol/src/primary-key.ts';\nimport {\n type CRUDMutation,\n type DeleteOp,\n type InsertOp,\n type Mutation,\n type UpdateOp,\n type UpsertOp,\n} from '../../../../zero-protocol/src/push.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {\n WriteAuthorizerImpl,\n type WriteAuthorizer,\n} from '../../auth/write-authorizer.ts';\nimport {type ZeroConfig} from '../../config/zero-config.ts';\nimport * as Mode from '../../db/mode-enum.ts';\nimport {getOrCreateCounter} from '../../observability/metrics.ts';\nimport {recordMutation} from '../../server/anonymous-otel-start.ts';\nimport type {PostgresDB, PostgresTransaction} from '../../types/pg.ts';\nimport {throwProtocolErrorIfSchemaVersionNotSupported} from '../../types/schema-versions.ts';\nimport {appSchema, upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport {SlidingWindowLimiter} from '../limiter/sliding-window-limiter.ts';\nimport type {RefCountedService, Service} from '../service.ts';\nimport {MutationAlreadyProcessedError} from './error.ts';\nimport {\n isProtocolError,\n ProtocolError,\n} from '../../../../zero-protocol/src/error.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\n\n// An error encountered processing a mutation.\n// Returned back to application for display to user.\nexport type MutationError = [\n kind: ErrorKind.MutationFailed | ErrorKind.MutationRateLimited,\n desc: string,\n];\n\nexport interface Mutagen extends RefCountedService {\n processMutation(\n mutation: Mutation,\n authData: JWTPayload | undefined,\n schemaVersion: number | undefined,\n customMutatorsEnabled: boolean,\n ): Promise<MutationError | undefined>;\n}\n\nexport class MutagenService implements Mutagen, Service {\n readonly id: string;\n readonly #lc: LogContext;\n readonly #upstream: PostgresDB;\n readonly #shard: ShardID;\n readonly #stopped = resolver();\n readonly #replica: Database;\n readonly #writeAuthorizer: WriteAuthorizerImpl;\n readonly #limiter: SlidingWindowLimiter | undefined;\n #refCount = 0;\n #isStopped = false;\n\n readonly #crudMutations = getOrCreateCounter(\n 'mutation',\n 'crud',\n 'Number of CRUD mutations processed',\n );\n\n constructor(\n lc: LogContext,\n shard: ShardID,\n clientGroupID: string,\n upstream: PostgresDB,\n config: ZeroConfig,\n ) {\n this.id = clientGroupID;\n this.#lc = lc;\n this.#upstream = upstream;\n this.#shard = shard;\n this.#replica = new Database(this.#lc, config.replica.file, {\n fileMustExist: true,\n });\n this.#writeAuthorizer = new WriteAuthorizerImpl(\n this.#lc,\n config,\n this.#replica,\n shard.appID,\n clientGroupID,\n );\n\n if (config.perUserMutationLimit.max !== undefined) {\n this.#limiter = new SlidingWindowLimiter(\n config.perUserMutationLimit.windowMs,\n config.perUserMutationLimit.max,\n );\n }\n }\n\n ref() {\n assert(!this.#isStopped, 'MutagenService is already stopped');\n ++this.#refCount;\n }\n\n unref() {\n assert(!this.#isStopped, 'MutagenService is already stopped');\n --this.#refCount;\n if (this.#refCount <= 0) {\n void this.stop();\n }\n }\n\n hasRefs(): boolean {\n return this.#refCount > 0;\n }\n\n processMutation(\n mutation: Mutation,\n authData: JWTPayload | undefined,\n schemaVersion: number | undefined,\n customMutatorsEnabled = false,\n ): Promise<MutationError | undefined> {\n if (this.#limiter?.canDo() === false) {\n return Promise.resolve([\n ErrorKind.MutationRateLimited,\n 'Rate limit exceeded',\n ]);\n }\n this.#crudMutations.add(1, {\n clientGroupID: this.id,\n });\n return processMutation(\n this.#lc,\n authData,\n this.#upstream,\n this.#shard,\n this.id,\n mutation,\n this.#writeAuthorizer,\n schemaVersion,\n undefined,\n customMutatorsEnabled,\n );\n }\n\n run(): Promise<void> {\n return this.#stopped.promise;\n }\n\n stop(): Promise<void> {\n if (this.#isStopped) {\n return this.#stopped.promise;\n }\n this.#writeAuthorizer.destroy();\n this.#isStopped = true;\n this.#stopped.resolve();\n return this.#stopped.promise;\n }\n}\n\nconst MAX_SERIALIZATION_ATTEMPTS = 10;\n\nexport async function processMutation(\n lc: LogContext,\n authData: JWTPayload | undefined,\n db: PostgresDB,\n shard: ShardID,\n clientGroupID: string,\n mutation: Mutation,\n writeAuthorizer: WriteAuthorizer,\n schemaVersion: number | undefined,\n onTxStart?: () => void | Promise<void>, // for testing\n customMutatorsEnabled = false,\n): Promise<MutationError | undefined> {\n assert(\n mutation.type === MutationType.CRUD,\n 'Only CRUD mutations are supported',\n );\n lc = lc.withContext('mutationID', mutation.id);\n lc = lc.withContext('processMutation');\n lc.debug?.('Process mutation start', mutation);\n\n // Record mutation processing attempt for telemetry (regardless of success/failure)\n recordMutation('crud');\n\n let result: MutationError | undefined;\n\n const start = Date.now();\n try {\n // Mutations can fail for a variety of reasons:\n //\n // - application error\n // - network/db error\n // - zero bug\n //\n // For application errors what we want is to re-run the mutation in\n // \"error mode\", which skips the actual mutation and just updates the\n // lastMutationID. Then return the error to the app.\n //\n // However, it's hard to tell the difference between application errors\n // and the other types.\n //\n // A reasonable policy ends up being to just retry every mutation once\n // in error mode. If the error mode mutation succeeds then we assume it\n // was an application error and return the error to the app. Otherwise,\n // we know it was something internal and we log it.\n //\n // This is not 100% correct - there are theoretical cases where we\n // return an internal error to the app that shouldn't have been. But it\n // would have to be a crazy coincidence: we'd have to have a network\n // error on the first attempt that resolves by the second attempt.\n //\n // One might ask why not try/catch just the calls to the mutators and\n // consider those application errors. That is actually what we do in\n // Replicache:\n //\n // https://github.com/rocicorp/todo-row-versioning/blob/9a0a79dc2d2de32c4fac61b5d1634bd9a9e66b7c/server/src/push.ts#L131\n //\n // We don't do it here because:\n //\n // 1. It's still not perfect. It's hard to isolate SQL errors in\n // mutators due to app developer mistakes from SQL errors due to\n // Zero mistakes.\n // 2. It's not possible to do this with the pg library we're using in\n // Zero anyway: https://github.com/porsager/postgres/issues/455.\n //\n // Personally I think this simple retry policy is nice.\n let errorMode = false;\n for (let i = 0; i < MAX_SERIALIZATION_ATTEMPTS; i++) {\n try {\n await db.begin(Mode.SERIALIZABLE, async tx => {\n // Simulates a concurrent request for testing. In production this is a noop.\n const done = onTxStart?.();\n try {\n return await processMutationWithTx(\n lc,\n tx,\n authData,\n shard,\n clientGroupID,\n schemaVersion,\n mutation,\n errorMode,\n writeAuthorizer,\n );\n } finally {\n await done;\n }\n });\n if (errorMode) {\n lc.debug?.('Ran mutation successfully in error mode');\n }\n break;\n } catch (e) {\n if (e instanceof MutationAlreadyProcessedError) {\n lc.debug?.(e.message);\n // Don't double-count already processed mutations, but they were counted above\n return undefined;\n }\n if (\n isProtocolError(e) &&\n !errorMode &&\n e.kind === ErrorKind.InvalidPush &&\n customMutatorsEnabled &&\n i < 2\n ) {\n // We're temporarily supporting custom mutators AND CRUD mutators at the same time.\n // This can create a lot of OOO mutation errors since we do not know when the API server\n // has applied a custom mutation before moving on to process CRUD mutations.\n // The temporary workaround (since CRUD is being deprecated) is to retry the mutation\n // after a small delay. Users are not expected to be running both CRUD and Custom mutators.\n // They should migrate completely to custom mutators.\n lc.info?.(\n 'Both CRUD and Custom mutators are being used at once. This is supported for now but IS NOT RECOMMENDED. Migrate completely to custom mutators.',\n e,\n );\n await new Promise(resolve => setTimeout(resolve, 100));\n continue;\n }\n if (isProtocolError(e) || errorMode) {\n lc.error?.('Process mutation error', e);\n throw e;\n }\n if (\n e instanceof postgres.PostgresError &&\n e.code === PG_SERIALIZATION_FAILURE\n ) {\n lc.info?.(`attempt ${i + 1}: ${String(e)}`, e);\n continue; // Retry up to MAX_SERIALIZATION_ATTEMPTS.\n }\n result = [ErrorKind.MutationFailed, String(e)];\n if (errorMode) {\n break;\n }\n lc.error?.('Got error running mutation, re-running in error mode', e);\n errorMode = true;\n i--;\n }\n }\n } finally {\n lc.debug?.('Process mutation complete in', Date.now() - start);\n }\n return result;\n}\n\nexport async function processMutationWithTx(\n lc: LogContext,\n tx: PostgresTransaction,\n authData: JWTPayload | undefined,\n shard: ShardID,\n clientGroupID: string,\n schemaVersion: number | undefined,\n mutation: CRUDMutation,\n errorMode: boolean,\n authorizer: WriteAuthorizer,\n) {\n const tasks: (() => Promise<unknown>)[] = [];\n\n async function execute(stmt: postgres.PendingQuery<postgres.Row[]>) {\n try {\n return await stmt.execute();\n } finally {\n const q = stmt as unknown as Query;\n lc.debug?.(`${q.string}: ${JSON.stringify(q.parameters)}`);\n }\n }\n\n authorizer.reloadPermissions();\n\n if (!errorMode) {\n const {ops} = mutation.args[0];\n const normalizedOps = authorizer.normalizeOps(ops);\n const [canPre, canPost] = await Promise.all([\n authorizer.canPreMutation(authData, normalizedOps),\n authorizer.canPostMutation(authData, normalizedOps),\n ]);\n if (canPre && canPost) {\n for (const op of ops) {\n switch (op.op) {\n case 'insert':\n tasks.push(() => execute(getInsertSQL(tx, op)));\n break;\n case 'upsert':\n tasks.push(() => execute(getUpsertSQL(tx, op)));\n break;\n case 'update':\n tasks.push(() => execute(getUpdateSQL(tx, op)));\n break;\n case 'delete':\n tasks.push(() => execute(getDeleteSQL(tx, op)));\n break;\n default:\n unreachable(op);\n }\n }\n }\n }\n\n // Confirm the mutation even though it may have been blocked by the authorizer.\n // Authorizer blocking a mutation is not an error but the correct result of the mutation.\n tasks.unshift(() =>\n checkSchemaVersionAndIncrementLastMutationID(\n tx,\n shard,\n clientGroupID,\n schemaVersion,\n mutation.clientID,\n mutation.id,\n ),\n );\n\n // Note: An error thrown from any Promise aborts the entire transaction.\n await Promise.all(tasks.map(task => task()));\n}\n\nexport function getInsertSQL(\n tx: postgres.TransactionSql,\n create: InsertOp,\n): postgres.PendingQuery<postgres.Row[]> {\n return tx`INSERT INTO ${tx(create.tableName)} ${tx(create.value)}`;\n}\n\nexport function getUpsertSQL(\n tx: postgres.TransactionSql,\n set: UpsertOp,\n): postgres.PendingQuery<postgres.Row[]> {\n const {tableName, primaryKey, value} = set;\n return tx`\n INSERT INTO ${tx(tableName)} ${tx(value)}\n ON CONFLICT (${tx(primaryKey)})\n DO UPDATE SET ${tx(value)}\n `;\n}\n\nfunction getUpdateSQL(\n tx: postgres.TransactionSql,\n update: UpdateOp,\n): postgres.PendingQuery<postgres.Row[]> {\n const table = update.tableName;\n const {primaryKey, value} = update;\n const id: Record<string, PrimaryKeyValue> = {};\n for (const key of primaryKey) {\n id[key] = v.parse(value[key], primaryKeyValueSchema);\n }\n return tx`UPDATE ${tx(table)} SET ${tx(value)} WHERE ${Object.entries(\n id,\n ).flatMap(([key, value], i) =>\n i ? [tx`AND`, tx`${tx(key)} = ${value}`] : tx`${tx(key)} = ${value}`,\n )}`;\n}\n\nfunction getDeleteSQL(\n tx: postgres.TransactionSql,\n deleteOp: DeleteOp,\n): postgres.PendingQuery<postgres.Row[]> {\n const {tableName, primaryKey, value} = deleteOp;\n\n const conditions = [];\n for (const key of primaryKey) {\n if (conditions.length > 0) {\n conditions.push(tx`AND`);\n }\n conditions.push(tx`${tx(key)} = ${value[key]}`);\n }\n\n return tx`DELETE FROM ${tx(tableName)} WHERE ${conditions}`;\n}\n\nasync function checkSchemaVersionAndIncrementLastMutationID(\n tx: PostgresTransaction,\n shard: ShardID,\n clientGroupID: string,\n schemaVersion: number | undefined,\n clientID: string,\n receivedMutationID: number,\n) {\n const [[{lastMutationID}], supportedVersionRange] = await Promise.all([\n tx<{lastMutationID: bigint}[]>`\n INSERT INTO ${tx(upstreamSchema(shard))}.clients \n as current (\"clientGroupID\", \"clientID\", \"lastMutationID\")\n VALUES (${clientGroupID}, ${clientID}, ${1})\n ON CONFLICT (\"clientGroupID\", \"clientID\")\n DO UPDATE SET \"lastMutationID\" = current.\"lastMutationID\" + 1\n RETURNING \"lastMutationID\"\n `,\n schemaVersion === undefined\n ? undefined\n : tx<\n {\n minSupportedVersion: number;\n maxSupportedVersion: number;\n }[]\n >`SELECT \"minSupportedVersion\", \"maxSupportedVersion\" \n FROM ${tx(appSchema(shard))}.\"schemaVersions\"`,\n ]);\n\n // ABORT if the resulting lastMutationID is not equal to the receivedMutationID.\n if (receivedMutationID < lastMutationID) {\n throw new MutationAlreadyProcessedError(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n } else if (receivedMutationID > lastMutationID) {\n throw new ProtocolError({\n kind: ErrorKind.InvalidPush,\n message: `Push contains unexpected mutation id ${receivedMutationID} for client ${clientID}. Expected mutation id ${lastMutationID.toString()}.`,\n origin: ErrorOrigin.ZeroCache,\n });\n }\n\n if (schemaVersion !== undefined && supportedVersionRange !== undefined) {\n assert(supportedVersionRange.length === 1);\n throwProtocolErrorIfSchemaVersionNotSupported(\n schemaVersion,\n supportedVersionRange[0],\n );\n }\n}\n\n// The slice of information from the Query object in Postgres.js that gets logged for debugging.\n// https://github.com/porsager/postgres/blob/f58cd4f3affd3e8ce8f53e42799672d86cd2c70b/src/connection.js#L219\ntype Query = {string: string; parameters: object[]};\n"],"names":["ErrorKind.MutationRateLimited","MutationType.CRUD","Mode.SERIALIZABLE","ErrorKind.InvalidPush","ErrorKind.MutationFailed","v.parse","value","ErrorOrigin.ZeroCache"],"mappings":"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"}
1
+ {"version":3,"file":"mutagen.js","sources":["../../../../../../zero-cache/src/services/mutagen/mutagen.ts"],"sourcesContent":["import {PG_SERIALIZATION_FAILURE} from '@drdgvhbh/postgres-error-codes';\nimport type {LogContext} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport type {JWTPayload} from 'jose';\nimport postgres from 'postgres';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport * as MutationType from '../../../../zero-protocol/src/mutation-type-enum.ts';\nimport {\n primaryKeyValueSchema,\n type PrimaryKeyValue,\n} from '../../../../zero-protocol/src/primary-key.ts';\nimport {\n type CRUDMutation,\n type DeleteOp,\n type InsertOp,\n type Mutation,\n type UpdateOp,\n type UpsertOp,\n} from '../../../../zero-protocol/src/push.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport type {DatabaseStorage} from '../../../../zqlite/src/database-storage.ts';\nimport {\n WriteAuthorizerImpl,\n type WriteAuthorizer,\n} from '../../auth/write-authorizer.ts';\nimport {type ZeroConfig} from '../../config/zero-config.ts';\nimport * as Mode from '../../db/mode-enum.ts';\nimport {getOrCreateCounter} from '../../observability/metrics.ts';\nimport {recordMutation} from '../../server/anonymous-otel-start.ts';\nimport type {PostgresDB, PostgresTransaction} from '../../types/pg.ts';\nimport {throwProtocolErrorIfSchemaVersionNotSupported} from '../../types/schema-versions.ts';\nimport {appSchema, upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport {SlidingWindowLimiter} from '../limiter/sliding-window-limiter.ts';\nimport type {RefCountedService, Service} from '../service.ts';\nimport {MutationAlreadyProcessedError} from './error.ts';\nimport {\n isProtocolError,\n ProtocolError,\n} from '../../../../zero-protocol/src/error.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\n\n// An error encountered processing a mutation.\n// Returned back to application for display to user.\nexport type MutationError = [\n kind: ErrorKind.MutationFailed | ErrorKind.MutationRateLimited,\n desc: string,\n];\n\nexport interface Mutagen extends RefCountedService {\n processMutation(\n mutation: Mutation,\n authData: JWTPayload | undefined,\n schemaVersion: number | undefined,\n customMutatorsEnabled: boolean,\n ): Promise<MutationError | undefined>;\n}\n\nexport class MutagenService implements Mutagen, Service {\n readonly id: string;\n readonly #lc: LogContext;\n readonly #upstream: PostgresDB;\n readonly #shard: ShardID;\n readonly #stopped = resolver();\n readonly #replica: Database;\n readonly #writeAuthorizer: WriteAuthorizerImpl;\n readonly #limiter: SlidingWindowLimiter | undefined;\n #refCount = 0;\n #isStopped = false;\n\n readonly #crudMutations = getOrCreateCounter(\n 'mutation',\n 'crud',\n 'Number of CRUD mutations processed',\n );\n\n constructor(\n lc: LogContext,\n shard: ShardID,\n clientGroupID: string,\n upstream: PostgresDB,\n config: ZeroConfig,\n writeAuthzStorage: DatabaseStorage,\n ) {\n this.id = clientGroupID;\n this.#lc = lc;\n this.#upstream = upstream;\n this.#shard = shard;\n this.#replica = new Database(this.#lc, config.replica.file, {\n fileMustExist: true,\n });\n this.#writeAuthorizer = new WriteAuthorizerImpl(\n this.#lc,\n config,\n this.#replica,\n shard.appID,\n clientGroupID,\n writeAuthzStorage,\n );\n\n if (config.perUserMutationLimit.max !== undefined) {\n this.#limiter = new SlidingWindowLimiter(\n config.perUserMutationLimit.windowMs,\n config.perUserMutationLimit.max,\n );\n }\n }\n\n ref() {\n assert(!this.#isStopped, 'MutagenService is already stopped');\n ++this.#refCount;\n }\n\n unref() {\n assert(!this.#isStopped, 'MutagenService is already stopped');\n --this.#refCount;\n if (this.#refCount <= 0) {\n void this.stop();\n }\n }\n\n hasRefs(): boolean {\n return this.#refCount > 0;\n }\n\n processMutation(\n mutation: Mutation,\n authData: JWTPayload | undefined,\n schemaVersion: number | undefined,\n customMutatorsEnabled = false,\n ): Promise<MutationError | undefined> {\n if (this.#limiter?.canDo() === false) {\n return Promise.resolve([\n ErrorKind.MutationRateLimited,\n 'Rate limit exceeded',\n ]);\n }\n this.#crudMutations.add(1, {\n clientGroupID: this.id,\n });\n return processMutation(\n this.#lc,\n authData,\n this.#upstream,\n this.#shard,\n this.id,\n mutation,\n this.#writeAuthorizer,\n schemaVersion,\n undefined,\n customMutatorsEnabled,\n );\n }\n\n run(): Promise<void> {\n return this.#stopped.promise;\n }\n\n stop(): Promise<void> {\n if (this.#isStopped) {\n return this.#stopped.promise;\n }\n this.#writeAuthorizer.destroy();\n this.#isStopped = true;\n this.#stopped.resolve();\n return this.#stopped.promise;\n }\n}\n\nconst MAX_SERIALIZATION_ATTEMPTS = 10;\n\nexport async function processMutation(\n lc: LogContext,\n authData: JWTPayload | undefined,\n db: PostgresDB,\n shard: ShardID,\n clientGroupID: string,\n mutation: Mutation,\n writeAuthorizer: WriteAuthorizer,\n schemaVersion: number | undefined,\n onTxStart?: () => void | Promise<void>, // for testing\n customMutatorsEnabled = false,\n): Promise<MutationError | undefined> {\n assert(\n mutation.type === MutationType.CRUD,\n 'Only CRUD mutations are supported',\n );\n lc = lc.withContext('mutationID', mutation.id);\n lc = lc.withContext('processMutation');\n lc.debug?.('Process mutation start', mutation);\n\n // Record mutation processing attempt for telemetry (regardless of success/failure)\n recordMutation('crud');\n\n let result: MutationError | undefined;\n\n const start = Date.now();\n try {\n // Mutations can fail for a variety of reasons:\n //\n // - application error\n // - network/db error\n // - zero bug\n //\n // For application errors what we want is to re-run the mutation in\n // \"error mode\", which skips the actual mutation and just updates the\n // lastMutationID. Then return the error to the app.\n //\n // However, it's hard to tell the difference between application errors\n // and the other types.\n //\n // A reasonable policy ends up being to just retry every mutation once\n // in error mode. If the error mode mutation succeeds then we assume it\n // was an application error and return the error to the app. Otherwise,\n // we know it was something internal and we log it.\n //\n // This is not 100% correct - there are theoretical cases where we\n // return an internal error to the app that shouldn't have been. But it\n // would have to be a crazy coincidence: we'd have to have a network\n // error on the first attempt that resolves by the second attempt.\n //\n // One might ask why not try/catch just the calls to the mutators and\n // consider those application errors. That is actually what we do in\n // Replicache:\n //\n // https://github.com/rocicorp/todo-row-versioning/blob/9a0a79dc2d2de32c4fac61b5d1634bd9a9e66b7c/server/src/push.ts#L131\n //\n // We don't do it here because:\n //\n // 1. It's still not perfect. It's hard to isolate SQL errors in\n // mutators due to app developer mistakes from SQL errors due to\n // Zero mistakes.\n // 2. It's not possible to do this with the pg library we're using in\n // Zero anyway: https://github.com/porsager/postgres/issues/455.\n //\n // Personally I think this simple retry policy is nice.\n let errorMode = false;\n for (let i = 0; i < MAX_SERIALIZATION_ATTEMPTS; i++) {\n try {\n await db.begin(Mode.SERIALIZABLE, async tx => {\n // Simulates a concurrent request for testing. In production this is a noop.\n const done = onTxStart?.();\n try {\n return await processMutationWithTx(\n lc,\n tx,\n authData,\n shard,\n clientGroupID,\n schemaVersion,\n mutation,\n errorMode,\n writeAuthorizer,\n );\n } finally {\n await done;\n }\n });\n if (errorMode) {\n lc.debug?.('Ran mutation successfully in error mode');\n }\n break;\n } catch (e) {\n if (e instanceof MutationAlreadyProcessedError) {\n lc.debug?.(e.message);\n // Don't double-count already processed mutations, but they were counted above\n return undefined;\n }\n if (\n isProtocolError(e) &&\n !errorMode &&\n e.kind === ErrorKind.InvalidPush &&\n customMutatorsEnabled &&\n i < 2\n ) {\n // We're temporarily supporting custom mutators AND CRUD mutators at the same time.\n // This can create a lot of OOO mutation errors since we do not know when the API server\n // has applied a custom mutation before moving on to process CRUD mutations.\n // The temporary workaround (since CRUD is being deprecated) is to retry the mutation\n // after a small delay. Users are not expected to be running both CRUD and Custom mutators.\n // They should migrate completely to custom mutators.\n lc.info?.(\n 'Both CRUD and Custom mutators are being used at once. This is supported for now but IS NOT RECOMMENDED. Migrate completely to custom mutators.',\n e,\n );\n await new Promise(resolve => setTimeout(resolve, 100));\n continue;\n }\n if (isProtocolError(e) || errorMode) {\n lc.error?.('Process mutation error', e);\n throw e;\n }\n if (\n e instanceof postgres.PostgresError &&\n e.code === PG_SERIALIZATION_FAILURE\n ) {\n lc.info?.(`attempt ${i + 1}: ${String(e)}`, e);\n continue; // Retry up to MAX_SERIALIZATION_ATTEMPTS.\n }\n result = [ErrorKind.MutationFailed, String(e)];\n if (errorMode) {\n break;\n }\n lc.error?.('Got error running mutation, re-running in error mode', e);\n errorMode = true;\n i--;\n }\n }\n } finally {\n lc.debug?.('Process mutation complete in', Date.now() - start);\n }\n return result;\n}\n\nexport async function processMutationWithTx(\n lc: LogContext,\n tx: PostgresTransaction,\n authData: JWTPayload | undefined,\n shard: ShardID,\n clientGroupID: string,\n schemaVersion: number | undefined,\n mutation: CRUDMutation,\n errorMode: boolean,\n authorizer: WriteAuthorizer,\n) {\n const tasks: (() => Promise<unknown>)[] = [];\n\n async function execute(stmt: postgres.PendingQuery<postgres.Row[]>) {\n try {\n return await stmt.execute();\n } finally {\n const q = stmt as unknown as Query;\n lc.debug?.(`${q.string}: ${JSON.stringify(q.parameters)}`);\n }\n }\n\n authorizer.reloadPermissions();\n\n if (!errorMode) {\n const {ops} = mutation.args[0];\n const normalizedOps = authorizer.normalizeOps(ops);\n const [canPre, canPost] = await Promise.all([\n authorizer.canPreMutation(authData, normalizedOps),\n authorizer.canPostMutation(authData, normalizedOps),\n ]);\n if (canPre && canPost) {\n for (const op of ops) {\n switch (op.op) {\n case 'insert':\n tasks.push(() => execute(getInsertSQL(tx, op)));\n break;\n case 'upsert':\n tasks.push(() => execute(getUpsertSQL(tx, op)));\n break;\n case 'update':\n tasks.push(() => execute(getUpdateSQL(tx, op)));\n break;\n case 'delete':\n tasks.push(() => execute(getDeleteSQL(tx, op)));\n break;\n default:\n unreachable(op);\n }\n }\n }\n }\n\n // Confirm the mutation even though it may have been blocked by the authorizer.\n // Authorizer blocking a mutation is not an error but the correct result of the mutation.\n tasks.unshift(() =>\n checkSchemaVersionAndIncrementLastMutationID(\n tx,\n shard,\n clientGroupID,\n schemaVersion,\n mutation.clientID,\n mutation.id,\n ),\n );\n\n // Note: An error thrown from any Promise aborts the entire transaction.\n await Promise.all(tasks.map(task => task()));\n}\n\nexport function getInsertSQL(\n tx: postgres.TransactionSql,\n create: InsertOp,\n): postgres.PendingQuery<postgres.Row[]> {\n return tx`INSERT INTO ${tx(create.tableName)} ${tx(create.value)}`;\n}\n\nexport function getUpsertSQL(\n tx: postgres.TransactionSql,\n set: UpsertOp,\n): postgres.PendingQuery<postgres.Row[]> {\n const {tableName, primaryKey, value} = set;\n return tx`\n INSERT INTO ${tx(tableName)} ${tx(value)}\n ON CONFLICT (${tx(primaryKey)})\n DO UPDATE SET ${tx(value)}\n `;\n}\n\nfunction getUpdateSQL(\n tx: postgres.TransactionSql,\n update: UpdateOp,\n): postgres.PendingQuery<postgres.Row[]> {\n const table = update.tableName;\n const {primaryKey, value} = update;\n const id: Record<string, PrimaryKeyValue> = {};\n for (const key of primaryKey) {\n id[key] = v.parse(value[key], primaryKeyValueSchema);\n }\n return tx`UPDATE ${tx(table)} SET ${tx(value)} WHERE ${Object.entries(\n id,\n ).flatMap(([key, value], i) =>\n i ? [tx`AND`, tx`${tx(key)} = ${value}`] : tx`${tx(key)} = ${value}`,\n )}`;\n}\n\nfunction getDeleteSQL(\n tx: postgres.TransactionSql,\n deleteOp: DeleteOp,\n): postgres.PendingQuery<postgres.Row[]> {\n const {tableName, primaryKey, value} = deleteOp;\n\n const conditions = [];\n for (const key of primaryKey) {\n if (conditions.length > 0) {\n conditions.push(tx`AND`);\n }\n conditions.push(tx`${tx(key)} = ${value[key]}`);\n }\n\n return tx`DELETE FROM ${tx(tableName)} WHERE ${conditions}`;\n}\n\nasync function checkSchemaVersionAndIncrementLastMutationID(\n tx: PostgresTransaction,\n shard: ShardID,\n clientGroupID: string,\n schemaVersion: number | undefined,\n clientID: string,\n receivedMutationID: number,\n) {\n const [[{lastMutationID}], supportedVersionRange] = await Promise.all([\n tx<{lastMutationID: bigint}[]>`\n INSERT INTO ${tx(upstreamSchema(shard))}.clients \n as current (\"clientGroupID\", \"clientID\", \"lastMutationID\")\n VALUES (${clientGroupID}, ${clientID}, ${1})\n ON CONFLICT (\"clientGroupID\", \"clientID\")\n DO UPDATE SET \"lastMutationID\" = current.\"lastMutationID\" + 1\n RETURNING \"lastMutationID\"\n `,\n schemaVersion === undefined\n ? undefined\n : tx<\n {\n minSupportedVersion: number;\n maxSupportedVersion: number;\n }[]\n >`SELECT \"minSupportedVersion\", \"maxSupportedVersion\" \n FROM ${tx(appSchema(shard))}.\"schemaVersions\"`,\n ]);\n\n // ABORT if the resulting lastMutationID is not equal to the receivedMutationID.\n if (receivedMutationID < lastMutationID) {\n throw new MutationAlreadyProcessedError(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n } else if (receivedMutationID > lastMutationID) {\n throw new ProtocolError({\n kind: ErrorKind.InvalidPush,\n message: `Push contains unexpected mutation id ${receivedMutationID} for client ${clientID}. Expected mutation id ${lastMutationID.toString()}.`,\n origin: ErrorOrigin.ZeroCache,\n });\n }\n\n if (schemaVersion !== undefined && supportedVersionRange !== undefined) {\n assert(supportedVersionRange.length === 1);\n throwProtocolErrorIfSchemaVersionNotSupported(\n schemaVersion,\n supportedVersionRange[0],\n );\n }\n}\n\n// The slice of information from the Query object in Postgres.js that gets logged for debugging.\n// https://github.com/porsager/postgres/blob/f58cd4f3affd3e8ce8f53e42799672d86cd2c70b/src/connection.js#L219\ntype Query = {string: string; parameters: object[]};\n"],"names":["ErrorKind.MutationRateLimited","MutationType.CRUD","Mode.SERIALIZABLE","ErrorKind.InvalidPush","ErrorKind.MutationFailed","v.parse","value","ErrorOrigin.ZeroCache"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2DO,MAAM,eAA2C;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW,SAAA;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AAAA,EAEJ,iBAAiB;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAGF,YACE,IACA,OACA,eACA,UACA,QACA,mBACA;AACA,SAAK,KAAK;AACV,SAAK,MAAM;AACX,SAAK,YAAY;AACjB,SAAK,SAAS;AACd,SAAK,WAAW,IAAI,SAAS,KAAK,KAAK,OAAO,QAAQ,MAAM;AAAA,MAC1D,eAAe;AAAA,IAAA,CAChB;AACD,SAAK,mBAAmB,IAAI;AAAA,MAC1B,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,OAAO,qBAAqB,QAAQ,QAAW;AACjD,WAAK,WAAW,IAAI;AAAA,QAClB,OAAO,qBAAqB;AAAA,QAC5B,OAAO,qBAAqB;AAAA,MAAA;AAAA,IAEhC;AAAA,EACF;AAAA,EAEA,MAAM;AACJ,WAAO,CAAC,KAAK,YAAY,mCAAmC;AAC5D,MAAE,KAAK;AAAA,EACT;AAAA,EAEA,QAAQ;AACN,WAAO,CAAC,KAAK,YAAY,mCAAmC;AAC5D,MAAE,KAAK;AACP,QAAI,KAAK,aAAa,GAAG;AACvB,WAAK,KAAK,KAAA;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EAEA,gBACE,UACA,UACA,eACA,wBAAwB,OACY;AACpC,QAAI,KAAK,UAAU,MAAA,MAAY,OAAO;AACpC,aAAO,QAAQ,QAAQ;AAAA,QACrBA;AAAAA,QACA;AAAA,MAAA,CACD;AAAA,IACH;AACA,SAAK,eAAe,IAAI,GAAG;AAAA,MACzB,eAAe,KAAK;AAAA,IAAA,CACrB;AACD,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AAAA,EAEA,MAAqB;AACnB,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA,EAEA,OAAsB;AACpB,QAAI,KAAK,YAAY;AACnB,aAAO,KAAK,SAAS;AAAA,IACvB;AACA,SAAK,iBAAiB,QAAA;AACtB,SAAK,aAAa;AAClB,SAAK,SAAS,QAAA;AACd,WAAO,KAAK,SAAS;AAAA,EACvB;AACF;AAEA,MAAM,6BAA6B;AAEnC,eAAsB,gBACpB,IACA,UACA,IACA,OACA,eACA,UACA,iBACA,eACA,WACA,wBAAwB,OACY;AACpC;AAAA,IACE,SAAS,SAASC;AAAAA,IAClB;AAAA,EAAA;AAEF,OAAK,GAAG,YAAY,cAAc,SAAS,EAAE;AAC7C,OAAK,GAAG,YAAY,iBAAiB;AACrC,KAAG,QAAQ,0BAA0B,QAAQ;AAG7C,iBAAe,MAAM;AAErB,MAAI;AAEJ,QAAM,QAAQ,KAAK,IAAA;AACnB,MAAI;AAuCF,QAAI,YAAY;AAChB,aAAS,IAAI,GAAG,IAAI,4BAA4B,KAAK;AACnD,UAAI;AACF,cAAM,GAAG,MAAMC,cAAmB,OAAM,OAAM;AAE5C,gBAAM,OAAO,YAAA;AACb,cAAI;AACF,mBAAO,MAAM;AAAA,cACX;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,UAEJ,UAAA;AACE,kBAAM;AAAA,UACR;AAAA,QACF,CAAC;AACD,YAAI,WAAW;AACb,aAAG,QAAQ,yCAAyC;AAAA,QACtD;AACA;AAAA,MACF,SAAS,GAAG;AACV,YAAI,aAAa,+BAA+B;AAC9C,aAAG,QAAQ,EAAE,OAAO;AAEpB,iBAAO;AAAA,QACT;AACA,YACE,gBAAgB,CAAC,KACjB,CAAC,aACD,EAAE,SAASC,eACX,yBACA,IAAI,GACJ;AAOA,aAAG;AAAA,YACD;AAAA,YACA;AAAA,UAAA;AAEF,gBAAM,IAAI,QAAQ,CAAA,YAAW,WAAW,SAAS,GAAG,CAAC;AACrD;AAAA,QACF;AACA,YAAI,gBAAgB,CAAC,KAAK,WAAW;AACnC,aAAG,QAAQ,0BAA0B,CAAC;AACtC,gBAAM;AAAA,QACR;AACA,YACE,aAAa,SAAS,iBACtB,EAAE,SAAS,0BACX;AACA,aAAG,OAAO,WAAW,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC;AAC7C;AAAA,QACF;AACA,iBAAS,CAACC,gBAA0B,OAAO,CAAC,CAAC;AAC7C,YAAI,WAAW;AACb;AAAA,QACF;AACA,WAAG,QAAQ,wDAAwD,CAAC;AACpE,oBAAY;AACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAA;AACE,OAAG,QAAQ,gCAAgC,KAAK,IAAA,IAAQ,KAAK;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,eAAsB,sBACpB,IACA,IACA,UACA,OACA,eACA,eACA,UACA,WACA,YACA;AACA,QAAM,QAAoC,CAAA;AAE1C,iBAAe,QAAQ,MAA6C;AAClE,QAAI;AACF,aAAO,MAAM,KAAK,QAAA;AAAA,IACpB,UAAA;AACE,YAAM,IAAI;AACV,SAAG,QAAQ,GAAG,EAAE,MAAM,KAAK,KAAK,UAAU,EAAE,UAAU,CAAC,EAAE;AAAA,IAC3D;AAAA,EACF;AAEA,aAAW,kBAAA;AAEX,MAAI,CAAC,WAAW;AACd,UAAM,EAAC,IAAA,IAAO,SAAS,KAAK,CAAC;AAC7B,UAAM,gBAAgB,WAAW,aAAa,GAAG;AACjD,UAAM,CAAC,QAAQ,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC1C,WAAW,eAAe,UAAU,aAAa;AAAA,MACjD,WAAW,gBAAgB,UAAU,aAAa;AAAA,IAAA,CACnD;AACD,QAAI,UAAU,SAAS;AACrB,iBAAW,MAAM,KAAK;AACpB,gBAAQ,GAAG,IAAA;AAAA,UACT,KAAK;AACH,kBAAM,KAAK,MAAM,QAAQ,aAAa,IAAI,EAAE,CAAC,CAAC;AAC9C;AAAA,UACF,KAAK;AACH,kBAAM,KAAK,MAAM,QAAQ,aAAa,IAAI,EAAE,CAAC,CAAC;AAC9C;AAAA,UACF,KAAK;AACH,kBAAM,KAAK,MAAM,QAAQ,aAAa,IAAI,EAAE,CAAC,CAAC;AAC9C;AAAA,UACF,KAAK;AACH,kBAAM,KAAK,MAAM,QAAQ,aAAa,IAAI,EAAE,CAAC,CAAC;AAC9C;AAAA,UACF;AACE,wBAAc;AAAA,QAAA;AAAA,MAEpB;AAAA,IACF;AAAA,EACF;AAIA,QAAM;AAAA,IAAQ,MACZ;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,SAAS;AAAA,IAAA;AAAA,EACX;AAIF,QAAM,QAAQ,IAAI,MAAM,IAAI,CAAA,SAAQ,KAAA,CAAM,CAAC;AAC7C;AAEO,SAAS,aACd,IACA,QACuC;AACvC,SAAO,iBAAiB,GAAG,OAAO,SAAS,CAAC,IAAI,GAAG,OAAO,KAAK,CAAC;AAClE;AAEO,SAAS,aACd,IACA,KACuC;AACvC,QAAM,EAAC,WAAW,YAAY,MAAA,IAAS;AACvC,SAAO;AAAA,kBACS,GAAG,SAAS,CAAC,IAAI,GAAG,KAAK,CAAC;AAAA,mBACzB,GAAG,UAAU,CAAC;AAAA,oBACb,GAAG,KAAK,CAAC;AAAA;AAE7B;AAEA,SAAS,aACP,IACA,QACuC;AACvC,QAAM,QAAQ,OAAO;AACrB,QAAM,EAAC,YAAY,MAAA,IAAS;AAC5B,QAAM,KAAsC,CAAA;AAC5C,aAAW,OAAO,YAAY;AAC5B,OAAG,GAAG,IAAIC,MAAQ,MAAM,GAAG,GAAG,qBAAqB;AAAA,EACrD;AACA,SAAO,YAAY,GAAG,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,UAAU,OAAO;AAAA,IAC5D;AAAA,EAAA,EACA;AAAA,IAAQ,CAAC,CAAC,KAAKC,MAAK,GAAG,MACvB,IAAI,CAAC,SAAS,KAAK,GAAG,GAAG,CAAC,MAAMA,MAAK,EAAE,IAAI,KAAK,GAAG,GAAG,CAAC,MAAMA,MAAK;AAAA,EAAA,CACnE;AACH;AAEA,SAAS,aACP,IACA,UACuC;AACvC,QAAM,EAAC,WAAW,YAAY,MAAA,IAAS;AAEvC,QAAM,aAAa,CAAA;AACnB,aAAW,OAAO,YAAY;AAC5B,QAAI,WAAW,SAAS,GAAG;AACzB,iBAAW,KAAK,OAAO;AAAA,IACzB;AACA,eAAW,KAAK,KAAK,GAAG,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,EAAE;AAAA,EAChD;AAEA,SAAO,iBAAiB,GAAG,SAAS,CAAC,UAAU,UAAU;AAC3D;AAEA,eAAe,6CACb,IACA,OACA,eACA,eACA,UACA,oBACA;AACA,QAAM,CAAC,CAAC,EAAC,eAAA,CAAe,GAAG,qBAAqB,IAAI,MAAM,QAAQ,IAAI;AAAA,IACpE;AAAA,kBACc,GAAG,eAAe,KAAK,CAAC,CAAC;AAAA;AAAA,oBAEvB,aAAa,KAAK,QAAQ,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAKhD,kBAAkB,SACd,SACA;AAAA,eAMO,GAAG,UAAU,KAAK,CAAC,CAAC;AAAA,EAAA,CAChC;AAGD,MAAI,qBAAqB,gBAAgB;AACvC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ,WAAW,qBAAqB,gBAAgB;AAC9C,UAAM,IAAI,cAAc;AAAA,MACtB,MAAMH;AAAAA,MACN,SAAS,wCAAwC,kBAAkB,eAAe,QAAQ,0BAA0B,eAAe,UAAU;AAAA,MAC7I,QAAQI;AAAAA,IAAY,CACrB;AAAA,EACH;AAEA,MAAI,kBAAkB,UAAa,0BAA0B,QAAW;AACtE,WAAO,sBAAsB,WAAW,CAAC;AACzC;AAAA,MACE;AAAA,MACA,sBAAsB,CAAC;AAAA,IAAA;AAAA,EAE3B;AACF;"}
@@ -140,6 +140,105 @@ export declare class PusherService implements Service, Pusher {
140
140
  readRowCountsByQuery?: Record<string, Record<string, number>> | undefined;
141
141
  readRowCount?: number | undefined;
142
142
  dbScansByQuery?: Record<string, Record<string, number>> | undefined;
143
+ plannerEvents?: ({
144
+ type: "attempt-start";
145
+ attemptNumber: number;
146
+ totalAttempts: number;
147
+ } | {
148
+ type: "connection-costs";
149
+ attemptNumber: number;
150
+ costs: {
151
+ connection: string;
152
+ cost: number;
153
+ costEstimate: {
154
+ limit?: number | undefined;
155
+ startupCost: number;
156
+ scanEst: number;
157
+ cost: number;
158
+ returnedRows: number;
159
+ selectivity: number;
160
+ };
161
+ pinned: boolean;
162
+ constraints: Record<string, Record<string, unknown> | null>;
163
+ constraintCosts: Record<string, {
164
+ limit?: number | undefined;
165
+ startupCost: number;
166
+ scanEst: number;
167
+ cost: number;
168
+ returnedRows: number;
169
+ selectivity: number;
170
+ }>;
171
+ }[];
172
+ } | {
173
+ type: "connection-selected";
174
+ attemptNumber: number;
175
+ connection: string;
176
+ cost: number;
177
+ isRoot: boolean;
178
+ } | {
179
+ type: "constraints-propagated";
180
+ attemptNumber: number;
181
+ connectionConstraints: {
182
+ connection: string;
183
+ constraints: Record<string, Record<string, unknown> | null>;
184
+ constraintCosts: Record<string, {
185
+ limit?: number | undefined;
186
+ startupCost: number;
187
+ scanEst: number;
188
+ cost: number;
189
+ returnedRows: number;
190
+ selectivity: number;
191
+ }>;
192
+ }[];
193
+ } | {
194
+ type: "plan-complete";
195
+ attemptNumber: number;
196
+ totalCost: number;
197
+ flipPattern: number;
198
+ joinStates: {
199
+ join: string;
200
+ type: "semi" | "flipped" | "unflippable";
201
+ }[];
202
+ } | {
203
+ type: "plan-failed";
204
+ attemptNumber: number;
205
+ reason: string;
206
+ } | {
207
+ type: "best-plan-selected";
208
+ bestAttemptNumber: number;
209
+ totalCost: number;
210
+ flipPattern: number;
211
+ joinStates: {
212
+ join: string;
213
+ type: "semi" | "flipped" | "unflippable";
214
+ }[];
215
+ } | {
216
+ attemptNumber?: number | undefined;
217
+ filters?: import("../../../../zero-protocol/src/ast.ts").Condition | undefined;
218
+ ordering?: readonly (readonly [string, "desc" | "asc"])[] | undefined;
219
+ joinType?: "semi" | "flipped" | "unflippable" | undefined;
220
+ type: "node-cost";
221
+ nodeType: "join" | "connection" | "fan-out" | "fan-in" | "terminus";
222
+ node: string;
223
+ branchPattern: number[];
224
+ downstreamChildSelectivity: number;
225
+ costEstimate: {
226
+ limit?: number | undefined;
227
+ startupCost: number;
228
+ scanEst: number;
229
+ cost: number;
230
+ returnedRows: number;
231
+ selectivity: number;
232
+ };
233
+ } | {
234
+ attemptNumber?: number | undefined;
235
+ constraint?: Record<string, unknown> | null | undefined;
236
+ type: "node-constraint";
237
+ nodeType: "join" | "connection" | "fan-out" | "fan-in" | "terminus";
238
+ node: string;
239
+ branchPattern: number[];
240
+ from: string;
241
+ })[] | undefined;
143
242
  warnings: string[];
144
243
  syncedRowCount: number;
145
244
  start: number;
@@ -340,6 +439,105 @@ export declare class PusherService implements Service, Pusher {
340
439
  readRowCountsByQuery?: Record<string, Record<string, number>> | undefined;
341
440
  readRowCount?: number | undefined;
342
441
  dbScansByQuery?: Record<string, Record<string, number>> | undefined;
442
+ plannerEvents?: ({
443
+ type: "attempt-start";
444
+ attemptNumber: number;
445
+ totalAttempts: number;
446
+ } | {
447
+ type: "connection-costs";
448
+ attemptNumber: number;
449
+ costs: {
450
+ connection: string;
451
+ cost: number;
452
+ costEstimate: {
453
+ limit?: number | undefined;
454
+ startupCost: number;
455
+ scanEst: number;
456
+ cost: number;
457
+ returnedRows: number;
458
+ selectivity: number;
459
+ };
460
+ pinned: boolean;
461
+ constraints: Record<string, Record<string, unknown> | null>;
462
+ constraintCosts: Record<string, {
463
+ limit?: number | undefined;
464
+ startupCost: number;
465
+ scanEst: number;
466
+ cost: number;
467
+ returnedRows: number;
468
+ selectivity: number;
469
+ }>;
470
+ }[];
471
+ } | {
472
+ type: "connection-selected";
473
+ attemptNumber: number;
474
+ connection: string;
475
+ cost: number;
476
+ isRoot: boolean;
477
+ } | {
478
+ type: "constraints-propagated";
479
+ attemptNumber: number;
480
+ connectionConstraints: {
481
+ connection: string;
482
+ constraints: Record<string, Record<string, unknown> | null>;
483
+ constraintCosts: Record<string, {
484
+ limit?: number | undefined;
485
+ startupCost: number;
486
+ scanEst: number;
487
+ cost: number;
488
+ returnedRows: number;
489
+ selectivity: number;
490
+ }>;
491
+ }[];
492
+ } | {
493
+ type: "plan-complete";
494
+ attemptNumber: number;
495
+ totalCost: number;
496
+ flipPattern: number;
497
+ joinStates: {
498
+ join: string;
499
+ type: "semi" | "flipped" | "unflippable";
500
+ }[];
501
+ } | {
502
+ type: "plan-failed";
503
+ attemptNumber: number;
504
+ reason: string;
505
+ } | {
506
+ type: "best-plan-selected";
507
+ bestAttemptNumber: number;
508
+ totalCost: number;
509
+ flipPattern: number;
510
+ joinStates: {
511
+ join: string;
512
+ type: "semi" | "flipped" | "unflippable";
513
+ }[];
514
+ } | {
515
+ attemptNumber?: number | undefined;
516
+ filters?: import("../../../../zero-protocol/src/ast.ts").Condition | undefined;
517
+ ordering?: readonly (readonly [string, "desc" | "asc"])[] | undefined;
518
+ joinType?: "semi" | "flipped" | "unflippable" | undefined;
519
+ type: "node-cost";
520
+ nodeType: "join" | "connection" | "fan-out" | "fan-in" | "terminus";
521
+ node: string;
522
+ branchPattern: number[];
523
+ downstreamChildSelectivity: number;
524
+ costEstimate: {
525
+ limit?: number | undefined;
526
+ startupCost: number;
527
+ scanEst: number;
528
+ cost: number;
529
+ returnedRows: number;
530
+ selectivity: number;
531
+ };
532
+ } | {
533
+ attemptNumber?: number | undefined;
534
+ constraint?: Record<string, unknown> | null | undefined;
535
+ type: "node-constraint";
536
+ nodeType: "join" | "connection" | "fan-out" | "fan-in" | "terminus";
537
+ node: string;
538
+ branchPattern: number[];
539
+ from: string;
540
+ })[] | undefined;
343
541
  warnings: string[];
344
542
  syncedRowCount: number;
345
543
  start: number;
@@ -1 +1 @@
1
- {"version":3,"file":"pusher.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/mutagen/pusher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAMjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uCAAuC,CAAC;AAQtE,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,QAAQ,EAEd,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,6BAA6B,CAAC;AAK5D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAElD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAC;AACzD,OAAO,KAAK,EAAC,aAAa,EAAE,YAAY,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,iBAAiB,EAAE,OAAO,EAAC,MAAM,eAAe,CAAC;AAE9D,MAAM,WAAW,MAAO,SAAQ,iBAAiB;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAErC,cAAc,CACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,MAAM,CAAC,UAAU,CAAC,CAAC;IACtB,WAAW,CACT,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,aAAa,CAAC;IACjB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,KAAK,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,OAAO,CAAC,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAc,YAAW,OAAO,EAAE,MAAM;;IACnD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;gBAWlB,QAAQ,EAAE,UAAU,EACpB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG;QAAC,GAAG,EAAE,MAAM,EAAE,CAAA;KAAC,EAChD,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,MAAM;IAgBvB,IAAI,OAAO,IAAI,MAAM,GAAG,SAAS,CAEhC;IAED,cAAc,CACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAKjC,WAAW,CACT,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,aAAa,EAAE,YAAY,CAAC;IAWjC,oBAAoB,CAAC,MAAM,EAAE,UAAU;IAW7C,GAAG;IAKH,KAAK;IAQL,OAAO,IAAI,OAAO;IAIlB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAKpB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAQtB;AAED,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AACF,KAAK,iBAAiB,GAAG,WAAW,GAAG,MAAM,CAAC;AA4T9C;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,SAAS,CAAC,iBAAiB,GAAG,SAAS,CAAC,EAAE,GAClD,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAqC1B"}
1
+ {"version":3,"file":"pusher.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/mutagen/pusher.ts"],"names":[],"mappings":"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"}
@@ -137,7 +137,7 @@ class PushWorker {
137
137
  this.#userPushURL = userPushURL;
138
138
  } else {
139
139
  if (this.#userPushURL !== userPushURL) {
140
- this.#lc.error?.(
140
+ this.#lc.warn?.(
141
141
  "Client provided different mutate parameters than client group",
142
142
  {
143
143
  clientID,
@@ -178,7 +178,7 @@ class PushWorker {
178
178
  const connectionTerminations = [];
179
179
  if ("kind" in response || "error" in response) {
180
180
  this.#lc.warn?.(
181
- "The server behind ZERO_PUSH_URL returned a push error.",
181
+ "The server behind ZERO_MUTATE_URL returned a push error.",
182
182
  response
183
183
  );
184
184
  const groupedMutationIDs = groupBy(
@@ -232,7 +232,7 @@ class PushWorker {
232
232
  const m = mutations[i];
233
233
  if ("error" in m.result) {
234
234
  this.#lc.warn?.(
235
- "The server behind ZERO_PUSH_URL returned a mutation error.",
235
+ "The server behind ZERO_MUTATE_URL returned a mutation error.",
236
236
  m.result
237
237
  );
238
238
  }
@@ -252,7 +252,7 @@ class PushWorker {
252
252
  }
253
253
  }
254
254
  if (failure && i < mutations.length - 1) {
255
- this.#lc.error?.(
255
+ this.#lc.warn?.(
256
256
  "push-response contains mutations after a mutation which should fatal the connection"
257
257
  );
258
258
  }
@@ -292,6 +292,7 @@ class PushWorker {
292
292
  "push",
293
293
  this.#lc,
294
294
  url,
295
+ url === this.#userPushURL,
295
296
  this.#pushURLPatterns,
296
297
  {
297
298
  appID: this.#config.app.id,
@@ -305,7 +306,6 @@ class PushWorker {
305
306
  entry.push
306
307
  );
307
308
  } catch (e) {
308
- this.#lc.error?.("failed to push", e);
309
309
  if (isProtocolError(e) && e.errorBody.kind === PushFailed) {
310
310
  return {
311
311
  ...e.errorBody,