liminal 0.17.4 → 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 +12 -0
- package/Client.ts +119 -165
- 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/_util/boundLayer.ts +11 -0
- package/_util/logCause.ts +8 -0
- 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 +47 -53
- 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/_util/boundLayer.d.ts +2 -0
- package/dist/_util/boundLayer.js +4 -0
- package/dist/_util/boundLayer.js.map +1 -0
- package/dist/_util/logCause.d.ts +2 -0
- package/dist/_util/logCause.js +7 -0
- package/dist/_util/logCause.js.map +1 -0
- package/dist/errors.d.ts +3 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/errors.ts +3 -3
- package/package.json +1 -1
- package/tsconfig.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
|
],
|
|
@@ -331,13 +282,31 @@ const make = <
|
|
|
331
282
|
),
|
|
332
283
|
live(replayCount),
|
|
333
284
|
)
|
|
334
|
-
}).pipe(
|
|
285
|
+
}).pipe(
|
|
286
|
+
Stream.unwrap,
|
|
287
|
+
Stream.interruptWhen(
|
|
288
|
+
Fiber.await(fiber).pipe(
|
|
289
|
+
Effect.flatMap(
|
|
290
|
+
Exit.match({
|
|
291
|
+
onSuccess: () => Effect.void,
|
|
292
|
+
onFailure: flow(
|
|
293
|
+
Cause.findError,
|
|
294
|
+
Result.match({
|
|
295
|
+
onSuccess: Effect.fail,
|
|
296
|
+
onFailure: () => Effect.void,
|
|
297
|
+
}),
|
|
298
|
+
),
|
|
299
|
+
}),
|
|
300
|
+
),
|
|
301
|
+
),
|
|
302
|
+
),
|
|
303
|
+
)
|
|
335
304
|
|
|
336
305
|
yield* Deferred.await(audition)
|
|
337
306
|
|
|
338
|
-
const encodingServices = yield* Effect.context<_["
|
|
307
|
+
const encodingServices = yield* Effect.context<_["F"]["Payload"]["EncodingServices"]>()
|
|
339
308
|
|
|
340
|
-
const f: F<
|
|
309
|
+
const f: F<Self, D> = (_tag) =>
|
|
341
310
|
Effect.fnUntraced(
|
|
342
311
|
function* (value) {
|
|
343
312
|
const exit = fiber.pollUnsafe()
|
|
@@ -347,23 +316,37 @@ const make = <
|
|
|
347
316
|
onFailure: flow(
|
|
348
317
|
Cause.findError,
|
|
349
318
|
Result.match({
|
|
350
|
-
onSuccess:
|
|
319
|
+
onSuccess: Effect.fail,
|
|
351
320
|
onFailure: () => new UnresolvedError(),
|
|
352
321
|
}),
|
|
353
322
|
),
|
|
354
323
|
})
|
|
355
324
|
}
|
|
356
325
|
const id = callId++
|
|
357
|
-
const inflight = yield* Deferred.make<_["
|
|
326
|
+
const inflight = yield* Deferred.make<_["F"]["Success"]["Type"], FError<D>>()
|
|
358
327
|
inflights[id] = inflight
|
|
359
328
|
yield* send({
|
|
360
|
-
_tag: "
|
|
329
|
+
_tag: "F.Payload",
|
|
361
330
|
id,
|
|
362
331
|
payload: { _tag, value } as never,
|
|
363
332
|
})
|
|
364
333
|
return yield* Effect.raceFirst(
|
|
365
334
|
Deferred.await(inflight),
|
|
366
|
-
Fiber.
|
|
335
|
+
Fiber.await(fiber).pipe(
|
|
336
|
+
Effect.flatMap(
|
|
337
|
+
(exit): Effect.Effect<never, ClientError | UnresolvedError | S.SchemaError> =>
|
|
338
|
+
Exit.match(exit, {
|
|
339
|
+
onSuccess: () => new UnresolvedError().asEffect(),
|
|
340
|
+
onFailure: flow(
|
|
341
|
+
Cause.findError,
|
|
342
|
+
Result.match({
|
|
343
|
+
onSuccess: Effect.fail,
|
|
344
|
+
onFailure: () => new UnresolvedError().asEffect(),
|
|
345
|
+
}),
|
|
346
|
+
),
|
|
347
|
+
}),
|
|
348
|
+
),
|
|
349
|
+
),
|
|
367
350
|
)
|
|
368
351
|
},
|
|
369
352
|
span("f"),
|
|
@@ -378,31 +361,27 @@ const make = <
|
|
|
378
361
|
return rcr
|
|
379
362
|
}).pipe(Layer.effect(client))
|
|
380
363
|
|
|
381
|
-
export const layerSocket = <
|
|
382
|
-
ClientSelf,
|
|
383
|
-
ClientId extends string,
|
|
384
|
-
MethodDefinitions extends Record<string, MethodDefinition.Any>,
|
|
385
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
386
|
-
>({
|
|
364
|
+
export const layerSocket = <Self, Id extends string, D extends ProtocolDefinition>({
|
|
387
365
|
client,
|
|
388
366
|
url,
|
|
389
367
|
protocols,
|
|
390
368
|
replay,
|
|
391
369
|
}: {
|
|
392
|
-
readonly client: Client<
|
|
370
|
+
readonly client: Client<Self, Id, D>
|
|
393
371
|
readonly url?: string | undefined
|
|
394
372
|
readonly protocols?: string | Array<string> | undefined
|
|
395
373
|
readonly replay?: ReplayConfig | undefined
|
|
396
374
|
}): Layer.Layer<
|
|
397
|
-
|
|
375
|
+
Self,
|
|
398
376
|
never,
|
|
399
377
|
| Socket.WebSocketConstructor
|
|
400
|
-
| Protocol
|
|
401
|
-
| Protocol
|
|
378
|
+
| Protocol<D>["Actor"]["DecodingServices"]
|
|
379
|
+
| Protocol<D>["F"]["Payload"]["EncodingServices"]
|
|
402
380
|
> =>
|
|
403
|
-
make<
|
|
381
|
+
make<Self, Id, D, Socket.WebSocketConstructor>(
|
|
404
382
|
client,
|
|
405
383
|
Effect.gen(function* () {
|
|
384
|
+
const { protocol } = client
|
|
406
385
|
const socket = yield* Socket.makeWebSocket(url ?? "/", {
|
|
407
386
|
protocols: ["liminal", Encoding.encodeBase64Url(client.key), ...(protocols ? Array.ensure(protocols) : [])],
|
|
408
387
|
})
|
|
@@ -412,49 +391,29 @@ export const layerSocket = <
|
|
|
412
391
|
.runRaw((raw) =>
|
|
413
392
|
pipe(
|
|
414
393
|
raw instanceof Uint8Array ? new TextDecoder().decode(raw) : raw,
|
|
415
|
-
|
|
394
|
+
protocol.decodeActor,
|
|
416
395
|
Effect.andThen(publish),
|
|
417
396
|
),
|
|
418
397
|
)
|
|
419
398
|
.pipe(
|
|
420
|
-
Effect.
|
|
421
|
-
|
|
399
|
+
Effect.catchIf(
|
|
400
|
+
Socket.isSocketError,
|
|
422
401
|
Effect.fnUntraced(function* (cause) {
|
|
423
402
|
const { reason } = cause
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
case "SocketOpenError": {
|
|
428
|
-
yield* debug(reason._tag, { cause })
|
|
429
|
-
return yield* publish({ _tag: "TransportFailure", cause })
|
|
430
|
-
}
|
|
431
|
-
case "SocketCloseError": {
|
|
432
|
-
const { code, closeReason } = reason
|
|
433
|
-
switch (code) {
|
|
434
|
-
case 1000: {
|
|
435
|
-
return yield* publish({ _tag: "Disconnect" })
|
|
436
|
-
}
|
|
437
|
-
case 4003: {
|
|
438
|
-
return yield* S.decodeUnknownEffect(S.fromJsonString(Protocol.AuditionFailure))(
|
|
439
|
-
closeReason,
|
|
440
|
-
).pipe(Effect.andThen(publish))
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
yield* debug("SocketCloseError", { cause })
|
|
444
|
-
return yield* publish({ _tag: "TransportFailure", cause })
|
|
445
|
-
}
|
|
403
|
+
if (reason._tag === "SocketCloseError" && reason.code === 1000) {
|
|
404
|
+
yield* debug("Socket.Disconnected")
|
|
405
|
+
return yield* publish({ _tag: "Disconnect" })
|
|
446
406
|
}
|
|
407
|
+
yield* debug(`SocketErrored.${reason._tag}`, { cause })
|
|
408
|
+
return yield* new ConnectionError({ cause })
|
|
447
409
|
}),
|
|
448
410
|
),
|
|
449
|
-
Effect.catchTag("SchemaError", Effect.die),
|
|
450
411
|
)
|
|
451
412
|
}, span("listen")),
|
|
452
413
|
send: Effect.fnUntraced(
|
|
453
414
|
function* (v) {
|
|
454
415
|
const write = yield* socket.writer
|
|
455
|
-
const message = yield*
|
|
456
|
-
Effect.mapError((cause) => new ConnectionError({ cause })),
|
|
457
|
-
)
|
|
416
|
+
const message = yield* protocol.encodeFPayload(v)
|
|
458
417
|
yield* write(message).pipe(
|
|
459
418
|
Effect.catchTag("SocketError", (cause) => new ConnectionError({ cause }).asEffect()),
|
|
460
419
|
)
|
|
@@ -467,36 +426,31 @@ export const layerSocket = <
|
|
|
467
426
|
replay,
|
|
468
427
|
)
|
|
469
428
|
|
|
470
|
-
export const layerWorker = <
|
|
471
|
-
ClientSelf,
|
|
472
|
-
ClientId extends string,
|
|
473
|
-
MethodDefinitions extends Record<string, MethodDefinition.Any>,
|
|
474
|
-
EventDefinitions extends Record<string, S.Struct.Fields>,
|
|
475
|
-
>({
|
|
429
|
+
export const layerWorker = <Self, Id extends string, D extends ProtocolDefinition>({
|
|
476
430
|
client,
|
|
477
431
|
replay,
|
|
478
432
|
}: {
|
|
479
|
-
readonly client: Client<
|
|
433
|
+
readonly client: Client<Self, Id, D>
|
|
480
434
|
readonly replay?: ReplayConfig | undefined
|
|
481
435
|
}): Layer.Layer<
|
|
482
|
-
|
|
436
|
+
Self,
|
|
483
437
|
never,
|
|
484
438
|
| Worker.WorkerPlatform
|
|
485
439
|
| Worker.Spawner
|
|
486
|
-
| Protocol
|
|
487
|
-
| Protocol
|
|
440
|
+
| Protocol<D>["Actor"]["DecodingServices"]
|
|
441
|
+
| Protocol<D>["F"]["Payload"]["EncodingServices"]
|
|
488
442
|
> =>
|
|
489
|
-
make<
|
|
443
|
+
make<Self, Id, D, Worker.WorkerPlatform | Worker.Spawner>(
|
|
490
444
|
client,
|
|
491
445
|
Effect.gen(function* () {
|
|
492
|
-
type T =
|
|
446
|
+
type T = Protocol<D>
|
|
493
447
|
|
|
494
448
|
const platform = yield* Worker.WorkerPlatform
|
|
495
449
|
const backing = yield* platform
|
|
496
|
-
.spawn<T["
|
|
450
|
+
.spawn<T["Actor"]["Type"], T["F"]["Payload"]["Type"] | string>(0)
|
|
497
451
|
.pipe(Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()))
|
|
498
452
|
|
|
499
|
-
const send = (message: T["
|
|
453
|
+
const send = (message: T["F"]["Payload"]["Type"]) =>
|
|
500
454
|
backing.send(message).pipe(
|
|
501
455
|
Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()),
|
|
502
456
|
span("send"),
|
|
@@ -509,14 +463,14 @@ export const layerWorker = <
|
|
|
509
463
|
backing.run(
|
|
510
464
|
Effect.fnUntraced(function* (message) {
|
|
511
465
|
yield* publish(message)
|
|
512
|
-
if (message._tag === "Disconnect" || message._tag === "
|
|
466
|
+
if (message._tag === "Disconnect" || message._tag === "Audition.Failure") {
|
|
513
467
|
yield* Deferred.succeed(stop, void 0)
|
|
514
468
|
}
|
|
515
469
|
}),
|
|
516
470
|
{ onSpawn: backing.send(client.key).pipe(Effect.orDie) },
|
|
517
471
|
),
|
|
518
472
|
Deferred.await(stop),
|
|
519
|
-
).pipe(Effect.catchTag("WorkerError", (cause) =>
|
|
473
|
+
).pipe(Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()))
|
|
520
474
|
}, span("listen")),
|
|
521
475
|
send,
|
|
522
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
|