@typed/fx 2.0.0-beta.0 → 2.0.0-beta.10

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 (640) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -21
  3. package/dist/Fx/Fx.d.ts +371 -19
  4. package/dist/Fx/Fx.d.ts.map +1 -1
  5. package/dist/Fx/Fx.js +37 -6
  6. package/dist/Fx/TypeId.d.ts +52 -6
  7. package/dist/Fx/TypeId.d.ts.map +1 -1
  8. package/dist/Fx/TypeId.js +41 -4
  9. package/dist/Fx/combinators/additive.d.ts +245 -0
  10. package/dist/Fx/combinators/additive.d.ts.map +1 -0
  11. package/dist/Fx/combinators/additive.js +243 -0
  12. package/dist/Fx/combinators/catch.d.ts +246 -12
  13. package/dist/Fx/combinators/catch.d.ts.map +1 -1
  14. package/dist/Fx/combinators/catch.js +236 -12
  15. package/dist/Fx/combinators/causes.d.ts +25 -2
  16. package/dist/Fx/combinators/causes.d.ts.map +1 -1
  17. package/dist/Fx/combinators/causes.js +25 -2
  18. package/dist/Fx/combinators/changesWithEffect.d.ts +40 -0
  19. package/dist/Fx/combinators/changesWithEffect.d.ts.map +1 -0
  20. package/dist/Fx/combinators/changesWithEffect.js +48 -0
  21. package/dist/Fx/combinators/compact.d.ts +18 -1
  22. package/dist/Fx/combinators/compact.d.ts.map +1 -1
  23. package/dist/Fx/combinators/compact.js +18 -1
  24. package/dist/Fx/combinators/concatMap.d.ts +86 -0
  25. package/dist/Fx/combinators/concatMap.d.ts.map +1 -0
  26. package/dist/Fx/combinators/concatMap.js +86 -0
  27. package/dist/Fx/combinators/continueWith.d.ts +113 -5
  28. package/dist/Fx/combinators/continueWith.d.ts.map +1 -1
  29. package/dist/Fx/combinators/continueWith.js +113 -5
  30. package/dist/Fx/combinators/debounce.d.ts +34 -0
  31. package/dist/Fx/combinators/debounce.d.ts.map +1 -0
  32. package/dist/Fx/combinators/debounce.js +35 -0
  33. package/dist/Fx/combinators/delay.d.ts +36 -0
  34. package/dist/Fx/combinators/delay.d.ts.map +1 -0
  35. package/dist/Fx/combinators/delay.js +33 -0
  36. package/dist/Fx/combinators/dropUntil.d.ts +71 -0
  37. package/dist/Fx/combinators/dropUntil.d.ts.map +1 -0
  38. package/dist/Fx/combinators/dropUntil.js +65 -0
  39. package/dist/Fx/combinators/during.d.ts +38 -0
  40. package/dist/Fx/combinators/during.d.ts.map +1 -0
  41. package/dist/Fx/combinators/during.js +85 -0
  42. package/dist/Fx/combinators/ensuring.d.ts +34 -4
  43. package/dist/Fx/combinators/ensuring.d.ts.map +1 -1
  44. package/dist/Fx/combinators/ensuring.js +34 -4
  45. package/dist/Fx/combinators/exhaustLatestMap.d.ts +41 -5
  46. package/dist/Fx/combinators/exhaustLatestMap.d.ts.map +1 -1
  47. package/dist/Fx/combinators/exhaustLatestMap.js +41 -5
  48. package/dist/Fx/combinators/exhaustLatestMapEffect.d.ts +40 -4
  49. package/dist/Fx/combinators/exhaustLatestMapEffect.d.ts.map +1 -1
  50. package/dist/Fx/combinators/exhaustLatestMapEffect.js +40 -4
  51. package/dist/Fx/combinators/exhaustMap.d.ts +38 -1
  52. package/dist/Fx/combinators/exhaustMap.d.ts.map +1 -1
  53. package/dist/Fx/combinators/exhaustMap.js +38 -1
  54. package/dist/Fx/combinators/exhaustMapEffect.d.ts +33 -1
  55. package/dist/Fx/combinators/exhaustMapEffect.d.ts.map +1 -1
  56. package/dist/Fx/combinators/exhaustMapEffect.js +33 -1
  57. package/dist/Fx/combinators/exit.d.ts +23 -2
  58. package/dist/Fx/combinators/exit.d.ts.map +1 -1
  59. package/dist/Fx/combinators/exit.js +23 -2
  60. package/dist/Fx/combinators/filter.d.ts +17 -1
  61. package/dist/Fx/combinators/filter.d.ts.map +1 -1
  62. package/dist/Fx/combinators/filter.js +17 -1
  63. package/dist/Fx/combinators/filterEffect.d.ts +22 -1
  64. package/dist/Fx/combinators/filterEffect.d.ts.map +1 -1
  65. package/dist/Fx/combinators/filterEffect.js +22 -1
  66. package/dist/Fx/combinators/filterMap.d.ts +20 -1
  67. package/dist/Fx/combinators/filterMap.d.ts.map +1 -1
  68. package/dist/Fx/combinators/filterMap.js +20 -1
  69. package/dist/Fx/combinators/filterMapEffect.d.ts +21 -1
  70. package/dist/Fx/combinators/filterMapEffect.d.ts.map +1 -1
  71. package/dist/Fx/combinators/filterMapEffect.js +21 -1
  72. package/dist/Fx/combinators/filterMapLoop.d.ts +20 -1
  73. package/dist/Fx/combinators/filterMapLoop.d.ts.map +1 -1
  74. package/dist/Fx/combinators/filterMapLoop.js +20 -1
  75. package/dist/Fx/combinators/filterMapLoopCause.d.ts +21 -1
  76. package/dist/Fx/combinators/filterMapLoopCause.d.ts.map +1 -1
  77. package/dist/Fx/combinators/filterMapLoopCause.js +21 -1
  78. package/dist/Fx/combinators/filterMapLoopCauseEffect.d.ts +21 -1
  79. package/dist/Fx/combinators/filterMapLoopCauseEffect.d.ts.map +1 -1
  80. package/dist/Fx/combinators/filterMapLoopCauseEffect.js +21 -1
  81. package/dist/Fx/combinators/filterMapLoopEffect.d.ts +21 -1
  82. package/dist/Fx/combinators/filterMapLoopEffect.d.ts.map +1 -1
  83. package/dist/Fx/combinators/filterMapLoopEffect.js +21 -1
  84. package/dist/Fx/combinators/flatMap.d.ts +50 -5
  85. package/dist/Fx/combinators/flatMap.d.ts.map +1 -1
  86. package/dist/Fx/combinators/flatMap.js +36 -3
  87. package/dist/Fx/combinators/flatMapConcurrently.d.ts +51 -4
  88. package/dist/Fx/combinators/flatMapConcurrently.d.ts.map +1 -1
  89. package/dist/Fx/combinators/flatMapConcurrently.js +51 -4
  90. package/dist/Fx/combinators/flatMapConcurrentlyEffect.d.ts +48 -4
  91. package/dist/Fx/combinators/flatMapConcurrentlyEffect.d.ts.map +1 -1
  92. package/dist/Fx/combinators/flatMapConcurrentlyEffect.js +40 -2
  93. package/dist/Fx/combinators/flatMapEffect.d.ts +46 -4
  94. package/dist/Fx/combinators/flatMapEffect.d.ts.map +1 -1
  95. package/dist/Fx/combinators/flatMapEffect.js +32 -2
  96. package/dist/Fx/combinators/flip.d.ts +34 -2
  97. package/dist/Fx/combinators/flip.d.ts.map +1 -1
  98. package/dist/Fx/combinators/flip.js +34 -2
  99. package/dist/Fx/combinators/gen.d.ts +29 -10
  100. package/dist/Fx/combinators/gen.d.ts.map +1 -1
  101. package/dist/Fx/combinators/gen.js +28 -4
  102. package/dist/Fx/combinators/genScoped.d.ts +33 -10
  103. package/dist/Fx/combinators/genScoped.d.ts.map +1 -1
  104. package/dist/Fx/combinators/genScoped.js +31 -3
  105. package/dist/Fx/combinators/grouped.d.ts +89 -0
  106. package/dist/Fx/combinators/grouped.d.ts.map +1 -0
  107. package/dist/Fx/combinators/grouped.js +146 -0
  108. package/dist/Fx/combinators/index.d.ts +45 -0
  109. package/dist/Fx/combinators/index.d.ts.map +1 -1
  110. package/dist/Fx/combinators/index.js +45 -0
  111. package/dist/Fx/combinators/keyed.d.ts +124 -10
  112. package/dist/Fx/combinators/keyed.d.ts.map +1 -1
  113. package/dist/Fx/combinators/keyed.js +69 -11
  114. package/dist/Fx/combinators/loop.d.ts +17 -1
  115. package/dist/Fx/combinators/loop.d.ts.map +1 -1
  116. package/dist/Fx/combinators/loop.js +17 -1
  117. package/dist/Fx/combinators/loopCause.d.ts +18 -1
  118. package/dist/Fx/combinators/loopCause.d.ts.map +1 -1
  119. package/dist/Fx/combinators/loopCause.js +18 -1
  120. package/dist/Fx/combinators/loopCauseEffect.d.ts +19 -1
  121. package/dist/Fx/combinators/loopCauseEffect.d.ts.map +1 -1
  122. package/dist/Fx/combinators/loopCauseEffect.js +19 -1
  123. package/dist/Fx/combinators/loopEffect.d.ts +24 -1
  124. package/dist/Fx/combinators/loopEffect.d.ts.map +1 -1
  125. package/dist/Fx/combinators/loopEffect.js +24 -1
  126. package/dist/Fx/combinators/map.d.ts +46 -1
  127. package/dist/Fx/combinators/map.d.ts.map +1 -1
  128. package/dist/Fx/combinators/map.js +43 -1
  129. package/dist/Fx/combinators/mapBoth.d.ts +40 -0
  130. package/dist/Fx/combinators/mapBoth.d.ts.map +1 -0
  131. package/dist/Fx/combinators/mapBoth.js +33 -0
  132. package/dist/Fx/combinators/mapEffect.d.ts +25 -1
  133. package/dist/Fx/combinators/mapEffect.d.ts.map +1 -1
  134. package/dist/Fx/combinators/mapEffect.js +25 -1
  135. package/dist/Fx/combinators/mapError.d.ts +33 -0
  136. package/dist/Fx/combinators/mapError.d.ts.map +1 -0
  137. package/dist/Fx/combinators/mapError.js +32 -0
  138. package/dist/Fx/combinators/mergeAll.d.ts +35 -1
  139. package/dist/Fx/combinators/mergeAll.d.ts.map +1 -1
  140. package/dist/Fx/combinators/mergeAll.js +35 -1
  141. package/dist/Fx/combinators/mergeOrdered.d.ts +36 -4
  142. package/dist/Fx/combinators/mergeOrdered.d.ts.map +1 -1
  143. package/dist/Fx/combinators/mergeOrdered.js +68 -14
  144. package/dist/Fx/combinators/onError.d.ts +34 -4
  145. package/dist/Fx/combinators/onError.d.ts.map +1 -1
  146. package/dist/Fx/combinators/onError.js +34 -4
  147. package/dist/Fx/combinators/onExit.d.ts +29 -3
  148. package/dist/Fx/combinators/onExit.d.ts.map +1 -1
  149. package/dist/Fx/combinators/onExit.js +29 -3
  150. package/dist/Fx/combinators/onInterrupt.d.ts +49 -4
  151. package/dist/Fx/combinators/onInterrupt.d.ts.map +1 -1
  152. package/dist/Fx/combinators/onInterrupt.js +49 -4
  153. package/dist/Fx/combinators/pairwise.d.ts +28 -0
  154. package/dist/Fx/combinators/pairwise.d.ts.map +1 -0
  155. package/dist/Fx/combinators/pairwise.js +31 -0
  156. package/dist/Fx/combinators/provide.d.ts +162 -8
  157. package/dist/Fx/combinators/provide.d.ts.map +1 -1
  158. package/dist/Fx/combinators/provide.js +154 -6
  159. package/dist/Fx/combinators/race.d.ts +92 -0
  160. package/dist/Fx/combinators/race.d.ts.map +1 -0
  161. package/dist/Fx/combinators/race.js +149 -0
  162. package/dist/Fx/combinators/repeat.d.ts +41 -0
  163. package/dist/Fx/combinators/repeat.d.ts.map +1 -0
  164. package/dist/Fx/combinators/repeat.js +57 -0
  165. package/dist/Fx/combinators/result.d.ts +45 -0
  166. package/dist/Fx/combinators/result.d.ts.map +1 -0
  167. package/dist/Fx/combinators/result.js +46 -0
  168. package/dist/Fx/combinators/retry.d.ts +53 -0
  169. package/dist/Fx/combinators/retry.d.ts.map +1 -0
  170. package/dist/Fx/combinators/retry.js +71 -0
  171. package/dist/Fx/combinators/sample.d.ts +31 -0
  172. package/dist/Fx/combinators/sample.d.ts.map +1 -0
  173. package/dist/Fx/combinators/sample.js +42 -0
  174. package/dist/Fx/combinators/scan.d.ts +72 -0
  175. package/dist/Fx/combinators/scan.d.ts.map +1 -0
  176. package/dist/Fx/combinators/scan.js +77 -0
  177. package/dist/Fx/combinators/since.d.ts +30 -0
  178. package/dist/Fx/combinators/since.d.ts.map +1 -0
  179. package/dist/Fx/combinators/since.js +39 -0
  180. package/dist/Fx/combinators/skip.d.ts +45 -1
  181. package/dist/Fx/combinators/skip.d.ts.map +1 -1
  182. package/dist/Fx/combinators/skip.js +43 -1
  183. package/dist/Fx/combinators/skipRepeats.d.ts +17 -1
  184. package/dist/Fx/combinators/skipRepeats.d.ts.map +1 -1
  185. package/dist/Fx/combinators/skipRepeats.js +17 -1
  186. package/dist/Fx/combinators/skipRepeatsWith.d.ts +18 -1
  187. package/dist/Fx/combinators/skipRepeatsWith.d.ts.map +1 -1
  188. package/dist/Fx/combinators/skipRepeatsWith.js +18 -1
  189. package/dist/Fx/combinators/skipWhile.d.ts +117 -0
  190. package/dist/Fx/combinators/skipWhile.d.ts.map +1 -0
  191. package/dist/Fx/combinators/skipWhile.js +134 -0
  192. package/dist/Fx/combinators/slice.d.ts +97 -2
  193. package/dist/Fx/combinators/slice.d.ts.map +1 -1
  194. package/dist/Fx/combinators/slice.js +45 -1
  195. package/dist/Fx/combinators/switchMap.d.ts +39 -1
  196. package/dist/Fx/combinators/switchMap.d.ts.map +1 -1
  197. package/dist/Fx/combinators/switchMap.js +43 -5
  198. package/dist/Fx/combinators/switchMapEffect.d.ts +38 -1
  199. package/dist/Fx/combinators/switchMapEffect.d.ts.map +1 -1
  200. package/dist/Fx/combinators/switchMapEffect.js +38 -1
  201. package/dist/Fx/combinators/take.d.ts +46 -1
  202. package/dist/Fx/combinators/take.d.ts.map +1 -1
  203. package/dist/Fx/combinators/take.js +44 -1
  204. package/dist/Fx/combinators/takeUntil.d.ts +62 -2
  205. package/dist/Fx/combinators/takeUntil.d.ts.map +1 -1
  206. package/dist/Fx/combinators/takeUntil.js +62 -2
  207. package/dist/Fx/combinators/takeWhile.d.ts +60 -0
  208. package/dist/Fx/combinators/takeWhile.d.ts.map +1 -0
  209. package/dist/Fx/combinators/takeWhile.js +54 -0
  210. package/dist/Fx/combinators/tapEffect.d.ts +17 -1
  211. package/dist/Fx/combinators/tapEffect.d.ts.map +1 -1
  212. package/dist/Fx/combinators/tapEffect.js +17 -1
  213. package/dist/Fx/combinators/throttle.d.ts +79 -0
  214. package/dist/Fx/combinators/throttle.d.ts.map +1 -0
  215. package/dist/Fx/combinators/throttle.js +99 -0
  216. package/dist/Fx/combinators/timeout.d.ts +76 -0
  217. package/dist/Fx/combinators/timeout.d.ts.map +1 -0
  218. package/dist/Fx/combinators/timeout.js +110 -0
  219. package/dist/Fx/combinators/tuple.d.ts +32 -2
  220. package/dist/Fx/combinators/tuple.d.ts.map +1 -1
  221. package/dist/Fx/combinators/tuple.js +36 -5
  222. package/dist/Fx/combinators/until.d.ts +27 -0
  223. package/dist/Fx/combinators/until.d.ts.map +1 -0
  224. package/dist/Fx/combinators/until.js +56 -0
  225. package/dist/Fx/combinators/unwrap.d.ts +31 -2
  226. package/dist/Fx/combinators/unwrap.d.ts.map +1 -1
  227. package/dist/Fx/combinators/unwrap.js +30 -1
  228. package/dist/Fx/combinators/unwrapScoped.d.ts +34 -1
  229. package/dist/Fx/combinators/unwrapScoped.d.ts.map +1 -1
  230. package/dist/Fx/combinators/unwrapScoped.js +34 -1
  231. package/dist/Fx/combinators/when.d.ts +37 -2
  232. package/dist/Fx/combinators/when.d.ts.map +1 -1
  233. package/dist/Fx/combinators/when.js +38 -3
  234. package/dist/Fx/combinators/withLatestFrom.d.ts +58 -0
  235. package/dist/Fx/combinators/withLatestFrom.d.ts.map +1 -0
  236. package/dist/Fx/combinators/withLatestFrom.js +68 -0
  237. package/dist/Fx/combinators/withSpan.d.ts +35 -1
  238. package/dist/Fx/combinators/withSpan.d.ts.map +1 -1
  239. package/dist/Fx/combinators/withSpan.js +34 -3
  240. package/dist/Fx/combinators/zip.d.ts +135 -0
  241. package/dist/Fx/combinators/zip.d.ts.map +1 -0
  242. package/dist/Fx/combinators/zip.js +160 -0
  243. package/dist/Fx/constructors/at.d.ts +23 -3
  244. package/dist/Fx/constructors/at.d.ts.map +1 -1
  245. package/dist/Fx/constructors/at.js +21 -1
  246. package/dist/Fx/constructors/die.d.ts +22 -1
  247. package/dist/Fx/constructors/die.d.ts.map +1 -1
  248. package/dist/Fx/constructors/die.js +22 -1
  249. package/dist/Fx/constructors/empty.d.ts +19 -1
  250. package/dist/Fx/constructors/empty.d.ts.map +1 -1
  251. package/dist/Fx/constructors/empty.js +19 -1
  252. package/dist/Fx/constructors/fail.d.ts +22 -1
  253. package/dist/Fx/constructors/fail.d.ts.map +1 -1
  254. package/dist/Fx/constructors/fail.js +22 -1
  255. package/dist/Fx/constructors/failCause.d.ts +23 -1
  256. package/dist/Fx/constructors/failCause.d.ts.map +1 -1
  257. package/dist/Fx/constructors/failCause.js +23 -1
  258. package/dist/Fx/constructors/fn.d.ts +116 -16
  259. package/dist/Fx/constructors/fn.d.ts.map +1 -1
  260. package/dist/Fx/constructors/fn.js +36 -0
  261. package/dist/Fx/constructors/fromEffect.d.ts +45 -3
  262. package/dist/Fx/constructors/fromEffect.d.ts.map +1 -1
  263. package/dist/Fx/constructors/fromEffect.js +45 -3
  264. package/dist/Fx/constructors/fromFailures.d.ts +25 -1
  265. package/dist/Fx/constructors/fromFailures.d.ts.map +1 -1
  266. package/dist/Fx/constructors/fromFailures.js +25 -1
  267. package/dist/Fx/constructors/fromIterable.d.ts +23 -1
  268. package/dist/Fx/constructors/fromIterable.d.ts.map +1 -1
  269. package/dist/Fx/constructors/fromIterable.js +23 -1
  270. package/dist/Fx/constructors/fromSchedule.d.ts +26 -1
  271. package/dist/Fx/constructors/fromSchedule.d.ts.map +1 -1
  272. package/dist/Fx/constructors/fromSchedule.js +28 -3
  273. package/dist/Fx/constructors/index.d.ts +2 -1
  274. package/dist/Fx/constructors/index.d.ts.map +1 -1
  275. package/dist/Fx/constructors/index.js +2 -1
  276. package/dist/Fx/constructors/interrupt.d.ts +22 -2
  277. package/dist/Fx/constructors/interrupt.d.ts.map +1 -1
  278. package/dist/Fx/constructors/interrupt.js +22 -2
  279. package/dist/Fx/constructors/make.d.ts +151 -4
  280. package/dist/Fx/constructors/make.d.ts.map +1 -1
  281. package/dist/Fx/constructors/make.js +60 -7
  282. package/dist/Fx/constructors/periodic.d.ts +31 -2
  283. package/dist/Fx/constructors/periodic.d.ts.map +1 -1
  284. package/dist/Fx/constructors/periodic.js +30 -1
  285. package/dist/Fx/constructors/succeed.d.ts +79 -7
  286. package/dist/Fx/constructors/succeed.d.ts.map +1 -1
  287. package/dist/Fx/constructors/succeed.js +79 -7
  288. package/dist/Fx/constructors/suspend.d.ts +28 -0
  289. package/dist/Fx/constructors/suspend.d.ts.map +1 -1
  290. package/dist/Fx/constructors/suspend.js +28 -0
  291. package/dist/Fx/constructors/sync.d.ts +32 -0
  292. package/dist/Fx/constructors/sync.d.ts.map +1 -0
  293. package/dist/Fx/constructors/sync.js +32 -0
  294. package/dist/Fx/internal/DeferredRef.d.ts +259 -7
  295. package/dist/Fx/internal/DeferredRef.d.ts.map +1 -1
  296. package/dist/Fx/internal/DeferredRef.js +260 -9
  297. package/dist/Fx/internal/UnionToTuple.d.ts +22 -0
  298. package/dist/Fx/internal/UnionToTuple.d.ts.map +1 -1
  299. package/dist/Fx/internal/diff.d.ts +586 -0
  300. package/dist/Fx/internal/diff.d.ts.map +1 -1
  301. package/dist/Fx/internal/diff.js +120 -9
  302. package/dist/Fx/internal/effectableEvaluateKey.d.ts +30 -0
  303. package/dist/Fx/internal/effectableEvaluateKey.d.ts.map +1 -0
  304. package/dist/Fx/internal/effectableEvaluateKey.js +29 -0
  305. package/dist/Fx/internal/effectableWithOverride.d.ts +55 -0
  306. package/dist/Fx/internal/effectableWithOverride.d.ts.map +1 -0
  307. package/dist/Fx/internal/effectableWithOverride.js +46 -0
  308. package/dist/Fx/internal/equivalence.d.ts +29 -0
  309. package/dist/Fx/internal/equivalence.d.ts.map +1 -1
  310. package/dist/Fx/internal/equivalence.js +29 -0
  311. package/dist/Fx/internal/multicast.d.ts +145 -2
  312. package/dist/Fx/internal/multicast.d.ts.map +1 -1
  313. package/dist/Fx/internal/multicast.js +146 -4
  314. package/dist/Fx/internal/ring-buffer.d.ts +149 -0
  315. package/dist/Fx/internal/ring-buffer.d.ts.map +1 -1
  316. package/dist/Fx/internal/ring-buffer.js +155 -0
  317. package/dist/Fx/internal/scope.d.ts +184 -0
  318. package/dist/Fx/internal/scope.d.ts.map +1 -1
  319. package/dist/Fx/internal/scope.js +150 -0
  320. package/dist/Fx/internal/yieldable.d.ts +117 -2
  321. package/dist/Fx/internal/yieldable.d.ts.map +1 -1
  322. package/dist/Fx/internal/yieldable.js +86 -3
  323. package/dist/Fx/run/collect.d.ts +93 -4
  324. package/dist/Fx/run/collect.d.ts.map +1 -1
  325. package/dist/Fx/run/collect.js +94 -5
  326. package/dist/Fx/run/first.d.ts +23 -1
  327. package/dist/Fx/run/first.d.ts.map +1 -1
  328. package/dist/Fx/run/first.js +23 -1
  329. package/dist/Fx/run/fork.d.ts +52 -2
  330. package/dist/Fx/run/fork.d.ts.map +1 -1
  331. package/dist/Fx/run/fork.js +52 -2
  332. package/dist/Fx/run/observe.d.ts +112 -4
  333. package/dist/Fx/run/observe.d.ts.map +1 -1
  334. package/dist/Fx/run/observe.js +137 -16
  335. package/dist/Fx/run/runPromise.d.ts +45 -2
  336. package/dist/Fx/run/runPromise.d.ts.map +1 -1
  337. package/dist/Fx/run/runPromise.js +45 -2
  338. package/dist/Fx/stream.d.ts +92 -0
  339. package/dist/Fx/stream.d.ts.map +1 -1
  340. package/dist/Fx/stream.js +60 -1
  341. package/dist/Push/Push.d.ts +1286 -98
  342. package/dist/Push/Push.d.ts.map +1 -1
  343. package/dist/Push/Push.js +1074 -88
  344. package/dist/RefArray.d.ts +2 -0
  345. package/dist/RefArray.d.ts.map +1 -0
  346. package/dist/RefArray.js +1 -0
  347. package/dist/RefBigDecimal.d.ts +2 -0
  348. package/dist/RefBigDecimal.d.ts.map +1 -0
  349. package/dist/RefBigDecimal.js +1 -0
  350. package/dist/RefBigInt.d.ts +2 -0
  351. package/dist/RefBigInt.d.ts.map +1 -0
  352. package/dist/RefBigInt.js +1 -0
  353. package/dist/RefBoolean.d.ts +2 -0
  354. package/dist/RefBoolean.d.ts.map +1 -0
  355. package/dist/RefBoolean.js +1 -0
  356. package/dist/RefCause.d.ts +2 -0
  357. package/dist/RefCause.d.ts.map +1 -0
  358. package/dist/RefCause.js +1 -0
  359. package/dist/RefChunk.d.ts +2 -0
  360. package/dist/RefChunk.d.ts.map +1 -0
  361. package/dist/RefChunk.js +1 -0
  362. package/dist/RefDateTime.d.ts +2 -0
  363. package/dist/RefDateTime.d.ts.map +1 -0
  364. package/dist/RefDateTime.js +1 -0
  365. package/dist/RefDuration.d.ts +2 -0
  366. package/dist/RefDuration.d.ts.map +1 -0
  367. package/dist/RefDuration.js +1 -0
  368. package/dist/RefGraph.d.ts +2 -0
  369. package/dist/RefGraph.d.ts.map +1 -0
  370. package/dist/RefGraph.js +1 -0
  371. package/dist/RefHashMap.d.ts +2 -0
  372. package/dist/RefHashMap.d.ts.map +1 -0
  373. package/dist/RefHashMap.js +1 -0
  374. package/dist/RefHashRing.d.ts +2 -0
  375. package/dist/RefHashRing.d.ts.map +1 -0
  376. package/dist/RefHashRing.js +1 -0
  377. package/dist/RefHashSet.d.ts +2 -0
  378. package/dist/RefHashSet.d.ts.map +1 -0
  379. package/dist/RefHashSet.js +1 -0
  380. package/dist/RefIterable.d.ts +2 -0
  381. package/dist/RefIterable.d.ts.map +1 -0
  382. package/dist/RefIterable.js +1 -0
  383. package/dist/RefOption.d.ts +2 -0
  384. package/dist/RefOption.d.ts.map +1 -0
  385. package/dist/RefOption.js +1 -0
  386. package/dist/RefRecord.d.ts +2 -0
  387. package/dist/RefRecord.d.ts.map +1 -0
  388. package/dist/RefRecord.js +1 -0
  389. package/dist/RefResult.d.ts +2 -0
  390. package/dist/RefResult.d.ts.map +1 -0
  391. package/dist/RefResult.js +1 -0
  392. package/dist/RefString.d.ts +2 -0
  393. package/dist/RefString.d.ts.map +1 -0
  394. package/dist/RefString.js +1 -0
  395. package/dist/RefStruct.d.ts +2 -0
  396. package/dist/RefStruct.d.ts.map +1 -0
  397. package/dist/RefStruct.js +1 -0
  398. package/dist/RefSubject/Hydration.d.ts +504 -0
  399. package/dist/RefSubject/Hydration.d.ts.map +1 -0
  400. package/dist/RefSubject/Hydration.js +300 -0
  401. package/dist/RefSubject/RefArray.d.ts +382 -35
  402. package/dist/RefSubject/RefArray.d.ts.map +1 -1
  403. package/dist/RefSubject/RefArray.js +374 -40
  404. package/dist/RefSubject/RefBigDecimal.d.ts +241 -21
  405. package/dist/RefSubject/RefBigDecimal.d.ts.map +1 -1
  406. package/dist/RefSubject/RefBigDecimal.js +229 -20
  407. package/dist/RefSubject/RefBigInt.d.ts +181 -16
  408. package/dist/RefSubject/RefBigInt.d.ts.map +1 -1
  409. package/dist/RefSubject/RefBigInt.js +169 -15
  410. package/dist/RefSubject/RefBoolean.d.ts +181 -16
  411. package/dist/RefSubject/RefBoolean.d.ts.map +1 -1
  412. package/dist/RefSubject/RefBoolean.js +169 -15
  413. package/dist/RefSubject/RefCause.d.ts +133 -12
  414. package/dist/RefSubject/RefCause.d.ts.map +1 -1
  415. package/dist/RefSubject/RefCause.js +121 -11
  416. package/dist/RefSubject/RefChunk.d.ts +481 -76
  417. package/dist/RefSubject/RefChunk.d.ts.map +1 -1
  418. package/dist/RefSubject/RefChunk.js +471 -75
  419. package/dist/RefSubject/RefDateTime.d.ts +137 -16
  420. package/dist/RefSubject/RefDateTime.d.ts.map +1 -1
  421. package/dist/RefSubject/RefDateTime.js +122 -12
  422. package/dist/RefSubject/RefDuration.d.ts +169 -15
  423. package/dist/RefSubject/RefDuration.d.ts.map +1 -1
  424. package/dist/RefSubject/RefDuration.js +157 -14
  425. package/dist/RefSubject/RefGraph.d.ts +349 -35
  426. package/dist/RefSubject/RefGraph.d.ts.map +1 -1
  427. package/dist/RefSubject/RefGraph.js +334 -32
  428. package/dist/RefSubject/RefHashMap.d.ts +323 -28
  429. package/dist/RefSubject/RefHashMap.d.ts.map +1 -1
  430. package/dist/RefSubject/RefHashMap.js +317 -29
  431. package/dist/RefSubject/RefHashRing.d.ts +159 -15
  432. package/dist/RefSubject/RefHashRing.d.ts.map +1 -1
  433. package/dist/RefSubject/RefHashRing.js +145 -12
  434. package/dist/RefSubject/RefHashSet.d.ts +251 -22
  435. package/dist/RefSubject/RefHashSet.d.ts.map +1 -1
  436. package/dist/RefSubject/RefHashSet.js +238 -20
  437. package/dist/RefSubject/RefIterable.d.ts +358 -32
  438. package/dist/RefSubject/RefIterable.d.ts.map +1 -1
  439. package/dist/RefSubject/RefIterable.js +350 -30
  440. package/dist/RefSubject/RefOption.d.ts +157 -14
  441. package/dist/RefSubject/RefOption.d.ts.map +1 -1
  442. package/dist/RefSubject/RefOption.js +145 -13
  443. package/dist/RefSubject/RefRecord.d.ts +402 -64
  444. package/dist/RefSubject/RefRecord.d.ts.map +1 -1
  445. package/dist/RefSubject/RefRecord.js +364 -39
  446. package/dist/RefSubject/RefResult.d.ts +167 -35
  447. package/dist/RefSubject/RefResult.d.ts.map +1 -1
  448. package/dist/RefSubject/RefResult.js +133 -12
  449. package/dist/RefSubject/RefString.d.ts +205 -18
  450. package/dist/RefSubject/RefString.d.ts.map +1 -1
  451. package/dist/RefSubject/RefString.js +193 -17
  452. package/dist/RefSubject/RefStruct.d.ts +169 -14
  453. package/dist/RefSubject/RefStruct.d.ts.map +1 -1
  454. package/dist/RefSubject/RefStruct.js +157 -13
  455. package/dist/RefSubject/RefSubject.d.ts +1242 -43
  456. package/dist/RefSubject/RefSubject.d.ts.map +1 -1
  457. package/dist/RefSubject/RefSubject.js +1012 -86
  458. package/dist/RefSubject/RefTrie.d.ts +323 -37
  459. package/dist/RefSubject/RefTrie.d.ts.map +1 -1
  460. package/dist/RefSubject/RefTrie.js +311 -31
  461. package/dist/RefSubject/RefTuple.d.ts +127 -11
  462. package/dist/RefSubject/RefTuple.d.ts.map +1 -1
  463. package/dist/RefSubject/RefTuple.js +114 -9
  464. package/dist/RefSubject/index.d.ts +1 -0
  465. package/dist/RefSubject/index.d.ts.map +1 -1
  466. package/dist/RefSubject/index.js +1 -0
  467. package/dist/RefSubject.d.ts +2 -1
  468. package/dist/RefSubject.d.ts.map +1 -1
  469. package/dist/RefSubject.js +2 -1
  470. package/dist/RefTrie.d.ts +2 -0
  471. package/dist/RefTrie.d.ts.map +1 -0
  472. package/dist/RefTrie.js +1 -0
  473. package/dist/RefTuple.d.ts +2 -0
  474. package/dist/RefTuple.d.ts.map +1 -0
  475. package/dist/RefTuple.js +1 -0
  476. package/dist/Sink/Sink.d.ts +396 -23
  477. package/dist/Sink/Sink.d.ts.map +1 -1
  478. package/dist/Sink/Sink.js +55 -7
  479. package/dist/Sink/combinators.d.ts +789 -3
  480. package/dist/Sink/combinators.d.ts.map +1 -1
  481. package/dist/Sink/combinators.js +812 -7
  482. package/dist/Subject/Subject.d.ts +1022 -27
  483. package/dist/Subject/Subject.d.ts.map +1 -1
  484. package/dist/Subject/Subject.js +909 -43
  485. package/dist/Versioned/Versioned.d.ts +475 -25
  486. package/dist/Versioned/Versioned.d.ts.map +1 -1
  487. package/dist/Versioned/Versioned.js +298 -46
  488. package/dist/index.d.ts +22 -3
  489. package/dist/index.d.ts.map +1 -1
  490. package/dist/index.js +22 -3
  491. package/package.json +125 -11
  492. package/dist/Fx/constructors/fromYieldable.d.ts +0 -12
  493. package/dist/Fx/constructors/fromYieldable.d.ts.map +0 -1
  494. package/dist/Fx/constructors/fromYieldable.js +0 -12
  495. package/src/Fx/Fx.ts +0 -164
  496. package/src/Fx/TypeId.ts +0 -25
  497. package/src/Fx/combinators/catch.ts +0 -165
  498. package/src/Fx/combinators/causes.ts +0 -23
  499. package/src/Fx/combinators/compact.ts +0 -15
  500. package/src/Fx/combinators/continueWith.ts +0 -78
  501. package/src/Fx/combinators/ensuring.ts +0 -23
  502. package/src/Fx/combinators/exhaustLatestMap.ts +0 -74
  503. package/src/Fx/combinators/exhaustLatestMapEffect.ts +0 -25
  504. package/src/Fx/combinators/exhaustMap.ts +0 -36
  505. package/src/Fx/combinators/exhaustMapEffect.ts +0 -23
  506. package/src/Fx/combinators/exit.ts +0 -15
  507. package/src/Fx/combinators/filter.ts +0 -22
  508. package/src/Fx/combinators/filterEffect.ts +0 -31
  509. package/src/Fx/combinators/filterMap.ts +0 -23
  510. package/src/Fx/combinators/filterMapEffect.ts +0 -32
  511. package/src/Fx/combinators/filterMapLoop.ts +0 -35
  512. package/src/Fx/combinators/filterMapLoopCause.ts +0 -36
  513. package/src/Fx/combinators/filterMapLoopCauseEffect.ts +0 -46
  514. package/src/Fx/combinators/filterMapLoopEffect.ts +0 -36
  515. package/src/Fx/combinators/flatMap.ts +0 -51
  516. package/src/Fx/combinators/flatMapConcurrently.ts +0 -36
  517. package/src/Fx/combinators/flatMapConcurrentlyEffect.ts +0 -26
  518. package/src/Fx/combinators/flatMapEffect.ts +0 -42
  519. package/src/Fx/combinators/flip.ts +0 -14
  520. package/src/Fx/combinators/gen.ts +0 -24
  521. package/src/Fx/combinators/genScoped.ts +0 -24
  522. package/src/Fx/combinators/index.ts +0 -51
  523. package/src/Fx/combinators/keyed.ts +0 -369
  524. package/src/Fx/combinators/loop.ts +0 -27
  525. package/src/Fx/combinators/loopCause.ts +0 -34
  526. package/src/Fx/combinators/loopCauseEffect.ts +0 -36
  527. package/src/Fx/combinators/loopEffect.ts +0 -34
  528. package/src/Fx/combinators/map.ts +0 -22
  529. package/src/Fx/combinators/mapEffect.ts +0 -32
  530. package/src/Fx/combinators/mergeAll.ts +0 -22
  531. package/src/Fx/combinators/mergeOrdered.ts +0 -123
  532. package/src/Fx/combinators/onError.ts +0 -40
  533. package/src/Fx/combinators/onExit.ts +0 -82
  534. package/src/Fx/combinators/onInterrupt.ts +0 -87
  535. package/src/Fx/combinators/provide.ts +0 -62
  536. package/src/Fx/combinators/skip.ts +0 -20
  537. package/src/Fx/combinators/skipRepeats.ts +0 -15
  538. package/src/Fx/combinators/skipRepeatsWith.ts +0 -40
  539. package/src/Fx/combinators/slice.ts +0 -32
  540. package/src/Fx/combinators/switchMap.ts +0 -55
  541. package/src/Fx/combinators/switchMapEffect.ts +0 -25
  542. package/src/Fx/combinators/take.ts +0 -17
  543. package/src/Fx/combinators/takeUntil.ts +0 -50
  544. package/src/Fx/combinators/tapEffect.ts +0 -39
  545. package/src/Fx/combinators/tuple.ts +0 -79
  546. package/src/Fx/combinators/unwrap.ts +0 -21
  547. package/src/Fx/combinators/unwrapScoped.ts +0 -26
  548. package/src/Fx/combinators/when.ts +0 -64
  549. package/src/Fx/combinators/withSpan.ts +0 -24
  550. package/src/Fx/constructors/at.ts +0 -23
  551. package/src/Fx/constructors/die.ts +0 -17
  552. package/src/Fx/constructors/empty.ts +0 -10
  553. package/src/Fx/constructors/fail.ts +0 -14
  554. package/src/Fx/constructors/failCause.ts +0 -14
  555. package/src/Fx/constructors/fn.ts +0 -245
  556. package/src/Fx/constructors/fromEffect.ts +0 -24
  557. package/src/Fx/constructors/fromFailures.ts +0 -19
  558. package/src/Fx/constructors/fromIterable.ts +0 -15
  559. package/src/Fx/constructors/fromSchedule.ts +0 -18
  560. package/src/Fx/constructors/fromYieldable.ts +0 -17
  561. package/src/Fx/constructors/index.ts +0 -15
  562. package/src/Fx/constructors/interrupt.ts +0 -13
  563. package/src/Fx/constructors/make.ts +0 -103
  564. package/src/Fx/constructors/periodic.ts +0 -15
  565. package/src/Fx/constructors/succeed.ts +0 -37
  566. package/src/Fx/constructors/suspend.ts +0 -6
  567. package/src/Fx/index.ts +0 -6
  568. package/src/Fx/internal/DeferredRef.ts +0 -87
  569. package/src/Fx/internal/UnionToTuple.ts +0 -12
  570. package/src/Fx/internal/diff.ts +0 -191
  571. package/src/Fx/internal/equivalence.ts +0 -12
  572. package/src/Fx/internal/multicast.ts +0 -51
  573. package/src/Fx/internal/ring-buffer.ts +0 -60
  574. package/src/Fx/internal/scope.ts +0 -58
  575. package/src/Fx/internal/yieldable.ts +0 -31
  576. package/src/Fx/run/collect.ts +0 -79
  577. package/src/Fx/run/first.ts +0 -20
  578. package/src/Fx/run/fork.ts +0 -40
  579. package/src/Fx/run/index.ts +0 -5
  580. package/src/Fx/run/observe.ts +0 -114
  581. package/src/Fx/run/runPromise.ts +0 -32
  582. package/src/Fx/stream.ts +0 -42
  583. package/src/Fx.catch.test.ts +0 -61
  584. package/src/Fx.fn.test.ts +0 -51
  585. package/src/Fx.lifecycle.test.ts +0 -80
  586. package/src/Fx.test.ts +0 -71
  587. package/src/Fx.ts +0 -1
  588. package/src/Push/Push.ts +0 -903
  589. package/src/Push/index.ts +0 -1
  590. package/src/Push.test.ts +0 -26
  591. package/src/Push.ts +0 -1
  592. package/src/RefSubject/RefArray.ts +0 -512
  593. package/src/RefSubject/RefBigDecimal.test.ts +0 -56
  594. package/src/RefSubject/RefBigDecimal.ts +0 -295
  595. package/src/RefSubject/RefBigInt.test.ts +0 -56
  596. package/src/RefSubject/RefBigInt.ts +0 -189
  597. package/src/RefSubject/RefBoolean.test.ts +0 -57
  598. package/src/RefSubject/RefBoolean.ts +0 -185
  599. package/src/RefSubject/RefCause.test.ts +0 -53
  600. package/src/RefSubject/RefCause.ts +0 -146
  601. package/src/RefSubject/RefChunk.ts +0 -510
  602. package/src/RefSubject/RefDateTime.test.ts +0 -43
  603. package/src/RefSubject/RefDateTime.ts +0 -264
  604. package/src/RefSubject/RefDuration.test.ts +0 -49
  605. package/src/RefSubject/RefDuration.ts +0 -188
  606. package/src/RefSubject/RefGraph.ts +0 -650
  607. package/src/RefSubject/RefHashMap.ts +0 -465
  608. package/src/RefSubject/RefHashRing.ts +0 -262
  609. package/src/RefSubject/RefHashSet.ts +0 -308
  610. package/src/RefSubject/RefIterable.ts +0 -445
  611. package/src/RefSubject/RefOption.test.ts +0 -67
  612. package/src/RefSubject/RefOption.ts +0 -193
  613. package/src/RefSubject/RefRecord.ts +0 -612
  614. package/src/RefSubject/RefResult.test.ts +0 -63
  615. package/src/RefSubject/RefResult.ts +0 -209
  616. package/src/RefSubject/RefString.test.ts +0 -61
  617. package/src/RefSubject/RefString.ts +0 -256
  618. package/src/RefSubject/RefStruct.test.ts +0 -60
  619. package/src/RefSubject/RefStruct.ts +0 -253
  620. package/src/RefSubject/RefSubject.ts +0 -2545
  621. package/src/RefSubject/RefTrie.ts +0 -356
  622. package/src/RefSubject/RefTuple.test.ts +0 -60
  623. package/src/RefSubject/RefTuple.ts +0 -231
  624. package/src/RefSubject/index.ts +0 -21
  625. package/src/RefSubject.test.ts +0 -65
  626. package/src/RefSubject.ts +0 -1
  627. package/src/Sink/Sink.ts +0 -159
  628. package/src/Sink/combinators.ts +0 -993
  629. package/src/Sink/index.ts +0 -2
  630. package/src/Sink.ts +0 -1
  631. package/src/Subject/Subject.ts +0 -441
  632. package/src/Subject/index.ts +0 -1
  633. package/src/Subject.test.ts +0 -47
  634. package/src/Subject.ts +0 -1
  635. package/src/Versioned/Versioned.ts +0 -521
  636. package/src/Versioned/index.ts +0 -1
  637. package/src/Versioned.test.ts +0 -23
  638. package/src/Versioned.ts +0 -1
  639. package/src/index.ts +0 -7
  640. package/tsconfig.json +0 -6
