@typed/fx 1.27.3 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/dist/cjs/AsyncData.js +1 -1
  2. package/dist/cjs/AsyncData.js.map +1 -1
  3. package/dist/cjs/Emitter.js +3 -3
  4. package/dist/cjs/Emitter.js.map +1 -1
  5. package/dist/cjs/Form.js +15 -15
  6. package/dist/cjs/Form.js.map +1 -1
  7. package/dist/cjs/FormEntry.js +3 -3
  8. package/dist/cjs/FormEntry.js.map +1 -1
  9. package/dist/cjs/Fx.js +11 -9
  10. package/dist/cjs/Fx.js.map +1 -1
  11. package/dist/cjs/Idle.js +8 -8
  12. package/dist/cjs/Idle.js.map +1 -1
  13. package/dist/cjs/Match.js +17 -17
  14. package/dist/cjs/Match.js.map +1 -1
  15. package/dist/cjs/Pull.js +3 -3
  16. package/dist/cjs/Pull.js.map +1 -1
  17. package/dist/cjs/Push.js +1 -1
  18. package/dist/cjs/Push.js.map +1 -1
  19. package/dist/cjs/RefArray.js +2 -2
  20. package/dist/cjs/RefArray.js.map +1 -1
  21. package/dist/cjs/RefChunk.js +1 -1
  22. package/dist/cjs/RefChunk.js.map +1 -1
  23. package/dist/cjs/RefHashMap.js +1 -1
  24. package/dist/cjs/RefHashMap.js.map +1 -1
  25. package/dist/cjs/RefHashSet.js +1 -1
  26. package/dist/cjs/RefHashSet.js.map +1 -1
  27. package/dist/cjs/RefSubject.js +150 -75
  28. package/dist/cjs/RefSubject.js.map +1 -1
  29. package/dist/cjs/Sink.js +14 -14
  30. package/dist/cjs/Sink.js.map +1 -1
  31. package/dist/cjs/Stream.js +1 -1
  32. package/dist/cjs/Stream.js.map +1 -1
  33. package/dist/cjs/Subject.js +27 -22
  34. package/dist/cjs/Subject.js.map +1 -1
  35. package/dist/cjs/Typeclass.js +1 -1
  36. package/dist/cjs/Typeclass.js.map +1 -1
  37. package/dist/cjs/Versioned.js +4 -4
  38. package/dist/cjs/Versioned.js.map +1 -1
  39. package/dist/cjs/index.js +1 -1
  40. package/dist/cjs/index.js.map +1 -1
  41. package/dist/cjs/internal/DeferredRef.js +14 -11
  42. package/dist/cjs/internal/DeferredRef.js.map +1 -1
  43. package/dist/cjs/internal/core.js +71 -42
  44. package/dist/cjs/internal/core.js.map +1 -1
  45. package/dist/cjs/internal/diff.js +1 -1
  46. package/dist/cjs/internal/diff.js.map +1 -1
  47. package/dist/cjs/internal/effect-loop-operator.js +1 -1
  48. package/dist/cjs/internal/effect-loop-operator.js.map +1 -1
  49. package/dist/cjs/internal/effect-operator.js +3 -3
  50. package/dist/cjs/internal/effect-operator.js.map +1 -1
  51. package/dist/cjs/internal/effect-producer.js +3 -3
  52. package/dist/cjs/internal/effect-producer.js.map +1 -1
  53. package/dist/cjs/internal/helpers.js +63 -42
  54. package/dist/cjs/internal/helpers.js.map +1 -1
  55. package/dist/cjs/internal/keyed.js +34 -26
  56. package/dist/cjs/internal/keyed.js.map +1 -1
  57. package/dist/cjs/internal/loop-operator.js +1 -1
  58. package/dist/cjs/internal/loop-operator.js.map +1 -1
  59. package/dist/cjs/internal/operator.js +1 -1
  60. package/dist/cjs/internal/operator.js.map +1 -1
  61. package/dist/cjs/internal/protos.js +1 -1
  62. package/dist/cjs/internal/protos.js.map +1 -1
  63. package/dist/cjs/internal/provide.js +1 -1
  64. package/dist/cjs/internal/provide.js.map +1 -1
  65. package/dist/cjs/internal/share.js +8 -13
  66. package/dist/cjs/internal/share.js.map +1 -1
  67. package/dist/cjs/internal/sync-operator.js +4 -4
  68. package/dist/cjs/internal/sync-operator.js.map +1 -1
  69. package/dist/cjs/internal/sync-producer.js +27 -23
  70. package/dist/cjs/internal/sync-producer.js.map +1 -1
  71. package/dist/cjs/internal/withKey.js +7 -7
  72. package/dist/cjs/internal/withKey.js.map +1 -1
  73. package/dist/dts/AsyncData.d.ts +2 -2
  74. package/dist/dts/AsyncData.d.ts.map +1 -1
  75. package/dist/dts/Emitter.d.ts +1 -1
  76. package/dist/dts/Emitter.d.ts.map +1 -1
  77. package/dist/dts/Fx.d.ts +39 -13
  78. package/dist/dts/Fx.d.ts.map +1 -1
  79. package/dist/dts/Idle.d.ts.map +1 -1
  80. package/dist/dts/Match.d.ts +1 -1
  81. package/dist/dts/Match.d.ts.map +1 -1
  82. package/dist/dts/Push.d.ts +4 -1
  83. package/dist/dts/Push.d.ts.map +1 -1
  84. package/dist/dts/RefArray.d.ts +1 -2
  85. package/dist/dts/RefArray.d.ts.map +1 -1
  86. package/dist/dts/RefChunk.d.ts.map +1 -1
  87. package/dist/dts/RefHashMap.d.ts +1 -1
  88. package/dist/dts/RefHashMap.d.ts.map +1 -1
  89. package/dist/dts/RefHashSet.d.ts.map +1 -1
  90. package/dist/dts/RefSubject.d.ts +64 -3
  91. package/dist/dts/RefSubject.d.ts.map +1 -1
  92. package/dist/dts/Sink.d.ts +2 -1
  93. package/dist/dts/Sink.d.ts.map +1 -1
  94. package/dist/dts/Subject.d.ts +2 -1
  95. package/dist/dts/Subject.d.ts.map +1 -1
  96. package/dist/dts/Versioned.d.ts +3 -1
  97. package/dist/dts/Versioned.d.ts.map +1 -1
  98. package/dist/dts/internal/DeferredRef.d.ts +6 -4
  99. package/dist/dts/internal/DeferredRef.d.ts.map +1 -1
  100. package/dist/dts/internal/core.d.ts +25 -12
  101. package/dist/dts/internal/core.d.ts.map +1 -1
  102. package/dist/dts/internal/diff.d.ts +1 -1
  103. package/dist/dts/internal/diff.d.ts.map +1 -1
  104. package/dist/dts/internal/effect-operator.d.ts.map +1 -1
  105. package/dist/dts/internal/helpers.d.ts +8 -6
  106. package/dist/dts/internal/helpers.d.ts.map +1 -1
  107. package/dist/dts/internal/keyed.d.ts +2 -2
  108. package/dist/dts/internal/keyed.d.ts.map +1 -1
  109. package/dist/dts/internal/loop-operator.d.ts +1 -1
  110. package/dist/dts/internal/loop-operator.d.ts.map +1 -1
  111. package/dist/dts/internal/protos.d.ts +1 -1
  112. package/dist/dts/internal/protos.d.ts.map +1 -1
  113. package/dist/dts/internal/provide.d.ts.map +1 -1
  114. package/dist/dts/internal/share.d.ts +1 -1
  115. package/dist/dts/internal/share.d.ts.map +1 -1
  116. package/dist/dts/internal/strategies.d.ts.map +1 -1
  117. package/dist/dts/internal/sync-operator.d.ts.map +1 -1
  118. package/dist/dts/internal/sync-producer.d.ts +4 -4
  119. package/dist/dts/internal/sync-producer.d.ts.map +1 -1
  120. package/dist/esm/Emitter.js +1 -1
  121. package/dist/esm/Emitter.js.map +1 -1
  122. package/dist/esm/Form.js +14 -14
  123. package/dist/esm/Form.js.map +1 -1
  124. package/dist/esm/FormEntry.js +2 -2
  125. package/dist/esm/FormEntry.js.map +1 -1
  126. package/dist/esm/Fx.js +16 -5
  127. package/dist/esm/Fx.js.map +1 -1
  128. package/dist/esm/Idle.js +7 -7
  129. package/dist/esm/Idle.js.map +1 -1
  130. package/dist/esm/Match.js +17 -17
  131. package/dist/esm/Match.js.map +1 -1
  132. package/dist/esm/Pull.js +2 -2
  133. package/dist/esm/Push.js.map +1 -1
  134. package/dist/esm/RefArray.js +1 -1
  135. package/dist/esm/RefArray.js.map +1 -1
  136. package/dist/esm/RefHashMap.js.map +1 -1
  137. package/dist/esm/RefSubject.js +140 -59
  138. package/dist/esm/RefSubject.js.map +1 -1
  139. package/dist/esm/Sink.js +13 -13
  140. package/dist/esm/Sink.js.map +1 -1
  141. package/dist/esm/Subject.js +29 -20
  142. package/dist/esm/Subject.js.map +1 -1
  143. package/dist/esm/Versioned.js +1 -1
  144. package/dist/esm/Versioned.js.map +1 -1
  145. package/dist/esm/internal/DeferredRef.js +13 -10
  146. package/dist/esm/internal/DeferredRef.js.map +1 -1
  147. package/dist/esm/internal/core.js +70 -37
  148. package/dist/esm/internal/core.js.map +1 -1
  149. package/dist/esm/internal/diff.js.map +1 -1
  150. package/dist/esm/internal/effect-operator.js +2 -2
  151. package/dist/esm/internal/effect-producer.js +1 -1
  152. package/dist/esm/internal/helpers.js +62 -39
  153. package/dist/esm/internal/helpers.js.map +1 -1
  154. package/dist/esm/internal/keyed.js +26 -17
  155. package/dist/esm/internal/keyed.js.map +1 -1
  156. package/dist/esm/internal/share.js +7 -12
  157. package/dist/esm/internal/share.js.map +1 -1
  158. package/dist/esm/internal/sync-operator.js +3 -3
  159. package/dist/esm/internal/sync-operator.js.map +1 -1
  160. package/dist/esm/internal/sync-producer.js +7 -5
  161. package/dist/esm/internal/sync-producer.js.map +1 -1
  162. package/dist/esm/internal/withKey.js +6 -6
  163. package/dist/esm/internal/withKey.js.map +1 -1
  164. package/package.json +8 -7
  165. package/src/Emitter.ts +2 -1
  166. package/src/Form.ts +22 -30
  167. package/src/FormEntry.ts +2 -2
  168. package/src/Fx.ts +54 -36
  169. package/src/Idle.ts +7 -7
  170. package/src/Match.ts +24 -26
  171. package/src/Pull.ts +2 -2
  172. package/src/Push.ts +4 -1
  173. package/src/RefArray.ts +1 -1
  174. package/src/RefHashMap.ts +1 -1
  175. package/src/RefSubject.ts +262 -98
  176. package/src/Sink.ts +15 -14
  177. package/src/Subject.ts +55 -39
  178. package/src/Versioned.ts +4 -2
  179. package/src/internal/DeferredRef.ts +21 -11
  180. package/src/internal/core.ts +92 -61
  181. package/src/internal/diff.ts +1 -1
  182. package/src/internal/effect-operator.ts +2 -2
  183. package/src/internal/effect-producer.ts +3 -3
  184. package/src/internal/helpers.ts +89 -42
  185. package/src/internal/keyed.ts +47 -42
  186. package/src/internal/loop-operator.ts +1 -1
  187. package/src/internal/protos.ts +1 -1
  188. package/src/internal/share.ts +11 -26
  189. package/src/internal/sync-operator.ts +3 -3
  190. package/src/internal/sync-producer.ts +7 -5
  191. package/src/internal/withKey.ts +6 -6
