@livestore/utils 0.3.0-dev.10 → 0.3.0-dev.12
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/effect/Effect.d.ts +4 -2
- package/dist/effect/Effect.d.ts.map +1 -1
- package/dist/effect/Effect.js +9 -1
- package/dist/effect/Effect.js.map +1 -1
- package/dist/effect/WebChannel/WebChannel.d.ts +61 -0
- package/dist/effect/WebChannel/WebChannel.d.ts.map +1 -0
- package/dist/effect/WebChannel/WebChannel.js +209 -0
- package/dist/effect/WebChannel/WebChannel.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 -8
- 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 +30 -1
- package/dist/effect/WebChannel/common.js.map +1 -1
- package/dist/effect/WebChannel.d.ts +5 -12
- package/dist/effect/WebChannel.d.ts.map +1 -1
- package/dist/effect/WebChannel.js +16 -31
- package/dist/effect/WebChannel.js.map +1 -1
- package/dist/effect/index.d.ts +2 -2
- package/dist/effect/index.d.ts.map +1 -1
- package/dist/effect/index.js +2 -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 +2 -0
- package/dist/env.js.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 +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts +0 -3
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js +0 -3
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js.map +1 -1
- package/package.json +4 -3
- package/src/effect/Effect.ts +14 -2
- package/src/effect/WebChannel/WebChannel.ts +357 -0
- package/src/effect/WebChannel/broadcastChannelWithAck.ts +86 -82
- package/src/effect/WebChannel/common.ts +56 -2
- package/src/effect/index.ts +4 -1
- package/src/env.ts +4 -0
- package/src/node/ChildProcessRunner/ChildProcessRunner.ts +0 -1
- package/src/node/ChildProcessRunner/ChildProcessWorker.ts +0 -3
- package/src/effect/WebChannel.ts +0 -305
package/src/effect/WebChannel.ts
DELETED
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
import type { Scope } from 'effect'
|
|
2
|
-
import { Deferred, Effect, Either, Option, Predicate, Queue } from 'effect'
|
|
3
|
-
|
|
4
|
-
import * as Schema from './Schema/index.js'
|
|
5
|
-
import * as Stream from './Stream.js'
|
|
6
|
-
import { type WebChannel, WebChannelSymbol } from './WebChannel/common.js'
|
|
7
|
-
|
|
8
|
-
export * from './WebChannel/broadcastChannelWithAck.js'
|
|
9
|
-
|
|
10
|
-
export * from './WebChannel/common.js'
|
|
11
|
-
|
|
12
|
-
export const noopChannel = <MsgListen, MsgSend>(): Effect.Effect<WebChannel<MsgListen, MsgSend>> =>
|
|
13
|
-
Effect.gen(function* () {
|
|
14
|
-
return {
|
|
15
|
-
[WebChannelSymbol]: WebChannelSymbol,
|
|
16
|
-
send: () => Effect.void,
|
|
17
|
-
listen: Stream.never,
|
|
18
|
-
closedDeferred: yield* Deferred.make<void>(),
|
|
19
|
-
schema: {
|
|
20
|
-
listen: Schema.Any,
|
|
21
|
-
send: Schema.Any,
|
|
22
|
-
} as any,
|
|
23
|
-
supportsTransferables: false,
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
export const broadcastChannel = <MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>({
|
|
28
|
-
channelName,
|
|
29
|
-
schema: inputSchema,
|
|
30
|
-
}: {
|
|
31
|
-
channelName: string
|
|
32
|
-
schema: InputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>
|
|
33
|
-
}): Effect.Effect<WebChannel<MsgListen, MsgSend>, never, Scope.Scope> =>
|
|
34
|
-
Effect.gen(function* () {
|
|
35
|
-
const schema = mapSchema(inputSchema)
|
|
36
|
-
|
|
37
|
-
const channel = new BroadcastChannel(channelName)
|
|
38
|
-
|
|
39
|
-
yield* Effect.addFinalizer(() => Effect.try(() => channel.close()).pipe(Effect.ignoreLogged))
|
|
40
|
-
|
|
41
|
-
const send = (message: MsgSend) =>
|
|
42
|
-
Effect.gen(function* () {
|
|
43
|
-
const messageEncoded = yield* Schema.encode(schema.send)(message)
|
|
44
|
-
channel.postMessage(messageEncoded)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
// TODO also listen to `messageerror` in parallel
|
|
48
|
-
const listen = Stream.fromEventListener<MessageEvent>(channel, 'message').pipe(
|
|
49
|
-
Stream.map((_) => Schema.decodeEither(schema.listen)(_.data)),
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
const closedDeferred = yield* Deferred.make<void>()
|
|
53
|
-
const supportsTransferables = false
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
[WebChannelSymbol]: WebChannelSymbol,
|
|
57
|
-
send,
|
|
58
|
-
listen,
|
|
59
|
-
closedDeferred,
|
|
60
|
-
schema,
|
|
61
|
-
supportsTransferables,
|
|
62
|
-
}
|
|
63
|
-
}).pipe(Effect.withSpan(`WebChannel:broadcastChannel(${channelName})`))
|
|
64
|
-
|
|
65
|
-
export const windowChannel = <MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>({
|
|
66
|
-
window,
|
|
67
|
-
targetOrigin = '*',
|
|
68
|
-
schema: inputSchema,
|
|
69
|
-
}: {
|
|
70
|
-
window: Window
|
|
71
|
-
targetOrigin?: string
|
|
72
|
-
schema: InputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>
|
|
73
|
-
}): Effect.Effect<WebChannel<MsgListen, MsgSend>, never, Scope.Scope> =>
|
|
74
|
-
Effect.gen(function* () {
|
|
75
|
-
const schema = mapSchema(inputSchema)
|
|
76
|
-
|
|
77
|
-
const send = (message: MsgSend) =>
|
|
78
|
-
Effect.gen(function* () {
|
|
79
|
-
const [messageEncoded, transferables] = yield* Schema.encodeWithTransferables(schema.send)(message)
|
|
80
|
-
window.postMessage(messageEncoded, targetOrigin, transferables)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
const listen = Stream.fromEventListener<MessageEvent>(window, 'message').pipe(
|
|
84
|
-
Stream.map((_) => Schema.decodeEither(schema.listen)(_.data)),
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
const closedDeferred = yield* Deferred.make<void>()
|
|
88
|
-
const supportsTransferables = true
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
[WebChannelSymbol]: WebChannelSymbol,
|
|
92
|
-
send,
|
|
93
|
-
listen,
|
|
94
|
-
closedDeferred,
|
|
95
|
-
schema,
|
|
96
|
-
supportsTransferables,
|
|
97
|
-
}
|
|
98
|
-
}).pipe(Effect.withSpan(`WebChannel:windowChannel`))
|
|
99
|
-
|
|
100
|
-
export const messagePortChannel: {
|
|
101
|
-
<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>(args: {
|
|
102
|
-
port: MessagePort
|
|
103
|
-
schema: InputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>
|
|
104
|
-
}): Effect.Effect<WebChannel<MsgListen, MsgSend>, never, Scope.Scope>
|
|
105
|
-
} = ({ port, schema: inputSchema }) =>
|
|
106
|
-
Effect.gen(function* () {
|
|
107
|
-
const schema = mapSchema(inputSchema)
|
|
108
|
-
|
|
109
|
-
const send = (message: any) =>
|
|
110
|
-
Effect.gen(function* () {
|
|
111
|
-
const [messageEncoded, transferables] = yield* Schema.encodeWithTransferables(schema.send)(message)
|
|
112
|
-
port.postMessage(messageEncoded, transferables)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
const listen = Stream.fromEventListener<MessageEvent>(port, 'message').pipe(
|
|
116
|
-
Stream.map((_) => Schema.decodeEither(schema.listen)(_.data)),
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
port.start()
|
|
120
|
-
|
|
121
|
-
const closedDeferred = yield* Deferred.make<void>()
|
|
122
|
-
const supportsTransferables = true
|
|
123
|
-
|
|
124
|
-
yield* Effect.addFinalizer(() => Effect.try(() => port.close()).pipe(Effect.ignoreLogged))
|
|
125
|
-
|
|
126
|
-
return {
|
|
127
|
-
[WebChannelSymbol]: WebChannelSymbol,
|
|
128
|
-
send,
|
|
129
|
-
listen,
|
|
130
|
-
closedDeferred,
|
|
131
|
-
schema,
|
|
132
|
-
supportsTransferables,
|
|
133
|
-
}
|
|
134
|
-
}).pipe(Effect.withSpan(`WebChannel:messagePortChannel`))
|
|
135
|
-
|
|
136
|
-
export const messagePortChannelWithAck: {
|
|
137
|
-
<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>(args: {
|
|
138
|
-
port: MessagePort
|
|
139
|
-
schema: InputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>
|
|
140
|
-
}): Effect.Effect<WebChannel<MsgListen, MsgSend>, never, Scope.Scope>
|
|
141
|
-
} = ({ port, schema: inputSchema }) =>
|
|
142
|
-
Effect.gen(function* () {
|
|
143
|
-
const schema = mapSchema(inputSchema)
|
|
144
|
-
|
|
145
|
-
type RequestId = string
|
|
146
|
-
const requestAckMap = new Map<RequestId, Deferred.Deferred<void>>()
|
|
147
|
-
|
|
148
|
-
const ChannelRequest = Schema.TaggedStruct('ChannelRequest', {
|
|
149
|
-
id: Schema.String,
|
|
150
|
-
payload: Schema.Union(schema.listen, schema.send),
|
|
151
|
-
})
|
|
152
|
-
const ChannelRequestAck = Schema.TaggedStruct('ChannelRequestAck', {
|
|
153
|
-
reqId: Schema.String,
|
|
154
|
-
})
|
|
155
|
-
const ChannelMessage = Schema.Union(ChannelRequest, ChannelRequestAck)
|
|
156
|
-
type ChannelMessage = typeof ChannelMessage.Type
|
|
157
|
-
|
|
158
|
-
const send = (message: any) =>
|
|
159
|
-
Effect.gen(function* () {
|
|
160
|
-
const id = crypto.randomUUID()
|
|
161
|
-
const [messageEncoded, transferables] = yield* Schema.encodeWithTransferables(ChannelMessage)({
|
|
162
|
-
_tag: 'ChannelRequest',
|
|
163
|
-
id,
|
|
164
|
-
payload: message,
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
const ack = yield* Deferred.make<void>()
|
|
168
|
-
requestAckMap.set(id, ack)
|
|
169
|
-
|
|
170
|
-
port.postMessage(messageEncoded, transferables)
|
|
171
|
-
|
|
172
|
-
yield* ack
|
|
173
|
-
|
|
174
|
-
requestAckMap.delete(id)
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
const listen = Stream.fromEventListener<MessageEvent>(port, 'message').pipe(
|
|
178
|
-
Stream.map((_) => Schema.decodeEither(ChannelMessage)(_.data)),
|
|
179
|
-
Stream.tap((msg) =>
|
|
180
|
-
Effect.gen(function* () {
|
|
181
|
-
if (msg._tag === 'Right') {
|
|
182
|
-
if (msg.right._tag === 'ChannelRequestAck') {
|
|
183
|
-
yield* Deferred.succeed(requestAckMap.get(msg.right.reqId)!, void 0)
|
|
184
|
-
} else if (msg.right._tag === 'ChannelRequest') {
|
|
185
|
-
port.postMessage(Schema.encodeSync(ChannelMessage)({ _tag: 'ChannelRequestAck', reqId: msg.right.id }))
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}),
|
|
189
|
-
),
|
|
190
|
-
Stream.filterMap((msg) =>
|
|
191
|
-
msg._tag === 'Left'
|
|
192
|
-
? Option.some(msg as any)
|
|
193
|
-
: msg.right._tag === 'ChannelRequest'
|
|
194
|
-
? Option.some(Either.right(msg.right.payload))
|
|
195
|
-
: Option.none(),
|
|
196
|
-
),
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
port.start()
|
|
200
|
-
|
|
201
|
-
const closedDeferred = yield* Deferred.make<void>()
|
|
202
|
-
const supportsTransferables = true
|
|
203
|
-
|
|
204
|
-
yield* Effect.addFinalizer(() => Effect.try(() => port.close()).pipe(Effect.ignoreLogged))
|
|
205
|
-
|
|
206
|
-
return {
|
|
207
|
-
[WebChannelSymbol]: WebChannelSymbol,
|
|
208
|
-
send,
|
|
209
|
-
listen,
|
|
210
|
-
closedDeferred,
|
|
211
|
-
schema,
|
|
212
|
-
supportsTransferables,
|
|
213
|
-
}
|
|
214
|
-
}).pipe(Effect.withSpan(`WebChannel:messagePortChannelWithAck`))
|
|
215
|
-
|
|
216
|
-
export type InputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded> =
|
|
217
|
-
| Schema.Schema<MsgListen | MsgSend, MsgListenEncoded | MsgSendEncoded>
|
|
218
|
-
| {
|
|
219
|
-
listen: Schema.Schema<MsgListen, MsgListenEncoded>
|
|
220
|
-
send: Schema.Schema<MsgSend, MsgSendEncoded>
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
export const mapSchema = <MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>(
|
|
224
|
-
schema: InputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>,
|
|
225
|
-
): {
|
|
226
|
-
listen: Schema.Schema<MsgListen, MsgListenEncoded>
|
|
227
|
-
send: Schema.Schema<MsgSend, MsgSendEncoded>
|
|
228
|
-
} =>
|
|
229
|
-
Predicate.hasProperty(schema, 'send') && Predicate.hasProperty(schema, 'listen')
|
|
230
|
-
? { send: schema.send, listen: schema.listen }
|
|
231
|
-
: ({ send: schema, listen: schema } as any)
|
|
232
|
-
|
|
233
|
-
export type QueueChannelProxy<MsgListen, MsgSend> = {
|
|
234
|
-
/** Only meant to be used externally */
|
|
235
|
-
webChannel: WebChannel<MsgListen, MsgSend>
|
|
236
|
-
/**
|
|
237
|
-
* Meant to be listened to (e.g. via `Stream.fromQueue`) for messages that have been sent
|
|
238
|
-
* via `webChannel.send()`.
|
|
239
|
-
*/
|
|
240
|
-
sendQueue: Queue.Dequeue<MsgSend>
|
|
241
|
-
/**
|
|
242
|
-
* Meant to be pushed to (e.g. via `Queue.offer`) for messages that will be received
|
|
243
|
-
* via `webChannel.listen()`.
|
|
244
|
-
*/
|
|
245
|
-
listenQueue: Queue.Enqueue<MsgListen>
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* From the outside the `sendQueue` is only accessible read-only,
|
|
250
|
-
* and the `listenQueue` is only accessible write-only.
|
|
251
|
-
*/
|
|
252
|
-
export const queueChannelProxy = <MsgListen, MsgSend>({
|
|
253
|
-
schema: inputSchema,
|
|
254
|
-
}: {
|
|
255
|
-
schema:
|
|
256
|
-
| Schema.Schema<MsgListen | MsgSend, any>
|
|
257
|
-
| { listen: Schema.Schema<MsgListen, any>; send: Schema.Schema<MsgSend, any> }
|
|
258
|
-
}): Effect.Effect<QueueChannelProxy<MsgListen, MsgSend>, never, Scope.Scope> =>
|
|
259
|
-
Effect.gen(function* () {
|
|
260
|
-
const sendQueue = yield* Queue.unbounded<MsgSend>().pipe(Effect.acquireRelease(Queue.shutdown))
|
|
261
|
-
const listenQueue = yield* Queue.unbounded<MsgListen>().pipe(Effect.acquireRelease(Queue.shutdown))
|
|
262
|
-
|
|
263
|
-
const send = (message: MsgSend) => Queue.offer(sendQueue, message)
|
|
264
|
-
|
|
265
|
-
const listen = Stream.fromQueue(listenQueue).pipe(Stream.map(Either.right))
|
|
266
|
-
|
|
267
|
-
const closedDeferred = yield* Deferred.make<void>()
|
|
268
|
-
const supportsTransferables = true
|
|
269
|
-
|
|
270
|
-
const schema = mapSchema(inputSchema)
|
|
271
|
-
|
|
272
|
-
const webChannel = {
|
|
273
|
-
[WebChannelSymbol]: WebChannelSymbol,
|
|
274
|
-
send,
|
|
275
|
-
listen,
|
|
276
|
-
closedDeferred,
|
|
277
|
-
schema,
|
|
278
|
-
supportsTransferables,
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return { webChannel, sendQueue, listenQueue }
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
// export const proxy = <MsgListen, MsgSend>({
|
|
285
|
-
// originWebChannel,
|
|
286
|
-
// proxyWebChannel,
|
|
287
|
-
// }: {
|
|
288
|
-
// originWebChannel: WebChannel<MsgListen, MsgSend>
|
|
289
|
-
// proxyWebChannel: QueueChannelProxy<MsgListen, MsgSend>
|
|
290
|
-
// }) =>
|
|
291
|
-
// Effect.gen(function* () {
|
|
292
|
-
// const proxyListen = originWebChannel.listen.pipe(
|
|
293
|
-
// Stream.flatten(),
|
|
294
|
-
// Stream.tap((_) => Queue.offer(proxyWebChannel.listenQueue, _)),
|
|
295
|
-
// Stream.runDrain,
|
|
296
|
-
// )
|
|
297
|
-
|
|
298
|
-
// const proxySend = proxyWebChannel.sendQueue.pipe(
|
|
299
|
-
// Stream.fromQueue,
|
|
300
|
-
// Stream.tap(originWebChannel.send),
|
|
301
|
-
// Stream.runDrain,
|
|
302
|
-
// )
|
|
303
|
-
|
|
304
|
-
// yield* Effect.all([proxyListen, proxySend], { concurrency: 2 })
|
|
305
|
-
// })
|