@rocicorp/zero 1.2.0 → 1.3.0-canary.0

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 (303) hide show
  1. package/out/analyze-query/src/bin-analyze.js +25 -25
  2. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  3. package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
  4. package/out/ast-to-zql/src/ast-to-zql.js +2 -1
  5. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  6. package/out/replicache/src/btree/node.d.ts.map +1 -1
  7. package/out/replicache/src/btree/node.js +2 -2
  8. package/out/replicache/src/btree/node.js.map +1 -1
  9. package/out/replicache/src/connection-loop.js +3 -3
  10. package/out/replicache/src/connection-loop.js.map +1 -1
  11. package/out/replicache/src/deleted-clients.d.ts +0 -4
  12. package/out/replicache/src/deleted-clients.d.ts.map +1 -1
  13. package/out/replicache/src/deleted-clients.js +1 -1
  14. package/out/replicache/src/deleted-clients.js.map +1 -1
  15. package/out/replicache/src/hash.d.ts.map +1 -1
  16. package/out/replicache/src/hash.js.map +1 -1
  17. package/out/replicache/src/process-scheduler.d.ts.map +1 -1
  18. package/out/replicache/src/process-scheduler.js.map +1 -1
  19. package/out/replicache/src/request-idle.js +1 -1
  20. package/out/replicache/src/request-idle.js.map +1 -1
  21. package/out/replicache/src/sync/patch.d.ts +1 -1
  22. package/out/replicache/src/sync/patch.d.ts.map +1 -1
  23. package/out/replicache/src/sync/patch.js +1 -1
  24. package/out/replicache/src/sync/patch.js.map +1 -1
  25. package/out/shared/src/arrays.d.ts.map +1 -1
  26. package/out/shared/src/arrays.js +1 -2
  27. package/out/shared/src/arrays.js.map +1 -1
  28. package/out/shared/src/bigint-json.js +1 -1
  29. package/out/shared/src/bigint-json.js.map +1 -1
  30. package/out/shared/src/btree-set.js +1 -1
  31. package/out/shared/src/btree-set.js.map +1 -1
  32. package/out/shared/src/iterables.d.ts +7 -0
  33. package/out/shared/src/iterables.d.ts.map +1 -1
  34. package/out/shared/src/iterables.js +10 -1
  35. package/out/shared/src/iterables.js.map +1 -1
  36. package/out/shared/src/logging.d.ts.map +1 -1
  37. package/out/shared/src/logging.js +10 -9
  38. package/out/shared/src/logging.js.map +1 -1
  39. package/out/shared/src/options.js +1 -1
  40. package/out/shared/src/options.js.map +1 -1
  41. package/out/shared/src/sorted-entries.d.ts +2 -0
  42. package/out/shared/src/sorted-entries.d.ts.map +1 -0
  43. package/out/shared/src/sorted-entries.js +9 -0
  44. package/out/shared/src/sorted-entries.js.map +1 -0
  45. package/out/shared/src/tdigest-schema.d.ts.map +1 -1
  46. package/out/shared/src/tdigest-schema.js.map +1 -1
  47. package/out/shared/src/tdigest.d.ts.map +1 -1
  48. package/out/shared/src/tdigest.js +7 -7
  49. package/out/shared/src/tdigest.js.map +1 -1
  50. package/out/shared/src/valita.d.ts.map +1 -1
  51. package/out/shared/src/valita.js +1 -1
  52. package/out/shared/src/valita.js.map +1 -1
  53. package/out/z2s/src/sql.d.ts +2 -2
  54. package/out/z2s/src/sql.d.ts.map +1 -1
  55. package/out/z2s/src/sql.js +3 -3
  56. package/out/z2s/src/sql.js.map +1 -1
  57. package/out/zero/package.js +6 -7
  58. package/out/zero/package.js.map +1 -1
  59. package/out/zero/src/pg.js +1 -1
  60. package/out/zero/src/server.js +1 -1
  61. package/out/zero-cache/src/auth/auth.d.ts +8 -26
  62. package/out/zero-cache/src/auth/auth.d.ts.map +1 -1
  63. package/out/zero-cache/src/auth/auth.js +57 -82
  64. package/out/zero-cache/src/auth/auth.js.map +1 -1
  65. package/out/zero-cache/src/auth/jwt.d.ts +3 -3
  66. package/out/zero-cache/src/auth/jwt.d.ts.map +1 -1
  67. package/out/zero-cache/src/auth/jwt.js.map +1 -1
  68. package/out/zero-cache/src/auth/load-permissions.js +1 -1
  69. package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
  70. package/out/zero-cache/src/config/zero-config.d.ts +38 -2
  71. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  72. package/out/zero-cache/src/config/zero-config.js +56 -1
  73. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  74. package/out/zero-cache/src/custom/fetch.d.ts +2 -9
  75. package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
  76. package/out/zero-cache/src/custom/fetch.js +11 -4
  77. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  78. package/out/zero-cache/src/custom-queries/transform-query.d.ts +20 -9
  79. package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +1 -1
  80. package/out/zero-cache/src/custom-queries/transform-query.js +74 -37
  81. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  82. package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
  83. package/out/zero-cache/src/db/migration-lite.js +1 -1
  84. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  85. package/out/zero-cache/src/db/migration.d.ts.map +1 -1
  86. package/out/zero-cache/src/db/migration.js +1 -1
  87. package/out/zero-cache/src/db/migration.js.map +1 -1
  88. package/out/zero-cache/src/db/pg-copy-binary.d.ts +101 -0
  89. package/out/zero-cache/src/db/pg-copy-binary.d.ts.map +1 -0
  90. package/out/zero-cache/src/db/pg-copy-binary.js +381 -0
  91. package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -0
  92. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  93. package/out/zero-cache/src/db/transaction-pool.js +3 -0
  94. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  95. package/out/zero-cache/src/db/warmup.d.ts.map +1 -1
  96. package/out/zero-cache/src/db/warmup.js +3 -1
  97. package/out/zero-cache/src/db/warmup.js.map +1 -1
  98. package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
  99. package/out/zero-cache/src/server/anonymous-otel-start.js +2 -1
  100. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  101. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  102. package/out/zero-cache/src/server/change-streamer.js +5 -2
  103. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  104. package/out/zero-cache/src/server/inspector-delegate.d.ts +2 -2
  105. package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
  106. package/out/zero-cache/src/server/inspector-delegate.js +4 -4
  107. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  108. package/out/zero-cache/src/server/main.js +1 -1
  109. package/out/zero-cache/src/server/main.js.map +1 -1
  110. package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
  111. package/out/zero-cache/src/server/reaper.js +4 -1
  112. package/out/zero-cache/src/server/reaper.js.map +1 -1
  113. package/out/zero-cache/src/server/runner/run-worker.js +1 -1
  114. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  115. package/out/zero-cache/src/server/syncer.js +41 -20
  116. package/out/zero-cache/src/server/syncer.js.map +1 -1
  117. package/out/zero-cache/src/server/worker-urls.d.ts.map +1 -1
  118. package/out/zero-cache/src/server/worker-urls.js +2 -1
  119. package/out/zero-cache/src/server/worker-urls.js.map +1 -1
  120. package/out/zero-cache/src/services/change-source/change-source.d.ts +4 -0
  121. package/out/zero-cache/src/services/change-source/change-source.d.ts.map +1 -1
  122. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
  123. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +3 -2
  124. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  125. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
  126. package/out/zero-cache/src/services/change-source/custom/change-source.js +5 -2
  127. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  128. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  129. package/out/zero-cache/src/services/change-source/pg/change-source.js +13 -4
  130. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  131. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +3 -1
  132. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  133. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +91 -9
  134. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  135. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +2 -2
  136. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  137. package/out/zero-cache/src/services/change-streamer/broadcast.js +1 -1
  138. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  139. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +3 -0
  140. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  141. package/out/zero-cache/src/services/life-cycle.d.ts +5 -4
  142. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  143. package/out/zero-cache/src/services/life-cycle.js +11 -11
  144. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  145. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  146. package/out/zero-cache/src/services/litestream/commands.js +5 -5
  147. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  148. package/out/zero-cache/src/services/mutagen/pusher.d.ts +20 -20
  149. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  150. package/out/zero-cache/src/services/mutagen/pusher.js +91 -104
  151. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  152. package/out/zero-cache/src/services/replicator/change-processor.js +1 -1
  153. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  154. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  155. package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.map +1 -1
  156. package/out/zero-cache/src/services/view-syncer/client-schema.js +4 -3
  157. package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
  158. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +168 -0
  159. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -0
  160. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js +385 -0
  161. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -0
  162. package/out/zero-cache/src/services/view-syncer/cvr-store.js +2 -2
  163. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  164. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  165. package/out/zero-cache/src/services/view-syncer/cvr.js +5 -4
  166. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  167. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +2 -3
  168. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
  169. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +3 -3
  170. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  171. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  172. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +5 -3
  173. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  174. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
  175. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +13 -7
  176. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  177. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +3 -1
  178. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  179. package/out/zero-cache/src/services/view-syncer/snapshotter.js +6 -9
  180. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  181. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +24 -26
  182. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  183. package/out/zero-cache/src/services/view-syncer/view-syncer.js +236 -124
  184. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  185. package/out/zero-cache/src/types/lite.d.ts.map +1 -1
  186. package/out/zero-cache/src/types/lite.js +3 -2
  187. package/out/zero-cache/src/types/lite.js.map +1 -1
  188. package/out/zero-cache/src/types/pg-types.js +4 -1
  189. package/out/zero-cache/src/types/pg-types.js.map +1 -1
  190. package/out/zero-cache/src/types/pg-versions.d.ts +3 -0
  191. package/out/zero-cache/src/types/pg-versions.d.ts.map +1 -0
  192. package/out/zero-cache/src/types/pg-versions.js +7 -0
  193. package/out/zero-cache/src/types/pg-versions.js.map +1 -0
  194. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  195. package/out/zero-cache/src/types/pg.js +6 -1
  196. package/out/zero-cache/src/types/pg.js.map +1 -1
  197. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  198. package/out/zero-cache/src/types/subscription.js +2 -2
  199. package/out/zero-cache/src/types/subscription.js.map +1 -1
  200. package/out/zero-cache/src/workers/connect-params.d.ts +1 -1
  201. package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
  202. package/out/zero-cache/src/workers/connect-params.js +1 -1
  203. package/out/zero-cache/src/workers/connect-params.js.map +1 -1
  204. package/out/zero-cache/src/workers/connection.js +2 -2
  205. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +2 -1
  206. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
  207. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +64 -38
  208. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  209. package/out/zero-cache/src/workers/syncer.d.ts +2 -1
  210. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  211. package/out/zero-cache/src/workers/syncer.js +70 -31
  212. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  213. package/out/zero-client/src/client/connection.d.ts +4 -4
  214. package/out/zero-client/src/client/connection.d.ts.map +1 -1
  215. package/out/zero-client/src/client/connection.js.map +1 -1
  216. package/out/zero-client/src/client/http-string.d.ts.map +1 -1
  217. package/out/zero-client/src/client/http-string.js.map +1 -1
  218. package/out/zero-client/src/client/metrics.d.ts.map +1 -1
  219. package/out/zero-client/src/client/metrics.js +2 -1
  220. package/out/zero-client/src/client/metrics.js.map +1 -1
  221. package/out/zero-client/src/client/options.d.ts +34 -5
  222. package/out/zero-client/src/client/options.d.ts.map +1 -1
  223. package/out/zero-client/src/client/options.js.map +1 -1
  224. package/out/zero-client/src/client/server-option.js +1 -1
  225. package/out/zero-client/src/client/server-option.js.map +1 -1
  226. package/out/zero-client/src/client/version.js +1 -1
  227. package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
  228. package/out/zero-client/src/client/zero-poke-handler.js +1 -1
  229. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
  230. package/out/zero-client/src/client/zero.d.ts +4 -3
  231. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  232. package/out/zero-client/src/client/zero.js +33 -11
  233. package/out/zero-client/src/client/zero.js.map +1 -1
  234. package/out/zero-pg/src/mod.js +1 -1
  235. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  236. package/out/zero-protocol/src/ast.js.map +1 -1
  237. package/out/zero-protocol/src/change-desired-queries.d.ts +4 -0
  238. package/out/zero-protocol/src/change-desired-queries.d.ts.map +1 -1
  239. package/out/zero-protocol/src/change-desired-queries.js +4 -1
  240. package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
  241. package/out/zero-protocol/src/connect.d.ts +4 -0
  242. package/out/zero-protocol/src/connect.d.ts.map +1 -1
  243. package/out/zero-protocol/src/connect.js +2 -1
  244. package/out/zero-protocol/src/connect.js.map +1 -1
  245. package/out/zero-protocol/src/primary-key.d.ts.map +1 -1
  246. package/out/zero-protocol/src/primary-key.js.map +1 -1
  247. package/out/zero-protocol/src/protocol-version.d.ts +1 -1
  248. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  249. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  250. package/out/zero-protocol/src/push.d.ts +4 -0
  251. package/out/zero-protocol/src/push.d.ts.map +1 -1
  252. package/out/zero-protocol/src/push.js +2 -1
  253. package/out/zero-protocol/src/push.js.map +1 -1
  254. package/out/zero-protocol/src/up.d.ts +3 -0
  255. package/out/zero-protocol/src/up.d.ts.map +1 -1
  256. package/out/zero-react/src/zero-provider.d.ts.map +1 -1
  257. package/out/zero-react/src/zero-provider.js +11 -5
  258. package/out/zero-react/src/zero-provider.js.map +1 -1
  259. package/out/zero-schema/src/name-mapper.js +1 -1
  260. package/out/zero-schema/src/name-mapper.js.map +1 -1
  261. package/out/zero-server/src/mod.js +1 -1
  262. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  263. package/out/zero-server/src/process-mutations.js +2 -1
  264. package/out/zero-server/src/process-mutations.js.map +1 -1
  265. package/out/zero-server/src/push-processor.d.ts +1 -0
  266. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  267. package/out/zero-server/src/push-processor.js +3 -2
  268. package/out/zero-server/src/push-processor.js.map +1 -1
  269. package/out/zero-solid/src/use-zero.d.ts.map +1 -1
  270. package/out/zero-solid/src/use-zero.js +8 -9
  271. package/out/zero-solid/src/use-zero.js.map +1 -1
  272. package/out/zql/src/builder/like.js +2 -1
  273. package/out/zql/src/builder/like.js.map +1 -1
  274. package/out/zql/src/ivm/data.d.ts.map +1 -1
  275. package/out/zql/src/ivm/data.js +6 -15
  276. package/out/zql/src/ivm/data.js.map +1 -1
  277. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  278. package/out/zql/src/ivm/memory-source.js +14 -8
  279. package/out/zql/src/ivm/memory-source.js.map +1 -1
  280. package/out/zql/src/query/complete-ordering.js +1 -1
  281. package/out/zql/src/query/complete-ordering.js.map +1 -1
  282. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  283. package/out/zql/src/query/query-impl.js +2 -2
  284. package/out/zql/src/query/query-impl.js.map +1 -1
  285. package/out/zql/src/query/query-registry.d.ts.map +1 -1
  286. package/out/zql/src/query/query-registry.js +2 -1
  287. package/out/zql/src/query/query-registry.js.map +1 -1
  288. package/out/zql/src/query/ttl.js +1 -1
  289. package/out/zql/src/query/ttl.js.map +1 -1
  290. package/out/zqlite/src/internal/sql.d.ts +2 -2
  291. package/out/zqlite/src/internal/sql.d.ts.map +1 -1
  292. package/out/zqlite/src/internal/sql.js +1 -2
  293. package/out/zqlite/src/internal/sql.js.map +1 -1
  294. package/out/zqlite/src/sqlite-cost-model.d.ts +1 -1
  295. package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
  296. package/out/zqlite/src/sqlite-cost-model.js +1 -1
  297. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  298. package/out/zqlite/src/sqlite-stat-fanout.js +1 -1
  299. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  300. package/out/zqlite/src/table-source.d.ts.map +1 -1
  301. package/out/zqlite/src/table-source.js +8 -12
  302. package/out/zqlite/src/table-source.js.map +1 -1
  303. package/package.json +6 -7