package/src/RefSubject.ts CHANGED
@@ -4,27 +4,31 @@
4
4
  */
5
5
 
6
6
  import * as C from "@typed/context"
7
- import type { Equivalence, FiberId, Runtime } from "effect"
8
- import { Fiber, MutableRef, Unify } from "effect"
7
+ import type { Tracer } from "effect"
8
+ import * as Array from "effect/Array"
9
9
  import * as Boolean from "effect/Boolean"
10
10
  import * as Cause from "effect/Cause"
11
11
  import * as Effect from "effect/Effect"
12
- import * as Equal from "effect/Equal"
12
+ import type * as Equivalence from "effect/Equivalence"
13
13
  import * as ExecutionStrategy from "effect/ExecutionStrategy"
14
14
  import * as Exit from "effect/Exit"
15
+ import * as Fiber from "effect/Fiber"
16
+ import type * as FiberId from "effect/FiberId"
15
17
  import { dual, identity } from "effect/Function"
16
18
  import * as Layer from "effect/Layer"
19
+ import * as MutableRef from "effect/MutableRef"
17
20
  import { sum } from "effect/Number"
18
21
  import * as Option from "effect/Option"
19
- import * as ReadonlyArray from "effect/ReadonlyArray"
22
+ import type * as Runtime from "effect/Runtime"
20
23
  import * as Scope from "effect/Scope"
