@livestore/utils 0.3.0-dev.2 → 0.3.0-dev.20

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 (144) hide show
  1. package/dist/.tsbuildinfo.json +1 -1
  2. package/dist/Deferred.d.ts.map +1 -1
  3. package/dist/base64.d.ts.map +1 -1
  4. package/dist/bun/mod.d.ts +5 -0
  5. package/dist/bun/mod.d.ts.map +1 -0
  6. package/dist/bun/mod.js +9 -0
  7. package/dist/bun/mod.js.map +1 -0
  8. package/dist/cuid/cuid.browser.d.ts.map +1 -1
  9. package/dist/cuid/cuid.node.d.ts.map +1 -1
  10. package/dist/effect/BucketQueue.d.ts +15 -2
  11. package/dist/effect/BucketQueue.d.ts.map +1 -1
  12. package/dist/effect/BucketQueue.js +24 -6
  13. package/dist/effect/BucketQueue.js.map +1 -1
  14. package/dist/effect/Effect.d.ts +4 -2
  15. package/dist/effect/Effect.d.ts.map +1 -1
  16. package/dist/effect/Effect.js +19 -5
  17. package/dist/effect/Effect.js.map +1 -1
  18. package/dist/effect/Logger.d.ts +2 -0
  19. package/dist/effect/Logger.d.ts.map +1 -1
  20. package/dist/effect/Logger.js +16 -1
  21. package/dist/effect/Logger.js.map +1 -1
  22. package/dist/effect/Scheduler.d.ts.map +1 -1
  23. package/dist/effect/Schema/debug-diff.d.ts.map +1 -1
  24. package/dist/effect/Schema/index.d.ts +1 -0
  25. package/dist/effect/Schema/index.d.ts.map +1 -1
  26. package/dist/effect/Schema/index.js +10 -0
  27. package/dist/effect/Schema/index.js.map +1 -1
  28. package/dist/effect/Schema/msgpack.d.ts +1 -1
  29. package/dist/effect/Schema/msgpack.d.ts.map +1 -1
  30. package/dist/effect/ServiceContext.d.ts.map +1 -1
  31. package/dist/effect/Stream.d.ts.map +1 -1
  32. package/dist/effect/Subscribable.d.ts +75 -0
  33. package/dist/effect/Subscribable.d.ts.map +1 -0
  34. package/dist/effect/Subscribable.js +76 -0
  35. package/dist/effect/Subscribable.js.map +1 -0
  36. package/dist/effect/TaskTracing.d.ts.map +1 -1
  37. package/dist/effect/{WebChannel.d.ts → WebChannel/WebChannel.d.ts} +32 -14
  38. package/dist/effect/WebChannel/WebChannel.d.ts.map +1 -0
  39. package/dist/effect/WebChannel/WebChannel.js +283 -0
  40. package/dist/effect/WebChannel/WebChannel.js.map +1 -0
  41. package/dist/effect/WebChannel/WebChannel.test.d.ts +2 -0
  42. package/dist/effect/WebChannel/WebChannel.test.d.ts.map +1 -0
  43. package/dist/effect/WebChannel/WebChannel.test.js +62 -0
  44. package/dist/effect/WebChannel/WebChannel.test.js.map +1 -0
  45. package/dist/effect/WebChannel/broadcastChannelWithAck.d.ts +5 -6
  46. package/dist/effect/WebChannel/broadcastChannelWithAck.d.ts.map +1 -1
  47. package/dist/effect/WebChannel/broadcastChannelWithAck.js +12 -9
  48. package/dist/effect/WebChannel/broadcastChannelWithAck.js.map +1 -1
  49. package/dist/effect/WebChannel/common.d.ts +16 -1
  50. package/dist/effect/WebChannel/common.d.ts.map +1 -1
  51. package/dist/effect/WebChannel/common.js +19 -1
  52. package/dist/effect/WebChannel/common.js.map +1 -1
  53. package/dist/effect/WebChannel/mod.d.ts +4 -0
  54. package/dist/effect/WebChannel/mod.d.ts.map +1 -0
  55. package/dist/effect/WebChannel/mod.js +4 -0
  56. package/dist/effect/WebChannel/mod.js.map +1 -0
  57. package/dist/effect/WebLock.d.ts.map +1 -1
  58. package/dist/effect/WebSocket.d.ts +1 -1
  59. package/dist/effect/WebSocket.d.ts.map +1 -1
  60. package/dist/effect/WebSocket.js +38 -19
  61. package/dist/effect/WebSocket.js.map +1 -1
  62. package/dist/effect/WebSocket.test.d.ts +2 -0
  63. package/dist/effect/WebSocket.test.d.ts.map +1 -0
  64. package/dist/effect/WebSocket.test.js +10 -0
  65. package/dist/effect/WebSocket.test.js.map +1 -0
  66. package/dist/effect/index.d.ts +4 -2
  67. package/dist/effect/index.d.ts.map +1 -1
  68. package/dist/effect/index.js +6 -2
  69. package/dist/effect/index.js.map +1 -1
  70. package/dist/env.d.ts +1 -0
  71. package/dist/env.d.ts.map +1 -1
  72. package/dist/env.js +3 -0
  73. package/dist/env.js.map +1 -1
  74. package/dist/fast-deep-equal.d.ts.map +1 -1
  75. package/dist/guards.d.ts.map +1 -1
  76. package/dist/index.d.ts +5 -4
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js.map +1 -1
  79. package/dist/misc.d.ts.map +1 -1
  80. package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts +0 -1
  81. package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts.map +1 -1
  82. package/dist/node/ChildProcessRunner/ChildProcessRunner.js +17 -11
  83. package/dist/node/ChildProcessRunner/ChildProcessRunner.js.map +1 -1
  84. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts +2 -0
  85. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts.map +1 -0
  86. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js +39 -0
  87. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js.map +1 -0
  88. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts +75 -0
  89. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts.map +1 -0
  90. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js +62 -0
  91. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js.map +1 -0
  92. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts +2 -0
  93. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts.map +1 -0
  94. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js +42 -0
  95. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js.map +1 -0
  96. package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts +1 -4
  97. package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts.map +1 -1
  98. package/dist/node/ChildProcessRunner/ChildProcessWorker.js +1 -4
  99. package/dist/node/ChildProcessRunner/ChildProcessWorker.js.map +1 -1
  100. package/dist/node/mod.d.ts +3 -2
  101. package/dist/node/mod.d.ts.map +1 -1
  102. package/dist/node/mod.js +36 -9
  103. package/dist/node/mod.js.map +1 -1
  104. package/dist/object/index.d.ts.map +1 -1
  105. package/dist/object/omit.d.ts.map +1 -1
  106. package/dist/object/pick.d.ts.map +1 -1
  107. package/dist/promise.d.ts.map +1 -1
  108. package/dist/set.d.ts.map +1 -1
  109. package/dist/string.d.ts.map +1 -1
  110. package/dist/time.d.ts.map +1 -1
  111. package/package.json +56 -40
  112. package/src/bun/mod.ts +12 -0
  113. package/src/effect/BucketQueue.ts +33 -6
  114. package/src/effect/Effect.ts +31 -6
  115. package/src/effect/Logger.ts +23 -1
  116. package/src/effect/Schema/index.ts +15 -0
  117. package/src/effect/Subscribable.ts +150 -0
  118. package/src/effect/WebChannel/WebChannel.test.ts +106 -0
  119. package/src/effect/WebChannel/WebChannel.ts +477 -0
  120. package/src/effect/WebChannel/broadcastChannelWithAck.ts +86 -83
  121. package/src/effect/WebChannel/common.ts +49 -2
  122. package/src/effect/WebChannel/mod.ts +3 -0
  123. package/src/effect/WebSocket.test.ts +14 -0
  124. package/src/effect/WebSocket.ts +64 -37
  125. package/src/effect/index.ts +10 -1
  126. package/src/env.ts +5 -0
  127. package/src/index.ts +4 -2
  128. package/src/node/ChildProcessRunner/ChildProcessRunner.ts +35 -29
  129. package/src/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.ts +52 -0
  130. package/src/node/ChildProcessRunner/ChildProcessRunnerTest/schema.ts +65 -0
  131. package/src/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.ts +53 -0
  132. package/src/node/ChildProcessRunner/ChildProcessWorker.ts +3 -6
  133. package/src/node/mod.ts +48 -10
  134. package/tmp/pack.tgz +0 -0
  135. package/tsconfig.json +1 -1
  136. package/dist/effect/WebChannel.d.ts.map +0 -1
  137. package/dist/effect/WebChannel.js +0 -162
  138. package/dist/effect/WebChannel.js.map +0 -1
  139. package/dist/nanoid/index.browser.d.ts +0 -2
  140. package/dist/nanoid/index.browser.d.ts.map +0 -1
  141. package/dist/nanoid/index.browser.js +0 -3
  142. package/dist/nanoid/index.browser.js.map +0 -1
  143. package/src/effect/WebChannel.ts +0 -290
  144. 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>(self: BucketQueue<A>, min: number, max: number) =>
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 bucket = yield* TRef.get(self)
15
- if (bucket.length < min) {
20
+ const bucketValue = yield* TRef.get(bucket)
21
+ if (bucketValue.length < min) {
16
22
  return yield* STM.retry
17
23
  } else {
18
- const elements = bucket.splice(0, Math.min(max, bucket.length))
19
- yield* TRef.set(self, bucket)
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))
@@ -1,6 +1,6 @@
1
1
  import * as OtelTracer from '@effect/opentelemetry/Tracer'
2
- import type { Context, Duration, Scope, Stream } from 'effect'
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 timedOut = false
128
+ let tookLongerThanTimer = false
117
129
 
118
130
  const timeoutFiber = Effect.sleep(duration).pipe(
119
131
  Effect.tap(() => {
120
- timedOut = true
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(Effect.exit)
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 (timedOut) {
156
+ if (tookLongerThanTimer) {
132
157
  const end = Date.now()
133
158
  yield* Effect.logWarning(`${label}: Actual duration: ${end - start}ms`)
134
159
  }
@@ -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
+ })