@@ -1 +1 @@
1
- {"version":3,"file":"lite.js","names":[],"sources":["../../../../../zero-cache/src/types/lite.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport {stringify, type JSONValue} from '../../../shared/src/bigint-json.ts';\nimport type {\n SchemaValue,\n ValueType,\n} from '../../../zero-schema/src/table-schema.ts';\nimport type {ColumnSpec, LiteTableSpec} from '../db/specs.ts';\nimport {dataTypeToZqlValueType as upstreamDataTypeToZqlValueType} from './pg-data-type.ts';\nimport type {PostgresValueType} from './pg.ts';\nimport type {RowValue} from './row-key.ts';\n\n/** Javascript value types supported by better-sqlite3. */\nexport type LiteValueType = number | bigint | string | null | Uint8Array;\n\nexport type LiteRow = Readonly<Record<string, LiteValueType>>;\nexport type LiteRowKey = LiteRow; // just for API readability\n\nfunction columnType(col: string, table: LiteTableSpec) {\n const spec = table.columns[col];\n assert(spec, `Unknown column ${col} in table ${table.name}`);\n return spec.dataType;\n}\n\nexport const JSON_STRINGIFIED = 's';\nexport const JSON_PARSED = 'p';\n\nexport type JSONFormat = typeof JSON_STRINGIFIED | typeof JSON_PARSED;\n\n/**\n * Creates a LiteRow from the supplied RowValue. A copy of the `row`\n * is made only if a value conversion is performed.\n */\nexport function liteRow(\n row: RowValue,\n table: LiteTableSpec,\n jsonFormat: JSONFormat,\n): {row: LiteRow; numCols: number} {\n let copyNeeded = false;\n let numCols = 0;\n\n for (const key in row) {\n numCols++;\n const val = row[key];\n const liteVal = liteValue(val, columnType(key, table), jsonFormat);\n if (val !== liteVal) {\n copyNeeded = true;\n break;\n }\n }\n if (!copyNeeded) {\n return {row: row as unknown as LiteRow, numCols};\n }\n // Slow path for when a conversion is needed.\n numCols = 0;\n const converted: Record<string, LiteValueType> = {};\n for (const key in row) {\n numCols++;\n converted[key] = liteValue(row[key], columnType(key, table), jsonFormat);\n }\n return {row: converted, numCols};\n}\n\n/**\n * Postgres values types that are supported by SQLite are stored as-is.\n * This includes Uint8Arrays for the `bytea` / `BLOB` type.\n * * `boolean` values are converted to `0` or `1` integers.\n * * `PreciseDate` values are converted to epoch microseconds.\n * * JSON and Array values are stored as `JSON.stringify()` strings.\n *\n * Note that this currently does not handle the `bytea[]` type, but that's\n * already a pretty questionable type.\n */\nexport function liteValue(\n val: PostgresValueType,\n pgType: string,\n jsonFormat: JSONFormat,\n): LiteValueType {\n if (val instanceof Uint8Array || val === null) {\n return val;\n }\n const valueType = liteTypeToZqlValueType(pgType);\n if (valueType === 'json') {\n if (jsonFormat === JSON_STRINGIFIED && typeof val === 'string') {\n // JSON and JSONB values are already strings if the JSON was not parsed.\n return val;\n }\n // Non-JSON/JSONB values will always appear as objects / arrays.\n return stringify(val);\n }\n const obj = toLiteValue(val);\n return obj && typeof obj === 'object' ? stringify(obj) : obj;\n}\n\nfunction toLiteValue(val: JSONValue): Exclude<JSONValue, boolean> {\n switch (typeof val) {\n case 'string':\n case 'number':\n case 'bigint':\n return val;\n case 'boolean':\n return val ? 1 : 0;\n }\n if (val === null) {\n return val;\n }\n if (Array.isArray(val)) {\n return val.map(v => toLiteValue(v));\n }\n assert(\n val.constructor?.name === 'Object',\n `Unhandled object type ${val.constructor?.name}`,\n );\n return val; // JSON\n}\n\nexport function mapLiteDataTypeToZqlSchemaValue(\n liteDataType: LiteTypeString,\n): SchemaValue {\n return {type: mapLiteDataTypeToZqlValueType(liteDataType)};\n}\n\nfunction mapLiteDataTypeToZqlValueType(dataType: LiteTypeString): ValueType {\n const type = liteTypeToZqlValueType(dataType);\n if (type === undefined) {\n throw new Error(`Unsupported data type ${dataType}`);\n }\n return type;\n}\n\n// Note: Includes the \"TEXT\" substring for SQLite type affinity\nconst TEXT_ENUM_ATTRIBUTE = '|TEXT_ENUM';\nconst NOT_NULL_ATTRIBUTE = '|NOT_NULL';\nexport const TEXT_ARRAY_ATTRIBUTE = '|TEXT_ARRAY';\n\n/**\n * The `LiteTypeString` utilizes SQLite's loose type system to encode\n * auxiliary information about the upstream column (e.g. type and\n * constraints) that does not necessarily affect how SQLite handles the data,\n * but nonetheless determines how higher level logic handles the data.\n *\n * The format of the type string is the original upstream type, followed\n * by any number of attributes, each of which begins with the `|` character.\n * The current list of attributes are:\n * * `|NOT_NULL` to indicate that the upstream column does not allow nulls\n * * `|TEXT_ENUM` to indicate an enum that should be treated as a string\n * * `|TEXT_ARRAY` to indicate an array\n *\n * Examples:\n * * `int8`\n * * `int8|NOT_NULL`\n * * `timestamp with time zone`\n * * `timestamp with time zone|NOT_NULL`\n * * `nomz|TEXT_ENUM`\n * * `nomz|NOT_NULL|TEXT_ENUM`\n * * `int8[]` - Legacy (read support)\n * * `int8[]|TEXT_ARRAY`\n * * `int8|TEXT_ARRAY[]` - Legacy (read support)\n * * `int8[]|TEXT_ARRAY[]` - Legacy (read support)\n * * `int8|NOT_NULL[]` - Legacy (read support)\n * * `nomz[]|TEXT_ENUM|TEXT_ARRAY`\n * * `nomz|TEXT_ENUM[]` - Legacy (read support)\n * * `nomz|TEXT_ENUM|TEXT_ARRAY[]` - Legacy (read support)\n */\nexport type LiteTypeString = string;\n\n/**\n * Formats a {@link LiteTypeString}.\n */\nexport function liteTypeString(\n upstreamDataType: string,\n notNull: boolean | null | undefined,\n textEnum: boolean,\n textArray: boolean,\n): LiteTypeString {\n let typeString = upstreamDataType;\n assert(typeString.indexOf('|') === -1, 'Upstream type should not contain |');\n if (notNull) {\n typeString += NOT_NULL_ATTRIBUTE;\n }\n if (textEnum) {\n typeString += TEXT_ENUM_ATTRIBUTE;\n }\n if (textArray) {\n typeString += TEXT_ARRAY_ATTRIBUTE;\n }\n return typeString;\n}\n\nexport function upstreamDataType(liteTypeString: LiteTypeString) {\n const delim = liteTypeString.indexOf('|');\n return delim > 0 ? liteTypeString.substring(0, delim) : liteTypeString;\n}\n\nexport function nullableUpstream(liteTypeString: LiteTypeString) {\n return !liteTypeString.includes(NOT_NULL_ATTRIBUTE);\n}\n\n/**\n * Returns the value type for the `pgDataType` if it is supported by ZQL.\n * (Note that `pgDataType` values are stored as-is in the SQLite column defs).\n *\n * For types not supported by ZQL, returns `undefined`.\n */\nexport function liteTypeToZqlValueType(\n liteTypeString: LiteTypeString,\n): ValueType | undefined {\n return upstreamDataTypeToZqlValueType(\n upstreamDataType(liteTypeString).toLowerCase(),\n liteTypeString.includes(TEXT_ENUM_ATTRIBUTE),\n isArray(liteTypeString),\n );\n}\n\nexport function isEnum(liteTypeString: LiteTypeString) {\n return liteTypeString.includes(TEXT_ENUM_ATTRIBUTE);\n}\n\nexport function isArray(liteTypeString: LiteTypeString) {\n return (\n liteTypeString.includes(TEXT_ARRAY_ATTRIBUTE) ||\n // Before we added `|TEXT_ARRAY`, we just used `[]` suffix to indicate arrays.\n liteTypeString.includes('[]')\n );\n}\n\nexport function assertValidLiteColumnSpec(spec: ColumnSpec) {\n const {dataType} = spec;\n assert(\n dataType.includes(TEXT_ARRAY_ATTRIBUTE) === dataType.includes('[]'),\n () =>\n `TEXT_ARRAY_ATTRIBUTE and [] must be consistent in dataType: ${dataType}`,\n );\n assert(\n dataType.includes('[]') === (spec.elemPgTypeClass !== null),\n () =>\n `[] in dataType (${dataType}) must match elemPgTypeClass presence (${spec.elemPgTypeClass})`,\n );\n\n // and no [] after |\n assert(!/^.+\\|.*\\[\\]/.test(dataType), `Invalid dataType ${dataType}`);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"lite.js","names":[],"sources":["../../../../../zero-cache/src/types/lite.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport {stringify, type JSONValue} from '../../../shared/src/bigint-json.ts';\nimport type {\n SchemaValue,\n ValueType,\n} from '../../../zero-schema/src/table-schema.ts';\nimport type {ColumnSpec, LiteTableSpec} from '../db/specs.ts';\nimport {dataTypeToZqlValueType as upstreamDataTypeToZqlValueType} from './pg-data-type.ts';\nimport type {PostgresValueType} from './pg.ts';\nimport type {RowValue} from './row-key.ts';\n\n/** Javascript value types supported by better-sqlite3. */\nexport type LiteValueType = number | bigint | string | null | Uint8Array;\n\nexport type LiteRow = Readonly<Record<string, LiteValueType>>;\nexport type LiteRowKey = LiteRow; // just for API readability\n\nfunction columnType(col: string, table: LiteTableSpec) {\n const spec = table.columns[col];\n assert(spec, `Unknown column ${col} in table ${table.name}`);\n return spec.dataType;\n}\n\nexport const JSON_STRINGIFIED = 's';\nexport const JSON_PARSED = 'p';\n\nexport type JSONFormat = typeof JSON_STRINGIFIED | typeof JSON_PARSED;\n\n/**\n * Creates a LiteRow from the supplied RowValue. A copy of the `row`\n * is made only if a value conversion is performed.\n */\nexport function liteRow(\n row: RowValue,\n table: LiteTableSpec,\n jsonFormat: JSONFormat,\n): {row: LiteRow; numCols: number} {\n let copyNeeded = false;\n let numCols = 0;\n\n for (const key in row) {\n numCols++;\n const val = row[key];\n const liteVal = liteValue(val, columnType(key, table), jsonFormat);\n if (val !== liteVal) {\n copyNeeded = true;\n break;\n }\n }\n if (!copyNeeded) {\n return {row: row as unknown as LiteRow, numCols};\n }\n // Slow path for when a conversion is needed.\n numCols = 0;\n const converted: Record<string, LiteValueType> = {};\n for (const key in row) {\n numCols++;\n converted[key] = liteValue(row[key], columnType(key, table), jsonFormat);\n }\n return {row: converted, numCols};\n}\n\n/**\n * Postgres values types that are supported by SQLite are stored as-is.\n * This includes Uint8Arrays for the `bytea` / `BLOB` type.\n * * `boolean` values are converted to `0` or `1` integers.\n * * `PreciseDate` values are converted to epoch microseconds.\n * * JSON and Array values are stored as `JSON.stringify()` strings.\n *\n * Note that this currently does not handle the `bytea[]` type, but that's\n * already a pretty questionable type.\n */\nexport function liteValue(\n val: PostgresValueType,\n pgType: string,\n jsonFormat: JSONFormat,\n): LiteValueType {\n if (val instanceof Uint8Array || val === null) {\n return val;\n }\n const valueType = liteTypeToZqlValueType(pgType);\n if (valueType === 'json') {\n if (jsonFormat === JSON_STRINGIFIED && typeof val === 'string') {\n // JSON and JSONB values are already strings if the JSON was not parsed.\n return val;\n }\n // Non-JSON/JSONB values will always appear as objects / arrays.\n return stringify(val);\n }\n const obj = toLiteValue(val);\n return obj && typeof obj === 'object' ? stringify(obj) : obj;\n}\n\nfunction toLiteValue(val: JSONValue): Exclude<JSONValue, boolean> {\n switch (typeof val) {\n case 'string':\n case 'number':\n case 'bigint':\n return val;\n case 'boolean':\n return val ? 1 : 0;\n }\n if (val === null) {\n return val;\n }\n if (Array.isArray(val)) {\n return val.map(v => toLiteValue(v));\n }\n assert(\n val.constructor?.name === 'Object',\n `Unhandled object type ${val.constructor?.name}`,\n );\n return val; // JSON\n}\n\nexport function mapLiteDataTypeToZqlSchemaValue(\n liteDataType: LiteTypeString,\n): SchemaValue {\n return {type: mapLiteDataTypeToZqlValueType(liteDataType)};\n}\n\nfunction mapLiteDataTypeToZqlValueType(dataType: LiteTypeString): ValueType {\n const type = liteTypeToZqlValueType(dataType);\n if (type === undefined) {\n throw new Error(`Unsupported data type ${dataType}`);\n }\n return type;\n}\n\n// Note: Includes the \"TEXT\" substring for SQLite type affinity\nconst TEXT_ENUM_ATTRIBUTE = '|TEXT_ENUM';\nconst NOT_NULL_ATTRIBUTE = '|NOT_NULL';\nexport const TEXT_ARRAY_ATTRIBUTE = '|TEXT_ARRAY';\n\n/**\n * The `LiteTypeString` utilizes SQLite's loose type system to encode\n * auxiliary information about the upstream column (e.g. type and\n * constraints) that does not necessarily affect how SQLite handles the data,\n * but nonetheless determines how higher level logic handles the data.\n *\n * The format of the type string is the original upstream type, followed\n * by any number of attributes, each of which begins with the `|` character.\n * The current list of attributes are:\n * * `|NOT_NULL` to indicate that the upstream column does not allow nulls\n * * `|TEXT_ENUM` to indicate an enum that should be treated as a string\n * * `|TEXT_ARRAY` to indicate an array\n *\n * Examples:\n * * `int8`\n * * `int8|NOT_NULL`\n * * `timestamp with time zone`\n * * `timestamp with time zone|NOT_NULL`\n * * `nomz|TEXT_ENUM`\n * * `nomz|NOT_NULL|TEXT_ENUM`\n * * `int8[]` - Legacy (read support)\n * * `int8[]|TEXT_ARRAY`\n * * `int8|TEXT_ARRAY[]` - Legacy (read support)\n * * `int8[]|TEXT_ARRAY[]` - Legacy (read support)\n * * `int8|NOT_NULL[]` - Legacy (read support)\n * * `nomz[]|TEXT_ENUM|TEXT_ARRAY`\n * * `nomz|TEXT_ENUM[]` - Legacy (read support)\n * * `nomz|TEXT_ENUM|TEXT_ARRAY[]` - Legacy (read support)\n */\nexport type LiteTypeString = string;\n\n/**\n * Formats a {@link LiteTypeString}.\n */\nexport function liteTypeString(\n upstreamDataType: string,\n notNull: boolean | null | undefined,\n textEnum: boolean,\n textArray: boolean,\n): LiteTypeString {\n let typeString = upstreamDataType;\n assert(!typeString.includes('|'), 'Upstream type should not contain |');\n if (notNull) {\n typeString += NOT_NULL_ATTRIBUTE;\n }\n if (textEnum) {\n typeString += TEXT_ENUM_ATTRIBUTE;\n }\n if (textArray) {\n typeString += TEXT_ARRAY_ATTRIBUTE;\n }\n return typeString;\n}\n\nexport function upstreamDataType(liteTypeString: LiteTypeString) {\n const delim = liteTypeString.indexOf('|');\n return delim > 0 ? liteTypeString.substring(0, delim) : liteTypeString;\n}\n\nexport function nullableUpstream(liteTypeString: LiteTypeString) {\n return !liteTypeString.includes(NOT_NULL_ATTRIBUTE);\n}\n\n/**\n * Returns the value type for the `pgDataType` if it is supported by ZQL.\n * (Note that `pgDataType` values are stored as-is in the SQLite column defs).\n *\n * For types not supported by ZQL, returns `undefined`.\n */\nexport function liteTypeToZqlValueType(\n liteTypeString: LiteTypeString,\n): ValueType | undefined {\n return upstreamDataTypeToZqlValueType(\n upstreamDataType(liteTypeString).toLowerCase(),\n liteTypeString.includes(TEXT_ENUM_ATTRIBUTE),\n isArray(liteTypeString),\n );\n}\n\nexport function isEnum(liteTypeString: LiteTypeString) {\n return liteTypeString.includes(TEXT_ENUM_ATTRIBUTE);\n}\n\nexport function isArray(liteTypeString: LiteTypeString) {\n return (\n liteTypeString.includes(TEXT_ARRAY_ATTRIBUTE) ||\n // Before we added `|TEXT_ARRAY`, we just used `[]` suffix to indicate arrays.\n liteTypeString.includes('[]')\n );\n}\n\nconst invalidDataTypeRe = /^.+\\|.*\\[\\]/;\n\nexport function assertValidLiteColumnSpec(spec: ColumnSpec) {\n const {dataType} = spec;\n assert(\n dataType.includes(TEXT_ARRAY_ATTRIBUTE) === dataType.includes('[]'),\n () =>\n `TEXT_ARRAY_ATTRIBUTE and [] must be consistent in dataType: ${dataType}`,\n );\n assert(\n dataType.includes('[]') === (spec.elemPgTypeClass !== null),\n () =>\n `[] in dataType (${dataType}) must match elemPgTypeClass presence (${spec.elemPgTypeClass})`,\n );\n\n // and no [] after |\n assert(!invalidDataTypeRe.test(dataType), `Invalid dataType ${dataType}`);\n}\n"],"mappings":"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"}
@@ -1,12 +1,15 @@
1
1
  //#region ../zero-cache/src/types/pg-types.ts
2
+ var BPCHAR = 1042;
3
+ var VARCHAR = 1043;
2
4
  var DATE = 1082;
3
5
  var TIME = 1083;
4
6
  var TIMESTAMP = 1114;
5
7
  var TIMESTAMPTZ = 1184;
6
8
  var TIMETZ = 1266;
7
9
  var NUMERIC = 1700;
10
+ var UUID = 2950;
8
11
  var JSONB = 3802;
9
12
  //#endregion
10
- export { DATE, JSONB, NUMERIC, TIME, TIMESTAMP, TIMESTAMPTZ, TIMETZ };
13
+ export { BPCHAR, DATE, JSONB, NUMERIC, TIME, TIMESTAMP, TIMESTAMPTZ, TIMETZ, UUID, VARCHAR };
11
14
 
12
15
  //# sourceMappingURL=pg-types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pg-types.js","names":[],"sources":["../../../../../zero-cache/src/types/pg-types.ts"],"sourcesContent":["// Forked from https=//github.com/brianc/node-pg-types/blob/5b26b826466cff4a9092b8c9e31960fe293ef3d9/lib/builtins.js\n\n/**\n * Following query was used to generate this file=\n\n SELECT json_object_agg(UPPER(PT.typname), PT.oid==int4 ORDER BY pt.oid)\n FROM pg_type PT\n WHERE typnamespace = (SELECT pgn.oid FROM pg_namespace pgn WHERE nspname = 'pg_catalog') -- Take only builting Postgres types with stable OID (extension types are not guaranted to be stable)\n AND typtype = 'b' -- Only basic types\n AND typelem = 0 -- Ignore aliases\n AND typisdefined -- Ignore undefined types\n */\n\nexport const BOOL = 16;\nexport const BYTEA = 17;\nexport const CHAR = 18;\nexport const INT8 = 20;\nexport const INT2 = 21;\nexport const INT4 = 23;\nexport const REGPROC = 24;\nexport const TEXT = 25;\nexport const OID = 26;\nexport const TID = 27;\nexport const XID = 28;\nexport const CID = 29;\nexport const JSON = 114;\nexport const XML = 142;\nexport const PG_NODE_TREE = 194;\nexport const SMGR = 210;\nexport const PATH = 602;\nexport const POLYGON = 604;\nexport const CIDR = 650;\nexport const FLOAT4 = 700;\nexport const FLOAT8 = 701;\nexport const ABSTIME = 702;\nexport const RELTIME = 703;\nexport const TINTERVAL = 704;\nexport const CIRCLE = 718;\nexport const MACADDR8 = 774;\nexport const MONEY = 790;\nexport const MACADDR = 829;\nexport const INET = 869;\nexport const ACLITEM = 1033;\nexport const BPCHAR = 1042;\nexport const VARCHAR = 1043;\nexport const DATE = 1082;\nexport const TIME = 1083;\nexport const TIMESTAMP = 1114;\nexport const TIMESTAMPTZ = 1184;\nexport const INTERVAL = 1186;\nexport const TIMETZ = 1266;\nexport const BIT = 1560;\nexport const VARBIT = 1562;\nexport const NUMERIC = 1700;\nexport const REFCURSOR = 1790;\nexport const REGPROCEDURE = 2202;\nexport const REGOPER = 2203;\nexport const REGOPERATOR = 2204;\nexport const REGCLASS = 2205;\nexport const REGTYPE = 2206;\nexport const UUID = 2950;\nexport const TXID_SNAPSHOT = 2970;\nexport const PG_LSN = 3220;\nexport const PG_NDISTINCT = 3361;\nexport const PG_DEPENDENCIES = 3402;\nexport const TSVECTOR = 3614;\nexport const TSQUERY = 3615;\nexport const GTSVECTOR = 3642;\nexport const REGCONFIG = 3734;\nexport const REGDICTIONARY = 3769;\nexport const JSONB = 3802;\nexport const REGNAMESPACE = 4089;\nexport const REGROLE = 4096;\n"],"mappings":";AA6CA,IAAa,OAAO;AACpB,IAAa,OAAO;AACpB,IAAa,YAAY;AACzB,IAAa,cAAc;AAE3B,IAAa,SAAS;AAGtB,IAAa,UAAU;AAiBvB,IAAa,QAAQ"}
1
+ {"version":3,"file":"pg-types.js","names":[],"sources":["../../../../../zero-cache/src/types/pg-types.ts"],"sourcesContent":["// Forked from https=//github.com/brianc/node-pg-types/blob/5b26b826466cff4a9092b8c9e31960fe293ef3d9/lib/builtins.js\n\n/**\n * Following query was used to generate this file=\n\n SELECT json_object_agg(UPPER(PT.typname), PT.oid==int4 ORDER BY pt.oid)\n FROM pg_type PT\n WHERE typnamespace = (SELECT pgn.oid FROM pg_namespace pgn WHERE nspname = 'pg_catalog') -- Take only builting Postgres types with stable OID (extension types are not guaranted to be stable)\n AND typtype = 'b' -- Only basic types\n AND typelem = 0 -- Ignore aliases\n AND typisdefined -- Ignore undefined types\n */\n\nexport const BOOL = 16;\nexport const BYTEA = 17;\nexport const CHAR = 18;\nexport const INT8 = 20;\nexport const INT2 = 21;\nexport const INT4 = 23;\nexport const REGPROC = 24;\nexport const TEXT = 25;\nexport const OID = 26;\nexport const TID = 27;\nexport const XID = 28;\nexport const CID = 29;\nexport const JSON = 114;\nexport const XML = 142;\nexport const PG_NODE_TREE = 194;\nexport const SMGR = 210;\nexport const PATH = 602;\nexport const POLYGON = 604;\nexport const CIDR = 650;\nexport const FLOAT4 = 700;\nexport const FLOAT8 = 701;\nexport const ABSTIME = 702;\nexport const RELTIME = 703;\nexport const TINTERVAL = 704;\nexport const CIRCLE = 718;\nexport const MACADDR8 = 774;\nexport const MONEY = 790;\nexport const MACADDR = 829;\nexport const INET = 869;\nexport const ACLITEM = 1033;\nexport const BPCHAR = 1042;\nexport const VARCHAR = 1043;\nexport const DATE = 1082;\nexport const TIME = 1083;\nexport const TIMESTAMP = 1114;\nexport const TIMESTAMPTZ = 1184;\nexport const INTERVAL = 1186;\nexport const TIMETZ = 1266;\nexport const BIT = 1560;\nexport const VARBIT = 1562;\nexport const NUMERIC = 1700;\nexport const REFCURSOR = 1790;\nexport const REGPROCEDURE = 2202;\nexport const REGOPER = 2203;\nexport const REGOPERATOR = 2204;\nexport const REGCLASS = 2205;\nexport const REGTYPE = 2206;\nexport const UUID = 2950;\nexport const TXID_SNAPSHOT = 2970;\nexport const PG_LSN = 3220;\nexport const PG_NDISTINCT = 3361;\nexport const PG_DEPENDENCIES = 3402;\nexport const TSVECTOR = 3614;\nexport const TSQUERY = 3615;\nexport const GTSVECTOR = 3642;\nexport const REGCONFIG = 3734;\nexport const REGDICTIONARY = 3769;\nexport const JSONB = 3802;\nexport const REGNAMESPACE = 4089;\nexport const REGROLE = 4096;\n"],"mappings":";AA2CA,IAAa,SAAS;AACtB,IAAa,UAAU;AACvB,IAAa,OAAO;AACpB,IAAa,OAAO;AACpB,IAAa,YAAY;AACzB,IAAa,cAAc;AAE3B,IAAa,SAAS;AAGtB,IAAa,UAAU;AAOvB,IAAa,OAAO;AAUpB,IAAa,QAAQ"}
@@ -0,0 +1,3 @@
1
+ export declare const PG_15 = 150000;
2
+ export declare const PG_17 = 170000;
3
+ //# sourceMappingURL=pg-versions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pg-versions.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/types/pg-versions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,SAAS,CAAC;AAC5B,eAAO,MAAM,KAAK,SAAS,CAAC"}
@@ -0,0 +1,7 @@
1
+ //#region ../zero-cache/src/types/pg-versions.ts
2
+ var PG_15 = 15e4;
3
+ var PG_17 = 17e4;
4
+ //#endregion
5
+ export { PG_15, PG_17 };
6
+
7
+ //# sourceMappingURL=pg-versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pg-versions.js","names":[],"sources":["../../../../../zero-cache/src/types/pg-versions.ts"],"sourcesContent":["export const PG_15 = 150000;\nexport const PG_17 = 170000;\n"],"mappings":";AAAA,IAAa,QAAQ;AACrB,IAAa,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/types/pg.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,QAAQ,EAAE,EAAc,KAAK,YAAY,EAAC,MAAM,UAAU,CAAC;AAClE,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,oCAAoC,CAAC;AAkB9E,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAiD7D;AAED,iBAAS,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAuBhD;AAcD,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAoBvE;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAkFrE;AAED,iBAAS,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,UAAU,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,uBAAoB,WAAgB;;;;;;;;;;;;;;;;;;2BAwBlD,OAAO;;;;;;2BAOP,OAAO;;;;;;2BAQP,MAAM,GAAG,IAAI;;;;;;2BAUb,MAAM;uBACV,MAAM,GAAG,MAAM;;;CAG9B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,cAAc,CAAC;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC,CAAC;AAEH,wBAAgB,QAAQ,CACtB,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;CAC/B,CAAC,EACF,IAAI,CAAC,EAAE,WAAW,GACjB,UAAU,CA4CZ;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,mBAAmB,QAE/D;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOhD,CAAC;AAEF,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,WAE1E"}
1
+ {"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/types/pg.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,QAAQ,EAAE,EAAc,KAAK,YAAY,EAAC,MAAM,UAAU,CAAC;AAClE,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,oCAAoC,CAAC;AAkB9E,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAmD7D;AAED,iBAAS,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAuBhD;AAcD,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAoBvE;AAOD,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CA8ErE;AAED,iBAAS,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,UAAU,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,uBAAoB,WAAgB;;;;;;;;;;;;;;;;;;2BAwBlD,OAAO;;;;;;2BAOP,OAAO;;;;;;2BAQP,MAAM,GAAG,IAAI;;;;;;2BAUb,MAAM;uBACV,MAAM,GAAG,MAAM;;;CAG9B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,cAAc,CAAC;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC,CAAC;AAEH,wBAAgB,QAAQ,CACtB,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;CAC/B,CAAC,EACF,IAAI,CAAC,EAAE,WAAW,GACjB,UAAU,CA4CZ;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,mBAAmB,QAE/D;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOhD,CAAC;AAEF,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,WAE1E"}
@@ -7,6 +7,8 @@ import { OID } from "@postgresql-typed/oids";
7
7
  //#region ../zero-cache/src/types/pg.ts
8
8
  var pgTimestampRe = /^(\d+)-(\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}(?:\.\d+)?)([+-]\d{1,2}(?::\d{2})?)?(?: BC)?$/;
9
9
  function timestampToFpMillis(timestamp) {
10
+ if (timestamp === "infinity") return Infinity;
11
+ if (timestamp === "-infinity") return -Infinity;
10
12
  const match = timestamp.match(pgTimestampRe);
11
13
  if (!match) throw new Error(`Error parsing ${timestamp}`);
12
14
  const [, yearStr, monthDay, time, tz] = match;
@@ -61,9 +63,10 @@ function millisecondsToPostgresTime(milliseconds) {
61
63
  const ms = milliseconds % 1e3;
62
64
  return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}.${ms.toString().padStart(3, "0")}+00`;
63
65
  }
66
+ var timeRegex = /^(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d{1,6}))?(?:([+-])(\d{1,2})(?::(\d{2}))?)?$/;
64
67
  function postgresTimeToMilliseconds(timeString) {
65
68
  if (!timeString || typeof timeString !== "string") throw new Error("Invalid time string: must be a non-empty string");
66
- const match = timeString.match(/^(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d{1,6}))?(?:([+-])(\d{1,2})(?::(\d{2}))?)?$/);
69
+ const match = timeString.match(timeRegex);
67
70
  if (!match) throw new Error(`Invalid time format: "${timeString}". Expected HH:MM:SS[.mmm][+|-HH[:MM]]`);
68
71
  const hours = parseInt(match[1], 10);
69
72
  const minutes = parseInt(match[2], 10);
@@ -90,6 +93,8 @@ function postgresTimeToMilliseconds(timeString) {
90
93
  return totalMs;
91
94
  }
92
95
  function dateToUTCMidnight(date) {
96
+ if (date === "infinity") return Infinity;
97
+ if (date === "-infinity") return -Infinity;
93
98
  const d = new Date(date);
94
99
  return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
95
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pg.js","names":[],"sources":["../../../../../zero-cache/src/types/pg.ts"],"sourcesContent":["import {PreciseDate} from '@google-cloud/precise-date';\nimport {OID} from '@postgresql-typed/oids';\nimport type {LogContext} from '@rocicorp/logger';\nimport postgres, {type Notice, type PostgresType} from 'postgres';\nimport {BigIntJSON, type JSONValue} from '../../../shared/src/bigint-json.ts';\nimport {randInt} from '../../../shared/src/rand.ts';\nimport {\n DATE,\n JSON,\n JSONB,\n NUMERIC,\n TIME,\n TIMESTAMP,\n TIMESTAMPTZ,\n TIMETZ,\n} from './pg-types.ts';\n\n// Matches: YEAR-MM-DD HH:MM:SS[.fraction][+-TZ[:MM]][ BC]\nconst pgTimestampRe =\n /^(\\d+)-(\\d{2}-\\d{2}) (\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?)([+-]\\d{1,2}(?::\\d{2})?)?(?: BC)?$/;\n\n// exported for testing.\nexport function timestampToFpMillis(timestamp: string): number {\n const match = timestamp.match(pgTimestampRe);\n if (!match) {\n throw new Error(`Error parsing ${timestamp}`);\n }\n\n const [, yearStr, monthDay, time, tz] = match;\n const bc = timestamp.endsWith(' BC');\n\n let year = Number(yearStr);\n if (bc) {\n // Postgres: 1 BC = JS year 0, 2 BC = JS year -1, N BC = -(N-1)\n year = -(year - 1);\n }\n\n // Format year as ISO 8601 expanded year if needed.\n // https://tc39.es/ecma262/#sec-expanded-years\n let isoYear: string;\n if (year >= 0 && year <= 9999) {\n isoYear = String(year).padStart(4, '0');\n } else if (year >= 0) {\n isoYear = '+' + String(year).padStart(6, '0');\n } else {\n isoYear = '-' + String(Math.abs(year)).padStart(6, '0');\n }\n\n // Build a UTC ISO string so PreciseDate returns microsecond precision.\n const utcString = `${isoYear}-${monthDay}T${time}Z`;\n\n try {\n const fullTime = new PreciseDate(utcString).getFullTime();\n const millis = Number(fullTime / 1_000_000n);\n const nanos = Number(fullTime % 1_000_000n);\n const ret = millis + nanos * 1e-6; // floating point milliseconds\n\n // Add back in the timezone offset. We passed local time as UTC,\n // so a positive offset means we need to subtract, and vice versa.\n if (tz) {\n const positiveOffset = tz.startsWith('+');\n const [hours, minutes] = tz.split(':');\n const offset =\n Math.abs(Number(hours)) * 60 + (minutes ? Number(minutes) : 0);\n const offsetMillis = offset * 60 * 1_000;\n return positiveOffset ? ret - offsetMillis : ret + offsetMillis;\n }\n return ret;\n } catch (e) {\n throw new Error(`Error parsing ${timestamp}`, {cause: e});\n }\n}\n\nfunction serializeTimestamp(val: unknown): string {\n switch (typeof val) {\n case 'string':\n return val; // Let Postgres parse it\n case 'number': {\n if (Number.isInteger(val)) {\n return new PreciseDate(val).toISOString();\n }\n // Convert floating point to bigint nanoseconds.\n const nanoseconds =\n 1_000_000n * BigInt(Math.trunc(val)) +\n BigInt(Math.trunc((val % 1) * 1e6));\n return new PreciseDate(nanoseconds).toISOString();\n }\n // Note: Don't support bigint inputs until we decide what the semantics are (e.g. micros vs nanos)\n // case 'bigint':\n // return new PreciseDate(val).toISOString();\n default:\n if (val instanceof Date) {\n return val.toISOString();\n }\n }\n throw new Error(`Unsupported type \"${typeof val}\" for timestamp: ${val}`);\n}\n\nconst MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;\n\nfunction serializeTime(x: unknown, type: 'time' | 'timetz'): string {\n switch (typeof x) {\n case 'string':\n return x; // Let Postgres parse it\n case 'number':\n return millisecondsToPostgresTime(x);\n }\n throw new Error(`Unsupported type \"${typeof x}\" for ${type}: ${x}`);\n}\n\nexport function millisecondsToPostgresTime(milliseconds: number): string {\n if (milliseconds < 0) {\n throw new Error('Milliseconds cannot be negative');\n }\n\n if (milliseconds >= MILLISECONDS_PER_DAY) {\n throw new Error(\n `Milliseconds cannot exceed 24 hours (${MILLISECONDS_PER_DAY}ms)`,\n );\n }\n\n milliseconds = Math.floor(milliseconds); // Ensure it's an integer\n\n const totalSeconds = Math.floor(milliseconds / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n const ms = milliseconds % 1000;\n\n return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}.${ms.toString().padStart(3, '0')}+00`;\n}\n\nexport function postgresTimeToMilliseconds(timeString: string): number {\n // Validate basic format\n if (!timeString || typeof timeString !== 'string') {\n throw new Error('Invalid time string: must be a non-empty string');\n }\n\n // Regular expression to match HH:MM:SS, HH:MM:SS.mmm, or HH:MM:SS+00 / HH:MM:SS.mmm+00\n // Supports optional timezone offset\n const timeRegex =\n /^(\\d{1,2}):(\\d{2}):(\\d{2})(?:\\.(\\d{1,6}))?(?:([+-])(\\d{1,2})(?::(\\d{2}))?)?$/;\n const match = timeString.match(timeRegex);\n\n if (!match) {\n throw new Error(\n `Invalid time format: \"${timeString}\". Expected HH:MM:SS[.mmm][+|-HH[:MM]]`,\n );\n }\n\n // Extract components\n const hours = parseInt(match[1], 10);\n const minutes = parseInt(match[2], 10);\n const seconds = parseInt(match[3], 10);\n // Handle optional milliseconds, pad right with zeros if needed\n let milliseconds = 0;\n if (match[4]) {\n // Pad microseconds to 6 digits\n const msString = match[4].padEnd(6, '0');\n // slice milliseconds out of the microseconds\n // e.g. 123456 -> 123, 1234 -> 123,\n milliseconds = parseInt(msString.slice(0, 3), 10);\n }\n\n // Validate ranges\n if (hours < 0 || hours > 24) {\n throw new Error(\n `Invalid hours: ${hours}. Must be between 0 and 24 (24 means end of day)`,\n );\n }\n\n if (minutes < 0 || minutes >= 60) {\n throw new Error(`Invalid minutes: ${minutes}. Must be between 0 and 59`);\n }\n\n if (seconds < 0 || seconds >= 60) {\n throw new Error(`Invalid seconds: ${seconds}. Must be between 0 and 59`);\n }\n\n if (milliseconds < 0 || milliseconds >= 1000) {\n throw new Error(\n `Invalid milliseconds: ${milliseconds}. Must be between 0 and 999`,\n );\n }\n\n // Special case: PostgreSQL allows 24:00:00 to represent end of day\n if (hours === 24 && (minutes !== 0 || seconds !== 0 || milliseconds !== 0)) {\n throw new Error(\n 'Invalid time: when hours is 24, minutes, seconds, and milliseconds must be 0',\n );\n }\n\n // Calculate total milliseconds\n let totalMs =\n hours * 3600000 + minutes * 60000 + seconds * 1000 + milliseconds;\n\n // Timezone Offset\n if (match[5]) {\n const sign = match[5] === '+' ? 1 : -1;\n const tzHours = parseInt(match[6], 10);\n const tzMinutes = match[7] ? parseInt(match[7], 10) : 0;\n const offsetMs = sign * (tzHours * 3600000 + tzMinutes * 60000);\n totalMs -= offsetMs;\n }\n\n // Normalize to 0-24h only if outside valid range\n if (totalMs > MILLISECONDS_PER_DAY || totalMs < 0) {\n return (\n ((totalMs % MILLISECONDS_PER_DAY) + MILLISECONDS_PER_DAY) %\n MILLISECONDS_PER_DAY\n );\n }\n\n return totalMs;\n}\n\nfunction dateToUTCMidnight(date: string): number {\n const d = new Date(date);\n return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());\n}\n\n/**\n * The (javascript) types of objects that can be returned by our configured\n * Postgres clients. For initial-sync, these comes from the postgres.js client:\n *\n * https://github.com/porsager/postgres/blob/master/src/types.js\n *\n * and for the replication stream these come from the the node-postgres client:\n *\n * https://github.com/brianc/node-pg-types/blob/master/lib/textParsers.js\n */\nexport type PostgresValueType = JSONValue | Uint8Array;\n\nexport type TypeOptions = {\n /**\n * Sends strings directly as JSON values (i.e. without JSON stringification).\n * The application is responsible for ensuring that string inputs for JSON\n * columns are already stringified. Other data types (e.g. objects) will\n * still be stringified by the pg client.\n */\n sendStringAsJson?: boolean;\n};\n\n/**\n * Configures types for the Postgres.js client library (`postgres`).\n *\n * @param jsonAsString Keep JSON / JSONB values as strings instead of parsing.\n */\nexport const postgresTypeConfig = ({sendStringAsJson}: TypeOptions = {}) => ({\n // Type the type IDs as `number` so that Typescript doesn't complain about\n // referencing external types during type inference.\n types: {\n bigint: postgres.BigInt,\n json: {\n to: JSON,\n from: [JSON, JSONB],\n serialize: sendStringAsJson\n ? (x: unknown) => (typeof x === 'string' ? x : BigIntJSON.stringify(x))\n : BigIntJSON.stringify,\n parse: BigIntJSON.parse,\n },\n // Timestamps are converted to PreciseDate objects.\n timestamp: {\n to: TIMESTAMP,\n from: [TIMESTAMP, TIMESTAMPTZ],\n serialize: serializeTimestamp,\n parse: timestampToFpMillis,\n },\n // Times are converted as strings\n time: {\n to: TIME,\n from: [TIME, TIMETZ],\n serialize: (x: unknown) => serializeTime(x, 'time'),\n parse: postgresTimeToMilliseconds,\n },\n\n timetz: {\n to: TIMETZ,\n from: [TIME, TIMETZ],\n serialize: (x: unknown) => serializeTime(x, 'timetz'),\n parse: postgresTimeToMilliseconds,\n },\n\n // The DATE type is stored directly as the PG normalized date string.\n date: {\n to: DATE,\n from: [DATE],\n serialize: (x: string | Date) =>\n (x instanceof Date ? x : new Date(x)).toISOString(),\n parse: dateToUTCMidnight,\n },\n // Returns a `js` number which can lose precision for large numbers.\n // JS number is 53 bits so this should generally not occur.\n // An API will be provided for users to override this type.\n numeric: {\n to: NUMERIC,\n from: [NUMERIC],\n serialize: (x: number) => String(x), // pg expects a string\n parse: (x: string | number) => Number(x),\n },\n },\n});\n\nexport type PostgresDB = postgres.Sql<{\n bigint: bigint;\n json: JSONValue;\n}>;\n\nexport type PostgresTransaction = postgres.TransactionSql<{\n bigint: bigint;\n json: JSONValue;\n}>;\n\nexport function pgClient(\n lc: LogContext,\n connectionURI: string,\n options?: postgres.Options<{\n bigint: PostgresType<bigint>;\n json: PostgresType<JSONValue>;\n }>,\n opts?: TypeOptions,\n): PostgresDB {\n const onnotice = (n: Notice) => {\n // https://www.postgresql.org/docs/current/plpgsql-errors-and-messages.html#PLPGSQL-STATEMENTS-RAISE\n switch (n.severity) {\n case 'NOTICE':\n return; // silenced\n case 'DEBUG':\n lc.debug?.(n);\n return;\n case 'WARNING':\n lc.warn?.(n);\n return;\n case 'EXCEPTION':\n lc.error?.(n);\n return;\n case 'LOG':\n case 'INFO':\n default:\n lc.info?.(n);\n }\n };\n const url = new URL(connectionURI);\n const sslFlag =\n url.searchParams.get('ssl') ?? url.searchParams.get('sslmode') ?? 'prefer';\n\n let ssl: boolean | 'prefer' | {rejectUnauthorized: boolean};\n if (sslFlag === 'disable' || sslFlag === 'false') {\n ssl = false;\n } else if (sslFlag === 'no-verify') {\n ssl = {rejectUnauthorized: false};\n } else {\n ssl = sslFlag as 'prefer';\n }\n\n // Set connections to expire between 5 and 10 minutes to free up state on PG.\n const maxLifetimeSeconds = randInt(5 * 60, 10 * 60);\n\n return postgres(connectionURI, {\n ...postgresTypeConfig(opts),\n onnotice,\n ['max_lifetime']: maxLifetimeSeconds,\n ssl,\n ...options,\n });\n}\n\n/**\n * Disables any statement_timeout for the current transaction. By default,\n * Postgres does not impose a statement timeout, but some users and providers\n * set one at the database level (even though it is explicitly discouraged by\n * the Postgres documentation).\n *\n * Zero logic in particular often does not fit into the category of general\n * application logic; for potentially long-running operations like migrations\n * and background cleanup, the statement timeout should be disabled to prevent\n * these operations from timing out.\n */\nexport function disableStatementTimeout(sql: PostgresTransaction) {\n void sql`SET LOCAL statement_timeout = 0;`.execute();\n}\n\nexport const typeNameByOID: Record<number, string> = Object.freeze(\n Object.fromEntries(\n Object.entries(OID).map(([name, oid]) => [\n oid,\n name.startsWith('_') ? `${name.substring(1)}[]` : name,\n ]),\n ),\n);\n\nexport function isPostgresError(e: unknown, ...codes: [string, ...string[]]) {\n return e instanceof postgres.PostgresError && codes.includes(e.code);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pg.js","names":[],"sources":["../../../../../zero-cache/src/types/pg.ts"],"sourcesContent":["import {PreciseDate} from '@google-cloud/precise-date';\nimport {OID} from '@postgresql-typed/oids';\nimport type {LogContext} from '@rocicorp/logger';\nimport postgres, {type Notice, type PostgresType} from 'postgres';\nimport {BigIntJSON, type JSONValue} from '../../../shared/src/bigint-json.ts';\nimport {randInt} from '../../../shared/src/rand.ts';\nimport {\n DATE,\n JSON,\n JSONB,\n NUMERIC,\n TIME,\n TIMESTAMP,\n TIMESTAMPTZ,\n TIMETZ,\n} from './pg-types.ts';\n\n// Matches: YEAR-MM-DD HH:MM:SS[.fraction][+-TZ[:MM]][ BC]\nconst pgTimestampRe =\n /^(\\d+)-(\\d{2}-\\d{2}) (\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?)([+-]\\d{1,2}(?::\\d{2})?)?(?: BC)?$/;\n\n// exported for testing.\nexport function timestampToFpMillis(timestamp: string): number {\n if (timestamp === 'infinity') return Infinity;\n if (timestamp === '-infinity') return -Infinity;\n const match = timestamp.match(pgTimestampRe);\n if (!match) {\n throw new Error(`Error parsing ${timestamp}`);\n }\n\n const [, yearStr, monthDay, time, tz] = match;\n const bc = timestamp.endsWith(' BC');\n\n let year = Number(yearStr);\n if (bc) {\n // Postgres: 1 BC = JS year 0, 2 BC = JS year -1, N BC = -(N-1)\n year = -(year - 1);\n }\n\n // Format year as ISO 8601 expanded year if needed.\n // https://tc39.es/ecma262/#sec-expanded-years\n let isoYear: string;\n if (year >= 0 && year <= 9999) {\n isoYear = String(year).padStart(4, '0');\n } else if (year >= 0) {\n isoYear = '+' + String(year).padStart(6, '0');\n } else {\n isoYear = '-' + String(Math.abs(year)).padStart(6, '0');\n }\n\n // Build a UTC ISO string so PreciseDate returns microsecond precision.\n const utcString = `${isoYear}-${monthDay}T${time}Z`;\n\n try {\n const fullTime = new PreciseDate(utcString).getFullTime();\n const millis = Number(fullTime / 1_000_000n);\n const nanos = Number(fullTime % 1_000_000n);\n const ret = millis + nanos * 1e-6; // floating point milliseconds\n\n // Add back in the timezone offset. We passed local time as UTC,\n // so a positive offset means we need to subtract, and vice versa.\n if (tz) {\n const positiveOffset = tz.startsWith('+');\n const [hours, minutes] = tz.split(':');\n const offset =\n Math.abs(Number(hours)) * 60 + (minutes ? Number(minutes) : 0);\n const offsetMillis = offset * 60 * 1_000;\n return positiveOffset ? ret - offsetMillis : ret + offsetMillis;\n }\n return ret;\n } catch (e) {\n throw new Error(`Error parsing ${timestamp}`, {cause: e});\n }\n}\n\nfunction serializeTimestamp(val: unknown): string {\n switch (typeof val) {\n case 'string':\n return val; // Let Postgres parse it\n case 'number': {\n if (Number.isInteger(val)) {\n return new PreciseDate(val).toISOString();\n }\n // Convert floating point to bigint nanoseconds.\n const nanoseconds =\n 1_000_000n * BigInt(Math.trunc(val)) +\n BigInt(Math.trunc((val % 1) * 1e6));\n return new PreciseDate(nanoseconds).toISOString();\n }\n // Note: Don't support bigint inputs until we decide what the semantics are (e.g. micros vs nanos)\n // case 'bigint':\n // return new PreciseDate(val).toISOString();\n default:\n if (val instanceof Date) {\n return val.toISOString();\n }\n }\n throw new Error(`Unsupported type \"${typeof val}\" for timestamp: ${val}`);\n}\n\nconst MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;\n\nfunction serializeTime(x: unknown, type: 'time' | 'timetz'): string {\n switch (typeof x) {\n case 'string':\n return x; // Let Postgres parse it\n case 'number':\n return millisecondsToPostgresTime(x);\n }\n throw new Error(`Unsupported type \"${typeof x}\" for ${type}: ${x}`);\n}\n\nexport function millisecondsToPostgresTime(milliseconds: number): string {\n if (milliseconds < 0) {\n throw new Error('Milliseconds cannot be negative');\n }\n\n if (milliseconds >= MILLISECONDS_PER_DAY) {\n throw new Error(\n `Milliseconds cannot exceed 24 hours (${MILLISECONDS_PER_DAY}ms)`,\n );\n }\n\n milliseconds = Math.floor(milliseconds); // Ensure it's an integer\n\n const totalSeconds = Math.floor(milliseconds / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n const ms = milliseconds % 1000;\n\n return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}.${ms.toString().padStart(3, '0')}+00`;\n}\n\n// Regular expression to match HH:MM:SS, HH:MM:SS.mmm, or HH:MM:SS+00 / HH:MM:SS.mmm+00\n// Supports optional timezone offset\nconst timeRegex =\n /^(\\d{1,2}):(\\d{2}):(\\d{2})(?:\\.(\\d{1,6}))?(?:([+-])(\\d{1,2})(?::(\\d{2}))?)?$/;\n\nexport function postgresTimeToMilliseconds(timeString: string): number {\n // Validate basic format\n if (!timeString || typeof timeString !== 'string') {\n throw new Error('Invalid time string: must be a non-empty string');\n }\n\n const match = timeString.match(timeRegex);\n\n if (!match) {\n throw new Error(\n `Invalid time format: \"${timeString}\". Expected HH:MM:SS[.mmm][+|-HH[:MM]]`,\n );\n }\n\n // Extract components\n const hours = parseInt(match[1], 10);\n const minutes = parseInt(match[2], 10);\n const seconds = parseInt(match[3], 10);\n // Handle optional milliseconds, pad right with zeros if needed\n let milliseconds = 0;\n if (match[4]) {\n // Pad microseconds to 6 digits\n const msString = match[4].padEnd(6, '0');\n // slice milliseconds out of the microseconds\n // e.g. 123456 -> 123, 1234 -> 123,\n milliseconds = parseInt(msString.slice(0, 3), 10);\n }\n\n // Validate ranges\n if (hours < 0 || hours > 24) {\n throw new Error(\n `Invalid hours: ${hours}. Must be between 0 and 24 (24 means end of day)`,\n );\n }\n\n if (minutes < 0 || minutes >= 60) {\n throw new Error(`Invalid minutes: ${minutes}. Must be between 0 and 59`);\n }\n\n if (seconds < 0 || seconds >= 60) {\n throw new Error(`Invalid seconds: ${seconds}. Must be between 0 and 59`);\n }\n\n if (milliseconds < 0 || milliseconds >= 1000) {\n throw new Error(\n `Invalid milliseconds: ${milliseconds}. Must be between 0 and 999`,\n );\n }\n\n // Special case: PostgreSQL allows 24:00:00 to represent end of day\n if (hours === 24 && (minutes !== 0 || seconds !== 0 || milliseconds !== 0)) {\n throw new Error(\n 'Invalid time: when hours is 24, minutes, seconds, and milliseconds must be 0',\n );\n }\n\n // Calculate total milliseconds\n let totalMs =\n hours * 3600000 + minutes * 60000 + seconds * 1000 + milliseconds;\n\n // Timezone Offset\n if (match[5]) {\n const sign = match[5] === '+' ? 1 : -1;\n const tzHours = parseInt(match[6], 10);\n const tzMinutes = match[7] ? parseInt(match[7], 10) : 0;\n const offsetMs = sign * (tzHours * 3600000 + tzMinutes * 60000);\n totalMs -= offsetMs;\n }\n\n // Normalize to 0-24h only if outside valid range\n if (totalMs > MILLISECONDS_PER_DAY || totalMs < 0) {\n return (\n ((totalMs % MILLISECONDS_PER_DAY) + MILLISECONDS_PER_DAY) %\n MILLISECONDS_PER_DAY\n );\n }\n\n return totalMs;\n}\n\nfunction dateToUTCMidnight(date: string): number {\n if (date === 'infinity') return Infinity;\n if (date === '-infinity') return -Infinity;\n const d = new Date(date);\n return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());\n}\n\n/**\n * The (javascript) types of objects that can be returned by our configured\n * Postgres clients. For initial-sync, these comes from the postgres.js client:\n *\n * https://github.com/porsager/postgres/blob/master/src/types.js\n *\n * and for the replication stream these come from the the node-postgres client:\n *\n * https://github.com/brianc/node-pg-types/blob/master/lib/textParsers.js\n */\nexport type PostgresValueType = JSONValue | Uint8Array;\n\nexport type TypeOptions = {\n /**\n * Sends strings directly as JSON values (i.e. without JSON stringification).\n * The application is responsible for ensuring that string inputs for JSON\n * columns are already stringified. Other data types (e.g. objects) will\n * still be stringified by the pg client.\n */\n sendStringAsJson?: boolean;\n};\n\n/**\n * Configures types for the Postgres.js client library (`postgres`).\n *\n * @param jsonAsString Keep JSON / JSONB values as strings instead of parsing.\n */\nexport const postgresTypeConfig = ({sendStringAsJson}: TypeOptions = {}) => ({\n // Type the type IDs as `number` so that Typescript doesn't complain about\n // referencing external types during type inference.\n types: {\n bigint: postgres.BigInt,\n json: {\n to: JSON,\n from: [JSON, JSONB],\n serialize: sendStringAsJson\n ? (x: unknown) => (typeof x === 'string' ? x : BigIntJSON.stringify(x))\n : BigIntJSON.stringify,\n parse: BigIntJSON.parse,\n },\n // Timestamps are converted to PreciseDate objects.\n timestamp: {\n to: TIMESTAMP,\n from: [TIMESTAMP, TIMESTAMPTZ],\n serialize: serializeTimestamp,\n parse: timestampToFpMillis,\n },\n // Times are converted as strings\n time: {\n to: TIME,\n from: [TIME, TIMETZ],\n serialize: (x: unknown) => serializeTime(x, 'time'),\n parse: postgresTimeToMilliseconds,\n },\n\n timetz: {\n to: TIMETZ,\n from: [TIME, TIMETZ],\n serialize: (x: unknown) => serializeTime(x, 'timetz'),\n parse: postgresTimeToMilliseconds,\n },\n\n // The DATE type is stored directly as the PG normalized date string.\n date: {\n to: DATE,\n from: [DATE],\n serialize: (x: string | Date) =>\n (x instanceof Date ? x : new Date(x)).toISOString(),\n parse: dateToUTCMidnight,\n },\n // Returns a `js` number which can lose precision for large numbers.\n // JS number is 53 bits so this should generally not occur.\n // An API will be provided for users to override this type.\n numeric: {\n to: NUMERIC,\n from: [NUMERIC],\n serialize: (x: number) => String(x), // pg expects a string\n parse: (x: string | number) => Number(x),\n },\n },\n});\n\nexport type PostgresDB = postgres.Sql<{\n bigint: bigint;\n json: JSONValue;\n}>;\n\nexport type PostgresTransaction = postgres.TransactionSql<{\n bigint: bigint;\n json: JSONValue;\n}>;\n\nexport function pgClient(\n lc: LogContext,\n connectionURI: string,\n options?: postgres.Options<{\n bigint: PostgresType<bigint>;\n json: PostgresType<JSONValue>;\n }>,\n opts?: TypeOptions,\n): PostgresDB {\n const onnotice = (n: Notice) => {\n // https://www.postgresql.org/docs/current/plpgsql-errors-and-messages.html#PLPGSQL-STATEMENTS-RAISE\n switch (n.severity) {\n case 'NOTICE':\n return; // silenced\n case 'DEBUG':\n lc.debug?.(n);\n return;\n case 'WARNING':\n lc.warn?.(n);\n return;\n case 'EXCEPTION':\n lc.error?.(n);\n return;\n case 'LOG':\n case 'INFO':\n default:\n lc.info?.(n);\n }\n };\n const url = new URL(connectionURI);\n const sslFlag =\n url.searchParams.get('ssl') ?? url.searchParams.get('sslmode') ?? 'prefer';\n\n let ssl: boolean | 'prefer' | {rejectUnauthorized: boolean};\n if (sslFlag === 'disable' || sslFlag === 'false') {\n ssl = false;\n } else if (sslFlag === 'no-verify') {\n ssl = {rejectUnauthorized: false};\n } else {\n ssl = sslFlag as 'prefer';\n }\n\n // Set connections to expire between 5 and 10 minutes to free up state on PG.\n const maxLifetimeSeconds = randInt(5 * 60, 10 * 60);\n\n return postgres(connectionURI, {\n ...postgresTypeConfig(opts),\n onnotice,\n ['max_lifetime']: maxLifetimeSeconds,\n ssl,\n ...options,\n });\n}\n\n/**\n * Disables any statement_timeout for the current transaction. By default,\n * Postgres does not impose a statement timeout, but some users and providers\n * set one at the database level (even though it is explicitly discouraged by\n * the Postgres documentation).\n *\n * Zero logic in particular often does not fit into the category of general\n * application logic; for potentially long-running operations like migrations\n * and background cleanup, the statement timeout should be disabled to prevent\n * these operations from timing out.\n */\nexport function disableStatementTimeout(sql: PostgresTransaction) {\n void sql`SET LOCAL statement_timeout = 0;`.execute().catch(() => {});\n}\n\nexport const typeNameByOID: Record<number, string> = Object.freeze(\n Object.fromEntries(\n Object.entries(OID).map(([name, oid]) => [\n oid,\n name.startsWith('_') ? `${name.substring(1)}[]` : name,\n ]),\n ),\n);\n\nexport function isPostgresError(e: unknown, ...codes: [string, ...string[]]) {\n return e instanceof postgres.PostgresError && codes.includes(e.code);\n}\n"],"mappings":";;;;;;;AAkBA,IAAM,gBACJ;AAGF,SAAgB,oBAAoB,WAA2B;AAC7D,KAAI,cAAc,WAAY,QAAO;AACrC,KAAI,cAAc,YAAa,QAAO;CACtC,MAAM,QAAQ,UAAU,MAAM,cAAc;AAC5C,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,iBAAiB,YAAY;CAG/C,MAAM,GAAG,SAAS,UAAU,MAAM,MAAM;CACxC,MAAM,KAAK,UAAU,SAAS,MAAM;CAEpC,IAAI,OAAO,OAAO,QAAQ;AAC1B,KAAI,GAEF,QAAO,EAAE,OAAO;CAKlB,IAAI;AACJ,KAAI,QAAQ,KAAK,QAAQ,KACvB,WAAU,OAAO,KAAK,CAAC,SAAS,GAAG,IAAI;UAC9B,QAAQ,EACjB,WAAU,MAAM,OAAO,KAAK,CAAC,SAAS,GAAG,IAAI;KAE7C,WAAU,MAAM,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC,SAAS,GAAG,IAAI;CAIzD,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK;AAEjD,KAAI;EACF,MAAM,WAAW,IAAI,YAAY,UAAU,CAAC,aAAa;EAGzD,MAAM,MAFS,OAAO,WAAW,SAAW,GAC9B,OAAO,WAAW,SAAW,GACd;AAI7B,MAAI,IAAI;GACN,MAAM,iBAAiB,GAAG,WAAW,IAAI;GACzC,MAAM,CAAC,OAAO,WAAW,GAAG,MAAM,IAAI;GAGtC,MAAM,gBADJ,KAAK,IAAI,OAAO,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,QAAQ,GAAG,MAChC,KAAK;AACnC,UAAO,iBAAiB,MAAM,eAAe,MAAM;;AAErD,SAAO;UACA,GAAG;AACV,QAAM,IAAI,MAAM,iBAAiB,aAAa,EAAC,OAAO,GAAE,CAAC;;;AAI7D,SAAS,mBAAmB,KAAsB;AAChD,SAAQ,OAAO,KAAf;EACE,KAAK,SACH,QAAO;EACT,KAAK;AACH,OAAI,OAAO,UAAU,IAAI,CACvB,QAAO,IAAI,YAAY,IAAI,CAAC,aAAa;AAM3C,UAAO,IAAI,YAFT,WAAa,OAAO,KAAK,MAAM,IAAI,CAAC,GACpC,OAAO,KAAK,MAAO,MAAM,IAAK,IAAI,CAAC,CACF,CAAC,aAAa;EAKnD,QACE,KAAI,eAAe,KACjB,QAAO,IAAI,aAAa;;AAG9B,OAAM,IAAI,MAAM,qBAAqB,OAAO,IAAI,mBAAmB,MAAM;;AAG3E,IAAM,uBAAuB,OAAU,KAAK;AAE5C,SAAS,cAAc,GAAY,MAAiC;AAClE,SAAQ,OAAO,GAAf;EACE,KAAK,SACH,QAAO;EACT,KAAK,SACH,QAAO,2BAA2B,EAAE;;AAExC,OAAM,IAAI,MAAM,qBAAqB,OAAO,EAAE,QAAQ,KAAK,IAAI,IAAI;;AAGrE,SAAgB,2BAA2B,cAA8B;AACvE,KAAI,eAAe,EACjB,OAAM,IAAI,MAAM,kCAAkC;AAGpD,KAAI,gBAAgB,qBAClB,OAAM,IAAI,MACR,wCAAwC,qBAAqB,KAC9D;AAGH,gBAAe,KAAK,MAAM,aAAa;CAEvC,MAAM,eAAe,KAAK,MAAM,eAAe,IAAK;CACpD,MAAM,QAAQ,KAAK,MAAM,eAAe,KAAK;CAC7C,MAAM,UAAU,KAAK,MAAO,eAAe,OAAQ,GAAG;CACtD,MAAM,UAAU,eAAe;CAC/B,MAAM,KAAK,eAAe;AAE1B,QAAO,GAAG,MAAM,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,QAAQ,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,QAAQ,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC;;AAK9J,IAAM,YACJ;AAEF,SAAgB,2BAA2B,YAA4B;AAErE,KAAI,CAAC,cAAc,OAAO,eAAe,SACvC,OAAM,IAAI,MAAM,kDAAkD;CAGpE,MAAM,QAAQ,WAAW,MAAM,UAAU;AAEzC,KAAI,CAAC,MACH,OAAM,IAAI,MACR,yBAAyB,WAAW,wCACrC;CAIH,MAAM,QAAQ,SAAS,MAAM,IAAI,GAAG;CACpC,MAAM,UAAU,SAAS,MAAM,IAAI,GAAG;CACtC,MAAM,UAAU,SAAS,MAAM,IAAI,GAAG;CAEtC,IAAI,eAAe;AACnB,KAAI,MAAM,IAAI;EAEZ,MAAM,WAAW,MAAM,GAAG,OAAO,GAAG,IAAI;AAGxC,iBAAe,SAAS,SAAS,MAAM,GAAG,EAAE,EAAE,GAAG;;AAInD,KAAI,QAAQ,KAAK,QAAQ,GACvB,OAAM,IAAI,MACR,kBAAkB,MAAM,kDACzB;AAGH,KAAI,UAAU,KAAK,WAAW,GAC5B,OAAM,IAAI,MAAM,oBAAoB,QAAQ,4BAA4B;AAG1E,KAAI,UAAU,KAAK,WAAW,GAC5B,OAAM,IAAI,MAAM,oBAAoB,QAAQ,4BAA4B;AAG1E,KAAI,eAAe,KAAK,gBAAgB,IACtC,OAAM,IAAI,MACR,yBAAyB,aAAa,6BACvC;AAIH,KAAI,UAAU,OAAO,YAAY,KAAK,YAAY,KAAK,iBAAiB,GACtE,OAAM,IAAI,MACR,+EACD;CAIH,IAAI,UACF,QAAQ,OAAU,UAAU,MAAQ,UAAU,MAAO;AAGvD,KAAI,MAAM,IAAI;EACZ,MAAM,OAAO,MAAM,OAAO,MAAM,IAAI;EACpC,MAAM,UAAU,SAAS,MAAM,IAAI,GAAG;EACtC,MAAM,YAAY,MAAM,KAAK,SAAS,MAAM,IAAI,GAAG,GAAG;EACtD,MAAM,WAAW,QAAQ,UAAU,OAAU,YAAY;AACzD,aAAW;;AAIb,KAAI,UAAU,wBAAwB,UAAU,EAC9C,SACI,UAAU,uBAAwB,wBACpC;AAIJ,QAAO;;AAGT,SAAS,kBAAkB,MAAsB;AAC/C,KAAI,SAAS,WAAY,QAAO;AAChC,KAAI,SAAS,YAAa,QAAO;CACjC,MAAM,IAAI,IAAI,KAAK,KAAK;AACxB,QAAO,KAAK,IAAI,EAAE,gBAAgB,EAAE,EAAE,aAAa,EAAE,EAAE,YAAY,CAAC;;;;;;;AA8BtE,IAAa,sBAAsB,EAAC,qBAAiC,EAAE,MAAM,EAG3E,OAAO;CACL,QAAQ,SAAS;CACjB,MAAM;EACJ,IAAA;EACA,MAAM,CAAA,KAAO,MAAM;EACnB,WAAW,oBACN,MAAgB,OAAO,MAAM,WAAW,IAAI,WAAW,UAAU,EAAE,GACpE,WAAW;EACf,OAAO,WAAW;EACnB;CAED,WAAW;EACT,IAAI;EACJ,MAAM,CAAC,WAAW,YAAY;EAC9B,WAAW;EACX,OAAO;EACR;CAED,MAAM;EACJ,IAAI;EACJ,MAAM,CAAC,MAAM,OAAO;EACpB,YAAY,MAAe,cAAc,GAAG,OAAO;EACnD,OAAO;EACR;CAED,QAAQ;EACN,IAAI;EACJ,MAAM,CAAC,MAAM,OAAO;EACpB,YAAY,MAAe,cAAc,GAAG,SAAS;EACrD,OAAO;EACR;CAGD,MAAM;EACJ,IAAI;EACJ,MAAM,CAAC,KAAK;EACZ,YAAY,OACT,aAAa,OAAO,IAAI,IAAI,KAAK,EAAE,EAAE,aAAa;EACrD,OAAO;EACR;CAID,SAAS;EACP,IAAI;EACJ,MAAM,CAAC,QAAQ;EACf,YAAY,MAAc,OAAO,EAAE;EACnC,QAAQ,MAAuB,OAAO,EAAE;EACzC;CACF,EACF;AAYD,SAAgB,SACd,IACA,eACA,SAIA,MACY;CACZ,MAAM,YAAY,MAAc;AAE9B,UAAQ,EAAE,UAAV;GACE,KAAK,SACH;GACF,KAAK;AACH,OAAG,QAAQ,EAAE;AACb;GACF,KAAK;AACH,OAAG,OAAO,EAAE;AACZ;GACF,KAAK;AACH,OAAG,QAAQ,EAAE;AACb;GAGF,QACE,IAAG,OAAO,EAAE;;;CAGlB,MAAM,MAAM,IAAI,IAAI,cAAc;CAClC,MAAM,UACJ,IAAI,aAAa,IAAI,MAAM,IAAI,IAAI,aAAa,IAAI,UAAU,IAAI;CAEpE,IAAI;AACJ,KAAI,YAAY,aAAa,YAAY,QACvC,OAAM;UACG,YAAY,YACrB,OAAM,EAAC,oBAAoB,OAAM;KAEjC,OAAM;CAIR,MAAM,qBAAqB,QAAQ,KAAQ,IAAQ;AAEnD,QAAO,SAAS,eAAe;EAC7B,GAAG,mBAAmB,KAAK;EAC3B;GACC,iBAAiB;EAClB;EACA,GAAG;EACJ,CAAC;;AAkBiD,OAAO,OAC1D,OAAO,YACL,OAAO,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,SAAS,CACvC,KACA,KAAK,WAAW,IAAI,GAAG,GAAG,KAAK,UAAU,EAAE,CAAC,MAAM,KACnD,CAAC,CACH,CACF;AAED,SAAgB,gBAAgB,GAAY,GAAG,OAA8B;AAC3E,QAAO,aAAa,SAAS,iBAAiB,MAAM,SAAS,EAAE,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/types/subscription.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,IAAI,EAAE,MAAM,EAAC,MAAM,cAAc,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,qBAAa,YAAY,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAE,YAAW,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;;IAC/D;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAC9B,OAAO,GAAE,OAAO,CAAC,CAAC,CAAM,EACxB,OAAO,GAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAU;IAqB/B;;;OAGG;gBACS,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,YAAK,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;IAqC1D;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,aAAa;IA4B7B,iEAAiE;IACjE,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,qDAAqD;IACrD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,6DAA6D;IAC7D,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;;;;;;;;;;OAWG;IACH,GAAG;IAUH;;;;;;;;OAQG;IACH,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK;IAIlB,wEAAwE;IACxE,IAAI,CAAC,GAAG,EAAE,KAAK;IAyBf,IAAI,QAAQ,IAAI,aAAa,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;KAAC,CAAC,GAAG,SAAS,CAI1E;IAiDD,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;CA0B3C;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IACvB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;IAEnC;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAE7B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjD;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,yCAAyC;AACzC,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,YAAY,CAAC;AAE7D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAAC,CAAC"}
1
+ {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/types/subscription.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,IAAI,EAAE,MAAM,EAAC,MAAM,cAAc,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,qBAAa,YAAY,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAE,YAAW,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;;IAC/D;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAC9B,OAAO,GAAE,OAAO,CAAC,CAAC,CAAM,EACxB,OAAO,GAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAU;IAqB/B;;;OAGG;gBACS,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,YAAK,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;IAqC1D;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,aAAa;IA6B7B,iEAAiE;IACjE,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,qDAAqD;IACrD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,6DAA6D;IAC7D,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;;;;;;;;;;OAWG;IACH,GAAG;IAUH;;;;;;;;OAQG;IACH,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK;IAIlB,wEAAwE;IACxE,IAAI,CAAC,GAAG,EAAE,KAAK;IAyBf,IAAI,QAAQ,IAAI,aAAa,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;KAAC,CAAC,GAAG,SAAS,CAI1E;IAiDD,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;CA0B3C;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IACvB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;IAEnC;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAE7B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjD;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,yCAAyC;AACzC,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,YAAY,CAAC;AAE7D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAAC,CAAC"}
@@ -127,8 +127,8 @@ var Subscription = class Subscription {
127
127
  }
128
128
  const consumer = this.#consumers.shift();
129
129
  if (consumer) consumer.resolve(entry);
130
- else if (this.#coalesce && this.#messages.length && this.#messages[this.#messages.length - 1] !== "terminus") {
131
- const prev = this.#messages[this.#messages.length - 1];
130
+ else if (this.#coalesce && this.#messages.length && this.#messages.at(-1) !== "terminus") {
131
+ const prev = this.#messages.at(-1);
132
132
  assert(prev !== "terminus", "prev should not be terminus after check");
133
133
  this.#messages[this.#messages.length - 1] = {
134
134
  value: this.#coalesce(entry, prev),
@@ -1 +1 @@
1
- {"version":3,"file":"subscription.js","names":["#consumers","#messages","#consuming","#pipelineEnabled","#coalesce","#consumed","#cleanup","#publish","#sentinel","#terminate","#pipeline"],"sources":["../../../../../zero-cache/src/types/subscription.ts"],"sourcesContent":["import {resolver, type Resolver} from '@rocicorp/resolver';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {Sink, Source} from './streams.ts';\n\n/**\n * A Subscription abstracts a continuous, logically infinite stream of messages intended\n * for serial processing. Unlike the more general Node `Stream` API, a Subscription has\n * a limited API with specific semantics:\n *\n * * **Serial processing**: Messages must be consumed via the {@link AsyncIterable}\n * interface, e.g.\n * ```ts\n * const subscription = server.subscribe(parameters);\n *\n * for await (const message of subscription) {\n * await process(message); // fully process the message before consuming the next\n * }\n * ```\n *\n * Moreover, the consumer is expected to completely process each message before\n * requesting the next. This is important for cleanup semantics (explained later).\n *\n * * **cancel()**, not close(): The underlying data in a subscription is logically infinite\n * and only terminated when the consumer is no longer interested in receiving the messages\n * (or requires a Subscription with a different configuration). As such, there is no API\n * for gracefully closing the subscription after pending messages are consumed; rather,\n * cancellation is immediate, and upon cancellation, pending messages are dropped. A\n * Subscription can also be terminated with exceptional (i.e. `Error`) circumstances,\n * for which the behavior is equivalent.\n *\n * * **Coalescing** (optional): A producer can configure pending messages in the Subscription\n * to be merged together with a {@link Options.coalesce coalesce} function. This is useful\n * for semantics in which the consumer is not necessarily interested in every incremental\n * change, but rather the cumulative change since the last processed message. A\n * Subscription with coalescing is guaranteed to have at most one outstanding message,\n * regardless of how quickly messages are produced and consumed. This effectively constrains\n * the amount of outstanding work in the system.\n *\n * ### Resource Tracking and Cleanup\n *\n * Because message consumption is constrained to the async iteration API, standard\n * control flow mechanisms allow the producer to perform bookkeeping without any\n * explicit cleanup actions on the part of the consumer. This includes:\n *\n * * **Per-message cleanup**: Each request for the {@link AsyncIterator.next next}\n * message, or the termination of the iteration, signals that the consumer has\n * finished processing the previous message. The producer of a Subscription can\n * supply a {@link Options.consumed consumed} callback to receive these processed\n * messages, allowing it to clean up attached resources (e.g. TransactionPools, etc.).\n *\n * * **Per-subscription cleanup**: The producer of a Subscription can supply a\n * {@link Options.cleanup cleanup} callback that is invoked when the Subscription\n * is terminated, either explicitly via {@link Subscription.cancel cancel()} /\n * {@link Subscription.fail fail()}, or implicitly when an iteration is exited via a\n * `break`, `return`, or `throw` statement. All unconsumed messages are passed to the\n * call back to facilitate bookkeeping.\n *\n * @param T The external message type, published to the AsyncIterable\n * @param M The internal message type used in the producer-side interfaces\n * (e.g. {@link push}, {@link Options.consumed}, {@link Options.coalesce},\n * and {@link Options.cleanup}). This is often the same as the external type\n * T, but may be diverged to facilitate internal bookkeeping.\n */\nexport class Subscription<T, M = T> implements Source<T>, Sink<M> {\n /**\n * Convenience factory method for creating a {@link Subscription} with internal message type\n * `M` as a subtype of `T`, defaulting to the same type. The default `publish` method publishes\n * the message of type `M` directly to the AsyncIterable.\n */\n static create<T, M extends T = T>(\n options: Options<M> = {},\n publish: (m: M) => T = m => m,\n ) {\n return new Subscription(options, publish);\n }\n\n // Consumers waiting to consume messages (i.e. an async iteration awaiting the next message).\n readonly #consumers: Resolver<Entry<M> | null>[] = [];\n // Messages waiting to be dequeued.\n readonly #messages: (Entry<M> | 'terminus')[] = [];\n // Messages dequeued but not yet consumed.\n readonly #consuming = new Set<Entry<M>>();\n readonly #pipelineEnabled: boolean;\n // Sentinel value signaling that the subscription is \"done\" and no more\n // messages can be added.\n #sentinel: 'canceled' | Error | undefined = undefined;\n\n #coalesce: ((curr: Entry<M>, prev: Entry<M>) => M) | undefined;\n #consumed: (prev: Entry<M>) => void;\n #cleanup: (unconsumed: Entry<M>[], err?: Error) => void;\n #publish: (internal: M) => T;\n\n /**\n * @param publish function for converting the internally pushed / coalesced message\n * of type `M` to the external type `T` exposed via async iteration.\n */\n constructor(options: Options<M> = {}, publish: (m: M) => T) {\n const {\n coalesce,\n consumed = () => {},\n cleanup = () => {},\n pipeline = coalesce === undefined,\n } = options;\n\n this.#coalesce = !coalesce\n ? undefined\n : (curr, prev) => {\n try {\n return coalesce(curr.value, prev.value);\n } finally {\n prev.resolve('coalesced');\n }\n };\n\n this.#consumed = entry => {\n consumed(entry.value);\n this.#consuming.delete(entry);\n entry.resolve('consumed');\n };\n\n this.#cleanup = (entries, err) => {\n cleanup(\n entries.map(e => e.value),\n err,\n );\n entries.forEach(e => e.resolve('unconsumed'));\n };\n\n this.#publish = publish;\n\n this.#pipelineEnabled = pipeline;\n }\n\n /**\n * Pushes the next message to be consumed, and returns a `result` that resolves to the\n * eventual {@link Result} of the `value`.\n *\n * If there is an existing unconsumed message and the Subscription has a\n * {@link Options#coalesce coalesce} function, the specified `value` will be coalesced\n * with the pending message. In this case, the result of the pending message\n * is resolved to `coalesced`, regardless of the `coalesce` function implementation.\n *\n * If the subscription is in a terminal state, the message is dropped and the\n * result resolves to `unconsumed`.\n */\n push(value: M): PendingResult {\n const {promise: result, resolve} = resolver<Result>();\n const entry = {value, resolve};\n\n if (this.#sentinel) {\n entry.resolve('unconsumed');\n return {result};\n }\n const consumer = this.#consumers.shift();\n if (consumer) {\n consumer.resolve(entry);\n } else if (\n this.#coalesce &&\n this.#messages.length &&\n this.#messages[this.#messages.length - 1] !== 'terminus'\n ) {\n const prev = this.#messages[this.#messages.length - 1];\n assert(prev !== 'terminus', 'prev should not be terminus after check');\n this.#messages[this.#messages.length - 1] = {\n value: this.#coalesce(entry, prev),\n resolve,\n };\n } else {\n this.#messages.push(entry);\n }\n return {result};\n }\n\n /** False if the subscription has been canceled or has failed. */\n get active(): boolean {\n return this.#sentinel === undefined;\n }\n\n /** The number of messages waiting to be dequeued. */\n get queued(): number {\n return this.#messages.length;\n }\n\n /** The number of messages dequeued but not yet \"consumed\" */\n get consuming(): number {\n return this.#consuming.size;\n }\n\n /**\n * Cancels the subscription after any queued messages are consumed. This is\n * meant for the producer-side code.\n *\n * Any messages pushed after calling `end()` will be unconsumed as if\n * `cancel()` were called (once the first set of pending messages is\n * consumed). In particular, if a coalesce function is defined, the new\n * messages will not be coalesced with the messages enqueued before `end()`\n * was called. However, to effect the intent of memory efficiency, multiple\n * messages pushed after calling `end()` will be coalesced together.\n *\n */\n end() {\n if (this.#sentinel) {\n // already terminated\n } else if (this.#messages.length === 0) {\n this.cancel();\n } else {\n this.#messages.push('terminus');\n }\n }\n\n /**\n * Cancels the subscription immediately, cleans up, and terminates any iteration.\n * This is intended for the consumer to call when it is no longer interested\n * in the subscription.\n *\n * @param err If an `err` is specified, an iteration over the Subscription /\n * Sink will throw the `err` (equivalent to the producer calling\n * {@link fail()}). If undefined, the iteration will exit gracefully.\n */\n cancel(err?: Error) {\n this.#terminate(err ?? 'canceled');\n }\n\n /** Fails the subscription, cleans up, and throws from any iteration. */\n fail(err: Error) {\n this.#terminate(err);\n }\n\n #terminate(sentinel: 'canceled' | Error) {\n if (!this.#sentinel) {\n this.#sentinel = sentinel;\n this.#cleanup(\n [...this.#consuming, ...this.#messages.filter(m => m !== 'terminus')],\n sentinel instanceof Error ? sentinel : undefined,\n );\n this.#messages.splice(0);\n\n for (\n let consumer = this.#consumers.shift();\n consumer;\n consumer = this.#consumers.shift()\n ) {\n sentinel === 'canceled'\n ? consumer.resolve(null)\n : consumer.reject(sentinel);\n }\n }\n }\n\n get pipeline(): AsyncIterable<{value: T; consumed: () => void}> | undefined {\n return this.#pipelineEnabled\n ? {[Symbol.asyncIterator]: () => this.#pipeline()}\n : undefined;\n }\n\n #pipeline(): AsyncIterator<{value: T; consumed: () => void}> {\n return {\n next: async () => {\n const entry = this.#messages.shift();\n if (entry === 'terminus') {\n this.cancel();\n return {value: undefined, done: true};\n }\n if (entry !== undefined) {\n this.#consuming.add(entry);\n return {\n value: {\n value: this.#publish(entry.value),\n consumed: () => this.#consumed(entry),\n },\n };\n }\n if (this.#sentinel === 'canceled') {\n return {value: undefined, done: true};\n }\n if (this.#sentinel) {\n return Promise.reject(this.#sentinel);\n }\n const consumer = resolver<Entry<M> | null>();\n this.#consumers.push(consumer);\n\n // Wait for push() (or termination) to resolve the consumer.\n const result = await consumer.promise;\n if (result !== null) {\n this.#consuming.add(result);\n return {\n value: {\n value: this.#publish(result.value),\n consumed: () => this.#consumed(result),\n },\n };\n }\n return {value: undefined, done: true};\n },\n\n return: value => {\n this.cancel();\n return Promise.resolve({value, done: true});\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n const delegate = this.#pipeline();\n\n let prevConsumed = () => {};\n return {\n next: async () => {\n prevConsumed();\n\n const entry = await delegate.next();\n if (entry.done) {\n return entry;\n }\n\n const {value, consumed} = entry.value;\n prevConsumed = consumed;\n return {value};\n },\n\n return: value => {\n prevConsumed();\n\n this.cancel();\n return Promise.resolve({value, done: true});\n },\n };\n }\n}\n\nexport type Options<M> = {\n /**\n * Coalesces messages waiting to be consumed. This is useful for \"watermark\" type\n * subscriptions in which the consumer is only interested in the cumulative state\n * change since the last processed message. When a `coalesce` function is specified,\n * there is guaranteed to be at most one message waiting to be consumed.\n *\n * Note that the `curr` argument comes before `prev`. This facilitates a common\n * scenario in which coalescing just means using the newest value; in such a case,\n * `coalesce` can simply be the identity function (e.g. `msg => msg`).\n */\n coalesce?: (curr: M, prev: M) => M;\n\n /**\n * Called on the previous message in an iteration (1) when the next message is requested,\n * or (2) when the iteration is terminated. This allows the producer to perform\n * per-message cleanup.\n *\n * Note that when a {@link Options.coalesce coalesce} function is defined,\n * `consumed` is _not_ called on the `prev` message; it is the responsibility of\n * producers requiring both coalescing and consumption notification to perform any\n * necessary cleanup of `prev` messages when coalescing.\n */\n consumed?: (prev: M) => void;\n\n /**\n * `cleanup` is called exactly once when the subscription is terminated via a failure or\n * cancelation (whichever happens first), which includes implicit cancelation when\n * the consumer exits an iteration via a `break`, `return`, or `throw` statement.\n *\n * Note that the `err` argument will only reflect an explicit cancelation via a call\n * to {@link Subscription.fail()}. On the other hand, if the iteration is canceled via\n * a `throw` statement, the thrown reason is not reflected in the `err` parameter, as that\n * information is not made available to the AsyncIterator implementation.\n */\n cleanup?: (unconsumed: M[], err?: Error) => void;\n\n /**\n * Enable or disable pipelining when streaming messages over a websocket.\n *\n * If unspecified, pipelining is enabled if there is no {@link Options.coalesce coalesce}\n * method, as pipelining is counter to the semantics of coalescing. However, the\n * application can explicitly enable pipelining even if there is a coalesce method\n * by specifying `true` for this option. This assumes that coalescing is either\n * not important for websocket semantics, or that the receiving end of the websocket\n * transport performs the desired coalescing.\n */\n pipeline?: boolean;\n};\n\n/** Post-queueing results of messages. */\nexport type Result = 'consumed' | 'coalesced' | 'unconsumed';\n\n/**\n * {@link Subscription.subscribe()} wraps the `Promise<Result>` in a `PendingResult`\n * object to avoid forcing all callers to handle the Promise, as most logic does not\n * need to.\n */\nexport type PendingResult = {result: Promise<Result>};\n\ntype Entry<M> = {\n readonly value: M;\n readonly resolve: (r: Result) => void;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"subscription.js","names":["#consumers","#messages","#consuming","#pipelineEnabled","#coalesce","#consumed","#cleanup","#publish","#sentinel","#terminate","#pipeline"],"sources":["../../../../../zero-cache/src/types/subscription.ts"],"sourcesContent":["import {resolver, type Resolver} from '@rocicorp/resolver';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {Sink, Source} from './streams.ts';\n\n/**\n * A Subscription abstracts a continuous, logically infinite stream of messages intended\n * for serial processing. Unlike the more general Node `Stream` API, a Subscription has\n * a limited API with specific semantics:\n *\n * * **Serial processing**: Messages must be consumed via the {@link AsyncIterable}\n * interface, e.g.\n * ```ts\n * const subscription = server.subscribe(parameters);\n *\n * for await (const message of subscription) {\n * await process(message); // fully process the message before consuming the next\n * }\n * ```\n *\n * Moreover, the consumer is expected to completely process each message before\n * requesting the next. This is important for cleanup semantics (explained later).\n *\n * * **cancel()**, not close(): The underlying data in a subscription is logically infinite\n * and only terminated when the consumer is no longer interested in receiving the messages\n * (or requires a Subscription with a different configuration). As such, there is no API\n * for gracefully closing the subscription after pending messages are consumed; rather,\n * cancellation is immediate, and upon cancellation, pending messages are dropped. A\n * Subscription can also be terminated with exceptional (i.e. `Error`) circumstances,\n * for which the behavior is equivalent.\n *\n * * **Coalescing** (optional): A producer can configure pending messages in the Subscription\n * to be merged together with a {@link Options.coalesce coalesce} function. This is useful\n * for semantics in which the consumer is not necessarily interested in every incremental\n * change, but rather the cumulative change since the last processed message. A\n * Subscription with coalescing is guaranteed to have at most one outstanding message,\n * regardless of how quickly messages are produced and consumed. This effectively constrains\n * the amount of outstanding work in the system.\n *\n * ### Resource Tracking and Cleanup\n *\n * Because message consumption is constrained to the async iteration API, standard\n * control flow mechanisms allow the producer to perform bookkeeping without any\n * explicit cleanup actions on the part of the consumer. This includes:\n *\n * * **Per-message cleanup**: Each request for the {@link AsyncIterator.next next}\n * message, or the termination of the iteration, signals that the consumer has\n * finished processing the previous message. The producer of a Subscription can\n * supply a {@link Options.consumed consumed} callback to receive these processed\n * messages, allowing it to clean up attached resources (e.g. TransactionPools, etc.).\n *\n * * **Per-subscription cleanup**: The producer of a Subscription can supply a\n * {@link Options.cleanup cleanup} callback that is invoked when the Subscription\n * is terminated, either explicitly via {@link Subscription.cancel cancel()} /\n * {@link Subscription.fail fail()}, or implicitly when an iteration is exited via a\n * `break`, `return`, or `throw` statement. All unconsumed messages are passed to the\n * call back to facilitate bookkeeping.\n *\n * @param T The external message type, published to the AsyncIterable\n * @param M The internal message type used in the producer-side interfaces\n * (e.g. {@link push}, {@link Options.consumed}, {@link Options.coalesce},\n * and {@link Options.cleanup}). This is often the same as the external type\n * T, but may be diverged to facilitate internal bookkeeping.\n */\nexport class Subscription<T, M = T> implements Source<T>, Sink<M> {\n /**\n * Convenience factory method for creating a {@link Subscription} with internal message type\n * `M` as a subtype of `T`, defaulting to the same type. The default `publish` method publishes\n * the message of type `M` directly to the AsyncIterable.\n */\n static create<T, M extends T = T>(\n options: Options<M> = {},\n publish: (m: M) => T = m => m,\n ) {\n return new Subscription(options, publish);\n }\n\n // Consumers waiting to consume messages (i.e. an async iteration awaiting the next message).\n readonly #consumers: Resolver<Entry<M> | null>[] = [];\n // Messages waiting to be dequeued.\n readonly #messages: (Entry<M> | 'terminus')[] = [];\n // Messages dequeued but not yet consumed.\n readonly #consuming = new Set<Entry<M>>();\n readonly #pipelineEnabled: boolean;\n // Sentinel value signaling that the subscription is \"done\" and no more\n // messages can be added.\n #sentinel: 'canceled' | Error | undefined = undefined;\n\n #coalesce: ((curr: Entry<M>, prev: Entry<M>) => M) | undefined;\n #consumed: (prev: Entry<M>) => void;\n #cleanup: (unconsumed: Entry<M>[], err?: Error) => void;\n #publish: (internal: M) => T;\n\n /**\n * @param publish function for converting the internally pushed / coalesced message\n * of type `M` to the external type `T` exposed via async iteration.\n */\n constructor(options: Options<M> = {}, publish: (m: M) => T) {\n const {\n coalesce,\n consumed = () => {},\n cleanup = () => {},\n pipeline = coalesce === undefined,\n } = options;\n\n this.#coalesce = !coalesce\n ? undefined\n : (curr, prev) => {\n try {\n return coalesce(curr.value, prev.value);\n } finally {\n prev.resolve('coalesced');\n }\n };\n\n this.#consumed = entry => {\n consumed(entry.value);\n this.#consuming.delete(entry);\n entry.resolve('consumed');\n };\n\n this.#cleanup = (entries, err) => {\n cleanup(\n entries.map(e => e.value),\n err,\n );\n entries.forEach(e => e.resolve('unconsumed'));\n };\n\n this.#publish = publish;\n\n this.#pipelineEnabled = pipeline;\n }\n\n /**\n * Pushes the next message to be consumed, and returns a `result` that resolves to the\n * eventual {@link Result} of the `value`.\n *\n * If there is an existing unconsumed message and the Subscription has a\n * {@link Options#coalesce coalesce} function, the specified `value` will be coalesced\n * with the pending message. In this case, the result of the pending message\n * is resolved to `coalesced`, regardless of the `coalesce` function implementation.\n *\n * If the subscription is in a terminal state, the message is dropped and the\n * result resolves to `unconsumed`.\n */\n push(value: M): PendingResult {\n const {promise: result, resolve} = resolver<Result>();\n const entry = {value, resolve};\n\n if (this.#sentinel) {\n entry.resolve('unconsumed');\n return {result};\n }\n const consumer = this.#consumers.shift();\n if (consumer) {\n consumer.resolve(entry);\n } else if (\n this.#coalesce &&\n this.#messages.length &&\n this.#messages.at(-1) !== 'terminus'\n ) {\n // oxlint-disable-next-line typescript/no-non-null-assertion\n const prev = this.#messages.at(-1)!;\n assert(prev !== 'terminus', 'prev should not be terminus after check');\n this.#messages[this.#messages.length - 1] = {\n value: this.#coalesce(entry, prev),\n resolve,\n };\n } else {\n this.#messages.push(entry);\n }\n return {result};\n }\n\n /** False if the subscription has been canceled or has failed. */\n get active(): boolean {\n return this.#sentinel === undefined;\n }\n\n /** The number of messages waiting to be dequeued. */\n get queued(): number {\n return this.#messages.length;\n }\n\n /** The number of messages dequeued but not yet \"consumed\" */\n get consuming(): number {\n return this.#consuming.size;\n }\n\n /**\n * Cancels the subscription after any queued messages are consumed. This is\n * meant for the producer-side code.\n *\n * Any messages pushed after calling `end()` will be unconsumed as if\n * `cancel()` were called (once the first set of pending messages is\n * consumed). In particular, if a coalesce function is defined, the new\n * messages will not be coalesced with the messages enqueued before `end()`\n * was called. However, to effect the intent of memory efficiency, multiple\n * messages pushed after calling `end()` will be coalesced together.\n *\n */\n end() {\n if (this.#sentinel) {\n // already terminated\n } else if (this.#messages.length === 0) {\n this.cancel();\n } else {\n this.#messages.push('terminus');\n }\n }\n\n /**\n * Cancels the subscription immediately, cleans up, and terminates any iteration.\n * This is intended for the consumer to call when it is no longer interested\n * in the subscription.\n *\n * @param err If an `err` is specified, an iteration over the Subscription /\n * Sink will throw the `err` (equivalent to the producer calling\n * {@link fail()}). If undefined, the iteration will exit gracefully.\n */\n cancel(err?: Error) {\n this.#terminate(err ?? 'canceled');\n }\n\n /** Fails the subscription, cleans up, and throws from any iteration. */\n fail(err: Error) {\n this.#terminate(err);\n }\n\n #terminate(sentinel: 'canceled' | Error) {\n if (!this.#sentinel) {\n this.#sentinel = sentinel;\n this.#cleanup(\n [...this.#consuming, ...this.#messages.filter(m => m !== 'terminus')],\n sentinel instanceof Error ? sentinel : undefined,\n );\n this.#messages.splice(0);\n\n for (\n let consumer = this.#consumers.shift();\n consumer;\n consumer = this.#consumers.shift()\n ) {\n sentinel === 'canceled'\n ? consumer.resolve(null)\n : consumer.reject(sentinel);\n }\n }\n }\n\n get pipeline(): AsyncIterable<{value: T; consumed: () => void}> | undefined {\n return this.#pipelineEnabled\n ? {[Symbol.asyncIterator]: () => this.#pipeline()}\n : undefined;\n }\n\n #pipeline(): AsyncIterator<{value: T; consumed: () => void}> {\n return {\n next: async () => {\n const entry = this.#messages.shift();\n if (entry === 'terminus') {\n this.cancel();\n return {value: undefined, done: true};\n }\n if (entry !== undefined) {\n this.#consuming.add(entry);\n return {\n value: {\n value: this.#publish(entry.value),\n consumed: () => this.#consumed(entry),\n },\n };\n }\n if (this.#sentinel === 'canceled') {\n return {value: undefined, done: true};\n }\n if (this.#sentinel) {\n return Promise.reject(this.#sentinel);\n }\n const consumer = resolver<Entry<M> | null>();\n this.#consumers.push(consumer);\n\n // Wait for push() (or termination) to resolve the consumer.\n const result = await consumer.promise;\n if (result !== null) {\n this.#consuming.add(result);\n return {\n value: {\n value: this.#publish(result.value),\n consumed: () => this.#consumed(result),\n },\n };\n }\n return {value: undefined, done: true};\n },\n\n return: value => {\n this.cancel();\n return Promise.resolve({value, done: true});\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n const delegate = this.#pipeline();\n\n let prevConsumed = () => {};\n return {\n next: async () => {\n prevConsumed();\n\n const entry = await delegate.next();\n if (entry.done) {\n return entry;\n }\n\n const {value, consumed} = entry.value;\n prevConsumed = consumed;\n return {value};\n },\n\n return: value => {\n prevConsumed();\n\n this.cancel();\n return Promise.resolve({value, done: true});\n },\n };\n }\n}\n\nexport type Options<M> = {\n /**\n * Coalesces messages waiting to be consumed. This is useful for \"watermark\" type\n * subscriptions in which the consumer is only interested in the cumulative state\n * change since the last processed message. When a `coalesce` function is specified,\n * there is guaranteed to be at most one message waiting to be consumed.\n *\n * Note that the `curr` argument comes before `prev`. This facilitates a common\n * scenario in which coalescing just means using the newest value; in such a case,\n * `coalesce` can simply be the identity function (e.g. `msg => msg`).\n */\n coalesce?: (curr: M, prev: M) => M;\n\n /**\n * Called on the previous message in an iteration (1) when the next message is requested,\n * or (2) when the iteration is terminated. This allows the producer to perform\n * per-message cleanup.\n *\n * Note that when a {@link Options.coalesce coalesce} function is defined,\n * `consumed` is _not_ called on the `prev` message; it is the responsibility of\n * producers requiring both coalescing and consumption notification to perform any\n * necessary cleanup of `prev` messages when coalescing.\n */\n consumed?: (prev: M) => void;\n\n /**\n * `cleanup` is called exactly once when the subscription is terminated via a failure or\n * cancelation (whichever happens first), which includes implicit cancelation when\n * the consumer exits an iteration via a `break`, `return`, or `throw` statement.\n *\n * Note that the `err` argument will only reflect an explicit cancelation via a call\n * to {@link Subscription.fail()}. On the other hand, if the iteration is canceled via\n * a `throw` statement, the thrown reason is not reflected in the `err` parameter, as that\n * information is not made available to the AsyncIterator implementation.\n */\n cleanup?: (unconsumed: M[], err?: Error) => void;\n\n /**\n * Enable or disable pipelining when streaming messages over a websocket.\n *\n * If unspecified, pipelining is enabled if there is no {@link Options.coalesce coalesce}\n * method, as pipelining is counter to the semantics of coalescing. However, the\n * application can explicitly enable pipelining even if there is a coalesce method\n * by specifying `true` for this option. This assumes that coalescing is either\n * not important for websocket semantics, or that the receiving end of the websocket\n * transport performs the desired coalescing.\n */\n pipeline?: boolean;\n};\n\n/** Post-queueing results of messages. */\nexport type Result = 'consumed' | 'coalesced' | 'unconsumed';\n\n/**\n * {@link Subscription.subscribe()} wraps the `Promise<Result>` in a `PendingResult`\n * object to avoid forcing all callers to handle the Promise, as most logic does not\n * need to.\n */\nexport type PendingResult = {result: Promise<Result>};\n\ntype Entry<M> = {\n readonly value: M;\n readonly resolve: (r: Result) => void;\n};\n"],"mappings":"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"}
@@ -11,7 +11,7 @@ export type ConnectParams = {
11
11
  readonly wsID: string;
12
12
  readonly debugPerf: boolean;
13
13
  readonly auth: string | undefined;
14
- readonly userID: string;
14
+ readonly userID: string | undefined;
15
15
  readonly initConnectionMsg: InitConnectionMessage | undefined;
16
16
  readonly httpCookie: string | undefined;
17
17
  readonly origin: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"connect-params.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/connect-params.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,YAAY,CAAC;AAEpD,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,uCAAuC,CAAC;AAG/C,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC9D,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,MAAM,EACvB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,mBAAmB,GAE1B;IACE,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CA0CJ"}
1
+ {"version":3,"file":"connect-params.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/connect-params.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,YAAY,CAAC;AAEpD,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,uCAAuC,CAAC;AAG/C,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC9D,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,MAAM,EACvB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,mBAAmB,GAE1B;IACE,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CA0CJ"}
@@ -12,7 +12,7 @@ function getConnectParams(protocolVersion, url, headers) {
12
12
  const timestamp = params.getInteger("ts", true);
13
13
  const lmID = params.getInteger("lmid", true);
14
14
  const wsID = params.get("wsid", false) ?? "";
15
- const userID = params.get("userID", false) ?? "";
15
+ const userID = params.get("userID", false) ?? void 0;
16
16
  const debugPerf = params.getBoolean("debugPerf");
17
17
  const { initConnectionMessage, authToken } = decodeSecProtocols(must(headers["sec-websocket-protocol"]));
18
18
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"connect-params.js","names":[],"sources":["../../../../../zero-cache/src/workers/connect-params.ts"],"sourcesContent":["import type {IncomingHttpHeaders} from 'node:http2';\nimport {must} from '../../../shared/src/must.ts';\nimport {\n decodeSecProtocols,\n type InitConnectionMessage,\n} from '../../../zero-protocol/src/connect.ts';\nimport {URLParams} from '../types/url-params.ts';\n\nexport type ConnectParams = {\n readonly protocolVersion: number;\n readonly clientID: string;\n readonly clientGroupID: string;\n readonly profileID: string | null;\n readonly baseCookie: string | null;\n readonly timestamp: number;\n readonly lmID: number;\n readonly wsID: string;\n readonly debugPerf: boolean;\n readonly auth: string | undefined;\n readonly userID: string;\n readonly initConnectionMsg: InitConnectionMessage | undefined;\n readonly httpCookie: string | undefined;\n readonly origin: string | undefined;\n};\n\nexport function getConnectParams(\n protocolVersion: number,\n url: URL,\n headers: IncomingHttpHeaders,\n):\n | {\n params: ConnectParams;\n error: null;\n }\n | {\n params: null;\n error: string;\n } {\n const params = new URLParams(url);\n\n try {\n const clientID = params.get('clientID', true);\n const clientGroupID = params.get('clientGroupID', true);\n const profileID = params.get('profileID', false);\n const baseCookie = params.get('baseCookie', false);\n const timestamp = params.getInteger('ts', true);\n const lmID = params.getInteger('lmid', true);\n const wsID = params.get('wsid', false) ?? '';\n const userID = params.get('userID', false) ?? '';\n const debugPerf = params.getBoolean('debugPerf');\n const {initConnectionMessage, authToken} = decodeSecProtocols(\n must(headers['sec-websocket-protocol']),\n );\n\n return {\n params: {\n protocolVersion,\n clientID,\n clientGroupID,\n profileID,\n baseCookie,\n timestamp,\n lmID,\n wsID,\n debugPerf,\n initConnectionMsg: initConnectionMessage,\n auth: authToken,\n userID,\n httpCookie: headers.cookie,\n origin: headers.origin,\n },\n error: null,\n };\n } catch (e) {\n return {\n params: null,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n}\n"],"mappings":";;;;AAyBA,SAAgB,iBACd,iBACA,KACA,SASI;CACJ,MAAM,SAAS,IAAI,UAAU,IAAI;AAEjC,KAAI;EACF,MAAM,WAAW,OAAO,IAAI,YAAY,KAAK;EAC7C,MAAM,gBAAgB,OAAO,IAAI,iBAAiB,KAAK;EACvD,MAAM,YAAY,OAAO,IAAI,aAAa,MAAM;EAChD,MAAM,aAAa,OAAO,IAAI,cAAc,MAAM;EAClD,MAAM,YAAY,OAAO,WAAW,MAAM,KAAK;EAC/C,MAAM,OAAO,OAAO,WAAW,QAAQ,KAAK;EAC5C,MAAM,OAAO,OAAO,IAAI,QAAQ,MAAM,IAAI;EAC1C,MAAM,SAAS,OAAO,IAAI,UAAU,MAAM,IAAI;EAC9C,MAAM,YAAY,OAAO,WAAW,YAAY;EAChD,MAAM,EAAC,uBAAuB,cAAa,mBACzC,KAAK,QAAQ,0BAA0B,CACxC;AAED,SAAO;GACL,QAAQ;IACN;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,mBAAmB;IACnB,MAAM;IACN;IACA,YAAY,QAAQ;IACpB,QAAQ,QAAQ;IACjB;GACD,OAAO;GACR;UACM,GAAG;AACV,SAAO;GACL,QAAQ;GACR,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;GAClD"}
1
+ {"version":3,"file":"connect-params.js","names":[],"sources":["../../../../../zero-cache/src/workers/connect-params.ts"],"sourcesContent":["import type {IncomingHttpHeaders} from 'node:http2';\nimport {must} from '../../../shared/src/must.ts';\nimport {\n decodeSecProtocols,\n type InitConnectionMessage,\n} from '../../../zero-protocol/src/connect.ts';\nimport {URLParams} from '../types/url-params.ts';\n\nexport type ConnectParams = {\n readonly protocolVersion: number;\n readonly clientID: string;\n readonly clientGroupID: string;\n readonly profileID: string | null;\n readonly baseCookie: string | null;\n readonly timestamp: number;\n readonly lmID: number;\n readonly wsID: string;\n readonly debugPerf: boolean;\n readonly auth: string | undefined;\n readonly userID: string | undefined;\n readonly initConnectionMsg: InitConnectionMessage | undefined;\n readonly httpCookie: string | undefined;\n readonly origin: string | undefined;\n};\n\nexport function getConnectParams(\n protocolVersion: number,\n url: URL,\n headers: IncomingHttpHeaders,\n):\n | {\n params: ConnectParams;\n error: null;\n }\n | {\n params: null;\n error: string;\n } {\n const params = new URLParams(url);\n\n try {\n const clientID = params.get('clientID', true);\n const clientGroupID = params.get('clientGroupID', true);\n const profileID = params.get('profileID', false);\n const baseCookie = params.get('baseCookie', false);\n const timestamp = params.getInteger('ts', true);\n const lmID = params.getInteger('lmid', true);\n const wsID = params.get('wsid', false) ?? '';\n const userID = params.get('userID', false) ?? undefined;\n const debugPerf = params.getBoolean('debugPerf');\n const {initConnectionMessage, authToken} = decodeSecProtocols(\n must(headers['sec-websocket-protocol']),\n );\n\n return {\n params: {\n protocolVersion,\n clientID,\n clientGroupID,\n profileID,\n baseCookie,\n timestamp,\n lmID,\n wsID,\n debugPerf,\n initConnectionMsg: initConnectionMessage,\n auth: authToken,\n userID,\n httpCookie: headers.cookie,\n origin: headers.origin,\n },\n error: null,\n };\n } catch (e) {\n return {\n params: null,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n}\n"],"mappings":";;;;AAyBA,SAAgB,iBACd,iBACA,KACA,SASI;CACJ,MAAM,SAAS,IAAI,UAAU,IAAI;AAEjC,KAAI;EACF,MAAM,WAAW,OAAO,IAAI,YAAY,KAAK;EAC7C,MAAM,gBAAgB,OAAO,IAAI,iBAAiB,KAAK;EACvD,MAAM,YAAY,OAAO,IAAI,aAAa,MAAM;EAChD,MAAM,aAAa,OAAO,IAAI,cAAc,MAAM;EAClD,MAAM,YAAY,OAAO,WAAW,MAAM,KAAK;EAC/C,MAAM,OAAO,OAAO,WAAW,QAAQ,KAAK;EAC5C,MAAM,OAAO,OAAO,IAAI,QAAQ,MAAM,IAAI;EAC1C,MAAM,SAAS,OAAO,IAAI,UAAU,MAAM,IAAI,KAAA;EAC9C,MAAM,YAAY,OAAO,WAAW,YAAY;EAChD,MAAM,EAAC,uBAAuB,cAAa,mBACzC,KAAK,QAAQ,0BAA0B,CACxC;AAED,SAAO;GACL,QAAQ;IACN;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,mBAAmB;IACnB,MAAM;IACN;IACA,YAAY,QAAQ;IACpB,QAAQ,QAAQ;IACjB;GACD,OAAO;GACR;UACM,GAAG;AACV,SAAO;GACL,QAAQ;GACR,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;GAClD"}
@@ -51,9 +51,9 @@ var Connection = class {
51
51
  * will only parse messages with schema(s) of supported protocol versions.
52
52
  */
53
53
  init() {
54
- if (this.#protocolVersion > 49 || this.#protocolVersion < 30) this.#closeWithError({
54
+ if (this.#protocolVersion > 50 || this.#protocolVersion < 30) this.#closeWithError({
55
55
  kind: VersionNotSupported,
56
- message: `server is at sync protocol v49 and does not support v${this.#protocolVersion}. The ${this.#protocolVersion > 49 ? "server" : "client"} must be updated to a newer release.`,
56
+ message: `server is at sync protocol v50 and does not support v${this.#protocolVersion}. The ${this.#protocolVersion > 50 ? "server" : "client"} must be updated to a newer release.`,
57
57
  origin: ZeroCache
58
58
  });
59
59
  else {
@@ -2,12 +2,13 @@ import type { LogContext } from '@rocicorp/logger';
2
2
  import type { Upstream } from '../../../zero-protocol/src/up.ts';
3
3
  import type { Mutagen } from '../services/mutagen/mutagen.ts';
4
4
  import type { Pusher } from '../services/mutagen/pusher.ts';
5
+ import { type ConnectionContextManager } from '../services/view-syncer/connection-context-manager.ts';
5
6
  import { type ViewSyncer } from '../services/view-syncer/view-syncer.ts';
6
7
  import type { ConnectParams } from './connect-params.ts';
7
8
  import type { HandlerResult, MessageHandler } from './connection.ts';
8
9
  export declare class SyncerWsMessageHandler implements MessageHandler {
9
10
  #private;
10
- constructor(lc: LogContext, connectParams: ConnectParams, viewSyncer: ViewSyncer, mutagen: Mutagen, pusher: Pusher | undefined);
11
+ constructor(lc: LogContext, connectParams: ConnectParams, contextManager: ConnectionContextManager, viewSyncer: ViewSyncer, mutagen: Mutagen | undefined, pusher: Pusher | undefined);
11
12
  handleMessage(msg: Upstream): Promise<HandlerResult[]>;
12
13
  }
13
14
  //# sourceMappingURL=syncer-ws-message-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"syncer-ws-message-handler.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/syncer-ws-message-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAOjD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,kCAAkC,CAAC;AAC/D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,gCAAgC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAC,aAAa,EAAE,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAInE,qBAAa,sBAAuB,YAAW,cAAc;;gBAUzD,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,GAAG,SAAS;IAmCtB,aAAa,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;CA+K7D"}
1
+ {"version":3,"file":"syncer-ws-message-handler.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/syncer-ws-message-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAOjD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,kCAAkC,CAAC;AAC/D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,gCAAgC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,uDAAuD,CAAC;AAC/D,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,wCAAwC,CAAC;AACvE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAC,aAAa,EAAE,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAiBnE,qBAAa,sBAAuB,YAAW,cAAc;;gBAWzD,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,aAAa,EAC5B,cAAc,EAAE,wBAAwB,EACxC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,GAAG,SAAS;IAoBtB,aAAa,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;CAgN7D"}