@proseql/core 0.1.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 (342) hide show
  1. package/LICENSE +21 -0
  2. package/dist/errors/crud-errors.d.ts +98 -0
  3. package/dist/errors/crud-errors.d.ts.map +1 -0
  4. package/dist/errors/crud-errors.js +23 -0
  5. package/dist/errors/crud-errors.js.map +1 -0
  6. package/dist/errors/index.d.ts +16 -0
  7. package/dist/errors/index.d.ts.map +1 -0
  8. package/dist/errors/index.js +12 -0
  9. package/dist/errors/index.js.map +1 -0
  10. package/dist/errors/migration-errors.d.ts +22 -0
  11. package/dist/errors/migration-errors.d.ts.map +1 -0
  12. package/dist/errors/migration-errors.js +14 -0
  13. package/dist/errors/migration-errors.js.map +1 -0
  14. package/dist/errors/plugin-errors.d.ts +15 -0
  15. package/dist/errors/plugin-errors.d.ts.map +1 -0
  16. package/dist/errors/plugin-errors.js +11 -0
  17. package/dist/errors/plugin-errors.js.map +1 -0
  18. package/dist/errors/query-errors.d.ts +31 -0
  19. package/dist/errors/query-errors.d.ts.map +1 -0
  20. package/dist/errors/query-errors.js +11 -0
  21. package/dist/errors/query-errors.js.map +1 -0
  22. package/dist/errors/storage-errors.d.ts +30 -0
  23. package/dist/errors/storage-errors.d.ts.map +1 -0
  24. package/dist/errors/storage-errors.js +11 -0
  25. package/dist/errors/storage-errors.js.map +1 -0
  26. package/dist/factories/crud-factory-with-relationships.d.ts +28 -0
  27. package/dist/factories/crud-factory-with-relationships.d.ts.map +1 -0
  28. package/dist/factories/crud-factory-with-relationships.js +8 -0
  29. package/dist/factories/crud-factory-with-relationships.js.map +1 -0
  30. package/dist/factories/crud-factory.d.ts +25 -0
  31. package/dist/factories/crud-factory.d.ts.map +1 -0
  32. package/dist/factories/crud-factory.js +8 -0
  33. package/dist/factories/crud-factory.js.map +1 -0
  34. package/dist/factories/database-effect.d.ts +241 -0
  35. package/dist/factories/database-effect.d.ts.map +1 -0
  36. package/dist/factories/database-effect.js +859 -0
  37. package/dist/factories/database-effect.js.map +1 -0
  38. package/dist/hooks/hook-runner.d.ts +60 -0
  39. package/dist/hooks/hook-runner.d.ts.map +1 -0
  40. package/dist/hooks/hook-runner.js +107 -0
  41. package/dist/hooks/hook-runner.js.map +1 -0
  42. package/dist/index.d.ts +84 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +110 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/indexes/index-lookup.d.ts +33 -0
  47. package/dist/indexes/index-lookup.d.ts.map +1 -0
  48. package/dist/indexes/index-lookup.js +180 -0
  49. package/dist/indexes/index-lookup.js.map +1 -0
  50. package/dist/indexes/index-manager.d.ts +118 -0
  51. package/dist/indexes/index-manager.d.ts.map +1 -0
  52. package/dist/indexes/index-manager.js +345 -0
  53. package/dist/indexes/index-manager.js.map +1 -0
  54. package/dist/indexes/search-index.d.ts +179 -0
  55. package/dist/indexes/search-index.d.ts.map +1 -0
  56. package/dist/indexes/search-index.js +405 -0
  57. package/dist/indexes/search-index.js.map +1 -0
  58. package/dist/migrations/migration-runner.d.ts +70 -0
  59. package/dist/migrations/migration-runner.d.ts.map +1 -0
  60. package/dist/migrations/migration-runner.js +271 -0
  61. package/dist/migrations/migration-runner.js.map +1 -0
  62. package/dist/migrations/migration-types.d.ts +63 -0
  63. package/dist/migrations/migration-types.d.ts.map +1 -0
  64. package/dist/migrations/migration-types.js +5 -0
  65. package/dist/migrations/migration-types.js.map +1 -0
  66. package/dist/operations/crud/create-with-relationships.d.ts +44 -0
  67. package/dist/operations/crud/create-with-relationships.d.ts.map +1 -0
  68. package/dist/operations/crud/create-with-relationships.js +483 -0
  69. package/dist/operations/crud/create-with-relationships.js.map +1 -0
  70. package/dist/operations/crud/create.d.ts +48 -0
  71. package/dist/operations/crud/create.d.ts.map +1 -0
  72. package/dist/operations/crud/create.js +333 -0
  73. package/dist/operations/crud/create.js.map +1 -0
  74. package/dist/operations/crud/delete-with-relationships.d.ts +63 -0
  75. package/dist/operations/crud/delete-with-relationships.d.ts.map +1 -0
  76. package/dist/operations/crud/delete-with-relationships.js +395 -0
  77. package/dist/operations/crud/delete-with-relationships.js.map +1 -0
  78. package/dist/operations/crud/delete.d.ts +58 -0
  79. package/dist/operations/crud/delete.d.ts.map +1 -0
  80. package/dist/operations/crud/delete.js +267 -0
  81. package/dist/operations/crud/delete.js.map +1 -0
  82. package/dist/operations/crud/unique-check.d.ts +114 -0
  83. package/dist/operations/crud/unique-check.d.ts.map +1 -0
  84. package/dist/operations/crud/unique-check.js +383 -0
  85. package/dist/operations/crud/unique-check.js.map +1 -0
  86. package/dist/operations/crud/update-with-relationships.d.ts +45 -0
  87. package/dist/operations/crud/update-with-relationships.d.ts.map +1 -0
  88. package/dist/operations/crud/update-with-relationships.js +516 -0
  89. package/dist/operations/crud/update-with-relationships.js.map +1 -0
  90. package/dist/operations/crud/update.d.ts +91 -0
  91. package/dist/operations/crud/update.d.ts.map +1 -0
  92. package/dist/operations/crud/update.js +505 -0
  93. package/dist/operations/crud/update.js.map +1 -0
  94. package/dist/operations/crud/upsert.d.ts +52 -0
  95. package/dist/operations/crud/upsert.d.ts.map +1 -0
  96. package/dist/operations/crud/upsert.js +386 -0
  97. package/dist/operations/crud/upsert.js.map +1 -0
  98. package/dist/operations/query/aggregate.d.ts +30 -0
  99. package/dist/operations/query/aggregate.d.ts.map +1 -0
  100. package/dist/operations/query/aggregate.js +227 -0
  101. package/dist/operations/query/aggregate.js.map +1 -0
  102. package/dist/operations/query/cursor-stream.d.ts +18 -0
  103. package/dist/operations/query/cursor-stream.d.ts.map +1 -0
  104. package/dist/operations/query/cursor-stream.js +199 -0
  105. package/dist/operations/query/cursor-stream.js.map +1 -0
  106. package/dist/operations/query/filter-stream.d.ts +12 -0
  107. package/dist/operations/query/filter-stream.d.ts.map +1 -0
  108. package/dist/operations/query/filter-stream.js +167 -0
  109. package/dist/operations/query/filter-stream.js.map +1 -0
  110. package/dist/operations/query/filter.d.ts +13 -0
  111. package/dist/operations/query/filter.d.ts.map +1 -0
  112. package/dist/operations/query/filter.js +267 -0
  113. package/dist/operations/query/filter.js.map +1 -0
  114. package/dist/operations/query/paginate-stream.d.ts +11 -0
  115. package/dist/operations/query/paginate-stream.d.ts.map +1 -0
  116. package/dist/operations/query/paginate-stream.js +22 -0
  117. package/dist/operations/query/paginate-stream.js.map +1 -0
  118. package/dist/operations/query/query-helpers.d.ts +14 -0
  119. package/dist/operations/query/query-helpers.d.ts.map +1 -0
  120. package/dist/operations/query/query-helpers.js +22 -0
  121. package/dist/operations/query/query-helpers.js.map +1 -0
  122. package/dist/operations/query/resolve-computed.d.ts +142 -0
  123. package/dist/operations/query/resolve-computed.d.ts.map +1 -0
  124. package/dist/operations/query/resolve-computed.js +197 -0
  125. package/dist/operations/query/resolve-computed.js.map +1 -0
  126. package/dist/operations/query/search.d.ts +110 -0
  127. package/dist/operations/query/search.d.ts.map +1 -0
  128. package/dist/operations/query/search.js +188 -0
  129. package/dist/operations/query/search.js.map +1 -0
  130. package/dist/operations/query/select-stream.d.ts +27 -0
  131. package/dist/operations/query/select-stream.d.ts.map +1 -0
  132. package/dist/operations/query/select-stream.js +88 -0
  133. package/dist/operations/query/select-stream.js.map +1 -0
  134. package/dist/operations/query/select.d.ts +54 -0
  135. package/dist/operations/query/select.d.ts.map +1 -0
  136. package/dist/operations/query/select.js +159 -0
  137. package/dist/operations/query/select.js.map +1 -0
  138. package/dist/operations/query/sort-stream.d.ts +46 -0
  139. package/dist/operations/query/sort-stream.d.ts.map +1 -0
  140. package/dist/operations/query/sort-stream.js +158 -0
  141. package/dist/operations/query/sort-stream.js.map +1 -0
  142. package/dist/operations/query/sort.d.ts +9 -0
  143. package/dist/operations/query/sort.d.ts.map +1 -0
  144. package/dist/operations/query/sort.js +58 -0
  145. package/dist/operations/query/sort.js.map +1 -0
  146. package/dist/operations/relationships/populate-stream.d.ts +29 -0
  147. package/dist/operations/relationships/populate-stream.d.ts.map +1 -0
  148. package/dist/operations/relationships/populate-stream.js +159 -0
  149. package/dist/operations/relationships/populate-stream.js.map +1 -0
  150. package/dist/operations/relationships/populate.d.ts +15 -0
  151. package/dist/operations/relationships/populate.d.ts.map +1 -0
  152. package/dist/operations/relationships/populate.js +228 -0
  153. package/dist/operations/relationships/populate.js.map +1 -0
  154. package/dist/plugins/plugin-hooks.d.ts +25 -0
  155. package/dist/plugins/plugin-hooks.d.ts.map +1 -0
  156. package/dist/plugins/plugin-hooks.js +64 -0
  157. package/dist/plugins/plugin-hooks.js.map +1 -0
  158. package/dist/plugins/plugin-registry.d.ts +26 -0
  159. package/dist/plugins/plugin-registry.d.ts.map +1 -0
  160. package/dist/plugins/plugin-registry.js +150 -0
  161. package/dist/plugins/plugin-registry.js.map +1 -0
  162. package/dist/plugins/plugin-types.d.ts +95 -0
  163. package/dist/plugins/plugin-types.d.ts.map +1 -0
  164. package/dist/plugins/plugin-types.js +6 -0
  165. package/dist/plugins/plugin-types.js.map +1 -0
  166. package/dist/plugins/plugin-validation.d.ts +49 -0
  167. package/dist/plugins/plugin-validation.d.ts.map +1 -0
  168. package/dist/plugins/plugin-validation.js +295 -0
  169. package/dist/plugins/plugin-validation.js.map +1 -0
  170. package/dist/reactive/change-event.d.ts +44 -0
  171. package/dist/reactive/change-event.d.ts.map +1 -0
  172. package/dist/reactive/change-event.js +49 -0
  173. package/dist/reactive/change-event.js.map +1 -0
  174. package/dist/reactive/change-pubsub.d.ts +32 -0
  175. package/dist/reactive/change-pubsub.d.ts.map +1 -0
  176. package/dist/reactive/change-pubsub.js +31 -0
  177. package/dist/reactive/change-pubsub.js.map +1 -0
  178. package/dist/reactive/evaluate-query.d.ts +62 -0
  179. package/dist/reactive/evaluate-query.d.ts.map +1 -0
  180. package/dist/reactive/evaluate-query.js +57 -0
  181. package/dist/reactive/evaluate-query.js.map +1 -0
  182. package/dist/reactive/watch-by-id.d.ts +53 -0
  183. package/dist/reactive/watch-by-id.d.ts.map +1 -0
  184. package/dist/reactive/watch-by-id.js +55 -0
  185. package/dist/reactive/watch-by-id.js.map +1 -0
  186. package/dist/reactive/watch.d.ts +78 -0
  187. package/dist/reactive/watch.d.ts.map +1 -0
  188. package/dist/reactive/watch.js +133 -0
  189. package/dist/reactive/watch.js.map +1 -0
  190. package/dist/serializers/codecs/hjson.d.ts +33 -0
  191. package/dist/serializers/codecs/hjson.d.ts.map +1 -0
  192. package/dist/serializers/codecs/hjson.js +40 -0
  193. package/dist/serializers/codecs/hjson.js.map +1 -0
  194. package/dist/serializers/codecs/json.d.ts +22 -0
  195. package/dist/serializers/codecs/json.d.ts.map +1 -0
  196. package/dist/serializers/codecs/json.js +28 -0
  197. package/dist/serializers/codecs/json.js.map +1 -0
  198. package/dist/serializers/codecs/json5.d.ts +26 -0
  199. package/dist/serializers/codecs/json5.d.ts.map +1 -0
  200. package/dist/serializers/codecs/json5.js +33 -0
  201. package/dist/serializers/codecs/json5.js.map +1 -0
  202. package/dist/serializers/codecs/jsonc.d.ts +29 -0
  203. package/dist/serializers/codecs/jsonc.d.ts.map +1 -0
  204. package/dist/serializers/codecs/jsonc.js +38 -0
  205. package/dist/serializers/codecs/jsonc.js.map +1 -0
  206. package/dist/serializers/codecs/jsonl.d.ts +17 -0
  207. package/dist/serializers/codecs/jsonl.d.ts.map +1 -0
  208. package/dist/serializers/codecs/jsonl.js +31 -0
  209. package/dist/serializers/codecs/jsonl.js.map +1 -0
  210. package/dist/serializers/codecs/prose.d.ts +419 -0
  211. package/dist/serializers/codecs/prose.d.ts.map +1 -0
  212. package/dist/serializers/codecs/prose.js +1060 -0
  213. package/dist/serializers/codecs/prose.js.map +1 -0
  214. package/dist/serializers/codecs/toml.d.ts +23 -0
  215. package/dist/serializers/codecs/toml.d.ts.map +1 -0
  216. package/dist/serializers/codecs/toml.js +66 -0
  217. package/dist/serializers/codecs/toml.js.map +1 -0
  218. package/dist/serializers/codecs/toon.d.ts +20 -0
  219. package/dist/serializers/codecs/toon.d.ts.map +1 -0
  220. package/dist/serializers/codecs/toon.js +33 -0
  221. package/dist/serializers/codecs/toon.js.map +1 -0
  222. package/dist/serializers/codecs/yaml.d.ts +24 -0
  223. package/dist/serializers/codecs/yaml.d.ts.map +1 -0
  224. package/dist/serializers/codecs/yaml.js +31 -0
  225. package/dist/serializers/codecs/yaml.js.map +1 -0
  226. package/dist/serializers/format-codec.d.ts +53 -0
  227. package/dist/serializers/format-codec.d.ts.map +1 -0
  228. package/dist/serializers/format-codec.js +148 -0
  229. package/dist/serializers/format-codec.js.map +1 -0
  230. package/dist/serializers/presets.d.ts +48 -0
  231. package/dist/serializers/presets.d.ts.map +1 -0
  232. package/dist/serializers/presets.js +72 -0
  233. package/dist/serializers/presets.js.map +1 -0
  234. package/dist/serializers/serializer-service.d.ts +11 -0
  235. package/dist/serializers/serializer-service.d.ts.map +1 -0
  236. package/dist/serializers/serializer-service.js +4 -0
  237. package/dist/serializers/serializer-service.js.map +1 -0
  238. package/dist/state/collection-state.d.ts +19 -0
  239. package/dist/state/collection-state.d.ts.map +1 -0
  240. package/dist/state/collection-state.js +15 -0
  241. package/dist/state/collection-state.js.map +1 -0
  242. package/dist/state/state-operations.d.ts +38 -0
  243. package/dist/state/state-operations.d.ts.map +1 -0
  244. package/dist/state/state-operations.js +65 -0
  245. package/dist/state/state-operations.js.map +1 -0
  246. package/dist/storage/in-memory-adapter-layer.d.ts +16 -0
  247. package/dist/storage/in-memory-adapter-layer.d.ts.map +1 -0
  248. package/dist/storage/in-memory-adapter-layer.js +81 -0
  249. package/dist/storage/in-memory-adapter-layer.js.map +1 -0
  250. package/dist/storage/persistence-effect.d.ts +244 -0
  251. package/dist/storage/persistence-effect.d.ts.map +1 -0
  252. package/dist/storage/persistence-effect.js +551 -0
  253. package/dist/storage/persistence-effect.js.map +1 -0
  254. package/dist/storage/storage-service.d.ts +22 -0
  255. package/dist/storage/storage-service.d.ts.map +1 -0
  256. package/dist/storage/storage-service.js +4 -0
  257. package/dist/storage/storage-service.js.map +1 -0
  258. package/dist/storage/transforms.d.ts +183 -0
  259. package/dist/storage/transforms.d.ts.map +1 -0
  260. package/dist/storage/transforms.js +263 -0
  261. package/dist/storage/transforms.js.map +1 -0
  262. package/dist/transactions/transaction.d.ts +87 -0
  263. package/dist/transactions/transaction.d.ts.map +1 -0
  264. package/dist/transactions/transaction.js +240 -0
  265. package/dist/transactions/transaction.js.map +1 -0
  266. package/dist/types/aggregate-types.d.ts +73 -0
  267. package/dist/types/aggregate-types.d.ts.map +1 -0
  268. package/dist/types/aggregate-types.js +14 -0
  269. package/dist/types/aggregate-types.js.map +1 -0
  270. package/dist/types/computed-types.d.ts +71 -0
  271. package/dist/types/computed-types.d.ts.map +1 -0
  272. package/dist/types/computed-types.js +8 -0
  273. package/dist/types/computed-types.js.map +1 -0
  274. package/dist/types/crud-relationship-types.d.ts +180 -0
  275. package/dist/types/crud-relationship-types.d.ts.map +1 -0
  276. package/dist/types/crud-relationship-types.js +17 -0
  277. package/dist/types/crud-relationship-types.js.map +1 -0
  278. package/dist/types/crud-types.d.ts +343 -0
  279. package/dist/types/crud-types.d.ts.map +1 -0
  280. package/dist/types/crud-types.js +43 -0
  281. package/dist/types/crud-types.js.map +1 -0
  282. package/dist/types/cursor-types.d.ts +52 -0
  283. package/dist/types/cursor-types.d.ts.map +1 -0
  284. package/dist/types/cursor-types.js +2 -0
  285. package/dist/types/cursor-types.js.map +1 -0
  286. package/dist/types/database-config-types.d.ts +196 -0
  287. package/dist/types/database-config-types.d.ts.map +1 -0
  288. package/dist/types/database-config-types.js +11 -0
  289. package/dist/types/database-config-types.js.map +1 -0
  290. package/dist/types/hook-types.d.ts +158 -0
  291. package/dist/types/hook-types.d.ts.map +1 -0
  292. package/dist/types/hook-types.js +6 -0
  293. package/dist/types/hook-types.js.map +1 -0
  294. package/dist/types/index-types.d.ts +42 -0
  295. package/dist/types/index-types.d.ts.map +1 -0
  296. package/dist/types/index-types.js +8 -0
  297. package/dist/types/index-types.js.map +1 -0
  298. package/dist/types/operators.d.ts +5 -0
  299. package/dist/types/operators.d.ts.map +1 -0
  300. package/dist/types/operators.js +297 -0
  301. package/dist/types/operators.js.map +1 -0
  302. package/dist/types/query-overloads.d.ts +54 -0
  303. package/dist/types/query-overloads.d.ts.map +1 -0
  304. package/dist/types/query-overloads.js +3 -0
  305. package/dist/types/query-overloads.js.map +1 -0
  306. package/dist/types/reactive-types.d.ts +75 -0
  307. package/dist/types/reactive-types.d.ts.map +1 -0
  308. package/dist/types/reactive-types.js +7 -0
  309. package/dist/types/reactive-types.js.map +1 -0
  310. package/dist/types/schema-types.d.ts +56 -0
  311. package/dist/types/schema-types.d.ts.map +1 -0
  312. package/dist/types/schema-types.js +8 -0
  313. package/dist/types/schema-types.js.map +1 -0
  314. package/dist/types/search-types.d.ts +82 -0
  315. package/dist/types/search-types.d.ts.map +1 -0
  316. package/dist/types/search-types.js +110 -0
  317. package/dist/types/search-types.js.map +1 -0
  318. package/dist/types/types.d.ts +286 -0
  319. package/dist/types/types.d.ts.map +1 -0
  320. package/dist/types/types.js +2 -0
  321. package/dist/types/types.js.map +1 -0
  322. package/dist/utils/id-generator.d.ts +97 -0
  323. package/dist/utils/id-generator.d.ts.map +1 -0
  324. package/dist/utils/id-generator.js +247 -0
  325. package/dist/utils/id-generator.js.map +1 -0
  326. package/dist/utils/nested-path.d.ts +56 -0
  327. package/dist/utils/nested-path.d.ts.map +1 -0
  328. package/dist/utils/nested-path.js +119 -0
  329. package/dist/utils/nested-path.js.map +1 -0
  330. package/dist/utils/path.d.ts +16 -0
  331. package/dist/utils/path.d.ts.map +1 -0
  332. package/dist/utils/path.js +24 -0
  333. package/dist/utils/path.js.map +1 -0
  334. package/dist/validators/foreign-key.d.ts +49 -0
  335. package/dist/validators/foreign-key.d.ts.map +1 -0
  336. package/dist/validators/foreign-key.js +153 -0
  337. package/dist/validators/foreign-key.js.map +1 -0
  338. package/dist/validators/schema-validator.d.ts +19 -0
  339. package/dist/validators/schema-validator.d.ts.map +1 -0
  340. package/dist/validators/schema-validator.js +34 -0
  341. package/dist/validators/schema-validator.js.map +1 -0
  342. package/package.json +57 -0
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Factory functions for creating ChangeEvent objects.
3
+ *
4
+ * These functions provide a convenient and type-safe way to create change events
5
+ * that are published by CRUD operations and file watchers to notify reactive subscriptions.
6
+ */
7
+ import type { ChangeEvent } from "../types/reactive-types.js";
8
+ /**
9
+ * Creates a ChangeEvent for a collection mutation.
10
+ *
11
+ * @param collection - The name of the collection that was modified
12
+ * @param operation - The type of mutation: "create", "update", "delete", or "reload"
13
+ * @returns A ChangeEvent object
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * // After creating an entity
18
+ * const event = createChangeEvent("books", "create")
19
+ * yield* PubSub.publish(pubsub, event)
20
+ *
21
+ * // After updating an entity
22
+ * const event = createChangeEvent("books", "update")
23
+ * yield* PubSub.publish(pubsub, event)
24
+ * ```
25
+ */
26
+ export declare const createChangeEvent: (collection: string, operation: ChangeEvent["operation"]) => ChangeEvent;
27
+ /**
28
+ * Creates a ChangeEvent for a file watcher reload.
29
+ *
30
+ * This is a convenience function for the common case of creating
31
+ * a reload event after data is reloaded from disk.
32
+ *
33
+ * @param collection - The name of the collection that was reloaded
34
+ * @returns A ChangeEvent with operation: "reload"
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * // After reloading data from disk
39
+ * const event = reloadEvent("books")
40
+ * yield* PubSub.publish(pubsub, event)
41
+ * ```
42
+ */
43
+ export declare const reloadEvent: (collection: string) => ChangeEvent;
44
+ //# sourceMappingURL=change-event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-event.d.ts","sourceRoot":"","sources":["../../src/reactive/change-event.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,iBAAiB,GAC7B,YAAY,MAAM,EAClB,WAAW,WAAW,CAAC,WAAW,CAAC,KACjC,WAGD,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,WAAW,GAAI,YAAY,MAAM,KAAG,WAG/C,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Factory functions for creating ChangeEvent objects.
3
+ *
4
+ * These functions provide a convenient and type-safe way to create change events
5
+ * that are published by CRUD operations and file watchers to notify reactive subscriptions.
6
+ */
7
+ /**
8
+ * Creates a ChangeEvent for a collection mutation.
9
+ *
10
+ * @param collection - The name of the collection that was modified
11
+ * @param operation - The type of mutation: "create", "update", "delete", or "reload"
12
+ * @returns A ChangeEvent object
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * // After creating an entity
17
+ * const event = createChangeEvent("books", "create")
18
+ * yield* PubSub.publish(pubsub, event)
19
+ *
20
+ * // After updating an entity
21
+ * const event = createChangeEvent("books", "update")
22
+ * yield* PubSub.publish(pubsub, event)
23
+ * ```
24
+ */
25
+ export const createChangeEvent = (collection, operation) => ({
26
+ collection,
27
+ operation,
28
+ });
29
+ /**
30
+ * Creates a ChangeEvent for a file watcher reload.
31
+ *
32
+ * This is a convenience function for the common case of creating
33
+ * a reload event after data is reloaded from disk.
34
+ *
35
+ * @param collection - The name of the collection that was reloaded
36
+ * @returns A ChangeEvent with operation: "reload"
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * // After reloading data from disk
41
+ * const event = reloadEvent("books")
42
+ * yield* PubSub.publish(pubsub, event)
43
+ * ```
44
+ */
45
+ export const reloadEvent = (collection) => ({
46
+ collection,
47
+ operation: "reload",
48
+ });
49
+ //# sourceMappingURL=change-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-event.js","sourceRoot":"","sources":["../../src/reactive/change-event.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAChC,UAAkB,EAClB,SAAmC,EACrB,EAAE,CAAC,CAAC;IAClB,UAAU;IACV,SAAS;CACT,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,UAAkB,EAAe,EAAE,CAAC,CAAC;IAChE,UAAU;IACV,SAAS,EAAE,QAAQ;CACnB,CAAC,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * PubSub for broadcasting change events to reactive query subscribers.
3
+ *
4
+ * Uses Effect's unbounded PubSub to ensure all change events are delivered
5
+ * to subscribers - dropping events would break subscription correctness.
6
+ */
7
+ import { type Effect, PubSub } from "effect";
8
+ import type { ChangeEvent } from "../types/reactive-types.js";
9
+ /**
10
+ * Creates an unbounded PubSub for broadcasting ChangeEvents.
11
+ *
12
+ * The PubSub is unbounded because:
13
+ * - Dropping change events would cause subscriptions to miss mutations
14
+ * - This could lead to stale result sets being displayed
15
+ * - Back-pressure is handled by debouncing at the subscription level
16
+ *
17
+ * @returns Effect that produces a PubSub for ChangeEvents
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const program = Effect.gen(function* () {
22
+ * const pubsub = yield* createChangePubSub()
23
+ * // Publishers can publish events
24
+ * yield* pubsub.publish({ collection: "books", operation: "create" })
25
+ * // Subscribers receive events via subscription queues
26
+ * const subscription = yield* pubsub.subscribe
27
+ * const event = yield* Queue.take(subscription)
28
+ * })
29
+ * ```
30
+ */
31
+ export declare const createChangePubSub: () => Effect.Effect<PubSub.PubSub<ChangeEvent>>;
32
+ //# sourceMappingURL=change-pubsub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-pubsub.d.ts","sourceRoot":"","sources":["../../src/reactive/change-pubsub.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,kBAAkB,QAAO,MAAM,CAAC,MAAM,CAClD,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CACS,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * PubSub for broadcasting change events to reactive query subscribers.
3
+ *
4
+ * Uses Effect's unbounded PubSub to ensure all change events are delivered
5
+ * to subscribers - dropping events would break subscription correctness.
6
+ */
7
+ import { PubSub } from "effect";
8
+ /**
9
+ * Creates an unbounded PubSub for broadcasting ChangeEvents.
10
+ *
11
+ * The PubSub is unbounded because:
12
+ * - Dropping change events would cause subscriptions to miss mutations
13
+ * - This could lead to stale result sets being displayed
14
+ * - Back-pressure is handled by debouncing at the subscription level
15
+ *
16
+ * @returns Effect that produces a PubSub for ChangeEvents
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const program = Effect.gen(function* () {
21
+ * const pubsub = yield* createChangePubSub()
22
+ * // Publishers can publish events
23
+ * yield* pubsub.publish({ collection: "books", operation: "create" })
24
+ * // Subscribers receive events via subscription queues
25
+ * const subscription = yield* pubsub.subscribe
26
+ * const event = yield* Queue.take(subscription)
27
+ * })
28
+ * ```
29
+ */
30
+ export const createChangePubSub = () => PubSub.unbounded();
31
+ //# sourceMappingURL=change-pubsub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-pubsub.js","sourceRoot":"","sources":["../../src/reactive/change-pubsub.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAe,MAAM,EAAE,MAAM,QAAQ,CAAC;AAG7C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAEhC,EAAE,CAAC,MAAM,CAAC,SAAS,EAAe,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Reusable query evaluation function for reactive queries.
3
+ *
4
+ * Reads the current state from a Ref and applies the query pipeline
5
+ * (filter, sort, select, paginate) to produce a result array.
6
+ *
7
+ * Used by watch() for initial emission and re-evaluation on change events.
8
+ */
9
+ import { Effect, Ref } from "effect";
10
+ /**
11
+ * Configuration for query evaluation.
12
+ * Mirrors the subset of QueryConfig that applies to reactive queries.
13
+ */
14
+ export interface EvaluateQueryConfig {
15
+ readonly where?: Record<string, unknown>;
16
+ readonly sort?: Record<string, "asc" | "desc">;
17
+ readonly select?: Record<string, unknown> | ReadonlyArray<string>;
18
+ readonly limit?: number;
19
+ readonly offset?: number;
20
+ }
21
+ /**
22
+ * Entity constraint: must have a readonly string `id` field.
23
+ */
24
+ type HasId = {
25
+ readonly id: string;
26
+ };
27
+ /**
28
+ * Evaluates a query against the current state in the Ref.
29
+ *
30
+ * Reads all entities from the Ref, applies the query pipeline (filter, sort,
31
+ * select, paginate), and returns the result as a ReadonlyArray.
32
+ *
33
+ * This is a pure function that:
34
+ * - Does NOT emit multiple values over time (unlike a Stream)
35
+ * - Does NOT provide cursor-based pagination (returns complete result snapshot)
36
+ * - Returns the entire result set as a single ReadonlyArray
37
+ *
38
+ * @param ref - The collection Ref containing entities keyed by ID
39
+ * @param config - Query configuration (where, sort, select, limit, offset)
40
+ * @returns Effect producing the query result as a ReadonlyArray
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const program = Effect.gen(function* () {
45
+ * const ref = yield* createCollectionState<Book>([
46
+ * { id: "1", title: "Dune", year: 1965, genre: "sci-fi" },
47
+ * { id: "2", title: "Neuromancer", year: 1984, genre: "sci-fi" },
48
+ * { id: "3", title: "The Hobbit", year: 1937, genre: "fantasy" },
49
+ * ])
50
+ *
51
+ * const results = yield* evaluateQuery(ref, {
52
+ * where: { genre: "sci-fi" },
53
+ * sort: { year: "desc" },
54
+ * limit: 1,
55
+ * })
56
+ * // results: [{ id: "2", title: "Neuromancer", year: 1984, genre: "sci-fi" }]
57
+ * })
58
+ * ```
59
+ */
60
+ export declare const evaluateQuery: <T extends HasId>(ref: Ref.Ref<ReadonlyMap<string, T>>, config?: EvaluateQueryConfig) => Effect.Effect<ReadonlyArray<T>>;
61
+ export {};
62
+ //# sourceMappingURL=evaluate-query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate-query.d.ts","sourceRoot":"","sources":["../../src/reactive/evaluate-query.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,GAAG,EAAU,MAAM,QAAQ,CAAC;AAM7C;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC,CAAC;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAClE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,KAAK,KAAK,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,KAAK,EAC5C,KAAK,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EACpC,SAAQ,mBAAwB,KAC9B,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAiB9B,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Reusable query evaluation function for reactive queries.
3
+ *
4
+ * Reads the current state from a Ref and applies the query pipeline
5
+ * (filter, sort, select, paginate) to produce a result array.
6
+ *
7
+ * Used by watch() for initial emission and re-evaluation on change events.
8
+ */
9
+ import { Effect, Ref, Stream } from "effect";
10
+ import { applyFilter } from "../operations/query/filter-stream.js";
11
+ import { applyPagination } from "../operations/query/paginate-stream.js";
12
+ import { applySelect } from "../operations/query/select-stream.js";
13
+ import { applySort } from "../operations/query/sort-stream.js";
14
+ /**
15
+ * Evaluates a query against the current state in the Ref.
16
+ *
17
+ * Reads all entities from the Ref, applies the query pipeline (filter, sort,
18
+ * select, paginate), and returns the result as a ReadonlyArray.
19
+ *
20
+ * This is a pure function that:
21
+ * - Does NOT emit multiple values over time (unlike a Stream)
22
+ * - Does NOT provide cursor-based pagination (returns complete result snapshot)
23
+ * - Returns the entire result set as a single ReadonlyArray
24
+ *
25
+ * @param ref - The collection Ref containing entities keyed by ID
26
+ * @param config - Query configuration (where, sort, select, limit, offset)
27
+ * @returns Effect producing the query result as a ReadonlyArray
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const program = Effect.gen(function* () {
32
+ * const ref = yield* createCollectionState<Book>([
33
+ * { id: "1", title: "Dune", year: 1965, genre: "sci-fi" },
34
+ * { id: "2", title: "Neuromancer", year: 1984, genre: "sci-fi" },
35
+ * { id: "3", title: "The Hobbit", year: 1937, genre: "fantasy" },
36
+ * ])
37
+ *
38
+ * const results = yield* evaluateQuery(ref, {
39
+ * where: { genre: "sci-fi" },
40
+ * sort: { year: "desc" },
41
+ * limit: 1,
42
+ * })
43
+ * // results: [{ id: "2", title: "Neuromancer", year: 1984, genre: "sci-fi" }]
44
+ * })
45
+ * ```
46
+ */
47
+ export const evaluateQuery = (ref, config = {}) => Effect.gen(function* () {
48
+ // Read current state from Ref
49
+ const map = yield* Ref.get(ref);
50
+ const entities = Array.from(map.values());
51
+ // Build and execute the query pipeline
52
+ const stream = Stream.fromIterable(entities).pipe(applyFilter(config.where), applySort(config.sort), applyPagination(config.offset, config.limit), applySelect(config.select));
53
+ // Collect results into an array
54
+ const chunk = yield* Stream.runCollect(stream);
55
+ return Array.from(chunk);
56
+ });
57
+ //# sourceMappingURL=evaluate-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate-query.js","sourceRoot":"","sources":["../../src/reactive/evaluate-query.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAmB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC5B,GAAoC,EACpC,SAA8B,EAAE,EACE,EAAE,CACpC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACnB,8BAA8B;IAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAE1C,uCAAuC;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,IAAI,CAChD,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EACzB,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EACtB,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,EAC5C,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAC1B,CAAC;IAEF,gCAAgC;IAChC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAqB,CAAC;AAC9C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * watchById() implementation for reactive single-entity queries.
3
+ *
4
+ * Thin wrapper over watch() that filters by ID and maps results to T | null.
5
+ * Emits the entity when it exists, or null when it's deleted or doesn't exist.
6
+ */
7
+ import { Effect, type PubSub, type Ref, Stream } from "effect";
8
+ import type { ChangeEvent } from "../types/reactive-types.js";
9
+ import { type WatchQueryConfig } from "./watch.js";
10
+ /**
11
+ * Entity constraint: must have a readonly string `id` field.
12
+ */
13
+ type HasId = {
14
+ readonly id: string;
15
+ };
16
+ /**
17
+ * Creates a reactive watch stream for a single entity by ID.
18
+ *
19
+ * This is a thin wrapper over watch() that:
20
+ * 1. Filters by `where: { id }` to only match the specific entity
21
+ * 2. Maps the result array to `T | null` (first element or null if empty)
22
+ *
23
+ * The stream:
24
+ * - Emits the entity immediately if it exists, or null if not
25
+ * - Re-emits when the entity is created, updated, or deleted
26
+ * - Emits null when the entity is deleted (result array becomes empty)
27
+ * - Is scoped: auto-cleanup when scope closes or stream is interrupted
28
+ *
29
+ * @param pubsub - The PubSub broadcasting ChangeEvents from mutations
30
+ * @param ref - The collection Ref containing entities keyed by ID
31
+ * @param collectionName - Name of the collection to watch (for filtering events)
32
+ * @param id - The entity ID to watch
33
+ * @param config - Optional additional watch configuration (debounceMs)
34
+ * @returns Scoped Effect producing a Stream of T | null
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * const program = Effect.gen(function* () {
39
+ * const pubsub = yield* createChangePubSub()
40
+ * const ref = yield* createCollectionState<Book>([
41
+ * { id: "1", title: "Dune", author: "Frank Herbert" }
42
+ * ])
43
+ *
44
+ * const stream = yield* watchById(pubsub, ref, "books", "1")
45
+ *
46
+ * // Emits: { id: "1", title: "Dune", author: "Frank Herbert" }
47
+ * // After delete: emits null
48
+ * }).pipe(Effect.scoped)
49
+ * ```
50
+ */
51
+ export declare const watchById: <T extends HasId>(pubsub: PubSub.PubSub<ChangeEvent>, ref: Ref.Ref<ReadonlyMap<string, T>>, collectionName: string, id: string, config?: Pick<WatchQueryConfig, "debounceMs">) => Effect.Effect<Stream.Stream<T | null>, never, import("effect").Scope.Scope>;
52
+ export {};
53
+ //# sourceMappingURL=watch-by-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-by-id.d.ts","sourceRoot":"","sources":["../../src/reactive/watch-by-id.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,GAAG,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,KAAK,gBAAgB,EAAS,MAAM,YAAY,CAAC;AAE1D;;GAEG;AACH,KAAK,KAAK,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,KAAK,EACxC,QAAQ,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAClC,KAAK,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EACpC,gBAAgB,MAAM,EACtB,IAAI,MAAM,EACV,SAAQ,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAM,KAC/C,MAAM,CAAC,MAAM,CACf,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,EACvB,KAAK,EACL,OAAO,QAAQ,EAAE,KAAK,CAAC,KAAK,CAa1B,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * watchById() implementation for reactive single-entity queries.
3
+ *
4
+ * Thin wrapper over watch() that filters by ID and maps results to T | null.
5
+ * Emits the entity when it exists, or null when it's deleted or doesn't exist.
6
+ */
7
+ import { Effect, Stream } from "effect";
8
+ import { watch } from "./watch.js";
9
+ /**
10
+ * Creates a reactive watch stream for a single entity by ID.
11
+ *
12
+ * This is a thin wrapper over watch() that:
13
+ * 1. Filters by `where: { id }` to only match the specific entity
14
+ * 2. Maps the result array to `T | null` (first element or null if empty)
15
+ *
16
+ * The stream:
17
+ * - Emits the entity immediately if it exists, or null if not
18
+ * - Re-emits when the entity is created, updated, or deleted
19
+ * - Emits null when the entity is deleted (result array becomes empty)
20
+ * - Is scoped: auto-cleanup when scope closes or stream is interrupted
21
+ *
22
+ * @param pubsub - The PubSub broadcasting ChangeEvents from mutations
23
+ * @param ref - The collection Ref containing entities keyed by ID
24
+ * @param collectionName - Name of the collection to watch (for filtering events)
25
+ * @param id - The entity ID to watch
26
+ * @param config - Optional additional watch configuration (debounceMs)
27
+ * @returns Scoped Effect producing a Stream of T | null
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const program = Effect.gen(function* () {
32
+ * const pubsub = yield* createChangePubSub()
33
+ * const ref = yield* createCollectionState<Book>([
34
+ * { id: "1", title: "Dune", author: "Frank Herbert" }
35
+ * ])
36
+ *
37
+ * const stream = yield* watchById(pubsub, ref, "books", "1")
38
+ *
39
+ * // Emits: { id: "1", title: "Dune", author: "Frank Herbert" }
40
+ * // After delete: emits null
41
+ * }).pipe(Effect.scoped)
42
+ * ```
43
+ */
44
+ export const watchById = (pubsub, ref, collectionName, id, config = {}) => Effect.gen(function* () {
45
+ // Use watch() with a where clause filtering by ID
46
+ const watchStream = yield* watch(pubsub, ref, collectionName, {
47
+ ...config,
48
+ where: { id },
49
+ });
50
+ // Map the result array to T | null
51
+ // - results[0] when the entity exists
52
+ // - null when the entity is deleted or doesn't exist
53
+ return Stream.map(watchStream, (results) => results[0] ?? null);
54
+ });
55
+ //# sourceMappingURL=watch-by-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-by-id.js","sourceRoot":"","sources":["../../src/reactive/watch-by-id.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAyB,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE/D,OAAO,EAAyB,KAAK,EAAE,MAAM,YAAY,CAAC;AAO1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACxB,MAAkC,EAClC,GAAoC,EACpC,cAAsB,EACtB,EAAU,EACV,SAA+C,EAAE,EAKhD,EAAE,CACH,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACnB,kDAAkD;IAClD,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE;QAC7D,GAAG,MAAM;QACT,KAAK,EAAE,EAAE,EAAE,EAAE;KACb,CAAC,CAAC;IAEH,mCAAmC;IACnC,sCAAsC;IACtC,qDAAqD;IACrD,OAAO,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;AACjE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Core watch() implementation for reactive queries.
3
+ *
4
+ * Creates a Stream that emits result sets whenever the underlying collection data changes.
5
+ * Subscribes to the PubSub for change notifications, filters events by collection name,
6
+ * re-evaluates the query pipeline on each change, deduplicates identical consecutive results,
7
+ * and emits the new result set.
8
+ */
9
+ import { Effect, PubSub, type Ref, Scope, Stream } from "effect";
10
+ import type { ChangeEvent } from "../types/reactive-types.js";
11
+ import { type EvaluateQueryConfig } from "./evaluate-query.js";
12
+ /**
13
+ * Configuration for the watch query.
14
+ * Extends EvaluateQueryConfig with debounce options.
15
+ */
16
+ export interface WatchQueryConfig extends EvaluateQueryConfig {
17
+ /**
18
+ * Debounce interval in milliseconds for change event processing.
19
+ * When multiple mutations occur in rapid succession, they are coalesced
20
+ * into a single re-evaluation after the debounce interval settles.
21
+ * Default: 10ms (fast enough for interactive use, long enough to batch bursts).
22
+ */
23
+ readonly debounceMs?: number;
24
+ }
25
+ /**
26
+ * Entity constraint: must have a readonly string `id` field.
27
+ */
28
+ type HasId = {
29
+ readonly id: string;
30
+ };
31
+ /**
32
+ * Creates a reactive watch stream that emits query results whenever the collection changes.
33
+ *
34
+ * The stream:
35
+ * 1. Emits the current result set immediately upon subscription
36
+ * 2. Subscribes to the PubSub for change notifications (scoped - auto-cleanup)
37
+ * 3. Filters events to only those matching the specified collection
38
+ * 4. Debounces change events to coalesce rapid mutations into single re-evaluations
39
+ * 5. Re-evaluates the query pipeline on each relevant change
40
+ * 6. Deduplicates consecutive identical result sets to avoid spurious emissions
41
+ * 7. Emits the new result set as a ReadonlyArray
42
+ *
43
+ * Resource management:
44
+ * - Uses Effect.acquireRelease to manage the PubSub subscription lifecycle
45
+ * - Subscription is acquired when the watch Effect runs and released when:
46
+ * - The enclosing Scope closes, OR
47
+ * - The stream is interrupted/completes (via Stream.ensuring)
48
+ * - This ensures no memory leaks from lingering subscriptions
49
+ *
50
+ * @param pubsub - The PubSub broadcasting ChangeEvents from mutations
51
+ * @param ref - The collection Ref containing entities keyed by ID
52
+ * @param collectionName - Name of the collection to watch (for filtering events)
53
+ * @param config - Optional query configuration (where, sort, select, limit, offset, debounceMs)
54
+ * @returns Scoped Effect producing a Stream of result arrays
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * const program = Effect.gen(function* () {
59
+ * const pubsub = yield* createChangePubSub()
60
+ * const ref = yield* createCollectionState<Book>([])
61
+ *
62
+ * const stream = yield* watch(pubsub, ref, "books", {
63
+ * where: { genre: "sci-fi" },
64
+ * sort: { year: "desc" },
65
+ * limit: 10,
66
+ * debounceMs: 50, // custom debounce interval
67
+ * })
68
+ *
69
+ * // Consume the stream
70
+ * yield* Stream.runForEach(stream, (results) =>
71
+ * Effect.log(`Got ${results.length} results`)
72
+ * )
73
+ * }).pipe(Effect.scoped)
74
+ * ```
75
+ */
76
+ export declare const watch: <T extends HasId>(pubsub: PubSub.PubSub<ChangeEvent>, ref: Ref.Ref<ReadonlyMap<string, T>>, collectionName: string, config?: WatchQueryConfig) => Effect.Effect<Stream.Stream<ReadonlyArray<T>>, never, Scope.Scope>;
77
+ export {};
78
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/reactive/watch.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEN,MAAM,EAGN,MAAM,EACN,KAAK,GAAG,EACR,KAAK,EACL,MAAM,EACN,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,KAAK,mBAAmB,EAAiB,MAAM,qBAAqB,CAAC;AAE9E;;;GAGG;AACH,MAAM,WAAW,gBAAiB,SAAQ,mBAAmB;IAC5D;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,KAAK,KAAK,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAgCrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,SAAS,KAAK,EACpC,QAAQ,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAClC,KAAK,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EACpC,gBAAgB,MAAM,EACtB,SAAQ,gBAAqB,KAC3B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAmFjE,CAAC"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Core watch() implementation for reactive queries.
3
+ *
4
+ * Creates a Stream that emits result sets whenever the underlying collection data changes.
5
+ * Subscribes to the PubSub for change notifications, filters events by collection name,
6
+ * re-evaluates the query pipeline on each change, deduplicates identical consecutive results,
7
+ * and emits the new result set.
8
+ */
9
+ import { Duration, Effect, ExecutionStrategy, Exit, PubSub, Scope, Stream, } from "effect";
10
+ import { evaluateQuery } from "./evaluate-query.js";
11
+ /**
12
+ * Compares two result arrays for structural equality.
13
+ *
14
+ * Uses JSON serialization for deep comparison. This is simple and correct for
15
+ * comparing arrays of plain objects (which is what query results are).
16
+ *
17
+ * @param a - First result array
18
+ * @param b - Second result array
19
+ * @returns true if the arrays are structurally equal
20
+ */
21
+ const resultsAreEqual = (a, b) => {
22
+ // Fast path: same reference
23
+ if (a === b)
24
+ return true;
25
+ // Fast path: different lengths
26
+ if (a.length !== b.length)
27
+ return false;
28
+ // Compare by serialization for deep structural equality
29
+ return JSON.stringify(a) === JSON.stringify(b);
30
+ };
31
+ /**
32
+ * Default debounce interval in milliseconds.
33
+ * Fast enough for interactive use, long enough to batch typical burst patterns.
34
+ */
35
+ const DEFAULT_DEBOUNCE_MS = 10;
36
+ /**
37
+ * Creates a reactive watch stream that emits query results whenever the collection changes.
38
+ *
39
+ * The stream:
40
+ * 1. Emits the current result set immediately upon subscription
41
+ * 2. Subscribes to the PubSub for change notifications (scoped - auto-cleanup)
42
+ * 3. Filters events to only those matching the specified collection
43
+ * 4. Debounces change events to coalesce rapid mutations into single re-evaluations
44
+ * 5. Re-evaluates the query pipeline on each relevant change
45
+ * 6. Deduplicates consecutive identical result sets to avoid spurious emissions
46
+ * 7. Emits the new result set as a ReadonlyArray
47
+ *
48
+ * Resource management:
49
+ * - Uses Effect.acquireRelease to manage the PubSub subscription lifecycle
50
+ * - Subscription is acquired when the watch Effect runs and released when:
51
+ * - The enclosing Scope closes, OR
52
+ * - The stream is interrupted/completes (via Stream.ensuring)
53
+ * - This ensures no memory leaks from lingering subscriptions
54
+ *
55
+ * @param pubsub - The PubSub broadcasting ChangeEvents from mutations
56
+ * @param ref - The collection Ref containing entities keyed by ID
57
+ * @param collectionName - Name of the collection to watch (for filtering events)
58
+ * @param config - Optional query configuration (where, sort, select, limit, offset, debounceMs)
59
+ * @returns Scoped Effect producing a Stream of result arrays
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * const program = Effect.gen(function* () {
64
+ * const pubsub = yield* createChangePubSub()
65
+ * const ref = yield* createCollectionState<Book>([])
66
+ *
67
+ * const stream = yield* watch(pubsub, ref, "books", {
68
+ * where: { genre: "sci-fi" },
69
+ * sort: { year: "desc" },
70
+ * limit: 10,
71
+ * debounceMs: 50, // custom debounce interval
72
+ * })
73
+ *
74
+ * // Consume the stream
75
+ * yield* Stream.runForEach(stream, (results) =>
76
+ * Effect.log(`Got ${results.length} results`)
77
+ * )
78
+ * }).pipe(Effect.scoped)
79
+ * ```
80
+ */
81
+ export const watch = (pubsub, ref, collectionName, config = {}) => Effect.gen(function* () {
82
+ // Get the current scope so we can fork a child scope for this subscription.
83
+ // The child scope allows us to clean up the subscription independently of
84
+ // the parent scope - either when the stream ends OR when the parent closes.
85
+ const parentScope = yield* Scope.Scope;
86
+ // Fork a child scope that will manage the subscription lifetime.
87
+ // When this child scope closes, the subscription will be cleaned up.
88
+ const subscriptionScope = yield* Scope.fork(parentScope, ExecutionStrategy.sequential);
89
+ // Use Effect.acquireRelease to manage the subscription:
90
+ // - Acquire: Subscribe to the PubSub (returns a Dequeue of ChangeEvents)
91
+ // - Release: Close the subscription scope (which triggers subscription cleanup)
92
+ //
93
+ // This explicit acquireRelease pattern makes the resource management visible
94
+ // and ensures proper cleanup when the stream is interrupted or completes.
95
+ const subscription = yield* Effect.acquireRelease(
96
+ // Acquire: Subscribe to the PubSub within the child scope
97
+ // PubSub.subscribe returns Effect<Dequeue, never, Scope.Scope>
98
+ // We provide the subscription scope so cleanup is tied to it
99
+ PubSub.subscribe(pubsub).pipe(Effect.provideService(Scope.Scope, subscriptionScope)),
100
+ // Release: Close the child scope to trigger subscription cleanup
101
+ // This runs when the enclosing scope closes
102
+ () => Scope.close(subscriptionScope, Exit.void));
103
+ // Create a stream from the subscription queue
104
+ const changeStream = Stream.fromQueue(subscription);
105
+ // Filter to only events for this collection
106
+ const filteredStream = Stream.filter(changeStream, (event) => event.collection === collectionName);
107
+ // Apply debouncing to coalesce rapid mutations into a single re-evaluation.
108
+ // This prevents re-evaluating the query on every single mutation when they
109
+ // arrive in bursts (e.g., createMany inserting 100 entities).
110
+ const debounceMs = config.debounceMs ?? DEFAULT_DEBOUNCE_MS;
111
+ const debouncedStream = Stream.debounce(filteredStream, Duration.millis(debounceMs));
112
+ // Map each (debounced) change event to a re-evaluation of the query.
113
+ // This transforms Stream<ChangeEvent> into Stream<ReadonlyArray<T>>
114
+ const changeResultStream = Stream.mapEffect(debouncedStream, () => evaluateQuery(ref, config));
115
+ // Create the initial emission stream: emit current result set immediately
116
+ const initialStream = Stream.fromEffect(evaluateQuery(ref, config));
117
+ // Concatenate initial emission with the change-driven stream
118
+ // This ensures subscribers receive the current state immediately,
119
+ // then receive updates as changes occur
120
+ const combinedStream = Stream.concat(initialStream, changeResultStream);
121
+ // Deduplicate consecutive identical result sets to avoid spurious emissions.
122
+ // This prevents re-emitting the same result set when a change event occurs
123
+ // but doesn't actually affect the query results (e.g., inserting an entity
124
+ // that doesn't match the where clause).
125
+ const deduplicatedStream = Stream.changesWith(combinedStream, resultsAreEqual);
126
+ // Ensure the subscription is cleaned up when the stream ends.
127
+ // This handles the case where the stream is interrupted or completed
128
+ // before the parent scope closes (e.g., Stream.take(n) stopping early).
129
+ // Closing the subscription scope triggers the acquireRelease cleanup.
130
+ const resultStream = Stream.ensuring(deduplicatedStream, Scope.close(subscriptionScope, Exit.void));
131
+ return resultStream;
132
+ });
133
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/reactive/watch.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACN,QAAQ,EACR,MAAM,EACN,iBAAiB,EACjB,IAAI,EACJ,MAAM,EAEN,KAAK,EACL,MAAM,GACN,MAAM,QAAQ,CAAC;AAEhB,OAAO,EAA4B,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAqB9E;;;;;;;;;GASG;AACH,MAAM,eAAe,GAAG,CACvB,CAAmB,EACnB,CAAmB,EACT,EAAE;IACZ,4BAA4B;IAC5B,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzB,+BAA+B;IAC/B,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAExC,wDAAwD;IACxD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CACpB,MAAkC,EAClC,GAAoC,EACpC,cAAsB,EACtB,SAA2B,EAAE,EACwC,EAAE,CACvE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACnB,4EAA4E;IAC5E,0EAA0E;IAC1E,4EAA4E;IAC5E,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IAEvC,iEAAiE;IACjE,qEAAqE;IACrE,MAAM,iBAAiB,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAC1C,WAAW,EACX,iBAAiB,CAAC,UAAU,CAC5B,CAAC;IAEF,wDAAwD;IACxD,yEAAyE;IACzE,gFAAgF;IAChF,EAAE;IACF,6EAA6E;IAC7E,0EAA0E;IAC1E,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc;IAChD,0DAA0D;IAC1D,+DAA+D;IAC/D,6DAA6D;IAC7D,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAC5B,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,EAAE,iBAAiB,CAAC,CACrD;IACD,iEAAiE;IACjE,4CAA4C;IAC5C,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,CAC/C,CAAC;IAEF,8CAA8C;IAC9C,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAEpD,4CAA4C;IAC5C,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CACnC,YAAY,EACZ,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,cAAc,CAC9C,CAAC;IAEF,4EAA4E;IAC5E,2EAA2E;IAC3E,8DAA8D;IAC9D,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,mBAAmB,CAAC;IAC5D,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,CACtC,cAAc,EACd,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAC3B,CAAC;IAEF,qEAAqE;IACrE,oEAAoE;IACpE,MAAM,kBAAkB,GAAG,MAAM,CAAC,SAAS,CAAC,eAAe,EAAE,GAAG,EAAE,CACjE,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAC1B,CAAC;IAEF,0EAA0E;IAC1E,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAEpE,6DAA6D;IAC7D,kEAAkE;IAClE,wCAAwC;IACxC,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;IAExE,6EAA6E;IAC7E,2EAA2E;IAC3E,2EAA2E;IAC3E,wCAAwC;IACxC,MAAM,kBAAkB,GAAG,MAAM,CAAC,WAAW,CAC5C,cAAc,EACd,eAAe,CACf,CAAC;IAEF,8DAA8D;IAC9D,qEAAqE;IACrE,wEAAwE;IACxE,sEAAsE;IACtE,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CACnC,kBAAkB,EAClB,KAAK,CAAC,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,CACzC,CAAC;IAEF,OAAO,YAAY,CAAC;AACrB,CAAC,CAAC,CAAC"}