@typed/fx 2.0.0-beta.6 → 2.0.0-beta.8

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 (270) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/dist/Fx/Fx.d.ts +9 -9
  4. package/dist/Fx/Fx.js +1 -1
  5. package/dist/Fx/TypeId.d.ts +3 -3
  6. package/dist/Fx/TypeId.js +2 -2
  7. package/dist/Fx/combinators/additive.d.ts +6 -6
  8. package/dist/Fx/combinators/additive.js +6 -6
  9. package/dist/Fx/combinators/catch.d.ts +7 -7
  10. package/dist/Fx/combinators/catch.js +7 -7
  11. package/dist/Fx/combinators/causes.d.ts +1 -1
  12. package/dist/Fx/combinators/causes.js +1 -1
  13. package/dist/Fx/combinators/changesWithEffect.d.ts +1 -1
  14. package/dist/Fx/combinators/changesWithEffect.js +1 -1
  15. package/dist/Fx/combinators/compact.d.ts +1 -1
  16. package/dist/Fx/combinators/compact.js +1 -1
  17. package/dist/Fx/combinators/concatMap.d.ts +2 -2
  18. package/dist/Fx/combinators/concatMap.js +2 -2
  19. package/dist/Fx/combinators/continueWith.d.ts +4 -4
  20. package/dist/Fx/combinators/continueWith.js +4 -4
  21. package/dist/Fx/combinators/debounce.d.ts +2 -2
  22. package/dist/Fx/combinators/debounce.d.ts.map +1 -1
  23. package/dist/Fx/combinators/debounce.js +1 -1
  24. package/dist/Fx/combinators/delay.d.ts +9 -7
  25. package/dist/Fx/combinators/delay.d.ts.map +1 -1
  26. package/dist/Fx/combinators/delay.js +8 -6
  27. package/dist/Fx/combinators/dropUntil.d.ts +2 -2
  28. package/dist/Fx/combinators/dropUntil.js +2 -2
  29. package/dist/Fx/combinators/during.d.ts +1 -1
  30. package/dist/Fx/combinators/during.js +1 -1
  31. package/dist/Fx/combinators/ensuring.d.ts +1 -1
  32. package/dist/Fx/combinators/ensuring.js +1 -1
  33. package/dist/Fx/combinators/exhaustLatestMap.d.ts +1 -1
  34. package/dist/Fx/combinators/exhaustLatestMap.js +1 -1
  35. package/dist/Fx/combinators/exhaustLatestMapEffect.d.ts +1 -1
  36. package/dist/Fx/combinators/exhaustLatestMapEffect.js +1 -1
  37. package/dist/Fx/combinators/exhaustMap.d.ts +1 -1
  38. package/dist/Fx/combinators/exhaustMap.js +1 -1
  39. package/dist/Fx/combinators/exhaustMapEffect.d.ts +1 -1
  40. package/dist/Fx/combinators/exhaustMapEffect.js +1 -1
  41. package/dist/Fx/combinators/exit.d.ts +1 -1
  42. package/dist/Fx/combinators/exit.js +1 -1
  43. package/dist/Fx/combinators/filter.d.ts +1 -1
  44. package/dist/Fx/combinators/filter.js +1 -1
  45. package/dist/Fx/combinators/filterEffect.d.ts +1 -1
  46. package/dist/Fx/combinators/filterEffect.js +1 -1
  47. package/dist/Fx/combinators/filterMap.d.ts +1 -1
  48. package/dist/Fx/combinators/filterMap.js +1 -1
  49. package/dist/Fx/combinators/filterMapEffect.d.ts +1 -1
  50. package/dist/Fx/combinators/filterMapEffect.js +1 -1
  51. package/dist/Fx/combinators/filterMapLoop.d.ts +1 -1
  52. package/dist/Fx/combinators/filterMapLoop.js +1 -1
  53. package/dist/Fx/combinators/filterMapLoopCause.d.ts +1 -1
  54. package/dist/Fx/combinators/filterMapLoopCause.js +1 -1
  55. package/dist/Fx/combinators/filterMapLoopCauseEffect.d.ts +1 -1
  56. package/dist/Fx/combinators/filterMapLoopCauseEffect.js +1 -1
  57. package/dist/Fx/combinators/filterMapLoopEffect.d.ts +1 -1
  58. package/dist/Fx/combinators/filterMapLoopEffect.js +1 -1
  59. package/dist/Fx/combinators/flatMap.d.ts +2 -2
  60. package/dist/Fx/combinators/flatMap.js +1 -1
  61. package/dist/Fx/combinators/flatMapConcurrently.d.ts +1 -1
  62. package/dist/Fx/combinators/flatMapConcurrently.js +1 -1
  63. package/dist/Fx/combinators/flatMapConcurrentlyEffect.d.ts +1 -1
  64. package/dist/Fx/combinators/flatMapConcurrentlyEffect.js +1 -1
  65. package/dist/Fx/combinators/flatMapEffect.d.ts +2 -2
  66. package/dist/Fx/combinators/flatMapEffect.js +1 -1
  67. package/dist/Fx/combinators/flip.d.ts +1 -1
  68. package/dist/Fx/combinators/flip.js +1 -1
  69. package/dist/Fx/combinators/gen.d.ts +1 -1
  70. package/dist/Fx/combinators/gen.js +1 -1
  71. package/dist/Fx/combinators/genScoped.d.ts +1 -1
  72. package/dist/Fx/combinators/genScoped.js +1 -1
  73. package/dist/Fx/combinators/grouped.d.ts +2 -2
  74. package/dist/Fx/combinators/grouped.js +2 -2
  75. package/dist/Fx/combinators/keyed.d.ts +2 -2
  76. package/dist/Fx/combinators/keyed.js +1 -1
  77. package/dist/Fx/combinators/loop.d.ts +1 -1
  78. package/dist/Fx/combinators/loop.js +1 -1
  79. package/dist/Fx/combinators/loopCause.d.ts +1 -1
  80. package/dist/Fx/combinators/loopCause.js +1 -1
  81. package/dist/Fx/combinators/loopCauseEffect.d.ts +1 -1
  82. package/dist/Fx/combinators/loopCauseEffect.js +1 -1
  83. package/dist/Fx/combinators/loopEffect.d.ts +1 -1
  84. package/dist/Fx/combinators/loopEffect.js +1 -1
  85. package/dist/Fx/combinators/map.d.ts +2 -2
  86. package/dist/Fx/combinators/map.js +2 -2
  87. package/dist/Fx/combinators/mapBoth.d.ts +1 -1
  88. package/dist/Fx/combinators/mapBoth.js +1 -1
  89. package/dist/Fx/combinators/mapEffect.d.ts +1 -1
  90. package/dist/Fx/combinators/mapEffect.js +1 -1
  91. package/dist/Fx/combinators/mapError.d.ts +1 -1
  92. package/dist/Fx/combinators/mapError.js +1 -1
  93. package/dist/Fx/combinators/mergeAll.d.ts +1 -1
  94. package/dist/Fx/combinators/mergeAll.js +1 -1
  95. package/dist/Fx/combinators/mergeOrdered.d.ts +1 -1
  96. package/dist/Fx/combinators/mergeOrdered.d.ts.map +1 -1
  97. package/dist/Fx/combinators/mergeOrdered.js +33 -11
  98. package/dist/Fx/combinators/onError.d.ts +1 -1
  99. package/dist/Fx/combinators/onError.js +1 -1
  100. package/dist/Fx/combinators/onExit.d.ts +1 -1
  101. package/dist/Fx/combinators/onExit.js +1 -1
  102. package/dist/Fx/combinators/onInterrupt.d.ts +1 -1
  103. package/dist/Fx/combinators/onInterrupt.js +1 -1
  104. package/dist/Fx/combinators/pairwise.d.ts +1 -1
  105. package/dist/Fx/combinators/pairwise.js +1 -1
  106. package/dist/Fx/combinators/provide.d.ts +4 -4
  107. package/dist/Fx/combinators/provide.js +4 -4
  108. package/dist/Fx/combinators/race.d.ts +2 -2
  109. package/dist/Fx/combinators/race.js +2 -2
  110. package/dist/Fx/combinators/repeat.d.ts +1 -1
  111. package/dist/Fx/combinators/repeat.js +1 -1
  112. package/dist/Fx/combinators/result.d.ts +1 -1
  113. package/dist/Fx/combinators/result.js +1 -1
  114. package/dist/Fx/combinators/retry.d.ts +1 -1
  115. package/dist/Fx/combinators/retry.js +1 -1
  116. package/dist/Fx/combinators/sample.d.ts +1 -1
  117. package/dist/Fx/combinators/sample.js +1 -1
  118. package/dist/Fx/combinators/scan.d.ts +2 -2
  119. package/dist/Fx/combinators/scan.js +2 -2
  120. package/dist/Fx/combinators/since.d.ts +1 -1
  121. package/dist/Fx/combinators/since.js +1 -1
  122. package/dist/Fx/combinators/skip.d.ts +2 -2
  123. package/dist/Fx/combinators/skip.js +2 -2
  124. package/dist/Fx/combinators/skipRepeats.d.ts +1 -1
  125. package/dist/Fx/combinators/skipRepeats.js +1 -1
  126. package/dist/Fx/combinators/skipRepeatsWith.d.ts +1 -1
  127. package/dist/Fx/combinators/skipRepeatsWith.js +1 -1
  128. package/dist/Fx/combinators/skipWhile.d.ts +4 -4
  129. package/dist/Fx/combinators/skipWhile.js +4 -4
  130. package/dist/Fx/combinators/slice.d.ts +3 -3
  131. package/dist/Fx/combinators/slice.js +2 -2
  132. package/dist/Fx/combinators/switchMap.d.ts +1 -1
  133. package/dist/Fx/combinators/switchMap.js +1 -1
  134. package/dist/Fx/combinators/switchMapEffect.d.ts +1 -1
  135. package/dist/Fx/combinators/switchMapEffect.js +1 -1
  136. package/dist/Fx/combinators/take.d.ts +2 -2
  137. package/dist/Fx/combinators/take.js +2 -2
  138. package/dist/Fx/combinators/takeUntil.d.ts +3 -3
  139. package/dist/Fx/combinators/takeUntil.js +3 -3
  140. package/dist/Fx/combinators/takeWhile.d.ts +2 -2
  141. package/dist/Fx/combinators/takeWhile.js +2 -2
  142. package/dist/Fx/combinators/tapEffect.d.ts +1 -1
  143. package/dist/Fx/combinators/tapEffect.js +1 -1
  144. package/dist/Fx/combinators/throttle.d.ts +3 -3
  145. package/dist/Fx/combinators/throttle.d.ts.map +1 -1
  146. package/dist/Fx/combinators/throttle.js +1 -1
  147. package/dist/Fx/combinators/timeout.d.ts +2 -2
  148. package/dist/Fx/combinators/timeout.js +2 -2
  149. package/dist/Fx/combinators/tuple.d.ts +2 -2
  150. package/dist/Fx/combinators/tuple.js +2 -2
  151. package/dist/Fx/combinators/until.d.ts +1 -1
  152. package/dist/Fx/combinators/until.js +1 -1
  153. package/dist/Fx/combinators/unwrap.d.ts +1 -1
  154. package/dist/Fx/combinators/unwrap.js +1 -1
  155. package/dist/Fx/combinators/unwrapScoped.d.ts +1 -1
  156. package/dist/Fx/combinators/unwrapScoped.js +1 -1
  157. package/dist/Fx/combinators/when.d.ts +2 -2
  158. package/dist/Fx/combinators/when.js +2 -2
  159. package/dist/Fx/combinators/withLatestFrom.d.ts +2 -2
  160. package/dist/Fx/combinators/withLatestFrom.js +2 -2
  161. package/dist/Fx/combinators/withSpan.d.ts +1 -1
  162. package/dist/Fx/combinators/withSpan.js +1 -1
  163. package/dist/Fx/combinators/zip.d.ts +4 -4
  164. package/dist/Fx/combinators/zip.js +4 -4
  165. package/dist/Fx/constructors/at.d.ts +1 -1
  166. package/dist/Fx/constructors/at.js +1 -1
  167. package/dist/Fx/constructors/die.d.ts +1 -1
  168. package/dist/Fx/constructors/die.js +1 -1
  169. package/dist/Fx/constructors/empty.d.ts +1 -1
  170. package/dist/Fx/constructors/empty.js +1 -1
  171. package/dist/Fx/constructors/fail.d.ts +1 -1
  172. package/dist/Fx/constructors/fail.js +1 -1
  173. package/dist/Fx/constructors/failCause.d.ts +1 -1
  174. package/dist/Fx/constructors/failCause.js +1 -1
  175. package/dist/Fx/constructors/fn.d.ts +4 -4
  176. package/dist/Fx/constructors/fn.js +1 -1
  177. package/dist/Fx/constructors/fromEffect.d.ts +2 -2
  178. package/dist/Fx/constructors/fromEffect.js +2 -2
  179. package/dist/Fx/constructors/fromFailures.d.ts +1 -1
  180. package/dist/Fx/constructors/fromFailures.js +1 -1
  181. package/dist/Fx/constructors/fromIterable.d.ts +1 -1
  182. package/dist/Fx/constructors/fromIterable.js +1 -1
  183. package/dist/Fx/constructors/fromSchedule.d.ts +6 -4
  184. package/dist/Fx/constructors/fromSchedule.d.ts.map +1 -1
  185. package/dist/Fx/constructors/fromSchedule.js +6 -4
  186. package/dist/Fx/constructors/interrupt.d.ts +1 -1
  187. package/dist/Fx/constructors/interrupt.js +1 -1
  188. package/dist/Fx/constructors/make.d.ts +9 -7
  189. package/dist/Fx/constructors/make.d.ts.map +1 -1
  190. package/dist/Fx/constructors/make.js +8 -6
  191. package/dist/Fx/constructors/periodic.d.ts +1 -1
  192. package/dist/Fx/constructors/periodic.js +1 -1
  193. package/dist/Fx/constructors/succeed.d.ts +4 -4
  194. package/dist/Fx/constructors/succeed.js +4 -4
  195. package/dist/Fx/constructors/suspend.d.ts +1 -1
  196. package/dist/Fx/constructors/suspend.js +1 -1
  197. package/dist/Fx/constructors/sync.d.ts +1 -1
  198. package/dist/Fx/constructors/sync.js +1 -1
  199. package/dist/Fx/run/collect.d.ts +4 -4
  200. package/dist/Fx/run/collect.js +4 -4
  201. package/dist/Fx/run/first.d.ts +1 -1
  202. package/dist/Fx/run/first.js +1 -1
  203. package/dist/Fx/run/fork.d.ts +2 -2
  204. package/dist/Fx/run/fork.js +2 -2
  205. package/dist/Fx/run/observe.d.ts +7 -5
  206. package/dist/Fx/run/observe.d.ts.map +1 -1
  207. package/dist/Fx/run/observe.js +30 -15
  208. package/dist/Fx/run/runPromise.d.ts +2 -2
  209. package/dist/Fx/run/runPromise.js +2 -2
  210. package/dist/Fx/stream.d.ts +4 -4
  211. package/dist/Fx/stream.js +2 -2
  212. package/dist/Push/Push.d.ts +30 -30
  213. package/dist/Push/Push.js +26 -26
  214. package/dist/RefSubject/Hydration.d.ts +24 -24
  215. package/dist/RefSubject/Hydration.js +5 -5
  216. package/dist/RefSubject/RefArray.d.ts +31 -31
  217. package/dist/RefSubject/RefArray.js +30 -30
  218. package/dist/RefSubject/RefBigDecimal.d.ts +20 -20
  219. package/dist/RefSubject/RefBigDecimal.js +19 -19
  220. package/dist/RefSubject/RefBigInt.d.ts +15 -15
  221. package/dist/RefSubject/RefBigInt.js +14 -14
  222. package/dist/RefSubject/RefBoolean.d.ts +15 -15
  223. package/dist/RefSubject/RefBoolean.js +14 -14
  224. package/dist/RefSubject/RefCause.d.ts +11 -11
  225. package/dist/RefSubject/RefCause.js +10 -10
  226. package/dist/RefSubject/RefChunk.d.ts +37 -37
  227. package/dist/RefSubject/RefChunk.js +36 -36
  228. package/dist/RefSubject/RefDateTime.d.ts +11 -11
  229. package/dist/RefSubject/RefDateTime.js +10 -10
  230. package/dist/RefSubject/RefDuration.d.ts +14 -14
  231. package/dist/RefSubject/RefDuration.js +13 -13
  232. package/dist/RefSubject/RefGraph.d.ts +29 -29
  233. package/dist/RefSubject/RefGraph.js +28 -28
  234. package/dist/RefSubject/RefHashMap.d.ts +27 -27
  235. package/dist/RefSubject/RefHashMap.js +26 -26
  236. package/dist/RefSubject/RefHashRing.d.ts +13 -13
  237. package/dist/RefSubject/RefHashRing.js +12 -12
  238. package/dist/RefSubject/RefHashSet.d.ts +21 -21
  239. package/dist/RefSubject/RefHashSet.js +20 -20
  240. package/dist/RefSubject/RefIterable.d.ts +30 -30
  241. package/dist/RefSubject/RefIterable.js +29 -29
  242. package/dist/RefSubject/RefOption.d.ts +13 -13
  243. package/dist/RefSubject/RefOption.js +12 -12
  244. package/dist/RefSubject/RefRecord.d.ts +31 -31
  245. package/dist/RefSubject/RefRecord.js +30 -30
  246. package/dist/RefSubject/RefResult.d.ts +12 -12
  247. package/dist/RefSubject/RefResult.js +11 -11
  248. package/dist/RefSubject/RefString.d.ts +17 -17
  249. package/dist/RefSubject/RefString.js +16 -16
  250. package/dist/RefSubject/RefStruct.d.ts +13 -13
  251. package/dist/RefSubject/RefStruct.js +12 -12
  252. package/dist/RefSubject/RefSubject.d.ts +93 -94
  253. package/dist/RefSubject/RefSubject.d.ts.map +1 -1
  254. package/dist/RefSubject/RefSubject.js +132 -77
  255. package/dist/RefSubject/RefTrie.d.ts +26 -26
  256. package/dist/RefSubject/RefTrie.js +25 -25
  257. package/dist/RefSubject/RefTuple.d.ts +11 -11
  258. package/dist/RefSubject/RefTuple.js +9 -9
  259. package/dist/Sink/Sink.d.ts +21 -19
  260. package/dist/Sink/Sink.d.ts.map +1 -1
  261. package/dist/Sink/Sink.js +5 -4
  262. package/dist/Sink/combinators.d.ts +33 -33
  263. package/dist/Sink/combinators.js +32 -32
  264. package/dist/Subject/Subject.d.ts +14 -13
  265. package/dist/Subject/Subject.d.ts.map +1 -1
  266. package/dist/Subject/Subject.js +11 -10
  267. package/dist/Versioned/Versioned.d.ts +31 -28
  268. package/dist/Versioned/Versioned.d.ts.map +1 -1
  269. package/dist/Versioned/Versioned.js +45 -37
  270. package/package.json +5 -4