@@ -2,6 +2,8 @@
2
2
  /** @effect-diagnostics missingEffectContext:skip-file */
3
3
  import * as Array from "effect/Array";
4
4
  import * as Effect from "effect/Effect";
5
+ import * as Effectable from "effect/Effectable";
6
+ import * as Semaphore from "effect/Semaphore";
5
7
  import { equals } from "effect/Equal";
6
8
  import * as Exit from "effect/Exit";
7
9
  import * as Fiber from "effect/Fiber";
@@ -12,17 +14,18 @@ import { sum } from "effect/Number";
12
14
  import * as Option from "effect/Option";
13
15
  import { pipeArguments } from "effect/Pipeable";
14
16
  import * as Scope from "effect/Scope";
15
- import * as ServiceMap from "effect/ServiceMap";
17
+ import * as Context from "effect/Context";
16
18
  import * as Stream from "effect/Stream";
17
19
  import { compact as fxCompact } from "../Fx/combinators/compact.js";
18
20
  import { continueWith } from "../Fx/combinators/continueWith.js";
19
21
  import { filterMapEffect as fxFilterMapEffect } from "../Fx/combinators/filterMapEffect.js";
20
22
  import { mapEffect as fxMapEffect } from "../Fx/combinators/mapEffect.js";
23
+ import { mergeAll as fxMergeAll } from "../Fx/combinators/mergeAll.js";
24
+ import { scanEffect as fxScanEffect } from "../Fx/combinators/scan.js";
21
25
  import { skipRepeats } from "../Fx/combinators/skipRepeats.js";
