@livestore/utils 0.3.0-dev.2 → 0.3.0-dev.21
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.json +1 -1
- package/dist/Deferred.d.ts.map +1 -1
- package/dist/base64.d.ts.map +1 -1
- package/dist/bun/mod.d.ts +5 -0
- package/dist/bun/mod.d.ts.map +1 -0
- package/dist/bun/mod.js +9 -0
- package/dist/bun/mod.js.map +1 -0
- package/dist/cuid/cuid.browser.d.ts.map +1 -1
- package/dist/cuid/cuid.node.d.ts.map +1 -1
- package/dist/effect/BucketQueue.d.ts +15 -2
- package/dist/effect/BucketQueue.d.ts.map +1 -1
- package/dist/effect/BucketQueue.js +24 -6
- package/dist/effect/BucketQueue.js.map +1 -1
- package/dist/effect/Effect.d.ts +4 -2
- package/dist/effect/Effect.d.ts.map +1 -1
- package/dist/effect/Effect.js +19 -5
- package/dist/effect/Effect.js.map +1 -1
- package/dist/effect/Logger.d.ts +2 -0
- package/dist/effect/Logger.d.ts.map +1 -1
- package/dist/effect/Logger.js +16 -1
- package/dist/effect/Logger.js.map +1 -1
- package/dist/effect/Scheduler.d.ts.map +1 -1
- package/dist/effect/Schema/debug-diff.d.ts.map +1 -1
- package/dist/effect/Schema/index.d.ts +1 -0
- package/dist/effect/Schema/index.d.ts.map +1 -1
- package/dist/effect/Schema/index.js +10 -0
- package/dist/effect/Schema/index.js.map +1 -1
- package/dist/effect/Schema/msgpack.d.ts +1 -1
- package/dist/effect/Schema/msgpack.d.ts.map +1 -1
- package/dist/effect/ServiceContext.d.ts.map +1 -1
- package/dist/effect/Stream.d.ts.map +1 -1
- package/dist/effect/Subscribable.d.ts +75 -0
- package/dist/effect/Subscribable.d.ts.map +1 -0
- package/dist/effect/Subscribable.js +76 -0
- package/dist/effect/Subscribable.js.map +1 -0
- package/dist/effect/TaskTracing.d.ts.map +1 -1
- package/dist/effect/{WebChannel.d.ts → WebChannel/WebChannel.d.ts} +32 -14
- package/dist/effect/WebChannel/WebChannel.d.ts.map +1 -0
- package/dist/effect/WebChannel/WebChannel.js +283 -0
- package/dist/effect/WebChannel/WebChannel.js.map +1 -0
- package/dist/effect/WebChannel/WebChannel.test.d.ts +2 -0
- package/dist/effect/WebChannel/WebChannel.test.d.ts.map +1 -0
- package/dist/effect/WebChannel/WebChannel.test.js +62 -0
- package/dist/effect/WebChannel/WebChannel.test.js.map +1 -0
- package/dist/effect/WebChannel/broadcastChannelWithAck.d.ts +5 -6
- package/dist/effect/WebChannel/broadcastChannelWithAck.d.ts.map +1 -1
- package/dist/effect/WebChannel/broadcastChannelWithAck.js +12 -9
- package/dist/effect/WebChannel/broadcastChannelWithAck.js.map +1 -1
- package/dist/effect/WebChannel/common.d.ts +16 -1
- package/dist/effect/WebChannel/common.d.ts.map +1 -1
- package/dist/effect/WebChannel/common.js +19 -1
- package/dist/effect/WebChannel/common.js.map +1 -1
- package/dist/effect/WebChannel/mod.d.ts +4 -0
- package/dist/effect/WebChannel/mod.d.ts.map +1 -0
- package/dist/effect/WebChannel/mod.js +4 -0
- package/dist/effect/WebChannel/mod.js.map +1 -0
- package/dist/effect/WebLock.d.ts.map +1 -1
- package/dist/effect/WebSocket.d.ts +1 -1
- package/dist/effect/WebSocket.d.ts.map +1 -1
- package/dist/effect/WebSocket.js +38 -19
- package/dist/effect/WebSocket.js.map +1 -1
- package/dist/effect/WebSocket.test.d.ts +2 -0
- package/dist/effect/WebSocket.test.d.ts.map +1 -0
- package/dist/effect/WebSocket.test.js +10 -0
- package/dist/effect/WebSocket.test.js.map +1 -0
- package/dist/effect/index.d.ts +4 -2
- package/dist/effect/index.d.ts.map +1 -1
- package/dist/effect/index.js +6 -2
- package/dist/effect/index.js.map +1 -1
- package/dist/env.d.ts +1 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +3 -0
- package/dist/env.js.map +1 -1
- package/dist/fast-deep-equal.d.ts.map +1 -1
- package/dist/guards.d.ts.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/misc.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js +17 -11
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts +2 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts.map +1 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js +39 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js.map +1 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts +75 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts.map +1 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js +62 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js.map +1 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts +2 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts.map +1 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js +42 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js.map +1 -0
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts +1 -4
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js +1 -4
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js.map +1 -1
- package/dist/node/mod.d.ts +3 -2
- package/dist/node/mod.d.ts.map +1 -1
- package/dist/node/mod.js +36 -9
- package/dist/node/mod.js.map +1 -1
- package/dist/object/index.d.ts.map +1 -1
- package/dist/object/omit.d.ts.map +1 -1
- package/dist/object/pick.d.ts.map +1 -1
- package/dist/promise.d.ts.map +1 -1
- package/dist/set.d.ts.map +1 -1
- package/dist/string.d.ts.map +1 -1
- package/dist/time.d.ts.map +1 -1
- package/package.json +56 -40
- package/src/bun/mod.ts +12 -0
- package/src/effect/BucketQueue.ts +33 -6
- package/src/effect/Effect.ts +31 -6
- package/src/effect/Logger.ts +23 -1
- package/src/effect/Schema/index.ts +15 -0
- package/src/effect/Subscribable.ts +150 -0
- package/src/effect/WebChannel/WebChannel.test.ts +106 -0
- package/src/effect/WebChannel/WebChannel.ts +477 -0
- package/src/effect/WebChannel/broadcastChannelWithAck.ts +86 -83
- package/src/effect/WebChannel/common.ts +49 -2
- package/src/effect/WebChannel/mod.ts +3 -0
- package/src/effect/WebSocket.test.ts +14 -0
- package/src/effect/WebSocket.ts +64 -37
- package/src/effect/index.ts +10 -1
- package/src/env.ts +5 -0
- package/src/index.ts +4 -2
- package/src/node/ChildProcessRunner/ChildProcessRunner.ts +35 -29
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.ts +52 -0
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/schema.ts +65 -0
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.ts +53 -0
- package/src/node/ChildProcessRunner/ChildProcessWorker.ts +3 -6
- package/src/node/mod.ts +48 -10
- package/tmp/pack.tgz +0 -0
- package/tsconfig.json +1 -1
- package/dist/effect/WebChannel.d.ts.map +0 -1
- package/dist/effect/WebChannel.js +0 -162
- package/dist/effect/WebChannel.js.map +0 -1
- package/dist/nanoid/index.browser.d.ts +0 -2
- package/dist/nanoid/index.browser.d.ts.map +0 -1
- package/dist/nanoid/index.browser.js +0 -3
- package/dist/nanoid/index.browser.js.map +0 -1
- package/src/effect/WebChannel.ts +0 -290
- package/src/nanoid/index.browser.ts +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Array, STM, TRef } from 'effect'
|
|
1
|
+
import { Array, Effect, STM, TRef } from 'effect'
|
|
2
2
|
|
|
3
3
|
export type BucketQueue<A> = TRef.TRef<A[]>
|
|
4
4
|
|
|
@@ -7,16 +7,43 @@ export const make = <A>(): STM.STM<BucketQueue<A>> => TRef.make<A[]>([])
|
|
|
7
7
|
export const offerAll = <A>(self: BucketQueue<A>, elements: ReadonlyArray<A>) =>
|
|
8
8
|
TRef.update(self, (bucket) => Array.appendAll(bucket, elements))
|
|
9
9
|
|
|
10
|
+
export const replace = <A>(self: BucketQueue<A>, elements: ReadonlyArray<A>) => TRef.set(self, elements as A[])
|
|
11
|
+
|
|
10
12
|
export const clear = <A>(self: BucketQueue<A>) => TRef.set(self, [])
|
|
11
13
|
|
|
12
|
-
export const takeBetween = <A>(
|
|
14
|
+
export const takeBetween = <A>(
|
|
15
|
+
bucket: BucketQueue<A>,
|
|
16
|
+
min: number,
|
|
17
|
+
max: number,
|
|
18
|
+
): STM.STM<ReadonlyArray<A>, never, never> =>
|
|
13
19
|
STM.gen(function* () {
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
20
|
+
const bucketValue = yield* TRef.get(bucket)
|
|
21
|
+
if (bucketValue.length < min) {
|
|
16
22
|
return yield* STM.retry
|
|
17
23
|
} else {
|
|
18
|
-
const elements =
|
|
19
|
-
yield* TRef.set(
|
|
24
|
+
const elements = bucketValue.splice(0, Math.min(max, bucketValue.length))
|
|
25
|
+
yield* TRef.set(bucket, bucketValue)
|
|
20
26
|
return elements
|
|
21
27
|
}
|
|
22
28
|
})
|
|
29
|
+
|
|
30
|
+
export const peekAll = <A>(bucket: BucketQueue<A>) => TRef.get(bucket)
|
|
31
|
+
|
|
32
|
+
/** Returns the elements up to the first element that matches the predicate, the rest is left in the queue
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const [elements, rest] = yield* BucketQueue.takeSplitWhere(bucket, (a) => a > 3)
|
|
37
|
+
* assert.deepStrictEqual(elements, [1, 2, 3])
|
|
38
|
+
* assert.deepStrictEqual(rest, [4, 5, 6])
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export const takeSplitWhere = <A>(bucket: BucketQueue<A>, predicate: (a: A) => boolean) =>
|
|
42
|
+
STM.gen(function* () {
|
|
43
|
+
const bucketValue = yield* TRef.get(bucket)
|
|
44
|
+
const [elements, rest] = Array.splitWhere(bucketValue, predicate)
|
|
45
|
+
yield* TRef.set(bucket, rest)
|
|
46
|
+
return elements
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
export const size = <A>(bucket: BucketQueue<A>) => TRef.get(bucket).pipe(Effect.map((_) => _.length))
|
package/src/effect/Effect.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as OtelTracer from '@effect/opentelemetry/Tracer'
|
|
2
|
-
import type { Context, Duration,
|
|
3
|
-
import { Cause, Deferred, Effect, Fiber, FiberRef, HashSet, Logger, pipe } from 'effect'
|
|
2
|
+
import type { Context, Duration, Stream } from 'effect'
|
|
3
|
+
import { Cause, Deferred, Effect, Fiber, FiberRef, HashSet, Logger, pipe, Scope } from 'effect'
|
|
4
4
|
import type { UnknownException } from 'effect/Cause'
|
|
5
5
|
import { log } from 'effect/Console'
|
|
6
6
|
import type { LazyArg } from 'effect/Function'
|
|
@@ -25,6 +25,18 @@ export * from 'effect/Effect'
|
|
|
25
25
|
// console.error(message, ...rest)
|
|
26
26
|
// })
|
|
27
27
|
|
|
28
|
+
/** Same as `Effect.scopeWith` but with a `CloseableScope` instead of a `Scope`. */
|
|
29
|
+
export const scopeWithCloseable = <R, E, A>(
|
|
30
|
+
fn: (scope: Scope.CloseableScope) => Effect.Effect<A, E, R | Scope.Scope>,
|
|
31
|
+
): Effect.Effect<A, E, R | Scope.Scope> =>
|
|
32
|
+
Effect.gen(function* () {
|
|
33
|
+
// const parentScope = yield* Scope.Scope
|
|
34
|
+
// const scope = yield* Scope.fork(parentScope, ExecutionStrategy.sequential)
|
|
35
|
+
const scope = yield* Scope.make()
|
|
36
|
+
yield* Effect.addFinalizer((exit) => Scope.close(scope, exit))
|
|
37
|
+
return yield* fn(scope).pipe(Scope.extend(scope))
|
|
38
|
+
})
|
|
39
|
+
|
|
28
40
|
export const tryAll = <Res>(
|
|
29
41
|
fn: () => Res,
|
|
30
42
|
): Res extends Effect.Effect<infer A, infer E, never>
|
|
@@ -113,11 +125,11 @@ export const logWarnIfTakesLongerThan =
|
|
|
113
125
|
Effect.gen(function* () {
|
|
114
126
|
const runtime = yield* Effect.runtime<never>()
|
|
115
127
|
|
|
116
|
-
let
|
|
128
|
+
let tookLongerThanTimer = false
|
|
117
129
|
|
|
118
130
|
const timeoutFiber = Effect.sleep(duration).pipe(
|
|
119
131
|
Effect.tap(() => {
|
|
120
|
-
|
|
132
|
+
tookLongerThanTimer = true
|
|
121
133
|
// TODO include span info
|
|
122
134
|
return Effect.logWarning(`${label}: Took longer than ${duration}ms`)
|
|
123
135
|
}),
|
|
@@ -126,9 +138,22 @@ export const logWarnIfTakesLongerThan =
|
|
|
126
138
|
)
|
|
127
139
|
|
|
128
140
|
const start = Date.now()
|
|
129
|
-
const res = yield* eff.pipe(
|
|
141
|
+
const res = yield* eff.pipe(
|
|
142
|
+
Effect.exit,
|
|
143
|
+
Effect.onInterrupt(
|
|
144
|
+
Effect.fn(function* () {
|
|
145
|
+
const end = Date.now()
|
|
146
|
+
|
|
147
|
+
yield* Fiber.interrupt(timeoutFiber)
|
|
148
|
+
|
|
149
|
+
if (tookLongerThanTimer) {
|
|
150
|
+
yield* Effect.logWarning(`${label}: Interrupted after ${end - start}ms`)
|
|
151
|
+
}
|
|
152
|
+
}),
|
|
153
|
+
),
|
|
154
|
+
)
|
|
130
155
|
|
|
131
|
-
if (
|
|
156
|
+
if (tookLongerThanTimer) {
|
|
132
157
|
const end = Date.now()
|
|
133
158
|
yield* Effect.logWarning(`${label}: Actual duration: ${end - start}ms`)
|
|
134
159
|
}
|
package/src/effect/Logger.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Logger } from 'effect'
|
|
1
|
+
import { Cause, HashMap, Logger, LogLevel } from 'effect'
|
|
2
2
|
|
|
3
3
|
export * from 'effect/Logger'
|
|
4
4
|
|
|
@@ -14,4 +14,26 @@ export const prettyWithThread = (threadName: string) =>
|
|
|
14
14
|
Logger.prettyLogger({
|
|
15
15
|
formatDate: (date) => `${defaultDateFormat(date)} ${threadName}`,
|
|
16
16
|
}),
|
|
17
|
+
// consoleLogger(threadName),
|
|
17
18
|
)
|
|
19
|
+
|
|
20
|
+
export const consoleLogger = (threadName: string) =>
|
|
21
|
+
Logger.make(({ message, annotations, date, logLevel, cause }) => {
|
|
22
|
+
const consoleFn =
|
|
23
|
+
logLevel === LogLevel.Debug
|
|
24
|
+
? console.debug
|
|
25
|
+
: logLevel === LogLevel.Info
|
|
26
|
+
? console.info
|
|
27
|
+
: logLevel === LogLevel.Warning
|
|
28
|
+
? console.warn
|
|
29
|
+
: console.error
|
|
30
|
+
|
|
31
|
+
const annotationsObj = Object.fromEntries(HashMap.entries(annotations))
|
|
32
|
+
|
|
33
|
+
const messages = Array.isArray(message) ? message : [message]
|
|
34
|
+
if (Cause.isEmpty(cause) === false) {
|
|
35
|
+
messages.push(Cause.pretty(cause, { renderErrorCause: true }))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
consoleFn(`[${defaultDateFormat(date)} ${threadName}]`, ...messages, annotationsObj)
|
|
39
|
+
})
|
|
@@ -56,3 +56,18 @@ export const JsonValue: Schema.Schema<JsonValue> = Schema.Union(
|
|
|
56
56
|
Schema.Array(Schema.suspend(() => JsonValue)),
|
|
57
57
|
Schema.Record({ key: Schema.String, value: Schema.suspend(() => JsonValue) }),
|
|
58
58
|
).annotations({ title: 'JsonValue' })
|
|
59
|
+
|
|
60
|
+
export const SearchParamsString = Schema.transform(
|
|
61
|
+
Schema.String,
|
|
62
|
+
Schema.Union(Schema.Record({ key: Schema.String, value: Schema.String }), Schema.String),
|
|
63
|
+
{
|
|
64
|
+
decode: (searchParamsString) => {
|
|
65
|
+
const searchParams = new URLSearchParams(searchParamsString)
|
|
66
|
+
return Object.fromEntries(searchParams.entries())
|
|
67
|
+
},
|
|
68
|
+
encode: (searchParams) => {
|
|
69
|
+
const searchParamsString = new URLSearchParams(Object.entries(searchParams)).toString()
|
|
70
|
+
return searchParamsString
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Fork of effect/Subscribable.ts which makes Subscribable yieldable
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @since 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { SubscriptionRef } from 'effect'
|
|
8
|
+
import { Effect, Effectable, Readable, Stream } from 'effect'
|
|
9
|
+
import { dual } from 'effect/Function'
|
|
10
|
+
import { hasProperty } from 'effect/Predicate'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @since 2.0.0
|
|
14
|
+
* @category type ids
|
|
15
|
+
*/
|
|
16
|
+
export const TypeId: unique symbol = Symbol.for('effect/Subscribable')
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @since 2.0.0
|
|
20
|
+
* @category type ids
|
|
21
|
+
*/
|
|
22
|
+
export type TypeId = typeof TypeId
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @since 2.0.0
|
|
26
|
+
* @category models
|
|
27
|
+
*/
|
|
28
|
+
export interface Subscribable<A, E = never, R = never> extends Readable.Readable<A, E, R>, Effect.Effect<A, E, R> {
|
|
29
|
+
readonly [TypeId]: TypeId
|
|
30
|
+
readonly changes: Stream.Stream<A, E, R>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @since 2.0.0
|
|
35
|
+
* @category refinements
|
|
36
|
+
*/
|
|
37
|
+
export const isSubscribable = (u: unknown): u is Subscribable<unknown, unknown, unknown> => hasProperty(u, TypeId)
|
|
38
|
+
|
|
39
|
+
// const Proto: Omit<Subscribable<any>, 'get' | 'changes'> = {
|
|
40
|
+
// [Readable.TypeId]: Readable.TypeId,
|
|
41
|
+
// [TypeId]: TypeId,
|
|
42
|
+
// pipe() {
|
|
43
|
+
// return pipeArguments(this, arguments)
|
|
44
|
+
// },
|
|
45
|
+
// }
|
|
46
|
+
|
|
47
|
+
class SubscribableImpl<in out A> extends Effectable.Class<A> implements Subscribable<A> {
|
|
48
|
+
// @ts-expect-error type symbol
|
|
49
|
+
readonly [TypeId] = TypeId
|
|
50
|
+
// @ts-expect-error type symbol
|
|
51
|
+
readonly [Readable.TypeId] = Readable.TypeId
|
|
52
|
+
constructor(
|
|
53
|
+
readonly get: Effect.Effect<A>,
|
|
54
|
+
readonly changes: Stream.Stream<A>,
|
|
55
|
+
) {
|
|
56
|
+
super()
|
|
57
|
+
}
|
|
58
|
+
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
|
59
|
+
commit() {
|
|
60
|
+
return this.get
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @since 2.0.0
|
|
66
|
+
* @category constructors
|
|
67
|
+
*/
|
|
68
|
+
// export const make = <A, E, R>(options: {
|
|
69
|
+
// readonly get: Effect.Effect<A, E, R>
|
|
70
|
+
// readonly changes: Stream.Stream<A, E, R>
|
|
71
|
+
// }): Subscribable<A, E, R> => Object.assign(Object.create(Proto), options)
|
|
72
|
+
|
|
73
|
+
export const make = <A, E, R>(options: {
|
|
74
|
+
readonly get: Effect.Effect<A, E, R>
|
|
75
|
+
readonly changes: Stream.Stream<A, E, R>
|
|
76
|
+
}): Subscribable<A, E, R> => new SubscribableImpl(options.get as any, options.changes as any) as Subscribable<A, E, R>
|
|
77
|
+
|
|
78
|
+
export const fromSubscriptionRef = <A>(ref: SubscriptionRef.SubscriptionRef<A>): Subscribable<A> =>
|
|
79
|
+
make({
|
|
80
|
+
get: ref.get,
|
|
81
|
+
changes: ref.changes,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @since 2.0.0
|
|
86
|
+
* @category combinators
|
|
87
|
+
*/
|
|
88
|
+
export const map: {
|
|
89
|
+
/**
|
|
90
|
+
* @since 2.0.0
|
|
91
|
+
* @category combinators
|
|
92
|
+
*/
|
|
93
|
+
<A, B>(f: (a: NoInfer<A>) => B): <E, R>(fa: Subscribable<A, E, R>) => Subscribable<B, E, R>
|
|
94
|
+
/**
|
|
95
|
+
* @since 2.0.0
|
|
96
|
+
* @category combinators
|
|
97
|
+
*/
|
|
98
|
+
<A, E, R, B>(self: Subscribable<A, E, R>, f: (a: NoInfer<A>) => B): Subscribable<B, E, R>
|
|
99
|
+
} = dual(
|
|
100
|
+
2,
|
|
101
|
+
<A, E, R, B>(self: Subscribable<A, E, R>, f: (a: NoInfer<A>) => B): Subscribable<B, E, R> =>
|
|
102
|
+
make({
|
|
103
|
+
get: Effect.map(self.get, f),
|
|
104
|
+
changes: Stream.map(self.changes, f),
|
|
105
|
+
}),
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @since 2.0.0
|
|
110
|
+
* @category combinators
|
|
111
|
+
*/
|
|
112
|
+
export const mapEffect: {
|
|
113
|
+
/**
|
|
114
|
+
* @since 2.0.0
|
|
115
|
+
* @category combinators
|
|
116
|
+
*/
|
|
117
|
+
<A, B, E2, R2>(
|
|
118
|
+
f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2>,
|
|
119
|
+
): <E, R>(fa: Subscribable<A, E, R>) => Subscribable<B, E | E2, R | R2>
|
|
120
|
+
/**
|
|
121
|
+
* @since 2.0.0
|
|
122
|
+
* @category combinators
|
|
123
|
+
*/
|
|
124
|
+
<A, E, R, B, E2, R2>(
|
|
125
|
+
self: Subscribable<A, E, R>,
|
|
126
|
+
f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2>,
|
|
127
|
+
): Subscribable<B, E | E2, R | R2>
|
|
128
|
+
} = dual(
|
|
129
|
+
2,
|
|
130
|
+
<A, E, R, B, E2, R2>(
|
|
131
|
+
self: Subscribable<A, E, R>,
|
|
132
|
+
f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2>,
|
|
133
|
+
): Subscribable<B, E | E2, R | R2> =>
|
|
134
|
+
make({
|
|
135
|
+
get: Effect.flatMap(self.get, f),
|
|
136
|
+
changes: Stream.mapEffect(self.changes, f),
|
|
137
|
+
}),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @since 2.0.0
|
|
142
|
+
* @category constructors
|
|
143
|
+
*/
|
|
144
|
+
export const unwrap = <A, E, R, E1, R1>(
|
|
145
|
+
effect: Effect.Effect<Subscribable<A, E, R>, E1, R1>,
|
|
146
|
+
): Subscribable<A, E | E1, R | R1> =>
|
|
147
|
+
make({
|
|
148
|
+
get: Effect.flatMap(effect, (s) => s.get),
|
|
149
|
+
changes: Stream.unwrap(Effect.map(effect, (s) => s.changes)),
|
|
150
|
+
})
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as Vitest from '@effect/vitest'
|
|
2
|
+
import { Effect, Schema, Stream } from 'effect'
|
|
3
|
+
import { JSDOM } from 'jsdom'
|
|
4
|
+
|
|
5
|
+
import * as WebChannel from './WebChannel.js'
|
|
6
|
+
|
|
7
|
+
Vitest.describe('WebChannel', () => {
|
|
8
|
+
Vitest.describe('windowChannel', () => {
|
|
9
|
+
Vitest.scopedLive('should work with 2 windows', () =>
|
|
10
|
+
Effect.gen(function* () {
|
|
11
|
+
const windowA = new JSDOM().window as unknown as globalThis.Window
|
|
12
|
+
const windowB = new JSDOM().window as unknown as globalThis.Window
|
|
13
|
+
|
|
14
|
+
const codeSideA = Effect.gen(function* () {
|
|
15
|
+
const channelToB = yield* WebChannel.windowChannel2({
|
|
16
|
+
listenWindow: windowA,
|
|
17
|
+
sendWindow: windowB,
|
|
18
|
+
ids: { own: 'a', other: 'b' },
|
|
19
|
+
schema: Schema.Number,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const msgFromBFiber = yield* channelToB.listen.pipe(
|
|
23
|
+
Stream.flatten(),
|
|
24
|
+
Stream.runHead,
|
|
25
|
+
Effect.flatten,
|
|
26
|
+
Effect.fork,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
yield* channelToB.send(1)
|
|
30
|
+
|
|
31
|
+
Vitest.expect(yield* msgFromBFiber).toEqual(2)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const codeSideB = Effect.gen(function* () {
|
|
35
|
+
const channelToA = yield* WebChannel.windowChannel2({
|
|
36
|
+
listenWindow: windowB,
|
|
37
|
+
sendWindow: windowA,
|
|
38
|
+
ids: { own: 'b', other: 'a' },
|
|
39
|
+
schema: Schema.Number,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const msgFromAFiber = yield* channelToA.listen.pipe(
|
|
43
|
+
Stream.flatten(),
|
|
44
|
+
Stream.runHead,
|
|
45
|
+
Effect.flatten,
|
|
46
|
+
Effect.fork,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
yield* channelToA.send(2)
|
|
50
|
+
|
|
51
|
+
Vitest.expect(yield* msgFromAFiber).toEqual(1)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
yield* Effect.all([codeSideA, codeSideB], { concurrency: 'unbounded' })
|
|
55
|
+
}),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
Vitest.scopedLive('should work with the same window', () =>
|
|
59
|
+
Effect.gen(function* () {
|
|
60
|
+
const window = new JSDOM().window as unknown as globalThis.Window
|
|
61
|
+
|
|
62
|
+
const codeSideA = Effect.gen(function* () {
|
|
63
|
+
const channelToB = yield* WebChannel.windowChannel2({
|
|
64
|
+
listenWindow: window,
|
|
65
|
+
sendWindow: window,
|
|
66
|
+
ids: { own: 'a', other: 'b' },
|
|
67
|
+
schema: Schema.Number,
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
const msgFromBFiber = yield* channelToB.listen.pipe(
|
|
71
|
+
Stream.flatten(),
|
|
72
|
+
Stream.runHead,
|
|
73
|
+
Effect.flatten,
|
|
74
|
+
Effect.fork,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
yield* channelToB.send(1)
|
|
78
|
+
|
|
79
|
+
Vitest.expect(yield* msgFromBFiber).toEqual(2)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const codeSideB = Effect.gen(function* () {
|
|
83
|
+
const channelToA = yield* WebChannel.windowChannel2({
|
|
84
|
+
listenWindow: window,
|
|
85
|
+
sendWindow: window,
|
|
86
|
+
ids: { own: 'b', other: 'a' },
|
|
87
|
+
schema: Schema.Number,
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const msgFromAFiber = yield* channelToA.listen.pipe(
|
|
91
|
+
Stream.flatten(),
|
|
92
|
+
Stream.runHead,
|
|
93
|
+
Effect.flatten,
|
|
94
|
+
Effect.fork,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
yield* channelToA.send(2)
|
|
98
|
+
|
|
99
|
+
Vitest.expect(yield* msgFromAFiber).toEqual(1)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
yield* Effect.all([codeSideA, codeSideB], { concurrency: 'unbounded' })
|
|
103
|
+
}),
|
|
104
|
+
)
|
|
105
|
+
})
|
|
106
|
+
})
|