liminal 0.17.5 → 0.17.6
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/Actor.ts +27 -42
- package/Audition.ts +27 -48
- package/CHANGELOG.md +6 -0
- package/Client.ts +86 -164
- package/ClientHandle.ts +6 -13
- package/F.ts +5 -7
- package/Method.ts +5 -13
- package/Protocol.ts +110 -69
- package/Send.ts +5 -9
- package/dist/Actor.d.ts +14 -14
- package/dist/Actor.js +2 -2
- package/dist/Actor.js.map +1 -1
- package/dist/Audition.d.ts +7 -7
- package/dist/Audition.js.map +1 -1
- package/dist/Client.d.ts +23 -28
- package/dist/Client.js +33 -51
- package/dist/Client.js.map +1 -1
- package/dist/ClientHandle.d.ts +6 -5
- package/dist/ClientHandle.js.map +1 -1
- package/dist/F.d.ts +2 -2
- package/dist/F.js +1 -1
- package/dist/F.js.map +1 -1
- package/dist/Method.d.ts +5 -10
- package/dist/Method.js +1 -1
- package/dist/Method.js.map +1 -1
- package/dist/Protocol.d.ts +50 -35
- package/dist/Protocol.js +31 -22
- package/dist/Protocol.js.map +1 -1
- package/dist/Send.d.ts +2 -1
- package/dist/errors.d.ts +3 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/errors.ts +3 -3
- package/package.json +1 -1
package/Client.ts
CHANGED
|
@@ -21,31 +21,19 @@ import {
|
|
|
21
21
|
Cause,
|
|
22
22
|
Result,
|
|
23
23
|
flow,
|
|
24
|
-
identity,
|
|
25
24
|
} from "effect"
|
|
26
25
|
import { Socket } from "effect/unstable/socket"
|
|
27
26
|
import { Worker } from "effect/unstable/workers"
|
|
28
27
|
|
|
29
|
-
import type { MethodDefinition } from "./Method.ts"
|
|
30
|
-
|
|
31
28
|
import * as Diagnostic from "./_util/Diagnostic.ts"
|
|
32
29
|
import { type ClientError, AuditionError, ConnectionError, type FError, UnresolvedError } from "./errors.ts"
|
|
33
30
|
import { type F } from "./F.ts"
|
|
34
|
-
import
|
|
31
|
+
import { Protocol, type ProtocolDefinition } from "./Protocol.ts"
|
|
35
32
|
|
|
36
33
|
const { debug, span } = Diagnostic.module("Client")
|
|
37
34
|
|
|
38
35
|
export const TypeId = "~liminal/Client" as const
|
|
39
36
|
|
|
40
|
-
export interface ClientDefinition<
|
|
41
|
-
MethodDefinitions extends Record<string, MethodDefinition.Any>,
|
|
42
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
43
|
-
> {
|
|
44
|
-
readonly methods: MethodDefinitions
|
|
45
|
-
|
|
46
|
-
readonly events: EventDefinitions
|
|
47
|
-
}
|
|
48
|
-
|
|
49
37
|
export interface ReplayConfig {
|
|
50
38
|
readonly mode: "startup" | "all-subscribers"
|
|
51
39
|
|
|
@@ -58,60 +46,49 @@ interface EventTake<A, E> {
|
|
|
58
46
|
readonly take: Take.Take<A, E>
|
|
59
47
|
}
|
|
60
48
|
|
|
61
|
-
export interface Session<
|
|
62
|
-
|
|
63
|
-
MethodDefinitions extends Record<string, MethodDefinition.Any>,
|
|
64
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
65
|
-
> {
|
|
66
|
-
readonly events: Stream.Stream<ReturnType<typeof S.TaggedUnion<EventDefinitions>>["Type"], ClientError>
|
|
49
|
+
export interface Session<Self, D extends ProtocolDefinition> {
|
|
50
|
+
readonly events: Stream.Stream<ReturnType<typeof S.TaggedUnion<D["events"]>>["Type"], ClientError | S.SchemaError>
|
|
67
51
|
|
|
68
|
-
readonly f: F<
|
|
52
|
+
readonly f: F<Self, D>
|
|
69
53
|
|
|
70
54
|
readonly end: Effect.Effect<void>
|
|
71
55
|
}
|
|
72
56
|
|
|
73
|
-
export type Service<
|
|
74
|
-
ClientSelf,
|
|
75
|
-
MethodDefinitions extends Record<string, MethodDefinition.Any>,
|
|
76
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
77
|
-
> = RcRef.RcRef<Session<ClientSelf, MethodDefinitions, EventDefinitions>, ClientError>
|
|
57
|
+
export type Service<ClientSelf, D extends ProtocolDefinition> = RcRef.RcRef<Session<ClientSelf, D>, ClientError>
|
|
78
58
|
|
|
79
|
-
export interface Client<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
> extends Context.Service<ClientSelf, Service<ClientSelf, MethodDefinitions, EventDefinitions>> {
|
|
85
|
-
new (_: never): Context.ServiceClass.Shape<ClientId, Service<ClientSelf, MethodDefinitions, EventDefinitions>>
|
|
59
|
+
export interface Client<Self, ClientId extends string, D extends ProtocolDefinition> extends Context.Service<
|
|
60
|
+
Self,
|
|
61
|
+
Service<Self, D>
|
|
62
|
+
> {
|
|
63
|
+
new (_: never): Context.ServiceClass.Shape<ClientId, Service<Self, D>>
|
|
86
64
|
|
|
87
65
|
readonly [TypeId]: typeof TypeId
|
|
88
66
|
|
|
89
|
-
readonly definition:
|
|
67
|
+
readonly definition: D
|
|
90
68
|
|
|
91
|
-
readonly
|
|
69
|
+
readonly protocol: Protocol<D>
|
|
92
70
|
|
|
93
|
-
readonly events: Stream.Stream<
|
|
71
|
+
readonly events: Stream.Stream<
|
|
72
|
+
ReturnType<typeof S.TaggedUnion<D["events"]>>["Type"],
|
|
73
|
+
ClientError | S.SchemaError,
|
|
74
|
+
Self
|
|
75
|
+
>
|
|
94
76
|
|
|
95
|
-
readonly f: F<
|
|
77
|
+
readonly f: F<Self, D>
|
|
96
78
|
|
|
97
|
-
readonly invalidate: Effect.Effect<void, never,
|
|
79
|
+
readonly invalidate: Effect.Effect<void, never, Self>
|
|
98
80
|
}
|
|
99
81
|
|
|
100
82
|
export const Service =
|
|
101
|
-
<
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
>(
|
|
107
|
-
id: ClientId,
|
|
108
|
-
definition: ClientDefinition<MethodDefinitions, EventDefinitions>,
|
|
109
|
-
): Client<ClientSelf, ClientId, MethodDefinitions, EventDefinitions> => {
|
|
110
|
-
const tag = Context.Service<ClientSelf, Service<ClientSelf, MethodDefinitions, EventDefinitions>>()(id)
|
|
83
|
+
<Self>() =>
|
|
84
|
+
<Id extends string, D extends ProtocolDefinition>(id: Id, definition: D): Client<Self, Id, D> => {
|
|
85
|
+
const tag = Context.Service<Self, Service<Self, D>>()(id)
|
|
86
|
+
|
|
87
|
+
const protocol = Protocol(definition)
|
|
111
88
|
|
|
112
89
|
const events = tag.asEffect().pipe(Effect.flatMap(RcRef.get), Effect.map(Struct.get("events")), Stream.unwrap)
|
|
113
90
|
|
|
114
|
-
const f: F<
|
|
91
|
+
const f: F<Self, D> = (_tag) =>
|
|
115
92
|
Effect.fnUntraced(function* (value) {
|
|
116
93
|
const { f } = yield* tag.asEffect().pipe(Effect.flatMap(RcRef.get))
|
|
117
94
|
return yield* f(_tag)(value)
|
|
@@ -131,54 +108,33 @@ export const Service =
|
|
|
131
108
|
return Object.assign(tag, {
|
|
132
109
|
[TypeId]: TypeId,
|
|
133
110
|
definition,
|
|
134
|
-
|
|
111
|
+
protocol,
|
|
135
112
|
events,
|
|
136
113
|
f,
|
|
137
114
|
invalidate,
|
|
138
115
|
})
|
|
139
116
|
}
|
|
140
117
|
|
|
141
|
-
export interface
|
|
142
|
-
MethodDefinitions extends Record<string, MethodDefinition.Any>,
|
|
143
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
144
|
-
> {
|
|
118
|
+
export interface ClientTransport<D extends ProtocolDefinition> {
|
|
145
119
|
readonly listen: (
|
|
146
|
-
publish: (
|
|
147
|
-
|
|
148
|
-
| Protocol.ProtocolSchemas<MethodDefinitions, EventDefinitions>["actor"]["Type"]
|
|
149
|
-
| typeof Protocol.TransportFailure.Type,
|
|
150
|
-
) => Effect.Effect<void, ClientError>,
|
|
151
|
-
) => Effect.Effect<
|
|
152
|
-
void,
|
|
153
|
-
ClientError,
|
|
154
|
-
Scope.Scope | Protocol.ProtocolSchemas<MethodDefinitions, EventDefinitions>["actor"]["DecodingServices"]
|
|
155
|
-
>
|
|
120
|
+
publish: (message: Protocol<D>["Actor"]["Type"]) => Effect.Effect<void, ClientError>,
|
|
121
|
+
) => Effect.Effect<void, ClientError | S.SchemaError, Scope.Scope | Protocol<D>["Actor"]["DecodingServices"]>
|
|
156
122
|
|
|
157
123
|
readonly send: (
|
|
158
|
-
message: Protocol
|
|
159
|
-
) => Effect.Effect<
|
|
160
|
-
void,
|
|
161
|
-
ConnectionError,
|
|
162
|
-
Protocol.ProtocolSchemas<MethodDefinitions, EventDefinitions>["f"]["payload"]["EncodingServices"]
|
|
163
|
-
>
|
|
124
|
+
message: Protocol<D>["F"]["Payload"]["Type"],
|
|
125
|
+
) => Effect.Effect<void, ClientError | S.SchemaError, Protocol<D>["F"]["Payload"]["EncodingServices"]>
|
|
164
126
|
}
|
|
165
127
|
|
|
166
|
-
const make = <
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
MethodDefinitions extends Record<string, MethodDefinition.Any>,
|
|
170
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
171
|
-
R,
|
|
172
|
-
>(
|
|
173
|
-
client: Client<ClientSelf, ClientId, MethodDefinitions, EventDefinitions>,
|
|
174
|
-
build: Effect.Effect<Transport<MethodDefinitions, EventDefinitions>, ClientError, R | Scope.Scope>,
|
|
128
|
+
const make = <Self, Id extends string, D extends ProtocolDefinition, R>(
|
|
129
|
+
client: Client<Self, Id, D>,
|
|
130
|
+
build: Effect.Effect<ClientTransport<D>, ClientError, R | Scope.Scope>,
|
|
175
131
|
replay?: ReplayConfig | undefined,
|
|
176
132
|
) =>
|
|
177
133
|
Effect.gen(function* () {
|
|
178
|
-
const rcr: RcRef.RcRef<Session<
|
|
134
|
+
const rcr: RcRef.RcRef<Session<Self, D>, ClientError> = yield* RcRef.make({
|
|
179
135
|
acquire: Effect.gen(function* () {
|
|
180
|
-
type _ = typeof client.
|
|
181
|
-
type Event = ReturnType<typeof S.TaggedUnion<
|
|
136
|
+
type _ = typeof client.protocol
|
|
137
|
+
type Event = ReturnType<typeof S.TaggedUnion<D["events"]>>["Type"]
|
|
182
138
|
|
|
183
139
|
yield* debug("AcquisitionStarted")
|
|
184
140
|
|
|
@@ -186,7 +142,7 @@ const make = <
|
|
|
186
142
|
|
|
187
143
|
const audition = yield* Deferred.make<void>()
|
|
188
144
|
|
|
189
|
-
const inflights: Record<string, Deferred.Deferred<_["
|
|
145
|
+
const inflights: Record<string, Deferred.Deferred<_["F"]["Success"]["Type"], FError<D>>> = {}
|
|
190
146
|
let callId = 0
|
|
191
147
|
let takeCount = 0
|
|
192
148
|
const pubsub = yield* PubSub.unbounded<EventTake<Event, ClientError>>()
|
|
@@ -228,33 +184,38 @@ const make = <
|
|
|
228
184
|
const fiber = yield* listen(
|
|
229
185
|
Effect.fnUntraced(function* (message) {
|
|
230
186
|
switch (message._tag) {
|
|
231
|
-
case "
|
|
232
|
-
yield* debug("
|
|
187
|
+
case "Audition.Success": {
|
|
188
|
+
yield* debug("Audition.Succeeded")
|
|
233
189
|
yield* Deferred.succeed(audition, void 0)
|
|
234
190
|
return
|
|
235
191
|
}
|
|
192
|
+
case "Audition.Failure": {
|
|
193
|
+
const { client, routed } = message
|
|
194
|
+
yield* debug("Audition.Failed", { client, routed })
|
|
195
|
+
return yield* new AuditionError({ value: { client, routed } })
|
|
196
|
+
}
|
|
236
197
|
case "Event": {
|
|
237
198
|
const { event } = message
|
|
238
|
-
yield* debug("
|
|
199
|
+
yield* debug("Event.Emitted", { event })
|
|
239
200
|
yield* publishTake([event as never], true)
|
|
240
201
|
return
|
|
241
202
|
}
|
|
242
|
-
case "
|
|
243
|
-
case "
|
|
203
|
+
case "F.Success":
|
|
204
|
+
case "F.Failure": {
|
|
244
205
|
const { id } = message
|
|
245
206
|
const deferred = inflights[id]
|
|
246
207
|
if (deferred) {
|
|
247
208
|
delete inflights[id]
|
|
248
209
|
switch (message._tag) {
|
|
249
|
-
case "
|
|
210
|
+
case "F.Success": {
|
|
250
211
|
const { _tag, value } = message.success as never
|
|
251
|
-
yield* debug("
|
|
212
|
+
yield* debug("Call.Succeeded", { id, _tag, value })
|
|
252
213
|
yield* Deferred.succeed(deferred, value)
|
|
253
214
|
return
|
|
254
215
|
}
|
|
255
|
-
case "
|
|
216
|
+
case "F.Failure": {
|
|
256
217
|
const { _tag, value } = message.failure as never
|
|
257
|
-
yield* debug("
|
|
218
|
+
yield* debug("Call.Failed", { id, _tag, value })
|
|
258
219
|
yield* Deferred.fail(deferred, value)
|
|
259
220
|
return
|
|
260
221
|
}
|
|
@@ -262,27 +223,17 @@ const make = <
|
|
|
262
223
|
}
|
|
263
224
|
return
|
|
264
225
|
}
|
|
265
|
-
case "AuditionFailure": {
|
|
266
|
-
const { client, routed } = message
|
|
267
|
-
yield* debug("AuditionFailed", { client, routed })
|
|
268
|
-
return yield* new AuditionError({ value: { client, routed } })
|
|
269
|
-
}
|
|
270
226
|
case "Disconnect": {
|
|
271
227
|
yield* debug("Disconnected")
|
|
272
228
|
return
|
|
273
229
|
}
|
|
274
|
-
case "TransportFailure": {
|
|
275
|
-
const { cause } = message
|
|
276
|
-
yield* debug("TransportFailed", { cause })
|
|
277
|
-
return yield* new ConnectionError({ cause })
|
|
278
|
-
}
|
|
279
230
|
}
|
|
280
231
|
}),
|
|
281
232
|
).pipe(
|
|
282
233
|
Effect.ensuring(
|
|
283
234
|
Effect.all(
|
|
284
235
|
[
|
|
285
|
-
debug("
|
|
236
|
+
debug("Client.Closed", { unresolved: Record.keys(inflights).length }),
|
|
286
237
|
Deferred.succeed(audition, void 0),
|
|
287
238
|
RcRef.invalidate(rcr),
|
|
288
239
|
],
|
|
@@ -353,9 +304,9 @@ const make = <
|
|
|
353
304
|
|
|
354
305
|
yield* Deferred.await(audition)
|
|
355
306
|
|
|
356
|
-
const encodingServices = yield* Effect.context<_["
|
|
307
|
+
const encodingServices = yield* Effect.context<_["F"]["Payload"]["EncodingServices"]>()
|
|
357
308
|
|
|
358
|
-
const f: F<
|
|
309
|
+
const f: F<Self, D> = (_tag) =>
|
|
359
310
|
Effect.fnUntraced(
|
|
360
311
|
function* (value) {
|
|
361
312
|
const exit = fiber.pollUnsafe()
|
|
@@ -365,17 +316,17 @@ const make = <
|
|
|
365
316
|
onFailure: flow(
|
|
366
317
|
Cause.findError,
|
|
367
318
|
Result.match({
|
|
368
|
-
onSuccess:
|
|
319
|
+
onSuccess: Effect.fail,
|
|
369
320
|
onFailure: () => new UnresolvedError(),
|
|
370
321
|
}),
|
|
371
322
|
),
|
|
372
323
|
})
|
|
373
324
|
}
|
|
374
325
|
const id = callId++
|
|
375
|
-
const inflight = yield* Deferred.make<_["
|
|
326
|
+
const inflight = yield* Deferred.make<_["F"]["Success"]["Type"], FError<D>>()
|
|
376
327
|
inflights[id] = inflight
|
|
377
328
|
yield* send({
|
|
378
|
-
_tag: "
|
|
329
|
+
_tag: "F.Payload",
|
|
379
330
|
id,
|
|
380
331
|
payload: { _tag, value } as never,
|
|
381
332
|
})
|
|
@@ -383,7 +334,7 @@ const make = <
|
|
|
383
334
|
Deferred.await(inflight),
|
|
384
335
|
Fiber.await(fiber).pipe(
|
|
385
336
|
Effect.flatMap(
|
|
386
|
-
(exit): Effect.Effect<never, ClientError | UnresolvedError> =>
|
|
337
|
+
(exit): Effect.Effect<never, ClientError | UnresolvedError | S.SchemaError> =>
|
|
387
338
|
Exit.match(exit, {
|
|
388
339
|
onSuccess: () => new UnresolvedError().asEffect(),
|
|
389
340
|
onFailure: flow(
|
|
@@ -410,31 +361,27 @@ const make = <
|
|
|
410
361
|
return rcr
|
|
411
362
|
}).pipe(Layer.effect(client))
|
|
412
363
|
|
|
413
|
-
export const layerSocket = <
|
|
414
|
-
ClientSelf,
|
|
415
|
-
ClientId extends string,
|
|
416
|
-
MethodDefinitions extends Record<string, MethodDefinition.Any>,
|
|
417
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
418
|
-
>({
|
|
364
|
+
export const layerSocket = <Self, Id extends string, D extends ProtocolDefinition>({
|
|
419
365
|
client,
|
|
420
366
|
url,
|
|
421
367
|
protocols,
|
|
422
368
|
replay,
|
|
423
369
|
}: {
|
|
424
|
-
readonly client: Client<
|
|
370
|
+
readonly client: Client<Self, Id, D>
|
|
425
371
|
readonly url?: string | undefined
|
|
426
372
|
readonly protocols?: string | Array<string> | undefined
|
|
427
373
|
readonly replay?: ReplayConfig | undefined
|
|
428
374
|
}): Layer.Layer<
|
|
429
|
-
|
|
375
|
+
Self,
|
|
430
376
|
never,
|
|
431
377
|
| Socket.WebSocketConstructor
|
|
432
|
-
| Protocol
|
|
433
|
-
| Protocol
|
|
378
|
+
| Protocol<D>["Actor"]["DecodingServices"]
|
|
379
|
+
| Protocol<D>["F"]["Payload"]["EncodingServices"]
|
|
434
380
|
> =>
|
|
435
|
-
make<
|
|
381
|
+
make<Self, Id, D, Socket.WebSocketConstructor>(
|
|
436
382
|
client,
|
|
437
383
|
Effect.gen(function* () {
|
|
384
|
+
const { protocol } = client
|
|
438
385
|
const socket = yield* Socket.makeWebSocket(url ?? "/", {
|
|
439
386
|
protocols: ["liminal", Encoding.encodeBase64Url(client.key), ...(protocols ? Array.ensure(protocols) : [])],
|
|
440
387
|
})
|
|
@@ -444,49 +391,29 @@ export const layerSocket = <
|
|
|
444
391
|
.runRaw((raw) =>
|
|
445
392
|
pipe(
|
|
446
393
|
raw instanceof Uint8Array ? new TextDecoder().decode(raw) : raw,
|
|
447
|
-
|
|
394
|
+
protocol.decodeActor,
|
|
448
395
|
Effect.andThen(publish),
|
|
449
396
|
),
|
|
450
397
|
)
|
|
451
398
|
.pipe(
|
|
452
|
-
Effect.
|
|
453
|
-
|
|
399
|
+
Effect.catchIf(
|
|
400
|
+
Socket.isSocketError,
|
|
454
401
|
Effect.fnUntraced(function* (cause) {
|
|
455
402
|
const { reason } = cause
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
case "SocketOpenError": {
|
|
460
|
-
yield* debug(reason._tag, { cause })
|
|
461
|
-
return yield* publish({ _tag: "TransportFailure", cause })
|
|
462
|
-
}
|
|
463
|
-
case "SocketCloseError": {
|
|
464
|
-
const { code, closeReason } = reason
|
|
465
|
-
switch (code) {
|
|
466
|
-
case 1000: {
|
|
467
|
-
return yield* publish({ _tag: "Disconnect" })
|
|
468
|
-
}
|
|
469
|
-
case 4003: {
|
|
470
|
-
return yield* S.decodeUnknownEffect(S.fromJsonString(Protocol.AuditionFailure))(
|
|
471
|
-
closeReason,
|
|
472
|
-
).pipe(Effect.andThen(publish))
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
yield* debug("SocketCloseError", { cause })
|
|
476
|
-
return yield* publish({ _tag: "TransportFailure", cause })
|
|
477
|
-
}
|
|
403
|
+
if (reason._tag === "SocketCloseError" && reason.code === 1000) {
|
|
404
|
+
yield* debug("Socket.Disconnected")
|
|
405
|
+
return yield* publish({ _tag: "Disconnect" })
|
|
478
406
|
}
|
|
407
|
+
yield* debug(`SocketErrored.${reason._tag}`, { cause })
|
|
408
|
+
return yield* new ConnectionError({ cause })
|
|
479
409
|
}),
|
|
480
410
|
),
|
|
481
|
-
Effect.catchTag("SchemaError", Effect.die),
|
|
482
411
|
)
|
|
483
412
|
}, span("listen")),
|
|
484
413
|
send: Effect.fnUntraced(
|
|
485
414
|
function* (v) {
|
|
486
415
|
const write = yield* socket.writer
|
|
487
|
-
const message = yield*
|
|
488
|
-
Effect.mapError((cause) => new ConnectionError({ cause })),
|
|
489
|
-
)
|
|
416
|
+
const message = yield* protocol.encodeFPayload(v)
|
|
490
417
|
yield* write(message).pipe(
|
|
491
418
|
Effect.catchTag("SocketError", (cause) => new ConnectionError({ cause }).asEffect()),
|
|
492
419
|
)
|
|
@@ -499,36 +426,31 @@ export const layerSocket = <
|
|
|
499
426
|
replay,
|
|
500
427
|
)
|
|
501
428
|
|
|
502
|
-
export const layerWorker = <
|
|
503
|
-
ClientSelf,
|
|
504
|
-
ClientId extends string,
|
|
505
|
-
MethodDefinitions extends Record<string, MethodDefinition.Any>,
|
|
506
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
507
|
-
>({
|
|
429
|
+
export const layerWorker = <Self, Id extends string, D extends ProtocolDefinition>({
|
|
508
430
|
client,
|
|
509
431
|
replay,
|
|
510
432
|
}: {
|
|
511
|
-
readonly client: Client<
|
|
433
|
+
readonly client: Client<Self, Id, D>
|
|
512
434
|
readonly replay?: ReplayConfig | undefined
|
|
513
435
|
}): Layer.Layer<
|
|
514
|
-
|
|
436
|
+
Self,
|
|
515
437
|
never,
|
|
516
438
|
| Worker.WorkerPlatform
|
|
517
439
|
| Worker.Spawner
|
|
518
|
-
| Protocol
|
|
519
|
-
| Protocol
|
|
440
|
+
| Protocol<D>["Actor"]["DecodingServices"]
|
|
441
|
+
| Protocol<D>["F"]["Payload"]["EncodingServices"]
|
|
520
442
|
> =>
|
|
521
|
-
make<
|
|
443
|
+
make<Self, Id, D, Worker.WorkerPlatform | Worker.Spawner>(
|
|
522
444
|
client,
|
|
523
445
|
Effect.gen(function* () {
|
|
524
|
-
type T =
|
|
446
|
+
type T = Protocol<D>
|
|
525
447
|
|
|
526
448
|
const platform = yield* Worker.WorkerPlatform
|
|
527
449
|
const backing = yield* platform
|
|
528
|
-
.spawn<T["
|
|
450
|
+
.spawn<T["Actor"]["Type"], T["F"]["Payload"]["Type"] | string>(0)
|
|
529
451
|
.pipe(Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()))
|
|
530
452
|
|
|
531
|
-
const send = (message: T["
|
|
453
|
+
const send = (message: T["F"]["Payload"]["Type"]) =>
|
|
532
454
|
backing.send(message).pipe(
|
|
533
455
|
Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()),
|
|
534
456
|
span("send"),
|
|
@@ -541,14 +463,14 @@ export const layerWorker = <
|
|
|
541
463
|
backing.run(
|
|
542
464
|
Effect.fnUntraced(function* (message) {
|
|
543
465
|
yield* publish(message)
|
|
544
|
-
if (message._tag === "Disconnect" || message._tag === "
|
|
466
|
+
if (message._tag === "Disconnect" || message._tag === "Audition.Failure") {
|
|
545
467
|
yield* Deferred.succeed(stop, void 0)
|
|
546
468
|
}
|
|
547
469
|
}),
|
|
548
470
|
{ onSpawn: backing.send(client.key).pipe(Effect.orDie) },
|
|
549
471
|
),
|
|
550
472
|
Deferred.await(stop),
|
|
551
|
-
).pipe(Effect.catchTag("WorkerError", (cause) =>
|
|
473
|
+
).pipe(Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()))
|
|
552
474
|
}, span("listen")),
|
|
553
475
|
send,
|
|
554
476
|
}
|
package/ClientHandle.ts
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import { Schema as S, Effect } from "effect"
|
|
2
2
|
|
|
3
|
+
import type { ProtocolDefinition } from "./Protocol.ts"
|
|
3
4
|
import type { Send } from "./Send.ts"
|
|
4
5
|
|
|
5
6
|
const TypeId = "~liminal/ClientHandle" as const
|
|
6
7
|
|
|
7
|
-
export interface ClientHandle<
|
|
8
|
-
ActorSelf,
|
|
9
|
-
AttachmentFields extends S.Struct.Fields,
|
|
10
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
11
|
-
> {
|
|
8
|
+
export interface ClientHandle<ActorSelf, AttachmentFields extends S.Struct.Fields, D extends ProtocolDefinition> {
|
|
12
9
|
readonly [TypeId]: typeof TypeId
|
|
13
10
|
|
|
14
|
-
readonly send: Send<ActorSelf,
|
|
11
|
+
readonly send: Send<ActorSelf, D>
|
|
15
12
|
|
|
16
13
|
readonly attachments: Effect.Effect<S.Struct<AttachmentFields>["Type"]>
|
|
17
14
|
|
|
@@ -22,17 +19,13 @@ export interface ClientHandle<
|
|
|
22
19
|
readonly disconnect: Effect.Effect<void, never, ActorSelf>
|
|
23
20
|
}
|
|
24
21
|
|
|
25
|
-
export const make = <
|
|
26
|
-
ActorSelf,
|
|
27
|
-
AttachmentFields extends S.Struct.Fields,
|
|
28
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
29
|
-
>({
|
|
22
|
+
export const make = <ActorSelf, AttachmentFields extends S.Struct.Fields, D extends ProtocolDefinition>({
|
|
30
23
|
send,
|
|
31
24
|
attachments,
|
|
32
25
|
save,
|
|
33
26
|
disconnect,
|
|
34
27
|
}: {
|
|
35
|
-
readonly send: Send<ActorSelf,
|
|
28
|
+
readonly send: Send<ActorSelf, D>
|
|
36
29
|
|
|
37
30
|
readonly attachments: Effect.Effect<S.Struct<AttachmentFields>["Type"]>
|
|
38
31
|
|
|
@@ -41,7 +34,7 @@ export const make = <
|
|
|
41
34
|
) => Effect.Effect<void, S.SchemaError, S.Struct<AttachmentFields>["EncodingServices"]>
|
|
42
35
|
|
|
43
36
|
readonly disconnect: Effect.Effect<void, never, ActorSelf>
|
|
44
|
-
}): ClientHandle<ActorSelf, AttachmentFields,
|
|
37
|
+
}): ClientHandle<ActorSelf, AttachmentFields, D> => ({
|
|
45
38
|
[TypeId]: TypeId,
|
|
46
39
|
send,
|
|
47
40
|
attachments,
|
package/F.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Effect } from "effect"
|
|
2
2
|
|
|
3
3
|
import type { FError } from "./errors.ts"
|
|
4
|
-
import type {
|
|
4
|
+
import type { ProtocolDefinition } from "./Protocol.ts"
|
|
5
5
|
|
|
6
|
-
export type F<
|
|
7
|
-
Method extends keyof MethodDefinitions,
|
|
8
|
-
>(
|
|
6
|
+
export type F<Self, D extends ProtocolDefinition> = <Method extends keyof D["methods"]>(
|
|
9
7
|
method: Method,
|
|
10
8
|
) => (
|
|
11
|
-
payload:
|
|
12
|
-
) => Effect.Effect<
|
|
9
|
+
payload: D["methods"][Method]["payload"]["Type"],
|
|
10
|
+
) => Effect.Effect<D["methods"][Method]["success"]["Type"], FError<D>, Self>
|
package/Method.ts
CHANGED
|
@@ -6,17 +6,9 @@ export interface MethodDefinition<Payload extends S.Top, Success extends S.Top,
|
|
|
6
6
|
readonly failure: Failure
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export
|
|
10
|
-
export type Any = MethodDefinition<S.Top, S.Top, S.Top>
|
|
9
|
+
export type Any = MethodDefinition<S.Top, S.Top, S.Top>
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
? U
|
|
14
|
-
: {
|
|
15
|
-
[K in keyof T & keyof U]: T[K] extends U[K] ? (U[K] extends T[K] ? T[K] : never) : never
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const define = <Payload extends S.Top, Success extends S.Top, Failure extends S.Top>({
|
|
11
|
+
export const make = <Payload extends S.Top, Success extends S.Top, Failure extends S.Top>({
|
|
20
12
|
payload,
|
|
21
13
|
success,
|
|
22
14
|
failure,
|
|
@@ -26,12 +18,12 @@ export const define = <Payload extends S.Top, Success extends S.Top, Failure ext
|
|
|
26
18
|
readonly failure: Failure
|
|
27
19
|
}): MethodDefinition<Payload, Success, Failure> => ({ payload, success, failure })
|
|
28
20
|
|
|
29
|
-
export type Handler<MethodDefinition extends
|
|
21
|
+
export type Handler<MethodDefinition extends Any, R> = (
|
|
30
22
|
payload: MethodDefinition["payload"]["Type"],
|
|
31
23
|
) => Effect.Effect<MethodDefinition["success"]["Type"], MethodDefinition["failure"]["Type"], R>
|
|
32
24
|
|
|
33
|
-
export type Handlers<MethodDefinitions extends Record<string,
|
|
25
|
+
export type Handlers<MethodDefinitions extends Record<string, Any>, R> = {
|
|
34
26
|
[K in keyof MethodDefinitions]: Handler<MethodDefinitions[K], R>
|
|
35
27
|
}
|
|
36
28
|
|
|
37
|
-
export const handler = <M extends
|
|
29
|
+
export const handler = <M extends Any, R>(_method: M, f: Handler<M, R>): Handler<M, R> => f
|