22
26
  import { slice as fxSlice } from "../Fx/combinators/slice.js";
23
27
  import { unwrap } from "../Fx/combinators/unwrap.js";
24
28
  import { fromEffect as fxFromEffect } from "../Fx/constructors/fromEffect.js";
25
- import { fromYieldable } from "../Fx/constructors/fromYieldable.js";
26
29
  import * as DeferredRef from "../Fx/internal/DeferredRef.js";
27
30
  import { getExitEquivalence } from "../Fx/internal/equivalence.js";
28
31
  import { YieldableFx } from "../Fx/internal/yieldable.js";
@@ -30,13 +33,92 @@ import { FxTypeId, isFx } from "../Fx/TypeId.js";
30
33
  import * as Sink from "../Sink/Sink.js";
31
34
  import * as Subject from "../Subject/Subject.js";
32
35
  import * as Versioned from "../Versioned/Versioned.js";
36
+ import { hasProperty } from "effect/Predicate";
37
+ /**
38
+ * Runtime symbol identifying writable RefSubject values.
39
+ *
40
+ * @remarks
41
+ * ## Why
42
+ *
43
+ * Provides stable runtime identity for RefSubject values without relying on classes or a renderer.
44
+ *
45
+ * ## Ownership and lifetime
46
+ *
47
+ * This declaration performs no acquisition and retains no resources. Implementations preserve
48
+ * source errors, services, and lifetime.
49
+ *
50
+ * @since 1.18.0
51
+ * @category Type identity
52
+ */
33
53
  export const RefSubjectTypeId = Symbol.for("@typed/fx/RefSubject");
