liminal 0.17.13 → 0.17.15
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 +12 -13
- package/ActorTransport.ts +6 -4
- package/Audition.ts +87 -40
- package/CHANGELOG.md +16 -0
- package/Client.ts +260 -134
- package/ClientDirectory.ts +50 -36
- package/ClientHandleEncoders.ts +15 -0
- package/Fn.ts +55 -0
- package/Method.ts +11 -21
- package/Protocol.ts +44 -36
- package/Reducer.ts +22 -0
- package/Tracing.ts +37 -0
- package/browser/BrowserActorNamespace.ts +65 -30
- package/dist/Actor.d.ts +1 -1
- package/dist/Actor.js +6 -6
- package/dist/Actor.js.map +1 -1
- package/dist/ActorTransport.d.ts +5 -4
- package/dist/Audition.d.ts +16 -9
- package/dist/Audition.js +25 -9
- package/dist/Audition.js.map +1 -1
- package/dist/Client.d.ts +21 -14
- package/dist/Client.js +147 -100
- package/dist/Client.js.map +1 -1
- package/dist/ClientDirectory.d.ts +14 -6
- package/dist/ClientDirectory.js +25 -22
- package/dist/ClientDirectory.js.map +1 -1
- package/dist/ClientHandleEncoders.d.ts +7 -0
- package/dist/ClientHandleEncoders.js +2 -0
- package/dist/ClientHandleEncoders.js.map +1 -0
- package/dist/Fn.d.ts +16 -0
- package/dist/Fn.js +2 -0
- package/dist/Fn.js.map +1 -0
- package/dist/Method.d.ts +9 -14
- package/dist/Method.js +0 -1
- package/dist/Method.js.map +1 -1
- package/dist/Protocol.d.ts +19 -22
- package/dist/Protocol.js +20 -15
- package/dist/Protocol.js.map +1 -1
- package/dist/Reducer.d.ts +11 -0
- package/dist/Reducer.js +2 -0
- package/dist/Reducer.js.map +1 -0
- package/dist/Tracing.d.ts +37 -0
- package/dist/Tracing.js +29 -0
- package/dist/Tracing.js.map +1 -0
- package/dist/browser/BrowserActorNamespace.d.ts +5 -5
- package/dist/browser/BrowserActorNamespace.js +41 -20
- package/dist/browser/BrowserActorNamespace.js.map +1 -1
- package/dist/errors.d.ts +0 -4
- package/dist/errors.js.map +1 -1
- package/dist/experimental/TaggedTemplateFunction.js +1 -1
- package/dist/experimental/TaggedTemplateFunction.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/package.json +16 -21
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/workerd/ActorHandle.d.ts +9 -0
- package/dist/workerd/ActorHandle.js +4 -0
- package/dist/workerd/ActorHandle.js.map +1 -0
- package/dist/workerd/WorkerdActorNamespace.d.ts +18 -18
- package/dist/workerd/WorkerdActorNamespace.js +43 -141
- package/dist/workerd/WorkerdActorNamespace.js.map +1 -1
- package/dist/workerd/WorkerdActorRuntime.d.ts +19 -0
- package/dist/workerd/WorkerdActorRuntime.js +204 -0
- package/dist/workerd/WorkerdActorRuntime.js.map +1 -0
- package/dist/workerd/index.d.ts +2 -0
- package/dist/workerd/index.js +2 -0
- package/dist/workerd/index.js.map +1 -1
- package/errors.ts +0 -6
- package/experimental/TaggedTemplateFunction.ts +1 -1
- package/index.ts +3 -3
- package/package.json +10 -25
- package/tsconfig.json +1 -1
- package/vitest.config.ts +7 -0
- package/workerd/ActorHandle.ts +29 -0
- package/workerd/WorkerdActorNamespace.ts +86 -273
- package/workerd/WorkerdActorRuntime.ts +422 -0
- package/workerd/index.ts +2 -0
- package/Accumulator.ts +0 -103
- package/F.ts +0 -10
- package/_diagnostic.ts +0 -3
- package/_util/Mutex.ts +0 -13
- package/dist/Accumulator.d.ts +0 -22
- package/dist/Accumulator.js +0 -37
- package/dist/Accumulator.js.map +0 -1
- package/dist/F.d.ts +0 -4
- package/dist/F.js +0 -2
- package/dist/F.js.map +0 -1
- package/dist/_diagnostic.d.ts +0 -4
- package/dist/_diagnostic.js +0 -3
- package/dist/_diagnostic.js.map +0 -1
- package/dist/_util/Mutex.d.ts +0 -7
- package/dist/_util/Mutex.js +0 -9
- package/dist/_util/Mutex.js.map +0 -1
package/dist/Actor.d.ts
CHANGED
|
@@ -21,6 +21,6 @@ export interface Actor<ActorSelf, ActorId extends string, Name extends TopFromSt
|
|
|
21
21
|
readonly definition: ActorDefinition<Name, AttachmentFields, ActorClientSelf, ActorClientId, D>;
|
|
22
22
|
readonly all: Sender<ActorSelf, D>;
|
|
23
23
|
readonly others: Sender<ActorSelf, D>;
|
|
24
|
-
readonly handler: <K extends keyof D["
|
|
24
|
+
readonly handler: <K extends keyof D["external"], R>(tag: K, f: Method.Handler<D["external"][K], R>) => Method.Handler<D["external"][K], R>;
|
|
25
25
|
}
|
|
26
26
|
export declare const Service: <ActorSelf>() => <ActorId extends string, Name extends TopFromString, D extends ProtocolDefinition, AttachmentFields extends S.Struct.Fields, ClientSelf, ClientId extends string>(id: ActorId, definition: ActorDefinition<Name, AttachmentFields, ClientSelf, ClientId, D>) => Actor<ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D>;
|
package/dist/Actor.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { Context, Schema as S, Effect } from "effect";
|
|
2
|
-
import
|
|
2
|
+
import * as Spanner from "liminal-util/Spanner";
|
|
3
3
|
import * as Method from "./Method.js";
|
|
4
4
|
import {} from "./Protocol.js";
|
|
5
|
-
const
|
|
5
|
+
const span = Spanner.make(import.meta.url);
|
|
6
6
|
export const TypeId = "~liminal/Actor";
|
|
7
7
|
export const Service = () => (id, definition) => {
|
|
8
8
|
const tag = Context.Service()(id);
|
|
9
9
|
const all = {
|
|
10
|
-
send: (key, payload) => tag.asEffect().pipe(Effect.flatMap(({ clients }) => Effect.forEach(clients, (client) => client.send(key, payload), { concurrency: "unbounded" })), span("all
|
|
11
|
-
disconnect: tag.asEffect().pipe(Effect.flatMap(({ clients }) => Effect.forEach(clients, ({ disconnect }) => disconnect)), span("all
|
|
10
|
+
send: (key, payload) => tag.asEffect().pipe(Effect.flatMap(({ clients }) => Effect.forEach(clients, (client) => client.send(key, payload), { concurrency: "unbounded" })), span("send-all")),
|
|
11
|
+
disconnect: tag.asEffect().pipe(Effect.flatMap(({ clients }) => Effect.forEach(clients, ({ disconnect }) => disconnect)), span("disconnect-all")),
|
|
12
12
|
};
|
|
13
13
|
const others = {
|
|
14
14
|
send: Effect.fnUntraced(function* (key, payload) {
|
|
15
15
|
const { clients, currentClient } = yield* tag;
|
|
16
16
|
yield* Effect.forEach(clients, (client) => (client === currentClient ? Effect.void : client.send(key, payload)), { concurrency: "unbounded" });
|
|
17
|
-
}, span("others
|
|
17
|
+
}, span("send-others")),
|
|
18
18
|
disconnect: Effect.gen(function* () {
|
|
19
19
|
const { clients, currentClient } = yield* tag;
|
|
20
20
|
yield* Effect.forEach(clients, (client) => (client === currentClient ? Effect.void : client.disconnect));
|
|
21
|
-
}).pipe(span("others
|
|
21
|
+
}).pipe(span("disconnect-others")),
|
|
22
22
|
};
|
|
23
23
|
const handler = (_tag, f) => f;
|
|
24
24
|
return Object.assign(tag, {
|
package/dist/Actor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Actor.js","sourceRoot":"","sources":["../Actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"Actor.js","sourceRoot":"","sources":["../Actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACrD,OAAO,KAAK,OAAO,MAAM,sBAAsB,CAAA;AAK/C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,EAA2B,MAAM,eAAe,CAAA;AAEvD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE1C,MAAM,CAAC,MAAM,MAAM,GAAG,gBAAyB,CAAA;AAsD/C,MAAM,CAAC,MAAM,OAAO,GAClB,GAAc,EAAE,CAChB,CAQE,EAAW,EACX,UAA4E,EACA,EAAE;IAC9E,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,EAA4D,CAAC,EAAE,CAAC,CAAA;IAE3F,MAAM,GAAG,GAAyB;QAChC,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CACrB,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,CACjB,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAC7B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAC7F,EACD,IAAI,CAAC,UAAU,CAAC,CACjB;QACH,UAAU,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,CAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EACxF,IAAI,CAAC,gBAAgB,CAAC,CACvB;KACF,CAAA;IAED,MAAM,MAAM,GAAyB;QACnC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,OAAO;YAC7C,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA;YAC7C,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CACnB,OAAO,EACP,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,EAChF,EAAE,WAAW,EAAE,WAAW,EAAE,CAC7B,CAAA;QACH,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC9B,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA;YAC7C,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAA;QAC1G,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;KACnC,CAAA;IAED,MAAM,OAAO,GAAG,CACd,IAAO,EACP,CAAsC,EACD,EAAE,CAAC,CAAC,CAAA;IAE3C,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE;QACxB,CAAC,MAAM,CAAC,EAAE,MAAM;QAChB,UAAU;QACV,GAAG;QACH,MAAM;QACN,OAAO;KACR,CAAC,CAAA;AACJ,CAAC,CAAA"}
|
package/dist/ActorTransport.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Effect, Schema as S } from "effect";
|
|
2
2
|
import type { Protocol, ProtocolDefinition } from "./Protocol.ts";
|
|
3
|
-
export interface ActorTransport<
|
|
4
|
-
readonly
|
|
5
|
-
readonly
|
|
6
|
-
readonly
|
|
3
|
+
export interface ActorTransport<Key, Client, AttachmentFields extends S.Struct.Fields, D extends ProtocolDefinition> {
|
|
4
|
+
readonly key: (client: Client) => Key;
|
|
5
|
+
readonly send: (client: Client, event: Protocol<D>["Event"]["Type"]) => Effect.Effect<void, S.SchemaError, Protocol<D>["Event"]["EncodingServices"]>;
|
|
6
|
+
readonly close: (client: Client) => Effect.Effect<void>;
|
|
7
|
+
readonly snapshot: (client: Client, attachments: S.Struct<AttachmentFields>["Type"]) => Effect.Effect<void, S.SchemaError, S.Struct<AttachmentFields>["EncodingServices"]>;
|
|
7
8
|
}
|
package/dist/Audition.d.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
import { Schema as S, Pipeable, Stream } from "effect";
|
|
2
|
-
import type { F } from "./F.ts";
|
|
3
|
-
import type { ProtocolDefinition } from "./Protocol.ts";
|
|
1
|
+
import { Schema as S, Pipeable, Stream, Types } from "effect";
|
|
4
2
|
import * as Client from "./Client.ts";
|
|
5
3
|
import { type ClientError } from "./errors.ts";
|
|
4
|
+
import type { Fn } from "./Fn.ts";
|
|
5
|
+
import type { Methods } from "./Method.ts";
|
|
6
|
+
import type { ProtocolDefinition } from "./Protocol.ts";
|
|
6
7
|
declare const TypeId: "~liminal/Audition";
|
|
7
|
-
export interface Audition<
|
|
8
|
+
export interface Audition<AuditionSelf, State extends S.Union<ReadonlyArray<S.Top>>, External extends Methods, Event> extends Pipeable.Pipeable {
|
|
8
9
|
readonly [TypeId]: typeof TypeId;
|
|
9
|
-
readonly
|
|
10
|
-
readonly
|
|
10
|
+
readonly state: Stream.Stream<State["Type"], ClientError | S.SchemaError, AuditionSelf | State["DecodingServices"]>;
|
|
11
|
+
readonly fn: Fn<AuditionSelf, External>;
|
|
12
|
+
readonly events: Stream.Stream<Event, ClientError | S.SchemaError, AuditionSelf>;
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
type MergeMethods<T extends Methods, U extends Methods> = [keyof T] extends [never] ? U : {
|
|
15
|
+
[K in keyof T & keyof U]: Types.Equals<T[K], U[K]> extends true ? T[K] : never;
|
|
16
|
+
};
|
|
17
|
+
type MergeState<State, D extends ProtocolDefinition> = [State] extends [never] ? S.Union<[S.Struct<D["state"]>]> : State extends S.Union<ReadonlyArray<S.Top>> ? S.Union<[...State["members"], S.Struct<D["state"]>]> : never;
|
|
18
|
+
export declare const empty: Audition<never, never, {}, never>;
|
|
19
|
+
export declare const cycleOn: <Event>(predicate: (event: Event) => boolean) => <AuditionSelf, State extends S.Union<ReadonlyArray<S.Top>>, External extends Methods>(audition: Audition<AuditionSelf, State, External, Event>) => Audition<AuditionSelf, State, External, Event>;
|
|
13
20
|
export declare const add: {
|
|
14
|
-
<ClientSelf, ClientId extends string, ClientD extends ProtocolDefinition>(client: Client.Client<ClientSelf, ClientId, ClientD>): <AuditionSelf,
|
|
15
|
-
<
|
|
21
|
+
<ClientSelf, ClientId extends string, ClientD extends ProtocolDefinition>(client: Client.Client<ClientSelf, ClientId, ClientD>): <AuditionSelf, State extends S.Union<ReadonlyArray<S.Top>> | never, External extends Methods, Event>(audition: Audition<AuditionSelf, State, External, Event>) => Audition<AuditionSelf | ClientSelf, MergeState<State, ClientD>, MergeMethods<External, ClientD["external"]>, Event | ReturnType<typeof S.TaggedUnion<ClientD["events"]>>["Type"]>;
|
|
22
|
+
<AuditionSelf, State extends S.Union<ReadonlyArray<S.Top>> | never, External extends Methods, Event, ClientSelf, ClientId extends string, ClientD extends ProtocolDefinition>(audition: Audition<AuditionSelf, State, External, Event>, client: Client.Client<ClientSelf, ClientId, ClientD>): Audition<AuditionSelf | ClientSelf, MergeState<State, ClientD>, MergeMethods<External, ClientD["external"]>, Event | ReturnType<typeof S.TaggedUnion<ClientD["events"]>>["Type"]>;
|
|
16
23
|
};
|
|
17
24
|
export {};
|
package/dist/Audition.js
CHANGED
|
@@ -1,29 +1,45 @@
|
|
|
1
|
-
import { Schema as S, Pipeable, Stream, Effect, Function } from "effect";
|
|
2
|
-
import { diagnostic } from "./_diagnostic.js";
|
|
1
|
+
import { Schema as S, Pipeable, Stream, Effect, Function, Types } from "effect";
|
|
3
2
|
import * as Client from "./Client.js";
|
|
4
3
|
import { AuditionError } from "./errors.js";
|
|
5
|
-
const { debug, span } = diagnostic("Audition");
|
|
6
4
|
const TypeId = "~liminal/Audition";
|
|
7
5
|
export const empty = {
|
|
8
6
|
[TypeId]: TypeId,
|
|
9
7
|
pipe() {
|
|
10
8
|
return Pipeable.pipeArguments(this, arguments);
|
|
11
9
|
},
|
|
10
|
+
state: Stream.fail(new AuditionError()),
|
|
11
|
+
fn: () => () => new AuditionError().asEffect(),
|
|
12
12
|
events: Stream.fail(new AuditionError()),
|
|
13
|
-
|
|
13
|
+
};
|
|
14
|
+
export const cycleOn = (predicate) => (audition) => {
|
|
15
|
+
const events = audition.events.pipe(Stream.takeUntil(predicate), Stream.forever);
|
|
16
|
+
const state = audition.state.pipe(Stream.forever);
|
|
17
|
+
return {
|
|
18
|
+
[TypeId]: TypeId,
|
|
19
|
+
pipe() {
|
|
20
|
+
return Pipeable.pipeArguments(this, arguments);
|
|
21
|
+
},
|
|
22
|
+
events,
|
|
23
|
+
fn: audition.fn,
|
|
24
|
+
state,
|
|
25
|
+
};
|
|
14
26
|
};
|
|
15
27
|
export const add = Function.dual(2, (audition, client) => {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
28
|
+
const fn = ((method, ...f) => Effect.fnUntraced(function* (payload) {
|
|
29
|
+
return yield* audition
|
|
30
|
+
.fn(method)(payload)
|
|
31
|
+
.pipe(Effect.catchTag("AuditionError", () => client.fn(method)(payload)));
|
|
32
|
+
}, ...f));
|
|
33
|
+
const events = audition.events.pipe(Stream.catchTag("AuditionError", () => Effect.succeed(client.events).pipe(Stream.unwrap)));
|
|
34
|
+
const state = audition.state.pipe(Stream.catchTag("AuditionError", () => Effect.succeed(client.state).pipe(Stream.unwrap)));
|
|
20
35
|
return {
|
|
21
36
|
[TypeId]: TypeId,
|
|
22
37
|
pipe() {
|
|
23
38
|
return Pipeable.pipeArguments(this, arguments);
|
|
24
39
|
},
|
|
25
40
|
events,
|
|
26
|
-
|
|
41
|
+
fn,
|
|
42
|
+
state,
|
|
27
43
|
};
|
|
28
44
|
});
|
|
29
45
|
//# sourceMappingURL=Audition.js.map
|
package/dist/Audition.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Audition.js","sourceRoot":"","sources":["../Audition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"Audition.js","sourceRoot":"","sources":["../Audition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAE/E,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,EAAoB,aAAa,EAAE,MAAM,aAAa,CAAA;AAK7D,MAAM,MAAM,GAAG,mBAA4B,CAAA;AAuB3C,MAAM,CAAC,MAAM,KAAK,GAAsC;IACtD,CAAC,MAAM,CAAC,EAAE,MAAM;IAChB,IAAI;QACF,OAAO,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;IAChD,CAAC;IACD,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,aAAa,EAAE,CAAC;IACvC,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,aAAa,EAAE,CAAC,QAAQ,EAAE;IAC9C,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,aAAa,EAAE,CAAC;CACzC,CAAA;AAED,MAAM,CAAC,MAAM,OAAO,GAClB,CAAQ,SAAoC,EAAE,EAAE,CAChD,CACE,QAAwD,EACR,EAAE;IAClD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;IAChF,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAEjD,OAAO;QACL,CAAC,MAAM,CAAC,EAAE,MAAM;QAChB,IAAI;YACF,OAAO,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAChD,CAAC;QACD,MAAM;QACN,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,KAAK;KACN,CAAA;AACH,CAAC,CAAA;AAEH,MAAM,CAAC,MAAM,GAAG,GA4BZ,QAAQ,CAAC,IAAI,CACf,CAAC,EACD,CASE,QAAwD,EACxD,MAAoD,EAMpD,EAAE;IACF,MAAM,EAAE,GAAG,CAAC,CAAC,MAAc,EAAE,GAAG,CAAQ,EAAE,EAAE,CAC1C,MAAM,CAAC,UAAU,CACf,QAAQ,CAAC,EAAE,OAAY;QACrB,OAAO,KAAK,CAAC,CAAC,QAAQ;aACnB,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;aACnB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7E,CAAC,EACD,GAAG,CAAC,CACL,CAA+E,CAAA;IAElF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CACjC,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAC1F,CAAA;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAC/B,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CACzF,CAAA;IAED,OAAO;QACL,CAAC,MAAM,CAAC,EAAE,MAAM;QAChB,IAAI;YACF,OAAO,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAChD,CAAC;QACD,MAAM;QACN,EAAE;QACF,KAAK;KACN,CAAA;AACH,CAAC,CACF,CAAA"}
|
package/dist/Client.d.ts
CHANGED
|
@@ -2,40 +2,47 @@ import { Context, Effect, Layer, RcRef, Scope, Stream, Schema as S } from "effec
|
|
|
2
2
|
import { Socket } from "effect/unstable/socket";
|
|
3
3
|
import { Worker } from "effect/unstable/workers";
|
|
4
4
|
import { type ClientError } from "./errors.ts";
|
|
5
|
-
import {
|
|
5
|
+
import type { Fn } from "./Fn.ts";
|
|
6
6
|
import { Protocol, type ProtocolDefinition } from "./Protocol.ts";
|
|
7
|
+
import * as Reducer from "./Reducer.ts";
|
|
7
8
|
export declare const TypeId: "~liminal/Client";
|
|
8
9
|
export interface ReplayConfig {
|
|
9
10
|
readonly mode: "startup" | "all-subscribers";
|
|
10
11
|
readonly limit?: number | undefined;
|
|
11
12
|
}
|
|
12
|
-
export
|
|
13
|
+
export type Service<ClientSelf, D extends ProtocolDefinition> = RcRef.RcRef<{
|
|
14
|
+
readonly state: Stream.Stream<S.Struct<D["state"]>["Type"], ClientError | S.SchemaError>;
|
|
13
15
|
readonly events: Stream.Stream<ReturnType<typeof S.TaggedUnion<D["events"]>>["Type"], ClientError | S.SchemaError>;
|
|
14
|
-
readonly
|
|
16
|
+
readonly fnRaw: <K extends keyof D["external"], M extends D["external"][K]>(tag: K, payload: M["payload"]["Type"]) => Effect.Effect<M["success"]["Type"], M["failure"]["Type"], ClientSelf>;
|
|
15
17
|
readonly end: Effect.Effect<void>;
|
|
16
|
-
}
|
|
17
|
-
export type Service<ClientSelf, D extends ProtocolDefinition> = RcRef.RcRef<Session<ClientSelf, D>, ClientError>;
|
|
18
|
+
}, ClientError>;
|
|
18
19
|
export interface Client<Self, ClientId extends string, D extends ProtocolDefinition> extends Context.Service<Self, Service<Self, D>> {
|
|
19
20
|
new (_: never): Context.ServiceClass.Shape<ClientId, Service<Self, D>>;
|
|
20
21
|
readonly [TypeId]: typeof TypeId;
|
|
21
22
|
readonly definition: D;
|
|
22
23
|
readonly protocol: Protocol<D>;
|
|
24
|
+
readonly state: Stream.Stream<S.Struct<D["state"]>["Type"], ClientError | S.SchemaError, Self | S.Struct<D["state"]>["DecodingServices"]>;
|
|
23
25
|
readonly events: Stream.Stream<ReturnType<typeof S.TaggedUnion<D["events"]>>["Type"], ClientError | S.SchemaError, Self>;
|
|
24
|
-
readonly
|
|
26
|
+
readonly fn: Fn<Self, D["external"]>;
|
|
25
27
|
readonly invalidate: Effect.Effect<void, never, Self>;
|
|
28
|
+
readonly reducer: <K extends keyof D["events"], R extends Reducer.Reducer<D, K>>(_tag: K, f: R) => R;
|
|
26
29
|
}
|
|
27
30
|
export declare const Service: <Self>() => <Id extends string, D extends ProtocolDefinition>(id: Id, definition: D) => Client<Self, Id, D>;
|
|
28
|
-
export interface ClientTransport<D extends ProtocolDefinition> {
|
|
29
|
-
readonly listen: (publish: (message: Protocol<D>["Actor"]["Type"]) => Effect.Effect<void, ClientError>) => Effect.Effect<void, ClientError | S.SchemaError, Scope.Scope | Protocol<D>["Actor"]["DecodingServices"]>;
|
|
31
|
+
export interface ClientTransport<D extends ProtocolDefinition, R> {
|
|
32
|
+
readonly listen: (publish: (message: Protocol<D>["Actor"]["Type"]) => Effect.Effect<void, ClientError, R>) => Effect.Effect<void, ClientError | S.SchemaError, Scope.Scope | Protocol<D>["Actor"]["DecodingServices"] | R>;
|
|
30
33
|
readonly send: (message: Protocol<D>["F"]["Payload"]["Type"]) => Effect.Effect<void, ClientError | S.SchemaError, Protocol<D>["F"]["Payload"]["EncodingServices"]>;
|
|
31
34
|
}
|
|
32
|
-
export declare const layerSocket: <Self, Id extends string, D extends ProtocolDefinition>({ client, url, protocols, replay, }: {
|
|
35
|
+
export declare const layerSocket: <Self, Id extends string, D extends ProtocolDefinition, Reducers extends Reducer.Reducers<D>, CR = never>({ client, reducers, url, protocols, replay, onConnect, }: {
|
|
33
36
|
readonly client: Client<Self, Id, D>;
|
|
34
|
-
readonly
|
|
35
|
-
readonly protocols?: string | Array<string> | undefined;
|
|
37
|
+
readonly reducers: Reducers;
|
|
36
38
|
readonly replay?: ReplayConfig | undefined;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
readonly onConnect?: undefined | ((state: S.Struct<D["state"]>["Type"]) => Effect.Effect<void, never, CR>);
|
|
40
|
+
readonly protocols?: string | Array<string> | undefined;
|
|
41
|
+
readonly url?: string | undefined;
|
|
42
|
+
}) => Layer.Layer<Self, never, Socket.WebSocketConstructor | Protocol<D>["Actor"]["DecodingServices"] | Protocol<D>["F"]["Payload"]["EncodingServices"] | Reducer.Reducers.Services<Self, Reducers> | CR>;
|
|
43
|
+
export declare const layerWorker: <Self, Id extends string, D extends ProtocolDefinition, Reducers extends Reducer.Reducers<D>, T extends Protocol<D>, CR = never>({ client, reducers, replay, onConnect, }: {
|
|
39
44
|
readonly client: Client<Self, Id, D>;
|
|
45
|
+
readonly reducers: Reducers;
|
|
40
46
|
readonly replay?: ReplayConfig | undefined;
|
|
41
|
-
|
|
47
|
+
readonly onConnect?: undefined | ((state: S.Struct<D["state"]>["Type"]) => Effect.Effect<void, never, CR>);
|
|
48
|
+
}) => Layer.Layer<Self, never, Worker.WorkerPlatform | Worker.Spawner | T["Actor"]["DecodingServices"] | T["F"]["Payload"]["EncodingServices"] | Reducer.Reducers.Services<Self, Reducers>>;
|
package/dist/Client.js
CHANGED
|
@@ -1,41 +1,47 @@
|
|
|
1
|
-
import { Context, Encoding, Deferred, Effect, Layer, Option, PubSub, RcRef, Record, pipe, Ref, Scope, Stream, Take, Schema as S, Array,
|
|
1
|
+
import { Context, Encoding, Deferred, Effect, Layer, Option, PubSub, RcRef, Record, pipe, Ref, Scope, Stream, Take, Schema as S, Array, Fiber, Exit, Cause, Result, flow, Tracer, identity, Semaphore, } from "effect";
|
|
2
2
|
import { Socket } from "effect/unstable/socket";
|
|
3
3
|
import { Worker } from "effect/unstable/workers";
|
|
4
|
-
import
|
|
4
|
+
import * as Spanner from "liminal-util/Spanner";
|
|
5
5
|
import { decodeJsonString, encodeJsonString } from "./_util/schema.js";
|
|
6
6
|
import { AuditionError, ConnectionError, UnresolvedError } from "./errors.js";
|
|
7
|
-
import {} from "./F.js";
|
|
8
7
|
import { Protocol } from "./Protocol.js";
|
|
9
|
-
|
|
8
|
+
import * as Reducer from "./Reducer.js";
|
|
9
|
+
import * as Tracing from "./Tracing.js";
|
|
10
|
+
const span = Spanner.make(import.meta.url);
|
|
10
11
|
export const TypeId = "~liminal/Client";
|
|
11
12
|
export const Service = () => (id, definition) => {
|
|
12
13
|
const tag = Context.Service()(id);
|
|
13
14
|
const protocol = Protocol(definition);
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const state = tag.asEffect().pipe(Effect.flatMap(RcRef.get), Effect.map(({ state }) => state), Stream.unwrap);
|
|
16
|
+
const events = tag.asEffect().pipe(Effect.flatMap(RcRef.get), Effect.map(({ events }) => events), Stream.unwrap);
|
|
17
|
+
const fn = ((_tag, ...f) => Effect.fnUntraced(function* (payload) {
|
|
18
|
+
const { fnRaw: fn } = yield* tag.asEffect().pipe(Effect.flatMap(RcRef.get));
|
|
19
|
+
return yield* fn(_tag, payload);
|
|
20
|
+
}, Effect.scoped, ...f));
|
|
19
21
|
const invalidate = tag.asEffect().pipe(Effect.flatMap((rc) => RcRef.get(rc).pipe(Effect.flatMap(({ end }) => end), Effect.andThen(RcRef.invalidate(rc)))), Effect.scoped, Effect.ignore);
|
|
22
|
+
const reducer = (_event, f) => f;
|
|
20
23
|
return Object.assign(tag, {
|
|
21
24
|
[TypeId]: TypeId,
|
|
22
25
|
definition,
|
|
23
26
|
protocol,
|
|
27
|
+
state,
|
|
24
28
|
events,
|
|
25
|
-
|
|
29
|
+
fn,
|
|
26
30
|
invalidate,
|
|
31
|
+
reducer,
|
|
27
32
|
});
|
|
28
33
|
};
|
|
29
|
-
const make = (client,
|
|
34
|
+
const make = ({ build, client, reducers, onConnect, replay, }) => Effect.gen(function* () {
|
|
30
35
|
const rcr = yield* RcRef.make({
|
|
31
36
|
acquire: Effect.gen(function* () {
|
|
32
|
-
yield* debug("AcquisitionStarted");
|
|
33
37
|
const { listen, send } = yield* build;
|
|
34
38
|
const audition = yield* Deferred.make();
|
|
39
|
+
const stateDeferred = yield* Deferred.make();
|
|
35
40
|
const inflights = {};
|
|
36
41
|
let callId = 0;
|
|
37
42
|
let takeCount = 0;
|
|
38
|
-
const
|
|
43
|
+
const eventsPubsub = yield* PubSub.unbounded();
|
|
44
|
+
const statePubsub = yield* PubSub.unbounded({ replay: 1 });
|
|
39
45
|
const replayState = yield* Ref.make({
|
|
40
46
|
startupOpen: true,
|
|
41
47
|
buffer: [],
|
|
@@ -57,64 +63,93 @@ const make = (client, build, replay) => Effect.gen(function* () {
|
|
|
57
63
|
return { startupOpen, buffer };
|
|
58
64
|
});
|
|
59
65
|
}
|
|
60
|
-
yield* PubSub.publish(
|
|
66
|
+
yield* PubSub.publish(eventsPubsub, eventTake);
|
|
61
67
|
});
|
|
62
68
|
const outer = yield* Scope.Scope;
|
|
63
69
|
const scope = yield* Scope.fork(outer, "sequential");
|
|
64
70
|
const end = Scope.close(scope, Exit.void);
|
|
71
|
+
const reduceMutex = yield* Semaphore.make(1);
|
|
72
|
+
const reduceTask = Semaphore.withPermits(reduceMutex, 1);
|
|
65
73
|
const fiber = yield* listen(Effect.fnUntraced(function* (message) {
|
|
66
74
|
switch (message._tag) {
|
|
67
75
|
case "Audition.Success": {
|
|
68
|
-
|
|
76
|
+
const { initial } = message;
|
|
77
|
+
yield* PubSub.publish(statePubsub, initial);
|
|
78
|
+
const state = yield* Ref.make(initial);
|
|
79
|
+
yield* Deferred.succeed(stateDeferred, state);
|
|
69
80
|
yield* Deferred.succeed(audition, void 0);
|
|
81
|
+
yield* onConnect?.(initial) ?? Effect.void;
|
|
70
82
|
return;
|
|
71
83
|
}
|
|
72
84
|
case "Audition.Failure": {
|
|
73
85
|
const { expected, actual } = message;
|
|
74
|
-
yield* debug("Audition.Failed", { expected, actual });
|
|
75
86
|
return yield* new AuditionError({ value: { expected, actual } });
|
|
76
87
|
}
|
|
77
88
|
case "Event": {
|
|
78
89
|
const { event } = message;
|
|
79
|
-
|
|
80
|
-
|
|
90
|
+
const { _tag } = event;
|
|
91
|
+
const reducer = reducers[_tag];
|
|
92
|
+
const state = yield* Deferred.await(stateDeferred);
|
|
93
|
+
yield* Effect.gen(function* () {
|
|
94
|
+
const current = yield* Ref.get(state);
|
|
95
|
+
const reduced = yield* reducer(event)(current).pipe(Effect.provideService(client, rcr));
|
|
96
|
+
if (reduced) {
|
|
97
|
+
yield* PubSub.publish(statePubsub, reduced);
|
|
98
|
+
yield* Ref.set(state, reduced);
|
|
99
|
+
}
|
|
100
|
+
}).pipe(reduceTask);
|
|
101
|
+
const parent = message.trace ? Tracer.externalSpan(message.trace) : undefined;
|
|
102
|
+
yield* publishTake([event], true).pipe(span("enqueue-event", {
|
|
103
|
+
attributes: { _tag },
|
|
104
|
+
kind: "consumer",
|
|
105
|
+
parent,
|
|
106
|
+
}));
|
|
81
107
|
return;
|
|
82
108
|
}
|
|
83
109
|
case "F.Success":
|
|
84
110
|
case "F.Failure": {
|
|
85
111
|
const { id } = message;
|
|
86
|
-
const
|
|
87
|
-
if (
|
|
112
|
+
const inflight = inflights[id];
|
|
113
|
+
if (inflight) {
|
|
88
114
|
delete inflights[id];
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
115
|
+
return yield* Effect.gen(function* () {
|
|
116
|
+
switch (message._tag) {
|
|
117
|
+
case "F.Success": {
|
|
118
|
+
const { value } = message.success;
|
|
119
|
+
yield* Deferred.succeed(inflight.deferred, value);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
case "F.Failure": {
|
|
123
|
+
const { _tag, value } = message.failure;
|
|
124
|
+
yield* Effect.annotateLogs(Effect.logDebug("Call.Failed"), { id, _tag });
|
|
125
|
+
yield* Deferred.fail(inflight.deferred, value);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
101
128
|
}
|
|
102
|
-
}
|
|
129
|
+
}).pipe(inflight.span ? Effect.withParentSpan(inflight.span, { captureStackTrace: false }) : identity);
|
|
103
130
|
}
|
|
104
131
|
return;
|
|
105
132
|
}
|
|
106
133
|
case "Disconnect": {
|
|
107
|
-
yield* debug("Disconnected");
|
|
108
134
|
return;
|
|
109
135
|
}
|
|
110
136
|
}
|
|
111
137
|
})).pipe(Effect.ensuring(Effect.all([
|
|
112
|
-
|
|
138
|
+
Effect.sync(() => Record.keys(inflights).length).pipe(Effect.flatMap((unresolved) => unresolved === 0
|
|
139
|
+
? Effect.void
|
|
140
|
+
: Effect.annotateLogs(Effect.logDebug("Client.Closed"), { unresolved }))),
|
|
113
141
|
Deferred.succeed(audition, void 0),
|
|
114
142
|
RcRef.invalidate(rcr),
|
|
115
143
|
], { concurrency: "unbounded" })), Effect.forkScoped, Effect.provideService(Scope.Scope, scope));
|
|
144
|
+
const interrupt = Stream.interruptWhen(Fiber.await(fiber).pipe(Effect.flatMap(Exit.match({
|
|
145
|
+
onSuccess: () => Effect.void,
|
|
146
|
+
onFailure: flow(Cause.findError, Result.match({
|
|
147
|
+
onSuccess: Effect.fail,
|
|
148
|
+
onFailure: () => Effect.void,
|
|
149
|
+
})),
|
|
150
|
+
}))));
|
|
116
151
|
const events = Effect.gen(function* () {
|
|
117
|
-
const queue = yield* PubSub.subscribe(
|
|
152
|
+
const queue = yield* PubSub.subscribe(eventsPubsub);
|
|
118
153
|
const live = (replayCount) => Stream.fromSubscription(queue).pipe(Stream.filter((entry) => entry.seq > replayCount), Stream.map((entry) => entry.take), Stream.flattenTake);
|
|
119
154
|
if (!replay) {
|
|
120
155
|
return live(-1);
|
|
@@ -134,16 +169,11 @@ const make = (client, build, replay) => Effect.gen(function* () {
|
|
|
134
169
|
return buffer.length === 0
|
|
135
170
|
? live(replayCount)
|
|
136
171
|
: Stream.concat(Stream.fromIterable(buffer).pipe(Stream.map((entry) => entry.take), Stream.flattenTake), live(replayCount));
|
|
137
|
-
}).pipe(Stream.unwrap,
|
|
138
|
-
|
|
139
|
-
onFailure: flow(Cause.findError, Result.match({
|
|
140
|
-
onSuccess: Effect.fail,
|
|
141
|
-
onFailure: () => Effect.void,
|
|
142
|
-
})),
|
|
143
|
-
})))));
|
|
144
|
-
yield* Deferred.await(audition);
|
|
172
|
+
}).pipe(Stream.unwrap, interrupt);
|
|
173
|
+
const state = Stream.fromPubSub(statePubsub).pipe(interrupt);
|
|
145
174
|
const encodingServices = yield* Effect.context();
|
|
146
|
-
|
|
175
|
+
yield* Deferred.await(audition);
|
|
176
|
+
const fnRaw = (_tag, value) => Effect.gen(function* () {
|
|
147
177
|
const exit = fiber.pollUnsafe();
|
|
148
178
|
if (exit) {
|
|
149
179
|
return yield* Exit.match(exit, {
|
|
@@ -155,82 +185,99 @@ const make = (client, build, replay) => Effect.gen(function* () {
|
|
|
155
185
|
});
|
|
156
186
|
}
|
|
157
187
|
const id = callId++;
|
|
158
|
-
const
|
|
159
|
-
|
|
188
|
+
const deferred = yield* Deferred.make();
|
|
189
|
+
const span = yield* Tracing.current;
|
|
190
|
+
const trace = span ? Tracing.toTraceEnvelope(span) : undefined;
|
|
191
|
+
inflights[id] = { deferred, span };
|
|
160
192
|
yield* send({
|
|
161
193
|
_tag: "F.Payload",
|
|
162
194
|
id,
|
|
163
195
|
payload: { _tag, value },
|
|
196
|
+
...(trace && { trace }),
|
|
164
197
|
});
|
|
165
|
-
return yield* Effect.raceFirst(Deferred.await(
|
|
198
|
+
return yield* Effect.raceFirst(Deferred.await(deferred), Fiber.await(fiber).pipe(Effect.flatMap((exit) => Exit.match(exit, {
|
|
166
199
|
onSuccess: () => new UnresolvedError().asEffect(),
|
|
167
200
|
onFailure: flow(Cause.findError, Result.match({
|
|
168
201
|
onSuccess: Effect.fail,
|
|
169
202
|
onFailure: () => new UnresolvedError().asEffect(),
|
|
170
203
|
})),
|
|
171
204
|
}))));
|
|
172
|
-
}
|
|
173
|
-
|
|
205
|
+
}).pipe(span("fn", {
|
|
206
|
+
kind: "client",
|
|
207
|
+
attributes: { _tag },
|
|
208
|
+
}), Effect.provide(encodingServices));
|
|
209
|
+
return { state, events, fnRaw, end };
|
|
174
210
|
}).pipe(span("acquire", { attributes: { client: client.key } }), Effect.annotateLogs("client", client.key)),
|
|
175
211
|
});
|
|
176
212
|
return rcr;
|
|
177
213
|
}).pipe(Layer.effect(client));
|
|
178
|
-
export const layerSocket = ({ client, url, protocols, replay, }) => {
|
|
214
|
+
export const layerSocket = ({ client, reducers, url, protocols, replay, onConnect, }) => {
|
|
179
215
|
const { F, Actor } = client.protocol;
|
|
180
216
|
const encodeFPayload = encodeJsonString(F.Payload);
|
|
181
217
|
const decodeActor = decodeJsonString(Actor);
|
|
182
|
-
return make(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
218
|
+
return make({
|
|
219
|
+
client,
|
|
220
|
+
reducers,
|
|
221
|
+
onConnect,
|
|
222
|
+
replay,
|
|
223
|
+
build: Effect.gen(function* () {
|
|
224
|
+
const socket = yield* Socket.makeWebSocket(url ?? "/", {
|
|
225
|
+
protocols: ["liminal", Encoding.encodeBase64Url(client.key), ...(protocols ? Array.ensure(protocols) : [])],
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
listen: Effect.fnUntraced(function* (publish) {
|
|
229
|
+
yield* socket
|
|
230
|
+
.runRaw((raw) => pipe(raw instanceof Uint8Array ? new TextDecoder().decode(raw) : raw, decodeActor, Effect.andThen(publish)))
|
|
231
|
+
.pipe(Effect.catchIf(Socket.isSocketError, Effect.fnUntraced(function* (cause) {
|
|
232
|
+
const { reason } = cause;
|
|
233
|
+
if (reason._tag === "SocketCloseError" && reason.code === 1000) {
|
|
234
|
+
return yield* publish({ _tag: "Disconnect" });
|
|
235
|
+
}
|
|
236
|
+
yield* Effect.annotateLogs(Effect.logDebug(`SocketErrored.${reason._tag}`), { cause });
|
|
237
|
+
return yield* new ConnectionError({ cause });
|
|
238
|
+
})));
|
|
239
|
+
}, span("listen")),
|
|
240
|
+
send: Effect.fnUntraced(function* (v) {
|
|
241
|
+
const write = yield* socket.writer;
|
|
242
|
+
const message = yield* encodeFPayload(v);
|
|
243
|
+
yield* write(message).pipe(Effect.catchTag("SocketError", (cause) => new ConnectionError({ cause }).asEffect()));
|
|
244
|
+
}, span("send"), Effect.scoped),
|
|
245
|
+
};
|
|
246
|
+
}),
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
export const layerWorker = ({ client, reducers, replay, onConnect, }) => make({
|
|
250
|
+
client,
|
|
251
|
+
reducers,
|
|
252
|
+
onConnect,
|
|
253
|
+
replay,
|
|
254
|
+
build: Effect.gen(function* () {
|
|
255
|
+
const platform = yield* Worker.WorkerPlatform;
|
|
256
|
+
const backing = yield* platform
|
|
257
|
+
.spawn(0)
|
|
258
|
+
.pipe(Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()));
|
|
259
|
+
const send = (message) => backing.send(message).pipe(Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()), span("send"));
|
|
186
260
|
return {
|
|
187
261
|
listen: Effect.fnUntraced(function* (publish) {
|
|
188
|
-
yield*
|
|
189
|
-
|
|
190
|
-
.
|
|
191
|
-
|
|
192
|
-
if (
|
|
193
|
-
yield*
|
|
194
|
-
return yield* publish({ _tag: "Disconnect" });
|
|
262
|
+
const stop = yield* Deferred.make();
|
|
263
|
+
yield* backing
|
|
264
|
+
.run(Effect.fnUntraced(function* (message) {
|
|
265
|
+
yield* publish(message);
|
|
266
|
+
if (message._tag === "Disconnect" || message._tag === "Audition.Failure") {
|
|
267
|
+
yield* Deferred.succeed(stop, void 0);
|
|
195
268
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
269
|
+
}), {
|
|
270
|
+
onSpawn: backing
|
|
271
|
+
.send({
|
|
272
|
+
_tag: "Audition.Payload",
|
|
273
|
+
client: client.key,
|
|
274
|
+
})
|
|
275
|
+
.pipe(Effect.orDie),
|
|
276
|
+
})
|
|
277
|
+
.pipe(Effect.raceFirst(Deferred.await(stop)), Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()));
|
|
199
278
|
}, span("listen")),
|
|
200
|
-
send
|
|
201
|
-
const write = yield* socket.writer;
|
|
202
|
-
const message = yield* encodeFPayload(v);
|
|
203
|
-
yield* write(message).pipe(Effect.catchTag("SocketError", (cause) => new ConnectionError({ cause }).asEffect()));
|
|
204
|
-
}, span("send"), Effect.scoped),
|
|
279
|
+
send,
|
|
205
280
|
};
|
|
206
|
-
}),
|
|
207
|
-
};
|
|
208
|
-
export const layerWorker = ({ client, replay, }) => make(client, Effect.gen(function* () {
|
|
209
|
-
const platform = yield* Worker.WorkerPlatform;
|
|
210
|
-
const backing = yield* platform
|
|
211
|
-
.spawn(0)
|
|
212
|
-
.pipe(Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()));
|
|
213
|
-
const send = (message) => backing.send(message).pipe(Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()), span("send"));
|
|
214
|
-
return {
|
|
215
|
-
listen: Effect.fnUntraced(function* (publish) {
|
|
216
|
-
const stop = yield* Deferred.make();
|
|
217
|
-
yield* backing
|
|
218
|
-
.run(Effect.fnUntraced(function* (message) {
|
|
219
|
-
yield* publish(message);
|
|
220
|
-
if (message._tag === "Disconnect" || message._tag === "Audition.Failure") {
|
|
221
|
-
yield* Deferred.succeed(stop, void 0);
|
|
222
|
-
}
|
|
223
|
-
}), {
|
|
224
|
-
onSpawn: backing
|
|
225
|
-
.send({
|
|
226
|
-
_tag: "Audition.Payload",
|
|
227
|
-
client: client.key,
|
|
228
|
-
})
|
|
229
|
-
.pipe(Effect.orDie),
|
|
230
|
-
})
|
|
231
|
-
.pipe(Effect.raceFirst(Deferred.await(stop)), Effect.catchTag("WorkerError", (cause) => new ConnectionError({ cause }).asEffect()));
|
|
232
|
-
}, span("listen")),
|
|
233
|
-
send,
|
|
234
|
-
};
|
|
235
|
-
}), replay);
|
|
281
|
+
}),
|
|
282
|
+
});
|
|
236
283
|
//# sourceMappingURL=Client.js.map
|