@@ -2,6 +2,7 @@
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";
5
6
  import * as Semaphore from "effect/Semaphore";
6
7
  import { equals } from "effect/Equal";
7
8
  import * as Exit from "effect/Exit";
@@ -47,7 +48,7 @@ import { hasProperty } from "effect/Predicate";
47
48
  * source errors, services, and lifetime.
48
49
  *
49
50
  * @since 1.18.0
50
- * @category combinators
51
+ * @category Type identity
51
52
  */
52
53
  export const RefSubjectTypeId = Symbol.for("@typed/fx/RefSubject");
53
54
  /**
@@ -64,7 +65,7 @@ export const RefSubjectTypeId = Symbol.for("@typed/fx/RefSubject");
64
65
  * source errors, services, and lifetime.
65
66
  *
66
67
  * @since 1.18.0
67
- * @category combinators
68
+ * @category Type identity
68
69
  */
69
70
  export const ComputedTypeId = Symbol.for("@typed/fx/Computed");
70
71
  /**
@@ -81,7 +82,7 @@ export const ComputedTypeId = Symbol.for("@typed/fx/Computed");
81
82
  * source errors, services, and lifetime.
82
83
  *
83
84
  * @since 1.18.0
84
- * @category combinators
85
+ * @category Type identity
85
86
  */
