@typed/fx 1.17.1 → 1.17.2
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.
- package/dist/RefRemoteData.d.ts +44 -0
- package/dist/RefRemoteData.d.ts.map +1 -0
- package/dist/RefRemoteData.js +61 -0
- package/dist/RefRemoteData.js.map +1 -0
- package/dist/RefSubject.d.ts +1 -0
- package/dist/RefSubject.d.ts.map +1 -1
- package/dist/RefSubject.js +12 -1
- package/dist/RefSubject.js.map +1 -1
- package/dist/cjs/RefRemoteData.d.ts +44 -0
- package/dist/cjs/RefRemoteData.d.ts.map +1 -0
- package/dist/cjs/RefRemoteData.js +91 -0
- package/dist/cjs/RefRemoteData.js.map +1 -0
- package/dist/cjs/RefSubject.d.ts +1 -0
- package/dist/cjs/RefSubject.d.ts.map +1 -1
- package/dist/cjs/RefSubject.js +12 -1
- package/dist/cjs/RefSubject.js.map +1 -1
- package/dist/cjs/data-first.d.ts +1 -0
- package/dist/cjs/data-first.d.ts.map +1 -1
- package/dist/cjs/data-first.js +1 -0
- package/dist/cjs/data-first.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/data-first.d.ts +1 -0
- package/dist/data-first.d.ts.map +1 -1
- package/dist/data-first.js +1 -0
- package/dist/data-first.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.cjs.build.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/RefRemoteData.ts +182 -0
- package/src/RefSubject.ts +30 -5
- package/src/data-first.ts +1 -0
- package/src/index.ts +1 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.cjs.build.json +5 -1
- package/tsconfig.json +6 -2
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as Either from '@effect/data/Either'
|
|
2
|
+
import * as Equivalence from '@effect/data/Equivalence'
|
|
3
|
+
import * as Option from '@effect/data/Option'
|
|
4
|
+
import * as Cause from '@effect/io/Cause'
|
|
5
|
+
import * as Effect from '@effect/io/Effect'
|
|
6
|
+
import * as Exit from '@effect/io/Exit'
|
|
7
|
+
import * as Fiber from '@effect/io/Fiber'
|
|
8
|
+
import * as SynchronizedRef from '@effect/io/Ref/Synchronized'
|
|
9
|
+
import * as Scope from '@effect/io/Scope'
|
|
10
|
+
import * as RemoteData from '@typed/remote-data'
|
|
11
|
+
import fastDeepEqual from 'fast-deep-equal'
|
|
12
|
+
|
|
13
|
+
import { Computed } from './Computed.js'
|
|
14
|
+
import { Fx } from './Fx.js'
|
|
15
|
+
import { RefSubject, makeRef } from './RefSubject.js'
|
|
16
|
+
import { drain } from './observe.js'
|
|
17
|
+
import { skipWhile } from './skipWhile.js'
|
|
18
|
+
import { take } from './slice.js'
|
|
19
|
+
import { switchMap } from './switchMap.js'
|
|
20
|
+
|
|
21
|
+
export interface RefRemoteData<E, A> extends RefSubject<never, RemoteData.RemoteData<E, A>> {
|
|
22
|
+
// Constructors/Setters
|
|
23
|
+
readonly succeed: (value: A) => Effect.Effect<never, never, RemoteData.RemoteData<E, A>>
|
|
24
|
+
readonly failCause: (
|
|
25
|
+
error: Cause.Cause<E>,
|
|
26
|
+
) => Effect.Effect<never, never, RemoteData.RemoteData<E, A>>
|
|
27
|
+
readonly fail: (error: E) => Effect.Effect<never, never, RemoteData.RemoteData<E, A>>
|
|
28
|
+
readonly fromExit: (
|
|
29
|
+
exit: Exit.Exit<E, A>,
|
|
30
|
+
) => Effect.Effect<never, never, RemoteData.RemoteData<E, A>>
|
|
31
|
+
readonly fromEither: (
|
|
32
|
+
either: Either.Either<E, A>,
|
|
33
|
+
) => Effect.Effect<never, never, RemoteData.RemoteData<E, A>>
|
|
34
|
+
readonly fromOption: (
|
|
35
|
+
option: Option.Option<A>,
|
|
36
|
+
) => Effect.Effect<never, never, RemoteData.RemoteData<E, A>>
|
|
37
|
+
|
|
38
|
+
// Computed
|
|
39
|
+
readonly mapValueEffect: <R2, E2, B>(
|
|
40
|
+
f: (a: A) => Effect.Effect<R2, E2, B>,
|
|
41
|
+
) => Computed<R2, E2, RemoteData.RemoteData<E, B>>
|
|
42
|
+
readonly mapValue: <B>(f: (a: A) => B) => Computed<never, never, RemoteData.RemoteData<E, B>>
|
|
43
|
+
|
|
44
|
+
// Effects
|
|
45
|
+
readonly runEffect: <R>(
|
|
46
|
+
effect: Effect.Effect<R, E, A>,
|
|
47
|
+
) => Effect.Effect<R | Scope.Scope, never, boolean>
|
|
48
|
+
|
|
49
|
+
readonly awaitNotLoading: Effect.Effect<Scope.Scope, never, void>
|
|
50
|
+
|
|
51
|
+
// Matching
|
|
52
|
+
readonly matchFx: <R2, E2, B, R3, E3, C, R4, E4, D, R5, E5, F>(options: {
|
|
53
|
+
onNoData: () => Fx<R2, E2, B>
|
|
54
|
+
onLoading: () => Fx<R3, E3, C>
|
|
55
|
+
onFailure: (cause: Cause.Cause<E>, refreshing: boolean) => Fx<R4, E4, D>
|
|
56
|
+
onSuccess: (value: A, refreshing: boolean) => Fx<R5, E5, F>
|
|
57
|
+
}) => Fx<R2 | R3 | R4 | R5, E2 | E3 | E4 | E5, B | C | D | F>
|
|
58
|
+
|
|
59
|
+
readonly matchEffect: <R2, E2, B, R3, E3, C, R4, E4, D, R5, E5, F>(options: {
|
|
60
|
+
onNoData: () => Effect.Effect<R2, E2, B>
|
|
61
|
+
onLoading: () => Effect.Effect<R3, E3, C>
|
|
62
|
+
onFailure: (cause: Cause.Cause<E>, refreshing: boolean) => Effect.Effect<R4, E4, D>
|
|
63
|
+
onSuccess: (value: A, refreshing: boolean) => Effect.Effect<R5, E5, F>
|
|
64
|
+
}) => Computed<R2 | R3 | R4 | R5, E2 | E3 | E4 | E5, B | C | D | F>
|
|
65
|
+
|
|
66
|
+
// States
|
|
67
|
+
readonly toLoading: Effect.Effect<never, never, RemoteData.RemoteData<E, A>>
|
|
68
|
+
readonly stopLoading: Effect.Effect<never, never, RemoteData.RemoteData<E, A>>
|
|
69
|
+
readonly isLoading: Computed<never, never, boolean>
|
|
70
|
+
readonly isRefreshing: Computed<never, never, boolean>
|
|
71
|
+
readonly isLoadingOrRefreshing: Computed<never, never, boolean>
|
|
72
|
+
readonly isFailure: Computed<never, never, boolean>
|
|
73
|
+
readonly isSuccess: Computed<never, never, boolean>
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function makeRefRemoteData<E, A>(
|
|
77
|
+
E: Equivalence.Equivalence<E> = fastDeepEqual,
|
|
78
|
+
A: Equivalence.Equivalence<A> = fastDeepEqual,
|
|
79
|
+
): Effect.Effect<Scope.Scope, never, RefRemoteData<E, A>> {
|
|
80
|
+
return Effect.gen(function* ($) {
|
|
81
|
+
const ref = yield* $(
|
|
82
|
+
makeRef(
|
|
83
|
+
Effect.succeed<RemoteData.RemoteData<E, A>>(RemoteData.noData),
|
|
84
|
+
RemoteData.getEquivalence(E, A),
|
|
85
|
+
),
|
|
86
|
+
)
|
|
87
|
+
const succeed = (value: A) => ref.set(RemoteData.success(value))
|
|
88
|
+
const failCause = (error: Cause.Cause<E>) => ref.set(RemoteData.failCause(error))
|
|
89
|
+
const mapValueEffect = <R2, E2, B>(
|
|
90
|
+
f: (a: A, refreshing: boolean) => Effect.Effect<R2, E2, B>,
|
|
91
|
+
): Computed<R2, E2, RemoteData.RemoteData<E, B>> =>
|
|
92
|
+
ref.mapEffect((data) =>
|
|
93
|
+
RemoteData.match(data, {
|
|
94
|
+
onNoData: () => Effect.succeed(RemoteData.noData as RemoteData.RemoteData<E, B>),
|
|
95
|
+
onLoading: () => Effect.succeed(RemoteData.loading),
|
|
96
|
+
onFailure: (cause, refreshing) => Effect.succeed(RemoteData.failCause(cause, refreshing)),
|
|
97
|
+
onSuccess: (a, refreshing) =>
|
|
98
|
+
f(a, refreshing).pipe(Effect.map((b) => RemoteData.success(b, refreshing))),
|
|
99
|
+
}),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
const toLoading = ref.update(RemoteData.toLoading)
|
|
103
|
+
const stopLoading = ref.update(RemoteData.stopLoading)
|
|
104
|
+
const isLoading = ref.map(RemoteData.isLoading)
|
|
105
|
+
const isRefreshing = ref.map(RemoteData.isRefreshing)
|
|
106
|
+
const isLoadingOrRefreshing = ref.map(RemoteData.isLoadingOrRefreshing)
|
|
107
|
+
|
|
108
|
+
// Ensure there can only ever be one loading fiber
|
|
109
|
+
const currentFiber = yield* $(
|
|
110
|
+
SynchronizedRef.make<Fiber.Fiber<never, boolean>>(Fiber.succeed(false)),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
const runEffect = <R>(effect: Effect.Effect<R, E, A>) =>
|
|
114
|
+
SynchronizedRef.updateAndGetEffect(currentFiber, (fiber) =>
|
|
115
|
+
Fiber.interrupt(fiber).pipe(
|
|
116
|
+
Effect.flatMap(() =>
|
|
117
|
+
ref.multiUpdate((current, set) =>
|
|
118
|
+
Effect.if(RemoteData.isLoadingOrRefreshing(current), {
|
|
119
|
+
onFalse: set(RemoteData.toLoading(current)).pipe(
|
|
120
|
+
Effect.zipRight(effect),
|
|
121
|
+
Effect.exit,
|
|
122
|
+
Effect.flatMap((exit) => set(RemoteData.fromExit(exit))),
|
|
123
|
+
Effect.as(true),
|
|
124
|
+
),
|
|
125
|
+
onTrue: Effect.as(stopLoading, false),
|
|
126
|
+
}).pipe(Effect.onInterrupt(() => stopLoading)),
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
Effect.forkScoped,
|
|
130
|
+
),
|
|
131
|
+
).pipe(Effect.flatMap(Fiber.join))
|
|
132
|
+
|
|
133
|
+
const matchFx = <R2, E2, B, R3, E3, C, R4, E4, D, R5, E5, F>(options: {
|
|
134
|
+
onNoData: () => Fx<R2, E2, B>
|
|
135
|
+
onLoading: () => Fx<R3, E3, C>
|
|
136
|
+
onFailure: (cause: Cause.Cause<E>, refreshing: boolean) => Fx<R4, E4, D>
|
|
137
|
+
onSuccess: (value: A, refreshing: boolean) => Fx<R5, E5, F>
|
|
138
|
+
}) =>
|
|
139
|
+
switchMap(
|
|
140
|
+
ref,
|
|
141
|
+
(data): Fx<R2 | R3 | R4 | R5, E2 | E3 | E4 | E5, B | C | D | F> =>
|
|
142
|
+
RemoteData.match(data, options),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
const matchEffect = <R2, E2, B, R3, E3, C, R4, E4, D, R5, E5, F>(options: {
|
|
146
|
+
onNoData: () => Effect.Effect<R2, E2, B>
|
|
147
|
+
onLoading: () => Effect.Effect<R3, E3, C>
|
|
148
|
+
onFailure: (cause: Cause.Cause<E>, refreshing: boolean) => Effect.Effect<R4, E4, D>
|
|
149
|
+
onSuccess: (value: A, refreshing: boolean) => Effect.Effect<R5, E5, F>
|
|
150
|
+
}) =>
|
|
151
|
+
ref.mapEffect(
|
|
152
|
+
(data): Effect.Effect<R2 | R3 | R4 | R5, E2 | E3 | E4 | E5, B | C | D | F> =>
|
|
153
|
+
RemoteData.match(data, options),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
const awaitNotLoading = drain(take(skipWhile(ref, RemoteData.isLoadingOrRefreshing), 1))
|
|
157
|
+
|
|
158
|
+
const refRemoteData: RefRemoteData<E, A> = Object.assign(ref, {
|
|
159
|
+
awaitNotLoading,
|
|
160
|
+
fail: (error: E) => failCause(Cause.fail(error)),
|
|
161
|
+
failCause,
|
|
162
|
+
fromEither: (either: Either.Either<E, A>) => ref.set(RemoteData.fromEither(either)),
|
|
163
|
+
fromExit: (exit: Exit.Exit<E, A>) => ref.set(RemoteData.fromExit(exit)),
|
|
164
|
+
fromOption: (option: Option.Option<A>) => ref.set(RemoteData.fromOption(option)),
|
|
165
|
+
isFailure: ref.map(RemoteData.isFailure),
|
|
166
|
+
isLoading,
|
|
167
|
+
isLoadingOrRefreshing,
|
|
168
|
+
isRefreshing,
|
|
169
|
+
isSuccess: ref.map(RemoteData.isSuccess),
|
|
170
|
+
mapValue: <B>(f: (a: A) => B) => mapValueEffect((a) => Effect.sync(() => f(a))),
|
|
171
|
+
mapValueEffect,
|
|
172
|
+
matchEffect: matchEffect,
|
|
173
|
+
matchFx: matchFx,
|
|
174
|
+
runEffect,
|
|
175
|
+
stopLoading,
|
|
176
|
+
succeed,
|
|
177
|
+
toLoading,
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
return refRemoteData
|
|
181
|
+
})
|
|
182
|
+
}
|
package/src/RefSubject.ts
CHANGED
|
@@ -61,6 +61,10 @@ export interface RefSubject<in out E, in out A>
|
|
|
61
61
|
|
|
62
62
|
readonly delete: Effect.Effect<never, E, Option.Option<A>>
|
|
63
63
|
|
|
64
|
+
readonly multiUpdate: <R2, E2, B>(
|
|
65
|
+
f: (current: A, set: (a: A) => Effect.Effect<never, never, A>) => Effect.Effect<R2, E2, B>,
|
|
66
|
+
) => Effect.Effect<R2, E | E2, B>
|
|
67
|
+
|
|
64
68
|
/**
|
|
65
69
|
* The current version of the RefSubject, starting with 0, 1 when initialized,
|
|
66
70
|
* and incremented each time the value is updated.
|
|
@@ -252,6 +256,14 @@ function makeModifyEffectFromContext<E, A>(
|
|
|
252
256
|
)
|
|
253
257
|
}
|
|
254
258
|
|
|
259
|
+
function makeMultiUpdateFromContext<E, A>(
|
|
260
|
+
get: RefSubject<E, A>['get'],
|
|
261
|
+
set: RefSubject<E, A>['set'],
|
|
262
|
+
lock: RefSubjectContext<E, A>['lock'],
|
|
263
|
+
): RefSubject<E, A>['multiUpdate'] {
|
|
264
|
+
return (f) => get.pipe(Effect.flatMap((current) => lock(f(current, set))))
|
|
265
|
+
}
|
|
266
|
+
|
|
255
267
|
function makeModify<E, A>(
|
|
256
268
|
modifyEffect: RefSubject<E, A>['modifyEffect'],
|
|
257
269
|
): RefSubject<E, A>['modify'] {
|
|
@@ -506,6 +518,7 @@ function unsafeMakeRefPrimitive<E, A>(
|
|
|
506
518
|
const ctx = makeRefSubjectContext(initial, scope, eq)
|
|
507
519
|
const get = makeGetFromContext(ctx)
|
|
508
520
|
const set = makeSetFromContext(ctx)
|
|
521
|
+
const multiUpdate = makeMultiUpdateFromContext(get, set, ctx.lock)
|
|
509
522
|
|
|
510
523
|
function run<R2>(sink: Sink<R2, E, A>) {
|
|
511
524
|
return Effect.suspend(() => {
|
|
@@ -533,6 +546,7 @@ function unsafeMakeRefPrimitive<E, A>(
|
|
|
533
546
|
modifyEffect: makeModifyEffectFromContext(get, ctx),
|
|
534
547
|
run,
|
|
535
548
|
set,
|
|
549
|
+
multiUpdate,
|
|
536
550
|
version: ctx.version,
|
|
537
551
|
}
|
|
538
552
|
|
|
@@ -575,6 +589,7 @@ interface RefPrimitive<E, A> {
|
|
|
575
589
|
modifyEffect: RefSubject<E, A>['modifyEffect']
|
|
576
590
|
set: RefSubject<E, A>['set']
|
|
577
591
|
delete: RefSubject<E, A>['delete']
|
|
592
|
+
multiUpdate: RefSubject<E, A>['multiUpdate']
|
|
578
593
|
|
|
579
594
|
// Primitive
|
|
580
595
|
version: MutableRef.MutableRef<number>
|
|
@@ -594,8 +609,15 @@ function tupleRefPrimitive<const Refs extends ReadonlyArray<RefSubject.Any>>(
|
|
|
594
609
|
refs.map((ref) => ref.get),
|
|
595
610
|
unboundedConcurrency,
|
|
596
611
|
) as Effect.Effect<never, _E, _A>
|
|
612
|
+
const set = (value: { readonly [K in keyof Refs]: Fx.Success<Refs[K]> }) =>
|
|
613
|
+
Effect.all(
|
|
614
|
+
value.map((v, i) => refs[i].set(v)),
|
|
615
|
+
unboundedConcurrency,
|
|
616
|
+
) as Effect.Effect<never, never, _A>
|
|
617
|
+
const multiUpdate = makeMultiUpdateFromContext(get, set, identity)
|
|
597
618
|
|
|
598
619
|
const primitive: RefPrimitive<_E, _A> = {
|
|
620
|
+
multiUpdate,
|
|
599
621
|
delete: Effect.map(
|
|
600
622
|
Effect.all(
|
|
601
623
|
refs.map((ref) => ref.delete),
|
|
@@ -618,11 +640,7 @@ function tupleRefPrimitive<const Refs extends ReadonlyArray<RefSubject.Any>>(
|
|
|
618
640
|
get,
|
|
619
641
|
modifyEffect: makeModifyEffectTuple(refs, get, eq),
|
|
620
642
|
run: (sink) => hold.run(sink),
|
|
621
|
-
set
|
|
622
|
-
Effect.all(
|
|
623
|
-
value.map((v, i) => refs[i].set(v)),
|
|
624
|
-
unboundedConcurrency,
|
|
625
|
-
) as Effect.Effect<never, never, _A>,
|
|
643
|
+
set,
|
|
626
644
|
version: MutableRef.make(0),
|
|
627
645
|
}
|
|
628
646
|
|
|
@@ -671,8 +689,15 @@ function structRefPrimitive<const Refs extends Readonly<Record<string, RefSubjec
|
|
|
671
689
|
mapRecord(refs, (ref) => ref.get),
|
|
672
690
|
unboundedConcurrency,
|
|
673
691
|
) as Effect.Effect<never, _E, _A>
|
|
692
|
+
const set = (value: { readonly [K in keyof Refs]: Fx.Success<Refs[K]> }) =>
|
|
693
|
+
Effect.all(
|
|
694
|
+
mapRecord(value, (v, i) => refs[i].set(v)),
|
|
695
|
+
unboundedConcurrency,
|
|
696
|
+
) as Effect.Effect<never, never, _A>
|
|
697
|
+
const multiUpdate = makeMultiUpdateFromContext(get, set, identity)
|
|
674
698
|
|
|
675
699
|
const primitive: RefPrimitive<_E, _A> = {
|
|
700
|
+
multiUpdate,
|
|
676
701
|
delete: Effect.map(
|
|
677
702
|
Effect.all(
|
|
678
703
|
mapRecord(refs, (ref) => ref.delete),
|
package/src/data-first.ts
CHANGED
package/src/index.ts
CHANGED