24
+ import * as Unify from "effect/Unify"
21
25
  import { type Fx } from "./Fx.js"
22
- import * as core from "./internal/core.js"
26
+ import * as internal from "./internal/core.js"
23
27
  import * as DeferredRef from "./internal/DeferredRef.js"
24
28
  import { getExitEquivalence, matchEffectPrimitive, withScope } from "./internal/helpers.js"
25
29
  import { FxEffectBase } from "./internal/protos.js"
26
30
  import { runtimeToLayer } from "./internal/provide.js"
27
- import * as share from "./internal/share.js"
31
+ import { hold } from "./internal/share.js"
28
32
  import type { UnionToTuple } from "./internal/UnionToTuple.js"
29
33
  import * as Sink from "./Sink.js"
30
34
  import * as Subject from "./Subject.js"
@@ -33,6 +37,15 @@ import * as Versioned from "./Versioned.js"
33
37
 
34
38
  const UNBOUNDED = { concurrency: "unbounded" } as const
35
39
 
40
+ // TODO: Kind of a Hack, but I don't really want to pollute the public API with this. What should we do with this?
41
+ const CURRENT_ENVIRONMENT_TAG = C.Tagged<never, string>("@typed/environment/CurrentEnvironment")
42
+ const checkIsDOM = (ctx: C.Context<any>) =>
43
+ C.getOption(ctx, CURRENT_ENVIRONMENT_TAG).pipe(
44
+ Option.map((s) => s === "dom" || s === "test:dom"),
45
+ // Default behavior should allow multiple updates via Fx interface
46
+ Option.getOrElse(() => true)
47
+ )
48
+
36
49
  /**
37
50
  * A Computed is essentially a readonly RefSubject.
38
51
  * @since 1.20.0
@@ -143,9 +156,16 @@ export namespace RefSubject {
143
156
  * @since 1.20.0
144
157
  */
145
158
  readonly make: <R>(
146
- fxOrEffect: Fx<A, E, R> | Effect.Effect<A, E, R>,
147
- options?: RefSubjectOptions<A>
159
+ fxOrEffect: Fx<A, E, R | Scope.Scope> | Effect.Effect<A, E, R | Scope.Scope>,
160
+ options?: RefSubjectOptions<A> & { readonly drop?: number; readonly take?: number }
148
161
  ) => Layer.Layer<I, never, R>
162
+
163
+ /**
164
+ * @since 2.0.0
165
+ */
166
+ readonly layer: <E2, R2>(
167
+ make: Effect.Effect<RefSubject<A, E>, E2, R2 | Scope.Scope>
168
+ ) => Layer.Layer<I, E2, R2>
149
169
  }
150
170
 
151
171
  /**
@@ -213,7 +233,6 @@ export type Identifier<T> = RefSubject.Identifier<T>
213
233
  */
214
234
  export interface RefSubjectOptions<A> {
215
235
  readonly eq?: Equivalence.Equivalence<A>
216
- readonly replay?: number
217
236
  readonly executionStrategy?: ExecutionStrategy.ExecutionStrategy
218
237
  }
219
238
 