86
87
  export const FilteredTypeId = Symbol.for("@typed/fx/Filtered");
87
88
  /**
@@ -101,12 +102,23 @@ export const FilteredTypeId = Symbol.for("@typed/fx/Filtered");
101
102
  * still owns any subscription created by `"multiple"`.
102
103
  *
103
104
  * @since 1.18.0
104
- * @category combinators
105
+ * @category Observation policy
105
106
  */
106
107
  export const CurrentComputedBehavior = Context.Reference("@typed/fx/CurrentComputedBehavior", {
107
108
  defaultValue: () => "multiple",
108
109
  });
109
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
+ }
110
122
  class ComputedImpl extends Versioned.VersionedTransform {
111
123
  [ComputedTypeId] = ComputedTypeId;
112
124
  _computed;
@@ -116,7 +128,7 @@ class ComputedImpl extends Versioned.VersionedTransform {
116
128
  super(input, (fx) => fxMapEffect(fx, f), Effect.flatMap(f));
117
129
  this.input = input;
118
130
  this.f = f;
119
- this._computed = Subject.hold(unwrap(Effect.map(Effect.context(), (ctx) => {
131
+ this._computed = holdInContext(unwrap(Effect.map(Effect.context(), (ctx) => {
120
132
  if (checkIsMultiple(ctx)) {
121
133
  return fxFromEffect(input).pipe(continueWith(() => input), skipRepeats, fxMapEffect(f));
122
134
  }
@@ -138,12 +150,13 @@ class ComputedImpl extends Versioned.VersionedTransform {
138
150
  *
139
151
  * ## Ownership and lifetime
140
152
  *
141
- * Current reads directly sample and transform the input. The pushed channel uses `Subject.hold`:
142
- * concurrent observers share one active upstream session and its latest retained projection; the
143
- * last observer ends the session and clears that held value. The observing Scope owns cleanup.
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.
144
157
  *
145
158
  * @since 1.18.0
146
- * @category combinators
159
+ * @category Derived queries
147
160
  */
148
161
  export function makeComputed(input, f) {
149
162
  return new ComputedImpl(input, f);
@@ -166,16 +179,14 @@ export function makeComputed(input, f) {
166
179
  *
167
180
  * ## Ownership and lifetime
168
181
  *
169
- * Calling `scan` allocates one private `MutableRef` for the returned Computed's Effect-read
170
- * accumulator. Every Effect read of that same Computed shares it and advances it after a
171
- * successful fold; separate `scan` calls do not share state. The pushed channel runs
172
- * `Fx.scanEffect` from `initial` inside `Subject.hold`: concurrent observers share the active scan
173
- * and its latest retained result, while the last observer ends that session and clears the held
174
- * value. The observing Scope owns subscription cleanup. The private read accumulator has no
175
- * finalizer and is collected with the returned Computed.
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.
176
187
  *
177
188
  * @since 1.0.0
178
- * @category combinators
189
+ * @category Accumulation
179
190
  */
180
191
  export const scan = dual(3, function scan(versioned, initial, f) {
181
192
  return new ComputedScanImpl(versioned, initial, (s, a) => Effect.succeed(f(s, a)));
@@ -191,16 +202,15 @@ export const scan = dual(3, function scan(versioned, initial, f) {
191
202
  *
192
203
  * ## Ownership and lifetime
193
204
  *
194
- * Calling `scanEffect` allocates one private `MutableRef` for the returned Computed's Effect-read
195
- * accumulator. Every Effect read of that same Computed shares it; the accumulator advances only
196
- * after `f` succeeds, so a typed failure leaves the previous state intact. The pushed channel runs
197
- * `Fx.scanEffect` from `initial` inside `Subject.hold`: concurrent observers share the active scan
198
- * and latest retained result, and each fold requires `R3`. The last observer ends that session and
199
- * clears the held value. The observing Scope owns cleanup; the private read accumulator has no
200
- * finalizer and is collected with the returned Computed.
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.
201
211
  *
202
212
  * @since 1.0.0
203
- * @category combinators
213
+ * @category Accumulation
204
214
  */
205
215
  export const scanEffect = dual(3, function scanEffect(versioned, initial, f) {
206
216
  return new ComputedScanImpl(versioned, initial, f);
@@ -212,15 +222,23 @@ class ComputedScanImpl extends Versioned.VersionedTransform {
212
222
  initial;
213
223
  f;
214
224
  constructor(input, initial, f) {
215
- const state = MutableRef.make(initial);
216
- super(input, (fx) => fxScanEffect(fx, initial, f), (effect) => Effect.flatMap(effect, (a) => Effect.flatMap(f(MutableRef.get(state), a), (next) => Effect.sync(() => {
217
- MutableRef.set(state, next);
218
- return next;
219
- }))));
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
+ }));
220
238
  this.input = input;
221
239
  this.initial = initial;
222
240
  this.f = f;
223
- this._computed = Subject.hold(unwrap(Effect.map(Effect.context(), (ctx) => {
241
+ this._computed = holdInContext(unwrap(Effect.map(Effect.context(), (ctx) => {
224
242
  if (checkIsMultiple(ctx)) {
225
243
  return fxFromEffect(input).pipe(continueWith(() => input), skipRepeats, fxScanEffect(initial, f));
226
244
  }
@@ -242,11 +260,12 @@ class ComputedScanImpl extends Versioned.VersionedTransform {
242
260
  *
243
261
  * ## Ownership and lifetime
244
262
  *
245
- * The make filtered view retains no independent value. Its Effect read fails with NoSuchElement
246
- * while absent; the observing Scope owns and finalizes its Fx subscription.
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.
247
266
  *
248
267
  * @since 1.18.0
249
- * @category combinators
268
+ * @category Optional queries
250
269
  */
251
270
  export function makeFiltered(input, f) {
252
271
  return new FilteredImpl(input, f);
@@ -260,7 +279,7 @@ class FilteredImpl extends Versioned.VersionedTransform {
260
279
  super(input, (fx) => fxFilterMapEffect(fx, f), (effect) => Effect.flatMap(Effect.flatMap(effect, f), Effect.fromOption));
261
280
  this.input = input;
262
281
  this.f = f;
263
- this._computed = Subject.hold(unwrap(Effect.map(Effect.context(), (ctx) => {
282
+ this._computed = holdInContext(unwrap(Effect.map(Effect.context(), (ctx) => {
264
283
  if (checkIsMultiple(ctx)) {
265
284
  return fxFromEffect(input).pipe(continueWith(() => input), skipRepeats, fxFilterMapEffect(f));
266
285
  }
@@ -504,7 +523,7 @@ class RefSubjectImpl extends YieldableFx {
504
523
  * ```
505
524
  *
506
525
  * @since 1.0.0
507
- * @category constructors
526
+ * @category Constructors
508
527
  */
509
528
  export function make(effect, options) {
510
529
  if (isFx(effect)) {
@@ -552,7 +571,7 @@ export function make(effect, options) {
552
571
  * ```
553
572
  *
554
573
  * @since 1.0.0
555
- * @category constructors
574
+ * @category Source adapters
556
575
  */
557
576
  export function fromEffect(effect, options) {
558
577
  return Effect.map(makeCore(effect, options), (core) => new RefSubjectImpl(core));
@@ -591,7 +610,7 @@ export function fromEffect(effect, options) {
591
610
  * ```
592
611
  *
593
612
  * @since 1.0.0
594
- * @category constructors
613
+ * @category Source adapters
595
614
  */
596
615
  export function fromFx(fx, options) {
597
616
  return Effect.gen(function* () {
@@ -619,7 +638,7 @@ export function fromFx(fx, options) {
619
638
  * expose `E`.
620
639
  *
621
640
  * @since 1.18.0
622
- * @category combinators
641
+ * @category Source adapters
623
642
  */
624
643
  export function fromStream(stream, options) {
625
644
  return Effect.gen(function* () {
@@ -657,7 +676,7 @@ export function fromStream(stream, options) {
657
676
  * ```
658
677
  *
659
678
  * @since 1.0.0
660
- * @category constructors
679
+ * @category Source adapters
661
680
  */
662
681
  export function fromOption(option, options) {
663
682
  return make(option, options);
@@ -682,7 +701,7 @@ export function fromOption(option, options) {
682
701
  * ```
683
702
  *
684
703
  * @since 1.0.0
685
- * @category constructors
704
+ * @category Source adapters
686
705
  */
687
706
  function optionFromNullable(value) {
688
707
  return value === null || value === undefined
@@ -705,7 +724,7 @@ function optionFromNullable(value) {
705
724
  * fail. The returned RefSubject owns and publishes subsequent Option writes.
706
725
  *
707
726
  * @since 1.18.0
708
- * @category combinators
727
+ * @category Source adapters
709
728
  */
710
729
  export function fromNullable(value, options) {
711
730
  return make(optionFromNullable(value), options);
@@ -742,12 +761,21 @@ function getOrInitializeCore(core, lockInitialize) {
742
761
  });
743
762
  }
744
763
  function initializeCoreEffect(core, lock) {
764
+ let completed = false;
745
765
  const initialize = Effect.onExit(Effect.provide(core.initial, core.services), (exit) => Effect.sync(() => {
766
+ completed = true;
746
767
  core._fiber = undefined;
747
768
  core.deferredRef.done(exit);
748
769
  }));
749
770
  const isSourceBacked = core.initial === core.deferredRef;
750
- return Effect.flatMap(Effect.forkIn(lock && !isSourceBacked ? core.semaphore.withPermits(1)(initialize) : initialize, core.scope), (fiber) => Effect.sync(() => (core._fiber = fiber)));
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
+ }));
751
779
  }
752
780
  function initializeCoreAndTap(core, lock) {
753
781
  return Effect.flatMapEager(initializeCoreEffect(core, lock), () =>
@@ -865,7 +893,7 @@ function sendEvent(core, exit) {
865
893
  * ```
866
894
  *
867
895
  * @since 1.0.0
868
- * @category combinators
896
+ * @category State updates
869
897
  */
870
898
  export const set = dual(2, function set(ref, a) {
871
899
  return ref.updates((ref) => ref.set(a));
@@ -907,7 +935,7 @@ export const set = dual(2, function set(ref, a) {
907
935
  * ```
908
936
  *
909
937
  * @since 1.0.0
910
- * @category combinators
938
+ * @category State updates
911
939
  */
912
940
  export function reset(ref) {
913
941
  return ref.updates((ref) => ref.delete);
@@ -937,7 +965,7 @@ export {
937
965
  * ```
938
966
  *
939
967
  * @since 1.20.0
940
- * @category combinators
968
+ * @category State updates
941
969
  */
942
970
  reset as delete, };
943
971
  /**
@@ -973,7 +1001,7 @@ reset as delete, };
973
1001
  * ```
974
1002
  *
975
1003
  * @since 1.0.0
976
- * @category combinators
1004
+ * @category State updates
977
1005
  */
978
1006
  export const updateEffect = dual(2, function updateEffect(ref, f) {
979
1007
  return ref.updates((ref) => Effect.flatMap(Effect.flatMap(ref.get, f), ref.set));
@@ -1022,7 +1050,7 @@ export const updateEffect = dual(2, function updateEffect(ref, f) {
1022
1050
  * ```
1023
1051
  *
1024
1052
  * @since 1.0.0
1025
- * @category combinators
1053
+ * @category State updates
1026
1054
  */
1027
1055
  export const update = dual(2, function update(ref, f) {
1028
1056
  return updateEffect(ref, (value) => Effect.succeed(f(value)));
@@ -1062,7 +1090,7 @@ export const update = dual(2, function update(ref, f) {
1062
1090
  * ```
1063
1091
  *
1064
1092
  * @since 1.0.0
1065
- * @category combinators
1093
+ * @category Transactions
1066
1094
  */
1067
1095
  export const modifyEffect = dual(2, function modifyEffect(ref, f) {
1068
1096
  return ref.updates((ref) => Effect.flatMap(ref.get, (value) => Effect.flatMap(f(value), ([b, a]) => Effect.as(ref.set(a), b))));
@@ -1099,7 +1127,7 @@ export const modifyEffect = dual(2, function modifyEffect(ref, f) {
1099
1127
  * ```
1100
1128
  *
1101
1129
  * @since 1.0.0
1102
- * @category combinators
1130
+ * @category Transactions
1103
1131
  */
1104
1132
  export const modify = dual(2, function modify(ref, f) {
1105
1133
  return modifyEffect(ref, (value) => Effect.succeed(f(value)));
@@ -1134,7 +1162,7 @@ export const modify = dual(2, function modify(ref, f) {
1134
1162
  * ```
1135
1163
  *
1136
1164
  * @since 1.0.0
1137
- * @category guards
1165
+ * @category Type guards
1138
1166
  */
1139
1167
  export function isRefSubject(value) {
1140
1168
  return hasProperty(value, RefSubjectTypeId) && value[RefSubjectTypeId] === RefSubjectTypeId;
@@ -1154,7 +1182,7 @@ const isRefSubjectDataFirst = (args) => isRefSubject(args[0]);
1154
1182
  * This synchronous predicate performs no Effect, subscription, or acquisition.
1155
1183
  *
1156
1184
  * @since 1.18.0
1157
- * @category guards
1185
+ * @category Type guards
1158
1186
  */
1159
1187
  export function isComputed(value) {
1160
1188
  return hasProperty(value, ComputedTypeId) && value[ComputedTypeId] === ComputedTypeId;
@@ -1203,7 +1231,7 @@ export function isComputed(value) {
1203
1231
  * ```
1204
1232
  *
1205
1233
  * @since 1.0.0
1206
- * @category combinators
1234
+ * @category Transactions
1207
1235
  */
1208
1236
  export const runUpdates = dual(isRefSubjectDataFirst, function runUpdates(ref, f, options) {
1209
1237
  if (options === undefined) {
@@ -1249,7 +1277,7 @@ export const runUpdates = dual(isRefSubjectDataFirst, function runUpdates(ref, f
1249
1277
  * ```
1250
1278
  *
1251
1279
  * @since 1.0.0
1252
- * @category combinators
1280
+ * @category State updates
1253
1281
  */
1254
1282
  export function increment(ref) {
1255
1283
  return update(ref, (value) => value + 1);
@@ -1287,7 +1315,7 @@ export function increment(ref) {
1287
1315
  * ```
1288
1316
  *
1289
1317
  * @since 1.0.0
1290
- * @category combinators
1318
+ * @category State updates
1291
1319
  */
1292
1320
  export function decrement(ref) {
1293
1321
  return update(ref, (value) => value - 1);
@@ -1315,7 +1343,7 @@ const Variance = {
1315
1343
  * while consumers require only the generated `Self` service.
1316
1344
  *
1317
1345
  * @since 1.18.0
1318
- * @category combinators
1346
+ * @category Services
1319
1347
  */
1320
1348
  export function Service() {
1321
1349
  return (id) => {
@@ -1327,6 +1355,11 @@ export function Service() {
1327
1355
  // @effect-diagnostics-next-line floatingEffect:off
1328
1356
  Object.assign(this, service);
1329
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
+ }));
1330
1363
  }
1331
1364
  static id = id;
1332
1365
  static service = service;
@@ -1351,7 +1384,7 @@ export function Service() {
1351
1384
  static [RefSubjectTypeId] = RefSubjectTypeId;
1352
1385
  static updates = (f) => Effect.flatMap(service, (ref) => ref.updates(f));
1353
1386
  // Yieldable
1354
- static override = service;
1387
+ static override = Effect.flatten(service);
1355
1388
  static [Symbol.iterator] = function* () {
1356
1389
  const ref = yield* service;
1357
1390
  return yield* ref;
@@ -1416,7 +1449,7 @@ function getDefaultBounds(options) {
1416
1449
  * ```
1417
1450
  *
1418
1451
  * @since 2.0.0
1419
- * @category combinators
1452
+ * @category Derived queries
1420
1453
  */
1421
1454
  export const proxy = (source) => {
1422
1455
  const target = {};
@@ -1471,7 +1504,7 @@ export const proxy = (source) => {
1471
1504
  * ```
1472
1505
  *
1473
1506
  * @since 1.0.0
1474
- * @category combinators
1507
+ * @category Derived queries
1475
1508
  */
1476
1509
  export const mapEffect = dual(2, function mapEffect(versioned, f) {
1477
1510
  return FilteredTypeId in versioned
@@ -1524,7 +1557,7 @@ export const mapEffect = dual(2, function mapEffect(versioned, f) {
1524
1557
  * ```
1525
1558
  *
1526
1559
  * @since 1.0.0
1527
- * @category combinators
1560
+ * @category Derived queries
1528
1561
  */
1529
1562
  export const map = dual(2, function map(versioned, f) {
1530
1563
  return mapEffect(versioned, (a) => Effect.succeed(f(a)));
@@ -1563,7 +1596,7 @@ export const map = dual(2, function map(versioned, f) {
1563
1596
  * ```
1564
1597
  *
1565
1598
  * @since 1.0.0
1566
- * @category combinators
1599
+ * @category Optional queries
1567
1600
  */
1568
1601
  export const filterMapEffect = dual(2, function filterMapEffect(versioned, f) {
1569
1602
  return new FilteredImpl(versioned, f);
@@ -1602,7 +1635,7 @@ export const filterMapEffect = dual(2, function filterMapEffect(versioned, f) {
1602
1635
  * ```
1603
1636
  *
1604
1637
  * @since 1.0.0
1605
- * @category combinators
1638
+ * @category Optional queries
1606
1639
  */
1607
1640
  export const filterMap = dual(2, function filterMap(versioned, f) {
1608
1641
  return new FilteredImpl(versioned, (a) => Effect.succeed(f(a)));
@@ -1643,7 +1676,7 @@ export const filterMap = dual(2, function filterMap(versioned, f) {
1643
1676
  * ```
1644
1677
  *
1645
1678
  * @since 1.0.0
1646
- * @category combinators
1679
+ * @category Optional queries
1647
1680
  */
1648
1681
  export const compact = function compact(versioned) {
1649
1682
  return new FilteredImpl(versioned, Effect.succeed);
@@ -1683,7 +1716,7 @@ export const compact = function compact(versioned) {
1683
1716
  * ```
1684
1717
  *
1685
1718
  * @since 1.0.0
1686
- * @category combinators
1719
+ * @category Optional queries
1687
1720
  */
1688
1721
  export const getOrElse = dual(2, function getOrElse(ref, fallback) {
1689
1722
  const computed = FilteredTypeId in ref ? ref.asComputed() : ref;
@@ -1742,7 +1775,7 @@ class RefSubjectSimpleTransform extends YieldableFx {
1742
1775
  * source RefSubject.
1743
1776
  *
1744
1777
  * @since 1.18.0
1745
- * @category combinators
1778
+ * @category Observation policy
1746
1779
  */
1747
1780
  export const slice = dual(3, function slice(ref, skip, take) {
1748
1781
  return new RefSubjectSimpleTransform(ref, (_) => fxSlice(_, { skip, take }), identity);
@@ -1832,7 +1865,7 @@ class RefSubjectTransform extends YieldableFx {
1832
1865
  * ```
1833
1866
  *
1834
1867
  * @since 1.0.0
1835
- * @category combinators
1868
+ * @category Writable views
1836
1869
  */
1837
1870
  export const transform = dual(3, function transform(ref, toB, toA) {
1838
1871
  return new RefSubjectTransform(ref, toB, toA);
@@ -1905,7 +1938,7 @@ function getRefKind(refs) {
1905
1938
  * ```
1906
1939
  *
1907
1940
  * @since 1.0.0
1908
- * @category combinators
1941
+ * @category State composition
1909
1942
  */
1910
1943
  export function struct(refs) {
1911
1944
  const kind = getRefKind(Object.values(refs));
@@ -1958,7 +1991,7 @@ export function struct(refs) {
1958
1991
  * ```
1959
1992
  *
1960
1993
  * @since 1.0.0
1961
- * @category combinators
1994
+ * @category State composition
1962
1995
  */
1963
1996
  export function tuple(refs) {
1964
1997
  const kind = getRefKind(refs);
@@ -1980,10 +2013,32 @@ const sampleRefSubject = (ref) =>
1980
2013
  Effect.gen(function* () {
1981
2014
  return yield* ref;
1982
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
+ }
1983
2038
  function makeCompositeVersioned(refs, current) {
1984
2039
  const version = Effect.map(Effect.all(refs.map((ref) => ref.version), UNBOUNDED), (versions) => versions.reduce(sum, 0));
1985
2040
  const changes = skipRepeats(fxMapEffect(fxMergeAll(...refs), () => current));
1986
- return Versioned.hold(Versioned.make(version, changes, current));
2041
+ return versionedInContext(() => Versioned.hold(Versioned.make(version, changes, current)));
1987
2042
  }
1988
2043
  class RefSubjectTuple extends YieldableFx {
1989
2044
  [ComputedTypeId] = ComputedTypeId;
@@ -1999,7 +2054,7 @@ class RefSubjectTuple extends YieldableFx {
1999
2054
  this.refs = refs;
2000
2055
  this.versioned = (refs.length > 0 && getTupleTransactionAccess(refs)
2001
2056
  ? makeCompositeVersioned(refs, Effect.all(refs.map(sampleRefSubject), UNBOUNDED))
2002
- : Versioned.hold(Versioned.tuple(refs)));
2057
+ : versionedInContext(() => Versioned.hold(Versioned.tuple(refs))));
2003
2058
  this.version = this.versioned.version;
2004
2059
  this.interrupt = Effect.all(refs.map((r) => r.interrupt), UNBOUNDED);
2005
2060
  this.subscriberCount = Effect.map(Effect.all(refs.map((r) => r.subscriberCount), UNBOUNDED), Array.reduce(0, sum));
@@ -2034,10 +2089,10 @@ class RefSubjectTuple extends YieldableFx {
2034
2089
  }
2035
2090
  }
2036
2091
  function makeTupleComputed(refs) {
2037
- return new ComputedImpl(Versioned.tuple(refs), Effect.succeed);
2092
+ return new ComputedImpl(versionedInContext(() => Versioned.tuple(refs)), Effect.succeed);
2038
2093
  }
2039
2094
  function makeTupleFiltered(refs) {
2040
- return new FilteredImpl(Versioned.tuple(refs), Effect.succeedSome);
2095
+ return new FilteredImpl(versionedInContext(() => Versioned.tuple(refs)), Effect.succeedSome);
2041
2096
  }
2042
2097
  function makeStructRef(refs) {
2043
2098
  return new RefSubjectStruct(refs);
@@ -2058,7 +2113,7 @@ class RefSubjectStruct extends YieldableFx {
2058
2113
  const current = Effect.map(Effect.all(keys.map((key) => sampleRefSubject(refs[key])), UNBOUNDED), (values) => Object.fromEntries(keys.map((key, index) => [key, values[index]])));
2059
2114
  this.versioned = (keys.length > 0 && getStructTransactionAccess(refs)
2060
2115
  ? makeCompositeVersioned(Object.values(refs), current)
2061
- : Versioned.hold(Versioned.struct(refs)));
2116
+ : versionedInContext(() => Versioned.hold(Versioned.struct(refs))));
2062
2117
  this.version = this.versioned.version;
2063
2118
  this.interrupt = Effect.all(Object.values(refs).map((r) => r.interrupt), UNBOUNDED);
2064
2119
  this.subscriberCount = Effect.map(Effect.all(Object.values(refs).map((r) => r.subscriberCount), UNBOUNDED), Array.reduce(0, sum));
@@ -2093,10 +2148,10 @@ class RefSubjectStruct extends YieldableFx {
2093
2148
  }
2094
2149
  }
2095
2150
  function makeStructComputed(refs) {
2096
- return new ComputedImpl(Versioned.struct(refs), Effect.succeed);
2151
+ return new ComputedImpl(versionedInContext(() => Versioned.struct(refs)), Effect.succeed);
2097
2152
  }
2098
2153
  function makeStructFiltered(refs) {
2099
- return new FilteredImpl(Versioned.struct(refs), Effect.succeedSome);
2154
+ return new FilteredImpl(versionedInContext(() => Versioned.struct(refs)), Effect.succeedSome);
2100
2155
  }
2101
2156
  /**
2102
2157
  * Lifts an Effect-provided Computed into a Computed facade.
@@ -2114,7 +2169,7 @@ function makeStructFiltered(refs) {
2114
2169
  * failures remain `E`, and the observing Scope owns the delegated subscription.
2115
2170
  *
2116
2171
  * @since 1.18.0
2117
- * @category combinators
2172
+ * @category Services
2118
2173
  */
2119
2174
  export function computedFromService(effect) {
2120
2175
  return new ComputedFromService(effect);
@@ -2152,7 +2207,7 @@ class ComputedFromService extends YieldableFx {
2152
2207
  * while absent; the observing Scope owns and finalizes its Fx subscription.
2153
2208
  *
2154
2209
  * @since 1.18.0
2155
- * @category combinators
2210
+ * @category Services
2156
2211
  */
2157
2212
  export function filteredFromService(effect) {
2158
2213
  return new FilteredFromService(effect);