@rocicorp/zero 1.6.0-canary.12 → 1.6.0-canary.13

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 (551) hide show
  1. package/README.md +3 -28
  2. package/out/_virtual/{_@oxc-project_runtime@0.130.0 → _@oxc-project_runtime@0.122.0}/helpers/usingCtx.js +1 -1
  3. package/out/analyze-query/src/analyze-cli.js +3 -3
  4. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  5. package/out/analyze-query/src/bin-analyze.js +1 -6
  6. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  7. package/out/analyze-query/src/bin-transform.js.map +1 -1
  8. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  9. package/out/ast-to-zql/src/bin.js.map +1 -1
  10. package/out/ast-to-zql/src/format.js.map +1 -1
  11. package/out/datadog/src/datadog-log-sink.js.map +1 -1
  12. package/out/otel/src/enabled.js.map +1 -1
  13. package/out/otel/src/log-options.js.map +1 -1
  14. package/out/otel/src/maybe-time.js.map +1 -1
  15. package/out/otel/src/span.js.map +1 -1
  16. package/out/replicache/src/async-iterable-to-array.js.map +1 -1
  17. package/out/replicache/src/bg-interval.js.map +1 -1
  18. package/out/replicache/src/btree/diff.js.map +1 -1
  19. package/out/replicache/src/btree/node.js.map +1 -1
  20. package/out/replicache/src/btree/read.js.map +1 -1
  21. package/out/replicache/src/btree/splice.js.map +1 -1
  22. package/out/replicache/src/btree/write.js +3 -6
  23. package/out/replicache/src/btree/write.js.map +1 -1
  24. package/out/replicache/src/call-default-fetch.js.map +1 -1
  25. package/out/replicache/src/connection-loop-delegates.js.map +1 -1
  26. package/out/replicache/src/connection-loop.js.map +1 -1
  27. package/out/replicache/src/cookies.js.map +1 -1
  28. package/out/replicache/src/dag/chunk.js.map +1 -1
  29. package/out/replicache/src/dag/gc.js.map +1 -1
  30. package/out/replicache/src/dag/key.js.map +1 -1
  31. package/out/replicache/src/dag/lazy-store.js.map +1 -1
  32. package/out/replicache/src/dag/store-impl.js.map +1 -1
  33. package/out/replicache/src/dag/store.js.map +1 -1
  34. package/out/replicache/src/dag/visitor.js.map +1 -1
  35. package/out/replicache/src/db/commit.js.map +1 -1
  36. package/out/replicache/src/db/index.js.map +1 -1
  37. package/out/replicache/src/db/read.js.map +1 -1
  38. package/out/replicache/src/db/rebase.js.map +1 -1
  39. package/out/replicache/src/db/write.js.map +1 -1
  40. package/out/replicache/src/deleted-clients.js.map +1 -1
  41. package/out/replicache/src/error-responses.js.map +1 -1
  42. package/out/replicache/src/frozen-json.js.map +1 -1
  43. package/out/replicache/src/get-default-puller.js.map +1 -1
  44. package/out/replicache/src/get-default-pusher.js.map +1 -1
  45. package/out/replicache/src/get-kv-store-provider.js.map +1 -1
  46. package/out/replicache/src/hash.js.map +1 -1
  47. package/out/replicache/src/http-request-info.js.map +1 -1
  48. package/out/replicache/src/index-defs.js.map +1 -1
  49. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  50. package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +1 -1
  51. package/out/replicache/src/kv/idb-store.js.map +1 -1
  52. package/out/replicache/src/kv/mem-store.js.map +1 -1
  53. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  54. package/out/replicache/src/kv/read-impl.js.map +1 -1
  55. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  56. package/out/replicache/src/kv/sqlite-store.js +1 -4
  57. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  58. package/out/replicache/src/kv/throw-if-closed.js.map +1 -1
  59. package/out/replicache/src/kv/write-impl-base.js.map +1 -1
  60. package/out/replicache/src/kv/write-impl.js.map +1 -1
  61. package/out/replicache/src/lazy.js.map +1 -1
  62. package/out/replicache/src/log-options.js.map +1 -1
  63. package/out/replicache/src/make-idb-name.js.map +1 -1
  64. package/out/replicache/src/new-client-channel.js.map +1 -1
  65. package/out/replicache/src/on-persist-channel.js.map +1 -1
  66. package/out/replicache/src/patch-operation.js.map +1 -1
  67. package/out/replicache/src/pending-mutations.js.map +1 -1
  68. package/out/replicache/src/persist/client-gc.js.map +1 -1
  69. package/out/replicache/src/persist/client-group-gc.js.map +1 -1
  70. package/out/replicache/src/persist/client-groups.js +0 -40
  71. package/out/replicache/src/persist/client-groups.js.map +1 -1
  72. package/out/replicache/src/persist/clients.js +0 -28
  73. package/out/replicache/src/persist/clients.js.map +1 -1
  74. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  75. package/out/replicache/src/persist/gather-mem-only-visitor.js.map +1 -1
  76. package/out/replicache/src/persist/gather-not-cached-visitor.js.map +1 -1
  77. package/out/replicache/src/persist/heartbeat.js.map +1 -1
  78. package/out/replicache/src/persist/idb-databases-store-db-name.js.map +1 -1
  79. package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
  80. package/out/replicache/src/persist/make-client-id.js.map +1 -1
  81. package/out/replicache/src/persist/persist.js.map +1 -1
  82. package/out/replicache/src/persist/refresh.js.map +1 -1
  83. package/out/replicache/src/process-scheduler.js.map +1 -1
  84. package/out/replicache/src/pusher.js.map +1 -1
  85. package/out/replicache/src/replicache-impl.js.map +1 -1
  86. package/out/replicache/src/report-error.js.map +1 -1
  87. package/out/replicache/src/request-idle.js.map +1 -1
  88. package/out/replicache/src/scan-iterator.js.map +1 -1
  89. package/out/replicache/src/scan-options.js.map +1 -1
  90. package/out/replicache/src/set-interval-with-signal.js.map +1 -1
  91. package/out/replicache/src/subscriptions.js.map +1 -1
  92. package/out/replicache/src/sync/diff.js.map +1 -1
  93. package/out/replicache/src/sync/ids.js.map +1 -1
  94. package/out/replicache/src/sync/patch.js.map +1 -1
  95. package/out/replicache/src/sync/pull-error.js.map +1 -1
  96. package/out/replicache/src/sync/pull.js.map +1 -1
  97. package/out/replicache/src/sync/push.js.map +1 -1
  98. package/out/replicache/src/sync/request-id.js.map +1 -1
  99. package/out/replicache/src/to-error.js.map +1 -1
  100. package/out/replicache/src/transaction-closed-error.js.map +1 -1
  101. package/out/replicache/src/transactions.js.map +1 -1
  102. package/out/replicache/src/with-transactions.js.map +1 -1
  103. package/out/shared/src/abort-error.js.map +1 -1
  104. package/out/shared/src/arrays.js.map +1 -1
  105. package/out/shared/src/asserts.js.map +1 -1
  106. package/out/shared/src/bigint-json.js.map +1 -1
  107. package/out/shared/src/binary-search.js.map +1 -1
  108. package/out/shared/src/broadcast-channel.js.map +1 -1
  109. package/out/shared/src/browser-env.js.map +1 -1
  110. package/out/shared/src/btree-set.js.map +1 -1
  111. package/out/shared/src/cache.js.map +1 -1
  112. package/out/shared/src/centroid.js.map +1 -1
  113. package/out/shared/src/custom-key-map.js.map +1 -1
  114. package/out/shared/src/custom-key-set.js.map +1 -1
  115. package/out/shared/src/deep-clone.js.map +1 -1
  116. package/out/shared/src/deep-merge.js.map +1 -1
  117. package/out/shared/src/document-visible.js.map +1 -1
  118. package/out/shared/src/dotenv.js.map +1 -1
  119. package/out/shared/src/error.js.map +1 -1
  120. package/out/shared/src/hash.js.map +1 -1
  121. package/out/shared/src/iterables.d.ts +0 -2
  122. package/out/shared/src/iterables.d.ts.map +1 -1
  123. package/out/shared/src/iterables.js +1 -9
  124. package/out/shared/src/iterables.js.map +1 -1
  125. package/out/shared/src/json-schema.js.map +1 -1
  126. package/out/shared/src/json.js.map +1 -1
  127. package/out/shared/src/logging-test-utils.js.map +1 -1
  128. package/out/shared/src/logging.js.map +1 -1
  129. package/out/shared/src/map.js.map +1 -1
  130. package/out/shared/src/must.js.map +1 -1
  131. package/out/shared/src/object-traversal.js.map +1 -1
  132. package/out/shared/src/objects.js.map +1 -1
  133. package/out/shared/src/options.js.map +1 -1
  134. package/out/shared/src/parse-big-int.js.map +1 -1
  135. package/out/shared/src/promise-race.js.map +1 -1
  136. package/out/shared/src/queue.d.ts.map +1 -1
  137. package/out/shared/src/queue.js +21 -15
  138. package/out/shared/src/queue.js.map +1 -1
  139. package/out/shared/src/rand.js.map +1 -1
  140. package/out/shared/src/random-uint64.js.map +1 -1
  141. package/out/shared/src/random-values.js.map +1 -1
  142. package/out/shared/src/record-proxy.js.map +1 -1
  143. package/out/shared/src/resolved-promises.js.map +1 -1
  144. package/out/shared/src/sentinels.js.map +1 -1
  145. package/out/shared/src/set-utils.js.map +1 -1
  146. package/out/shared/src/size-of-value.js.map +1 -1
  147. package/out/shared/src/sleep.js.map +1 -1
  148. package/out/shared/src/sorted-entries.js.map +1 -1
  149. package/out/shared/src/string-compare.js.map +1 -1
  150. package/out/shared/src/subscribable.js.map +1 -1
  151. package/out/shared/src/tdigest-schema.js.map +1 -1
  152. package/out/shared/src/tdigest.js.map +1 -1
  153. package/out/shared/src/valita.js.map +1 -1
  154. package/out/z2s/src/compiler.js.map +1 -1
  155. package/out/z2s/src/sql.js.map +1 -1
  156. package/out/zero/package.js +26 -34
  157. package/out/zero/package.js.map +1 -1
  158. package/out/zero/src/build-schema.js.map +1 -1
  159. package/out/zero/src/zero-cache-dev.js.map +1 -1
  160. package/out/zero/src/zero-out.js.map +1 -1
  161. package/out/zero-cache/src/auth/auth.js.map +1 -1
  162. package/out/zero-cache/src/auth/jwt.js.map +1 -1
  163. package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
  164. package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
  165. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  166. package/out/zero-cache/src/config/network.js.map +1 -1
  167. package/out/zero-cache/src/config/normalize.js.map +1 -1
  168. package/out/zero-cache/src/config/server-context.js.map +1 -1
  169. package/out/zero-cache/src/config/zero-config.js +0 -5
  170. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  171. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  172. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  173. package/out/zero-cache/src/db/create.js.map +1 -1
  174. package/out/zero-cache/src/db/delete-lite-db.js.map +1 -1
  175. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  176. package/out/zero-cache/src/db/migration-lite.js +0 -19
  177. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  178. package/out/zero-cache/src/db/migration.js +0 -19
  179. package/out/zero-cache/src/db/migration.js.map +1 -1
  180. package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -1
  181. package/out/zero-cache/src/db/pg-copy.js.map +1 -1
  182. package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
  183. package/out/zero-cache/src/db/pg-type-parser.js.map +1 -1
  184. package/out/zero-cache/src/db/run-transaction.js.map +1 -1
  185. package/out/zero-cache/src/db/specs.js.map +1 -1
  186. package/out/zero-cache/src/db/statements.js.map +1 -1
  187. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  188. package/out/zero-cache/src/db/warmup.js.map +1 -1
  189. package/out/zero-cache/src/observability/events.js.map +1 -1
  190. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  191. package/out/zero-cache/src/scripts/decommission.js.map +1 -1
  192. package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
  193. package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
  194. package/out/zero-cache/src/scripts/permissions.js +2 -1
  195. package/out/zero-cache/src/scripts/permissions.js.map +1 -1
  196. package/out/zero-cache/src/server/anonymous-otel-start.js +7 -8
  197. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  198. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  199. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  200. package/out/zero-cache/src/server/logging.js.map +1 -1
  201. package/out/zero-cache/src/server/main.js.map +1 -1
  202. package/out/zero-cache/src/server/mutator.js.map +1 -1
  203. package/out/zero-cache/src/server/otel-diag-logger.js.map +1 -1
  204. package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
  205. package/out/zero-cache/src/server/otel-start.js.map +1 -1
  206. package/out/zero-cache/src/server/priority-op.js.map +1 -1
  207. package/out/zero-cache/src/server/reaper.js.map +1 -1
  208. package/out/zero-cache/src/server/replicator.js.map +1 -1
  209. package/out/zero-cache/src/server/runner/main.js.map +1 -1
  210. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  211. package/out/zero-cache/src/server/runner/runtime.js.map +1 -1
  212. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  213. package/out/zero-cache/src/server/shadow-syncer.js.map +1 -1
  214. package/out/zero-cache/src/server/syncer.js.map +1 -1
  215. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  216. package/out/zero-cache/src/server/worker-urls.js.map +1 -1
  217. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  218. package/out/zero-cache/src/services/analyze.js +2 -5
  219. package/out/zero-cache/src/services/analyze.js.map +1 -1
  220. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  221. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  222. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  223. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  224. package/out/zero-cache/src/services/change-source/pg/backfill-metadata.js.map +1 -1
  225. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  226. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  227. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  228. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  229. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.js.map +1 -1
  230. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js.map +1 -1
  231. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  232. package/out/zero-cache/src/services/change-source/pg/lsn.js.map +1 -1
  233. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  234. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  235. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  236. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
  237. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  238. package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
  239. package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
  240. package/out/zero-cache/src/services/change-source/protocol/current/data.js +0 -2
  241. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  242. package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -1
  243. package/out/zero-cache/src/services/change-source/protocol/current/json.js.map +1 -1
  244. package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
  245. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  246. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  247. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  248. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  249. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  250. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  251. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  252. package/out/zero-cache/src/services/change-streamer/replica-monitor.js.map +1 -1
  253. package/out/zero-cache/src/services/change-streamer/schema/init.js +25 -21
  254. package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
  255. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  256. package/out/zero-cache/src/services/change-streamer/snapshot.js +0 -15
  257. package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
  258. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  259. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  260. package/out/zero-cache/src/services/heapz.js.map +1 -1
  261. package/out/zero-cache/src/services/http-service.js.map +1 -1
  262. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  263. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js.map +1 -1
  264. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  265. package/out/zero-cache/src/services/mutagen/error.js.map +1 -1
  266. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  267. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  268. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  269. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  270. package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
  271. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  272. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  273. package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
  274. package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -1
  275. package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
  276. package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
  277. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  278. package/out/zero-cache/src/services/replicator/schema/table-metadata.js.map +1 -1
  279. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  280. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  281. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  282. package/out/zero-cache/src/services/run-ast.js +0 -1
  283. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  284. package/out/zero-cache/src/services/runner.js.map +1 -1
  285. package/out/zero-cache/src/services/running-state.js.map +1 -1
  286. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
  287. package/out/zero-cache/src/services/statz.js.map +1 -1
  288. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
  289. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  290. package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
  291. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  292. package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts.map +1 -1
  293. package/out/zero-cache/src/services/view-syncer/cvr-purger.js +1 -2
  294. package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
  295. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  296. package/out/zero-cache/src/services/view-syncer/cvr-store.js +1 -2
  297. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  298. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  299. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  300. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +14 -0
  301. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
  302. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +25 -2
  303. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  304. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  305. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  306. package/out/zero-cache/src/services/view-syncer/row-set-signature.js.map +1 -1
  307. package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
  308. package/out/zero-cache/src/services/view-syncer/schema/init.js +113 -97
  309. package/out/zero-cache/src/services/view-syncer/schema/init.js.map +1 -1
  310. package/out/zero-cache/src/services/view-syncer/schema/types.js +1 -103
  311. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  312. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  313. package/out/zero-cache/src/services/view-syncer/tracer.js.map +1 -1
  314. package/out/zero-cache/src/services/view-syncer/ttl-clock.js.map +1 -1
  315. package/out/zero-cache/src/services/view-syncer/view-syncer.js +1 -4
  316. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  317. package/out/zero-cache/src/types/configuration-error.js.map +1 -1
  318. package/out/zero-cache/src/types/error-with-level.js.map +1 -1
  319. package/out/zero-cache/src/types/http.js.map +1 -1
  320. package/out/zero-cache/src/types/lexi-version.js.map +1 -1
  321. package/out/zero-cache/src/types/lite.js.map +1 -1
  322. package/out/zero-cache/src/types/names.js.map +1 -1
  323. package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
  324. package/out/zero-cache/src/types/pg.js.map +1 -1
  325. package/out/zero-cache/src/types/processes.js.map +1 -1
  326. package/out/zero-cache/src/types/profiler.js.map +1 -1
  327. package/out/zero-cache/src/types/row-key.js.map +1 -1
  328. package/out/zero-cache/src/types/shards.js.map +1 -1
  329. package/out/zero-cache/src/types/sql.js.map +1 -1
  330. package/out/zero-cache/src/types/state-version.js.map +1 -1
  331. package/out/zero-cache/src/types/streams.js.map +1 -1
  332. package/out/zero-cache/src/types/strings.js.map +1 -1
  333. package/out/zero-cache/src/types/subscription.js.map +1 -1
  334. package/out/zero-cache/src/types/timeout.js.map +1 -1
  335. package/out/zero-cache/src/types/url-params.js.map +1 -1
  336. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  337. package/out/zero-cache/src/types/ws.js.map +1 -1
  338. package/out/zero-cache/src/workers/connect-params.js.map +1 -1
  339. package/out/zero-cache/src/workers/connection.js.map +1 -1
  340. package/out/zero-cache/src/workers/mutator.js.map +1 -1
  341. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  342. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  343. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  344. package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
  345. package/out/zero-client/src/client/connection-manager.js +1 -2
  346. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  347. package/out/zero-client/src/client/connection.js.map +1 -1
  348. package/out/zero-client/src/client/context.js.map +1 -1
  349. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  350. package/out/zero-client/src/client/crud.js.map +1 -1
  351. package/out/zero-client/src/client/custom.js +1 -2
  352. package/out/zero-client/src/client/custom.js.map +1 -1
  353. package/out/zero-client/src/client/delete-clients-manager.js.map +1 -1
  354. package/out/zero-client/src/client/enable-analytics.js.map +1 -1
  355. package/out/zero-client/src/client/error.js.map +1 -1
  356. package/out/zero-client/src/client/http-string.js.map +1 -1
  357. package/out/zero-client/src/client/inspector/client-group.js.map +1 -1
  358. package/out/zero-client/src/client/inspector/client.js.map +1 -1
  359. package/out/zero-client/src/client/inspector/html-dialog-prompt.js.map +1 -1
  360. package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
  361. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  362. package/out/zero-client/src/client/inspector/query.js.map +1 -1
  363. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  364. package/out/zero-client/src/client/keys.js.map +1 -1
  365. package/out/zero-client/src/client/log-options.js.map +1 -1
  366. package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
  367. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  368. package/out/zero-client/src/client/metrics.js.map +1 -1
  369. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  370. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  371. package/out/zero-client/src/client/options.js.map +1 -1
  372. package/out/zero-client/src/client/query-manager.js.map +1 -1
  373. package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
  374. package/out/zero-client/src/client/server-option.js.map +1 -1
  375. package/out/zero-client/src/client/version.js +1 -1
  376. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
  377. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  378. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  379. package/out/zero-client/src/client/zero.js +32 -58
  380. package/out/zero-client/src/client/zero.js.map +1 -1
  381. package/out/zero-client/src/util/nanoid.js.map +1 -1
  382. package/out/zero-client/src/util/socket.d.ts +3 -0
  383. package/out/zero-client/src/util/socket.d.ts.map +1 -0
  384. package/out/zero-client/src/util/socket.js +8 -0
  385. package/out/zero-client/src/util/socket.js.map +1 -0
  386. package/out/zero-protocol/src/analyze-query-result.js +0 -3
  387. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  388. package/out/zero-protocol/src/application-error.js.map +1 -1
  389. package/out/zero-protocol/src/ast.js.map +1 -1
  390. package/out/zero-protocol/src/change-desired-queries.js +0 -1
  391. package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
  392. package/out/zero-protocol/src/client-schema.js.map +1 -1
  393. package/out/zero-protocol/src/close-connection.js.map +1 -1
  394. package/out/zero-protocol/src/connect.js +0 -7
  395. package/out/zero-protocol/src/connect.js.map +1 -1
  396. package/out/zero-protocol/src/custom-queries.js.map +1 -1
  397. package/out/zero-protocol/src/data.js.map +1 -1
  398. package/out/zero-protocol/src/delete-clients.js.map +1 -1
  399. package/out/zero-protocol/src/down.js.map +1 -1
  400. package/out/zero-protocol/src/error.js +0 -7
  401. package/out/zero-protocol/src/error.js.map +1 -1
  402. package/out/zero-protocol/src/inspect-down.js.map +1 -1
  403. package/out/zero-protocol/src/inspect-up.js +0 -1
  404. package/out/zero-protocol/src/inspect-up.js.map +1 -1
  405. package/out/zero-protocol/src/mutate-server.js.map +1 -1
  406. package/out/zero-protocol/src/mutation-id.js.map +1 -1
  407. package/out/zero-protocol/src/mutation.js.map +1 -1
  408. package/out/zero-protocol/src/mutations-patch.js.map +1 -1
  409. package/out/zero-protocol/src/ping.js.map +1 -1
  410. package/out/zero-protocol/src/poke.js +0 -4
  411. package/out/zero-protocol/src/poke.js.map +1 -1
  412. package/out/zero-protocol/src/pong.js.map +1 -1
  413. package/out/zero-protocol/src/primary-key.js.map +1 -1
  414. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  415. package/out/zero-protocol/src/pull.js.map +1 -1
  416. package/out/zero-protocol/src/push.js +0 -16
  417. package/out/zero-protocol/src/push.js.map +1 -1
  418. package/out/zero-protocol/src/queries-patch.js.map +1 -1
  419. package/out/zero-protocol/src/query-hash.js.map +1 -1
  420. package/out/zero-protocol/src/query-server.js.map +1 -1
  421. package/out/zero-protocol/src/row-patch.js.map +1 -1
  422. package/out/zero-protocol/src/up.js.map +1 -1
  423. package/out/zero-protocol/src/update-auth.js.map +1 -1
  424. package/out/zero-protocol/src/version.js.map +1 -1
  425. package/out/zero-react/src/use-connection-state.js.map +1 -1
  426. package/out/zero-react/src/use-query.js.map +1 -1
  427. package/out/zero-react/src/use-zero-online.js.map +1 -1
  428. package/out/zero-react/src/zero-provider.js.map +1 -1
  429. package/out/zero-schema/src/builder/relationship-builder.js.map +1 -1
  430. package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
  431. package/out/zero-schema/src/builder/table-builder.js.map +1 -1
  432. package/out/zero-schema/src/compiled-permissions.js.map +1 -1
  433. package/out/zero-schema/src/name-mapper.js.map +1 -1
  434. package/out/zero-schema/src/permissions.js.map +1 -1
  435. package/out/zero-schema/src/schema-config.js.map +1 -1
  436. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  437. package/out/zero-server/src/adapters/kysely.js.map +1 -1
  438. package/out/zero-server/src/adapters/pg.js.map +1 -1
  439. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  440. package/out/zero-server/src/adapters/prisma.js.map +1 -1
  441. package/out/zero-server/src/custom.js +1 -2
  442. package/out/zero-server/src/custom.js.map +1 -1
  443. package/out/zero-server/src/logging.js.map +1 -1
  444. package/out/zero-server/src/pg-query-executor.js.map +1 -1
  445. package/out/zero-server/src/process-mutations.js.map +1 -1
  446. package/out/zero-server/src/push-processor.js.map +1 -1
  447. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  448. package/out/zero-server/src/schema.js.map +1 -1
  449. package/out/zero-server/src/zql-database.js.map +1 -1
  450. package/out/zero-solid/src/solid-view.js.map +1 -1
  451. package/out/zero-solid/src/use-connection-state.js.map +1 -1
  452. package/out/zero-solid/src/use-query.js.map +1 -1
  453. package/out/zero-solid/src/use-zero-online.js.map +1 -1
  454. package/out/zero-solid/src/use-zero.js.map +1 -1
  455. package/out/zero-types/src/format.js.map +1 -1
  456. package/out/zero-types/src/name-mapper.js.map +1 -1
  457. package/out/zql/src/builder/builder.js.map +1 -1
  458. package/out/zql/src/builder/debug-delegate.d.ts +0 -5
  459. package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
  460. package/out/zql/src/builder/debug-delegate.js +1 -10
  461. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  462. package/out/zql/src/builder/filter.js.map +1 -1
  463. package/out/zql/src/builder/like.js.map +1 -1
  464. package/out/zql/src/error.js.map +1 -1
  465. package/out/zql/src/ivm/array-view.js.map +1 -1
  466. package/out/zql/src/ivm/cap.js.map +1 -1
  467. package/out/zql/src/ivm/change.js.map +1 -1
  468. package/out/zql/src/ivm/constraint.js +1 -1
  469. package/out/zql/src/ivm/constraint.js.map +1 -1
  470. package/out/zql/src/ivm/data.js.map +1 -1
  471. package/out/zql/src/ivm/exists.js.map +1 -1
  472. package/out/zql/src/ivm/fan-in.js.map +1 -1
  473. package/out/zql/src/ivm/fan-out.js.map +1 -1
  474. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  475. package/out/zql/src/ivm/filter-push.js.map +1 -1
  476. package/out/zql/src/ivm/filter.js.map +1 -1
  477. package/out/zql/src/ivm/flipped-join.d.ts +8 -4
  478. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  479. package/out/zql/src/ivm/flipped-join.js +63 -59
  480. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  481. package/out/zql/src/ivm/join-utils.js.map +1 -1
  482. package/out/zql/src/ivm/join.js.map +1 -1
  483. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  484. package/out/zql/src/ivm/memory-source.js.map +1 -1
  485. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  486. package/out/zql/src/ivm/operator.d.ts +1 -1
  487. package/out/zql/src/ivm/operator.js.map +1 -1
  488. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  489. package/out/zql/src/ivm/schema.d.ts +8 -0
  490. package/out/zql/src/ivm/schema.d.ts.map +1 -1
  491. package/out/zql/src/ivm/skip-yields.js.map +1 -1
  492. package/out/zql/src/ivm/skip.js.map +1 -1
  493. package/out/zql/src/ivm/source.js.map +1 -1
  494. package/out/zql/src/ivm/stream.js.map +1 -1
  495. package/out/zql/src/ivm/take.js.map +1 -1
  496. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  497. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  498. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  499. package/out/zql/src/mutate/crud.js.map +1 -1
  500. package/out/zql/src/mutate/custom.js.map +1 -1
  501. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  502. package/out/zql/src/mutate/mutator.js.map +1 -1
  503. package/out/zql/src/planner/planner-builder.js.map +1 -1
  504. package/out/zql/src/planner/planner-connection.js.map +1 -1
  505. package/out/zql/src/planner/planner-constraint.js.map +1 -1
  506. package/out/zql/src/planner/planner-debug.js.map +1 -1
  507. package/out/zql/src/planner/planner-fan-in.js.map +1 -1
  508. package/out/zql/src/planner/planner-fan-out.js.map +1 -1
  509. package/out/zql/src/planner/planner-graph.js.map +1 -1
  510. package/out/zql/src/planner/planner-join.d.ts.map +1 -1
  511. package/out/zql/src/planner/planner-join.js +1 -2
  512. package/out/zql/src/planner/planner-join.js.map +1 -1
  513. package/out/zql/src/planner/planner-node.js.map +1 -1
  514. package/out/zql/src/planner/planner-source.js.map +1 -1
  515. package/out/zql/src/planner/planner-terminus.js.map +1 -1
  516. package/out/zql/src/query/complete-ordering.js.map +1 -1
  517. package/out/zql/src/query/create-builder.js.map +1 -1
  518. package/out/zql/src/query/error.js.map +1 -1
  519. package/out/zql/src/query/escape-like.js.map +1 -1
  520. package/out/zql/src/query/expression.js.map +1 -1
  521. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  522. package/out/zql/src/query/metrics-delegate.js.map +1 -1
  523. package/out/zql/src/query/named.js.map +1 -1
  524. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  525. package/out/zql/src/query/query-impl.js +1 -1
  526. package/out/zql/src/query/query-impl.js.map +1 -1
  527. package/out/zql/src/query/query-internals.js.map +1 -1
  528. package/out/zql/src/query/query-registry.js.map +1 -1
  529. package/out/zql/src/query/runnable-query-impl.js.map +1 -1
  530. package/out/zql/src/query/static-query.js.map +1 -1
  531. package/out/zql/src/query/ttl.js.map +1 -1
  532. package/out/zql/src/query/validate-input.js.map +1 -1
  533. package/out/zqlite/src/database-storage.js.map +1 -1
  534. package/out/zqlite/src/db.js.map +1 -1
  535. package/out/zqlite/src/explain-queries.js.map +1 -1
  536. package/out/zqlite/src/internal/sql-inline.js.map +1 -1
  537. package/out/zqlite/src/internal/sql.js.map +1 -1
  538. package/out/zqlite/src/internal/statement-cache.js.map +1 -1
  539. package/out/zqlite/src/query-builder.js.map +1 -1
  540. package/out/zqlite/src/query-delegate.js.map +1 -1
  541. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  542. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  543. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  544. package/out/zqlite/src/table-source.d.ts.map +1 -1
  545. package/out/zqlite/src/table-source.js +6 -6
  546. package/out/zqlite/src/table-source.js.map +1 -1
  547. package/package.json +26 -42
  548. package/out/shared/src/ring-buffer.d.ts +0 -32
  549. package/out/shared/src/ring-buffer.d.ts.map +0 -1
  550. package/out/shared/src/ring-buffer.js +0 -109
  551. package/out/shared/src/ring-buffer.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"change-streamer.js","names":[],"sources":["../../../../../zero-cache/src/server/change-streamer.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {DatabaseInitError} from '../../../zqlite/src/db.ts';\nimport {getServerContext} from '../config/server-context.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {deleteLiteDB} from '../db/delete-lite-db.ts';\nimport {warmupConnections} from '../db/warmup.ts';\nimport {initEventSink, publishCriticalEvent} from '../observability/events.ts';\nimport {upgradeReplica} from '../services/change-source/common/replica-schema.ts';\nimport {initializeCustomChangeSource} from '../services/change-source/custom/change-source.ts';\nimport {initializePostgresChangeSource} from '../services/change-source/pg/change-source.ts';\nimport {BackupMonitor} from '../services/change-streamer/backup-monitor.ts';\nimport {ChangeStreamerHttpServer} from '../services/change-streamer/change-streamer-http.ts';\nimport {initializeStreamer} from '../services/change-streamer/change-streamer-service.ts';\nimport type {ChangeStreamerService} from '../services/change-streamer/change-streamer.ts';\nimport {ReplicaMonitor} from '../services/change-streamer/replica-monitor.ts';\nimport {initChangeStreamerSchema} from '../services/change-streamer/schema/init.ts';\nimport {AutoResetSignal} from '../services/change-streamer/schema/tables.ts';\nimport {PurgeLocker} from '../services/change-streamer/storer.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {\n BackupNotFoundException,\n restoreReplica,\n} from '../services/litestream/commands.ts';\nimport {\n replicationStatusError,\n ReplicationStatusPublisher,\n} from '../services/replicator/replication-status.ts';\nimport {connectPgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...argv: string[]\n): Promise<void> {\n const workerStartTime = Date.now();\n const config = getNormalizedZeroConfig({env, argv});\n const {\n taskID,\n changeStreamer: {\n port,\n address,\n protocol,\n startupDelayMs,\n backPressureLimitHeapProportion,\n flowControlConsensusPaddingSeconds,\n },\n upstream,\n change,\n replica,\n initialSync,\n litestream,\n keepaliveTimeoutMs,\n } = config;\n\n startOtelAuto(\n createLogContext(config, 'change-streamer', 0, false),\n 'change-streamer',\n 0,\n );\n lc = createLogContext(config, 'change-streamer');\n initEventSink(lc, config);\n\n // Kick off DB connection warmup in the background.\n const changeDB = await connectPgClient(\n lc,\n change.db,\n 'change-streamer',\n {\n max: change.maxConns,\n },\n {sendStringAsJson: true},\n );\n void warmupConnections(lc, changeDB, 'change').catch(() => {});\n\n const {autoReset, replicationLag} = config;\n const shard = getShardConfig(config);\n\n // Ensure the change DB schema is initialized/up-to-date, then acquire\n // a lock to prevent change-lock purges. This ensures that (this)\n // change-streamer will be able to resume from the backup.\n await initChangeStreamerSchema(lc, changeDB, shard);\n let purgeLock = await new PurgeLocker(lc, shard, changeDB).acquire();\n\n // Restore from litestream if the change-log has entries.\n if (purgeLock) {\n try {\n await restoreReplica(lc, config, purgeLock);\n } catch (e) {\n // If the restore failed, e.g. due to a corrupt or missing backup, the\n // replication-manager recovers by re-syncing.\n const log = e instanceof BackupNotFoundException ? 'warn' : 'error';\n lc[log]?.(\n `error restoring backup. resyncing the replica: ${String(e)}`,\n e,\n );\n\n // The purgeLock must be released if the backup could not be restored,\n // or it will otherwise prevent the change-db update after the resync\n // completes.\n await purgeLock.release();\n purgeLock = null;\n }\n }\n\n let changeStreamer: ChangeStreamerService | undefined;\n\n const context = getServerContext(config);\n\n for (const first of [true, false]) {\n try {\n // Note: This performs initial sync of the replica if necessary.\n const {changeSource, subscriptionState} =\n upstream.type === 'pg'\n ? await initializePostgresChangeSource(\n lc,\n upstream.db,\n shard,\n replica.file,\n {\n ...initialSync,\n replicationSlotFailover: upstream.pgReplicationSlotFailover,\n },\n context,\n replicationLag.reportIntervalMs,\n )\n : await initializeCustomChangeSource(\n lc,\n upstream.db,\n shard,\n replica.file,\n context,\n );\n\n const replicationStatusPublisher =\n ReplicationStatusPublisher.forReplicaFile(replica.file);\n\n changeStreamer = await initializeStreamer(\n lc,\n shard,\n taskID,\n address,\n protocol,\n changeDB,\n changeSource,\n replicationStatusPublisher,\n subscriptionState,\n purgeLock,\n autoReset ?? false,\n {\n backPressureLimitHeapProportion,\n flowControlConsensusPaddingSeconds,\n statementTimeoutMs: change.statementTimeoutMs,\n },\n setTimeout,\n );\n break;\n } catch (e) {\n if (first && e instanceof AutoResetSignal) {\n lc.warn?.(`resetting replica ${replica.file}`, e);\n // TODO: Make deleteLiteDB work with litestream. It will probably have to be\n // a semantic wipe instead of a file delete.\n deleteLiteDB(replica.file);\n // Release the purge lock before retrying. This is safe because the\n // purge lock exists to preserve change-log entries so the new\n // change-streamer can resume from the backup replica's watermark.\n // An AutoResetSignal means we cant resume from the backup replica\n // (e.g. its replication slot is gone), so the change-log entries the lock\n // was protecting are no longer needed. The retry performs a fresh\n // initial sync with a new replication slot, independent of the old\n // change-log. Releasing is also necessary to avoid a\n // self-deadlock when CHANGE_DB == UPSTREAM_DB:\n // CREATE_REPLICATION_SLOT waits for all older transactions to\n // finish, including this lock's open transaction.\n await purgeLock?.release();\n purgeLock = null;\n continue; // execute again with a fresh initial-sync\n }\n if (e instanceof DatabaseInitError) {\n throw new Error(\n `Cannot open ZERO_REPLICA_FILE at \"${replica.file}\". Please check that the path is valid.`,\n {cause: e},\n );\n }\n throw e;\n }\n }\n // impossible: upstream must have advanced in order for replication to be stuck.\n assert(changeStreamer, `resetting replica did not advance replicaVersion`);\n\n // Perform any upgrades to the replica in case it was restored from an\n // earlier version. Note that this upgrade is done by the replicator worker\n // as well (in both the replication-manager and the view-syncer), but the\n // change-streamer independently reads the replica, and it is fine run the\n // upgrade logic redundantly since it is idempotent.\n await upgradeReplica(lc, 'change-streamer-init', replica.file);\n\n const {backupURL, port: metricsPort} = litestream;\n const monitor = backupURL\n ? new BackupMonitor(\n lc,\n replica.file,\n backupURL,\n `http://localhost:${metricsPort}/metrics`,\n changeStreamer,\n // The time between when the zero-cache was started to when the\n // change-streamer is ready to start serves as the initial delay for\n // watermark cleanup (as it either includes a similar replica\n // restoration/preparation step, or an initial-sync, which\n // generally takes longer).\n //\n // Consider: Also account for permanent volumes?\n Date.now() - workerStartTime,\n )\n : new ReplicaMonitor(lc, replica.file, changeStreamer);\n\n const changeStreamerWebServer = new ChangeStreamerHttpServer(\n lc,\n {port, keepaliveTimeoutMs, startupDelayMs},\n parent,\n changeStreamer,\n monitor instanceof BackupMonitor ? monitor : null,\n );\n\n parent.send(['ready', {ready: true}]);\n\n // Note: The changeStreamer itself is not started here; it is started by the\n // changeStreamerWebServer.\n return runUntilKilled(lc, parent, changeStreamerWebServer, monitor);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)).catch(\n async e => {\n await publishCriticalEvent(\n lc,\n replicationStatusError(lc, 'Initializing', e),\n );\n throw e;\n },\n ),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"change-streamer.js","names":[],"sources":["../../../../../zero-cache/src/server/change-streamer.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {DatabaseInitError} from '../../../zqlite/src/db.ts';\nimport {getServerContext} from '../config/server-context.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {deleteLiteDB} from '../db/delete-lite-db.ts';\nimport {warmupConnections} from '../db/warmup.ts';\nimport {initEventSink, publishCriticalEvent} from '../observability/events.ts';\nimport {upgradeReplica} from '../services/change-source/common/replica-schema.ts';\nimport {initializeCustomChangeSource} from '../services/change-source/custom/change-source.ts';\nimport {initializePostgresChangeSource} from '../services/change-source/pg/change-source.ts';\nimport {BackupMonitor} from '../services/change-streamer/backup-monitor.ts';\nimport {ChangeStreamerHttpServer} from '../services/change-streamer/change-streamer-http.ts';\nimport {initializeStreamer} from '../services/change-streamer/change-streamer-service.ts';\nimport type {ChangeStreamerService} from '../services/change-streamer/change-streamer.ts';\nimport {ReplicaMonitor} from '../services/change-streamer/replica-monitor.ts';\nimport {initChangeStreamerSchema} from '../services/change-streamer/schema/init.ts';\nimport {AutoResetSignal} from '../services/change-streamer/schema/tables.ts';\nimport {PurgeLocker} from '../services/change-streamer/storer.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {\n BackupNotFoundException,\n restoreReplica,\n} from '../services/litestream/commands.ts';\nimport {\n replicationStatusError,\n ReplicationStatusPublisher,\n} from '../services/replicator/replication-status.ts';\nimport {connectPgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...argv: string[]\n): Promise<void> {\n const workerStartTime = Date.now();\n const config = getNormalizedZeroConfig({env, argv});\n const {\n taskID,\n changeStreamer: {\n port,\n address,\n protocol,\n startupDelayMs,\n backPressureLimitHeapProportion,\n flowControlConsensusPaddingSeconds,\n },\n upstream,\n change,\n replica,\n initialSync,\n litestream,\n keepaliveTimeoutMs,\n } = config;\n\n startOtelAuto(\n createLogContext(config, 'change-streamer', 0, false),\n 'change-streamer',\n 0,\n );\n lc = createLogContext(config, 'change-streamer');\n initEventSink(lc, config);\n\n // Kick off DB connection warmup in the background.\n const changeDB = await connectPgClient(\n lc,\n change.db,\n 'change-streamer',\n {\n max: change.maxConns,\n },\n {sendStringAsJson: true},\n );\n void warmupConnections(lc, changeDB, 'change').catch(() => {});\n\n const {autoReset, replicationLag} = config;\n const shard = getShardConfig(config);\n\n // Ensure the change DB schema is initialized/up-to-date, then acquire\n // a lock to prevent change-lock purges. This ensures that (this)\n // change-streamer will be able to resume from the backup.\n await initChangeStreamerSchema(lc, changeDB, shard);\n let purgeLock = await new PurgeLocker(lc, shard, changeDB).acquire();\n\n // Restore from litestream if the change-log has entries.\n if (purgeLock) {\n try {\n await restoreReplica(lc, config, purgeLock);\n } catch (e) {\n // If the restore failed, e.g. due to a corrupt or missing backup, the\n // replication-manager recovers by re-syncing.\n const log = e instanceof BackupNotFoundException ? 'warn' : 'error';\n lc[log]?.(\n `error restoring backup. resyncing the replica: ${String(e)}`,\n e,\n );\n\n // The purgeLock must be released if the backup could not be restored,\n // or it will otherwise prevent the change-db update after the resync\n // completes.\n await purgeLock.release();\n purgeLock = null;\n }\n }\n\n let changeStreamer: ChangeStreamerService | undefined;\n\n const context = getServerContext(config);\n\n for (const first of [true, false]) {\n try {\n // Note: This performs initial sync of the replica if necessary.\n const {changeSource, subscriptionState} =\n upstream.type === 'pg'\n ? await initializePostgresChangeSource(\n lc,\n upstream.db,\n shard,\n replica.file,\n {\n ...initialSync,\n replicationSlotFailover: upstream.pgReplicationSlotFailover,\n },\n context,\n replicationLag.reportIntervalMs,\n )\n : await initializeCustomChangeSource(\n lc,\n upstream.db,\n shard,\n replica.file,\n context,\n );\n\n const replicationStatusPublisher =\n ReplicationStatusPublisher.forReplicaFile(replica.file);\n\n changeStreamer = await initializeStreamer(\n lc,\n shard,\n taskID,\n address,\n protocol,\n changeDB,\n changeSource,\n replicationStatusPublisher,\n subscriptionState,\n purgeLock,\n autoReset ?? false,\n {\n backPressureLimitHeapProportion,\n flowControlConsensusPaddingSeconds,\n statementTimeoutMs: change.statementTimeoutMs,\n },\n setTimeout,\n );\n break;\n } catch (e) {\n if (first && e instanceof AutoResetSignal) {\n lc.warn?.(`resetting replica ${replica.file}`, e);\n // TODO: Make deleteLiteDB work with litestream. It will probably have to be\n // a semantic wipe instead of a file delete.\n deleteLiteDB(replica.file);\n // Release the purge lock before retrying. This is safe because the\n // purge lock exists to preserve change-log entries so the new\n // change-streamer can resume from the backup replica's watermark.\n // An AutoResetSignal means we cant resume from the backup replica\n // (e.g. its replication slot is gone), so the change-log entries the lock\n // was protecting are no longer needed. The retry performs a fresh\n // initial sync with a new replication slot, independent of the old\n // change-log. Releasing is also necessary to avoid a\n // self-deadlock when CHANGE_DB == UPSTREAM_DB:\n // CREATE_REPLICATION_SLOT waits for all older transactions to\n // finish, including this lock's open transaction.\n await purgeLock?.release();\n purgeLock = null;\n continue; // execute again with a fresh initial-sync\n }\n if (e instanceof DatabaseInitError) {\n throw new Error(\n `Cannot open ZERO_REPLICA_FILE at \"${replica.file}\". Please check that the path is valid.`,\n {cause: e},\n );\n }\n throw e;\n }\n }\n // impossible: upstream must have advanced in order for replication to be stuck.\n assert(changeStreamer, `resetting replica did not advance replicaVersion`);\n\n // Perform any upgrades to the replica in case it was restored from an\n // earlier version. Note that this upgrade is done by the replicator worker\n // as well (in both the replication-manager and the view-syncer), but the\n // change-streamer independently reads the replica, and it is fine run the\n // upgrade logic redundantly since it is idempotent.\n await upgradeReplica(lc, 'change-streamer-init', replica.file);\n\n const {backupURL, port: metricsPort} = litestream;\n const monitor = backupURL\n ? new BackupMonitor(\n lc,\n replica.file,\n backupURL,\n `http://localhost:${metricsPort}/metrics`,\n changeStreamer,\n // The time between when the zero-cache was started to when the\n // change-streamer is ready to start serves as the initial delay for\n // watermark cleanup (as it either includes a similar replica\n // restoration/preparation step, or an initial-sync, which\n // generally takes longer).\n //\n // Consider: Also account for permanent volumes?\n Date.now() - workerStartTime,\n )\n : new ReplicaMonitor(lc, replica.file, changeStreamer);\n\n const changeStreamerWebServer = new ChangeStreamerHttpServer(\n lc,\n {port, keepaliveTimeoutMs, startupDelayMs},\n parent,\n changeStreamer,\n monitor instanceof BackupMonitor ? monitor : null,\n );\n\n parent.send(['ready', {ready: true}]);\n\n // Note: The changeStreamer itself is not started here; it is started by the\n // changeStreamerWebServer.\n return runUntilKilled(lc, parent, changeStreamerWebServer, monitor);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)).catch(\n async e => {\n await publishCriticalEvent(\n lc,\n replicationStatusError(lc, 'Initializing', e),\n );\n throw e;\n },\n ),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,IAAI,KAAK,IAAI,WAAW,QAAQ,EAAE,EAAE,eAAe;AAEnD,eAA8B,UAC5B,QACA,KACA,GAAG,MACY;CACf,MAAM,kBAAkB,KAAK,KAAK;CAClC,MAAM,SAAS,wBAAwB;EAAC;EAAK;EAAK,CAAC;CACnD,MAAM,EACJ,QACA,gBAAgB,EACd,MACA,SACA,UACA,gBACA,iCACA,sCAEF,UACA,QACA,SACA,aACA,YACA,uBACE;AAEJ,eACE,iBAAiB,QAAQ,mBAAmB,GAAG,MAAM,EACrD,mBACA,EACD;AACD,MAAK,iBAAiB,QAAQ,kBAAkB;AAChD,eAAc,IAAI,OAAO;CAGzB,MAAM,WAAW,MAAM,gBACrB,IACA,OAAO,IACP,mBACA,EACE,KAAK,OAAO,UACb,EACD,EAAC,kBAAkB,MAAK,CACzB;AACI,mBAAkB,IAAI,UAAU,SAAS,CAAC,YAAY,GAAG;CAE9D,MAAM,EAAC,WAAW,mBAAkB;CACpC,MAAM,QAAQ,eAAe,OAAO;AAKpC,OAAM,yBAAyB,IAAI,UAAU,MAAM;CACnD,IAAI,YAAY,MAAM,IAAI,YAAY,IAAI,OAAO,SAAS,CAAC,SAAS;AAGpE,KAAI,UACF,KAAI;AACF,QAAM,eAAe,IAAI,QAAQ,UAAU;UACpC,GAAG;EAGV,MAAM,MAAM,aAAa,0BAA0B,SAAS;AAC5D,KAAG,OACD,kDAAkD,OAAO,EAAE,IAC3D,EACD;AAKD,QAAM,UAAU,SAAS;AACzB,cAAY;;CAIhB,IAAI;CAEJ,MAAM,UAAU,iBAAiB,OAAO;AAExC,MAAK,MAAM,SAAS,CAAC,MAAM,MAAM,CAC/B,KAAI;EAEF,MAAM,EAAC,cAAc,sBACnB,SAAS,SAAS,OACd,MAAM,+BACJ,IACA,SAAS,IACT,OACA,QAAQ,MACR;GACE,GAAG;GACH,yBAAyB,SAAS;GACnC,EACD,SACA,eAAe,iBAChB,GACD,MAAM,6BACJ,IACA,SAAS,IACT,OACA,QAAQ,MACR,QACD;EAEP,MAAM,6BACJ,2BAA2B,eAAe,QAAQ,KAAK;AAEzD,mBAAiB,MAAM,mBACrB,IACA,OACA,QACA,SACA,UACA,UACA,cACA,4BACA,mBACA,WACA,aAAa,OACb;GACE;GACA;GACA,oBAAoB,OAAO;GAC5B,EACD,WACD;AACD;UACO,GAAG;AACV,MAAI,SAAS,aAAa,iBAAiB;AACzC,MAAG,OAAO,qBAAqB,QAAQ,QAAQ,EAAE;AAGjD,gBAAa,QAAQ,KAAK;AAY1B,SAAM,WAAW,SAAS;AAC1B,eAAY;AACZ;;AAEF,MAAI,aAAa,kBACf,OAAM,IAAI,MACR,qCAAqC,QAAQ,KAAK,0CAClD,EAAC,OAAO,GAAE,CACX;AAEH,QAAM;;AAIV,QAAO,gBAAgB,mDAAmD;AAO1E,OAAM,eAAe,IAAI,wBAAwB,QAAQ,KAAK;CAE9D,MAAM,EAAC,WAAW,MAAM,gBAAe;CACvC,MAAM,UAAU,YACZ,IAAI,cACF,IACA,QAAQ,MACR,WACA,oBAAoB,YAAY,WAChC,gBAQA,KAAK,KAAK,GAAG,gBACd,GACD,IAAI,eAAe,IAAI,QAAQ,MAAM,eAAe;CAExD,MAAM,0BAA0B,IAAI,yBAClC,IACA;EAAC;EAAM;EAAoB;EAAe,EAC1C,QACA,gBACA,mBAAmB,gBAAgB,UAAU,KAC9C;AAED,QAAO,KAAK,CAAC,SAAS,EAAC,OAAO,MAAK,CAAC,CAAC;AAIrC,QAAO,eAAe,IAAI,QAAQ,yBAAyB,QAAQ;;AAIrE,IAAI,CAAC,mBAAmB,CACjB,WAAU,UACb,UAAU,KAAK,aAAa,EAAE,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,EAAE,CAAC,CAAC,MACnE,OAAM,MAAK;AACT,OAAM,qBACJ,IACA,uBAAuB,IAAI,gBAAgB,EAAE,CAC9C;AACD,OAAM;EAET,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"inspector-delegate.js","names":["#globalMetrics","#perQueryHydrateMs","#perQueryUpdateMetrics","#queryIDToAST","#customQueryTransformer"],"sources":["../../../../../zero-cache/src/server/inspector-delegate.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {mapValues} from '../../../shared/src/objects.ts';\nimport {TDigest} from '../../../shared/src/tdigest.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport type {QueryServerMetrics as QueryServerMetricsJSON} from '../../../zero-protocol/src/inspect-down.ts';\nimport {hashOfNameAndArgs} from '../../../zero-protocol/src/query-hash.ts';\nimport {\n isServerMetric,\n type MetricMap,\n type MetricsDelegate,\n} from '../../../zql/src/query/metrics-delegate.ts';\nimport {isDevelopmentMode} from '../config/normalize.ts';\nimport type {CustomQueryTransformer} from '../custom-queries/transform-query.ts';\nimport type {ConnectionContext} from '../services/view-syncer/connection-context-manager.ts';\nimport type {CustomQueryRecord} from '../services/view-syncer/schema/types.ts';\nimport {ProtocolErrorWithLevel} from '../types/error-with-level.ts';\n\n/**\n * Server-side metrics collected for queries during materialization and update.\n * These metrics are reported via the inspector and complement client-side metrics.\n * Used for the global aggregate (all queries combined).\n */\nexport type ServerMetrics = {\n 'query-materialization-server': TDigest;\n 'query-update-server': TDigest;\n};\n\ntype ClientGroupID = string;\n\n/**\n * Set of authenticated client group IDs. We keep this outside of the class to\n * share this state across all instances of the InspectorDelegate.\n */\nconst authenticatedClientGroupIDs = new Set<ClientGroupID>();\n\nexport class InspectorDelegate implements MetricsDelegate {\n readonly #globalMetrics: ServerMetrics = newMetrics();\n readonly #perQueryHydrateMs = new Map<string, number>();\n readonly #perQueryUpdateMetrics = new Map<string, TDigest>();\n readonly #queryIDToAST: Map<string, AST> = new Map();\n readonly #customQueryTransformer: CustomQueryTransformer | undefined;\n\n constructor(customQueryTransformer: CustomQueryTransformer | undefined) {\n this.#customQueryTransformer = customQueryTransformer;\n }\n\n addMetric<K extends keyof MetricMap>(\n metric: K,\n value: number,\n ...args: MetricMap[K]\n ): void {\n assert(isServerMetric(metric), `Invalid server metric: ${metric}`);\n const queryID = args[0];\n if (metric === 'query-materialization-server') {\n this.#perQueryHydrateMs.set(queryID, value);\n } else {\n let digest = this.#perQueryUpdateMetrics.get(queryID);\n if (!digest) {\n digest = new TDigest();\n this.#perQueryUpdateMetrics.set(queryID, digest);\n }\n digest.add(value);\n }\n this.#globalMetrics[metric].add(value);\n }\n\n getMetricsJSONForQuery(queryID: string): QueryServerMetricsJSON | null {\n const hydrateMs = this.#perQueryHydrateMs.get(queryID);\n const updateMetrics = this.#perQueryUpdateMetrics.get(queryID);\n if (hydrateMs === undefined && updateMetrics === undefined) {\n return null;\n }\n return {\n 'query-hydration-server-ms': hydrateMs,\n 'query-update-server': (updateMetrics ?? new TDigest()).toJSON(),\n };\n }\n\n getMetricsJSON() {\n return mapValues(this.#globalMetrics, v => v.toJSON());\n }\n\n getASTForQuery(queryID: string): AST | undefined {\n return this.#queryIDToAST.get(queryID);\n }\n\n removeQuery(queryID: string): void {\n this.#perQueryHydrateMs.delete(queryID);\n this.#perQueryUpdateMetrics.delete(queryID);\n this.#queryIDToAST.delete(queryID);\n }\n\n addQuery(queryID: string, ast: AST): void {\n this.#queryIDToAST.set(queryID, ast);\n }\n\n /**\n * Check if the client is authenticated. We only require authentication once\n * per \"worker\".\n */\n isAuthenticated(clientGroupID: ClientGroupID): boolean {\n return (\n isDevelopmentMode() || authenticatedClientGroupIDs.has(clientGroupID)\n );\n }\n\n setAuthenticated(clientGroupID: ClientGroupID): void {\n authenticatedClientGroupIDs.add(clientGroupID);\n }\n\n clearAuthenticated(clientGroupID: ClientGroupID) {\n authenticatedClientGroupIDs.delete(clientGroupID);\n }\n\n /**\n * Transforms a single custom query by name and args using the configured\n * CustomQueryTransformer. This is primarily used by the inspector to transform\n * queries for analysis.\n */\n async transformCustomQuery(\n name: string,\n args: readonly ReadonlyJSONValue[],\n ctx: ConnectionContext,\n ): Promise<AST> {\n assert(\n this.#customQueryTransformer,\n 'Custom query transformation requested but no CustomQueryTransformer is configured',\n );\n\n // Create a fake CustomQueryRecord for the single query\n const queryID = hashOfNameAndArgs(name, args);\n const queries: CustomQueryRecord[] = [\n {\n id: queryID,\n type: 'custom',\n name,\n args,\n clientState: {},\n },\n ];\n\n const results = await this.#customQueryTransformer.transform(ctx, queries);\n\n if ('kind' in results.result) {\n throw new ProtocolErrorWithLevel(results.result, 'warn');\n }\n\n const result = results.result[0];\n if (!result) {\n throw new Error('No transformation result returned');\n }\n\n if ('error' in result) {\n const message =\n result.message ?? 'Unknown application error from custom query';\n throw new Error(\n `Error transforming custom query ${name} (${result.error}): ${message} ${JSON.stringify(result.details)}`,\n );\n }\n\n return result.transformedAst;\n }\n}\n\nfunction newMetrics(): ServerMetrics {\n return {\n 'query-materialization-server': new TDigest(),\n 'query-update-server': new TDigest(),\n };\n}\n"],"mappings":";;;;;;;;;;;;AAkCA,IAAM,8CAA8B,IAAI,IAAmB;AAE3D,IAAa,oBAAb,MAA0D;CACxD,iBAAyC,WAAW;CACpD,qCAA8B,IAAI,IAAoB;CACtD,yCAAkC,IAAI,IAAqB;CAC3D,gCAA2C,IAAI,IAAI;CACnD;CAEA,YAAY,wBAA4D;EACtE,KAAKI,0BAA0B;CACjC;CAEA,UACE,QACA,OACA,GAAG,MACG;EACN,OAAO,eAAe,MAAM,GAAG,0BAA0B,QAAQ;EACjE,MAAM,UAAU,KAAK;EACrB,IAAI,WAAW,gCACb,KAAKH,mBAAmB,IAAI,SAAS,KAAK;OACrC;GACL,IAAI,SAAS,KAAKC,uBAAuB,IAAI,OAAO;GACpD,IAAI,CAAC,QAAQ;IACX,SAAS,IAAI,QAAQ;IACrB,KAAKA,uBAAuB,IAAI,SAAS,MAAM;GACjD;GACA,OAAO,IAAI,KAAK;EAClB;EACA,KAAKF,eAAe,QAAQ,IAAI,KAAK;CACvC;CAEA,uBAAuB,SAAgD;EACrE,MAAM,YAAY,KAAKC,mBAAmB,IAAI,OAAO;EACrD,MAAM,gBAAgB,KAAKC,uBAAuB,IAAI,OAAO;EAC7D,IAAI,cAAc,KAAA,KAAa,kBAAkB,KAAA,GAC/C,OAAO;EAET,OAAO;GACL,6BAA6B;GAC7B,wBAAwB,iBAAiB,IAAI,QAAQ,GAAG,OAAO;EACjE;CACF;CAEA,iBAAiB;EACf,OAAO,UAAU,KAAKF,iBAAgB,MAAK,EAAE,OAAO,CAAC;CACvD;CAEA,eAAe,SAAkC;EAC/C,OAAO,KAAKG,cAAc,IAAI,OAAO;CACvC;CAEA,YAAY,SAAuB;EACjC,KAAKF,mBAAmB,OAAO,OAAO;EACtC,KAAKC,uBAAuB,OAAO,OAAO;EAC1C,KAAKC,cAAc,OAAO,OAAO;CACnC;CAEA,SAAS,SAAiB,KAAgB;EACxC,KAAKA,cAAc,IAAI,SAAS,GAAG;CACrC;;;;;CAMA,gBAAgB,eAAuC;EACrD,OACE,kBAAkB,KAAK,4BAA4B,IAAI,aAAa;CAExE;CAEA,iBAAiB,eAAoC;EACnD,4BAA4B,IAAI,aAAa;CAC/C;CAEA,mBAAmB,eAA8B;EAC/C,4BAA4B,OAAO,aAAa;CAClD;;;;;;CAOA,MAAM,qBACJ,MACA,MACA,KACc;EACd,OACE,KAAKC,yBACL,mFACF;EAIA,MAAM,UAA+B,CACnC;GACE,IAHY,kBAAkB,MAAM,IAGhC;GACJ,MAAM;GACN;GACA;GACA,aAAa,CAAC;EAChB,CACF;EAEA,MAAM,UAAU,MAAM,KAAKA,wBAAwB,UAAU,KAAK,OAAO;EAEzE,IAAI,UAAU,QAAQ,QACpB,MAAM,IAAI,uBAAuB,QAAQ,QAAQ,MAAM;EAGzD,MAAM,SAAS,QAAQ,OAAO;EAC9B,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,mCAAmC;EAGrD,IAAI,WAAW,QAAQ;GACrB,MAAM,UACJ,OAAO,WAAW;GACpB,MAAM,IAAI,MACR,mCAAmC,KAAK,IAAI,OAAO,MAAM,KAAK,QAAQ,GAAG,KAAK,UAAU,OAAO,OAAO,GACxG;EACF;EAEA,OAAO,OAAO;CAChB;AACF;AAEA,SAAS,aAA4B;CACnC,OAAO;EACL,gCAAgC,IAAI,QAAQ;EAC5C,uBAAuB,IAAI,QAAQ;CACrC;AACF"}
1
+ {"version":3,"file":"inspector-delegate.js","names":["#globalMetrics","#perQueryHydrateMs","#perQueryUpdateMetrics","#queryIDToAST","#customQueryTransformer"],"sources":["../../../../../zero-cache/src/server/inspector-delegate.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {mapValues} from '../../../shared/src/objects.ts';\nimport {TDigest} from '../../../shared/src/tdigest.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport type {QueryServerMetrics as QueryServerMetricsJSON} from '../../../zero-protocol/src/inspect-down.ts';\nimport {hashOfNameAndArgs} from '../../../zero-protocol/src/query-hash.ts';\nimport {\n isServerMetric,\n type MetricMap,\n type MetricsDelegate,\n} from '../../../zql/src/query/metrics-delegate.ts';\nimport {isDevelopmentMode} from '../config/normalize.ts';\nimport type {CustomQueryTransformer} from '../custom-queries/transform-query.ts';\nimport type {ConnectionContext} from '../services/view-syncer/connection-context-manager.ts';\nimport type {CustomQueryRecord} from '../services/view-syncer/schema/types.ts';\nimport {ProtocolErrorWithLevel} from '../types/error-with-level.ts';\n\n/**\n * Server-side metrics collected for queries during materialization and update.\n * These metrics are reported via the inspector and complement client-side metrics.\n * Used for the global aggregate (all queries combined).\n */\nexport type ServerMetrics = {\n 'query-materialization-server': TDigest;\n 'query-update-server': TDigest;\n};\n\ntype ClientGroupID = string;\n\n/**\n * Set of authenticated client group IDs. We keep this outside of the class to\n * share this state across all instances of the InspectorDelegate.\n */\nconst authenticatedClientGroupIDs = new Set<ClientGroupID>();\n\nexport class InspectorDelegate implements MetricsDelegate {\n readonly #globalMetrics: ServerMetrics = newMetrics();\n readonly #perQueryHydrateMs = new Map<string, number>();\n readonly #perQueryUpdateMetrics = new Map<string, TDigest>();\n readonly #queryIDToAST: Map<string, AST> = new Map();\n readonly #customQueryTransformer: CustomQueryTransformer | undefined;\n\n constructor(customQueryTransformer: CustomQueryTransformer | undefined) {\n this.#customQueryTransformer = customQueryTransformer;\n }\n\n addMetric<K extends keyof MetricMap>(\n metric: K,\n value: number,\n ...args: MetricMap[K]\n ): void {\n assert(isServerMetric(metric), `Invalid server metric: ${metric}`);\n const queryID = args[0];\n if (metric === 'query-materialization-server') {\n this.#perQueryHydrateMs.set(queryID, value);\n } else {\n let digest = this.#perQueryUpdateMetrics.get(queryID);\n if (!digest) {\n digest = new TDigest();\n this.#perQueryUpdateMetrics.set(queryID, digest);\n }\n digest.add(value);\n }\n this.#globalMetrics[metric].add(value);\n }\n\n getMetricsJSONForQuery(queryID: string): QueryServerMetricsJSON | null {\n const hydrateMs = this.#perQueryHydrateMs.get(queryID);\n const updateMetrics = this.#perQueryUpdateMetrics.get(queryID);\n if (hydrateMs === undefined && updateMetrics === undefined) {\n return null;\n }\n return {\n 'query-hydration-server-ms': hydrateMs,\n 'query-update-server': (updateMetrics ?? new TDigest()).toJSON(),\n };\n }\n\n getMetricsJSON() {\n return mapValues(this.#globalMetrics, v => v.toJSON());\n }\n\n getASTForQuery(queryID: string): AST | undefined {\n return this.#queryIDToAST.get(queryID);\n }\n\n removeQuery(queryID: string): void {\n this.#perQueryHydrateMs.delete(queryID);\n this.#perQueryUpdateMetrics.delete(queryID);\n this.#queryIDToAST.delete(queryID);\n }\n\n addQuery(queryID: string, ast: AST): void {\n this.#queryIDToAST.set(queryID, ast);\n }\n\n /**\n * Check if the client is authenticated. We only require authentication once\n * per \"worker\".\n */\n isAuthenticated(clientGroupID: ClientGroupID): boolean {\n return (\n isDevelopmentMode() || authenticatedClientGroupIDs.has(clientGroupID)\n );\n }\n\n setAuthenticated(clientGroupID: ClientGroupID): void {\n authenticatedClientGroupIDs.add(clientGroupID);\n }\n\n clearAuthenticated(clientGroupID: ClientGroupID) {\n authenticatedClientGroupIDs.delete(clientGroupID);\n }\n\n /**\n * Transforms a single custom query by name and args using the configured\n * CustomQueryTransformer. This is primarily used by the inspector to transform\n * queries for analysis.\n */\n async transformCustomQuery(\n name: string,\n args: readonly ReadonlyJSONValue[],\n ctx: ConnectionContext,\n ): Promise<AST> {\n assert(\n this.#customQueryTransformer,\n 'Custom query transformation requested but no CustomQueryTransformer is configured',\n );\n\n // Create a fake CustomQueryRecord for the single query\n const queryID = hashOfNameAndArgs(name, args);\n const queries: CustomQueryRecord[] = [\n {\n id: queryID,\n type: 'custom',\n name,\n args,\n clientState: {},\n },\n ];\n\n const results = await this.#customQueryTransformer.transform(ctx, queries);\n\n if ('kind' in results.result) {\n throw new ProtocolErrorWithLevel(results.result, 'warn');\n }\n\n const result = results.result[0];\n if (!result) {\n throw new Error('No transformation result returned');\n }\n\n if ('error' in result) {\n const message =\n result.message ?? 'Unknown application error from custom query';\n throw new Error(\n `Error transforming custom query ${name} (${result.error}): ${message} ${JSON.stringify(result.details)}`,\n );\n }\n\n return result.transformedAst;\n }\n}\n\nfunction newMetrics(): ServerMetrics {\n return {\n 'query-materialization-server': new TDigest(),\n 'query-update-server': new TDigest(),\n };\n}\n"],"mappings":";;;;;;;;;;;;AAkCA,IAAM,8CAA8B,IAAI,KAAoB;AAE5D,IAAa,oBAAb,MAA0D;CACxD,iBAAyC,YAAY;CACrD,qCAA8B,IAAI,KAAqB;CACvD,yCAAkC,IAAI,KAAsB;CAC5D,gCAA2C,IAAI,KAAK;CACpD;CAEA,YAAY,wBAA4D;AACtE,QAAA,yBAA+B;;CAGjC,UACE,QACA,OACA,GAAG,MACG;AACN,SAAO,eAAe,OAAO,EAAE,0BAA0B,SAAS;EAClE,MAAM,UAAU,KAAK;AACrB,MAAI,WAAW,+BACb,OAAA,kBAAwB,IAAI,SAAS,MAAM;OACtC;GACL,IAAI,SAAS,MAAA,sBAA4B,IAAI,QAAQ;AACrD,OAAI,CAAC,QAAQ;AACX,aAAS,IAAI,SAAS;AACtB,UAAA,sBAA4B,IAAI,SAAS,OAAO;;AAElD,UAAO,IAAI,MAAM;;AAEnB,QAAA,cAAoB,QAAQ,IAAI,MAAM;;CAGxC,uBAAuB,SAAgD;EACrE,MAAM,YAAY,MAAA,kBAAwB,IAAI,QAAQ;EACtD,MAAM,gBAAgB,MAAA,sBAA4B,IAAI,QAAQ;AAC9D,MAAI,cAAc,KAAA,KAAa,kBAAkB,KAAA,EAC/C,QAAO;AAET,SAAO;GACL,6BAA6B;GAC7B,wBAAwB,iBAAiB,IAAI,SAAS,EAAE,QAAQ;GACjE;;CAGH,iBAAiB;AACf,SAAO,UAAU,MAAA,gBAAqB,MAAK,EAAE,QAAQ,CAAC;;CAGxD,eAAe,SAAkC;AAC/C,SAAO,MAAA,aAAmB,IAAI,QAAQ;;CAGxC,YAAY,SAAuB;AACjC,QAAA,kBAAwB,OAAO,QAAQ;AACvC,QAAA,sBAA4B,OAAO,QAAQ;AAC3C,QAAA,aAAmB,OAAO,QAAQ;;CAGpC,SAAS,SAAiB,KAAgB;AACxC,QAAA,aAAmB,IAAI,SAAS,IAAI;;;;;;CAOtC,gBAAgB,eAAuC;AACrD,SACE,mBAAmB,IAAI,4BAA4B,IAAI,cAAc;;CAIzE,iBAAiB,eAAoC;AACnD,8BAA4B,IAAI,cAAc;;CAGhD,mBAAmB,eAA8B;AAC/C,8BAA4B,OAAO,cAAc;;;;;;;CAQnD,MAAM,qBACJ,MACA,MACA,KACc;AACd,SACE,MAAA,wBACA,oFACD;EAID,MAAM,UAA+B,CACnC;GACE,IAHY,kBAAkB,MAAM,KAAK;GAIzC,MAAM;GACN;GACA;GACA,aAAa,EAAE;GAChB,CACF;EAED,MAAM,UAAU,MAAM,MAAA,uBAA6B,UAAU,KAAK,QAAQ;AAE1E,MAAI,UAAU,QAAQ,OACpB,OAAM,IAAI,uBAAuB,QAAQ,QAAQ,OAAO;EAG1D,MAAM,SAAS,QAAQ,OAAO;AAC9B,MAAI,CAAC,OACH,OAAM,IAAI,MAAM,oCAAoC;AAGtD,MAAI,WAAW,QAAQ;GACrB,MAAM,UACJ,OAAO,WAAW;AACpB,SAAM,IAAI,MACR,mCAAmC,KAAK,IAAI,OAAO,MAAM,KAAK,QAAQ,GAAG,KAAK,UAAU,OAAO,QAAQ,GACxG;;AAGH,SAAO,OAAO;;;AAIlB,SAAS,aAA4B;AACnC,QAAO;EACL,gCAAgC,IAAI,SAAS;EAC7C,uBAAuB,IAAI,SAAS;EACrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"logging.js","names":["#sinks"],"sources":["../../../../../zero-cache/src/server/logging.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {type Context, type LogLevel, type LogSink} from '@rocicorp/logger';\nimport {otelLogsEnabled} from '../../../otel/src/enabled.ts';\nimport {\n createLogContext as createLogContextShared,\n getLogSink,\n type LogConfig,\n} from '../../../shared/src/logging.ts';\nimport {UNHANDLED_EXCEPTION_ERROR_CODE} from '../services/life-cycle.ts';\nimport {OtelLogSink} from './otel-log-sink.ts';\n\nexport function createLogContext(\n {log}: {log: LogConfig},\n worker: string,\n workerIndex = 0,\n includeOtel = true,\n): LogContext {\n const logSink = createLogSink(log, includeOtel);\n const lc = createLogContextShared({log}, {worker, workerIndex}, logSink);\n process.on('uncaughtException', async (err, origin) => {\n lc.error?.(origin, err);\n await logSink.flush?.();\n process.exit(UNHANDLED_EXCEPTION_ERROR_CODE);\n });\n return lc;\n}\n\nfunction createLogSink(config: LogConfig, includeOtel: boolean): LogSink {\n const sink = getLogSink(config);\n if (includeOtel && otelLogsEnabled()) {\n const otelSink = new OtelLogSink();\n return new CompositeLogSink([otelSink, sink]);\n }\n return sink;\n}\n\nclass CompositeLogSink implements LogSink {\n readonly #sinks: LogSink[];\n\n constructor(sinks: LogSink[]) {\n this.#sinks = sinks;\n }\n\n log(level: LogLevel, context: Context | undefined, ...args: unknown[]): void {\n for (const sink of this.#sinks) {\n sink.log(level, context, ...args);\n }\n }\n}\n"],"mappings":";;;;;;AAWA,SAAgB,iBACd,EAAC,OACD,QACA,cAAc,GACd,cAAc,MACF;CACZ,MAAM,UAAU,cAAc,KAAK,WAAW;CAC9C,MAAM,KAAK,mBAAuB,EAAC,IAAG,GAAG;EAAC;EAAQ;CAAW,GAAG,OAAO;CACvE,QAAQ,GAAG,qBAAqB,OAAO,KAAK,WAAW;EACrD,GAAG,QAAQ,QAAQ,GAAG;EACtB,MAAM,QAAQ,QAAQ;EACtB,QAAQ,KAAA,EAAmC;CAC7C,CAAC;CACD,OAAO;AACT;AAEA,SAAS,cAAc,QAAmB,aAA+B;CACvE,MAAM,OAAO,WAAW,MAAM;CAC9B,IAAI,eAAe,gBAAgB,GAEjC,OAAO,IAAI,iBAAiB,CAAC,IADR,YACQ,GAAU,IAAI,CAAC;CAE9C,OAAO;AACT;AAEA,IAAM,mBAAN,MAA0C;CACxC;CAEA,YAAY,OAAkB;EAC5B,KAAKA,SAAS;CAChB;CAEA,IAAI,OAAiB,SAA8B,GAAG,MAAuB;EAC3E,KAAK,MAAM,QAAQ,KAAKA,QACtB,KAAK,IAAI,OAAO,SAAS,GAAG,IAAI;CAEpC;AACF"}
1
+ {"version":3,"file":"logging.js","names":["#sinks"],"sources":["../../../../../zero-cache/src/server/logging.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {type Context, type LogLevel, type LogSink} from '@rocicorp/logger';\nimport {otelLogsEnabled} from '../../../otel/src/enabled.ts';\nimport {\n createLogContext as createLogContextShared,\n getLogSink,\n type LogConfig,\n} from '../../../shared/src/logging.ts';\nimport {UNHANDLED_EXCEPTION_ERROR_CODE} from '../services/life-cycle.ts';\nimport {OtelLogSink} from './otel-log-sink.ts';\n\nexport function createLogContext(\n {log}: {log: LogConfig},\n worker: string,\n workerIndex = 0,\n includeOtel = true,\n): LogContext {\n const logSink = createLogSink(log, includeOtel);\n const lc = createLogContextShared({log}, {worker, workerIndex}, logSink);\n process.on('uncaughtException', async (err, origin) => {\n lc.error?.(origin, err);\n await logSink.flush?.();\n process.exit(UNHANDLED_EXCEPTION_ERROR_CODE);\n });\n return lc;\n}\n\nfunction createLogSink(config: LogConfig, includeOtel: boolean): LogSink {\n const sink = getLogSink(config);\n if (includeOtel && otelLogsEnabled()) {\n const otelSink = new OtelLogSink();\n return new CompositeLogSink([otelSink, sink]);\n }\n return sink;\n}\n\nclass CompositeLogSink implements LogSink {\n readonly #sinks: LogSink[];\n\n constructor(sinks: LogSink[]) {\n this.#sinks = sinks;\n }\n\n log(level: LogLevel, context: Context | undefined, ...args: unknown[]): void {\n for (const sink of this.#sinks) {\n sink.log(level, context, ...args);\n }\n }\n}\n"],"mappings":";;;;;;AAWA,SAAgB,iBACd,EAAC,OACD,QACA,cAAc,GACd,cAAc,MACF;CACZ,MAAM,UAAU,cAAc,KAAK,YAAY;CAC/C,MAAM,KAAK,mBAAuB,EAAC,KAAI,EAAE;EAAC;EAAQ;EAAY,EAAE,QAAQ;AACxE,SAAQ,GAAG,qBAAqB,OAAO,KAAK,WAAW;AACrD,KAAG,QAAQ,QAAQ,IAAI;AACvB,QAAM,QAAQ,SAAS;AACvB,UAAQ,KAAA,GAAoC;GAC5C;AACF,QAAO;;AAGT,SAAS,cAAc,QAAmB,aAA+B;CACvE,MAAM,OAAO,WAAW,OAAO;AAC/B,KAAI,eAAe,iBAAiB,CAElC,QAAO,IAAI,iBAAiB,CADX,IAAI,aAAa,EACK,KAAK,CAAC;AAE/C,QAAO;;AAGT,IAAM,mBAAN,MAA0C;CACxC;CAEA,YAAY,OAAkB;AAC5B,QAAA,QAAc;;CAGhB,IAAI,OAAiB,SAA8B,GAAG,MAAuB;AAC3E,OAAK,MAAM,QAAQ,MAAA,MACjB,MAAK,IAAI,OAAO,SAAS,GAAG,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":[],"sources":["../../../../../zero-cache/src/server/main.ts"],"sourcesContent":["import path from 'node:path';\nimport {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport {must} from '../../../shared/src/must.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {\n exitAfter,\n ProcessManager,\n runUntilKilled,\n type WorkerType,\n} from '../services/life-cycle.ts';\nimport {\n restoreReplica,\n startReplicaBackupProcess,\n} from '../services/litestream/commands.ts';\nimport {\n childWorker,\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {\n createNotifierFrom,\n handleSubscriptionsFrom,\n type ReplicaFileMode,\n subscribeTo,\n} from '../workers/replicator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\nimport {WorkerDispatcher} from './worker-dispatcher.ts';\nimport {\n CHANGE_STREAMER_URL,\n MUTATOR_URL,\n REAPER_URL,\n REPLICATOR_URL,\n SHADOW_SYNCER_URL,\n SYNCER_URL,\n} from './worker-urls.ts';\n\nconst clientConnectionBifurcated = false;\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n const startMs = Date.now();\n const config = getNormalizedZeroConfig({env});\n\n startOtelAuto(\n createLogContext(config, 'dispatcher', 0, false),\n 'dispatcher',\n 0,\n );\n lc = createLogContext(config, 'dispatcher');\n initEventSink(lc, config);\n\n const processes = new ProcessManager(lc, parent);\n\n const {numSyncWorkers: numSyncers} = config;\n if (config.enableCrudMutations && config.upstream.maxConns < numSyncers) {\n throw new Error(\n `Insufficient upstream connections (${config.upstream.maxConns}) for ${numSyncers} syncers.` +\n `Increase ZERO_UPSTREAM_MAX_CONNS or decrease ZERO_NUM_SYNC_WORKERS (which defaults to available cores).`,\n );\n }\n if (config.cvr.maxConns < numSyncers) {\n throw new Error(\n `Insufficient cvr connections (${config.cvr.maxConns}) for ${numSyncers} syncers.` +\n `Increase ZERO_CVR_MAX_CONNS or decrease ZERO_NUM_SYNC_WORKERS (which defaults to available cores).`,\n );\n }\n\n const internalFlags: string[] =\n numSyncers === 0\n ? []\n : [\n '--upstream-max-conns-per-worker',\n String(Math.floor(config.upstream.maxConns / numSyncers)),\n '--cvr-max-conns-per-worker',\n String(Math.floor(config.cvr.maxConns / numSyncers)),\n ];\n\n function loadWorker(\n moduleUrl: URL,\n type: WorkerType,\n id?: string | number,\n ...args: string[]\n ): Worker {\n const worker = childWorker(moduleUrl, env, ...args, ...internalFlags);\n const name = path.basename(moduleUrl.pathname) + (id ? ` (${id})` : '');\n return processes.addWorker(worker, type, name);\n }\n\n const {\n taskID,\n changeStreamer: {mode: changeStreamerMode, uri: changeStreamerURI},\n litestream,\n } = config;\n const runChangeStreamer =\n changeStreamerMode === 'dedicated' && changeStreamerURI === undefined;\n\n let changeStreamer: Worker | undefined;\n\n if (!runChangeStreamer) {\n changeStreamer = undefined;\n if (litestream.executable) {\n // For view-syncers, the backup is restored here. For the replication-manager,\n // the backup is restored in the change-streamer worker.\n await restoreReplica(lc, config, null);\n }\n } else {\n const {promise: changeStreamerReady, resolve: changeStreamerStarted} =\n resolver();\n changeStreamer = loadWorker(CHANGE_STREAMER_URL, 'supporting').once(\n 'message',\n changeStreamerStarted,\n );\n\n // Wait for the change-streamer to be ready to guarantee that a replica\n // file is present.\n await changeStreamerReady;\n\n if (litestream.backupURL) {\n // Start a backup replicator and corresponding litestream backup process.\n const {promise: backupReady, resolve} = resolver();\n const mode: ReplicaFileMode = 'backup';\n loadWorker(REPLICATOR_URL, 'supporting', mode, mode).once(\n // Wait for the Replicator's first message (i.e. \"ready\") before starting\n // litestream backup in order to avoid contending on the lock when the\n // replicator first prepares the db file.\n 'message',\n () => {\n processes.addSubprocess(\n startReplicaBackupProcess(lc, config),\n 'supporting',\n 'litestream',\n );\n resolve();\n },\n );\n await backupReady;\n }\n }\n\n if (numSyncers > 0) {\n const {promise: reaperReady, resolve: reaperStarted} = resolver();\n loadWorker(REAPER_URL, 'supporting').once('message', reaperStarted);\n // Before starting the view-syncers, ensure that the reaper has started\n // up, indicating that any CVR db migrations have been performed.\n await reaperReady;\n }\n\n // Only run the shadow-sync canary on the replication-manager (or in\n // single-node mode, where it also owns upstream). Running on every\n // view-syncer would hammer the upstream with N redundant canaries.\n if (config.shadowSync.enabled && runChangeStreamer) {\n const {promise: shadowReady, resolve: shadowStarted} = resolver();\n loadWorker(SHADOW_SYNCER_URL, 'supporting').once('message', shadowStarted);\n await shadowReady;\n }\n\n const syncers: Worker[] = [];\n if (numSyncers) {\n const mode: ReplicaFileMode =\n runChangeStreamer && litestream.backupURL ? 'serving-copy' : 'serving';\n const {promise: replicaReady, resolve} = resolver();\n const replicator = loadWorker(\n REPLICATOR_URL,\n 'supporting',\n mode,\n mode,\n ).once('message', () => {\n subscribeTo(lc, replicator);\n resolve();\n });\n await replicaReady;\n\n const notifier = createNotifierFrom(lc, replicator);\n for (let i = 0; i < numSyncers; i++) {\n syncers.push(loadWorker(SYNCER_URL, 'user-facing', i, mode, String(i)));\n }\n syncers.forEach(syncer => handleSubscriptionsFrom(lc, syncer, notifier));\n }\n let mutator: Worker | undefined;\n if (clientConnectionBifurcated) {\n mutator = loadWorker(MUTATOR_URL, 'supporting', 'mutator');\n }\n\n lc.info?.('waiting for workers to be ready ...');\n const logWaiting = setInterval(\n () => lc.info?.(`still waiting for ${processes.initializing().join(', ')}`),\n 10_000,\n );\n await processes.allWorkersReady();\n clearInterval(logWaiting);\n lc.info?.(`all workers ready (${Date.now() - startMs} ms)`);\n\n parent.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent,\n new WorkerDispatcher(\n lc,\n taskID,\n parent,\n syncers,\n mutator,\n changeStreamer,\n ),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'dispatcher');\n }\n\n await processes.done();\n}\n\nif (!singleProcessMode()) {\n void exitAfter(lc, () => runWorker(must(parentWorker), process.env));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"main.js","names":[],"sources":["../../../../../zero-cache/src/server/main.ts"],"sourcesContent":["import path from 'node:path';\nimport {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport {must} from '../../../shared/src/must.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {\n exitAfter,\n ProcessManager,\n runUntilKilled,\n type WorkerType,\n} from '../services/life-cycle.ts';\nimport {\n restoreReplica,\n startReplicaBackupProcess,\n} from '../services/litestream/commands.ts';\nimport {\n childWorker,\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {\n createNotifierFrom,\n handleSubscriptionsFrom,\n type ReplicaFileMode,\n subscribeTo,\n} from '../workers/replicator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\nimport {WorkerDispatcher} from './worker-dispatcher.ts';\nimport {\n CHANGE_STREAMER_URL,\n MUTATOR_URL,\n REAPER_URL,\n REPLICATOR_URL,\n SHADOW_SYNCER_URL,\n SYNCER_URL,\n} from './worker-urls.ts';\n\nconst clientConnectionBifurcated = false;\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n const startMs = Date.now();\n const config = getNormalizedZeroConfig({env});\n\n startOtelAuto(\n createLogContext(config, 'dispatcher', 0, false),\n 'dispatcher',\n 0,\n );\n lc = createLogContext(config, 'dispatcher');\n initEventSink(lc, config);\n\n const processes = new ProcessManager(lc, parent);\n\n const {numSyncWorkers: numSyncers} = config;\n if (config.enableCrudMutations && config.upstream.maxConns < numSyncers) {\n throw new Error(\n `Insufficient upstream connections (${config.upstream.maxConns}) for ${numSyncers} syncers.` +\n `Increase ZERO_UPSTREAM_MAX_CONNS or decrease ZERO_NUM_SYNC_WORKERS (which defaults to available cores).`,\n );\n }\n if (config.cvr.maxConns < numSyncers) {\n throw new Error(\n `Insufficient cvr connections (${config.cvr.maxConns}) for ${numSyncers} syncers.` +\n `Increase ZERO_CVR_MAX_CONNS or decrease ZERO_NUM_SYNC_WORKERS (which defaults to available cores).`,\n );\n }\n\n const internalFlags: string[] =\n numSyncers === 0\n ? []\n : [\n '--upstream-max-conns-per-worker',\n String(Math.floor(config.upstream.maxConns / numSyncers)),\n '--cvr-max-conns-per-worker',\n String(Math.floor(config.cvr.maxConns / numSyncers)),\n ];\n\n function loadWorker(\n moduleUrl: URL,\n type: WorkerType,\n id?: string | number,\n ...args: string[]\n ): Worker {\n const worker = childWorker(moduleUrl, env, ...args, ...internalFlags);\n const name = path.basename(moduleUrl.pathname) + (id ? ` (${id})` : '');\n return processes.addWorker(worker, type, name);\n }\n\n const {\n taskID,\n changeStreamer: {mode: changeStreamerMode, uri: changeStreamerURI},\n litestream,\n } = config;\n const runChangeStreamer =\n changeStreamerMode === 'dedicated' && changeStreamerURI === undefined;\n\n let changeStreamer: Worker | undefined;\n\n if (!runChangeStreamer) {\n changeStreamer = undefined;\n if (litestream.executable) {\n // For view-syncers, the backup is restored here. For the replication-manager,\n // the backup is restored in the change-streamer worker.\n await restoreReplica(lc, config, null);\n }\n } else {\n const {promise: changeStreamerReady, resolve: changeStreamerStarted} =\n resolver();\n changeStreamer = loadWorker(CHANGE_STREAMER_URL, 'supporting').once(\n 'message',\n changeStreamerStarted,\n );\n\n // Wait for the change-streamer to be ready to guarantee that a replica\n // file is present.\n await changeStreamerReady;\n\n if (litestream.backupURL) {\n // Start a backup replicator and corresponding litestream backup process.\n const {promise: backupReady, resolve} = resolver();\n const mode: ReplicaFileMode = 'backup';\n loadWorker(REPLICATOR_URL, 'supporting', mode, mode).once(\n // Wait for the Replicator's first message (i.e. \"ready\") before starting\n // litestream backup in order to avoid contending on the lock when the\n // replicator first prepares the db file.\n 'message',\n () => {\n processes.addSubprocess(\n startReplicaBackupProcess(lc, config),\n 'supporting',\n 'litestream',\n );\n resolve();\n },\n );\n await backupReady;\n }\n }\n\n if (numSyncers > 0) {\n const {promise: reaperReady, resolve: reaperStarted} = resolver();\n loadWorker(REAPER_URL, 'supporting').once('message', reaperStarted);\n // Before starting the view-syncers, ensure that the reaper has started\n // up, indicating that any CVR db migrations have been performed.\n await reaperReady;\n }\n\n // Only run the shadow-sync canary on the replication-manager (or in\n // single-node mode, where it also owns upstream). Running on every\n // view-syncer would hammer the upstream with N redundant canaries.\n if (config.shadowSync.enabled && runChangeStreamer) {\n const {promise: shadowReady, resolve: shadowStarted} = resolver();\n loadWorker(SHADOW_SYNCER_URL, 'supporting').once('message', shadowStarted);\n await shadowReady;\n }\n\n const syncers: Worker[] = [];\n if (numSyncers) {\n const mode: ReplicaFileMode =\n runChangeStreamer && litestream.backupURL ? 'serving-copy' : 'serving';\n const {promise: replicaReady, resolve} = resolver();\n const replicator = loadWorker(\n REPLICATOR_URL,\n 'supporting',\n mode,\n mode,\n ).once('message', () => {\n subscribeTo(lc, replicator);\n resolve();\n });\n await replicaReady;\n\n const notifier = createNotifierFrom(lc, replicator);\n for (let i = 0; i < numSyncers; i++) {\n syncers.push(loadWorker(SYNCER_URL, 'user-facing', i, mode, String(i)));\n }\n syncers.forEach(syncer => handleSubscriptionsFrom(lc, syncer, notifier));\n }\n let mutator: Worker | undefined;\n if (clientConnectionBifurcated) {\n mutator = loadWorker(MUTATOR_URL, 'supporting', 'mutator');\n }\n\n lc.info?.('waiting for workers to be ready ...');\n const logWaiting = setInterval(\n () => lc.info?.(`still waiting for ${processes.initializing().join(', ')}`),\n 10_000,\n );\n await processes.allWorkersReady();\n clearInterval(logWaiting);\n lc.info?.(`all workers ready (${Date.now() - startMs} ms)`);\n\n parent.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent,\n new WorkerDispatcher(\n lc,\n taskID,\n parent,\n syncers,\n mutator,\n changeStreamer,\n ),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'dispatcher');\n }\n\n await processes.done();\n}\n\nif (!singleProcessMode()) {\n void exitAfter(lc, () => runWorker(must(parentWorker), process.env));\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mutator.js","names":[],"sources":["../../../../../zero-cache/src/server/mutator.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {must} from '../../../shared/src/must.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {Mutator} from '../workers/mutator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nfunction runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n startOtelAuto(createLogContext(config, 'mutator', 0, false), 'mutator', 0);\n lc = createLogContext(config, 'mutator');\n initEventSink(lc, config);\n\n // TODO: create `PusherFactory`\n return runUntilKilled(lc, parent, new Mutator());\n}\n\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;AAeA,IAAI,KAAK,IAAI,WAAW,QAAQ,CAAC,GAAG,cAAc;AAElD,SAAS,UACP,QACA,KACA,GAAG,MACY;CACf,MAAM,SAAS,wBAAwB;EAAC;EAAK,MAAM,KAAK,MAAM,CAAC;CAAC,CAAC;CACjE,cAAc,iBAAiB,QAAQ,WAAW,GAAG,KAAK,GAAG,WAAW,CAAC;CACzE,KAAK,iBAAiB,QAAQ,SAAS;CACvC,cAAc,IAAI,MAAM;CAGxB,OAAO,eAAe,IAAI,QAAQ,IAAI,QAAQ,CAAC;AACjD;AAEA,IAAI,CAAC,kBAAkB,GACrB,UAAe,UACb,UAAU,KAAK,YAAY,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,CACrE"}
1
+ {"version":3,"file":"mutator.js","names":[],"sources":["../../../../../zero-cache/src/server/mutator.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {must} from '../../../shared/src/must.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {Mutator} from '../workers/mutator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nfunction runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n startOtelAuto(createLogContext(config, 'mutator', 0, false), 'mutator', 0);\n lc = createLogContext(config, 'mutator');\n initEventSink(lc, config);\n\n // TODO: create `PusherFactory`\n return runUntilKilled(lc, parent, new Mutator());\n}\n\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;AAeA,IAAI,KAAK,IAAI,WAAW,QAAQ,EAAE,EAAE,eAAe;AAEnD,SAAS,UACP,QACA,KACA,GAAG,MACY;CACf,MAAM,SAAS,wBAAwB;EAAC;EAAK,MAAM,KAAK,MAAM,EAAE;EAAC,CAAC;AAClE,eAAc,iBAAiB,QAAQ,WAAW,GAAG,MAAM,EAAE,WAAW,EAAE;AAC1E,MAAK,iBAAiB,QAAQ,UAAU;AACxC,eAAc,IAAI,OAAO;AAGzB,QAAO,eAAe,IAAI,QAAQ,IAAI,SAAS,CAAC;;AAGlD,IAAI,CAAC,mBAAmB,CACjB,WAAU,UACb,UAAU,KAAK,aAAa,EAAE,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,EAAE,CAAC,CACrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"otel-diag-logger.js","names":[],"sources":["../../../../../zero-cache/src/server/otel-diag-logger.ts"],"sourcesContent":["import {diag, DiagLogLevel} from '@opentelemetry/api';\nimport type {LogContext} from '@rocicorp/logger';\n\nfunction getOtelLogLevel(level: string | undefined): DiagLogLevel | undefined {\n if (!level) return undefined;\n\n const normalizedLevel = level.toLowerCase();\n switch (normalizedLevel) {\n case 'none':\n return DiagLogLevel.NONE;\n case 'error':\n return DiagLogLevel.ERROR;\n case 'warn':\n case 'warning':\n return DiagLogLevel.WARN;\n case 'info':\n return DiagLogLevel.INFO;\n case 'debug':\n return DiagLogLevel.DEBUG;\n case 'verbose':\n return DiagLogLevel.VERBOSE;\n case 'all':\n return DiagLogLevel.ALL;\n default:\n return undefined;\n }\n}\n\nlet diagLoggerConfigured = false;\n\n/**\n * Sets up the OpenTelemetry diagnostic logger with custom error handling and suppression.\n * This function can be called multiple times safely - it will only configure the logger once per LogContext.\n *\n * @param lc LogContext for routing OTEL diagnostic messages to the application logger\n * @param force If true, will reconfigure even if already configured (useful after NodeSDK setup)\n * @returns true if the logger was configured, false if it was already configured and not forced\n */\nexport function setupOtelDiagnosticLogger(\n lc?: LogContext,\n force = false,\n): boolean {\n if (!lc) {\n return false;\n }\n\n if (!force && diagLoggerConfigured) {\n return false;\n }\n\n const log = lc.withContext('component', 'otel');\n\n // Log level ERROR is reserved for unforced application errors. Since otel\n // errors do not affect application functionality, they are limited to WARN.\n diag.setLogger(\n {\n verbose: (msg: string, ...args: unknown[]) => log.debug?.(msg, ...args),\n debug: (msg: string, ...args: unknown[]) => log.debug?.(msg, ...args),\n info: (msg: string, ...args: unknown[]) => log.info?.(msg, ...args),\n warn: (msg: string, ...args: unknown[]) => log.warn?.(msg, ...args),\n error: (msg: string, ...args: unknown[]) => log.warn?.(msg, ...args),\n },\n {\n logLevel:\n getOtelLogLevel(process.env.OTEL_LOG_LEVEL) ?? DiagLogLevel.ERROR,\n suppressOverrideMessage: true,\n },\n );\n\n diagLoggerConfigured = true;\n return true;\n}\n\n/**\n * Reset the diagnostic logger configuration state.\n * This is primarily useful for testing scenarios.\n */\nexport function resetOtelDiagnosticLogger(): void {\n diagLoggerConfigured = false;\n}\n"],"mappings":";;AAGA,SAAS,gBAAgB,OAAqD;CAC5E,IAAI,CAAC,OAAO,OAAO,KAAA;CAGnB,QADwB,MAAM,YACtB,GAAR;EACE,KAAK,QACH,OAAO,aAAa;EACtB,KAAK,SACH,OAAO,aAAa;EACtB,KAAK;EACL,KAAK,WACH,OAAO,aAAa;EACtB,KAAK,QACH,OAAO,aAAa;EACtB,KAAK,SACH,OAAO,aAAa;EACtB,KAAK,WACH,OAAO,aAAa;EACtB,KAAK,OACH,OAAO,aAAa;EACtB,SACE;CACJ;AACF;AAEA,IAAI,uBAAuB;;;;;;;;;AAU3B,SAAgB,0BACd,IACA,QAAQ,OACC;CACT,IAAI,CAAC,IACH,OAAO;CAGT,IAAI,CAAC,SAAS,sBACZ,OAAO;CAGT,MAAM,MAAM,GAAG,YAAY,aAAa,MAAM;CAI9C,KAAK,UACH;EACE,UAAU,KAAa,GAAG,SAAoB,IAAI,QAAQ,KAAK,GAAG,IAAI;EACtE,QAAQ,KAAa,GAAG,SAAoB,IAAI,QAAQ,KAAK,GAAG,IAAI;EACpE,OAAO,KAAa,GAAG,SAAoB,IAAI,OAAO,KAAK,GAAG,IAAI;EAClE,OAAO,KAAa,GAAG,SAAoB,IAAI,OAAO,KAAK,GAAG,IAAI;EAClE,QAAQ,KAAa,GAAG,SAAoB,IAAI,OAAO,KAAK,GAAG,IAAI;CACrE,GACA;EACE,UACE,gBAAgB,QAAQ,IAAI,cAAc,KAAK,aAAa;EAC9D,yBAAyB;CAC3B,CACF;CAEA,uBAAuB;CACvB,OAAO;AACT"}
1
+ {"version":3,"file":"otel-diag-logger.js","names":[],"sources":["../../../../../zero-cache/src/server/otel-diag-logger.ts"],"sourcesContent":["import {diag, DiagLogLevel} from '@opentelemetry/api';\nimport type {LogContext} from '@rocicorp/logger';\n\nfunction getOtelLogLevel(level: string | undefined): DiagLogLevel | undefined {\n if (!level) return undefined;\n\n const normalizedLevel = level.toLowerCase();\n switch (normalizedLevel) {\n case 'none':\n return DiagLogLevel.NONE;\n case 'error':\n return DiagLogLevel.ERROR;\n case 'warn':\n case 'warning':\n return DiagLogLevel.WARN;\n case 'info':\n return DiagLogLevel.INFO;\n case 'debug':\n return DiagLogLevel.DEBUG;\n case 'verbose':\n return DiagLogLevel.VERBOSE;\n case 'all':\n return DiagLogLevel.ALL;\n default:\n return undefined;\n }\n}\n\nlet diagLoggerConfigured = false;\n\n/**\n * Sets up the OpenTelemetry diagnostic logger with custom error handling and suppression.\n * This function can be called multiple times safely - it will only configure the logger once per LogContext.\n *\n * @param lc LogContext for routing OTEL diagnostic messages to the application logger\n * @param force If true, will reconfigure even if already configured (useful after NodeSDK setup)\n * @returns true if the logger was configured, false if it was already configured and not forced\n */\nexport function setupOtelDiagnosticLogger(\n lc?: LogContext,\n force = false,\n): boolean {\n if (!lc) {\n return false;\n }\n\n if (!force && diagLoggerConfigured) {\n return false;\n }\n\n const log = lc.withContext('component', 'otel');\n\n // Log level ERROR is reserved for unforced application errors. Since otel\n // errors do not affect application functionality, they are limited to WARN.\n diag.setLogger(\n {\n verbose: (msg: string, ...args: unknown[]) => log.debug?.(msg, ...args),\n debug: (msg: string, ...args: unknown[]) => log.debug?.(msg, ...args),\n info: (msg: string, ...args: unknown[]) => log.info?.(msg, ...args),\n warn: (msg: string, ...args: unknown[]) => log.warn?.(msg, ...args),\n error: (msg: string, ...args: unknown[]) => log.warn?.(msg, ...args),\n },\n {\n logLevel:\n getOtelLogLevel(process.env.OTEL_LOG_LEVEL) ?? DiagLogLevel.ERROR,\n suppressOverrideMessage: true,\n },\n );\n\n diagLoggerConfigured = true;\n return true;\n}\n\n/**\n * Reset the diagnostic logger configuration state.\n * This is primarily useful for testing scenarios.\n */\nexport function resetOtelDiagnosticLogger(): void {\n diagLoggerConfigured = false;\n}\n"],"mappings":";;AAGA,SAAS,gBAAgB,OAAqD;AAC5E,KAAI,CAAC,MAAO,QAAO,KAAA;AAGnB,SADwB,MAAM,aAAa,EAC3C;EACE,KAAK,OACH,QAAO,aAAa;EACtB,KAAK,QACH,QAAO,aAAa;EACtB,KAAK;EACL,KAAK,UACH,QAAO,aAAa;EACtB,KAAK,OACH,QAAO,aAAa;EACtB,KAAK,QACH,QAAO,aAAa;EACtB,KAAK,UACH,QAAO,aAAa;EACtB,KAAK,MACH,QAAO,aAAa;EACtB,QACE;;;AAIN,IAAI,uBAAuB;;;;;;;;;AAU3B,SAAgB,0BACd,IACA,QAAQ,OACC;AACT,KAAI,CAAC,GACH,QAAO;AAGT,KAAI,CAAC,SAAS,qBACZ,QAAO;CAGT,MAAM,MAAM,GAAG,YAAY,aAAa,OAAO;AAI/C,MAAK,UACH;EACE,UAAU,KAAa,GAAG,SAAoB,IAAI,QAAQ,KAAK,GAAG,KAAK;EACvE,QAAQ,KAAa,GAAG,SAAoB,IAAI,QAAQ,KAAK,GAAG,KAAK;EACrE,OAAO,KAAa,GAAG,SAAoB,IAAI,OAAO,KAAK,GAAG,KAAK;EACnE,OAAO,KAAa,GAAG,SAAoB,IAAI,OAAO,KAAK,GAAG,KAAK;EACnE,QAAQ,KAAa,GAAG,SAAoB,IAAI,OAAO,KAAK,GAAG,KAAK;EACrE,EACD;EACE,UACE,gBAAgB,QAAQ,IAAI,eAAe,IAAI,aAAa;EAC9D,yBAAyB;EAC1B,CACF;AAED,wBAAuB;AACvB,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"otel-log-sink.js","names":["#logger"],"sources":["../../../../../zero-cache/src/server/otel-log-sink.ts"],"sourcesContent":["import {\n logs,\n SeverityNumber,\n type AnyValueMap,\n type Logger,\n type LogRecord,\n} from '@opentelemetry/api-logs';\nimport type {Context, LogLevel, LogSink} from '@rocicorp/logger';\nimport {stringify} from '../../../shared/src/bigint-json.ts';\nimport {errorOrObject} from '../../../shared/src/logging.ts';\n\nexport class OtelLogSink implements LogSink {\n readonly #logger: Logger;\n\n constructor() {\n this.#logger = logs.getLogger('zero-cache');\n }\n\n log(level: LogLevel, context: Context | undefined, ...args: unknown[]): void {\n const lastObj = errorOrObject(args.at(-1));\n if (lastObj) {\n args.pop();\n }\n\n let message = args.length\n ? args.map(s => (typeof s === 'string' ? s : stringify(s))).join(' ')\n : '';\n\n if (lastObj) {\n message += ` ${stringify(lastObj)}`;\n }\n\n const payload: LogRecord = {\n severityText: level,\n severityNumber: toErrorNum(level),\n body: message,\n };\n if (context) {\n payload.attributes = context as AnyValueMap;\n }\n this.#logger.emit(payload);\n }\n}\n\nfunction toErrorNum(level: LogLevel): SeverityNumber {\n switch (level) {\n case 'error':\n return SeverityNumber.ERROR;\n case 'warn':\n return SeverityNumber.WARN;\n case 'info':\n return SeverityNumber.INFO;\n case 'debug':\n return SeverityNumber.DEBUG;\n default:\n throw new Error(`Unknown log level: ${level}`);\n }\n}\n"],"mappings":";;;;AAWA,IAAa,cAAb,MAA4C;CAC1C;CAEA,cAAc;EACZ,KAAKA,UAAU,KAAK,UAAU,YAAY;CAC5C;CAEA,IAAI,OAAiB,SAA8B,GAAG,MAAuB;EAC3E,MAAM,UAAU,cAAc,KAAK,GAAG,EAAE,CAAC;EACzC,IAAI,SACF,KAAK,IAAI;EAGX,IAAI,UAAU,KAAK,SACf,KAAK,KAAI,MAAM,OAAO,MAAM,WAAW,IAAI,UAAU,CAAC,CAAE,EAAE,KAAK,GAAG,IAClE;EAEJ,IAAI,SACF,WAAW,IAAI,UAAU,OAAO;EAGlC,MAAM,UAAqB;GACzB,cAAc;GACd,gBAAgB,WAAW,KAAK;GAChC,MAAM;EACR;EACA,IAAI,SACF,QAAQ,aAAa;EAEvB,KAAKA,QAAQ,KAAK,OAAO;CAC3B;AACF;AAEA,SAAS,WAAW,OAAiC;CACnD,QAAQ,OAAR;EACE,KAAK,SACH,OAAO,eAAe;EACxB,KAAK,QACH,OAAO,eAAe;EACxB,KAAK,QACH,OAAO,eAAe;EACxB,KAAK,SACH,OAAO,eAAe;EACxB,SACE,MAAM,IAAI,MAAM,sBAAsB,OAAO;CACjD;AACF"}
1
+ {"version":3,"file":"otel-log-sink.js","names":["#logger"],"sources":["../../../../../zero-cache/src/server/otel-log-sink.ts"],"sourcesContent":["import {\n logs,\n SeverityNumber,\n type AnyValueMap,\n type Logger,\n type LogRecord,\n} from '@opentelemetry/api-logs';\nimport type {Context, LogLevel, LogSink} from '@rocicorp/logger';\nimport {stringify} from '../../../shared/src/bigint-json.ts';\nimport {errorOrObject} from '../../../shared/src/logging.ts';\n\nexport class OtelLogSink implements LogSink {\n readonly #logger: Logger;\n\n constructor() {\n this.#logger = logs.getLogger('zero-cache');\n }\n\n log(level: LogLevel, context: Context | undefined, ...args: unknown[]): void {\n const lastObj = errorOrObject(args.at(-1));\n if (lastObj) {\n args.pop();\n }\n\n let message = args.length\n ? args.map(s => (typeof s === 'string' ? s : stringify(s))).join(' ')\n : '';\n\n if (lastObj) {\n message += ` ${stringify(lastObj)}`;\n }\n\n const payload: LogRecord = {\n severityText: level,\n severityNumber: toErrorNum(level),\n body: message,\n };\n if (context) {\n payload.attributes = context as AnyValueMap;\n }\n this.#logger.emit(payload);\n }\n}\n\nfunction toErrorNum(level: LogLevel): SeverityNumber {\n switch (level) {\n case 'error':\n return SeverityNumber.ERROR;\n case 'warn':\n return SeverityNumber.WARN;\n case 'info':\n return SeverityNumber.INFO;\n case 'debug':\n return SeverityNumber.DEBUG;\n default:\n throw new Error(`Unknown log level: ${level}`);\n }\n}\n"],"mappings":";;;;AAWA,IAAa,cAAb,MAA4C;CAC1C;CAEA,cAAc;AACZ,QAAA,SAAe,KAAK,UAAU,aAAa;;CAG7C,IAAI,OAAiB,SAA8B,GAAG,MAAuB;EAC3E,MAAM,UAAU,cAAc,KAAK,GAAG,GAAG,CAAC;AAC1C,MAAI,QACF,MAAK,KAAK;EAGZ,IAAI,UAAU,KAAK,SACf,KAAK,KAAI,MAAM,OAAO,MAAM,WAAW,IAAI,UAAU,EAAE,CAAE,CAAC,KAAK,IAAI,GACnE;AAEJ,MAAI,QACF,YAAW,IAAI,UAAU,QAAQ;EAGnC,MAAM,UAAqB;GACzB,cAAc;GACd,gBAAgB,WAAW,MAAM;GACjC,MAAM;GACP;AACD,MAAI,QACF,SAAQ,aAAa;AAEvB,QAAA,OAAa,KAAK,QAAQ;;;AAI9B,SAAS,WAAW,OAAiC;AACnD,SAAQ,OAAR;EACE,KAAK,QACH,QAAO,eAAe;EACxB,KAAK,OACH,QAAO,eAAe;EACxB,KAAK,OACH,QAAO,eAAe;EACxB,KAAK,QACH,QAAO,eAAe;EACxB,QACE,OAAM,IAAI,MAAM,sBAAsB,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"otel-start.js","names":["#instance","#started"],"sources":["../../../../../zero-cache/src/server/otel-start.ts"],"sourcesContent":["import {logs} from '@opentelemetry/api-logs';\nimport {getNodeAutoInstrumentations} from '@opentelemetry/auto-instrumentations-node';\nimport {resourceFromAttributes} from '@opentelemetry/resources';\nimport {NodeSDK} from '@opentelemetry/sdk-node';\nimport {ATTR_SERVICE_VERSION} from '@opentelemetry/semantic-conventions';\nimport type {LogContext} from '@rocicorp/logger';\nimport {\n otelEnabled,\n otelLogsEnabled,\n otelMetricsEnabled,\n otelTracesEnabled,\n} from '../../../otel/src/enabled.ts';\nimport {setupOtelDiagnosticLogger} from './otel-diag-logger.ts';\n\nclass OtelManager {\n static #instance: OtelManager;\n #started = false;\n\n private constructor() {}\n\n static getInstance(): OtelManager {\n if (!OtelManager.#instance) {\n OtelManager.#instance = new OtelManager();\n }\n return OtelManager.#instance;\n }\n\n startOtelAuto(\n lc: LogContext | undefined,\n workerName: string,\n workerIndex: number,\n ) {\n if (this.#started || !otelEnabled()) {\n return;\n }\n this.#started = true;\n\n // Store and temporarily remove OTEL_LOG_LEVEL to prevent NodeSDK from setting its own logger\n const otelLogLevel = process.env.OTEL_LOG_LEVEL;\n delete process.env.OTEL_LOG_LEVEL;\n\n // Use exponential histograms by default to reduce cardinality from auto-instrumentation\n // This affects HTTP server/client and other auto-instrumented histogram metrics\n // Exponential histograms automatically adjust bucket boundaries and use fewer buckets\n process.env.OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION ??=\n 'base2_exponential_bucket_histogram';\n\n const resource = resourceFromAttributes({\n [ATTR_SERVICE_VERSION]: process.env.ZERO_SERVER_VERSION ?? 'unknown',\n // Tag every metric/trace/log with the worker name and index so each\n // worker process in a multi-worker pod is distinguishable. Without\n // this, N syncer workers sharing the same pod labels clobber each\n // other in the OTel collector on every scrape interval.\n // These mirror the 'worker' and 'workerIndex' keys in every log\n // context so logs and metrics can be correlated on the same fields.\n // Using a stable index instead of PID avoids label churn in Prometheus.\n 'process.worker': workerName,\n 'process.worker_index': workerIndex,\n });\n\n // Set defaults to be backwards compatible with the previously\n // hard-coded exporters\n process.env.OTEL_EXPORTER_OTLP_PROTOCOL ??= 'http/json';\n process.env.OTEL_METRICS_EXPORTER ??= otelMetricsEnabled()\n ? 'otlp'\n : 'none';\n process.env.OTEL_TRACES_EXPORTER ??= otelTracesEnabled() ? 'otlp' : 'none';\n process.env.OTEL_LOGS_EXPORTER ??= otelLogsEnabled() ? 'otlp' : 'none';\n\n const sdk = new NodeSDK({\n resource,\n autoDetectResources: true,\n instrumentations:\n process.env.OTEL_NODE_ENABLED_INSTRUMENTATIONS ||\n process.env.OTEL_NODE_DISABLED_INSTRUMENTATIONS\n ? [getNodeAutoInstrumentations()]\n : [],\n });\n\n try {\n sdk.start();\n } finally {\n if (otelLogLevel) {\n process.env.OTEL_LOG_LEVEL = otelLogLevel;\n }\n }\n setupOtelDiagnosticLogger(lc, true);\n\n logs.getLogger('zero-cache').emit({\n severityText: 'INFO',\n body: 'OpenTelemetry SDK started successfully',\n });\n }\n}\n\nexport const startOtelAuto = (\n lc: LogContext | undefined,\n workerName: string,\n workerIndex: number,\n) => OtelManager.getInstance().startOtelAuto(lc, workerName, workerIndex);\n"],"mappings":";;;;;;;;AAcA,IAAM,cAAN,MAAM,YAAY;CAChB,OAAOA;CACP,WAAW;CAEX,cAAsB,CAAC;CAEvB,OAAO,cAA2B;EAChC,IAAI,CAAC,YAAYA,WACf,YAAYA,YAAY,IAAI,YAAY;EAE1C,OAAO,YAAYA;CACrB;CAEA,cACE,IACA,YACA,aACA;EACA,IAAI,KAAKC,YAAY,CAAC,YAAY,GAChC;EAEF,KAAKA,WAAW;EAGhB,MAAM,eAAe,QAAQ,IAAI;EACjC,OAAO,QAAQ,IAAI;EAKnB,QAAQ,IAAI,6DACV;EAEF,MAAM,WAAW,uBAAuB;IACrC,uBAAuB,QAAQ,IAAI,uBAAuB;GAQ3D,kBAAkB;GAClB,wBAAwB;EAC1B,CAAC;EAID,QAAQ,IAAI,gCAAgC;EAC5C,QAAQ,IAAI,0BAA0B,mBAAmB,IACrD,SACA;EACJ,QAAQ,IAAI,yBAAyB,kBAAkB,IAAI,SAAS;EACpE,QAAQ,IAAI,uBAAuB,gBAAgB,IAAI,SAAS;EAEhE,MAAM,MAAM,IAAI,QAAQ;GACtB;GACA,qBAAqB;GACrB,kBACE,QAAQ,IAAI,sCACZ,QAAQ,IAAI,sCACR,CAAC,4BAA4B,CAAC,IAC9B,CAAC;EACT,CAAC;EAED,IAAI;GACF,IAAI,MAAM;EACZ,UAAU;GACR,IAAI,cACF,QAAQ,IAAI,iBAAiB;EAEjC;EACA,0BAA0B,IAAI,IAAI;EAElC,KAAK,UAAU,YAAY,EAAE,KAAK;GAChC,cAAc;GACd,MAAM;EACR,CAAC;CACH;AACF;AAEA,IAAa,iBACX,IACA,YACA,gBACG,YAAY,YAAY,EAAE,cAAc,IAAI,YAAY,WAAW"}
1
+ {"version":3,"file":"otel-start.js","names":["#instance","#started"],"sources":["../../../../../zero-cache/src/server/otel-start.ts"],"sourcesContent":["import {logs} from '@opentelemetry/api-logs';\nimport {getNodeAutoInstrumentations} from '@opentelemetry/auto-instrumentations-node';\nimport {resourceFromAttributes} from '@opentelemetry/resources';\nimport {NodeSDK} from '@opentelemetry/sdk-node';\nimport {ATTR_SERVICE_VERSION} from '@opentelemetry/semantic-conventions';\nimport type {LogContext} from '@rocicorp/logger';\nimport {\n otelEnabled,\n otelLogsEnabled,\n otelMetricsEnabled,\n otelTracesEnabled,\n} from '../../../otel/src/enabled.ts';\nimport {setupOtelDiagnosticLogger} from './otel-diag-logger.ts';\n\nclass OtelManager {\n static #instance: OtelManager;\n #started = false;\n\n private constructor() {}\n\n static getInstance(): OtelManager {\n if (!OtelManager.#instance) {\n OtelManager.#instance = new OtelManager();\n }\n return OtelManager.#instance;\n }\n\n startOtelAuto(\n lc: LogContext | undefined,\n workerName: string,\n workerIndex: number,\n ) {\n if (this.#started || !otelEnabled()) {\n return;\n }\n this.#started = true;\n\n // Store and temporarily remove OTEL_LOG_LEVEL to prevent NodeSDK from setting its own logger\n const otelLogLevel = process.env.OTEL_LOG_LEVEL;\n delete process.env.OTEL_LOG_LEVEL;\n\n // Use exponential histograms by default to reduce cardinality from auto-instrumentation\n // This affects HTTP server/client and other auto-instrumented histogram metrics\n // Exponential histograms automatically adjust bucket boundaries and use fewer buckets\n process.env.OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION ??=\n 'base2_exponential_bucket_histogram';\n\n const resource = resourceFromAttributes({\n [ATTR_SERVICE_VERSION]: process.env.ZERO_SERVER_VERSION ?? 'unknown',\n // Tag every metric/trace/log with the worker name and index so each\n // worker process in a multi-worker pod is distinguishable. Without\n // this, N syncer workers sharing the same pod labels clobber each\n // other in the OTel collector on every scrape interval.\n // These mirror the 'worker' and 'workerIndex' keys in every log\n // context so logs and metrics can be correlated on the same fields.\n // Using a stable index instead of PID avoids label churn in Prometheus.\n 'process.worker': workerName,\n 'process.worker_index': workerIndex,\n });\n\n // Set defaults to be backwards compatible with the previously\n // hard-coded exporters\n process.env.OTEL_EXPORTER_OTLP_PROTOCOL ??= 'http/json';\n process.env.OTEL_METRICS_EXPORTER ??= otelMetricsEnabled()\n ? 'otlp'\n : 'none';\n process.env.OTEL_TRACES_EXPORTER ??= otelTracesEnabled() ? 'otlp' : 'none';\n process.env.OTEL_LOGS_EXPORTER ??= otelLogsEnabled() ? 'otlp' : 'none';\n\n const sdk = new NodeSDK({\n resource,\n autoDetectResources: true,\n instrumentations:\n process.env.OTEL_NODE_ENABLED_INSTRUMENTATIONS ||\n process.env.OTEL_NODE_DISABLED_INSTRUMENTATIONS\n ? [getNodeAutoInstrumentations()]\n : [],\n });\n\n try {\n sdk.start();\n } finally {\n if (otelLogLevel) {\n process.env.OTEL_LOG_LEVEL = otelLogLevel;\n }\n }\n setupOtelDiagnosticLogger(lc, true);\n\n logs.getLogger('zero-cache').emit({\n severityText: 'INFO',\n body: 'OpenTelemetry SDK started successfully',\n });\n }\n}\n\nexport const startOtelAuto = (\n lc: LogContext | undefined,\n workerName: string,\n workerIndex: number,\n) => OtelManager.getInstance().startOtelAuto(lc, workerName, workerIndex);\n"],"mappings":";;;;;;;;AAcA,IAAM,cAAN,MAAM,YAAY;CAChB,QAAA;CACA,WAAW;CAEX,cAAsB;CAEtB,OAAO,cAA2B;AAChC,MAAI,CAAC,aAAA,SACH,cAAA,WAAwB,IAAI,aAAa;AAE3C,SAAO,aAAA;;CAGT,cACE,IACA,YACA,aACA;AACA,MAAI,MAAA,WAAiB,CAAC,aAAa,CACjC;AAEF,QAAA,UAAgB;EAGhB,MAAM,eAAe,QAAQ,IAAI;AACjC,SAAO,QAAQ,IAAI;AAKnB,UAAQ,IAAI,6DACV;EAEF,MAAM,WAAW,uBAAuB;IACrC,uBAAuB,QAAQ,IAAI,uBAAuB;GAQ3D,kBAAkB;GAClB,wBAAwB;GACzB,CAAC;AAIF,UAAQ,IAAI,gCAAgC;AAC5C,UAAQ,IAAI,0BAA0B,oBAAoB,GACtD,SACA;AACJ,UAAQ,IAAI,yBAAyB,mBAAmB,GAAG,SAAS;AACpE,UAAQ,IAAI,uBAAuB,iBAAiB,GAAG,SAAS;EAEhE,MAAM,MAAM,IAAI,QAAQ;GACtB;GACA,qBAAqB;GACrB,kBACE,QAAQ,IAAI,sCACZ,QAAQ,IAAI,sCACR,CAAC,6BAA6B,CAAC,GAC/B,EAAE;GACT,CAAC;AAEF,MAAI;AACF,OAAI,OAAO;YACH;AACR,OAAI,aACF,SAAQ,IAAI,iBAAiB;;AAGjC,4BAA0B,IAAI,KAAK;AAEnC,OAAK,UAAU,aAAa,CAAC,KAAK;GAChC,cAAc;GACd,MAAM;GACP,CAAC;;;AAIN,IAAa,iBACX,IACA,YACA,gBACG,YAAY,aAAa,CAAC,cAAc,IAAI,YAAY,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"priority-op.js","names":[],"sources":["../../../../../zero-cache/src/server/priority-op.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\n\nlet priorityOpCounter = 0;\nlet runningPriorityOpCounter = 0;\n\n/**\n * Run an operation with priority, indicating that IVM should use smaller time\n * slices to allow this operation to proceed more quickly\n */\nexport async function runPriorityOp<T>(\n lc: LogContext,\n description: string,\n op: () => Promise<T>,\n) {\n const id = priorityOpCounter++;\n runningPriorityOpCounter++;\n const start = Date.now();\n lc = lc.withContext('priorityOpID', id);\n try {\n lc.debug?.(`running priority op ${description}`);\n const result = await op();\n lc.debug?.(\n `finished priority op ${description} in ${Date.now() - start} ms`,\n );\n return result;\n } catch (e) {\n lc.debug?.(`failed priority op ${description} in ${Date.now() - start} ms`);\n throw e;\n } finally {\n runningPriorityOpCounter--;\n }\n}\n\nexport function isPriorityOpRunning() {\n return runningPriorityOpCounter > 0;\n}\n"],"mappings":";AAEA,IAAI,oBAAoB;AACxB,IAAI,2BAA2B;;;;;AAM/B,eAAsB,cACpB,IACA,aACA,IACA;CACA,MAAM,KAAK;CACX;CACA,MAAM,QAAQ,KAAK,IAAI;CACvB,KAAK,GAAG,YAAY,gBAAgB,EAAE;CACtC,IAAI;EACF,GAAG,QAAQ,uBAAuB,aAAa;EAC/C,MAAM,SAAS,MAAM,GAAG;EACxB,GAAG,QACD,wBAAwB,YAAY,MAAM,KAAK,IAAI,IAAI,MAAM,IAC/D;EACA,OAAO;CACT,SAAS,GAAG;EACV,GAAG,QAAQ,sBAAsB,YAAY,MAAM,KAAK,IAAI,IAAI,MAAM,IAAI;EAC1E,MAAM;CACR,UAAU;EACR;CACF;AACF;AAEA,SAAgB,sBAAsB;CACpC,OAAO,2BAA2B;AACpC"}
1
+ {"version":3,"file":"priority-op.js","names":[],"sources":["../../../../../zero-cache/src/server/priority-op.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\n\nlet priorityOpCounter = 0;\nlet runningPriorityOpCounter = 0;\n\n/**\n * Run an operation with priority, indicating that IVM should use smaller time\n * slices to allow this operation to proceed more quickly\n */\nexport async function runPriorityOp<T>(\n lc: LogContext,\n description: string,\n op: () => Promise<T>,\n) {\n const id = priorityOpCounter++;\n runningPriorityOpCounter++;\n const start = Date.now();\n lc = lc.withContext('priorityOpID', id);\n try {\n lc.debug?.(`running priority op ${description}`);\n const result = await op();\n lc.debug?.(\n `finished priority op ${description} in ${Date.now() - start} ms`,\n );\n return result;\n } catch (e) {\n lc.debug?.(`failed priority op ${description} in ${Date.now() - start} ms`);\n throw e;\n } finally {\n runningPriorityOpCounter--;\n }\n}\n\nexport function isPriorityOpRunning() {\n return runningPriorityOpCounter > 0;\n}\n"],"mappings":";AAEA,IAAI,oBAAoB;AACxB,IAAI,2BAA2B;;;;;AAM/B,eAAsB,cACpB,IACA,aACA,IACA;CACA,MAAM,KAAK;AACX;CACA,MAAM,QAAQ,KAAK,KAAK;AACxB,MAAK,GAAG,YAAY,gBAAgB,GAAG;AACvC,KAAI;AACF,KAAG,QAAQ,uBAAuB,cAAc;EAChD,MAAM,SAAS,MAAM,IAAI;AACzB,KAAG,QACD,wBAAwB,YAAY,MAAM,KAAK,KAAK,GAAG,MAAM,KAC9D;AACD,SAAO;UACA,GAAG;AACV,KAAG,QAAQ,sBAAsB,YAAY,MAAM,KAAK,KAAK,GAAG,MAAM,KAAK;AAC3E,QAAM;WACE;AACR;;;AAIJ,SAAgB,sBAAsB;AACpC,QAAO,2BAA2B"}
@@ -1 +1 @@
1
- {"version":3,"file":"reaper.js","names":[],"sources":["../../../../../zero-cache/src/server/reaper.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {must} from '../../../shared/src/must.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {ActiveUsersGauge} from '../services/view-syncer/active-users-gauge.ts';\nimport {CVRPurger} from '../services/view-syncer/cvr-purger.ts';\nimport {initViewSyncerSchema} from '../services/view-syncer/schema/init.ts';\nimport {connectPgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardID} from '../types/shards.ts';\nimport {startAnonymousTelemetry} from './anonymous-otel-start.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\nconst MS_PER_HOUR = 1000 * 60 * 60;\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...argv: string[]\n): Promise<void> {\n const config = getNormalizedZeroConfig({env, argv});\n\n startOtelAuto(createLogContext(config, 'reaper', 0, false), 'reaper', 0);\n lc = createLogContext(config, 'reaper');\n initEventSink(lc, config);\n startAnonymousTelemetry(lc, config);\n\n const {cvr} = config;\n const shard = getShardID(config);\n const cvrDB = await connectPgClient(lc, cvr.db, `sync-cvr-purger`, {\n max: 1,\n });\n await initViewSyncerSchema(lc, cvrDB, shard);\n parent.send(['ready', {ready: true}]);\n\n return runUntilKilled(\n lc,\n parent,\n new CVRPurger(lc, cvrDB, shard, {\n inactivityThresholdMs:\n cvr.garbageCollectionInactivityThresholdHours * MS_PER_HOUR,\n initialBatchSize: cvr.garbageCollectionInitialBatchSize,\n initialIntervalMs: cvr.garbageCollectionInitialIntervalSeconds * 1000,\n }),\n // Periodically computes and exports active users gauge to anonymous telemetry\n new ActiveUsersGauge(lc, cvrDB, shard, {\n // Default 10minutes refresh; can be made configurable later if needed\n updateIntervalMs: 10 * 60 * 1000,\n }),\n );\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmBA,IAAM,cAAc,MAAO,KAAK;AAGhC,IAAI,KAAK,IAAI,WAAW,QAAQ,CAAC,GAAG,cAAc;AAElD,eAA8B,UAC5B,QACA,KACA,GAAG,MACY;CACf,MAAM,SAAS,wBAAwB;EAAC;EAAK;CAAI,CAAC;CAElD,cAAc,iBAAiB,QAAQ,UAAU,GAAG,KAAK,GAAG,UAAU,CAAC;CACvE,KAAK,iBAAiB,QAAQ,QAAQ;CACtC,cAAc,IAAI,MAAM;CACxB,wBAAwB,IAAI,MAAM;CAElC,MAAM,EAAC,QAAO;CACd,MAAM,QAAQ,WAAW,MAAM;CAC/B,MAAM,QAAQ,MAAM,gBAAgB,IAAI,IAAI,IAAI,mBAAmB,EACjE,KAAK,EACP,CAAC;CACD,MAAM,qBAAqB,IAAI,OAAO,KAAK;CAC3C,OAAO,KAAK,CAAC,SAAS,EAAC,OAAO,KAAI,CAAC,CAAC;CAEpC,OAAO,eACL,IACA,QACA,IAAI,UAAU,IAAI,OAAO,OAAO;EAC9B,uBACE,IAAI,4CAA4C;EAClD,kBAAkB,IAAI;EACtB,mBAAmB,IAAI,0CAA0C;CACnE,CAAC,GAED,IAAI,iBAAiB,IAAI,OAAO,OAAO,EAErC,kBAAkB,MAAU,IAC9B,CAAC,CACH;AACF;AAGA,IAAI,CAAC,kBAAkB,GACrB,UAAe,UACb,UAAU,KAAK,YAAY,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,CACrE"}
1
+ {"version":3,"file":"reaper.js","names":[],"sources":["../../../../../zero-cache/src/server/reaper.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {must} from '../../../shared/src/must.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {ActiveUsersGauge} from '../services/view-syncer/active-users-gauge.ts';\nimport {CVRPurger} from '../services/view-syncer/cvr-purger.ts';\nimport {initViewSyncerSchema} from '../services/view-syncer/schema/init.ts';\nimport {connectPgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardID} from '../types/shards.ts';\nimport {startAnonymousTelemetry} from './anonymous-otel-start.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\nconst MS_PER_HOUR = 1000 * 60 * 60;\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...argv: string[]\n): Promise<void> {\n const config = getNormalizedZeroConfig({env, argv});\n\n startOtelAuto(createLogContext(config, 'reaper', 0, false), 'reaper', 0);\n lc = createLogContext(config, 'reaper');\n initEventSink(lc, config);\n startAnonymousTelemetry(lc, config);\n\n const {cvr} = config;\n const shard = getShardID(config);\n const cvrDB = await connectPgClient(lc, cvr.db, `sync-cvr-purger`, {\n max: 1,\n });\n await initViewSyncerSchema(lc, cvrDB, shard);\n parent.send(['ready', {ready: true}]);\n\n return runUntilKilled(\n lc,\n parent,\n new CVRPurger(lc, cvrDB, shard, {\n inactivityThresholdMs:\n cvr.garbageCollectionInactivityThresholdHours * MS_PER_HOUR,\n initialBatchSize: cvr.garbageCollectionInitialBatchSize,\n initialIntervalMs: cvr.garbageCollectionInitialIntervalSeconds * 1000,\n }),\n // Periodically computes and exports active users gauge to anonymous telemetry\n new ActiveUsersGauge(lc, cvrDB, shard, {\n // Default 10minutes refresh; can be made configurable later if needed\n updateIntervalMs: 10 * 60 * 1000,\n }),\n );\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmBA,IAAM,cAAc,MAAO,KAAK;AAGhC,IAAI,KAAK,IAAI,WAAW,QAAQ,EAAE,EAAE,eAAe;AAEnD,eAA8B,UAC5B,QACA,KACA,GAAG,MACY;CACf,MAAM,SAAS,wBAAwB;EAAC;EAAK;EAAK,CAAC;AAEnD,eAAc,iBAAiB,QAAQ,UAAU,GAAG,MAAM,EAAE,UAAU,EAAE;AACxE,MAAK,iBAAiB,QAAQ,SAAS;AACvC,eAAc,IAAI,OAAO;AACzB,yBAAwB,IAAI,OAAO;CAEnC,MAAM,EAAC,QAAO;CACd,MAAM,QAAQ,WAAW,OAAO;CAChC,MAAM,QAAQ,MAAM,gBAAgB,IAAI,IAAI,IAAI,mBAAmB,EACjE,KAAK,GACN,CAAC;AACF,OAAM,qBAAqB,IAAI,OAAO,MAAM;AAC5C,QAAO,KAAK,CAAC,SAAS,EAAC,OAAO,MAAK,CAAC,CAAC;AAErC,QAAO,eACL,IACA,QACA,IAAI,UAAU,IAAI,OAAO,OAAO;EAC9B,uBACE,IAAI,4CAA4C;EAClD,kBAAkB,IAAI;EACtB,mBAAmB,IAAI,0CAA0C;EAClE,CAAC,EAEF,IAAI,iBAAiB,IAAI,OAAO,OAAO,EAErC,kBAAkB,MAAU,KAC7B,CAAC,CACH;;AAIH,IAAI,CAAC,mBAAmB,CACjB,WAAU,UACb,UAAU,KAAK,aAAa,EAAE,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,EAAE,CAAC,CACrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"replicator.js","names":[],"sources":["../../../../../zero-cache/src/server/replicator.ts"],"sourcesContent":["import {stat} from 'node:fs/promises';\nimport {pid} from 'node:process';\nimport type {ObservableCallback} from '@opentelemetry/api';\nimport {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {getOrCreateGauge} from '../observability/metrics.ts';\nimport {ChangeStreamerHttpClient} from '../services/change-streamer/change-streamer-http.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {ReplicationStatusPublisher} from '../services/replicator/replication-status.ts';\nimport {\n ReplicatorService,\n type ReplicatorMode,\n} from '../services/replicator/replicator.ts';\nimport {ThreadWriteWorkerClient} from '../services/replicator/write-worker-client.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {\n getPragmaConfig,\n replicaFileModeSchema,\n setUpMessageHandlers,\n setupReplica,\n type WalMode,\n} from '../workers/replicator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n assert(args.length > 0, `replicator mode not specified`);\n const fileMode = v.parse(args[0], replicaFileModeSchema);\n\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n const mode: ReplicatorMode = fileMode === 'backup' ? 'backup' : 'serving';\n const workerName = `${mode}-replicator`;\n startOtelAuto(createLogContext(config, workerName, 0, false), workerName, 0);\n lc = createLogContext(config, workerName);\n initEventSink(lc, config);\n\n const {file: dbPath, walMode} = await setupReplica(\n lc,\n fileMode,\n config.replica,\n );\n\n setupMetrics(lc, dbPath, walMode);\n\n // Create the write worker for async SQLite writes.\n const pragmas = getPragmaConfig(fileMode);\n const workerClient = new ThreadWriteWorkerClient();\n await workerClient.init(dbPath, mode, pragmas, config.log);\n\n const runningLocalChangeStreamer =\n config.changeStreamer.mode === 'dedicated' && !config.changeStreamer.uri;\n const shard = getShardConfig(config);\n const {\n taskID,\n change,\n changeStreamer: {\n port,\n uri: changeStreamerURI = runningLocalChangeStreamer\n ? `http://localhost:${port}/`\n : undefined,\n },\n } = config;\n const changeStreamer = new ChangeStreamerHttpClient(\n lc,\n shard,\n change.db,\n changeStreamerURI,\n );\n\n const replicator = new ReplicatorService(\n lc,\n taskID,\n `${workerName}-${pid}`,\n mode,\n changeStreamer,\n workerClient,\n runningLocalChangeStreamer\n ? // publish ReplicationStatusEvents from backup-replicator only\n ReplicationStatusPublisher.forReplicaFile(dbPath)\n : null,\n );\n\n setUpMessageHandlers(lc, replicator, parent);\n\n const running = runUntilKilled(lc, parent, replicator);\n\n // Signal readiness once the first ReplicaVersionReady notification is received.\n for await (const _ of replicator.subscribe()) {\n parent.send(['ready', {ready: true}]);\n break;\n }\n\n return running;\n}\n\nfunction setupMetrics(lc: LogContext, file: string, walMode: WalMode) {\n getOrCreateGauge('replica', 'db_size', {\n description:\n `The size of the replica's main db file, ` +\n `which does not include the wal file(s)`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, file));\n\n getOrCreateGauge('replica', 'wal_size', {\n description: `The size of the replica's wal file`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, `${file}-wal`));\n\n if (walMode === 'wal2') {\n getOrCreateGauge('replica', 'wal2_size', {\n description: `The size of the replica's wal2 file`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, `${file}-wal2`));\n }\n}\n\nfunction observeFileSize(lc: LogContext, file: string): ObservableCallback {\n return async o => {\n try {\n const stats = await stat(file);\n o.observe(stats.size);\n } catch (e) {\n lc.warn?.(`unable to stat ${file} for size metrics`, e);\n }\n };\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAmCA,IAAI,KAAK,IAAI,WAAW,QAAQ,CAAC,GAAG,cAAc;AAElD,eAA8B,UAC5B,QACA,KACA,GAAG,MACY;CACf,OAAO,KAAK,SAAS,GAAG,+BAA+B;CACvD,MAAM,WAAW,MAAQ,KAAK,IAAI,qBAAqB;CAEvD,MAAM,SAAS,wBAAwB;EAAC;EAAK,MAAM,KAAK,MAAM,CAAC;CAAC,CAAC;CACjE,MAAM,OAAuB,aAAa,WAAW,WAAW;CAChE,MAAM,aAAa,GAAG,KAAK;CAC3B,cAAc,iBAAiB,QAAQ,YAAY,GAAG,KAAK,GAAG,YAAY,CAAC;CAC3E,KAAK,iBAAiB,QAAQ,UAAU;CACxC,cAAc,IAAI,MAAM;CAExB,MAAM,EAAC,MAAM,QAAQ,YAAW,MAAM,aACpC,IACA,UACA,OAAO,OACT;CAEA,aAAa,IAAI,QAAQ,OAAO;CAGhC,MAAM,UAAU,gBAAgB,QAAQ;CACxC,MAAM,eAAe,IAAI,wBAAwB;CACjD,MAAM,aAAa,KAAK,QAAQ,MAAM,SAAS,OAAO,GAAG;CAEzD,MAAM,6BACJ,OAAO,eAAe,SAAS,eAAe,CAAC,OAAO,eAAe;CACvE,MAAM,QAAQ,eAAe,MAAM;CACnC,MAAM,EACJ,QACA,QACA,gBAAgB,EACd,MACA,KAAK,oBAAoB,6BACrB,oBAAoB,KAAK,KACzB,KAAA,QAEJ;CACJ,MAAM,iBAAiB,IAAI,yBACzB,IACA,OACA,OAAO,IACP,iBACF;CAEA,MAAM,aAAa,IAAI,kBACrB,IACA,QACA,GAAG,WAAW,GAAG,OACjB,MACA,gBACA,cACA,6BAEI,2BAA2B,eAAe,MAAM,IAChD,IACN;CAEA,qBAAqB,IAAI,YAAY,MAAM;CAE3C,MAAM,UAAU,eAAe,IAAI,QAAQ,UAAU;CAGrD,WAAW,MAAM,KAAK,WAAW,UAAU,GAAG;EAC5C,OAAO,KAAK,CAAC,SAAS,EAAC,OAAO,KAAI,CAAC,CAAC;EACpC;CACF;CAEA,OAAO;AACT;AAEA,SAAS,aAAa,IAAgB,MAAc,SAAkB;CACpE,iBAAiB,WAAW,WAAW;EACrC,aACE;EAEF,MAAM;CACR,CAAC,EAAE,YAAY,gBAAgB,IAAI,IAAI,CAAC;CAExC,iBAAiB,WAAW,YAAY;EACtC,aAAa;EACb,MAAM;CACR,CAAC,EAAE,YAAY,gBAAgB,IAAI,GAAG,KAAK,KAAK,CAAC;CAEjD,IAAI,YAAY,QACd,iBAAiB,WAAW,aAAa;EACvC,aAAa;EACb,MAAM;CACR,CAAC,EAAE,YAAY,gBAAgB,IAAI,GAAG,KAAK,MAAM,CAAC;AAEtD;AAEA,SAAS,gBAAgB,IAAgB,MAAkC;CACzE,OAAO,OAAM,MAAK;EAChB,IAAI;GACF,MAAM,QAAQ,MAAM,KAAK,IAAI;GAC7B,EAAE,QAAQ,MAAM,IAAI;EACtB,SAAS,GAAG;GACV,GAAG,OAAO,kBAAkB,KAAK,oBAAoB,CAAC;EACxD;CACF;AACF;AAGA,IAAI,CAAC,kBAAkB,GACrB,UAAe,UACb,UAAU,KAAK,YAAY,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,CACrE"}
1
+ {"version":3,"file":"replicator.js","names":[],"sources":["../../../../../zero-cache/src/server/replicator.ts"],"sourcesContent":["import {stat} from 'node:fs/promises';\nimport {pid} from 'node:process';\nimport type {ObservableCallback} from '@opentelemetry/api';\nimport {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {getOrCreateGauge} from '../observability/metrics.ts';\nimport {ChangeStreamerHttpClient} from '../services/change-streamer/change-streamer-http.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {ReplicationStatusPublisher} from '../services/replicator/replication-status.ts';\nimport {\n ReplicatorService,\n type ReplicatorMode,\n} from '../services/replicator/replicator.ts';\nimport {ThreadWriteWorkerClient} from '../services/replicator/write-worker-client.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {\n getPragmaConfig,\n replicaFileModeSchema,\n setUpMessageHandlers,\n setupReplica,\n type WalMode,\n} from '../workers/replicator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n assert(args.length > 0, `replicator mode not specified`);\n const fileMode = v.parse(args[0], replicaFileModeSchema);\n\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n const mode: ReplicatorMode = fileMode === 'backup' ? 'backup' : 'serving';\n const workerName = `${mode}-replicator`;\n startOtelAuto(createLogContext(config, workerName, 0, false), workerName, 0);\n lc = createLogContext(config, workerName);\n initEventSink(lc, config);\n\n const {file: dbPath, walMode} = await setupReplica(\n lc,\n fileMode,\n config.replica,\n );\n\n setupMetrics(lc, dbPath, walMode);\n\n // Create the write worker for async SQLite writes.\n const pragmas = getPragmaConfig(fileMode);\n const workerClient = new ThreadWriteWorkerClient();\n await workerClient.init(dbPath, mode, pragmas, config.log);\n\n const runningLocalChangeStreamer =\n config.changeStreamer.mode === 'dedicated' && !config.changeStreamer.uri;\n const shard = getShardConfig(config);\n const {\n taskID,\n change,\n changeStreamer: {\n port,\n uri: changeStreamerURI = runningLocalChangeStreamer\n ? `http://localhost:${port}/`\n : undefined,\n },\n } = config;\n const changeStreamer = new ChangeStreamerHttpClient(\n lc,\n shard,\n change.db,\n changeStreamerURI,\n );\n\n const replicator = new ReplicatorService(\n lc,\n taskID,\n `${workerName}-${pid}`,\n mode,\n changeStreamer,\n workerClient,\n runningLocalChangeStreamer\n ? // publish ReplicationStatusEvents from backup-replicator only\n ReplicationStatusPublisher.forReplicaFile(dbPath)\n : null,\n );\n\n setUpMessageHandlers(lc, replicator, parent);\n\n const running = runUntilKilled(lc, parent, replicator);\n\n // Signal readiness once the first ReplicaVersionReady notification is received.\n for await (const _ of replicator.subscribe()) {\n parent.send(['ready', {ready: true}]);\n break;\n }\n\n return running;\n}\n\nfunction setupMetrics(lc: LogContext, file: string, walMode: WalMode) {\n getOrCreateGauge('replica', 'db_size', {\n description:\n `The size of the replica's main db file, ` +\n `which does not include the wal file(s)`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, file));\n\n getOrCreateGauge('replica', 'wal_size', {\n description: `The size of the replica's wal file`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, `${file}-wal`));\n\n if (walMode === 'wal2') {\n getOrCreateGauge('replica', 'wal2_size', {\n description: `The size of the replica's wal2 file`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, `${file}-wal2`));\n }\n}\n\nfunction observeFileSize(lc: LogContext, file: string): ObservableCallback {\n return async o => {\n try {\n const stats = await stat(file);\n o.observe(stats.size);\n } catch (e) {\n lc.warn?.(`unable to stat ${file} for size metrics`, e);\n }\n };\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAmCA,IAAI,KAAK,IAAI,WAAW,QAAQ,EAAE,EAAE,eAAe;AAEnD,eAA8B,UAC5B,QACA,KACA,GAAG,MACY;AACf,QAAO,KAAK,SAAS,GAAG,gCAAgC;CACxD,MAAM,WAAW,MAAQ,KAAK,IAAI,sBAAsB;CAExD,MAAM,SAAS,wBAAwB;EAAC;EAAK,MAAM,KAAK,MAAM,EAAE;EAAC,CAAC;CAClE,MAAM,OAAuB,aAAa,WAAW,WAAW;CAChE,MAAM,aAAa,GAAG,KAAK;AAC3B,eAAc,iBAAiB,QAAQ,YAAY,GAAG,MAAM,EAAE,YAAY,EAAE;AAC5E,MAAK,iBAAiB,QAAQ,WAAW;AACzC,eAAc,IAAI,OAAO;CAEzB,MAAM,EAAC,MAAM,QAAQ,YAAW,MAAM,aACpC,IACA,UACA,OAAO,QACR;AAED,cAAa,IAAI,QAAQ,QAAQ;CAGjC,MAAM,UAAU,gBAAgB,SAAS;CACzC,MAAM,eAAe,IAAI,yBAAyB;AAClD,OAAM,aAAa,KAAK,QAAQ,MAAM,SAAS,OAAO,IAAI;CAE1D,MAAM,6BACJ,OAAO,eAAe,SAAS,eAAe,CAAC,OAAO,eAAe;CACvE,MAAM,QAAQ,eAAe,OAAO;CACpC,MAAM,EACJ,QACA,QACA,gBAAgB,EACd,MACA,KAAK,oBAAoB,6BACrB,oBAAoB,KAAK,KACzB,KAAA,QAEJ;CACJ,MAAM,iBAAiB,IAAI,yBACzB,IACA,OACA,OAAO,IACP,kBACD;CAED,MAAM,aAAa,IAAI,kBACrB,IACA,QACA,GAAG,WAAW,GAAG,OACjB,MACA,gBACA,cACA,6BAEI,2BAA2B,eAAe,OAAO,GACjD,KACL;AAED,sBAAqB,IAAI,YAAY,OAAO;CAE5C,MAAM,UAAU,eAAe,IAAI,QAAQ,WAAW;AAGtD,YAAW,MAAM,KAAK,WAAW,WAAW,EAAE;AAC5C,SAAO,KAAK,CAAC,SAAS,EAAC,OAAO,MAAK,CAAC,CAAC;AACrC;;AAGF,QAAO;;AAGT,SAAS,aAAa,IAAgB,MAAc,SAAkB;AACpE,kBAAiB,WAAW,WAAW;EACrC,aACE;EAEF,MAAM;EACP,CAAC,CAAC,YAAY,gBAAgB,IAAI,KAAK,CAAC;AAEzC,kBAAiB,WAAW,YAAY;EACtC,aAAa;EACb,MAAM;EACP,CAAC,CAAC,YAAY,gBAAgB,IAAI,GAAG,KAAK,MAAM,CAAC;AAElD,KAAI,YAAY,OACd,kBAAiB,WAAW,aAAa;EACvC,aAAa;EACb,MAAM;EACP,CAAC,CAAC,YAAY,gBAAgB,IAAI,GAAG,KAAK,OAAO,CAAC;;AAIvD,SAAS,gBAAgB,IAAgB,MAAkC;AACzE,QAAO,OAAM,MAAK;AAChB,MAAI;GACF,MAAM,QAAQ,MAAM,KAAK,KAAK;AAC9B,KAAE,QAAQ,MAAM,KAAK;WACd,GAAG;AACV,MAAG,OAAO,kBAAkB,KAAK,oBAAoB,EAAE;;;;AAM7D,IAAI,CAAC,mBAAmB,CACjB,WAAU,UACb,UAAU,KAAK,aAAa,EAAE,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,EAAE,CAAC,CACrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":[],"sources":["../../../../../../zero-cache/src/server/runner/main.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport '../../../../shared/src/dotenv.ts';\n\nimport {exitAfter} from '../../services/life-cycle.ts';\nimport {parentWorker, singleProcessMode} from '../../types/processes.ts';\nimport {runWorker} from './run-worker.ts';\n\nif (!singleProcessMode()) {\n void exitAfter(new LogContext('info', {}, consoleLogSink), () =>\n runWorker(parentWorker, process.env),\n );\n}\n\nexport default runWorker;\n"],"mappings":";;;;;;AAOA,IAAI,CAAC,kBAAkB,GACrB,UAAe,IAAI,WAAW,QAAQ,CAAC,GAAG,cAAc,SACtD,UAAU,cAAc,QAAQ,GAAG,CACrC"}
1
+ {"version":3,"file":"main.js","names":[],"sources":["../../../../../../zero-cache/src/server/runner/main.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport '../../../../shared/src/dotenv.ts';\n\nimport {exitAfter} from '../../services/life-cycle.ts';\nimport {parentWorker, singleProcessMode} from '../../types/processes.ts';\nimport {runWorker} from './run-worker.ts';\n\nif (!singleProcessMode()) {\n void exitAfter(new LogContext('info', {}, consoleLogSink), () =>\n runWorker(parentWorker, process.env),\n );\n}\n\nexport default runWorker;\n"],"mappings":";;;;;;AAOA,IAAI,CAAC,mBAAmB,CACjB,WAAU,IAAI,WAAW,QAAQ,EAAE,EAAE,eAAe,QACvD,UAAU,cAAc,QAAQ,IAAI,CACrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-worker.js","names":[],"sources":["../../../../../../zero-cache/src/server/runner/run-worker.ts"],"sourcesContent":["import '../../../../shared/src/dotenv.ts';\n\nimport {styleText} from 'node:util';\nimport {resolver, type Resolver} from '@rocicorp/resolver';\nimport {colorConsole} from '../../../../shared/src/logging.ts';\nimport {PROTOCOL_VERSION} from '../../../../zero-protocol/src/protocol-version.ts';\nimport {normalizeZeroConfig} from '../../config/normalize.ts';\nimport {getServerVersion, getZeroConfig} from '../../config/zero-config.ts';\nimport {ProcessManager, runUntilKilled} from '../../services/life-cycle.ts';\nimport {childWorker, type Worker} from '../../types/processes.ts';\nimport {createLogContext} from '../logging.ts';\nimport {MAIN_URL} from '../worker-urls.ts';\nimport {getTaskID} from './runtime.ts';\nimport {ZeroDispatcher} from './zero-dispatcher.ts';\n\nconst startupMessageEnv = 'ZERO_ENABLE_STARTUP_MESSAGE';\n\nfunction printStartupMessage(env: NodeJS.ProcessEnv) {\n if (env[startupMessageEnv] !== '1') {\n return;\n }\n\n colorConsole.log(\n `\\nBTW, ${styleText(['bold', 'cyan'], 'Cloud Zero')} ` +\n 'is now available - professional Zero hosting from the team that built it.\\n' +\n `Get started now: ${styleText(['blue', 'underline'], 'https://zero.rocicorp.dev/cloud')}\\n\\n` +\n styleText('dim', `Disable this message with ${startupMessageEnv}=0`) +\n '\\n',\n );\n}\n\n/**\n * Top-level `runner` entry point to the zero-cache. This layer is responsible for:\n * * runtime-based config normalization\n * * lazy startup\n * * serving /statsz\n * * auto-reset restarts (TODO)\n */\nexport async function runWorker(\n parent: Worker | null,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n // Note: Deprecation warnings are only emitted at this top-level parse;\n // they are suppressed when parsed in subprocesses.\n const cfg = getZeroConfig({env, emitDeprecationWarnings: true});\n const lc = createLogContext(cfg, 'runner');\n\n const defaultTaskID = await getTaskID(lc);\n const config = normalizeZeroConfig(lc, cfg, env, defaultTaskID);\n const processes = new ProcessManager(lc, parent ?? process);\n\n const {port, keepaliveTimeoutMs, lazyStartup} = config;\n const serverVersion = getServerVersion(config);\n lc.info?.(`starting server${!serverVersion ? '' : `@${serverVersion}`} `, {\n protocolVersion: PROTOCOL_VERSION,\n taskID: config.taskID,\n app: config.app,\n shard: config.shard,\n port: config.port,\n });\n\n let zeroCache: Resolver<Worker> | undefined;\n function startZeroCache(): Promise<Worker> {\n if (zeroCache === undefined) {\n const startMs = performance.now();\n lc.info?.('starting zero-cache');\n\n const r = (zeroCache = resolver<Worker>());\n const w = childWorker(MAIN_URL, env)\n .once('message', () => {\n r.resolve(w);\n lc.info?.(`zero-cache ready (${performance.now() - startMs} ms)`);\n })\n .once('error', r.reject);\n\n processes.addWorker(w, 'user-facing', 'zero-cache');\n }\n return zeroCache.promise;\n }\n\n // Eagerly start the zero-cache if it was not configured with --lazy-startup.\n if (!lazyStartup) {\n void startZeroCache();\n }\n\n await processes.allWorkersReady();\n parent?.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent ?? process,\n new ZeroDispatcher(\n config,\n lc,\n {port, keepaliveTimeoutMs},\n startZeroCache,\n () => printStartupMessage(env),\n ),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'main');\n }\n\n await processes.done();\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,IAAM,oBAAoB;AAE1B,SAAS,oBAAoB,KAAwB;CACnD,IAAI,IAAI,uBAAuB,KAC7B;CAGF,aAAa,IACX,UAAU,UAAU,CAAC,QAAQ,MAAM,GAAG,YAAY,EAAE;mBAE9B,UAAU,CAAC,QAAQ,WAAW,GAAG,iCAAiC,EAAE,QACxF,UAAU,OAAO,6BAA6B,kBAAkB,GAAG,IACnE,IACJ;AACF;;;;;;;;AASA,eAAsB,UACpB,QACA,KACe;CAGf,MAAM,MAAM,cAAc;EAAC;EAAK,yBAAyB;CAAI,CAAC;CAC9D,MAAM,KAAK,iBAAiB,KAAK,QAAQ;CAGzC,MAAM,SAAS,oBAAoB,IAAI,KAAK,KAAK,MADrB,UAAU,EAAE,CACsB;CAC9D,MAAM,YAAY,IAAI,eAAe,IAAI,UAAU,OAAO;CAE1D,MAAM,EAAC,MAAM,oBAAoB,gBAAe;CAChD,MAAM,gBAAgB,iBAAiB,MAAM;CAC7C,GAAG,OAAO,kBAAkB,CAAC,gBAAgB,KAAK,IAAI,gBAAgB,IAAI;EACxE,iBAAA;EACA,QAAQ,OAAO;EACf,KAAK,OAAO;EACZ,OAAO,OAAO;EACd,MAAM,OAAO;CACf,CAAC;CAED,IAAI;CACJ,SAAS,iBAAkC;EACzC,IAAI,cAAc,KAAA,GAAW;GAC3B,MAAM,UAAU,YAAY,IAAI;GAChC,GAAG,OAAO,qBAAqB;GAE/B,MAAM,IAAK,YAAY,SAAiB;GACxC,MAAM,IAAI,YAAY,UAAU,GAAG,EAChC,KAAK,iBAAiB;IACrB,EAAE,QAAQ,CAAC;IACX,GAAG,OAAO,qBAAqB,YAAY,IAAI,IAAI,QAAQ,KAAK;GAClE,CAAC,EACA,KAAK,SAAS,EAAE,MAAM;GAEzB,UAAU,UAAU,GAAG,eAAe,YAAY;EACpD;EACA,OAAO,UAAU;CACnB;CAGA,IAAI,CAAC,aACH,eAAoB;CAGtB,MAAM,UAAU,gBAAgB;CAChC,QAAQ,KAAK,CAAC,SAAS,EAAC,OAAO,KAAI,CAAC,CAAC;CAErC,IAAI;EACF,MAAM,eACJ,IACA,UAAU,SACV,IAAI,eACF,QACA,IACA;GAAC;GAAM;EAAkB,GACzB,sBACM,oBAAoB,GAAG,CAC/B,CACF;CACF,SAAS,KAAK;EACZ,UAAU,gBAAgB,KAAK,MAAM;CACvC;CAEA,MAAM,UAAU,KAAK;AACvB"}
1
+ {"version":3,"file":"run-worker.js","names":[],"sources":["../../../../../../zero-cache/src/server/runner/run-worker.ts"],"sourcesContent":["import '../../../../shared/src/dotenv.ts';\n\nimport {styleText} from 'node:util';\nimport {resolver, type Resolver} from '@rocicorp/resolver';\nimport {colorConsole} from '../../../../shared/src/logging.ts';\nimport {PROTOCOL_VERSION} from '../../../../zero-protocol/src/protocol-version.ts';\nimport {normalizeZeroConfig} from '../../config/normalize.ts';\nimport {getServerVersion, getZeroConfig} from '../../config/zero-config.ts';\nimport {ProcessManager, runUntilKilled} from '../../services/life-cycle.ts';\nimport {childWorker, type Worker} from '../../types/processes.ts';\nimport {createLogContext} from '../logging.ts';\nimport {MAIN_URL} from '../worker-urls.ts';\nimport {getTaskID} from './runtime.ts';\nimport {ZeroDispatcher} from './zero-dispatcher.ts';\n\nconst startupMessageEnv = 'ZERO_ENABLE_STARTUP_MESSAGE';\n\nfunction printStartupMessage(env: NodeJS.ProcessEnv) {\n if (env[startupMessageEnv] !== '1') {\n return;\n }\n\n colorConsole.log(\n `\\nBTW, ${styleText(['bold', 'cyan'], 'Cloud Zero')} ` +\n 'is now available - professional Zero hosting from the team that built it.\\n' +\n `Get started now: ${styleText(['blue', 'underline'], 'https://zero.rocicorp.dev/cloud')}\\n\\n` +\n styleText('dim', `Disable this message with ${startupMessageEnv}=0`) +\n '\\n',\n );\n}\n\n/**\n * Top-level `runner` entry point to the zero-cache. This layer is responsible for:\n * * runtime-based config normalization\n * * lazy startup\n * * serving /statsz\n * * auto-reset restarts (TODO)\n */\nexport async function runWorker(\n parent: Worker | null,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n // Note: Deprecation warnings are only emitted at this top-level parse;\n // they are suppressed when parsed in subprocesses.\n const cfg = getZeroConfig({env, emitDeprecationWarnings: true});\n const lc = createLogContext(cfg, 'runner');\n\n const defaultTaskID = await getTaskID(lc);\n const config = normalizeZeroConfig(lc, cfg, env, defaultTaskID);\n const processes = new ProcessManager(lc, parent ?? process);\n\n const {port, keepaliveTimeoutMs, lazyStartup} = config;\n const serverVersion = getServerVersion(config);\n lc.info?.(`starting server${!serverVersion ? '' : `@${serverVersion}`} `, {\n protocolVersion: PROTOCOL_VERSION,\n taskID: config.taskID,\n app: config.app,\n shard: config.shard,\n port: config.port,\n });\n\n let zeroCache: Resolver<Worker> | undefined;\n function startZeroCache(): Promise<Worker> {\n if (zeroCache === undefined) {\n const startMs = performance.now();\n lc.info?.('starting zero-cache');\n\n const r = (zeroCache = resolver<Worker>());\n const w = childWorker(MAIN_URL, env)\n .once('message', () => {\n r.resolve(w);\n lc.info?.(`zero-cache ready (${performance.now() - startMs} ms)`);\n })\n .once('error', r.reject);\n\n processes.addWorker(w, 'user-facing', 'zero-cache');\n }\n return zeroCache.promise;\n }\n\n // Eagerly start the zero-cache if it was not configured with --lazy-startup.\n if (!lazyStartup) {\n void startZeroCache();\n }\n\n await processes.allWorkersReady();\n parent?.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent ?? process,\n new ZeroDispatcher(\n config,\n lc,\n {port, keepaliveTimeoutMs},\n startZeroCache,\n () => printStartupMessage(env),\n ),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'main');\n }\n\n await processes.done();\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,IAAM,oBAAoB;AAE1B,SAAS,oBAAoB,KAAwB;AACnD,KAAI,IAAI,uBAAuB,IAC7B;AAGF,cAAa,IACX,UAAU,UAAU,CAAC,QAAQ,OAAO,EAAE,aAAa,CAAC;mBAE9B,UAAU,CAAC,QAAQ,YAAY,EAAE,kCAAkC,CAAC,QACxF,UAAU,OAAO,6BAA6B,kBAAkB,IAAI,GACpE,KACH;;;;;;;;;AAUH,eAAsB,UACpB,QACA,KACe;CAGf,MAAM,MAAM,cAAc;EAAC;EAAK,yBAAyB;EAAK,CAAC;CAC/D,MAAM,KAAK,iBAAiB,KAAK,SAAS;CAG1C,MAAM,SAAS,oBAAoB,IAAI,KAAK,KADtB,MAAM,UAAU,GAAG,CACsB;CAC/D,MAAM,YAAY,IAAI,eAAe,IAAI,UAAU,QAAQ;CAE3D,MAAM,EAAC,MAAM,oBAAoB,gBAAe;CAChD,MAAM,gBAAgB,iBAAiB,OAAO;AAC9C,IAAG,OAAO,kBAAkB,CAAC,gBAAgB,KAAK,IAAI,gBAAgB,IAAI;EACxE,iBAAA;EACA,QAAQ,OAAO;EACf,KAAK,OAAO;EACZ,OAAO,OAAO;EACd,MAAM,OAAO;EACd,CAAC;CAEF,IAAI;CACJ,SAAS,iBAAkC;AACzC,MAAI,cAAc,KAAA,GAAW;GAC3B,MAAM,UAAU,YAAY,KAAK;AACjC,MAAG,OAAO,sBAAsB;GAEhC,MAAM,IAAK,YAAY,UAAkB;GACzC,MAAM,IAAI,YAAY,UAAU,IAAI,CACjC,KAAK,iBAAiB;AACrB,MAAE,QAAQ,EAAE;AACZ,OAAG,OAAO,qBAAqB,YAAY,KAAK,GAAG,QAAQ,MAAM;KACjE,CACD,KAAK,SAAS,EAAE,OAAO;AAE1B,aAAU,UAAU,GAAG,eAAe,aAAa;;AAErD,SAAO,UAAU;;AAInB,KAAI,CAAC,YACE,iBAAgB;AAGvB,OAAM,UAAU,iBAAiB;AACjC,SAAQ,KAAK,CAAC,SAAS,EAAC,OAAO,MAAK,CAAC,CAAC;AAEtC,KAAI;AACF,QAAM,eACJ,IACA,UAAU,SACV,IAAI,eACF,QACA,IACA;GAAC;GAAM;GAAmB,EAC1B,sBACM,oBAAoB,IAAI,CAC/B,CACF;UACM,KAAK;AACZ,YAAU,gBAAgB,KAAK,OAAO;;AAGxC,OAAM,UAAU,MAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","names":[],"sources":["../../../../../../zero-cache/src/server/runner/runtime.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {nanoid} from 'nanoid';\nimport * as v from '../../../../shared/src/valita.ts';\n\n// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v4-response.html\nconst containerMetadataSchema = v.object({['TaskARN']: v.string()});\n\nexport async function getTaskID(lc: LogContext) {\n const containerURI = process.env['ECS_CONTAINER_METADATA_URI_V4'];\n if (containerURI) {\n try {\n const resp = await fetch(`${containerURI}`);\n const metadata = await resp.json();\n // Logged purely for debugging.\n lc.info?.(`Container metadata`, {metadata});\n } catch (e) {\n lc.warn?.('unable to lookup container metadata', e);\n }\n\n try {\n const resp = await fetch(`${containerURI}/task`);\n const metadata = v.parse(\n await resp.json(),\n containerMetadataSchema,\n 'passthrough',\n );\n lc.info?.(`Task metadata`, {metadata});\n const {TaskARN: taskID} = metadata;\n // Task ARN's are long, e.g.\n // \"arn:aws:ecs:us-east-1:712907626835:task/zbugs-prod-Cluster-vvNFcPUVpGHr/0042ea25bf534dc19975e26f61441737\"\n // We only care about the unique ID, i.e. the last path component.\n const lastSlash = taskID.lastIndexOf('/');\n return taskID.substring(lastSlash + 1); // works for lastSlash === -1 too\n } catch (e) {\n lc.warn?.('unable to determine task ID. falling back to random ID', e);\n }\n }\n return nanoid();\n}\n"],"mappings":";;;AAKA,IAAM,0BAA0B,eAAE,OAAO,GAAE,YAAY,eAAE,OAAO,EAAC,CAAC;AAElE,eAAsB,UAAU,IAAgB;CAC9C,MAAM,eAAe,QAAQ,IAAI;CACjC,IAAI,cAAc;EAChB,IAAI;GAEF,MAAM,WAAW,OAAM,MADJ,MAAM,GAAG,cAAc,GACd,KAAK;GAEjC,GAAG,OAAO,sBAAsB,EAAC,SAAQ,CAAC;EAC5C,SAAS,GAAG;GACV,GAAG,OAAO,uCAAuC,CAAC;EACpD;EAEA,IAAI;GAEF,MAAM,WAAW,MACf,OAAM,MAFW,MAAM,GAAG,aAAa,MAAM,GAElC,KAAK,GAChB,yBACA,aACF;GACA,GAAG,OAAO,iBAAiB,EAAC,SAAQ,CAAC;GACrC,MAAM,EAAC,SAAS,WAAU;GAI1B,MAAM,YAAY,OAAO,YAAY,GAAG;GACxC,OAAO,OAAO,UAAU,YAAY,CAAC;EACvC,SAAS,GAAG;GACV,GAAG,OAAO,0DAA0D,CAAC;EACvE;CACF;CACA,OAAO,OAAO;AAChB"}
1
+ {"version":3,"file":"runtime.js","names":[],"sources":["../../../../../../zero-cache/src/server/runner/runtime.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {nanoid} from 'nanoid';\nimport * as v from '../../../../shared/src/valita.ts';\n\n// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v4-response.html\nconst containerMetadataSchema = v.object({['TaskARN']: v.string()});\n\nexport async function getTaskID(lc: LogContext) {\n const containerURI = process.env['ECS_CONTAINER_METADATA_URI_V4'];\n if (containerURI) {\n try {\n const resp = await fetch(`${containerURI}`);\n const metadata = await resp.json();\n // Logged purely for debugging.\n lc.info?.(`Container metadata`, {metadata});\n } catch (e) {\n lc.warn?.('unable to lookup container metadata', e);\n }\n\n try {\n const resp = await fetch(`${containerURI}/task`);\n const metadata = v.parse(\n await resp.json(),\n containerMetadataSchema,\n 'passthrough',\n );\n lc.info?.(`Task metadata`, {metadata});\n const {TaskARN: taskID} = metadata;\n // Task ARN's are long, e.g.\n // \"arn:aws:ecs:us-east-1:712907626835:task/zbugs-prod-Cluster-vvNFcPUVpGHr/0042ea25bf534dc19975e26f61441737\"\n // We only care about the unique ID, i.e. the last path component.\n const lastSlash = taskID.lastIndexOf('/');\n return taskID.substring(lastSlash + 1); // works for lastSlash === -1 too\n } catch (e) {\n lc.warn?.('unable to determine task ID. falling back to random ID', e);\n }\n }\n return nanoid();\n}\n"],"mappings":";;;AAKA,IAAM,0BAA0B,eAAE,OAAO,GAAE,YAAY,eAAE,QAAQ,EAAC,CAAC;AAEnE,eAAsB,UAAU,IAAgB;CAC9C,MAAM,eAAe,QAAQ,IAAI;AACjC,KAAI,cAAc;AAChB,MAAI;GAEF,MAAM,WAAW,OADJ,MAAM,MAAM,GAAG,eAAe,EACf,MAAM;AAElC,MAAG,OAAO,sBAAsB,EAAC,UAAS,CAAC;WACpC,GAAG;AACV,MAAG,OAAO,uCAAuC,EAAE;;AAGrD,MAAI;GAEF,MAAM,WAAW,MACf,OAFW,MAAM,MAAM,GAAG,aAAa,OAAO,EAEnC,MAAM,EACjB,yBACA,cACD;AACD,MAAG,OAAO,iBAAiB,EAAC,UAAS,CAAC;GACtC,MAAM,EAAC,SAAS,WAAU;GAI1B,MAAM,YAAY,OAAO,YAAY,IAAI;AACzC,UAAO,OAAO,UAAU,YAAY,EAAE;WAC/B,GAAG;AACV,MAAG,OAAO,0DAA0D,EAAE;;;AAG1E,QAAO,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"zero-dispatcher.js","names":["#getWorker","#onStart","#handoff"],"sources":["../../../../../../zero-cache/src/server/runner/zero-dispatcher.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {NormalizedZeroConfig} from '../../config/normalize.ts';\nimport {handleHeapzRequest} from '../../services/heapz.ts';\nimport {HttpService, type Options} from '../../services/http-service.ts';\nimport {handleStatzRequest} from '../../services/statz.ts';\nimport type {IncomingMessageSubset} from '../../types/http.ts';\nimport type {Worker} from '../../types/processes.ts';\nimport {\n installWebSocketHandoff,\n type HandoffSpec,\n} from '../../types/websocket-handoff.ts';\n\nexport class ZeroDispatcher extends HttpService {\n readonly id = 'zero-dispatcher';\n readonly #getWorker: () => Promise<Worker>;\n readonly #onStart: (() => void) | undefined;\n\n constructor(\n config: NormalizedZeroConfig,\n lc: LogContext,\n opts: Options,\n getWorker: () => Promise<Worker>,\n onStart?: () => void,\n ) {\n super(`zero-dispatcher`, lc, opts, fastify => {\n fastify.get('/statz', (req, res) =>\n handleStatzRequest(lc, config, req, res),\n );\n fastify.get('/heapz', (req, res) =>\n handleHeapzRequest(lc, config, req, res),\n );\n installWebSocketHandoff(lc, this.#handoff, fastify.server);\n });\n this.#getWorker = getWorker;\n this.#onStart = onStart;\n }\n\n protected override _onStart() {\n this.#onStart?.();\n }\n\n readonly #handoff = (\n _req: IncomingMessageSubset,\n dispatch: (h: HandoffSpec<string>) => void,\n onError: (error: unknown) => void,\n ) => {\n void this.#getWorker().then(\n sender => dispatch({payload: 'unused', sender}),\n onError,\n );\n };\n}\n"],"mappings":";;;;;AAYA,IAAa,iBAAb,cAAoC,YAAY;CAC9C,KAAc;CACd;CACA;CAEA,YACE,QACA,IACA,MACA,WACA,SACA;EACA,MAAM,mBAAmB,IAAI,OAAM,YAAW;GAC5C,QAAQ,IAAI,WAAW,KAAK,QAC1B,mBAAmB,IAAI,QAAQ,KAAK,GAAG,CACzC;GACA,QAAQ,IAAI,WAAW,KAAK,QAC1B,mBAAmB,IAAI,QAAQ,KAAK,GAAG,CACzC;GACA,wBAAwB,IAAI,KAAKE,UAAU,QAAQ,MAAM;EAC3D,CAAC;EACD,KAAKF,aAAa;EAClB,KAAKC,WAAW;CAClB;CAEA,WAA8B;EAC5B,KAAKA,WAAW;CAClB;CAEA,YACE,MACA,UACA,YACG;EACH,KAAUD,WAAW,EAAE,MACrB,WAAU,SAAS;GAAC,SAAS;GAAU;EAAM,CAAC,GAC9C,OACF;CACF;AACF"}
1
+ {"version":3,"file":"zero-dispatcher.js","names":["#getWorker","#onStart","#handoff"],"sources":["../../../../../../zero-cache/src/server/runner/zero-dispatcher.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {NormalizedZeroConfig} from '../../config/normalize.ts';\nimport {handleHeapzRequest} from '../../services/heapz.ts';\nimport {HttpService, type Options} from '../../services/http-service.ts';\nimport {handleStatzRequest} from '../../services/statz.ts';\nimport type {IncomingMessageSubset} from '../../types/http.ts';\nimport type {Worker} from '../../types/processes.ts';\nimport {\n installWebSocketHandoff,\n type HandoffSpec,\n} from '../../types/websocket-handoff.ts';\n\nexport class ZeroDispatcher extends HttpService {\n readonly id = 'zero-dispatcher';\n readonly #getWorker: () => Promise<Worker>;\n readonly #onStart: (() => void) | undefined;\n\n constructor(\n config: NormalizedZeroConfig,\n lc: LogContext,\n opts: Options,\n getWorker: () => Promise<Worker>,\n onStart?: () => void,\n ) {\n super(`zero-dispatcher`, lc, opts, fastify => {\n fastify.get('/statz', (req, res) =>\n handleStatzRequest(lc, config, req, res),\n );\n fastify.get('/heapz', (req, res) =>\n handleHeapzRequest(lc, config, req, res),\n );\n installWebSocketHandoff(lc, this.#handoff, fastify.server);\n });\n this.#getWorker = getWorker;\n this.#onStart = onStart;\n }\n\n protected override _onStart() {\n this.#onStart?.();\n }\n\n readonly #handoff = (\n _req: IncomingMessageSubset,\n dispatch: (h: HandoffSpec<string>) => void,\n onError: (error: unknown) => void,\n ) => {\n void this.#getWorker().then(\n sender => dispatch({payload: 'unused', sender}),\n onError,\n );\n };\n}\n"],"mappings":";;;;;AAYA,IAAa,iBAAb,cAAoC,YAAY;CAC9C,KAAc;CACd;CACA;CAEA,YACE,QACA,IACA,MACA,WACA,SACA;AACA,QAAM,mBAAmB,IAAI,OAAM,YAAW;AAC5C,WAAQ,IAAI,WAAW,KAAK,QAC1B,mBAAmB,IAAI,QAAQ,KAAK,IAAI,CACzC;AACD,WAAQ,IAAI,WAAW,KAAK,QAC1B,mBAAmB,IAAI,QAAQ,KAAK,IAAI,CACzC;AACD,2BAAwB,IAAI,MAAA,SAAe,QAAQ,OAAO;IAC1D;AACF,QAAA,YAAkB;AAClB,QAAA,UAAgB;;CAGlB,WAA8B;AAC5B,QAAA,WAAiB;;CAGnB,YACE,MACA,UACA,YACG;AACE,QAAA,WAAiB,CAAC,MACrB,WAAU,SAAS;GAAC,SAAS;GAAU;GAAO,CAAC,EAC/C,QACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"shadow-syncer.js","names":[],"sources":["../../../../../zero-cache/src/server/shadow-syncer.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {must} from '../../../shared/src/must.ts';\nimport {getServerContext} from '../config/server-context.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {ShadowSyncService} from '../services/shadow-sync/shadow-sync-service.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\nconst MS_PER_HOUR = 1000 * 60 * 60;\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...argv: string[]\n): Promise<void> {\n const config = getNormalizedZeroConfig({env, argv});\n\n startOtelAuto(\n createLogContext(config, 'shadow-syncer', 0, false),\n 'shadow-syncer',\n 0,\n );\n lc = createLogContext(config, 'shadow-syncer');\n initEventSink(lc, config);\n\n const {shadowSync, upstream, initialSync} = config;\n const shard = getShardConfig(config);\n const service = new ShadowSyncService(\n lc,\n shard,\n upstream.db,\n getServerContext(config),\n {\n intervalMs: shadowSync.intervalHours * MS_PER_HOUR,\n sampleRate: shadowSync.sampleRate,\n maxRowsPerTable: shadowSync.maxRowsPerTable,\n textCopy: initialSync.textCopy,\n },\n );\n\n parent.send(['ready', {ready: true}]);\n\n return runUntilKilled(lc, parent, service);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;;;AAgBA,IAAM,cAAc,MAAO,KAAK;AAGhC,IAAI,KAAK,IAAI,WAAW,QAAQ,CAAC,GAAG,cAAc;AAElD,SAAwB,UACtB,QACA,KACA,GAAG,MACY;CACf,MAAM,SAAS,wBAAwB;EAAC;EAAK;CAAI,CAAC;CAElD,cACE,iBAAiB,QAAQ,iBAAiB,GAAG,KAAK,GAClD,iBACA,CACF;CACA,KAAK,iBAAiB,QAAQ,eAAe;CAC7C,cAAc,IAAI,MAAM;CAExB,MAAM,EAAC,YAAY,UAAU,gBAAe;CAC5C,MAAM,QAAQ,eAAe,MAAM;CACnC,MAAM,UAAU,IAAI,kBAClB,IACA,OACA,SAAS,IACT,iBAAiB,MAAM,GACvB;EACE,YAAY,WAAW,gBAAgB;EACvC,YAAY,WAAW;EACvB,iBAAiB,WAAW;EAC5B,UAAU,YAAY;CACxB,CACF;CAEA,OAAO,KAAK,CAAC,SAAS,EAAC,OAAO,KAAI,CAAC,CAAC;CAEpC,OAAO,eAAe,IAAI,QAAQ,OAAO;AAC3C;AAGA,IAAI,CAAC,kBAAkB,GACrB,UAAe,UACb,UAAU,KAAK,YAAY,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,CACrE"}
1
+ {"version":3,"file":"shadow-syncer.js","names":[],"sources":["../../../../../zero-cache/src/server/shadow-syncer.ts"],"sourcesContent":["import {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {must} from '../../../shared/src/must.ts';\nimport {getServerContext} from '../config/server-context.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {ShadowSyncService} from '../services/shadow-sync/shadow-sync-service.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\nconst MS_PER_HOUR = 1000 * 60 * 60;\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...argv: string[]\n): Promise<void> {\n const config = getNormalizedZeroConfig({env, argv});\n\n startOtelAuto(\n createLogContext(config, 'shadow-syncer', 0, false),\n 'shadow-syncer',\n 0,\n );\n lc = createLogContext(config, 'shadow-syncer');\n initEventSink(lc, config);\n\n const {shadowSync, upstream, initialSync} = config;\n const shard = getShardConfig(config);\n const service = new ShadowSyncService(\n lc,\n shard,\n upstream.db,\n getServerContext(config),\n {\n intervalMs: shadowSync.intervalHours * MS_PER_HOUR,\n sampleRate: shadowSync.sampleRate,\n maxRowsPerTable: shadowSync.maxRowsPerTable,\n textCopy: initialSync.textCopy,\n },\n );\n\n parent.send(['ready', {ready: true}]);\n\n return runUntilKilled(lc, parent, service);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;;;AAgBA,IAAM,cAAc,MAAO,KAAK;AAGhC,IAAI,KAAK,IAAI,WAAW,QAAQ,EAAE,EAAE,eAAe;AAEnD,SAAwB,UACtB,QACA,KACA,GAAG,MACY;CACf,MAAM,SAAS,wBAAwB;EAAC;EAAK;EAAK,CAAC;AAEnD,eACE,iBAAiB,QAAQ,iBAAiB,GAAG,MAAM,EACnD,iBACA,EACD;AACD,MAAK,iBAAiB,QAAQ,gBAAgB;AAC9C,eAAc,IAAI,OAAO;CAEzB,MAAM,EAAC,YAAY,UAAU,gBAAe;CAC5C,MAAM,QAAQ,eAAe,OAAO;CACpC,MAAM,UAAU,IAAI,kBAClB,IACA,OACA,SAAS,IACT,iBAAiB,OAAO,EACxB;EACE,YAAY,WAAW,gBAAgB;EACvC,YAAY,WAAW;EACvB,iBAAiB,WAAW;EAC5B,UAAU,YAAY;EACvB,CACF;AAED,QAAO,KAAK,CAAC,SAAS,EAAC,OAAO,MAAK,CAAC,CAAC;AAErC,QAAO,eAAe,IAAI,QAAQ,QAAQ;;AAI5C,IAAI,CAAC,mBAAmB,CACjB,WAAU,UACb,UAAU,KAAK,aAAa,EAAE,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,EAAE,CAAC,CACrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"syncer.js","names":[],"sources":["../../../../../zero-cache/src/server/syncer.ts"],"sourcesContent":["import {randomUUID} from 'node:crypto';\nimport {tmpdir} from 'node:os';\nimport path from 'node:path';\nimport {pid} from 'node:process';\nimport {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {randInt} from '../../../shared/src/rand.ts';\nimport {promiseVoid} from '../../../shared/src/resolved-promises.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {DatabaseStorage} from '../../../zqlite/src/database-storage.ts';\nimport type {ValidateLegacyJWT} from '../auth/auth.ts';\nimport {tokenConfigOptions, verifyToken} from '../auth/jwt.ts';\nimport type {NormalizedZeroConfig} from '../config/normalize.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {CustomQueryTransformer} from '../custom-queries/transform-query.ts';\nimport {warmupConnections} from '../db/warmup.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {MutagenService} from '../services/mutagen/mutagen.ts';\nimport {PusherService} from '../services/mutagen/pusher.ts';\nimport type {ReplicaState} from '../services/replicator/replicator.ts';\nimport {\n type ConnectionContextManager,\n ConnectionContextManagerImpl,\n} from '../services/view-syncer/connection-context-manager.ts';\nimport type {DrainCoordinator} from '../services/view-syncer/drain-coordinator.ts';\nimport {PipelineDriver} from '../services/view-syncer/pipeline-driver.ts';\nimport {Snapshotter} from '../services/view-syncer/snapshotter.ts';\nimport {ViewSyncerService} from '../services/view-syncer/view-syncer.ts';\nimport {ProtocolErrorWithLevel} from '../types/error-with-level.ts';\nimport {connectPgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardID} from '../types/shards.ts';\nimport type {Subscription} from '../types/subscription.ts';\nimport {replicaFileModeSchema, replicaFileName} from '../workers/replicator.ts';\nimport {Syncer} from '../workers/syncer.ts';\nimport {startAnonymousTelemetry} from './anonymous-otel-start.ts';\nimport {InspectorDelegate} from './inspector-delegate.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\nimport {isPriorityOpRunning, runPriorityOp} from './priority-op.ts';\n\nfunction randomID() {\n return randInt(1, Number.MAX_SAFE_INTEGER).toString(36);\n}\n\nfunction getCustomQueryConfig(\n config: Pick<NormalizedZeroConfig, 'query' | 'getQueries'>,\n) {\n const queryConfig = config.query?.url ? config.query : config.getQueries;\n\n if (!queryConfig?.url) {\n return undefined;\n }\n\n return {\n url: queryConfig.url,\n apiKey: queryConfig.apiKey,\n allowedClientHeaders: queryConfig.allowedClientHeaders,\n forwardCookies: queryConfig.forwardCookies ?? false,\n };\n}\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n assert(args.length >= 2, `expected [fileMode, workerIndex, ...flags]`);\n const fileMode = v.parse(args[0], replicaFileModeSchema);\n const workerIndex = Number(args[1]);\n const config = getNormalizedZeroConfig({env, argv: args.slice(2)});\n\n startOtelAuto(\n createLogContext(config, 'syncer', workerIndex, false),\n 'syncer',\n workerIndex,\n );\n lc = createLogContext(config, 'syncer', workerIndex);\n initEventSink(lc, config);\n\n const {cvr, upstream, enableCrudMutations} = config;\n\n const replicaFile = replicaFileName(config.replica.file, fileMode);\n lc.debug?.(`running view-syncer on ${replicaFile}`);\n\n const cvrDB = await connectPgClient(lc, cvr.db, `sync-worker-${pid}-cvr`, {\n max: must(cvr.maxConnsPerWorker, 'cvr.maxConnsPerWorker must be set'),\n });\n\n const upstreamDB =\n enableCrudMutations && upstream.type === 'pg'\n ? await connectPgClient(lc, upstream.db, `sync-worker-${pid}-upstream`, {\n max: must(\n upstream.maxConnsPerWorker,\n 'upstream.maxConnsPerWorker must be set',\n ),\n })\n : undefined;\n\n const dbWarmup = Promise.allSettled([\n warmupConnections(lc, cvrDB, 'cvr'),\n upstreamDB ? warmupConnections(lc, upstreamDB, 'upstream') : promiseVoid,\n ]);\n\n const tmpDir = config.storageDBTmpDir ?? tmpdir();\n const operatorStorage = DatabaseStorage.create(\n lc,\n path.join(tmpDir, `sync-worker-${randomUUID()}`),\n );\n const writeAuthzStorage = DatabaseStorage.create(\n lc,\n path.join(tmpDir, `mutagen-${randomUUID()}`),\n );\n\n const shard = getShardID(config);\n const customQueryConfig = getCustomQueryConfig(config);\n const pushConfig =\n config.push.url === undefined && config.mutate.url === undefined\n ? undefined\n : {\n ...config.push,\n ...config.mutate,\n url: must(\n config.push.url ?? config.mutate.url,\n 'No push or mutate URL configured',\n ),\n };\n\n /** @deprecated used in JWT validation */\n let validateLegacyJWT: ValidateLegacyJWT | undefined = undefined;\n\n const tokenOptions = tokenConfigOptions(config.auth ?? {});\n if (tokenOptions.length === 1) {\n validateLegacyJWT = async (token, {userID}) => {\n if (!userID) {\n throw new ProtocolErrorWithLevel(\n {\n kind: 'Unauthorized',\n message: 'UserID is required for JWT validation.',\n origin: 'zeroCache',\n },\n 'warn',\n );\n }\n\n const decoded = await verifyToken(config.auth, token, {\n subject: userID,\n ...(config.auth?.issuer && {issuer: config.auth.issuer}),\n ...(config.auth?.audience && {\n audience: config.auth.audience,\n }),\n });\n return {\n type: 'jwt',\n raw: token,\n decoded,\n };\n };\n }\n\n const viewSyncerFactory = (\n id: string,\n sub: Subscription<ReplicaState>,\n drainCoordinator: DrainCoordinator,\n ) => {\n const logger = lc\n .withContext('component', 'view-syncer')\n .withContext('clientGroupID', id)\n .withContext('instance', randomID());\n\n const customQueryTransformer =\n customQueryConfig && new CustomQueryTransformer(logger, shard);\n const connContextManager = new ConnectionContextManagerImpl(\n logger,\n config.auth.revalidateIntervalSeconds,\n config.auth.retransformIntervalSeconds,\n customQueryConfig,\n pushConfig,\n validateLegacyJWT,\n );\n\n lc.debug?.(\n `creating view syncer. Query Planner Enabled: ${config.enableQueryPlanner}`,\n );\n\n const inspectorDelegate = new InspectorDelegate(customQueryTransformer);\n\n const priorityOpRunningYieldThresholdMs = Math.max(\n config.yieldThresholdMs / 4,\n 2,\n );\n const normalYieldThresholdMs = Math.max(config.yieldThresholdMs, 2);\n\n return new ViewSyncerService(\n config,\n logger,\n shard,\n config.taskID,\n id,\n cvrDB,\n new PipelineDriver(\n logger,\n config.log,\n new Snapshotter(logger, replicaFile, shard),\n shard,\n operatorStorage.createClientGroupStorage(id),\n id,\n inspectorDelegate,\n () =>\n isPriorityOpRunning()\n ? priorityOpRunningYieldThresholdMs\n : normalYieldThresholdMs,\n config.enableQueryPlanner,\n config,\n ),\n sub,\n drainCoordinator,\n config.log.slowHydrateThreshold,\n inspectorDelegate,\n connContextManager,\n customQueryTransformer,\n runPriorityOp,\n );\n };\n\n const mutagenFactory = upstreamDB\n ? (id: string) =>\n new MutagenService(\n lc\n .withContext('component', 'mutagen')\n .withContext('clientGroupID', id),\n shard,\n id,\n upstreamDB,\n config,\n writeAuthzStorage,\n )\n : undefined;\n\n const pusherFactory =\n pushConfig === undefined\n ? undefined\n : (id: string, connContextManager: ConnectionContextManager) =>\n new PusherService(\n config,\n lc.withContext('clientGroupID', id),\n id,\n connContextManager,\n );\n\n const syncer = new Syncer(\n lc,\n config,\n viewSyncerFactory,\n mutagenFactory,\n pusherFactory,\n parent,\n validateLegacyJWT,\n );\n\n startAnonymousTelemetry(lc, config);\n\n void dbWarmup.then(() => parent.send(['ready', {ready: true}]));\n\n return runUntilKilled(lc, parent, syncer);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"syncer.js","names":[],"sources":["../../../../../zero-cache/src/server/syncer.ts"],"sourcesContent":["import {randomUUID} from 'node:crypto';\nimport {tmpdir} from 'node:os';\nimport path from 'node:path';\nimport {pid} from 'node:process';\nimport {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {randInt} from '../../../shared/src/rand.ts';\nimport {promiseVoid} from '../../../shared/src/resolved-promises.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {DatabaseStorage} from '../../../zqlite/src/database-storage.ts';\nimport type {ValidateLegacyJWT} from '../auth/auth.ts';\nimport {tokenConfigOptions, verifyToken} from '../auth/jwt.ts';\nimport type {NormalizedZeroConfig} from '../config/normalize.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {CustomQueryTransformer} from '../custom-queries/transform-query.ts';\nimport {warmupConnections} from '../db/warmup.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {MutagenService} from '../services/mutagen/mutagen.ts';\nimport {PusherService} from '../services/mutagen/pusher.ts';\nimport type {ReplicaState} from '../services/replicator/replicator.ts';\nimport {\n type ConnectionContextManager,\n ConnectionContextManagerImpl,\n} from '../services/view-syncer/connection-context-manager.ts';\nimport type {DrainCoordinator} from '../services/view-syncer/drain-coordinator.ts';\nimport {PipelineDriver} from '../services/view-syncer/pipeline-driver.ts';\nimport {Snapshotter} from '../services/view-syncer/snapshotter.ts';\nimport {ViewSyncerService} from '../services/view-syncer/view-syncer.ts';\nimport {ProtocolErrorWithLevel} from '../types/error-with-level.ts';\nimport {connectPgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardID} from '../types/shards.ts';\nimport type {Subscription} from '../types/subscription.ts';\nimport {replicaFileModeSchema, replicaFileName} from '../workers/replicator.ts';\nimport {Syncer} from '../workers/syncer.ts';\nimport {startAnonymousTelemetry} from './anonymous-otel-start.ts';\nimport {InspectorDelegate} from './inspector-delegate.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\nimport {isPriorityOpRunning, runPriorityOp} from './priority-op.ts';\n\nfunction randomID() {\n return randInt(1, Number.MAX_SAFE_INTEGER).toString(36);\n}\n\nfunction getCustomQueryConfig(\n config: Pick<NormalizedZeroConfig, 'query' | 'getQueries'>,\n) {\n const queryConfig = config.query?.url ? config.query : config.getQueries;\n\n if (!queryConfig?.url) {\n return undefined;\n }\n\n return {\n url: queryConfig.url,\n apiKey: queryConfig.apiKey,\n allowedClientHeaders: queryConfig.allowedClientHeaders,\n forwardCookies: queryConfig.forwardCookies ?? false,\n };\n}\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n assert(args.length >= 2, `expected [fileMode, workerIndex, ...flags]`);\n const fileMode = v.parse(args[0], replicaFileModeSchema);\n const workerIndex = Number(args[1]);\n const config = getNormalizedZeroConfig({env, argv: args.slice(2)});\n\n startOtelAuto(\n createLogContext(config, 'syncer', workerIndex, false),\n 'syncer',\n workerIndex,\n );\n lc = createLogContext(config, 'syncer', workerIndex);\n initEventSink(lc, config);\n\n const {cvr, upstream, enableCrudMutations} = config;\n\n const replicaFile = replicaFileName(config.replica.file, fileMode);\n lc.debug?.(`running view-syncer on ${replicaFile}`);\n\n const cvrDB = await connectPgClient(lc, cvr.db, `sync-worker-${pid}-cvr`, {\n max: must(cvr.maxConnsPerWorker, 'cvr.maxConnsPerWorker must be set'),\n });\n\n const upstreamDB =\n enableCrudMutations && upstream.type === 'pg'\n ? await connectPgClient(lc, upstream.db, `sync-worker-${pid}-upstream`, {\n max: must(\n upstream.maxConnsPerWorker,\n 'upstream.maxConnsPerWorker must be set',\n ),\n })\n : undefined;\n\n const dbWarmup = Promise.allSettled([\n warmupConnections(lc, cvrDB, 'cvr'),\n upstreamDB ? warmupConnections(lc, upstreamDB, 'upstream') : promiseVoid,\n ]);\n\n const tmpDir = config.storageDBTmpDir ?? tmpdir();\n const operatorStorage = DatabaseStorage.create(\n lc,\n path.join(tmpDir, `sync-worker-${randomUUID()}`),\n );\n const writeAuthzStorage = DatabaseStorage.create(\n lc,\n path.join(tmpDir, `mutagen-${randomUUID()}`),\n );\n\n const shard = getShardID(config);\n const customQueryConfig = getCustomQueryConfig(config);\n const pushConfig =\n config.push.url === undefined && config.mutate.url === undefined\n ? undefined\n : {\n ...config.push,\n ...config.mutate,\n url: must(\n config.push.url ?? config.mutate.url,\n 'No push or mutate URL configured',\n ),\n };\n\n /** @deprecated used in JWT validation */\n let validateLegacyJWT: ValidateLegacyJWT | undefined = undefined;\n\n const tokenOptions = tokenConfigOptions(config.auth ?? {});\n if (tokenOptions.length === 1) {\n validateLegacyJWT = async (token, {userID}) => {\n if (!userID) {\n throw new ProtocolErrorWithLevel(\n {\n kind: 'Unauthorized',\n message: 'UserID is required for JWT validation.',\n origin: 'zeroCache',\n },\n 'warn',\n );\n }\n\n const decoded = await verifyToken(config.auth, token, {\n subject: userID,\n ...(config.auth?.issuer && {issuer: config.auth.issuer}),\n ...(config.auth?.audience && {\n audience: config.auth.audience,\n }),\n });\n return {\n type: 'jwt',\n raw: token,\n decoded,\n };\n };\n }\n\n const viewSyncerFactory = (\n id: string,\n sub: Subscription<ReplicaState>,\n drainCoordinator: DrainCoordinator,\n ) => {\n const logger = lc\n .withContext('component', 'view-syncer')\n .withContext('clientGroupID', id)\n .withContext('instance', randomID());\n\n const customQueryTransformer =\n customQueryConfig && new CustomQueryTransformer(logger, shard);\n const connContextManager = new ConnectionContextManagerImpl(\n logger,\n config.auth.revalidateIntervalSeconds,\n config.auth.retransformIntervalSeconds,\n customQueryConfig,\n pushConfig,\n validateLegacyJWT,\n );\n\n lc.debug?.(\n `creating view syncer. Query Planner Enabled: ${config.enableQueryPlanner}`,\n );\n\n const inspectorDelegate = new InspectorDelegate(customQueryTransformer);\n\n const priorityOpRunningYieldThresholdMs = Math.max(\n config.yieldThresholdMs / 4,\n 2,\n );\n const normalYieldThresholdMs = Math.max(config.yieldThresholdMs, 2);\n\n return new ViewSyncerService(\n config,\n logger,\n shard,\n config.taskID,\n id,\n cvrDB,\n new PipelineDriver(\n logger,\n config.log,\n new Snapshotter(logger, replicaFile, shard),\n shard,\n operatorStorage.createClientGroupStorage(id),\n id,\n inspectorDelegate,\n () =>\n isPriorityOpRunning()\n ? priorityOpRunningYieldThresholdMs\n : normalYieldThresholdMs,\n config.enableQueryPlanner,\n config,\n ),\n sub,\n drainCoordinator,\n config.log.slowHydrateThreshold,\n inspectorDelegate,\n connContextManager,\n customQueryTransformer,\n runPriorityOp,\n );\n };\n\n const mutagenFactory = upstreamDB\n ? (id: string) =>\n new MutagenService(\n lc\n .withContext('component', 'mutagen')\n .withContext('clientGroupID', id),\n shard,\n id,\n upstreamDB,\n config,\n writeAuthzStorage,\n )\n : undefined;\n\n const pusherFactory =\n pushConfig === undefined\n ? undefined\n : (id: string, connContextManager: ConnectionContextManager) =>\n new PusherService(\n config,\n lc.withContext('clientGroupID', id),\n id,\n connContextManager,\n );\n\n const syncer = new Syncer(\n lc,\n config,\n viewSyncerFactory,\n mutagenFactory,\n pusherFactory,\n parent,\n validateLegacyJWT,\n );\n\n startAnonymousTelemetry(lc, config);\n\n void dbWarmup.then(() => parent.send(['ready', {ready: true}]));\n\n return runUntilKilled(lc, parent, syncer);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(lc, () =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAS,WAAW;AAClB,QAAO,QAAQ,GAAG,OAAO,iBAAiB,CAAC,SAAS,GAAG;;AAGzD,SAAS,qBACP,QACA;CACA,MAAM,cAAc,OAAO,OAAO,MAAM,OAAO,QAAQ,OAAO;AAE9D,KAAI,CAAC,aAAa,IAChB;AAGF,QAAO;EACL,KAAK,YAAY;EACjB,QAAQ,YAAY;EACpB,sBAAsB,YAAY;EAClC,gBAAgB,YAAY,kBAAkB;EAC/C;;AAIH,IAAI,KAAK,IAAI,WAAW,QAAQ,EAAE,EAAE,eAAe;AAEnD,eAA8B,UAC5B,QACA,KACA,GAAG,MACY;AACf,QAAO,KAAK,UAAU,GAAG,6CAA6C;CACtE,MAAM,WAAW,MAAQ,KAAK,IAAI,sBAAsB;CACxD,MAAM,cAAc,OAAO,KAAK,GAAG;CACnC,MAAM,SAAS,wBAAwB;EAAC;EAAK,MAAM,KAAK,MAAM,EAAE;EAAC,CAAC;AAElE,eACE,iBAAiB,QAAQ,UAAU,aAAa,MAAM,EACtD,UACA,YACD;AACD,MAAK,iBAAiB,QAAQ,UAAU,YAAY;AACpD,eAAc,IAAI,OAAO;CAEzB,MAAM,EAAC,KAAK,UAAU,wBAAuB;CAE7C,MAAM,cAAc,gBAAgB,OAAO,QAAQ,MAAM,SAAS;AAClE,IAAG,QAAQ,0BAA0B,cAAc;CAEnD,MAAM,QAAQ,MAAM,gBAAgB,IAAI,IAAI,IAAI,eAAe,IAAI,OAAO,EACxE,KAAK,KAAK,IAAI,mBAAmB,oCAAoC,EACtE,CAAC;CAEF,MAAM,aACJ,uBAAuB,SAAS,SAAS,OACrC,MAAM,gBAAgB,IAAI,SAAS,IAAI,eAAe,IAAI,YAAY,EACpE,KAAK,KACH,SAAS,mBACT,yCACD,EACF,CAAC,GACF,KAAA;CAEN,MAAM,WAAW,QAAQ,WAAW,CAClC,kBAAkB,IAAI,OAAO,MAAM,EACnC,aAAa,kBAAkB,IAAI,YAAY,WAAW,GAAG,YAC9D,CAAC;CAEF,MAAM,SAAS,OAAO,mBAAmB,QAAQ;CACjD,MAAM,kBAAkB,gBAAgB,OACtC,IACA,KAAK,KAAK,QAAQ,eAAe,YAAY,GAAG,CACjD;CACD,MAAM,oBAAoB,gBAAgB,OACxC,IACA,KAAK,KAAK,QAAQ,WAAW,YAAY,GAAG,CAC7C;CAED,MAAM,QAAQ,WAAW,OAAO;CAChC,MAAM,oBAAoB,qBAAqB,OAAO;CACtD,MAAM,aACJ,OAAO,KAAK,QAAQ,KAAA,KAAa,OAAO,OAAO,QAAQ,KAAA,IACnD,KAAA,IACA;EACE,GAAG,OAAO;EACV,GAAG,OAAO;EACV,KAAK,KACH,OAAO,KAAK,OAAO,OAAO,OAAO,KACjC,mCACD;EACF;;CAGP,IAAI,oBAAmD,KAAA;AAGvD,KADqB,mBAAmB,OAAO,QAAQ,EAAE,CAAC,CACzC,WAAW,EAC1B,qBAAoB,OAAO,OAAO,EAAC,aAAY;AAC7C,MAAI,CAAC,OACH,OAAM,IAAI,uBACR;GACE,MAAM;GACN,SAAS;GACT,QAAQ;GACT,EACD,OACD;AAUH,SAAO;GACL,MAAM;GACN,KAAK;GACL,SAVc,MAAM,YAAY,OAAO,MAAM,OAAO;IACpD,SAAS;IACT,GAAI,OAAO,MAAM,UAAU,EAAC,QAAQ,OAAO,KAAK,QAAO;IACvD,GAAI,OAAO,MAAM,YAAY,EAC3B,UAAU,OAAO,KAAK,UACvB;IACF,CAAC;GAKD;;CAIL,MAAM,qBACJ,IACA,KACA,qBACG;EACH,MAAM,SAAS,GACZ,YAAY,aAAa,cAAc,CACvC,YAAY,iBAAiB,GAAG,CAChC,YAAY,YAAY,UAAU,CAAC;EAEtC,MAAM,yBACJ,qBAAqB,IAAI,uBAAuB,QAAQ,MAAM;EAChE,MAAM,qBAAqB,IAAI,6BAC7B,QACA,OAAO,KAAK,2BACZ,OAAO,KAAK,4BACZ,mBACA,YACA,kBACD;AAED,KAAG,QACD,gDAAgD,OAAO,qBACxD;EAED,MAAM,oBAAoB,IAAI,kBAAkB,uBAAuB;EAEvE,MAAM,oCAAoC,KAAK,IAC7C,OAAO,mBAAmB,GAC1B,EACD;EACD,MAAM,yBAAyB,KAAK,IAAI,OAAO,kBAAkB,EAAE;AAEnE,SAAO,IAAI,kBACT,QACA,QACA,OACA,OAAO,QACP,IACA,OACA,IAAI,eACF,QACA,OAAO,KACP,IAAI,YAAY,QAAQ,aAAa,MAAM,EAC3C,OACA,gBAAgB,yBAAyB,GAAG,EAC5C,IACA,yBAEE,qBAAqB,GACjB,oCACA,wBACN,OAAO,oBACP,OACD,EACD,KACA,kBACA,OAAO,IAAI,sBACX,mBACA,oBACA,wBACA,cACD;;CA4BH,MAAM,SAAS,IAAI,OACjB,IACA,QACA,mBA5BqB,cAClB,OACC,IAAI,eACF,GACG,YAAY,aAAa,UAAU,CACnC,YAAY,iBAAiB,GAAG,EACnC,OACA,IACA,YACA,QACA,kBACD,GACH,KAAA,GAGF,eAAe,KAAA,IACX,KAAA,KACC,IAAY,uBACX,IAAI,cACF,QACA,GAAG,YAAY,iBAAiB,GAAG,EACnC,IACA,mBACD,EAQP,QACA,kBACD;AAED,yBAAwB,IAAI,OAAO;AAE9B,UAAS,WAAW,OAAO,KAAK,CAAC,SAAS,EAAC,OAAO,MAAK,CAAC,CAAC,CAAC;AAE/D,QAAO,eAAe,IAAI,QAAQ,OAAO;;AAI3C,IAAI,CAAC,mBAAmB,CACjB,WAAU,UACb,UAAU,KAAK,aAAa,EAAE,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,EAAE,CAAC,CACrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"worker-dispatcher.js","names":["#lc","#state"],"sources":["../../../../../zero-cache/src/server/worker-dispatcher.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport UrlPattern from 'url-pattern';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {h32} from '../../../shared/src/hash.ts';\nimport {getOrCreateGauge} from '../observability/metrics.ts';\nimport {RunningState} from '../services/running-state.ts';\nimport type {Service} from '../services/service.ts';\nimport type {IncomingMessageSubset} from '../types/http.ts';\nimport type {Worker} from '../types/processes.ts';\nimport {installWebSocketHandoff} from '../types/websocket-handoff.ts';\nimport {getConnectParams} from '../workers/connect-params.ts';\n\nexport class WorkerDispatcher implements Service {\n readonly id = 'worker-dispatcher';\n readonly #lc: LogContext;\n\n readonly #state = new RunningState(this.id);\n\n constructor(\n lc: LogContext,\n taskID: string,\n parent: Worker,\n syncers: Worker[],\n mutator: Worker | undefined,\n changeStreamer: Worker | undefined,\n ) {\n this.#lc = lc;\n\n function connectParams(req: IncomingMessageSubset) {\n const {headers, url: u} = req;\n const url = new URL(u ?? '', 'http://unused/');\n const path = parsePath(url);\n if (!path) {\n throw new Error(`Invalid URL: ${u}`);\n }\n const version = Number(path.version);\n if (Number.isNaN(version)) {\n throw new Error(`Invalid version: ${u}`);\n }\n const {params, error} = getConnectParams(version, url, headers);\n if (error !== null) {\n throw new Error(error);\n }\n return params;\n }\n\n const handlePush = (req: IncomingMessageSubset) => {\n assert(\n mutator !== undefined,\n 'Received a push for a custom mutation but no `push.url` was configured.',\n );\n return {payload: connectParams(req), sender: mutator};\n };\n\n let maxProtocolVersion = 0;\n getOrCreateGauge(\n 'sync',\n 'max-protocol-version',\n 'Latest sync protocol version from a connecting client',\n ).addCallback(result => {\n if (maxProtocolVersion) {\n result.observe(maxProtocolVersion);\n }\n });\n\n const handleSync = (req: IncomingMessageSubset) => {\n assert(syncers.length, 'Received a sync request with no sync workers.');\n const params = connectParams(req);\n const {clientGroupID, protocolVersion} = params;\n maxProtocolVersion = Math.max(maxProtocolVersion, protocolVersion);\n\n // Include the TaskID when hash-bucketting the client group to the sync\n // worker. This diversifies the distribution of client groups (across\n // workers) for different tasks, so that if one task sheds connections\n // from its most heavily loaded sync worker(s), those client groups will\n // be distributed uniformly across workers on the receiving task(s).\n const syncer = h32(taskID + '/' + clientGroupID) % syncers.length;\n\n lc.debug?.(`connecting ${clientGroupID} to syncer ${syncer}`);\n return {payload: params, sender: syncers[syncer]};\n };\n\n const handleChangeStream = (req: IncomingMessageSubset) => {\n // Note: The change-streamer is generally not dispatched via the main\n // port, and in particular, should *not* be accessible via that\n // port in single-node mode. However, this plumbing is maintained\n // for the purpose of allowing --lazy-startup of the\n // replication-manager as a possible future feature.\n assert(\n syncers.length === 0 && mutator === undefined,\n 'Dispatch to the change-streamer via the main port ' +\n 'is only allowed in multi-node mode',\n );\n assert(\n changeStreamer,\n 'Received a change-streamer request without a change-streamer worker',\n );\n const url = new URL(req.url ?? '', 'http://unused/');\n const path = parsePath(url);\n if (!path) {\n throw new Error(`Invalid URL: ${req.url}`);\n }\n\n return {\n payload: path.action,\n sender: changeStreamer,\n };\n };\n\n // handoff messages from this ZeroDispatcher to the appropriate worker (pool).\n installWebSocketHandoff<unknown>(\n lc,\n request => {\n const {url: u} = request;\n const url = new URL(u ?? '', 'http://unused/');\n const path = parsePath(url);\n if (!path) {\n throw new Error(`Invalid URL: ${u}`);\n }\n switch (path.worker) {\n case 'sync':\n return handleSync(request);\n case 'replication':\n return handleChangeStream(request);\n case 'mutate':\n return handlePush(request);\n default:\n throw new Error(`Invalid URL: ${u}`);\n }\n },\n parent,\n );\n }\n\n run() {\n const readyStart = Date.now();\n getOrCreateGauge('server', 'uptime', {\n description: 'Cumulative uptime, starting from when requests are served',\n unit: 's',\n }).addCallback(result => result.observe((Date.now() - readyStart) / 1000));\n\n return this.#state.stopped();\n }\n\n stop() {\n this.#state.stop(this.#lc);\n return this.#state.stopped();\n }\n}\n\nconst URL_PATTERN = new UrlPattern('(/:base)/:worker/v:version/:action');\n\nexport function parsePath(url: URL):\n | {\n base?: string;\n worker: 'sync' | 'mutate' | 'replication';\n version: string;\n action: string;\n }\n | undefined {\n // The match() returns both null and undefined.\n return URL_PATTERN.match(url.pathname) || undefined;\n} // The server allows the client to use any /:base/ path to facilitate\n// servicing requests on the same domain as the application.\n"],"mappings":";;;;;;;;AAYA,IAAa,mBAAb,MAAiD;CAC/C,KAAc;CACd;CAEA,SAAkB,IAAI,aAAa,KAAK,EAAE;CAE1C,YACE,IACA,QACA,QACA,SACA,SACA,gBACA;EACA,KAAKA,MAAM;EAEX,SAAS,cAAc,KAA4B;GACjD,MAAM,EAAC,SAAS,KAAK,MAAK;GAC1B,MAAM,MAAM,IAAI,IAAI,KAAK,IAAI,gBAAgB;GAC7C,MAAM,OAAO,UAAU,GAAG;GAC1B,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,gBAAgB,GAAG;GAErC,MAAM,UAAU,OAAO,KAAK,OAAO;GACnC,IAAI,OAAO,MAAM,OAAO,GACtB,MAAM,IAAI,MAAM,oBAAoB,GAAG;GAEzC,MAAM,EAAC,QAAQ,UAAS,iBAAiB,SAAS,KAAK,OAAO;GAC9D,IAAI,UAAU,MACZ,MAAM,IAAI,MAAM,KAAK;GAEvB,OAAO;EACT;EAEA,MAAM,cAAc,QAA+B;GACjD,OACE,YAAY,KAAA,GACZ,yEACF;GACA,OAAO;IAAC,SAAS,cAAc,GAAG;IAAG,QAAQ;GAAO;EACtD;EAEA,IAAI,qBAAqB;EACzB,iBACE,QACA,wBACA,uDACF,EAAE,aAAY,WAAU;GACtB,IAAI,oBACF,OAAO,QAAQ,kBAAkB;EAErC,CAAC;EAED,MAAM,cAAc,QAA+B;GACjD,OAAO,QAAQ,QAAQ,+CAA+C;GACtE,MAAM,SAAS,cAAc,GAAG;GAChC,MAAM,EAAC,eAAe,oBAAmB;GACzC,qBAAqB,KAAK,IAAI,oBAAoB,eAAe;GAOjE,MAAM,SAAS,IAAI,SAAS,MAAM,aAAa,IAAI,QAAQ;GAE3D,GAAG,QAAQ,cAAc,cAAc,aAAa,QAAQ;GAC5D,OAAO;IAAC,SAAS;IAAQ,QAAQ,QAAQ;GAAO;EAClD;EAEA,MAAM,sBAAsB,QAA+B;GAMzD,OACE,QAAQ,WAAW,KAAK,YAAY,KAAA,GACpC,sFAEF;GACA,OACE,gBACA,qEACF;GAEA,MAAM,OAAO,UAAU,IADP,IAAI,IAAI,OAAO,IAAI,gBACZ,CAAG;GAC1B,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,gBAAgB,IAAI,KAAK;GAG3C,OAAO;IACL,SAAS,KAAK;IACd,QAAQ;GACV;EACF;EAGA,wBACE,KACA,YAAW;GACT,MAAM,EAAC,KAAK,MAAK;GAEjB,MAAM,OAAO,UAAU,IADP,IAAI,KAAK,IAAI,gBACN,CAAG;GAC1B,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,gBAAgB,GAAG;GAErC,QAAQ,KAAK,QAAb;IACE,KAAK,QACH,OAAO,WAAW,OAAO;IAC3B,KAAK,eACH,OAAO,mBAAmB,OAAO;IACnC,KAAK,UACH,OAAO,WAAW,OAAO;IAC3B,SACE,MAAM,IAAI,MAAM,gBAAgB,GAAG;GACvC;EACF,GACA,MACF;CACF;CAEA,MAAM;EACJ,MAAM,aAAa,KAAK,IAAI;EAC5B,iBAAiB,UAAU,UAAU;GACnC,aAAa;GACb,MAAM;EACR,CAAC,EAAE,aAAY,WAAU,OAAO,SAAS,KAAK,IAAI,IAAI,cAAc,GAAI,CAAC;EAEzE,OAAO,KAAKC,OAAO,QAAQ;CAC7B;CAEA,OAAO;EACL,KAAKA,OAAO,KAAK,KAAKD,GAAG;EACzB,OAAO,KAAKC,OAAO,QAAQ;CAC7B;AACF;AAEA,IAAM,cAAc,IAAI,WAAW,oCAAoC;AAEvE,SAAgB,UAAU,KAOZ;CAEZ,OAAO,YAAY,MAAM,IAAI,QAAQ,KAAK,KAAA;AAC5C"}
1
+ {"version":3,"file":"worker-dispatcher.js","names":["#lc","#state"],"sources":["../../../../../zero-cache/src/server/worker-dispatcher.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport UrlPattern from 'url-pattern';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {h32} from '../../../shared/src/hash.ts';\nimport {getOrCreateGauge} from '../observability/metrics.ts';\nimport {RunningState} from '../services/running-state.ts';\nimport type {Service} from '../services/service.ts';\nimport type {IncomingMessageSubset} from '../types/http.ts';\nimport type {Worker} from '../types/processes.ts';\nimport {installWebSocketHandoff} from '../types/websocket-handoff.ts';\nimport {getConnectParams} from '../workers/connect-params.ts';\n\nexport class WorkerDispatcher implements Service {\n readonly id = 'worker-dispatcher';\n readonly #lc: LogContext;\n\n readonly #state = new RunningState(this.id);\n\n constructor(\n lc: LogContext,\n taskID: string,\n parent: Worker,\n syncers: Worker[],\n mutator: Worker | undefined,\n changeStreamer: Worker | undefined,\n ) {\n this.#lc = lc;\n\n function connectParams(req: IncomingMessageSubset) {\n const {headers, url: u} = req;\n const url = new URL(u ?? '', 'http://unused/');\n const path = parsePath(url);\n if (!path) {\n throw new Error(`Invalid URL: ${u}`);\n }\n const version = Number(path.version);\n if (Number.isNaN(version)) {\n throw new Error(`Invalid version: ${u}`);\n }\n const {params, error} = getConnectParams(version, url, headers);\n if (error !== null) {\n throw new Error(error);\n }\n return params;\n }\n\n const handlePush = (req: IncomingMessageSubset) => {\n assert(\n mutator !== undefined,\n 'Received a push for a custom mutation but no `push.url` was configured.',\n );\n return {payload: connectParams(req), sender: mutator};\n };\n\n let maxProtocolVersion = 0;\n getOrCreateGauge(\n 'sync',\n 'max-protocol-version',\n 'Latest sync protocol version from a connecting client',\n ).addCallback(result => {\n if (maxProtocolVersion) {\n result.observe(maxProtocolVersion);\n }\n });\n\n const handleSync = (req: IncomingMessageSubset) => {\n assert(syncers.length, 'Received a sync request with no sync workers.');\n const params = connectParams(req);\n const {clientGroupID, protocolVersion} = params;\n maxProtocolVersion = Math.max(maxProtocolVersion, protocolVersion);\n\n // Include the TaskID when hash-bucketting the client group to the sync\n // worker. This diversifies the distribution of client groups (across\n // workers) for different tasks, so that if one task sheds connections\n // from its most heavily loaded sync worker(s), those client groups will\n // be distributed uniformly across workers on the receiving task(s).\n const syncer = h32(taskID + '/' + clientGroupID) % syncers.length;\n\n lc.debug?.(`connecting ${clientGroupID} to syncer ${syncer}`);\n return {payload: params, sender: syncers[syncer]};\n };\n\n const handleChangeStream = (req: IncomingMessageSubset) => {\n // Note: The change-streamer is generally not dispatched via the main\n // port, and in particular, should *not* be accessible via that\n // port in single-node mode. However, this plumbing is maintained\n // for the purpose of allowing --lazy-startup of the\n // replication-manager as a possible future feature.\n assert(\n syncers.length === 0 && mutator === undefined,\n 'Dispatch to the change-streamer via the main port ' +\n 'is only allowed in multi-node mode',\n );\n assert(\n changeStreamer,\n 'Received a change-streamer request without a change-streamer worker',\n );\n const url = new URL(req.url ?? '', 'http://unused/');\n const path = parsePath(url);\n if (!path) {\n throw new Error(`Invalid URL: ${req.url}`);\n }\n\n return {\n payload: path.action,\n sender: changeStreamer,\n };\n };\n\n // handoff messages from this ZeroDispatcher to the appropriate worker (pool).\n installWebSocketHandoff<unknown>(\n lc,\n request => {\n const {url: u} = request;\n const url = new URL(u ?? '', 'http://unused/');\n const path = parsePath(url);\n if (!path) {\n throw new Error(`Invalid URL: ${u}`);\n }\n switch (path.worker) {\n case 'sync':\n return handleSync(request);\n case 'replication':\n return handleChangeStream(request);\n case 'mutate':\n return handlePush(request);\n default:\n throw new Error(`Invalid URL: ${u}`);\n }\n },\n parent,\n );\n }\n\n run() {\n const readyStart = Date.now();\n getOrCreateGauge('server', 'uptime', {\n description: 'Cumulative uptime, starting from when requests are served',\n unit: 's',\n }).addCallback(result => result.observe((Date.now() - readyStart) / 1000));\n\n return this.#state.stopped();\n }\n\n stop() {\n this.#state.stop(this.#lc);\n return this.#state.stopped();\n }\n}\n\nconst URL_PATTERN = new UrlPattern('(/:base)/:worker/v:version/:action');\n\nexport function parsePath(url: URL):\n | {\n base?: string;\n worker: 'sync' | 'mutate' | 'replication';\n version: string;\n action: string;\n }\n | undefined {\n // The match() returns both null and undefined.\n return URL_PATTERN.match(url.pathname) || undefined;\n} // The server allows the client to use any /:base/ path to facilitate\n// servicing requests on the same domain as the application.\n"],"mappings":";;;;;;;;AAYA,IAAa,mBAAb,MAAiD;CAC/C,KAAc;CACd;CAEA,SAAkB,IAAI,aAAa,KAAK,GAAG;CAE3C,YACE,IACA,QACA,QACA,SACA,SACA,gBACA;AACA,QAAA,KAAW;EAEX,SAAS,cAAc,KAA4B;GACjD,MAAM,EAAC,SAAS,KAAK,MAAK;GAC1B,MAAM,MAAM,IAAI,IAAI,KAAK,IAAI,iBAAiB;GAC9C,MAAM,OAAO,UAAU,IAAI;AAC3B,OAAI,CAAC,KACH,OAAM,IAAI,MAAM,gBAAgB,IAAI;GAEtC,MAAM,UAAU,OAAO,KAAK,QAAQ;AACpC,OAAI,OAAO,MAAM,QAAQ,CACvB,OAAM,IAAI,MAAM,oBAAoB,IAAI;GAE1C,MAAM,EAAC,QAAQ,UAAS,iBAAiB,SAAS,KAAK,QAAQ;AAC/D,OAAI,UAAU,KACZ,OAAM,IAAI,MAAM,MAAM;AAExB,UAAO;;EAGT,MAAM,cAAc,QAA+B;AACjD,UACE,YAAY,KAAA,GACZ,0EACD;AACD,UAAO;IAAC,SAAS,cAAc,IAAI;IAAE,QAAQ;IAAQ;;EAGvD,IAAI,qBAAqB;AACzB,mBACE,QACA,wBACA,wDACD,CAAC,aAAY,WAAU;AACtB,OAAI,mBACF,QAAO,QAAQ,mBAAmB;IAEpC;EAEF,MAAM,cAAc,QAA+B;AACjD,UAAO,QAAQ,QAAQ,gDAAgD;GACvE,MAAM,SAAS,cAAc,IAAI;GACjC,MAAM,EAAC,eAAe,oBAAmB;AACzC,wBAAqB,KAAK,IAAI,oBAAoB,gBAAgB;GAOlE,MAAM,SAAS,IAAI,SAAS,MAAM,cAAc,GAAG,QAAQ;AAE3D,MAAG,QAAQ,cAAc,cAAc,aAAa,SAAS;AAC7D,UAAO;IAAC,SAAS;IAAQ,QAAQ,QAAQ;IAAQ;;EAGnD,MAAM,sBAAsB,QAA+B;AAMzD,UACE,QAAQ,WAAW,KAAK,YAAY,KAAA,GACpC,uFAED;AACD,UACE,gBACA,sEACD;GAED,MAAM,OAAO,UADD,IAAI,IAAI,IAAI,OAAO,IAAI,iBAAiB,CACzB;AAC3B,OAAI,CAAC,KACH,OAAM,IAAI,MAAM,gBAAgB,IAAI,MAAM;AAG5C,UAAO;IACL,SAAS,KAAK;IACd,QAAQ;IACT;;AAIH,0BACE,KACA,YAAW;GACT,MAAM,EAAC,KAAK,MAAK;GAEjB,MAAM,OAAO,UADD,IAAI,IAAI,KAAK,IAAI,iBAAiB,CACnB;AAC3B,OAAI,CAAC,KACH,OAAM,IAAI,MAAM,gBAAgB,IAAI;AAEtC,WAAQ,KAAK,QAAb;IACE,KAAK,OACH,QAAO,WAAW,QAAQ;IAC5B,KAAK,cACH,QAAO,mBAAmB,QAAQ;IACpC,KAAK,SACH,QAAO,WAAW,QAAQ;IAC5B,QACE,OAAM,IAAI,MAAM,gBAAgB,IAAI;;KAG1C,OACD;;CAGH,MAAM;EACJ,MAAM,aAAa,KAAK,KAAK;AAC7B,mBAAiB,UAAU,UAAU;GACnC,aAAa;GACb,MAAM;GACP,CAAC,CAAC,aAAY,WAAU,OAAO,SAAS,KAAK,KAAK,GAAG,cAAc,IAAK,CAAC;AAE1E,SAAO,MAAA,MAAY,SAAS;;CAG9B,OAAO;AACL,QAAA,MAAY,KAAK,MAAA,GAAS;AAC1B,SAAO,MAAA,MAAY,SAAS;;;AAIhC,IAAM,cAAc,IAAI,WAAW,qCAAqC;AAExE,SAAgB,UAAU,KAOZ;AAEZ,QAAO,YAAY,MAAM,IAAI,SAAS,IAAI,KAAA"}