@@ -234,15 +253,17 @@ export function fromFx<A, E, R>(
234
253
  fx: Fx<A, E, R>,
235
254
  options?: RefSubjectOptions<A>
236
255
  ): Effect.Effect<RefSubject<A, E>, never, R | Scope.Scope> {
237
- return DeferredRef.make<E, A>(getExitEquivalence(options?.eq ?? Equal.equals)).pipe(
256
+ return DeferredRef.make<E, A>(getExitEquivalence(options?.eq ?? internal.deepEquals)).pipe(
238
257
  Effect.bindTo("deferredRef"),
239
258
  Effect.bind("core", ({ deferredRef }) => makeCore(deferredRef, options)),
240
259
  Effect.tap(({ core, deferredRef }) =>
241
260
  Effect.forkIn(
242
261
  fx.run(Sink.make(
243
262
  (cause) =>
244
- Effect.flatMap(Effect.sync(() => deferredRef.done(Exit.failCause(cause))), () =>
245
- core.subject.onFailure(cause)),
263
+ Effect.flatMap(
264
+ Effect.sync(() => deferredRef.done(Exit.failCause(cause))),
265
+ () => core.subject.onFailure(cause)
266
+ ),
246
267
  (value) =>
247
268
  Effect.flatMap(Effect.sync(() => deferredRef.done(Exit.succeed(value))), () => setCore(core, value))
248
269
  )),
@@ -260,7 +281,7 @@ export function fromRefSubject<A, E, R>(
260
281
  ref: RefSubject<A, E, R>,
261
282
  options?: RefSubjectOptions<A>
262
283
  ): Effect.Effect<RefSubject.Derived<A, E, R>, never, R | Scope.Scope> {
263
- return DeferredRef.make<E, A>(getExitEquivalence(options?.eq ?? Equal.equals)).pipe(
284
+ return DeferredRef.make<E, A>(getExitEquivalence(options?.eq ?? internal.deepEquals)).pipe(
264
285
  Effect.bindTo("deferredRef"),
265
286
  Effect.bind("core", ({ deferredRef }) => makeCore<A, E, R>(deferredRef, options)),
266
287
  Effect.tap(({ core, deferredRef }) =>
@@ -358,15 +379,21 @@ export function unsafeMake<E, A>(
358
379
  const { id, initial, options, scope } = params
359
380
  return Effect.flatMap(Effect.runtime(), (runtime) => {
360
381
  const core = unsafeMakeCore(initial, id, runtime, scope, options)
382
+ const current = MutableRef.get(core.deferredRef.current)
361
383
 
362
384
  // Sometimes we might be instantiating directly from a known value
363
385
  // Here we seed the value and ensure the subject has it as well for re-broadcasting
364
- if ("initialValue" in params) {
386
+ if ("initialValue" in params && Option.isNone(current)) {
365
387
  core.deferredRef.done(Exit.succeed(params.initialValue))
366
388
  return Effect.map(core.subject.onSuccess(params.initialValue), () => new RefSubjectImpl(core))
389
+ } else if (Option.isSome(current)) {
390
+ return Effect.map(
391
+ Effect.matchCauseEffect(current.value, core.subject),
392
+ () => new RefSubjectImpl(core)
393
+ )
394
+ } else {
395
+ return Effect.succeed(new RefSubjectImpl(core))
367
396
  }
368
-
369
- return Effect.succeed(new RefSubjectImpl(core))
370
397
  })
371
398
  }
372
399
 
@@ -411,7 +438,7 @@ class RefSubjectImpl<A, E, R, R2> extends FxEffectBase<A, E, Exclude<R, R2> | Sc
411
438
  }
412
439
 
413
440
  unsafeGet: () => Exit.Exit<A, E> = () =>
414
- Option.getOrThrowWith(this.core.deferredRef.current, () => new Cause.NoSuchElementException())
441
+ Option.getOrThrowWith(MutableRef.get(this.core.deferredRef.current), () => new Cause.NoSuchElementException())
415
442
 
416
443
  onSuccess(value: A): Effect.Effect<unknown, never, Exclude<R, R2>> {
417
444
  return setCore(this.core, value)
@@ -593,7 +620,7 @@ export const runUpdates: {
593
620
  Effect.tapErrorCause(Unify.unify((cause) =>
594
621
  Cause.isInterruptedOnly(cause)
595
622
  ? options.onInterrupt(initial)
596
- : Effect.unit
623
+ : Effect.void
597
624
  ))
598
625
  )
599
626
  )
@@ -607,7 +634,7 @@ export const runUpdates: {
607
634
  Effect.tapErrorCause(Unify.unify((cause) =>
608
635
  Cause.isInterruptedOnly(cause)
609
636
  ? Effect.flatMap(ref.get, options.onInterrupt)
610
- : Effect.unit
637
+ : Effect.void
611
638
  ))
612
639
  )
613
640
  )
@@ -619,12 +646,13 @@ export const runUpdates: {
619
646
  class RefSubjectCore<A, E, R, R2> {
620
647
  constructor(
621
648
  readonly initial: Effect.Effect<A, E, R>,
622
- readonly subject: Subject.Subject<A, E, R>,
649
+ readonly subject: Subject.HoldSubjectImpl<A, E>,
623
650
  readonly runtime: Runtime.Runtime<R2>,
624
651
  readonly scope: Scope.CloseableScope,
625
652
  readonly deferredRef: DeferredRef.DeferredRef<E, A>,
626
653
  readonly semaphore: Effect.Semaphore
627
- ) {}
654
+ ) {
655
+ }
628
656
 
629
657
  public _fiber: Fiber.Fiber<A, E> | undefined = undefined
630
658
  }
@@ -640,22 +668,9 @@ function makeCore<A, E, R>(
640
668
  "scope",
641
669
  ({ executionStrategy, runtime }) => Scope.fork(C.get(runtime.context, Scope.Scope), executionStrategy)
642
670
  ),
643
- Effect.bind(
644
- "deferredRef",
645
- () => DeferredRef.make<E, A>(getExitEquivalence(options?.eq ?? Equal.equals))
646
- ),
647
- Effect.let("subject", () => Subject.unsafeMake<A, E>(Math.max(1, options?.replay ?? 1))),
648
- Effect.tap(({ scope, subject }) => Scope.addFinalizer(scope, subject.interrupt)),
649
- Effect.map(({ deferredRef, runtime, scope, subject }) =>
650
- new RefSubjectCore(
651
- initial,
652
- subject,
653
- runtime,
654
- scope,
655
- deferredRef,
656
- Effect.unsafeMakeSemaphore(1)
657
- )
658
- )
671
+ Effect.bind("id", () => Effect.fiberId),
672
+ Effect.map(({ id, runtime, scope }) => unsafeMakeCore(initial, id, runtime, scope, options)),
673
+ Effect.tap((core) => Scope.addFinalizer(core.scope, Effect.provide(core.subject.interrupt, core.runtime.context)))
659
674
  )
660
675
  }
661
676
 
@@ -666,14 +681,33 @@ function unsafeMakeCore<A, E, R>(
666
681
  scope: Scope.CloseableScope,
667
682
  options?: RefSubjectOptions<A>
668
683
  ) {
669
- return new RefSubjectCore(
684
+ const subject = new Subject.HoldSubjectImpl<A, E>()
685
+ const core = new RefSubjectCore(
670
686
  initial,
671
- Subject.unsafeMake<A, E>(Math.max(1, options?.replay ?? 1)),
687
+ subject,
672
688
  runtime,
673
689
  scope,
674
- DeferredRef.unsafeMake(id, getExitEquivalence(options?.eq ?? Equal.equals)),
690
+ DeferredRef.unsafeMake(id, getExitEquivalence(options?.eq ?? internal.deepEquals), subject.lastValue),
675
691
  Effect.unsafeMakeSemaphore(1)
676
692
  )
693
+
694
+ const onSuccess = (a: A) => core.deferredRef.done(Exit.succeed(a))
695
+ const onCause = (cause: Cause.Cause<E>) => core.deferredRef.done(Exit.failCause(cause))
696
+ const onError = (e: E) => onCause(Cause.fail(e))
697
+
698
+ // Initialize the core with the initial value if it is synchronous
699
+ matchEffectPrimitive(initial, {
700
+ Success: onSuccess,
701
+ Failure: onCause,
702
+ Some: onSuccess,
703
+ None: onError,
704
+ Left: onError,
705
+ Right: onSuccess,
706
+ Sync: (f) => onSuccess(f()),
707
+ Otherwise: () => false
708
+ })
709
+
710
+ return core
677
711
  }
678
712
 
679
713
  function getOrInitializeCore<A, E, R, R2>(
@@ -681,7 +715,7 @@ function getOrInitializeCore<A, E, R, R2>(
681
715
  lockInitialize: boolean
682
716
  ): Effect.Effect<A, E, Exclude<R, R2>> {
683
717
  return Effect.suspend(() => {
684
- if (core._fiber === undefined && Option.isNone(core.deferredRef.current)) {
718
+ if (core._fiber === undefined && Option.isNone(MutableRef.get(core.deferredRef.current))) {
685
719
  return initializeCoreAndTap(core, lockInitialize)
686
720
  } else {
687
721
  return core.deferredRef
@@ -704,7 +738,7 @@ function initializeCoreEffect<A, E, R, R2>(
704
738
 
705
739
  return Effect.flatMap(
706
740
  Effect.forkIn(
707
- lock && core.semaphore ? core.semaphore.withPermits(1)(initialize) : initialize,
741
+ lock ? core.semaphore.withPermits(1)(initialize) : initialize,
708
742
  core.scope
709
743
  ),
710
744
  (fiber) => Effect.sync(() => core._fiber = fiber)
@@ -736,7 +770,7 @@ function initializeCore<A, E, R, R2>(
736
770
  None: onError,
737
771
  Left: onError,
738
772
  Right: onSuccess,
739
- Sync: (f) => onSuccess(f()),
773
+ Sync: (f) => Effect.suspend(() => onSuccess(f())),
740
774
  Otherwise: () => initializeCoreEffect(core, lock)
741
775
  })
742
776
  }
@@ -772,7 +806,7 @@ function onFailureCore<A, E, R, R2>(core: RefSubjectCore<A, E, R, R2>, cause: Ca
772
806
  if (core.deferredRef.done(exit)) {
773
807
  return sendEvent(core, exit)
774
808
  } else {
775
- return Effect.unit
809
+ return Effect.void
776
810
  }
777
811
  })
778
812
  }
@@ -782,7 +816,7 @@ function interruptCore<A, E, R, R2>(core: RefSubjectCore<A, E, R, R2>): Effect.E
782
816
  core.deferredRef.reset()
783
817
 
784
818
  const closeScope = Scope.close(core.scope, Exit.interrupt(id))
785
- const interruptFiber = core._fiber ? Fiber.interrupt(core._fiber) : Effect.unit
819
+ const interruptFiber = core._fiber ? Fiber.interrupt(core._fiber) : Effect.void
786
820
  const interruptSubject = core.subject.interrupt
787
821
 
788
822
  return Effect.all([closeScope, interruptFiber, interruptSubject], { discard: true })
@@ -793,7 +827,7 @@ function deleteCore<A, E, R, R2>(
793
827
  core: RefSubjectCore<A, E, R, R2>
794
828
  ): Effect.Effect<Option.Option<A>, E, Exclude<R, R2>> {
795
829
  return Effect.suspend(() => {
796
- const current = core.deferredRef.current
830
+ const current = MutableRef.get(core.deferredRef.current)
797
831
  core.deferredRef.reset()
798
832
 
799
833
  if (Option.isNone(current)) {
@@ -803,7 +837,7 @@ function deleteCore<A, E, R, R2>(
803
837
  return core.subject.subscriberCount.pipe(
804
838
  Effect.provide(core.runtime.context),
805
839
  Effect.flatMap(
806
- (count: number) => count > 0 && !core._fiber ? initializeCore(core, false) : Effect.unit
840
+ (count: number) => count > 0 && !core._fiber ? initializeCore(core, false) : Effect.void
807
841
  ),
808
842
  Effect.zipRight(Effect.asSome(current.value))
809
843
  )
@@ -1039,6 +1073,7 @@ class ComputedImpl<R0, E0, A, E, R, E2, R2, C, E3, R3> extends Versioned.Version
1039
1073
  R0 | Exclude<R, Scope.Scope> | R2 | R3
1040
1074
  > implements Computed<C, E0 | E | E2 | E3, R0 | Exclude<R, Scope.Scope> | R2 | R3> {
1041
1075
  readonly [ComputedTypeId]: ComputedTypeId = ComputedTypeId
1076
+ private _computed: Fx<C, E0 | E | E2 | E3, R0 | R | Scope.Scope | R2 | R3>
1042
1077
 
1043
1078
  constructor(
1044
1079
  readonly input: Versioned.Versioned<R0, E0, A, E, R, A, E2, R2>,
@@ -1046,9 +1081,28 @@ class ComputedImpl<R0, E0, A, E, R, E2, R2, C, E3, R3> extends Versioned.Version
1046
1081
  ) {
1047
1082
  super(
1048
1083
  input,
1049
- (fx) => share.hold(core.mapEffect(fx, f)) as any,
1084
+ (fx) => internal.mapEffect(fx, f) as any,
1050
1085
  Effect.flatMap(f)
1051
1086
  )
1087
+
1088
+ this._computed = hold(internal.fromFxEffect(
1089
+ Effect.contextWith((ctx: C.Context<R0 | R | Scope.Scope | R2 | R3>) => {
1090
+ if (checkIsDOM(ctx)) {
1091
+ return internal.fromEffect(input).pipe(
1092
+ (_) => internal.continueWith(_, () => input),
1093
+ internal.skipRepeats,
1094
+ (_) => internal.mapEffect(_, f),
1095
+ internal.skipRepeats
1096
+ )
1097
+ }
1098
+
1099
+ return internal.fromEffect(Effect.flatMap(input, f))
1100
+ })
1101
+ ))
1102
+ }
1103
+
1104
+ run<R4>(sink: Sink.Sink<C, E0 | E | E2 | E3, R4>) {
1105
+ return this._computed.run(sink) as any
1052
1106
  }
1053
1107
 
1054
1108
  unsafeGet: () => Exit.Exit<C, E0 | E | E2 | E3> = () =>
@@ -1073,12 +1127,13 @@ class FilteredImpl<R0, E0, A, E, R, E2, R2, C, E3, R3> extends Versioned.Version
1073
1127
  R2,
1074
1128
  C,
1075
1129
  E0 | E | E2 | E3,
1076
- Exclude<R, Scope.Scope> | R2 | R3 | Scope.Scope,
1130
+ R0 | Exclude<R, Scope.Scope> | R2 | R3 | Scope.Scope,
1077
1131
  C,
1078
1132
  E0 | E | E2 | E3 | Cause.NoSuchElementException,
1079
- R0 | Exclude<R, Scope.Scope> | R2 | R3 | R2 | R3
1080
- > implements Filtered<C, E0 | E | E2 | E3, R0 | Exclude<R, Scope.Scope> | R2 | R3 | R2 | R3> {
1133
+ R0 | Exclude<R, Scope.Scope> | R2 | R3
1134
+ > implements Filtered<C, E0 | E | E2 | E3, R0 | Exclude<R, Scope.Scope> | R2 | R3> {
1081
1135
  readonly [FilteredTypeId]: FilteredTypeId = FilteredTypeId
1136
+ private _filtered: Fx<C, E | E2 | E3, Scope.Scope | R0 | R | R2 | R3 | Exclude<R, Scope.Scope>>
1082
1137
 
1083
1138
  constructor(
1084
1139
  readonly input: Versioned.Versioned<R0, E0, A, E, R, A, E2, R2>,
@@ -1086,9 +1141,27 @@ class FilteredImpl<R0, E0, A, E, R, E2, R2, C, E3, R3> extends Versioned.Version
1086
1141
  ) {
1087
1142
  super(
1088
1143
  input,
1089
- (fx) => share.hold(core.filterMapEffect(fx, f)) as any,
1144
+ (fx) => internal.filterMapEffect(fx, f) as any,
1090
1145
  (effect) => Effect.flatten(Effect.flatMap(effect, f))
1091
1146
  )
1147
+
1148
+ this._filtered = hold(internal.fromFxEffect(
1149
+ Effect.contextWith((ctx: C.Context<R0 | Exclude<R, Scope.Scope> | R2 | R3 | Scope.Scope>) => {
1150
+ if (checkIsDOM(ctx)) {
1151
+ return internal.fromEffect(input).pipe(
1152
+ (_) => internal.continueWith(_, () => input),
1153
+ internal.skipRepeats,
1154
+ (_) => internal.filterMapEffect(_, f),
1155
+ internal.skipRepeats
1156
+ )
1157
+ }
1158
+
1159
+ return Effect.flatMap(input, f).pipe(
1160
+ internal.fromEffect,
1161
+ (_) => internal.filterMap(_, identity)
1162
+ )
1163
+ })
1164
+ ))
1092
1165
  }
1093
1166
 
1094
1167
  static make<R0, E0, A, E, R, E2, R2, C, E3, R3>(
@@ -1106,6 +1179,10 @@ class FilteredImpl<R0, E0, A, E, R, E2, R2, C, E3, R3> extends Versioned.Version
1106
1179
  return ComputedImpl.make(this.input, this.f)
1107
1180
  }
1108
1181
 
1182
+ run<R4>(sink: Sink.Sink<C, E0 | E | E2 | E3, R4>) {
1183
+ return this._filtered.run(sink) as any
1184
+ }
1185
+
1109
1186
  unsafeGet: () => Exit.Exit<C, Cause.NoSuchElementException | E0 | E | E2 | E3> = () =>
1110
1187
  Option.getOrThrowWith(this._currentValue, () => new Cause.NoSuchElementException())
1111
1188
  }
@@ -1136,7 +1213,7 @@ export const skipRepeatsWith: {
1136
1213
  ref: RefSubject<A, E, R> | Computed<A, E, R> | Filtered<A, E, R>,
1137
1214
  eq: Equivalence.Equivalence<A>
1138
1215
  ): Computed<A, E, R> | Filtered<A, E, R> {
1139
- const versioned = Versioned.transform(ref, (fx) => core.skipRepeatsWith(fx, eq), identity)
1216
+ const versioned = Versioned.transform(ref, (fx) => internal.skipRepeatsWith(fx, eq), identity)
1140
1217
 
1141
1218
  if (FilteredTypeId in ref) {
1142
1219
  return FilteredImpl.make(versioned, Effect.succeedSome)
@@ -1163,7 +1240,7 @@ export function skipRepeats<A, E, R>(
1163
1240
  export function skipRepeats<A, E, R>(
1164
1241
  ref: RefSubject<A, E, R> | Computed<A, E, R> | Filtered<A, E, R>
1165
1242
  ): Computed<A, E, R> | Filtered<A, E, R> {
1166
- return skipRepeatsWith(ref, Equal.equals)
1243
+ return skipRepeatsWith(ref, internal.deepEquals)
1167
1244
  }
1168
1245
 
1169
1246
  /**
@@ -1270,8 +1347,8 @@ class RefSubjectTransformEffect<A, E, R, B, E2, R2, R3, E3>
1270
1347
  }
1271
1348
 
1272
1349
  run<R4 = never>(sink: Sink.Sink<B, E | E2 | E3, R4>): Effect.Effect<unknown, never, R | R2 | R3 | Scope.Scope | R4> {
1273
- return core.skipRepeats(
1274
- core.merge(core.tapEffect(core.mapEffect(this.ref, this.from), this.subject.onSuccess), this.subject)
1350
+ return internal.skipRepeats(
1351
+ internal.merge(internal.tapEffect(internal.mapEffect(this.ref, this.from), this.subject.onSuccess), this.subject)
1275
1352
  ).run(
1276
1353
  sink
1277
1354
  )
@@ -1481,7 +1558,7 @@ class RefSubjectTuple<
1481
1558
  this.interrupt = Effect.all(refs.map((r) => r.interrupt), UNBOUNDED)
1482
1559
  this.subscriberCount = Effect.map(
1483
1560
  Effect.all(refs.map((r) => r.subscriberCount), UNBOUNDED),
1484
- ReadonlyArray.reduce(0, sum)
1561
+ Array.reduce(0, sum)
1485
1562
  )
1486
1563
 
1487
1564
  this.getSetDelete = {
@@ -1652,7 +1729,7 @@ class RefSubjectStruct<
1652
1729
  this.interrupt = Effect.all(Object.values(refs).map((r) => r.interrupt), UNBOUNDED)
1653
1730
  this.subscriberCount = Effect.map(
1654
1731
  Effect.all(Object.values(refs).map((r) => r.subscriberCount), UNBOUNDED),
1655
- ReadonlyArray.reduce(0, sum)
1732
+ Array.reduce(0, sum)
1656
1733
  )
1657
1734
 
1658
1735
  this.getSetDelete = {
@@ -1865,10 +1942,23 @@ class RefSubjectTagged<I, E, A> extends FxEffectBase<
1865
1942
  return this.tag.withEffect((ref) => ref.onSuccess(value))
1866
1943
  }
1867
1944
 
1945
+ layer = <E2, R2>(make: Effect.Effect<RefSubject<A, E>, E2, R2 | Scope.Scope>): Layer.Layer<I, E2, R2> =>
1946
+ this.tag.scoped(make)
1947
+
1868
1948
  make = <R>(
1869
- fxOrEffect: Fx<A, E, R> | Effect.Effect<A, E, R>,
1870
- options?: RefSubjectOptions<A>
1871
- ): Layer.Layer<I, never, R> => this.tag.scoped(make(fxOrEffect, options))
1949
+ fxOrEffect: Fx<A, E, R | Scope.Scope> | Effect.Effect<A, E, R | Scope.Scope>,
1950
+ options?: RefSubjectOptions<A> & { readonly drop?: number; readonly take?: number }
1951
+ ): Layer.Layer<I, never, R> => {
1952
+ return this.tag.scoped(Effect.gen(function*(_) {
1953
+ let ref = yield* make(fxOrEffect, options)
1954
+
1955
+ if (options?.drop || options?.take) {
1956
+ ref = slice(ref, options.drop ?? 0, options.take ?? Infinity)
1957
+ }
1958
+
1959
+ return ref
1960
+ }))
1961
+ }
1872
1962
  }
1873
1963
 
1874
1964
  /**
@@ -1906,7 +1996,7 @@ class RefSubjectFromTag<I, S, A, E, R> extends FxEffectBase<
1906
1996
  super()
1907
1997
 
1908
1998
  this._get = Effect.map(tag, f)
1909
- this._fx = core.fromFxEffect(this._get)
1999
+ this._fx = internal.fromFxEffect(this._get)
1910
2000
 
1911
2001
  this.version = Effect.flatMap(this._get, (ref) => ref.version)
1912
2002
  this.interrupt = Effect.flatMap(this._get, (ref) => ref.interrupt)
@@ -2221,7 +2311,7 @@ export const slice: {
2221
2311
  } = dual(
2222
2312
  3,
2223
2313
  function slice<A, E, R>(ref: RefSubject<A, E, R>, drop: number, take: number): RefSubject<A, E, R> {
2224
- return new RefSubjectSlice(ref, drop, take)
2314
+ return new RefSubjectSimpleTransform(ref, (_) => internal.slice(_, drop, take), identity)
2225
2315
  }
2226
2316
  )
2227
2317
 
@@ -2245,35 +2335,121 @@ export const take: {
2245
2335
  return slice(ref, 0, take)
2246
2336
  })
2247
2337
 
2248
- class RefSubjectSlice<A, E, R> extends FxEffectBase<A, E, R | Scope.Scope, A, E, R> implements RefSubject<A, E, R> {
2338
+ /**
2339
+ * Get the current value of the RefSubject. If it has not been set yet, a Fiber will be used to wait for the value to be set.
2340
+ *
2341
+ * @since 1.25.0
2342
+ */
2343
+ export const get: {
2344
+ <A, E = never, R = never>(ref: RefSubject<A, E, R>): Effect.Effect<A, E, R>
2345
+ <A, E = never, R = never>(ref: Computed<A, E, R>): Effect.Effect<A, E, R>
2346
+ <A, E = never, R = never>(ref: Filtered<A, E, R>): Effect.Effect<A, E | Cause.NoSuchElementException, R>
2347
+ } = <A, E, R>(
2348
+ ref: RefSubject<A, E, R> | Computed<A, E, R> | Filtered<A, E, R>
2349
+ ): Effect.Effect<A, E | Cause.NoSuchElementException, R> => ref
2350
+
2351
+ /**
2352
+ * Synchronously get the current Exit value of the RefSubject. If it has not been set yet, a Cause.NoSuchElementException will be thrown.
2353
+ *
2354
+ * Note: This is unimplemented for RefSubject.tagged and RefSubject.fromTag because they require the Effect context by definition.
2355
+ * It will throw immediately.
2356
+ *
2357
+ * @since 1.25.0
2358
+ */
2359
+ export const unsafeGetExit = <A, E = never, R = never>(ref: RefSubject<A, E, R>): Exit.Exit<A, E> => ref.unsafeGet()
2360
+
2361
+ /**
2362
+ * Synchronously get the current value of the RefSubject.
2363
+ *
2364
+ * @since 1.25.0
2365
+ */
2366
+ export const unsafeGet = <A, E = never, R = never>(ref: RefSubject<A, E, R>): A => Effect.runSync(unsafeGetExit(ref))
2367
+
2368
+ /**
2369
+ * Extract all values from an object using a Proxy
2370
+ *
2371
+ * @since 2.0.0
2372
+ */
2373
+ export const proxy: {
2374
+ <A extends ReadonlyArray<any> | Readonly<Record<PropertyKey, any>>, E, R>(
2375
+ source: Computed<A, E, R>
2376
+ ): { readonly [K in keyof A]: Computed<A[K], E, R> }
2377
+
2378
+ <A extends ReadonlyArray<any> | Readonly<Record<PropertyKey, any>>, E, R>(
2379
+ source: Filtered<A, E, R>
2380
+ ): { readonly [K in keyof A]: Filtered<A[K], E, R> }
2381
+ } = <
2382
+ A extends Readonly<Record<PropertyKey, any>> | ReadonlyArray<any>,
2383
+ E,
2384
+ R
2385
+ >(
2386
+ source: Computed<A, E, R> | Filtered<A, E, R>
2387
+ ): any => {
2388
+ const target: any = {}
2389
+ return new Proxy(target, {
2390
+ get(self, prop) {
2391
+ if (prop in self) return self[prop]
2392
+ return self[prop] = map(source, (a) => a[prop as keyof A])
2393
+ }
2394
+ })
2395
+ }
2396
+
2397
+ /**
2398
+ * @since 2.0.0
2399
+ */
2400
+ export const withSpan: {
2401
+ (name: string, options?: {
2402
+ readonly attributes?: Record<string, unknown>
2403
+ readonly links?: ReadonlyArray<Tracer.SpanLink>
2404
+ readonly parent?: Tracer.ParentSpan
2405
+ readonly root?: boolean
2406
+ readonly context?: C.Context<never>
2407
+ }): <A, E, R>(self: RefSubject<A, E, R>) => RefSubject<A, E, R>
2408
+
2409
+ <A, E, R>(self: RefSubject<A, E, R>, name: string, options?: {
2410
+ readonly attributes?: Record<string, unknown>
2411
+ readonly links?: ReadonlyArray<Tracer.SpanLink>
2412
+ readonly parent?: Tracer.ParentSpan
2413
+ readonly root?: boolean
2414
+ readonly context?: C.Context<never>
2415
+ }): RefSubject<A, E, R>
2416
+ } = dual(
2417
+ isRefSubjectDataFirst,
2418
+ (ref, name, options) =>
2419
+ new RefSubjectSimpleTransform(ref, (fx) => internal.withSpan(fx, name, options), Effect.withSpan(name, options))
2420
+ )
2421
+
2422
+ class RefSubjectSimpleTransform<A, E, R, R2, R3> extends FxEffectBase<A, E, R | R2 | Scope.Scope, A, E, R | R3>
2423
+ implements RefSubject<A, E, R | R2 | R3>
2424
+ {
2249
2425
  readonly [ComputedTypeId]: ComputedTypeId = ComputedTypeId
2250
2426
  readonly [RefSubjectTypeId]: RefSubjectTypeId = RefSubjectTypeId
2251
2427
 
2252
2428
  readonly version: Effect.Effect<number, E, R>
2253
2429
  readonly interrupt: Effect.Effect<void, never, R>
2254
2430
  readonly subscriberCount: Effect.Effect<number, never, R>
2255
- private _fx: Fx<A, E, Scope.Scope | R>
2431
+ private _fx: Fx<A, E, Scope.Scope | R | R2>
2256
2432
 
2257
2433
  constructor(
2258
2434
  readonly ref: RefSubject<A, E, R>,
2259
- readonly drop: number,
2260
- readonly take: number
2435
+ readonly transformFx: (fx: Fx<A, E, Scope.Scope | R>) => Fx<A, E, Scope.Scope | R | R2>,
2436
+ readonly transformEffect: (effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R | R3>
2261
2437
  ) {
2262
2438
  super()
2263
2439
 
2264
2440
  this.version = ref.version
2265
2441
  this.interrupt = ref.interrupt
2266
2442
  this.subscriberCount = ref.subscriberCount
2267
- this._fx = share.hold(core.slice(ref, drop, take))
2268
- this._effect = ref
2443
+
2444
+ this._fx = transformFx(ref)
2269
2445
  }
2270
2446
 
2271
- run<R2>(sink: Sink.Sink<A, E, R2>): Effect.Effect<unknown, never, R | R2 | Scope.Scope> {
2447
+ run<R4>(sink: Sink.Sink<A, E, R4>) {
2272
2448
  return this._fx.run(sink)
2273
2449
  }
2274
2450
 
2275
- toEffect(): Effect.Effect<A, E, R> {
2276
- return this.ref
2451
+ toEffect(): Effect.Effect<A, E, R | R3> {
2452
+ return this.transformEffect(this.ref)
2277
2453
  }
2278
2454
 
2279
2455
  runUpdates<E2, R2, C>(
@@ -2294,31 +2470,19 @@ class RefSubjectSlice<A, E, R> extends FxEffectBase<A, E, R | Scope.Scope, A, E,
2294
2470
  }
2295
2471
 
2296
2472
  /**
2297
- * Get the current value of the RefSubject. If it has not been set yet, a Fiber will be used to wait for the value to be set.
2298
- *
2299
- * @since 1.25.0
2300
- */
2301
- export const get: {
2302
- <A, E = never, R = never>(ref: RefSubject<A, E, R>): Effect.Effect<A, E, R>
2303
- <A, E = never, R = never>(ref: Computed<A, E, R>): Effect.Effect<A, E, R>
2304
- <A, E = never, R = never>(ref: Filtered<A, E, R>): Effect.Effect<A, E | Cause.NoSuchElementException, R>
2305
- } = <A, E, R>(
2306
- ref: RefSubject<A, E, R> | Computed<A, E, R> | Filtered<A, E, R>
2307
- ): Effect.Effect<A, E | Cause.NoSuchElementException, R> => ref
2308
-
2309
- /**
2310
- * Synchronously get the current Exit value of the RefSubject. If it has not been set yet, a Cause.NoSuchElementException will be thrown.
2311
- *
2312
- * Note: This is unimplemented for RefSubject.tagged and RefSubject.fromTag because they require the Effect context by definition.
2313
- * It will throw immediately.
2314
- *
2315
- * @since 1.25.0
2473
+ * @since 2.0.0
2316
2474
  */
2317
- export const unsafeGetExit = <A, E = never, R = never>(ref: RefSubject<A, E, R>): Exit.Exit<A, E> => ref.unsafeGet()
2475
+ export const when: {
2476
+ <B, C>(options: { onTrue: B; onFalse: C }): {
2477
+ <E, R>(ref: Filtered<boolean, E, R>): Filtered<B | C, E, R>
2478
+ <E, R>(ref: Computed<boolean, E, R>): Computed<B | C, E, R>
2479
+ }
2318
2480
 
2319
- /**
2320
- * Synchronously get the current value of the RefSubject.
2321
- *
2322
- * @since 1.25.0
2323
- */
2324
- export const unsafeGet = <A, E = never, R = never>(ref: RefSubject<A, E, R>): A => Effect.runSync(unsafeGetExit(ref))
2481
+ <E, R, B, C>(ref: Filtered<boolean, E, R>, options: { onTrue: B; onFalse: C }): Filtered<B | C, E, R>
2482
+ <E, R, B, C>(ref: Computed<boolean, E, R>, options: { onTrue: B; onFalse: C }): Computed<B | C, E, R>
2483
+ } = dual(2, function when<E, R, B, C>(ref: Computed<boolean, E, R> | Filtered<boolean, E, R>, options: {
2484
+ onTrue: B
2485
+ onFalse: C
2486
+ }): any {
2487
+ return map(ref, (a) => a ? options.onTrue : options.onFalse)
2488
+ })