54
+ /**
55
+ * Runtime symbol identifying read-only Computed values.
56
+ *
57
+ * @remarks
58
+ * ## Why
59
+ *
60
+ * Provides stable runtime identity for Computed values without relying on classes or a renderer.
61
+ *
62
+ * ## Ownership and lifetime
63
+ *
64
+ * This declaration performs no acquisition and retains no resources. Implementations preserve
65
+ * source errors, services, and lifetime.
66
+ *
67
+ * @since 1.18.0
68
+ * @category Type identity
69
+ */
34
70
  export const ComputedTypeId = Symbol.for("@typed/fx/Computed");
71
+ /**
72
+ * Runtime symbol identifying conditionally available Filtered values.
73
+ *
74
+ * @remarks
75
+ * ## Why
76
+ *
77
+ * Provides stable runtime identity for Filtered values without relying on classes or a renderer.
78
+ *
79
+ * ## Ownership and lifetime
80
+ *
81
+ * This declaration performs no acquisition and retains no resources. Implementations preserve
82
+ * source errors, services, and lifetime.
83
+ *
84
+ * @since 1.18.0
85
+ * @category Type identity
86
+ */
35
87
  export const FilteredTypeId = Symbol.for("@typed/fx/Filtered");
36
- export const CurrentComputedBehavior = ServiceMap.Reference("@typed/fx/CurrentComputedBehavior", {
88
+ /**
89
+ * Selects whether a computed Fx observes only its current value or also follows later pushes.
90
+ *
91
+ * @remarks
92
+ * ## Why
93
+ *
94
+ * `"multiple"` (the default) emits the current value and then follows distinct source pushes.
95
+ * `"one"` emits only the current value. Hydration temporarily uses `"one"` when it must resolve a
96
+ * single server value without leaving a live observation running.
97
+ *
98
+ * ## Ownership and lifetime
99
+ *
100
+ * This is an Effect Context reference with a default value, not mutable global state. Supplying a
101
+ * value changes computed observation only in the provided Effect context; the observing Scope
102
+ * still owns any subscription created by `"multiple"`.
103
+ *
104
+ * @since 1.18.0
105
+ * @category Observation policy
106
+ */
107
+ export const CurrentComputedBehavior = Context.Reference("@typed/fx/CurrentComputedBehavior", {
37
108
  defaultValue: () => "multiple",
38
109
  });
39
- const checkIsMultiple = (ctx) => ServiceMap.getReferenceUnsafe(ctx, CurrentComputedBehavior) === "multiple";
110
+ const checkIsMultiple = (ctx) => Context.getUnsafe(ctx, CurrentComputedBehavior) === "multiple";
111
+ function holdInContext(fx) {
112
+ const contexts = new WeakMap();
113
+ return unwrap(Effect.map(Effect.context(), (context) => {
114
+ let shared = contexts.get(context);
115
+ if (!shared) {
116
+ shared = Subject.hold(fx);
117
+ contexts.set(context, shared);
118
+ }
119
+ return shared;
120
+ }));
121
+ }
40
122
  class ComputedImpl extends Versioned.VersionedTransform {
41
123
  [ComputedTypeId] = ComputedTypeId;
42
124
  _computed;
@@ -46,20 +128,145 @@ class ComputedImpl extends Versioned.VersionedTransform {
46
128
  super(input, (fx) => fxMapEffect(fx, f), Effect.flatMap(f));
47
129
  this.input = input;
48
130
  this.f = f;
49
- this._computed = Subject.hold(unwrap(Effect.map(Effect.services(), (ctx) => {
131
+ this._computed = holdInContext(unwrap(Effect.map(Effect.context(), (ctx) => {
50
132
  if (checkIsMultiple(ctx)) {
51
- return fromYieldable(input).pipe(continueWith(() => input), skipRepeats, fxMapEffect(f));
133
+ return fxFromEffect(input).pipe(continueWith(() => input), skipRepeats, fxMapEffect(f));
52
134
  }
53
- return fxFromEffect(Effect.flatMap(input.asEffect(), f));
135
+ return fxFromEffect(Effect.flatMap(input, f));
54
136
  })));
55
137
  }
56
138
  run(sink) {
57
139
  return this._computed.run(sink);
58
140
  }
59
141
  }
142
+ /**
143
+ * Builds a read-only Computed projection from a Versioned source.
144
+ *
145
+ * @remarks
146
+ * ## Why
147
+ *
148
+ * Applies the same Effectful projection to current reads and pushed versions, preserving all three
149
+ * Versioned channels without granting writes to the source.
150
+ *
151
+ * ## Ownership and lifetime
152
+ *
153
+ * Current reads cache the transformed input by source version within each Effect Context. The
154
+ * pushed channel uses `Subject.hold`: observers with the same Context object share one upstream
155
+ * session and its retained projection; distinct Context objects have separate sessions. The last
156
+ * observer ends its session and clears its held value. The observing Scope owns cleanup.
157
+ *
158
+ * @since 1.18.0
159
+ * @category Derived queries
160
+ */
60
161
  export function makeComputed(input, f) {
61
162
  return new ComputedImpl(input, f);
62
163
  }
164
+ /**
165
+ * Stateful scan over a `RefSubject` / `Computed`, producing a `Computed` of the accumulated state.
166
+ *
167
+ * Fx subscriptions follow `Fx.scan` semantics (emit `initial`, then fold each source value).
168
+ * Effect sampling accumulates across source versions via a private state ref (do not mix heavy
169
+ * subscribe + sample on the same scan if you need a single shared accumulator).
170
+ *
171
+ * @remarks
172
+ * ## Why
173
+ *
174
+ * Stateful scan over a `RefSubject` / `Computed`, producing a `Computed` of the accumulated state.
175
+ * Fx subscriptions follow `Fx.scan` semantics (emit `initial`, then fold each source value).
176
+ * Effect sampling accumulates across source versions via a private state ref (do not mix heavy
177
+ * subscribe + sample on the same scan if you need a single shared accumulator). The result remains
178
+ * a lazy view rather than a duplicated mutable value.
179
+ *
180
+ * ## Ownership and lifetime
181
+ *
182
+ * Each Effect Context object gets a private current-read accumulator, advanced after a successful
183
+ * fold for a new source version. The pushed channel runs `Fx.scanEffect` from `initial` inside
184
+ * `Subject.hold`: observers using the same Context share that active scan and retained result.
185
+ * The last observer ends its session and clears its held value. The observing Scope owns
186
+ * subscription cleanup. Read accumulators are weakly held by Context and need no finalizer.
187
+ *
188
+ * @since 1.0.0
189
+ * @category Accumulation
190
+ */
191
+ export const scan = dual(3, function scan(versioned, initial, f) {
192
+ return new ComputedScanImpl(versioned, initial, (s, a) => Effect.succeed(f(s, a)));
193
+ });
194
+ /**
195
+ * Effectful stateful scan over a `RefSubject` / `Computed`, producing a `Computed` of the accumulated state.
196
+ *
197
+ * @remarks
198
+ * ## Why
199
+ *
200
+ * Effectful stateful scan over a `RefSubject` / `Computed`, producing a `Computed` of the
201
+ * accumulated state. The result remains a lazy view rather than a duplicated mutable value.
202
+ *
203
+ * ## Ownership and lifetime
204
+ *
205
+ * Each Effect Context object gets a private current-read accumulator. It advances only after `f`
206
+ * succeeds, so a typed failure leaves the previous state intact. The pushed channel runs
207
+ * `Fx.scanEffect` from `initial` inside `Subject.hold`: observers using the same Context share
208
+ * that active scan and retained result; each fold requires `R3`. The last observer ends its
209
+ * session and clears its held value. The observing Scope owns cleanup. Read accumulators are
210
+ * weakly held by Context and need no finalizer.
211
+ *
212
+ * @since 1.0.0
213
+ * @category Accumulation
214
+ */
215
+ export const scanEffect = dual(3, function scanEffect(versioned, initial, f) {
216
+ return new ComputedScanImpl(versioned, initial, f);
217
+ });
218
+ class ComputedScanImpl extends Versioned.VersionedTransform {
219
+ [ComputedTypeId] = ComputedTypeId;
220
+ _computed;
221
+ input;
222
+ initial;
223
+ f;
224
+ constructor(input, initial, f) {
225
+ const states = new WeakMap();
226
+ super(input, (fx) => fxScanEffect(fx, initial, f), (effect) => Effect.contextWith((context) => {
227
+ let state = states.get(context);
228
+ if (!state) {
229
+ state = MutableRef.make(initial);
230
+ states.set(context, state);
231
+ }
232
+ const current = state;
233
+ return Effect.flatMap(effect, (a) => Effect.flatMap(f(MutableRef.get(current), a), (next) => Effect.sync(() => {
234
+ MutableRef.set(current, next);
235
+ return next;
236
+ })));
237
+ }));
238
+ this.input = input;
239
+ this.initial = initial;
240
+ this.f = f;
241
+ this._computed = holdInContext(unwrap(Effect.map(Effect.context(), (ctx) => {
242
+ if (checkIsMultiple(ctx)) {
243
+ return fxFromEffect(input).pipe(continueWith(() => input), skipRepeats, fxScanEffect(initial, f));
244
+ }
245
+ return fxFromEffect(Effect.flatMap(input, (a) => f(initial, a)));
246
+ })));
247
+ }
248
+ run(sink) {
249
+ return this._computed.run(sink);
250
+ }
251
+ }
252
+ /**
253
+ * Builds a Filtered view from the three channels of a Versioned source.
254
+ *
255
+ * @remarks
256
+ * ## Why
257
+ *
258
+ * Applies `f` to current reads and later pushes while preserving absence as Filtered semantics:
259
+ * Effect reads fail with `NoSuchElementError`, whereas the Fx channel simply omits absent values.
260
+ *
261
+ * ## Ownership and lifetime
262
+ *
263
+ * Sampled results and pushed sessions are isolated by Effect Context identity. Within one Context,
264
+ * current reads cache by source version and observers share the active held projection. Its
265
+ * Effect read fails with NoSuchElement while absent; the observing Scope owns its subscription.
266
+ *
267
+ * @since 1.18.0
268
+ * @category Optional queries
269
+ */
63
270
  export function makeFiltered(input, f) {
64
271
  return new FilteredImpl(input, f);
65
272
  }
@@ -69,14 +276,14 @@ class FilteredImpl extends Versioned.VersionedTransform {
69
276
  input;
70
277
  f;
71
278
  constructor(input, f) {
72
- super(input, (fx) => fxFilterMapEffect(fx, f), (effect) => Effect.flatMap(Effect.flatMap(effect, f), (option) => option.asEffect()));
279
+ super(input, (fx) => fxFilterMapEffect(fx, f), (effect) => Effect.flatMap(Effect.flatMap(effect, f), Effect.fromOption));
73
280
  this.input = input;
74
281
  this.f = f;
75
- this._computed = Subject.hold(unwrap(Effect.map(Effect.services(), (ctx) => {
282
+ this._computed = holdInContext(unwrap(Effect.map(Effect.context(), (ctx) => {
76
283
  if (checkIsMultiple(ctx)) {
77
- return fromYieldable(input).pipe(continueWith(() => input), skipRepeats, fxFilterMapEffect(f));
284
+ return fxFromEffect(input).pipe(continueWith(() => input), skipRepeats, fxFilterMapEffect(f));
78
285
  }
79
- return fxCompact(fxFromEffect(Effect.flatMap(input.asEffect(), f)));
286
+ return fxCompact(fxFromEffect(Effect.flatMap(input, f)));
80
287
  })));
81
288
  }
82
289
  run(sink) {
@@ -86,6 +293,7 @@ class FilteredImpl extends Versioned.VersionedTransform {
86
293
  return new ComputedImpl(this.input, this.f);
87
294
  }
88
295
  }
296
+ let nextTransactionOrder = 0;
89
297
  class RefSubjectCore {
90
298
  initial;
91
299
  subject;
@@ -93,6 +301,7 @@ class RefSubjectCore {
93
301
  scope;
94
302
  deferredRef;
95
303
  semaphore;
304
+ transactionOrder = nextTransactionOrder++;
96
305
  constructor(initial, subject, services, scope, deferredRef, semaphore) {
97
306
  this.initial = initial;
98
307
  this.subject = subject;
@@ -103,10 +312,116 @@ class RefSubjectCore {
103
312
  }
104
313
  _fiber = undefined;
105
314
  }
106
- function getSetDelete(ref) {
315
+ function combineTransactionCores(accesses) {
316
+ return [...new Set(accesses.flatMap((access) => access.cores))].sort((left, right) => left.transactionOrder - right.transactionOrder);
317
+ }
318
+ function getTupleTransactionAccess(refs) {
319
+ const accessEffects = refs.map(getTransactionAccess);
320
+ if (!accessEffects.every((access) => access !== undefined)) {
321
+ return undefined;
322
+ }
323
+ return Effect.map(Effect.all(accessEffects, UNBOUNDED), (accessOptions) => Option.map(Option.all(accessOptions), (accesses) => ({
324
+ cores: combineTransactionCores(accesses),
325
+ getSetDelete: (recordCommit) => {
326
+ const transactions = accesses.map((access) => access.getSetDelete(recordCommit));
327
+ return {
328
+ get: Effect.all(transactions.map((transaction) => transaction.get), UNBOUNDED),
329
+ set: (value) => Effect.all(transactions.map((transaction, index) => transaction.set(value[index])), UNBOUNDED),
330
+ delete: Effect.map(Effect.all(transactions.map((transaction) => transaction.delete), UNBOUNDED), Option.all),
331
+ };
332
+ },
333
+ })));
334
+ }
335
+ function getStructTransactionAccess(refs) {
336
+ const keys = Object.keys(refs);
337
+ const accessEffects = keys.map((key) => getTransactionAccess(refs[key]));
338
+ if (!accessEffects.every((access) => access !== undefined)) {
339
+ return undefined;
340
+ }
341
+ return Effect.map(Effect.all(accessEffects, UNBOUNDED), (accessOptions) => Option.map(Option.all(accessOptions), (accesses) => ({
342
+ cores: combineTransactionCores(accesses),
343
+ getSetDelete: (recordCommit) => {
344
+ const transactions = accesses.map((access) => access.getSetDelete(recordCommit));
345
+ return {
346
+ get: Effect.map(Effect.all(transactions.map((transaction) => transaction.get), UNBOUNDED), (values) => Object.fromEntries(keys.map((key, index) => [key, values[index]]))),
347
+ set: (value) => Effect.all(transactions.map((transaction, index) => transaction.set(value[keys[index]])), UNBOUNDED),
348
+ delete: Effect.map(Effect.all(transactions.map((transaction) => transaction.delete), UNBOUNDED), (values) => Option.all(Object.fromEntries(keys.map((key, index) => [key, values[index]])))),
349
+ };
350
+ },
351
+ })));
352
+ }
353
+ function getTransactionAccess(ref) {
354
+ if (ref instanceof RefSubjectImpl) {
355
+ return Effect.succeed(Option.some({
356
+ cores: [ref.core],
357
+ getSetDelete: (recordCommit) => getSetDelete(ref.core, (exit) => recordCommit([ref.core, exit, ref.core.deferredRef.version])),
358
+ }));
359
+ }
360
+ if (ref instanceof RefSubjectSimpleTransform)
361
+ return getTransactionAccess(ref.ref);
362
+ if (ref instanceof RefSubjectTransform) {
363
+ const accessEffect = getTransactionAccess(ref.ref);
364
+ if (!accessEffect)
365
+ return undefined;
366
+ return Effect.map(accessEffect, Option.map((access) => ({
367
+ cores: access.cores,
368
+ getSetDelete: (recordCommit) => {
369
+ const transaction = access.getSetDelete(recordCommit);
370
+ return {
371
+ get: Effect.map(transaction.get, ref.toB),
372
+ set: (value) => Effect.map(transaction.set(ref.toA(value)), ref.toB),
373
+ delete: Effect.map(transaction.delete, Option.map(ref.toB)),
374
+ };
375
+ },
376
+ })));
377
+ }
378
+ if (ref instanceof RefSubjectTuple)
379
+ return getTupleTransactionAccess(ref.refs);
380
+ if (ref instanceof RefSubjectStruct)
381
+ return getStructTransactionAccess(ref.refs);
382
+ if (typeof ref === "function") {
383
+ const service = ref.service;
384
+ if (Effect.isEffect(service)) {
385
+ return Effect.flatMap(service, (providedRef) => {
386
+ const accessEffect = getTransactionAccess(providedRef);
387
+ return accessEffect ?? Effect.succeed(Option.none());
388
+ });
389
+ }
390
+ }
391
+ return undefined;
392
+ }
393
+ function withTransactionLocks(cores, effect) {
394
+ let locked = effect;
395
+ for (let index = cores.length - 1; index >= 0; index--) {
396
+ locked = cores[index].semaphore.withPermits(1)(locked);
397
+ }
398
+ return locked;
399
+ }
400
+ function runTransaction(access, run) {
401
+ return Effect.uninterruptibleMask((restore) => {
402
+ const commits = [];
403
+ const transaction = restore(withTransactionLocks(access.cores, Effect.suspend(() => run(access.getSetDelete((commit) => {
404
+ commits.push(commit);
405
+ })))));
406
+ return Effect.flatMap(Effect.exit(transaction), (exit) => Effect.andThen(Effect.forEach(commits, ([core, commit, version]) => sendCurrentEvent(core, commit, version), {
407
+ discard: true,
408
+ }), exit));
409
+ });
410
+ }
411
+ function sendCurrentEvent(core, commit, version) {
412
+ return Effect.suspend(() => {
413
+ const current = MutableRef.get(core.deferredRef.current);
414
+ return core.deferredRef.version === version &&
415
+ Option.isSome(current) &&
416
+ core.deferredRef.eq(current.value, commit)
417
+ ? sendEvent(core, commit)
418
+ : Effect.void;
419
+ });
420
+ }
421
+ function getSetDelete(ref, recordCommit) {
107
422
  return {
108
423
  get: getOrInitializeCore(ref, false),
109
- set: (a) => setCore(ref, a),
424
+ set: (a) => bufferSuccessCore(ref, a, recordCommit),
110
425
  delete: deleteCore(ref),
111
426
  };
112
427
  }
@@ -116,7 +431,6 @@ class RefSubjectImpl extends YieldableFx {
116
431
  version;
117
432
  interrupt;
118
433
  subscriberCount;
119
- getSetDelete;
120
434
  core;
121
435
  constructor(core) {
122
436
  super();
@@ -124,25 +438,25 @@ class RefSubjectImpl extends YieldableFx {
124
438
  this.version = Effect.sync(() => core.deferredRef.version);
125
439
  this.interrupt = Effect.provide(interruptCore(core), core.services);
126
440
  this.subscriberCount = Effect.provide(core.subject.subscriberCount, core.services);
127
- this.getSetDelete = getSetDelete(core);
128
441
  this.updates = this.updates.bind(this);
129
442
  this.onSuccess = this.onSuccess.bind(this);
130
443
  this.onFailure = this.onFailure.bind(this);
131
444
  }
132
445
  run(sink) {
446
+ const subscribe = Effect.provide(this.core.subject.run(sink), this.core.services);
133
447
  return Effect.matchCauseEffect(getOrInitializeCore(this.core, true), {
134
- onFailure: (cause) => sink.onFailure(cause),
135
- onSuccess: () => Effect.provide(this.core.subject.run(sink), this.core.services),
448
+ onFailure: () => subscribe,
449
+ onSuccess: () => subscribe,
136
450
  });
137
451
  }
138
452
  updates(run) {
139
- return this.core.semaphore.withPermits(1)(run(this.getSetDelete));
453
+ return updateCore(this.core, (recordCommit) => run(getSetDelete(this.core, recordCommit)));
140
454
  }
141
455
  onSuccess(value) {
142
- return setCore(this.core, value);
456
+ return updateCore(this.core, (recordCommit) => bufferSuccessCore(this.core, value, recordCommit));
143
457
  }
144
458
  onFailure(cause) {
145
- return onFailureCore(this.core, cause);
459
+ return updateCore(this.core, (recordCommit) => bufferFailureCore(this.core, cause, recordCommit));
146
460
  }
147
461
  toEffect() {
148
462
  return getOrInitializeCore(this.core, true);
@@ -151,6 +465,31 @@ class RefSubjectImpl extends YieldableFx {
151
465
  /**
152
466
  * Creates a new `RefSubject` from a value, `Effect`, or `Fx`.
153
467
  *
468
+ * @remarks
469
+ * ## Why
470
+ *
471
+ * `RefSubject` keeps current state and pushed changes independent of any UI
472
+ * renderer. Domain transitions can therefore be constructed, composed, and
473
+ * tested with Effect alone; rendering is one optional consumer of the state.
474
+ * Plain values, Effect programs, pull-based Effect `Stream`s, and push-based
475
+ * `Fx` sources all enter through the same state boundary.
476
+ *
477
+ * ## Ownership and lifetime
478
+ *
479
+ * Creation requires an Effect `Scope`. That scope owns source acquisition,
480
+ * subscriptions, and finalization. The returned `RefSubject` exposes the
481
+ * source error type when read or observed, while construction itself cannot
482
+ * fail. Closing the scope interrupts a live source and releases its resources.
483
+ *
484
+ * ## Initialization
485
+ *
486
+ * Calling `make` is lazy because it returns an Effect: nothing is allocated and no source runs
487
+ * until that creation Effect is executed. After creation, a plain value is immediately available.
488
+ * An Effect input runs once on the first current read or observation. Fx and Stream inputs instead
489
+ * start one shared source run when the creation Effect executes; reads wait for their first value
490
+ * or failure and later emissions replace the retained current state. Equality and buffering
491
+ * behavior can be customized with `RefSubjectOptions`.
492
+ *
154
493
  * @example
155
494
  * ```ts
156
495
  * import { Effect } from "effect"
@@ -184,7 +523,7 @@ class RefSubjectImpl extends YieldableFx {
184
523
  * ```
185
524
  *
186
525
  * @since 1.0.0
187
- * @category constructors
526
+ * @category Constructors
188
527
  */
189
528
  export function make(effect, options) {
190
529
  if (isFx(effect)) {
@@ -203,6 +542,19 @@ export function make(effect, options) {
203
542
  /**
204
543
  * Creates a `RefSubject` from an `Effect`.
205
544
  *
545
+ * @remarks
546
+ * ## Why
547
+ *
548
+ * Makes effect acquisition explicit while normalizing it into current RefSubject state and
549
+ * subsequent pushed versions.
550
+ *
551
+ * ## Ownership and lifetime
552
+ *
553
+ * The creation Effect requires Scope and the source's services, which it captures for the private
554
+ * initializer Scope. The source Effect itself stays deferred until the first current read or
555
+ * observation and runs at most once. Source failures remain visible on reads and observations;
556
+ * closing the creation Scope interrupts an initializer that is still running.
557
+ *
206
558
  * @example
207
559
  * ```ts
208
560
  * import { Effect } from "effect"
@@ -219,7 +571,7 @@ export function make(effect, options) {
219
571
  * ```
220
572
  *
221
573
  * @since 1.0.0
222
- * @category constructors
574
+ * @category Source adapters
223
575
  */
224
576
  export function fromEffect(effect, options) {
225
577
  return Effect.map(makeCore(effect, options), (core) => new RefSubjectImpl(core));
@@ -227,6 +579,17 @@ export function fromEffect(effect, options) {
227
579
  /**
228
580
  * Creates a `RefSubject` from an `Fx`, tracking the latest emitted value.
229
581
  *
582
+ * @remarks
583
+ * ## Why
584
+ *
585
+ * Makes fx acquisition explicit while normalizing it into current RefSubject state and subsequent
586
+ * pushed versions.
587
+ *
588
+ * ## Ownership and lifetime
589
+ *
590
+ * The creation Effect requires Scope. It owns initializer acquisition, live source subscriptions,
591
+ * and cleanup; source failures and services stay on reads and pushes.
592
+ *
230
593
  * @example
231
594
  * ```ts
232
595
  * import { Effect } from "effect"
@@ -247,35 +610,136 @@ export function fromEffect(effect, options) {
247
610
  * ```
248
611
  *
249
612
  * @since 1.0.0
250
- * @category constructors
613
+ * @category Source adapters
251
614
  */
252
615
  export function fromFx(fx, options) {
253
616
  return Effect.gen(function* () {
254
617
  const core = yield* makeDeferredCore(options);
255
618
  const ref = new RefSubjectImpl(core);
256
- yield* Effect.forkIn(fx.run(Sink.make((cause) => onFailureCore(core, cause), (value) => setCore(core, value))), core.scope, { startImmediately: true });
619
+ yield* Effect.forkIn(fx.run(Sink.make((cause) => updateCore(core, (recordCommit) => bufferFailureCore(core, cause, recordCommit)), (value) => updateCore(core, (recordCommit) => bufferSuccessCore(core, value, recordCommit)))), core.scope, { startImmediately: true });
257
620
  return ref;
258
621
  });
259
622
  }
623
+ /**
624
+ * Creates a RefSubject that tracks the latest value emitted by an Effect Stream.
625
+ *
626
+ * @remarks
627
+ * ## Why
628
+ *
629
+ * Bridges a pull-based Stream into renderer-independent state: each emitted value enters the
630
+ * RefSubject's serialized commit path, while a stream failure becomes the ref's current and pushed
631
+ * failure.
632
+ *
633
+ * ## Ownership and lifetime
634
+ *
635
+ * Construction forks stream consumption immediately into the RefSubject's private Scope and cannot
636
+ * fail. `R` is required while constructing that fiber; closing the outer Scope interrupts it.
637
+ * Before the first value or failure, a current read waits for initialization. Later reads and pushes
638
+ * expose `E`.
639
+ *
640
+ * @since 1.18.0
641
+ * @category Source adapters
642
+ */
260
643
  export function fromStream(stream, options) {
261
644
  return Effect.gen(function* () {
262
645
  const core = yield* makeDeferredCore(options);
263
646
  const ref = new RefSubjectImpl(core);
264
- yield* Effect.forkIn(stream.pipe(redirectCause(core), Stream.runForEach((value) => setCore(core, value))), core.scope, { startImmediately: true });
647
+ yield* Effect.forkIn(stream.pipe(redirectCause(core), Stream.runForEach((value) => updateCore(core, (recordCommit) => bufferSuccessCore(core, value, recordCommit)))), core.scope, { startImmediately: true });
265
648
  return ref;
266
649
  });
267
650
  }
651
+ /**
652
+ * Creates a `RefSubject` from an `Option` value.
653
+ *
654
+ * @remarks
655
+ * ## Why
656
+ *
657
+ * Stores the Option itself in writable state. `None` is an ordinary current value and does not add
658
+ * `NoSuchElementError`; callers opt into absence semantics with `compact`, or a fallback with
659
+ * `getOrElse`.
660
+ *
661
+ * ## Ownership and lifetime
662
+ *
663
+ * Construction requires Scope because it delegates to `make`, but the supplied Option needs no
664
+ * services and cannot fail. The returned RefSubject owns and publishes subsequent Option writes.
665
+ *
666
+ * @example
667
+ * ```ts
668
+ * import { Effect, Option } from "effect"
669
+ * import * as RefSubject from "@typed/fx/RefSubject"
670
+ *
671
+ * const program = Effect.gen(function* () {
672
+ * const ref = yield* RefSubject.fromOption(Option.some(42))
673
+ * const value = yield* ref
674
+ * console.log(Option.isSome(value)) // true
675
+ * })
676
+ * ```
677
+ *
678
+ * @since 1.0.0
679
+ * @category Source adapters
680
+ */
681
+ export function fromOption(option, options) {
682
+ return make(option, options);
683
+ }
684
+ /**
685
+ * Creates a `RefSubject` from a nullable value (null/undefined become `Option.none()`).
686
+ *
687
+ * @example
688
+ * ```ts
689
+ * import { Effect, Option } from "effect"
690
+ * import * as RefSubject from "@typed/fx/RefSubject"
691
+ *
692
+ * const program = Effect.gen(function* () {
693
+ * const ref = yield* RefSubject.fromNullable("hello")
694
+ * const value = yield* ref
695
+ * console.log(Option.isSome(value)) // true
696
+ *
697
+ * const empty = yield* RefSubject.fromNullable(null)
698
+ * const none = yield* empty
699
+ * console.log(Option.isNone(none)) // true
700
+ * })
701
+ * ```
702
+ *
703
+ * @since 1.0.0
704
+ * @category Source adapters
705
+ */
706
+ function optionFromNullable(value) {
707
+ return value === null || value === undefined
708
+ ? Option.none()
709
+ : Option.some(value);
710
+ }
711
+ /**
712
+ * Creates Option-valued RefSubject state from a nullable input.
713
+ *
714
+ * @remarks
715
+ * ## Why
716
+ *
717
+ * Converts `null` and `undefined` to `Option.none` and every other value to `Option.some`, then
718
+ * stores that Option in a writable RefSubject. It does not create Filtered state or add
719
+ * `NoSuchElementError`.
720
+ *
721
+ * ## Ownership and lifetime
722
+ *
723
+ * Construction requires Scope because it delegates to `make`; it needs no services and cannot
724
+ * fail. The returned RefSubject owns and publishes subsequent Option writes.
725
+ *
726
+ * @since 1.18.0
727
+ * @category Source adapters
728
+ */
729
+ export function fromNullable(value, options) {
730
+ return make(optionFromNullable(value), options);
731
+ }
268
732
  function redirectCause(core) {
269
- return Stream.catchCause((cause) => Stream.unwrap(Effect.as(onFailureCore(core, cause), Stream.empty)));
733
+ return Stream.catchCause((cause) => Stream.unwrap(Effect.as(updateCore(core, (recordCommit) => bufferFailureCore(core, cause, recordCommit)), Stream.empty)));
270
734
  }
271
735
  function makeCore(initial, options, deferredRef) {
272
736
  return Effect.gen(function* () {
273
- const services = yield* Effect.services();
274
- const scope = yield* Scope.fork(ServiceMap.get(services, Scope.Scope));
737
+ const services = yield* Effect.context();
738
+ const scope = yield* Scope.fork(Context.get(services, Scope.Scope));
275
739
  const id = yield* Effect.withFiber((fiber) => Effect.succeed(fiber.id));
276
740
  const subject = new Subject.HoldSubjectImpl();
277
741
  const core = new RefSubjectCore(initial, subject, services, scope, deferredRef ??
278
- DeferredRef.unsafeMake(id, getExitEquivalence(options?.eq ?? equals), subject.lastValue), Effect.makeSemaphoreUnsafe(1));
742
+ DeferredRef.unsafeMake(id, getExitEquivalence(options?.eq ?? equals), subject.lastValue), Semaphore.makeUnsafe(1));
279
743
  yield* Scope.addFinalizer(scope, core.subject.interrupt);
280
744
  return core;
281
745
  });
@@ -283,7 +747,7 @@ function makeCore(initial, options, deferredRef) {
283
747
  function makeDeferredCore(options) {
284
748
  return Effect.gen(function* () {
285
749
  const deferredRef = yield* DeferredRef.make(getExitEquivalence(options?.eq ?? equals));
286
- return yield* makeCore(deferredRef.asEffect(), options, deferredRef);
750
+ return yield* makeCore(deferredRef, options, deferredRef);
287
751
  });
288
752
  }
289
753
  function getOrInitializeCore(core, lockInitialize) {
@@ -292,30 +756,51 @@ function getOrInitializeCore(core, lockInitialize) {
292
756
  return initializeCoreAndTap(core, lockInitialize);
293
757
  }
294
758
  else {
295
- return core.deferredRef.asEffect();
759
+ return core.deferredRef;
296
760
  }
297
761
  });
298
762
  }
299
763
  function initializeCoreEffect(core, lock) {
764
+ let completed = false;
300
765
  const initialize = Effect.onExit(Effect.provide(core.initial, core.services), (exit) => Effect.sync(() => {
766
+ completed = true;
301
767
  core._fiber = undefined;
302
768
  core.deferredRef.done(exit);
303
769
  }));
304
- return Effect.flatMap(Effect.forkIn(lock ? core.semaphore.withPermits(1)(initialize) : initialize, core.scope), (fiber) => Effect.sync(() => (core._fiber = fiber)));
770
+ const isSourceBacked = core.initial === core.deferredRef;
771
+ return Effect.flatMap(Effect.forkIn(lock && !isSourceBacked ? core.semaphore.withPermits(1)(initialize) : initialize, core.scope,
772
+ // Acquire the initializer's permit before a competing update can hold it while awaiting us.
773
+ { startImmediately: true }), (fiber) => Effect.sync(() => {
774
+ // A synchronous initializer has already cleared its ownership in onExit.
775
+ if (!completed)
776
+ core._fiber = fiber;
777
+ return fiber;
778
+ }));
305
779
  }
306
780
  function initializeCoreAndTap(core, lock) {
307
- return Effect.flatMapEager(initializeCoreEffect(core, lock), () => tapEventCore(core, core.deferredRef.asEffect()));
781
+ return Effect.flatMapEager(initializeCoreEffect(core, lock), () =>
782
+ // Kind of weird hack, but this second clause will happen for HydrationRefs that are already hydrated
783
+ core.deferredRef.current === core.subject.lastValue
784
+ ? tapEventCore(core, core.deferredRef)
785
+ : core.deferredRef);
786
+ }
787
+ function updateCore(core, run) {
788
+ return Effect.uninterruptibleMask((restore) => {
789
+ const commits = [];
790
+ const transaction = restore(core.semaphore.withPermits(1)(Effect.suspend(() => run((commit) => {
791
+ commits.push(commit);
792
+ }))));
793
+ return Effect.flatMap(Effect.exit(transaction), (exit) => Effect.andThen(Effect.forEach(commits, (commit) => sendEvent(core, commit), { discard: true }), exit));
794
+ });
308
795
  }
309
796
  function setCore(core, a) {
310
797
  return Effect.suspend(() => {
311
798
  const exit = Exit.succeed(a);
312
799
  if (core.deferredRef.done(exit)) {
313
- // If the value changed, send an event
314
- return Effect.as(sendEvent(core, exit), a);
800
+ return Effect.succeed(Option.some(exit));
315
801
  }
316
802
  else {
317
- // Otherwise, just return the current value
318
- return Effect.succeed(a);
803
+ return Effect.succeed(Option.none());
319
804
  }
320
805
  });
321
806
  }
@@ -323,13 +808,26 @@ function onFailureCore(core, cause) {
323
808
  const exit = Exit.failCause(cause);
324
809
  return Effect.suspend(() => {
325
810
  if (core.deferredRef.done(exit)) {
326
- return sendEvent(core, exit);
811
+ return Effect.succeed(Option.some(exit));
327
812
  }
328
813
  else {
329
- return Effect.void;
814
+ return Effect.succeed(Option.none());
330
815
  }
331
816
  });
332
817
  }
818
+ function bufferSuccessCore(core, value, recordCommit) {
819
+ return Effect.map(setCore(core, value), (commit) => {
820
+ if (Option.isSome(commit))
821
+ recordCommit(commit.value);
822
+ return value;
823
+ });
824
+ }
825
+ function bufferFailureCore(core, cause, recordCommit) {
826
+ return Effect.asVoid(Effect.map(onFailureCore(core, cause), (commit) => {
827
+ if (Option.isSome(commit))
828
+ recordCommit(commit.value);
829
+ }));
830
+ }
333
831
  function interruptCore(core) {
334
832
  return Effect.withFiber((fiber) => {
335
833
  core.deferredRef.reset();
@@ -363,6 +861,17 @@ function sendEvent(core, exit) {
363
861
  /**
364
862
  * Sets the value of a `RefSubject`.
365
863
  *
864
+ * @remarks
865
+ * ## Why
866
+ *
867
+ * Sets the value of a `RefSubject`. The transition is serialized at the RefSubject rather than
868
+ * coordinated by callers or UI components.
869
+ *
870
+ * ## Ownership and lifetime
871
+ *
872
+ * Running set performs one serialized subject transition and resolves with its committed value. It
873
+ * acquires no resource; failures and services remain those of the source ref.
874
+ *
366
875
  * @example
367
876
  * ```ts
368
877
  * import { Effect } from "effect"
@@ -384,7 +893,7 @@ function sendEvent(core, exit) {
384
893
  * ```
385
894
  *
386
895
  * @since 1.0.0
387
- * @category combinators
896
+ * @category State updates
388
897
  */
389
898
  export const set = dual(2, function set(ref, a) {
390
899
  return ref.updates((ref) => ref.set(a));
@@ -392,6 +901,17 @@ export const set = dual(2, function set(ref, a) {
392
901
  /**
393
902
  * Resets a `RefSubject` to its initial value, returning the previous value if it existed.
394
903
  *
904
+ * @remarks
905
+ * ## Why
906
+ *
907
+ * Resets a `RefSubject` to its initial value, returning the previous value if it existed. The
908
+ * transition is serialized at the RefSubject rather than coordinated by callers or UI components.
909
+ *
910
+ * ## Ownership and lifetime
911
+ *
912
+ * Running reset performs one serialized subject transition and resolves with its committed value.
913
+ * It acquires no resource; failures and services remain those of the source ref.
914
+ *
395
915
  * @example
396
916
  * ```ts
397
917
  * import { Effect, Option } from "effect"
@@ -415,7 +935,7 @@ export const set = dual(2, function set(ref, a) {
415
935
  * ```
416
936
  *
417
937
  * @since 1.0.0
418
- * @category combinators
938
+ * @category State updates
419
939
  */
420
940
  export function reset(ref) {
421
941
  return ref.updates((ref) => ref.delete);
@@ -445,12 +965,23 @@ export {
445
965
  * ```
446
966
  *
447
967
  * @since 1.20.0
448
- * @category combinators
968
+ * @category State updates
449
969
  */
450
970
  reset as delete, };
451
971
  /**
452
972
  * Updates a `RefSubject` using an `Effect`ful function.
453
973
  *
974
+ * @remarks
975
+ * ## Why
976
+ *
977
+ * Updates a `RefSubject` using an `Effect`ful function. The transition is serialized at the
978
+ * RefSubject rather than coordinated by callers or UI components.
979
+ *
980
+ * ## Ownership and lifetime
981
+ *
982
+ * Running update effect performs one serialized subject transition and resolves with its committed
983
+ * value. It acquires no resource; failures and services remain those of the source ref.
984
+ *
454
985
  * @example
455
986
  * ```ts
456
987
  * import { Effect } from "effect"
@@ -470,7 +1001,7 @@ reset as delete, };
470
1001
  * ```
471
1002
  *
472
1003
  * @since 1.0.0
473
- * @category combinators
1004
+ * @category State updates
474
1005
  */
475
1006
  export const updateEffect = dual(2, function updateEffect(ref, f) {
476
1007
  return ref.updates((ref) => Effect.flatMap(Effect.flatMap(ref.get, f), ref.set));
@@ -478,6 +1009,26 @@ export const updateEffect = dual(2, function updateEffect(ref, f) {
478
1009
  /**
479
1010
  * Updates a `RefSubject` using a pure function.
480
1011
  *
1012
+ * @remarks
1013
+ * ## Why
1014
+ *
1015
+ * `update` expresses a state transition where the state lives, without moving
1016
+ * transition logic into a component or renderer. The same function can run in
1017
+ * application code, tests, workers, event handlers, or a Typed template.
1018
+ *
1019
+ * ## Ownership and lifetime
1020
+ *
1021
+ * The update runs inside the RefSubject's existing synchronized update
1022
+ * boundary: it reads the committed value, derives the next value, commits it,
1023
+ * and publishes that change. It acquires no independent resource and retains
1024
+ * the subject's existing error and service channels.
1025
+ *
1026
+ * ## Concurrency and failure
1027
+ *
1028
+ * Concurrent updates are serialized by the subject core so each function sees
1029
+ * a committed value. A pure updater adds no error channel; failures already
1030
+ * associated with reading or writing the RefSubject remain explicit in `E`.
1031
+ *
481
1032
  * @example
482
1033
  * ```ts
483
1034
  * import { Effect } from "effect"
@@ -499,7 +1050,7 @@ export const updateEffect = dual(2, function updateEffect(ref, f) {
499
1050
  * ```
500
1051
  *
501
1052
  * @since 1.0.0
502
- * @category combinators
1053
+ * @category State updates
503
1054
  */
504
1055
  export const update = dual(2, function update(ref, f) {
505
1056
  return updateEffect(ref, (value) => Effect.succeed(f(value)));
@@ -507,6 +1058,18 @@ export const update = dual(2, function update(ref, f) {
507
1058
  /**
508
1059
  * Modifies a `RefSubject` using an `Effect`ful function that returns both a result and a new value.
509
1060
  *
1061
+ * @remarks
1062
+ * ## Why
1063
+ *
1064
+ * Modifies a `RefSubject` using an `Effect`ful function that returns both a result and a new
1065
+ * value. The transition is serialized at the RefSubject rather than coordinated by callers or UI
1066
+ * components.
1067
+ *
1068
+ * ## Ownership and lifetime
1069
+ *
1070
+ * Running modify effect performs one serialized subject transition and resolves with its committed
1071
+ * value. It acquires no resource; failures and services remain those of the source ref.
1072
+ *
510
1073
  * @example
511
1074
  * ```ts
512
1075
  * import { Effect } from "effect"
@@ -527,14 +1090,25 @@ export const update = dual(2, function update(ref, f) {
527
1090
  * ```
528
1091
  *
529
1092
  * @since 1.0.0
530
- * @category combinators
1093
+ * @category Transactions
531
1094
  */
532
1095
  export const modifyEffect = dual(2, function modifyEffect(ref, f) {
533
- return ref.updates((ref) => Effect.flatMap(ref.get, (value) => Effect.flatMap(f(value), ([b, a]) => Effect.flatMap(ref.set(a), () => Effect.succeed(b)))));
1096
+ return ref.updates((ref) => Effect.flatMap(ref.get, (value) => Effect.flatMap(f(value), ([b, a]) => Effect.as(ref.set(a), b))));
534
1097
  });
535
1098
  /**
536
1099
  * Modifies a `RefSubject` using a pure function that returns both a result and a new value.
537
1100
  *
1101
+ * @remarks
1102
+ * ## Why
1103
+ *
1104
+ * Modifies a `RefSubject` using a pure function that returns both a result and a new value. The
1105
+ * transition is serialized at the RefSubject rather than coordinated by callers or UI components.
1106
+ *
1107
+ * ## Ownership and lifetime
1108
+ *
1109
+ * Running modify performs one serialized subject transition and resolves with its committed value.
1110
+ * It acquires no resource; failures and services remain those of the source ref.
1111
+ *
538
1112
  * @example
539
1113
  * ```ts
540
1114
  * import { Effect } from "effect"
@@ -553,7 +1127,7 @@ export const modifyEffect = dual(2, function modifyEffect(ref, f) {
553
1127
  * ```
554
1128
  *
555
1129
  * @since 1.0.0
556
- * @category combinators
1130
+ * @category Transactions
557
1131
  */
558
1132
  export const modify = dual(2, function modify(ref, f) {
559
1133
  return modifyEffect(ref, (value) => Effect.succeed(f(value)));
@@ -561,6 +1135,16 @@ export const modify = dual(2, function modify(ref, f) {
561
1135
  /**
562
1136
  * Checks if a value is a `RefSubject`.
563
1137
  *
1138
+ * @remarks
1139
+ * ## Why
1140
+ *
1141
+ * Checks if a value is a `RefSubject`.
1142
+ *
1143
+ * ## Ownership and lifetime
1144
+ *
1145
+ * The derived ref owns no independent state or subscription. It follows the source lifetime and
1146
+ * routes writes through the source's synchronized update boundary.
1147
+ *
564
1148
  * @example
565
1149
  * ```ts
566
1150
  * import { Effect } from "effect"
@@ -578,14 +1162,45 @@ export const modify = dual(2, function modify(ref, f) {
578
1162
  * ```
579
1163
  *
580
1164
  * @since 1.0.0
581
- * @category guards
1165
+ * @category Type guards
582
1166
  */
583
1167
  export function isRefSubject(value) {
584
- return value && typeof value === "object" && value[RefSubjectTypeId] === RefSubjectTypeId;
1168
+ return hasProperty(value, RefSubjectTypeId) && value[RefSubjectTypeId] === RefSubjectTypeId;
585
1169
  }
586
1170
  const isRefSubjectDataFirst = (args) => isRefSubject(args[0]);
587
1171
  /**
1172
+ * Tests whether a value carries the public Computed TypeId.
1173
+ *
1174
+ * @remarks
1175
+ * ## Why
1176
+ *
1177
+ * Uses the TypeId contract rather than a concrete implementation class, so custom Computed values
1178
+ * and service facades participate in the same runtime guard.
1179
+ *
1180
+ * ## Ownership and lifetime
1181
+ *
1182
+ * This synchronous predicate performs no Effect, subscription, or acquisition.
1183
+ *
1184
+ * @since 1.18.0
1185
+ * @category Type guards
1186
+ */
1187
+ export function isComputed(value) {
1188
+ return hasProperty(value, ComputedTypeId) && value[ComputedTypeId] === ComputedTypeId;
1189
+ }
1190
+ /**
1191
+ * Runs an effect that can modify a `RefSubject` transactionally, with optional interrupt handling.
1192
+ *
1193
+ * @remarks
1194
+ * ## Why
1195
+ *
588
1196
  * Runs an effect that can modify a `RefSubject` transactionally, with optional interrupt handling.
1197
+ * The transition is serialized at the RefSubject rather than coordinated by callers or UI
1198
+ * components.
1199
+ *
1200
+ * ## Ownership and lifetime
1201
+ *
1202
+ * Running run updates performs one serialized subject transition and resolves with its committed
1203
+ * value. It acquires no resource; failures and services remain those of the source ref.
589
1204
  *
590
1205
  * @example
591
1206
  * ```ts
@@ -616,7 +1231,7 @@ const isRefSubjectDataFirst = (args) => isRefSubject(args[0]);
616
1231
  * ```
617
1232
  *
618
1233
  * @since 1.0.0
619
- * @category combinators
1234
+ * @category Transactions
620
1235
  */
621
1236
  export const runUpdates = dual(isRefSubjectDataFirst, function runUpdates(ref, f, options) {
622
1237
  if (options === undefined) {
@@ -632,6 +1247,17 @@ export const runUpdates = dual(isRefSubjectDataFirst, function runUpdates(ref, f
632
1247
  /**
633
1248
  * Increments a numeric `RefSubject` by 1.
634
1249
  *
1250
+ * @remarks
1251
+ * ## Why
1252
+ *
1253
+ * Increments a numeric `RefSubject` by 1. The transition is serialized at the RefSubject rather
1254
+ * than coordinated by callers or UI components.
1255
+ *
1256
+ * ## Ownership and lifetime
1257
+ *
1258
+ * Running increment performs one serialized subject transition and resolves with its committed
1259
+ * value. It acquires no resource; failures and services remain those of the source ref.
1260
+ *
635
1261
  * @example
636
1262
  * ```ts
637
1263
  * import { Effect } from "effect"
@@ -651,7 +1277,7 @@ export const runUpdates = dual(isRefSubjectDataFirst, function runUpdates(ref, f
651
1277
  * ```
652
1278
  *
653
1279
  * @since 1.0.0
654
- * @category combinators
1280
+ * @category State updates
655
1281
  */
656
1282
  export function increment(ref) {
657
1283
  return update(ref, (value) => value + 1);
@@ -659,6 +1285,17 @@ export function increment(ref) {
659
1285
  /**
660
1286
  * Decrements a numeric `RefSubject` by 1.
661
1287
  *
1288
+ * @remarks
1289
+ * ## Why
1290
+ *
1291
+ * Decrements a numeric `RefSubject` by 1. The transition is serialized at the RefSubject rather
1292
+ * than coordinated by callers or UI components.
1293
+ *
1294
+ * ## Ownership and lifetime
1295
+ *
1296
+ * Running decrement performs one serialized subject transition and resolves with its committed
1297
+ * value. It acquires no resource; failures and services remain those of the source ref.
1298
+ *
662
1299
  * @example
663
1300
  * ```ts
664
1301
  * import { Effect } from "effect"
@@ -678,7 +1315,7 @@ export function increment(ref) {
678
1315
  * ```
679
1316
  *
680
1317
  * @since 1.0.0
681
- * @category combinators
1318
+ * @category State updates
682
1319
  */
683
1320
  export function decrement(ref) {
684
1321
  return update(ref, (value) => value - 1);
@@ -688,12 +1325,42 @@ const Variance = {
688
1325
  _E: identity,
689
1326
  _R: identity,
690
1327
  };
1328
+ /**
1329
+ * Creates a Context-backed RefSubject service facade and Layer constructors.
1330
+ *
1331
+ * @remarks
1332
+ * ## Why
1333
+ *
1334
+ * The returned class is simultaneously a service tag, a current-value Effect, an Fx source, and a
1335
+ * writable RefSubject facade. This lets consumers read, observe, and update renderer-independent
1336
+ * state without manually retrieving the underlying service from Context.
1337
+ *
1338
+ * ## Ownership and lifetime
1339
+ *
1340
+ * Calling `Service` is pure. `layer` installs an existing scoped RefSubject; `make` constructs one
1341
+ * and installs it in a Layer. The Layer Scope owns the subject and its initializer subscription.
1342
+ * Reads and pushes expose the declared `E` channel; construction requirements remain on the Layer,
1343
+ * while consumers require only the generated `Self` service.
1344
+ *
1345
+ * @since 1.18.0
1346
+ * @category Services
1347
+ */
691
1348
  export function Service() {
692
1349
  return (id) => {
693
- const service = ServiceMap.Service(id);
1350
+ const service = Context.Service(id);
694
1351
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
695
1352
  return class RefSubjectService {
696
1353
  /// Service
1354
+ static {
1355
+ // @effect-diagnostics-next-line floatingEffect:off
1356
+ Object.assign(this, service);
1357
+ Object.setPrototypeOf(this, Object.getPrototypeOf(service));
1358
+ // @effect-diagnostics-next-line floatingEffect:off
1359
+ Object.assign(this, Effectable.Prototype({
1360
+ label: "RefSubject.Service",
1361
+ evaluate: () => Effect.flatMap(service, identity),
1362
+ }));
1363
+ }
697
1364
  static id = id;
698
1365
  static service = service;
699
1366
  static layer = (make) => Layer.effect(service, make);
@@ -703,21 +1370,21 @@ export function Service() {
703
1370
  };
704
1371
  // Fx
705
1372
  static [FxTypeId] = Variance;
706
- static run = (sink) => Effect.flatMap(service.asEffect(), (ref) => ref.run(sink));
1373
+ static run = (sink) => Effect.flatMap(service, (ref) => ref.run(sink));
707
1374
  // Sink
708
- static onSuccess = (value) => Effect.flatMap(service.asEffect(), (ref) => ref.onSuccess(value));
709
- static onFailure = (cause) => Effect.flatMap(service.asEffect(), (ref) => ref.onFailure(cause));
1375
+ static onSuccess = (value) => Effect.flatMap(service, (ref) => ref.onSuccess(value));
1376
+ static onFailure = (cause) => Effect.flatMap(service, (ref) => ref.onFailure(cause));
710
1377
  /// Computed
711
1378
  static [ComputedTypeId] = ComputedTypeId;
712
- static version = Effect.flatMap(service.asEffect(), (ref) => ref.version);
1379
+ static version = Effect.flatMap(service, (ref) => ref.version);
713
1380
  // Subject
714
- static subscriberCount = Effect.flatMap(service.asEffect(), (ref) => ref.subscriberCount);
715
- static interrupt = Effect.flatMap(service.asEffect(), (ref) => ref.interrupt);
1381
+ static subscriberCount = Effect.flatMap(service, (ref) => ref.subscriberCount);
1382
+ static interrupt = Effect.flatMap(service, (ref) => ref.interrupt);
716
1383
  // RefSubject
717
1384
  static [RefSubjectTypeId] = RefSubjectTypeId;
718
- static updates = (f) => Effect.flatMap(service.asEffect(), (ref) => ref.updates(f));
1385
+ static updates = (f) => Effect.flatMap(service, (ref) => ref.updates(f));
719
1386
  // Yieldable
720
- static asEffect = () => Effect.flatMap(service.asEffect(), Effect.fromYieldable);
1387
+ static override = Effect.flatten(service);
721
1388
  static [Symbol.iterator] = function* () {
722
1389
  const ref = yield* service;
723
1390
  return yield* ref;
@@ -741,6 +1408,19 @@ function getDefaultBounds(options) {
741
1408
  * Extract all values from an object using a Proxy.
742
1409
  * Allows accessing nested properties of a `Computed` or `Filtered` object/array as individual computed values.
743
1410
  *
1411
+ * @remarks
1412
+ * ## Why
1413
+ *
1414
+ * Lazily creates one property projection per accessed key and memoizes that projection on the
1415
+ * JavaScript Proxy. A Computed or RefSubject source produces Computed properties; only a Filtered
1416
+ * source produces Filtered properties and preserves conditional absence.
1417
+ *
1418
+ * ## Ownership and lifetime
1419
+ *
1420
+ * The Proxy caches derived view objects, not property values. Computed property reads expose only
1421
+ * the source's `E`; Filtered property reads can additionally fail with `NoSuchElementError` while
1422
+ * their source is absent. Each observed property follows the source and uses the observing Scope.
1423
+ *
744
1424
  * @example
745
1425
  * ```ts
746
1426
  * import { Effect } from "effect"
@@ -769,7 +1449,7 @@ function getDefaultBounds(options) {
769
1449
  * ```
770
1450
  *
771
1451
  * @since 2.0.0
772
- * @category combinators
1452
+ * @category Derived queries
773
1453
  */
774
1454
  export const proxy = (source) => {
775
1455
  const target = {};
@@ -784,6 +1464,20 @@ export const proxy = (source) => {
784
1464
  /**
785
1465
  * Transforms a `RefSubject`, `Computed`, or `Filtered` using an `Effect`ful function.
786
1466
  *
1467
+ * @remarks
1468
+ * ## Why
1469
+ *
1470
+ * Applies one Effectful derivation to current reads and pushed versions. RefSubject and Computed
1471
+ * inputs return Computed and add only `E2`; a Filtered input returns Filtered and preserves its
1472
+ * conditional absence in addition to `E2`.
1473
+ *
1474
+ * ## Ownership and lifetime
1475
+ *
1476
+ * No callback runs until the result is read or observed. Computed results cannot become absent and
1477
+ * do not add `NoSuchElementError`; only the Filtered overload can fail a current read for absence.
1478
+ * Callback services and failures remain `R2` and `E2`, and the observing Scope owns subscription
1479
+ * cleanup.
1480
+ *
787
1481
  * @example
788
1482
  * ```ts
789
1483
  * import { Effect } from "effect"
@@ -810,7 +1504,7 @@ export const proxy = (source) => {
810
1504
  * ```
811
1505
  *
812
1506
  * @since 1.0.0
813
- * @category combinators
1507
+ * @category Derived queries
814
1508
  */
815
1509
  export const mapEffect = dual(2, function mapEffect(versioned, f) {
816
1510
  return FilteredTypeId in versioned
@@ -820,6 +1514,25 @@ export const mapEffect = dual(2, function mapEffect(versioned, f) {
820
1514
  /**
821
1515
  * Transforms a `RefSubject`, `Computed`, or `Filtered` using a pure function.
822
1516
  *
1517
+ * @remarks
1518
+ * ## Why
1519
+ *
1520
+ * `map` creates derived state instead of copying source state into a component.
1521
+ * Reads and pushed updates remain connected to the original `Versioned` value,
1522
+ * so a projection can be tested without rendering and consumed by any renderer.
1523
+ *
1524
+ * ## Ownership and lifetime
1525
+ *
1526
+ * The returned `Computed` or `Filtered` view does not take ownership of the
1527
+ * source. It follows the source lifetime and preserves its error and service
1528
+ * channels. The pure mapping function adds neither resources nor failures.
1529
+ *
1530
+ * ## Re-computation
1531
+ *
1532
+ * The mapping function runs for the current value and subsequent committed
1533
+ * source versions. Updates still occur on the writable source; the derived view
1534
+ * is read-only unless a more specific bidirectional combinator is used.
1535
+ *
823
1536
  * @example
824
1537
  * ```ts
825
1538
  * import { Effect } from "effect"
@@ -844,7 +1557,7 @@ export const mapEffect = dual(2, function mapEffect(versioned, f) {
844
1557
  * ```
845
1558
  *
846
1559
  * @since 1.0.0
847
- * @category combinators
1560
+ * @category Derived queries
848
1561
  */
849
1562
  export const map = dual(2, function map(versioned, f) {
850
1563
  return mapEffect(versioned, (a) => Effect.succeed(f(a)));
@@ -852,6 +1565,18 @@ export const map = dual(2, function map(versioned, f) {
852
1565
  /**
853
1566
  * Filters and transforms a `RefSubject`, `Computed`, or `Filtered` using an `Effect`ful function that returns an `Option`.
854
1567
  *
1568
+ * @remarks
1569
+ * ## Why
1570
+ *
1571
+ * Filters and transforms a `RefSubject`, `Computed`, or `Filtered` using an `Effect`ful function
1572
+ * that returns an `Option`. Current reads and pushed versions use the same derivation, preventing
1573
+ * snapshot and subscription behavior from diverging.
1574
+ *
1575
+ * ## Ownership and lifetime
1576
+ *
1577
+ * The filter map effect view retains no independent value. Its Effect read fails with NoSuchElement
1578
+ * while absent; the observing Scope owns and finalizes its Fx subscription.
1579
+ *
855
1580
  * @example
856
1581
  * ```ts
857
1582
  * import { Effect, Option } from "effect"
@@ -871,7 +1596,7 @@ export const map = dual(2, function map(versioned, f) {
871
1596
  * ```
872
1597
  *
873
1598
  * @since 1.0.0
874
- * @category combinators
1599
+ * @category Optional queries
875
1600
  */
876
1601
  export const filterMapEffect = dual(2, function filterMapEffect(versioned, f) {
877
1602
  return new FilteredImpl(versioned, f);
@@ -879,6 +1604,18 @@ export const filterMapEffect = dual(2, function filterMapEffect(versioned, f) {
879
1604
  /**
880
1605
  * Filters and transforms a `RefSubject`, `Computed`, or `Filtered` using a pure function that returns an `Option`.
881
1606
  *
1607
+ * @remarks
1608
+ * ## Why
1609
+ *
1610
+ * Filters and transforms a `RefSubject`, `Computed`, or `Filtered` using a pure function that
1611
+ * returns an `Option`. Current reads and pushed versions use the same derivation, preventing
1612
+ * snapshot and subscription behavior from diverging.
1613
+ *
1614
+ * ## Ownership and lifetime
1615
+ *
1616
+ * The filter map view retains no independent value. Its Effect read fails with NoSuchElement
1617
+ * while absent; the observing Scope owns and finalizes its Fx subscription.
1618
+ *
882
1619
  * @example
883
1620
  * ```ts
884
1621
  * import { Effect, Option } from "effect"
@@ -898,7 +1635,7 @@ export const filterMapEffect = dual(2, function filterMapEffect(versioned, f) {
898
1635
  * ```
899
1636
  *
900
1637
  * @since 1.0.0
901
- * @category combinators
1638
+ * @category Optional queries
902
1639
  */
903
1640
  export const filterMap = dual(2, function filterMap(versioned, f) {
904
1641
  return new FilteredImpl(versioned, (a) => Effect.succeed(f(a)));
@@ -906,6 +1643,18 @@ export const filterMap = dual(2, function filterMap(versioned, f) {
906
1643
  /**
907
1644
  * Converts a `Computed` or `Filtered` of `Option<A>` into a `Filtered<A>`, filtering out `None` values.
908
1645
  *
1646
+ * @remarks
1647
+ * ## Why
1648
+ *
1649
+ * Converts a `Computed` or `Filtered` of `Option<A>` into a `Filtered<A>`, filtering out `None`
1650
+ * values. Current reads and pushed versions use the same derivation, preventing snapshot and
1651
+ * subscription behavior from diverging.
1652
+ *
1653
+ * ## Ownership and lifetime
1654
+ *
1655
+ * The compact view retains no independent value. Its Effect read fails with NoSuchElement
1656
+ * while absent; the observing Scope owns and finalizes its Fx subscription.
1657
+ *
909
1658
  * @example
910
1659
  * ```ts
911
1660
  * import { Effect, Option } from "effect"
@@ -927,11 +1676,52 @@ export const filterMap = dual(2, function filterMap(versioned, f) {
927
1676
  * ```
928
1677
  *
929
1678
  * @since 1.0.0
930
- * @category combinators
1679
+ * @category Optional queries
931
1680
  */
932
1681
  export const compact = function compact(versioned) {
933
1682
  return new FilteredImpl(versioned, Effect.succeed);
934
1683
  };
1684
+ /**
1685
+ * Returns a `Computed` that yields the value inside the `Option`, or the fallback when `None`.
1686
+ * Works with `Computed<Option<A>>` (e.g. from `fromOption` / `fromNullable`) and with `Filtered<A>`.
1687
+ *
1688
+ * @remarks
1689
+ * ## Why
1690
+ *
1691
+ * Returns a `Computed` that yields the value inside the `Option`, or the fallback when `None`.
1692
+ * Works with `Computed<Option<A>>` (e.g. from `fromOption` / `fromNullable`) and with
1693
+ * `Filtered<A>`. Current reads and pushed versions use the same derivation, preventing snapshot
1694
+ * and subscription behavior from diverging.
1695
+ *
1696
+ * ## Ownership and lifetime
1697
+ *
1698
+ * The returned Computed never fails for absence: `None` or an absent Filtered value invokes
1699
+ * `fallback`. It preserves only the input's declared `E` and `R`; the pure fallback adds no failure,
1700
+ * service, subscription, or retained value.
1701
+ *
1702
+ * @example
1703
+ * ```ts
1704
+ * import { Effect, Option } from "effect"
1705
+ * import * as RefSubject from "@typed/fx/RefSubject"
1706
+ *
1707
+ * const program = Effect.gen(function* () {
1708
+ * const ref = yield* RefSubject.fromOption(Option.some(42))
1709
+ * const withDefault = RefSubject.getOrElse(ref, () => 0)
1710
+ * expect(yield* withDefault).toBe(42)
1711
+ *
1712
+ * const empty = yield* RefSubject.fromNullable(null)
1713
+ * const fallback = RefSubject.getOrElse(empty, () => 99)
1714
+ * expect(yield* fallback).toBe(99)
1715
+ * })
1716
+ * ```
1717
+ *
1718
+ * @since 1.0.0
1719
+ * @category Optional queries
1720
+ */
1721
+ export const getOrElse = dual(2, function getOrElse(ref, fallback) {
1722
+ const computed = FilteredTypeId in ref ? ref.asComputed() : ref;
1723
+ return map(computed, (opt) => Option.getOrElse(opt, fallback));
1724
+ });
935
1725
  class RefSubjectSimpleTransform extends YieldableFx {
936
1726
  [ComputedTypeId] = ComputedTypeId;
937
1727
  [RefSubjectTypeId] = RefSubjectTypeId;
@@ -956,7 +1746,7 @@ class RefSubjectSimpleTransform extends YieldableFx {
956
1746
  return this._fx.run(sink);
957
1747
  }
958
1748
  toEffect() {
959
- return this.transformEffect(this.ref.asEffect());
1749
+ return this.transformEffect(this.ref);
960
1750
  }
961
1751
  updates(run) {
962
1752
  return this.ref.updates(run);
@@ -968,6 +1758,25 @@ class RefSubjectSimpleTransform extends YieldableFx {
968
1758
  return this.ref.onSuccess(value);
969
1759
  }
970
1760
  }
1761
+ /**
1762
+ * Limits which pushed versions a RefSubject view observes without changing its state.
1763
+ *
1764
+ * @remarks
1765
+ * ## Why
1766
+ *
1767
+ * Applies `skip` and `take` only to the Fx observation channel. Current reads still sample the
1768
+ * underlying RefSubject directly, and writes still use its original serialized update boundary.
1769
+ *
1770
+ * ## Ownership and lifetime
1771
+ *
1772
+ * Creating the view starts nothing and retains no value. Each observation uses its Scope and ends
1773
+ * after `take` selected pushes; ending that observation does not interrupt or delete the source.
1774
+ * Version, interruption, subscriber count, reads, failures, services, and writes delegate to the
1775
+ * source RefSubject.
1776
+ *
1777
+ * @since 1.18.0
1778
+ * @category Observation policy
1779
+ */
971
1780
  export const slice = dual(3, function slice(ref, skip, take) {
972
1781
  return new RefSubjectSimpleTransform(ref, (_) => fxSlice(_, { skip, take }), identity);
973
1782
  });
@@ -995,7 +1804,7 @@ class RefSubjectTransform extends YieldableFx {
995
1804
  return this._fx.run(sink);
996
1805
  }
997
1806
  toEffect() {
998
- return Effect.map(this.ref.asEffect(), this.toB);
1807
+ return Effect.map(this.ref, this.toB);
999
1808
  }
1000
1809
  updates(run) {
1001
1810
  return this.ref.updates((innerRef) => {
@@ -1017,6 +1826,17 @@ class RefSubjectTransform extends YieldableFx {
1017
1826
  /**
1018
1827
  * Transforms a `RefSubject` invariantly using bidirectional mapping functions.
1019
1828
  *
1829
+ * @remarks
1830
+ * ## Why
1831
+ *
1832
+ * Creates a bidirectional lens over state: reads map outward and writes map back to the original
1833
+ * RefSubject without allocating a second store.
1834
+ *
1835
+ * ## Ownership and lifetime
1836
+ *
1837
+ * The derived ref owns no independent state or subscription. It follows the source lifetime and
1838
+ * routes writes through the source's synchronized update boundary.
1839
+ *
1020
1840
  * @example
1021
1841
  * ```ts
1022
1842
  * import { Effect } from "effect"
@@ -1045,7 +1865,7 @@ class RefSubjectTransform extends YieldableFx {
1045
1865
  * ```
1046
1866
  *
1047
1867
  * @since 1.0.0
1048
- * @category combinators
1868
+ * @category Writable views
1049
1869
  */
1050
1870
  export const transform = dual(3, function transform(ref, toB, toA) {
1051
1871
  return new RefSubjectTransform(ref, toB, toA);
@@ -1077,6 +1897,17 @@ function getRefKind(refs) {
1077
1897
  /**
1078
1898
  * Combines multiple `RefSubject`, `Computed`, or `Filtered` instances into a single struct.
1079
1899
  *
1900
+ * @remarks
1901
+ * ## Why
1902
+ *
1903
+ * Combines several refs into one state value while preserving whether the result is writable,
1904
+ * computed, or filtered from its inputs.
1905
+ *
1906
+ * ## Ownership and lifetime
1907
+ *
1908
+ * This declaration performs no acquisition and retains no resources. Implementations preserve
1909
+ * source errors, services, and lifetime.
1910
+ *
1080
1911
  * @example
1081
1912
  * ```ts
1082
1913
  * import { Effect } from "effect"
@@ -1107,7 +1938,7 @@ function getRefKind(refs) {
1107
1938
  * ```
1108
1939
  *
1109
1940
  * @since 1.0.0
1110
- * @category combinators
1941
+ * @category State composition
1111
1942
  */
1112
1943
  export function struct(refs) {
1113
1944
  const kind = getRefKind(Object.values(refs));
@@ -1123,6 +1954,17 @@ export function struct(refs) {
1123
1954
  /**
1124
1955
  * Combines multiple `RefSubject`, `Computed`, or `Filtered` instances into a single tuple.
1125
1956
  *
1957
+ * @remarks
1958
+ * ## Why
1959
+ *
1960
+ * Combines several refs into one state value while preserving whether the result is writable,
1961
+ * computed, or filtered from its inputs.
1962
+ *
1963
+ * ## Ownership and lifetime
1964
+ *
1965
+ * This declaration performs no acquisition and retains no resources. Implementations preserve
1966
+ * source errors, services, and lifetime.
1967
+ *
1126
1968
  * @example
1127
1969
  * ```ts
1128
1970
  * import { Effect } from "effect"
@@ -1149,7 +1991,7 @@ export function struct(refs) {
1149
1991
  * ```
1150
1992
  *
1151
1993
  * @since 1.0.0
1152
- * @category combinators
1994
+ * @category State composition
1153
1995
  */
1154
1996
  export function tuple(refs) {
1155
1997
  const kind = getRefKind(refs);
@@ -1166,6 +2008,38 @@ function makeTupleRef(refs) {
1166
2008
  return new RefSubjectTuple(refs);
1167
2009
  }
1168
2010
  const UNBOUNDED = { concurrency: "unbounded" };
2011
+ const sampleRefSubject = (ref) =>
2012
+ // @effect-diagnostics-next-line unnecessaryEffectGen:off
2013
+ Effect.gen(function* () {
2014
+ return yield* ref;
2015
+ });
2016
+ function versionedInContext(make) {
2017
+ // Automatic composites share both pushed sessions and in-flight reads only within one Context.
2018
+ const contexts = new WeakMap();
2019
+ const current = Effect.map(Effect.context(), (context) => {
2020
+ let versioned = contexts.get(context);
2021
+ if (!versioned) {
2022
+ versioned = make();
2023
+ contexts.set(context, versioned);
2024
+ }
2025
+ return versioned;
2026
+ });
2027
+ return new (class extends YieldableFx {
2028
+ version = Effect.flatMap(current, (versioned) => versioned.version);
2029
+ interrupt = Effect.flatMap(current, (versioned) => versioned.interrupt);
2030
+ run(sink) {
2031
+ return Effect.flatMap(current, (versioned) => versioned.run(sink));
2032
+ }
2033
+ toEffect() {
2034
+ return Effect.flatMap(current, identity);
2035
+ }
2036
+ })();
2037
+ }
2038
+ function makeCompositeVersioned(refs, current) {
2039
+ const version = Effect.map(Effect.all(refs.map((ref) => ref.version), UNBOUNDED), (versions) => versions.reduce(sum, 0));
2040
+ const changes = skipRepeats(fxMapEffect(fxMergeAll(...refs), () => current));
2041
+ return versionedInContext(() => Versioned.hold(Versioned.make(version, changes, current)));
2042
+ }
1169
2043
  class RefSubjectTuple extends YieldableFx {
1170
2044
  [ComputedTypeId] = ComputedTypeId;
1171
2045
  [RefSubjectTypeId] = RefSubjectTypeId;
@@ -1178,12 +2052,14 @@ class RefSubjectTuple extends YieldableFx {
1178
2052
  constructor(refs) {
1179
2053
  super();
1180
2054
  this.refs = refs;
1181
- this.versioned = Versioned.hold(Versioned.tuple(refs));
2055
+ this.versioned = (refs.length > 0 && getTupleTransactionAccess(refs)
2056
+ ? makeCompositeVersioned(refs, Effect.all(refs.map(sampleRefSubject), UNBOUNDED))
2057
+ : versionedInContext(() => Versioned.hold(Versioned.tuple(refs))));
1182
2058
  this.version = this.versioned.version;
1183
2059
  this.interrupt = Effect.all(refs.map((r) => r.interrupt), UNBOUNDED);
1184
2060
  this.subscriberCount = Effect.map(Effect.all(refs.map((r) => r.subscriberCount), UNBOUNDED), Array.reduce(0, sum));
1185
2061
  this.getSetDelete = {
1186
- get: this.versioned.asEffect(),
2062
+ get: this.versioned,
1187
2063
  set: (a) => Effect.all(refs.map((r, i) => set(r, a[i])), UNBOUNDED),
1188
2064
  delete: Effect.map(Effect.all(refs.map((r) => reset(r)), UNBOUNDED), Option.all),
1189
2065
  };
@@ -1195,10 +2071,15 @@ class RefSubjectTuple extends YieldableFx {
1195
2071
  return this.versioned.run(sink);
1196
2072
  }
1197
2073
  toEffect() {
1198
- return this.versioned.asEffect();
2074
+ return this.versioned;
1199
2075
  }
1200
2076
  updates(run) {
1201
- return run(this.getSetDelete);
2077
+ const accessEffect = getTransactionAccess(this);
2078
+ return accessEffect
2079
+ ? Effect.flatMap(accessEffect, (transactionAccess) => Option.isSome(transactionAccess)
2080
+ ? runTransaction(transactionAccess.value, run)
2081
+ : Effect.suspend(() => run(this.getSetDelete)))
2082
+ : Effect.suspend(() => run(this.getSetDelete));
1202
2083
  }
1203
2084
  onFailure(cause) {
1204
2085
  return Effect.all(this.refs.map((ref) => ref.onFailure(cause)));
@@ -1208,10 +2089,10 @@ class RefSubjectTuple extends YieldableFx {
1208
2089
  }
1209
2090
  }
1210
2091
  function makeTupleComputed(refs) {
1211
- return new ComputedImpl(Versioned.tuple(refs), Effect.succeed);
2092
+ return new ComputedImpl(versionedInContext(() => Versioned.tuple(refs)), Effect.succeed);
1212
2093
  }
1213
2094
  function makeTupleFiltered(refs) {
1214
- return new FilteredImpl(Versioned.tuple(refs), Effect.succeedSome);
2095
+ return new FilteredImpl(versionedInContext(() => Versioned.tuple(refs)), Effect.succeedSome);
1215
2096
  }
1216
2097
  function makeStructRef(refs) {
1217
2098
  return new RefSubjectStruct(refs);
@@ -1228,12 +2109,16 @@ class RefSubjectStruct extends YieldableFx {
1228
2109
  constructor(refs) {
1229
2110
  super();
1230
2111
  this.refs = refs;
1231
- this.versioned = Versioned.hold(Versioned.struct(refs));
2112
+ const keys = Object.keys(refs);
2113
+ const current = Effect.map(Effect.all(keys.map((key) => sampleRefSubject(refs[key])), UNBOUNDED), (values) => Object.fromEntries(keys.map((key, index) => [key, values[index]])));
2114
+ this.versioned = (keys.length > 0 && getStructTransactionAccess(refs)
2115
+ ? makeCompositeVersioned(Object.values(refs), current)
2116
+ : versionedInContext(() => Versioned.hold(Versioned.struct(refs))));
1232
2117
  this.version = this.versioned.version;
1233
2118
  this.interrupt = Effect.all(Object.values(refs).map((r) => r.interrupt), UNBOUNDED);
1234
2119
  this.subscriberCount = Effect.map(Effect.all(Object.values(refs).map((r) => r.subscriberCount), UNBOUNDED), Array.reduce(0, sum));
1235
2120
  this.getSetDelete = {
1236
- get: this.versioned.asEffect(),
2121
+ get: this.versioned,
1237
2122
  set: (a) => Effect.all(Object.keys(refs).map((k) => set(refs[k], a[k])), UNBOUNDED),
1238
2123
  delete: Effect.map(Effect.all(Object.values(refs).map((r) => reset(r)), UNBOUNDED), Option.all),
1239
2124
  };
@@ -1245,10 +2130,15 @@ class RefSubjectStruct extends YieldableFx {
1245
2130
  return this.versioned.run(sink);
1246
2131
  }
1247
2132
  toEffect() {
1248
- return this.versioned.asEffect();
2133
+ return this.versioned;
1249
2134
  }
1250
2135
  updates(run) {
1251
- return run(this.getSetDelete);
2136
+ const accessEffect = getTransactionAccess(this);
2137
+ return accessEffect
2138
+ ? Effect.flatMap(accessEffect, (transactionAccess) => Option.isSome(transactionAccess)
2139
+ ? runTransaction(transactionAccess.value, run)
2140
+ : Effect.suspend(() => run(this.getSetDelete)))
2141
+ : Effect.suspend(() => run(this.getSetDelete));
1252
2142
  }
1253
2143
  onFailure(cause) {
1254
2144
  return Effect.all(Object.values(this.refs).map((ref) => ref.onFailure(cause)));
@@ -1258,11 +2148,29 @@ class RefSubjectStruct extends YieldableFx {
1258
2148
  }
1259
2149
  }
1260
2150
  function makeStructComputed(refs) {
1261
- return new ComputedImpl(Versioned.struct(refs), Effect.succeed);
2151
+ return new ComputedImpl(versionedInContext(() => Versioned.struct(refs)), Effect.succeed);
1262
2152
  }
1263
2153
  function makeStructFiltered(refs) {
1264
- return new FilteredImpl(Versioned.struct(refs), Effect.succeedSome);
2154
+ return new FilteredImpl(versionedInContext(() => Versioned.struct(refs)), Effect.succeedSome);
1265
2155
  }
2156
+ /**
2157
+ * Lifts an Effect-provided Computed into a Computed facade.
2158
+ *
2159
+ * @remarks
2160
+ * ## Why
2161
+ *
2162
+ * Defers service lookup until each version read, current read, interruption, or Fx observation, so
2163
+ * callers can compose a Context-provided Computed without manually flat-mapping the service Effect.
2164
+ *
2165
+ * ## Ownership and lifetime
2166
+ *
2167
+ * The facade caches neither the resolved Computed nor its value. Each operation runs the supplied
2168
+ * Effect, then delegates to the resolved Computed. Service requirements combine as `R | R2`, source
2169
+ * failures remain `E`, and the observing Scope owns the delegated subscription.
2170
+ *
2171
+ * @since 1.18.0
2172
+ * @category Services
2173
+ */
1266
2174
  export function computedFromService(effect) {
1267
2175
  return new ComputedFromService(effect);
1268
2176
  }
@@ -1281,9 +2189,26 @@ class ComputedFromService extends YieldableFx {
1281
2189
  return Effect.flatMap(this.effect, (c) => c.run(sink));
1282
2190
  }
1283
2191
  toEffect() {
1284
- return Effect.flatMap(this.effect, (c) => c.asEffect());
2192
+ return Effect.flatMap(this.effect, (c) => c);
1285
2193
  }
1286
2194
  }
2195
+ /**
2196
+ * Defers retrieval of a Filtered value from Effect Context while preserving Filtered behavior.
2197
+ *
2198
+ * @remarks
2199
+ * ## Why
2200
+ *
2201
+ * Lets a service-provided Filtered participate directly in Effect reads and Fx observation without
2202
+ * manually flat-mapping the service tag at every use.
2203
+ *
2204
+ * ## Ownership and lifetime
2205
+ *
2206
+ * The filtered from service view retains no independent value. Its Effect read fails with NoSuchElement
2207
+ * while absent; the observing Scope owns and finalizes its Fx subscription.
2208
+ *
2209
+ * @since 1.18.0
2210
+ * @category Services
2211
+ */
1287
2212
  export function filteredFromService(effect) {
1288
2213
  return new FilteredFromService(effect);
1289
2214
  }
@@ -1302,9 +2227,10 @@ class FilteredFromService extends YieldableFx {
1302
2227
  return Effect.flatMap(this.effect, (c) => c.run(sink));
1303
2228
  }
1304
2229
  toEffect() {
1305
- return Effect.flatMap(this.effect, (c) => c.asEffect());
2230
+ return Effect.flatMap(this.effect, (c) => c);
1306
2231
  }
1307
2232
  asComputed() {
1308
2233
  return computedFromService(Effect.map(this.effect, (c) => c.asComputed()));
1309
2234
  }
1310
2235
  }
2236
+ export * from "./Hydration.js";