@livestore/utils 0.4.0 → 0.5.0-dev.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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/NoopTracer.d.ts +7 -8
- package/dist/NoopTracer.d.ts.map +1 -1
- package/dist/NoopTracer.js +3 -18
- package/dist/NoopTracer.js.map +1 -1
- package/dist/NoopTracer.test.d.ts +2 -0
- package/dist/NoopTracer.test.d.ts.map +1 -0
- package/dist/NoopTracer.test.js +17 -0
- package/dist/NoopTracer.test.js.map +1 -0
- package/dist/browser/Opfs/Opfs.d.ts +179 -29
- package/dist/browser/Opfs/Opfs.d.ts.map +1 -1
- package/dist/browser/Opfs/Opfs.js +132 -307
- package/dist/browser/Opfs/Opfs.js.map +1 -1
- package/dist/browser/Opfs/debug-utils.d.ts.map +1 -1
- package/dist/browser/Opfs/debug-utils.js +5 -4
- package/dist/browser/Opfs/debug-utils.js.map +1 -1
- package/dist/browser/Opfs/utils.d.ts +8 -8
- package/dist/browser/Opfs/utils.d.ts.map +1 -1
- package/dist/browser/Opfs/utils.js +35 -26
- package/dist/browser/Opfs/utils.js.map +1 -1
- package/dist/browser/QuotaExceededError.d.ts +10 -9
- package/dist/browser/QuotaExceededError.d.ts.map +1 -1
- package/dist/browser/WebChannelBrowser.d.ts.map +1 -1
- package/dist/browser/WebChannelBrowser.js +21 -10
- package/dist/browser/WebChannelBrowser.js.map +1 -1
- package/dist/browser/WebError.d.ts +54 -86
- package/dist/browser/WebError.d.ts.map +1 -1
- package/dist/browser/WebError.js +91 -84
- package/dist/browser/WebError.js.map +1 -1
- package/dist/browser/WebError.test.js +6 -6
- package/dist/browser/WebError.test.js.map +1 -1
- package/dist/browser/WebLock.d.ts.map +1 -1
- package/dist/browser/WebLock.js +13 -13
- package/dist/browser/WebLock.js.map +1 -1
- package/dist/effect/Debug.d.ts +4 -7
- package/dist/effect/Debug.d.ts.map +1 -1
- package/dist/effect/Debug.js +32 -36
- package/dist/effect/Debug.js.map +1 -1
- package/dist/effect/Effect.d.ts +31 -22
- package/dist/effect/Effect.d.ts.map +1 -1
- package/dist/effect/Effect.js +51 -47
- package/dist/effect/Effect.js.map +1 -1
- package/dist/effect/Effect.test.d.ts +2 -0
- package/dist/effect/Effect.test.d.ts.map +1 -0
- package/dist/effect/Effect.test.js +72 -0
- package/dist/effect/Effect.test.js.map +1 -0
- package/dist/effect/Error.d.ts +4 -6
- package/dist/effect/Error.d.ts.map +1 -1
- package/dist/effect/Logger.d.ts +0 -6
- package/dist/effect/Logger.d.ts.map +1 -1
- package/dist/effect/Logger.js +0 -32
- package/dist/effect/Logger.js.map +1 -1
- package/dist/effect/OtelTracer.d.ts +1 -1
- package/dist/effect/OtelTracer.d.ts.map +1 -1
- package/dist/effect/OtelTracer.js +2 -3
- package/dist/effect/OtelTracer.js.map +1 -1
- package/dist/effect/RpcClient.d.ts +7 -7
- package/dist/effect/RpcClient.d.ts.map +1 -1
- package/dist/effect/RpcClient.js +72 -52
- package/dist/effect/RpcClient.js.map +1 -1
- package/dist/effect/Schedule.d.ts +1 -1
- package/dist/effect/Schedule.d.ts.map +1 -1
- package/dist/effect/Schedule.js +2 -2
- package/dist/effect/Schedule.js.map +1 -1
- package/dist/effect/Schema/debug-diff.d.ts +1 -1
- package/dist/effect/Schema/debug-diff.d.ts.map +1 -1
- package/dist/effect/Schema/debug-diff.js +5 -7
- package/dist/effect/Schema/debug-diff.js.map +1 -1
- package/dist/effect/Schema/debug-diff.test.js +7 -4
- package/dist/effect/Schema/debug-diff.test.js.map +1 -1
- package/dist/effect/Schema/index.d.ts +28 -20
- package/dist/effect/Schema/index.d.ts.map +1 -1
- package/dist/effect/Schema/index.js +55 -28
- package/dist/effect/Schema/index.js.map +1 -1
- package/dist/effect/Stream.d.ts +13 -5
- package/dist/effect/Stream.d.ts.map +1 -1
- package/dist/effect/Stream.js +19 -12
- package/dist/effect/Stream.js.map +1 -1
- package/dist/effect/Stream.test.js +9 -9
- package/dist/effect/Stream.test.js.map +1 -1
- package/dist/effect/Subscribable.d.ts +9 -3
- package/dist/effect/Subscribable.d.ts.map +1 -1
- package/dist/effect/Subscribable.js +20 -35
- package/dist/effect/Subscribable.js.map +1 -1
- package/dist/effect/SubscriptionRef.d.ts +5 -6
- package/dist/effect/SubscriptionRef.d.ts.map +1 -1
- package/dist/effect/SubscriptionRef.js +2 -3
- package/dist/effect/SubscriptionRef.js.map +1 -1
- package/dist/effect/TaskTracing.d.ts +1 -1
- package/dist/effect/TaskTracing.d.ts.map +1 -1
- package/dist/effect/TaskTracing.js +12 -16
- package/dist/effect/TaskTracing.js.map +1 -1
- package/dist/effect/WebChannel/WebChannel.d.ts +7 -7
- package/dist/effect/WebChannel/WebChannel.d.ts.map +1 -1
- package/dist/effect/WebChannel/WebChannel.js +64 -43
- package/dist/effect/WebChannel/WebChannel.js.map +1 -1
- package/dist/effect/WebChannel/WebChannel.test.js +15 -15
- package/dist/effect/WebChannel/WebChannel.test.js.map +1 -1
- package/dist/effect/WebChannel/broadcastChannelWithAck.d.ts.map +1 -1
- package/dist/effect/WebChannel/broadcastChannelWithAck.js +16 -9
- package/dist/effect/WebChannel/broadcastChannelWithAck.js.map +1 -1
- package/dist/effect/WebChannel/common.d.ts +16 -17
- package/dist/effect/WebChannel/common.d.ts.map +1 -1
- package/dist/effect/WebChannel/common.js +6 -6
- package/dist/effect/WebChannel/common.js.map +1 -1
- package/dist/effect/WebSocket.d.ts +4 -6
- package/dist/effect/WebSocket.d.ts.map +1 -1
- package/dist/effect/WebSocket.js +4 -4
- package/dist/effect/WebSocket.js.map +1 -1
- package/dist/effect/WebSocket.test.js +2 -2
- package/dist/effect/WebSocket.test.js.map +1 -1
- package/dist/effect/mod.browser-build.test.d.ts +2 -0
- package/dist/effect/mod.browser-build.test.d.ts.map +1 -0
- package/dist/effect/mod.browser-build.test.js +18 -0
- package/dist/effect/mod.browser-build.test.js.map +1 -0
- package/dist/effect/mod.d.ts +13 -15
- package/dist/effect/mod.d.ts.map +1 -1
- package/dist/effect/mod.js +13 -18
- package/dist/effect/mod.js.map +1 -1
- package/dist/effect/spanEvent.d.ts.map +1 -1
- package/dist/effect/spanEvent.js +2 -2
- package/dist/effect/spanEvent.js.map +1 -1
- package/dist/effect/spanEvent.test.js +10 -13
- package/dist/effect/spanEvent.test.js.map +1 -1
- package/dist/fast-deep-equal.d.ts.map +1 -1
- package/dist/fast-deep-equal.js +1 -2
- package/dist/fast-deep-equal.js.map +1 -1
- package/dist/misc.js +2 -2
- package/dist/misc.js.map +1 -1
- package/dist/mod.d.ts +0 -35
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +0 -8
- package/dist/mod.js.map +1 -1
- package/dist/node/mod.d.ts +17 -11
- package/dist/node/mod.d.ts.map +1 -1
- package/dist/node/mod.js +23 -16
- package/dist/node/mod.js.map +1 -1
- package/dist/object/index.d.ts +0 -9
- package/dist/object/index.d.ts.map +1 -1
- package/dist/object/index.js +0 -9
- package/dist/object/index.js.map +1 -1
- package/dist/string.d.ts +0 -2
- package/dist/string.d.ts.map +1 -1
- package/dist/string.js +0 -2
- package/dist/string.js.map +1 -1
- package/package.json +18 -36
- package/src/NoopTracer.test.ts +20 -0
- package/src/NoopTracer.ts +18 -41
- package/src/browser/Opfs/Opfs.ts +304 -277
- package/src/browser/Opfs/debug-utils.ts +7 -6
- package/src/browser/Opfs/utils.ts +36 -26
- package/src/browser/QuotaExceededError.ts +13 -10
- package/src/browser/WebChannelBrowser.ts +25 -11
- package/src/browser/WebError.test.ts +6 -6
- package/src/browser/WebError.ts +107 -133
- package/src/browser/WebLock.ts +13 -14
- package/src/effect/Debug.ts +66 -59
- package/src/effect/Effect.test.ts +117 -0
- package/src/effect/Effect.ts +84 -71
- package/src/effect/Logger.ts +0 -48
- package/src/effect/OtelTracer.ts +2 -3
- package/src/effect/RpcClient.ts +80 -61
- package/src/effect/Schedule.ts +4 -5
- package/src/effect/Schema/debug-diff.test.ts +6 -6
- package/src/effect/Schema/debug-diff.ts +6 -8
- package/src/effect/Schema/index.ts +122 -61
- package/src/effect/Stream.test.ts +9 -9
- package/src/effect/Stream.ts +23 -16
- package/src/effect/Subscribable.ts +31 -42
- package/src/effect/SubscriptionRef.ts +8 -12
- package/src/effect/TaskTracing.ts +13 -16
- package/src/effect/WebChannel/WebChannel.test.ts +23 -23
- package/src/effect/WebChannel/WebChannel.ts +87 -55
- package/src/effect/WebChannel/broadcastChannelWithAck.ts +21 -11
- package/src/effect/WebChannel/common.ts +14 -15
- package/src/effect/WebSocket.test.ts +2 -2
- package/src/effect/WebSocket.ts +9 -6
- package/src/effect/mod.browser-build.test.ts +19 -0
- package/src/effect/mod.ts +35 -69
- package/src/effect/spanEvent.test.ts +10 -13
- package/src/effect/spanEvent.ts +5 -3
- package/src/fast-deep-equal.ts +1 -2
- package/src/misc.ts +2 -2
- package/src/mod.ts +0 -36
- package/src/node/mod.ts +26 -20
- package/src/object/index.ts +0 -24
- package/src/string.ts +0 -3
- package/dist/effect/BucketQueue.d.ts +0 -20
- package/dist/effect/BucketQueue.d.ts.map +0 -1
- package/dist/effect/BucketQueue.js +0 -34
- package/dist/effect/BucketQueue.js.map +0 -1
- package/dist/effect/Scheduler.d.ts +0 -4
- package/dist/effect/Scheduler.d.ts.map +0 -1
- package/dist/effect/Scheduler.js +0 -9
- package/dist/effect/Scheduler.js.map +0 -1
- package/dist/effect/ServiceContext.d.ts +0 -37
- package/dist/effect/ServiceContext.d.ts.map +0 -1
- package/dist/effect/ServiceContext.js +0 -55
- package/dist/effect/ServiceContext.js.map +0 -1
- package/dist/guards.d.ts +0 -20
- package/dist/guards.d.ts.map +0 -1
- package/dist/guards.js +0 -20
- package/dist/guards.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts +0 -4
- package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js +0 -128
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts +0 -10
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js +0 -217
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts +0 -84
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js +0 -68
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts +0 -2
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js +0 -52
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts +0 -23
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js +0 -138
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js.map +0 -1
- package/dist/object/omit.d.ts +0 -3
- package/dist/object/omit.d.ts.map +0 -1
- package/dist/object/omit.js +0 -14
- package/dist/object/omit.js.map +0 -1
- package/dist/object/pick.d.ts +0 -14
- package/dist/object/pick.d.ts.map +0 -1
- package/dist/object/pick.js +0 -17
- package/dist/object/pick.js.map +0 -1
- package/dist/time.d.ts +0 -12
- package/dist/time.d.ts.map +0 -1
- package/dist/time.js +0 -22
- package/dist/time.js.map +0 -1
- package/src/effect/BucketQueue.ts +0 -49
- package/src/effect/Scheduler.ts +0 -13
- package/src/effect/ServiceContext.ts +0 -108
- package/src/guards.ts +0 -23
- package/src/node/ChildProcessRunner/ChildProcessRunner.ts +0 -148
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.ts +0 -311
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/schema.ts +0 -78
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.ts +0 -65
- package/src/node/ChildProcessRunner/ChildProcessWorker.ts +0 -169
- package/src/object/omit.ts +0 -17
- package/src/object/pick.ts +0 -27
- package/src/time.ts +0 -25
package/src/effect/Effect.ts
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
import * as OtelTracer from '@effect/opentelemetry/
|
|
1
|
+
import * as OtelTracer from '@effect/opentelemetry/OtelTracer'
|
|
2
2
|
import {
|
|
3
3
|
Cause,
|
|
4
|
+
Console,
|
|
4
5
|
type Context,
|
|
5
6
|
Deferred,
|
|
6
7
|
Duration,
|
|
7
8
|
Effect,
|
|
9
|
+
Function,
|
|
8
10
|
Fiber,
|
|
9
11
|
pipe,
|
|
12
|
+
Predicate,
|
|
10
13
|
Scope,
|
|
11
14
|
type Stream,
|
|
12
15
|
} from 'effect'
|
|
13
|
-
import type { UnknownException } from 'effect/Cause'
|
|
14
|
-
import { log } from 'effect/Console'
|
|
15
|
-
import { dual, type LazyArg } from 'effect/Function'
|
|
16
|
-
import type { Predicate, Refinement } from 'effect/Predicate'
|
|
17
16
|
|
|
18
|
-
import { isDevEnv,
|
|
19
|
-
import { UnknownError } from './Error.ts'
|
|
17
|
+
import { isDevEnv, objectToString } from '../misc.ts'
|
|
20
18
|
|
|
21
19
|
export * from 'effect/Effect'
|
|
22
20
|
export { spanEvent } from './spanEvent.ts'
|
|
@@ -36,16 +34,14 @@ export { spanEvent } from './spanEvent.ts'
|
|
|
36
34
|
// console.error(message, ...rest)
|
|
37
35
|
// })
|
|
38
36
|
|
|
39
|
-
/** Same as `Effect.scopeWith` but with a
|
|
37
|
+
/** Same as `Effect.scopeWith` but with a closeable `Scope`. */
|
|
40
38
|
export const scopeWithCloseable = <R, E, A>(
|
|
41
|
-
fn: (scope: Scope.
|
|
39
|
+
fn: (scope: Scope.Closeable) => Effect.Effect<A, E, R | Scope.Scope>,
|
|
42
40
|
): Effect.Effect<A, E, R | Scope.Scope> =>
|
|
43
41
|
Effect.gen(function* () {
|
|
44
|
-
// const parentScope = yield* Scope.Scope
|
|
45
|
-
// const scope = yield* Scope.fork(parentScope, ExecutionStrategy.sequential)
|
|
46
42
|
const scope = yield* Scope.make()
|
|
47
43
|
yield* Effect.addFinalizer((exit) => Scope.close(scope, exit))
|
|
48
|
-
return yield* fn(scope).pipe(Scope.
|
|
44
|
+
return yield* fn(scope).pipe(Scope.provide(scope))
|
|
49
45
|
})
|
|
50
46
|
|
|
51
47
|
export type SyncOrPromiseOrEffect<TResult, TError = never, TContext = never> =
|
|
@@ -53,22 +49,43 @@ export type SyncOrPromiseOrEffect<TResult, TError = never, TContext = never> =
|
|
|
53
49
|
| Promise<TResult>
|
|
54
50
|
| Effect.Effect<TResult, TError, TContext>
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Creates an Effect from an operation that may return a value, a Promise-like value, or another Effect.
|
|
54
|
+
*
|
|
55
|
+
* @remarks
|
|
56
|
+
* Synchronous values succeed directly, and Promise-like values are awaited. Synchronous throws and Promise rejections
|
|
57
|
+
* are mapped to `Cause.UnknownError`. When the operation returns an Effect, that Effect is executed rather than
|
|
58
|
+
* produced as a successful value; its failures and service requirements are preserved.
|
|
59
|
+
*
|
|
60
|
+
* @param operation - A callback that may return a synchronous value, a Promise-like value, or an Effect
|
|
61
|
+
* @returns An Effect representing the normalized outcome of the operation
|
|
62
|
+
*/
|
|
63
|
+
export function trySyncOrPromiseOrEffect<Return>(
|
|
64
|
+
operation: () => Return,
|
|
65
|
+
): Effect.Effect<
|
|
66
|
+
Return extends Effect.Effect<infer A, infer _E, infer _R> ? A : Return extends PromiseLike<infer A> ? A : Return,
|
|
67
|
+
Cause.UnknownError | (Return extends Effect.Effect<infer _A, infer E, infer _R> ? E : never),
|
|
68
|
+
Return extends Effect.Effect<infer _A, infer _E, infer R> ? R : never
|
|
69
|
+
>
|
|
70
|
+
export function trySyncOrPromiseOrEffect(operation: () => unknown): Effect.Effect<unknown, unknown, unknown> {
|
|
71
|
+
return Effect.try({
|
|
72
|
+
try: () => {
|
|
73
|
+
const result = operation()
|
|
74
|
+
|
|
75
|
+
if (Effect.isEffect(result) === true) {
|
|
76
|
+
// @effect-diagnostics-next-line anyUnknownInErrorContext:off -- dynamic implementation boundary; the public overload preserves exact Effect error and requirement channels
|
|
77
|
+
return result
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (Predicate.isPromiseLike(result) === true) {
|
|
81
|
+
return Effect.tryPromise(() => result)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return Effect.succeed(result)
|
|
85
|
+
},
|
|
86
|
+
catch: (cause) => new Cause.UnknownError(cause),
|
|
87
|
+
}).pipe(Effect.flatten)
|
|
88
|
+
}
|
|
72
89
|
|
|
73
90
|
export const acquireReleaseLog = (label: string) =>
|
|
74
91
|
Effect.acquireRelease(Effect.log(`${label} acquire`), (_, ex) => Effect.log(`${label} release`, ex))
|
|
@@ -85,16 +102,11 @@ export const logBefore =
|
|
|
85
102
|
|
|
86
103
|
/** Logs both on errors and defects */
|
|
87
104
|
export const tapCauseLogPretty = <R, E, A>(eff: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
88
|
-
Effect.
|
|
105
|
+
Effect.tapCause(eff, (cause) =>
|
|
89
106
|
Effect.gen(function* () {
|
|
90
|
-
if (Cause.
|
|
91
|
-
// console.log('interrupted', Cause.pretty(err), err)
|
|
92
|
-
return
|
|
93
|
-
}
|
|
107
|
+
if (Cause.hasInterruptsOnly(cause) === true) return
|
|
94
108
|
|
|
95
|
-
const span = yield* OtelTracer.currentOtelSpan.pipe(
|
|
96
|
-
Effect.catchTag('NoSuchElementException', (_) => Effect.succeed(undefined)),
|
|
97
|
-
)
|
|
109
|
+
const span = yield* OtelTracer.currentOtelSpan.pipe(Effect.catchTag('NoSuchElementError', (_) => Effect.void))
|
|
98
110
|
|
|
99
111
|
const firstErrLine = cause.toString().split('\n')[0]
|
|
100
112
|
yield* Effect.logError(firstErrLine, cause).pipe((_) =>
|
|
@@ -121,7 +133,7 @@ export const dieDebugger = (msg: string, ...args: ReadonlyArray<unknown>): Effec
|
|
|
121
133
|
debugger
|
|
122
134
|
void args // Keeps the variable in scope so it's inspectable when the debugger pauses
|
|
123
135
|
}
|
|
124
|
-
return Effect.
|
|
136
|
+
return Effect.die(new Error(msg))
|
|
125
137
|
})
|
|
126
138
|
|
|
127
139
|
/**
|
|
@@ -136,27 +148,27 @@ export const orDieDebugger = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Eff
|
|
|
136
148
|
Effect.matchEffect(self, {
|
|
137
149
|
onFailure: (error) =>
|
|
138
150
|
// Keep the debugger hook so that `debugger` runs only when the wrapped effect actually fails, not while building the wrapper.
|
|
139
|
-
Effect.
|
|
151
|
+
Effect.suspend(() => {
|
|
140
152
|
if (isDevEnv() === true) {
|
|
141
153
|
// oxlint-disable-next-line eslint(no-debugger) -- intentional breakpoint for impossible states during development
|
|
142
154
|
debugger
|
|
143
155
|
}
|
|
144
|
-
return error
|
|
156
|
+
return Effect.die(error)
|
|
145
157
|
}),
|
|
146
158
|
onSuccess: Effect.succeed,
|
|
147
159
|
})
|
|
148
160
|
|
|
149
161
|
export const ignoreIf: {
|
|
150
162
|
<E, EB extends E>(
|
|
151
|
-
refinement: Refinement<NoInfer<E>, EB>,
|
|
163
|
+
refinement: Predicate.Refinement<NoInfer<E>, EB>,
|
|
152
164
|
): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, Exclude<E, EB>, R>
|
|
153
|
-
<E>(predicate: Predicate<NoInfer<E>>): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, E, R>
|
|
165
|
+
<E>(predicate: Predicate.Predicate<NoInfer<E>>): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, E, R>
|
|
154
166
|
<A, E, R, EB extends E>(
|
|
155
167
|
self: Effect.Effect<A, E, R>,
|
|
156
|
-
refinement: Refinement<E, EB>,
|
|
168
|
+
refinement: Predicate.Refinement<E, EB>,
|
|
157
169
|
): Effect.Effect<void, Exclude<E, EB>, R>
|
|
158
|
-
<A, E, R>(self: Effect.Effect<A, E, R>, predicate: Predicate<E>): Effect.Effect<void, E, R>
|
|
159
|
-
} = dual(2, <A, E, R>(self: Effect.Effect<A, E, R>, predicate: Predicate<E>) =>
|
|
170
|
+
<A, E, R>(self: Effect.Effect<A, E, R>, predicate: Predicate.Predicate<E>): Effect.Effect<void, E, R>
|
|
171
|
+
} = Function.dual(2, <A, E, R>(self: Effect.Effect<A, E, R>, predicate: Predicate.Predicate<E>) =>
|
|
160
172
|
self.pipe(Effect.catchIf(predicate, () => Effect.void)),
|
|
161
173
|
)
|
|
162
174
|
|
|
@@ -167,9 +179,9 @@ export const eventListener = <TEvent = unknown>(
|
|
|
167
179
|
options?: { once?: boolean },
|
|
168
180
|
) =>
|
|
169
181
|
Effect.gen(function* () {
|
|
170
|
-
const
|
|
182
|
+
const services = yield* Effect.context()
|
|
171
183
|
|
|
172
|
-
const handlerFn = (event: TEvent) => handler(event).pipe(Effect.
|
|
184
|
+
const handlerFn = (event: TEvent) => handler(event).pipe(Effect.runForkWith(services))
|
|
173
185
|
|
|
174
186
|
target.addEventListener(type, handlerFn, { once: options?.once ?? false })
|
|
175
187
|
|
|
@@ -177,10 +189,10 @@ export const eventListener = <TEvent = unknown>(
|
|
|
177
189
|
})
|
|
178
190
|
|
|
179
191
|
export const logWarnIfTakesLongerThan =
|
|
180
|
-
({ label, duration }: { label: string; duration: Duration.
|
|
192
|
+
({ label, duration }: { label: string; duration: Duration.Input }) =>
|
|
181
193
|
<R, E, A>(eff: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
182
194
|
Effect.gen(function* () {
|
|
183
|
-
const
|
|
195
|
+
const services = yield* Effect.context()
|
|
184
196
|
|
|
185
197
|
let tookLongerThanTimer = false
|
|
186
198
|
|
|
@@ -190,8 +202,7 @@ export const logWarnIfTakesLongerThan =
|
|
|
190
202
|
// TODO include span info
|
|
191
203
|
return Effect.logWarning(`${label}: Took longer than ${objectToString(duration)}ms`)
|
|
192
204
|
}),
|
|
193
|
-
Effect.
|
|
194
|
-
Effect.runFork,
|
|
205
|
+
Effect.runForkWith(services),
|
|
195
206
|
)
|
|
196
207
|
|
|
197
208
|
const start = Date.now()
|
|
@@ -228,7 +239,7 @@ export const logDuration =
|
|
|
228
239
|
const start = Date.now()
|
|
229
240
|
const res = yield* eff
|
|
230
241
|
const end = Date.now()
|
|
231
|
-
yield* Effect.log(`${label}: ${Duration.format(end - start)}`)
|
|
242
|
+
yield* Effect.log(`${label}: ${Duration.format(Duration.millis(end - start))}`)
|
|
232
243
|
return res
|
|
233
244
|
})
|
|
234
245
|
|
|
@@ -240,7 +251,7 @@ export const tapSync =
|
|
|
240
251
|
export const debugLogEnv = (msg?: string): Effect.Effect<Context.Context<never>> =>
|
|
241
252
|
pipe(
|
|
242
253
|
Effect.context<never>(),
|
|
243
|
-
Effect.tap((env) => log(msg ?? 'debugLogEnv', env)),
|
|
254
|
+
Effect.tap((env) => Console.log(msg ?? 'debugLogEnv', env)),
|
|
244
255
|
)
|
|
245
256
|
|
|
246
257
|
/**
|
|
@@ -250,25 +261,26 @@ export const debugLogEnv = (msg?: string): Effect.Effect<Context.Context<never>>
|
|
|
250
261
|
*
|
|
251
262
|
* This function allows you to enforce a time limit on the execution of an
|
|
252
263
|
* effect. If the effect does not complete within the given duration, it dies
|
|
253
|
-
* with a {@link Cause.
|
|
254
|
-
* {@link Effect.timeout}, which adds `
|
|
264
|
+
* with a {@link Cause.TimeoutError} as an unchecked defect. Unlike
|
|
265
|
+
* {@link Effect.timeout}, which adds `TimeoutError` to the error channel,
|
|
255
266
|
* this function keeps the error channel unchanged by treating the timeout as
|
|
256
267
|
* a defect.
|
|
257
268
|
*
|
|
258
269
|
* The returned effect will either:
|
|
259
270
|
* - Succeed with the original effect's result if it completes within the
|
|
260
271
|
* specified duration.
|
|
261
|
-
* - Die with a {@link Cause.
|
|
272
|
+
* - Die with a {@link Cause.TimeoutError} defect if the time limit is exceeded.
|
|
262
273
|
*
|
|
263
274
|
* @see {@link timeoutOrDieMessage} for a version with a custom message.
|
|
264
|
-
* @see {@link Effect.timeout} for a version that raises a `
|
|
265
|
-
* @see {@link Effect.
|
|
275
|
+
* @see {@link Effect.timeout} for a version that raises a `TimeoutError` as a typed error.
|
|
276
|
+
* @see {@link Effect.timeoutOrElse} for a version with a custom timeout branch.
|
|
266
277
|
*/
|
|
267
|
-
export const timeoutOrDie =
|
|
278
|
+
export const timeoutOrDie =
|
|
279
|
+
(duration: Duration.Input) =>
|
|
268
280
|
<A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
269
|
-
Effect.
|
|
281
|
+
Effect.timeoutOrElse(self, {
|
|
270
282
|
duration,
|
|
271
|
-
|
|
283
|
+
orElse: () => Effect.die(new Cause.TimeoutError()),
|
|
272
284
|
})
|
|
273
285
|
|
|
274
286
|
/**
|
|
@@ -278,25 +290,26 @@ export const timeoutOrDie = (duration: Duration.DurationInput) =>
|
|
|
278
290
|
* @remarks
|
|
279
291
|
*
|
|
280
292
|
* This function behaves like {@link timeoutOrDie}, but allows you to provide
|
|
281
|
-
* a custom message for the {@link Cause.
|
|
293
|
+
* a custom message for the {@link Cause.TimeoutError} defect. This is useful
|
|
282
294
|
* for adding context about which operation timed out, making it easier to
|
|
283
295
|
* diagnose issues in logs or error reports.
|
|
284
296
|
*
|
|
285
297
|
* The returned effect will either:
|
|
286
298
|
* - Succeed with the original effect's result if it completes within the
|
|
287
299
|
* specified duration.
|
|
288
|
-
* - Die with a {@link Cause.
|
|
300
|
+
* - Die with a {@link Cause.TimeoutError} defect containing the provided
|
|
289
301
|
* message if the time limit is exceeded.
|
|
290
302
|
*
|
|
291
303
|
* @see {@link timeoutOrDie} for a version without a custom message.
|
|
292
|
-
* @see {@link Effect.timeout} for a version that raises a `
|
|
293
|
-
* @see {@link Effect.
|
|
304
|
+
* @see {@link Effect.timeout} for a version that raises a `TimeoutError` as a typed error.
|
|
305
|
+
* @see {@link Effect.timeoutOrElse} for a version with a custom timeout branch.
|
|
294
306
|
*/
|
|
295
|
-
export const timeoutOrDieMessage =
|
|
307
|
+
export const timeoutOrDieMessage =
|
|
308
|
+
(duration: Duration.Input, message: string) =>
|
|
296
309
|
<A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
297
|
-
Effect.
|
|
310
|
+
Effect.timeoutOrElse(self, {
|
|
298
311
|
duration,
|
|
299
|
-
|
|
312
|
+
orElse: () => Effect.die(new Cause.TimeoutError(message)),
|
|
300
313
|
})
|
|
301
314
|
|
|
302
315
|
export const toForkedDeferred = <R, E, A>(
|
|
@@ -328,16 +341,16 @@ export const withPerformanceMeasure =
|
|
|
328
341
|
)
|
|
329
342
|
|
|
330
343
|
const getSpanTrace = () => {
|
|
331
|
-
const
|
|
332
|
-
if (
|
|
344
|
+
const fiber = Fiber.getCurrent()
|
|
345
|
+
if (fiber === undefined || fiber.currentSpan === undefined) {
|
|
333
346
|
return 'No current fiber'
|
|
334
347
|
}
|
|
335
348
|
|
|
336
349
|
return ''
|
|
337
350
|
// const msg = Effect.runSync(
|
|
338
351
|
// Effect.fail({ message: '' }).pipe(
|
|
339
|
-
// Effect.withParentSpan(
|
|
340
|
-
// Effect.
|
|
352
|
+
// Effect.withParentSpan(fiber.currentSpan),
|
|
353
|
+
// Effect.catchCause((cause) => Effect.succeed(cause.toString())),
|
|
341
354
|
// ),
|
|
342
355
|
// )
|
|
343
356
|
|
package/src/effect/Logger.ts
CHANGED
|
@@ -1,49 +1 @@
|
|
|
1
|
-
import { Cause, HashMap, Logger, LogLevel } from 'effect'
|
|
2
|
-
|
|
3
1
|
export * from 'effect/Logger'
|
|
4
|
-
|
|
5
|
-
const defaultDateFormat = (date: Date): string =>
|
|
6
|
-
`${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date
|
|
7
|
-
.getSeconds()
|
|
8
|
-
.toString()
|
|
9
|
-
.padStart(2, '0')}.${date.getMilliseconds().toString().padStart(3, '0')}`
|
|
10
|
-
|
|
11
|
-
export const prettyWithThread = (threadName: string, options: { mode?: 'tty' | 'browser' } = {}) =>
|
|
12
|
-
Logger.replace(
|
|
13
|
-
Logger.defaultLogger,
|
|
14
|
-
Logger.prettyLogger({
|
|
15
|
-
formatDate: (date) => `${defaultDateFormat(date)} ${threadName}`,
|
|
16
|
-
mode: options.mode,
|
|
17
|
-
}),
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
export const consoleLogger = (threadName: string) =>
|
|
21
|
-
Logger.make(({ message, annotations, date, logLevel, cause }) => {
|
|
22
|
-
const isCloudflareWorker = typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers'
|
|
23
|
-
const consoleFn =
|
|
24
|
-
logLevel === LogLevel.Debug
|
|
25
|
-
? // Cloudflare Workers doesn't support console.debug 🤷
|
|
26
|
-
isCloudflareWorker === true
|
|
27
|
-
? console.log
|
|
28
|
-
: console.debug
|
|
29
|
-
: logLevel === LogLevel.Info
|
|
30
|
-
? console.info
|
|
31
|
-
: logLevel === LogLevel.Warning
|
|
32
|
-
? console.warn
|
|
33
|
-
: console.error
|
|
34
|
-
|
|
35
|
-
const annotationsObj = Object.fromEntries(HashMap.entries(annotations))
|
|
36
|
-
|
|
37
|
-
const messages = Array.isArray(message) === true ? message : [message]
|
|
38
|
-
if (Cause.isEmpty(cause) === false) {
|
|
39
|
-
messages.push(Cause.pretty(cause, { renderErrorCause: true }))
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (Object.keys(annotationsObj).length > 0) {
|
|
43
|
-
messages.push(annotationsObj)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
consoleFn(`[${defaultDateFormat(date)} ${threadName}]`, ...messages)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
export const consoleWithThread = (threadName: string) => Logger.replace(Logger.defaultLogger, consoleLogger(threadName))
|
package/src/effect/OtelTracer.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { makeExternalSpan } from '@effect/opentelemetry/
|
|
1
|
+
import { makeExternalSpan } from '@effect/opentelemetry/OtelTracer'
|
|
2
2
|
import type { Link as OtelSpanLink } from '@opentelemetry/api'
|
|
3
3
|
import type { SpanLink as EffectSpanLink } from 'effect/Tracer'
|
|
4
4
|
|
|
5
|
-
export * from '@effect/opentelemetry/
|
|
5
|
+
export * from '@effect/opentelemetry/OtelTracer'
|
|
6
6
|
|
|
7
7
|
export const makeSpanLink = (otelSpanLink: OtelSpanLink): EffectSpanLink => ({
|
|
8
|
-
_tag: 'SpanLink',
|
|
9
8
|
span: makeExternalSpan(otelSpanLink.context),
|
|
10
9
|
attributes: otelSpanLink.attributes ?? {},
|
|
11
10
|
})
|
package/src/effect/RpcClient.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
export * from '
|
|
1
|
+
export * from 'effect/unstable/rpc/RpcClient'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { RpcClient, RpcClientError, RpcSerialization } from '
|
|
5
|
-
import { Protocol } from '
|
|
6
|
-
import { constPing, type FromServerEncoded } from '
|
|
7
|
-
import {
|
|
8
|
-
import { constVoid, identity } from 'effect/Function'
|
|
3
|
+
import { Cause, Deferred, Effect, Function, Latch, Layer, References, Result, Schedule, type Scope } from 'effect'
|
|
4
|
+
import { RpcClient, RpcClientError, RpcSerialization } from 'effect/unstable/rpc'
|
|
5
|
+
import { Protocol } from 'effect/unstable/rpc/RpcClient'
|
|
6
|
+
import { constPing, type FromServerEncoded } from 'effect/unstable/rpc/RpcMessage'
|
|
7
|
+
import { Socket } from 'effect/unstable/socket'
|
|
9
8
|
|
|
10
9
|
import * as SubscriptionRef from './SubscriptionRef.ts'
|
|
11
10
|
|
|
@@ -20,7 +19,7 @@ export const layerProtocolSocketWithIsConnected = (options: {
|
|
|
20
19
|
readonly isConnected: SubscriptionRef.SubscriptionRef<boolean>
|
|
21
20
|
readonly pingSchedule?: Schedule.Schedule<unknown> | undefined
|
|
22
21
|
}): Layer.Layer<Protocol, never, RpcSerialization.RpcSerialization | Socket.Socket> =>
|
|
23
|
-
Layer.
|
|
22
|
+
Layer.effect(Protocol, makeProtocolSocketWithIsConnected(options))
|
|
24
23
|
|
|
25
24
|
export const makeProtocolSocketWithIsConnected = (options: {
|
|
26
25
|
readonly url: string
|
|
@@ -29,16 +28,22 @@ export const makeProtocolSocketWithIsConnected = (options: {
|
|
|
29
28
|
readonly isConnected: SubscriptionRef.SubscriptionRef<boolean>
|
|
30
29
|
// CHANGED: add ping schedule
|
|
31
30
|
readonly pingSchedule?: Schedule.Schedule<unknown> | undefined
|
|
32
|
-
}): Effect.Effect<Protocol['
|
|
31
|
+
}): Effect.Effect<Protocol['Service'], never, Scope.Scope | RpcSerialization.RpcSerialization | Socket.Socket> =>
|
|
33
32
|
Protocol.make(
|
|
34
|
-
Effect.fnUntraced(function* (writeResponse) {
|
|
33
|
+
Effect.fnUntraced(function* (writeResponse, clientIds) {
|
|
35
34
|
const socket = yield* Socket.Socket
|
|
36
35
|
const serialization = yield* RpcSerialization.RpcSerialization
|
|
36
|
+
const requestClientMap = new Map<string | number, number>()
|
|
37
37
|
|
|
38
38
|
const write = yield* socket.writer
|
|
39
|
-
|
|
39
|
+
let parser = serialization.makeUnsafe()
|
|
40
40
|
|
|
41
41
|
const pinger = yield* makePinger(write(parser.encode(constPing)!), options?.pingSchedule)
|
|
42
|
+
let currentError: RpcClientError.RpcClientError | undefined
|
|
43
|
+
|
|
44
|
+
const markConnected = SubscriptionRef.set(options.isConnected, true)
|
|
45
|
+
const broadcast = (response: FromServerEncoded) =>
|
|
46
|
+
Effect.forEach(clientIds, (clientId) => writeResponse(clientId, response))
|
|
42
47
|
|
|
43
48
|
yield* Effect.suspend(() => {
|
|
44
49
|
// We rely on the heartbeat watchdog while streaming arbitrarily long payloads.
|
|
@@ -46,7 +51,8 @@ export const makeProtocolSocketWithIsConnected = (options: {
|
|
|
46
51
|
// don't contain explicit `Pong` messages don't trigger the open-timeout defect.
|
|
47
52
|
// (The actual pong handler still calls `onPong()` to resolve manual pings.)
|
|
48
53
|
// CHANGED: don't reset parser on every message
|
|
49
|
-
// parser = serialization.
|
|
54
|
+
// parser = serialization.makeUnsafe()
|
|
55
|
+
currentError = undefined
|
|
50
56
|
pinger.reset()
|
|
51
57
|
return socket
|
|
52
58
|
.runRaw((message) => {
|
|
@@ -63,94 +69,107 @@ export const makeProtocolSocketWithIsConnected = (options: {
|
|
|
63
69
|
pinger.reset()
|
|
64
70
|
if (response._tag === 'Pong') {
|
|
65
71
|
pinger.onPong()
|
|
72
|
+
return markConnected
|
|
73
|
+
}
|
|
74
|
+
if ('requestId' in response) {
|
|
75
|
+
const clientId = requestClientMap.get(response.requestId)
|
|
76
|
+
if (clientId !== undefined) {
|
|
77
|
+
if (response._tag === 'Exit') {
|
|
78
|
+
requestClientMap.delete(response.requestId)
|
|
79
|
+
}
|
|
80
|
+
return markConnected.pipe(Effect.andThen(writeResponse(clientId, response)))
|
|
81
|
+
}
|
|
66
82
|
}
|
|
67
|
-
return
|
|
68
|
-
// CHANGED: set isConnected to true on pong
|
|
69
|
-
Effect.tap(
|
|
70
|
-
Effect.fn(function* () {
|
|
71
|
-
if (options?.isConnected !== undefined) {
|
|
72
|
-
yield* SubscriptionRef.set(options.isConnected, true)
|
|
73
|
-
}
|
|
74
|
-
}),
|
|
75
|
-
),
|
|
76
|
-
)
|
|
83
|
+
return markConnected.pipe(Effect.andThen(broadcast(response)))
|
|
77
84
|
},
|
|
78
|
-
step: constVoid,
|
|
85
|
+
step: Function.constVoid,
|
|
79
86
|
})
|
|
80
87
|
} catch (defect) {
|
|
81
|
-
return
|
|
88
|
+
return broadcast({
|
|
82
89
|
_tag: 'ClientProtocolError',
|
|
83
90
|
error: new RpcClientError.RpcClientError({
|
|
84
|
-
reason:
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
reason: new RpcClientError.RpcClientDefect({
|
|
92
|
+
message: 'Error decoding message',
|
|
93
|
+
cause: defect,
|
|
94
|
+
}),
|
|
87
95
|
}),
|
|
88
96
|
})
|
|
89
97
|
}
|
|
90
98
|
})
|
|
91
99
|
.pipe(
|
|
92
100
|
Effect.raceFirst(
|
|
93
|
-
Effect.
|
|
94
|
-
pinger.timeout,
|
|
101
|
+
Effect.flatMap(pinger.timeout, () =>
|
|
95
102
|
Effect.fail(
|
|
96
|
-
new Socket.
|
|
97
|
-
reason:
|
|
98
|
-
|
|
103
|
+
new Socket.SocketError({
|
|
104
|
+
reason: new Socket.SocketOpenError({
|
|
105
|
+
kind: 'Timeout',
|
|
106
|
+
cause: new Error('ping timeout'),
|
|
107
|
+
}),
|
|
99
108
|
}),
|
|
100
109
|
),
|
|
101
110
|
),
|
|
102
111
|
),
|
|
103
112
|
)
|
|
104
113
|
}).pipe(
|
|
105
|
-
Effect.
|
|
114
|
+
Effect.flatMap(() =>
|
|
106
115
|
Effect.fail(
|
|
107
|
-
new Socket.
|
|
108
|
-
reason:
|
|
109
|
-
|
|
110
|
-
|
|
116
|
+
new Socket.SocketError({
|
|
117
|
+
reason: new Socket.SocketCloseError({
|
|
118
|
+
code: 1000,
|
|
119
|
+
closeReason: 'Closing connection',
|
|
120
|
+
}),
|
|
111
121
|
}),
|
|
112
122
|
),
|
|
113
123
|
),
|
|
114
|
-
Effect.
|
|
124
|
+
Effect.tapCause(
|
|
115
125
|
Effect.fn(function* (cause) {
|
|
116
126
|
// CHANGED: set isConnected to false on error
|
|
117
|
-
|
|
118
|
-
yield* SubscriptionRef.set(options.isConnected, false)
|
|
119
|
-
}
|
|
127
|
+
yield* SubscriptionRef.set(options.isConnected, false)
|
|
120
128
|
|
|
121
|
-
const error = Cause.
|
|
129
|
+
const error = Cause.findError(cause)
|
|
122
130
|
if (
|
|
123
131
|
options?.retryTransientErrors !== undefined &&
|
|
124
|
-
|
|
125
|
-
|
|
132
|
+
Result.isSuccess(error) === true &&
|
|
133
|
+
error.success.reason._tag === 'SocketOpenError'
|
|
126
134
|
) {
|
|
127
135
|
return
|
|
128
136
|
}
|
|
129
137
|
// yield* Effect.logError('Error in socket', cause)
|
|
130
|
-
|
|
138
|
+
currentError = new RpcClientError.RpcClientError({
|
|
139
|
+
reason:
|
|
140
|
+
Result.isSuccess(error) === true
|
|
141
|
+
? error.success.reason
|
|
142
|
+
: new RpcClientError.RpcClientDefect({
|
|
143
|
+
message: 'Unknown socket error',
|
|
144
|
+
cause: Cause.squash(cause),
|
|
145
|
+
}),
|
|
146
|
+
})
|
|
147
|
+
return yield* broadcast({
|
|
131
148
|
_tag: 'ClientProtocolError',
|
|
132
|
-
error:
|
|
133
|
-
reason: 'Protocol',
|
|
134
|
-
message: 'Error in socket',
|
|
135
|
-
cause: Cause.squash(cause),
|
|
136
|
-
}),
|
|
149
|
+
error: currentError,
|
|
137
150
|
})
|
|
138
151
|
}),
|
|
139
152
|
),
|
|
140
153
|
// CHANGED: make configurable via schedule
|
|
141
|
-
options?.retryTransientErrors !== undefined ? Effect.retry(options.retryTransientErrors) : identity,
|
|
154
|
+
options?.retryTransientErrors !== undefined ? Effect.retry(options.retryTransientErrors) : Function.identity,
|
|
142
155
|
Effect.annotateLogs({
|
|
143
156
|
module: 'RpcClient',
|
|
144
157
|
method: 'makeProtocolSocket',
|
|
145
158
|
}),
|
|
146
159
|
Effect.interruptible,
|
|
147
160
|
Effect.ignore, // Errors are already handled
|
|
148
|
-
Effect.
|
|
161
|
+
Effect.provideService(References.UnhandledLogLevel, undefined),
|
|
149
162
|
Effect.forkScoped,
|
|
150
163
|
)
|
|
151
164
|
|
|
152
165
|
return {
|
|
153
|
-
send: (request) => {
|
|
166
|
+
send: (clientId, request) => {
|
|
167
|
+
if (currentError !== undefined) {
|
|
168
|
+
return Effect.fail(currentError)
|
|
169
|
+
}
|
|
170
|
+
if (request._tag === 'Request') {
|
|
171
|
+
requestClientMap.set(request.id, clientId)
|
|
172
|
+
}
|
|
154
173
|
const encoded = parser.encode(request)
|
|
155
174
|
if (encoded === undefined) return Effect.void
|
|
156
175
|
|
|
@@ -165,33 +184,33 @@ export const makeProtocolSocketWithIsConnected = (options: {
|
|
|
165
184
|
|
|
166
185
|
export const SocketPinger = Effect.map(RpcClient.Protocol, (protocol) => (protocol as any).pinger as SocketPinger)
|
|
167
186
|
|
|
168
|
-
export type SocketPinger = Effect.
|
|
187
|
+
export type SocketPinger = Effect.Success<ReturnType<typeof makePinger>>
|
|
169
188
|
|
|
170
189
|
const makePinger = Effect.fnUntraced(function* <A, E, R>(
|
|
171
190
|
writePing: Effect.Effect<A, E, R>,
|
|
172
|
-
pingSchedule: Schedule.Schedule<unknown> = Schedule.spaced(10000).pipe(Schedule.addDelay(() => 5000)),
|
|
191
|
+
pingSchedule: Schedule.Schedule<unknown> = Schedule.spaced(10000).pipe(Schedule.addDelay(() => Effect.succeed(5000))),
|
|
173
192
|
) {
|
|
174
193
|
// CHANGED: add manual ping deferreds
|
|
175
194
|
const manualPingDeferreds = new Set<Deferred.Deferred<void>>()
|
|
176
195
|
|
|
177
196
|
let recievedPong = true
|
|
178
|
-
const latch =
|
|
197
|
+
const latch = Latch.makeUnsafe()
|
|
179
198
|
const reset = () => {
|
|
180
199
|
recievedPong = true
|
|
181
|
-
latch.
|
|
200
|
+
latch.closeUnsafe()
|
|
182
201
|
}
|
|
183
202
|
const onPong = () => {
|
|
184
203
|
recievedPong = true
|
|
185
204
|
// CHANGED: mark all manual ping deferreds as done
|
|
186
205
|
for (const deferred of manualPingDeferreds) {
|
|
187
|
-
Deferred.
|
|
206
|
+
Deferred.doneUnsafe(deferred, Effect.void)
|
|
188
207
|
}
|
|
189
208
|
}
|
|
190
209
|
yield* Effect.suspend(() => {
|
|
191
210
|
// Starting new ping
|
|
192
|
-
if (recievedPong === false) return latch.open
|
|
211
|
+
if (recievedPong === false) return Effect.asVoid(latch.open)
|
|
193
212
|
recievedPong = false
|
|
194
|
-
return writePing
|
|
213
|
+
return Effect.asVoid(writePing)
|
|
195
214
|
}).pipe(
|
|
196
215
|
// CHANGED: make configurable via schedule
|
|
197
216
|
Effect.schedule(pingSchedule),
|
|
@@ -205,7 +224,7 @@ const makePinger = Effect.fnUntraced(function* <A, E, R>(
|
|
|
205
224
|
const ping = Effect.gen(function* () {
|
|
206
225
|
const deferred = yield* Deferred.make<void>()
|
|
207
226
|
manualPingDeferreds.add(deferred)
|
|
208
|
-
yield* deferred
|
|
227
|
+
yield* Deferred.await(deferred)
|
|
209
228
|
manualPingDeferreds.delete(deferred)
|
|
210
229
|
})
|
|
211
230
|
|
package/src/effect/Schedule.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { Duration, pipe, Schedule } from 'effect'
|
|
1
|
+
import { Duration, Effect, pipe, Schedule } from 'effect'
|
|
2
2
|
|
|
3
3
|
export * from 'effect/Schedule'
|
|
4
4
|
|
|
5
|
-
export const exponentialBackoff10Sec
|
|
5
|
+
export const exponentialBackoff10Sec = pipe(
|
|
6
6
|
Schedule.exponential(Duration.millis(10), 4), // 10ms, 40ms, 160ms, 640ms, 2560ms, ...
|
|
7
|
-
Schedule.
|
|
8
|
-
Schedule.
|
|
9
|
-
Schedule.whileOutput(Duration.lessThanOrEqualTo(Duration.seconds(10))), // max 10 seconds
|
|
7
|
+
Schedule.modifyDelay(({ duration }) => Effect.succeed(Duration.min(duration, Duration.seconds(1)))),
|
|
8
|
+
Schedule.upTo({ duration: Duration.seconds(10) }),
|
|
10
9
|
)
|