liminal 0.17.15 → 0.17.17
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 +22 -33
- package/{workerd/ActorHandle.ts → ActorHandle.ts} +7 -2
- package/{workerd/WorkerdActorNamespace.ts → ActorNamespace.ts} +46 -32
- package/{workerd/WorkerdActorRuntime.ts → ActorRuntime.ts} +71 -44
- package/ActorTransport.ts +2 -2
- package/Audition.ts +1 -1
- package/BrowserActorNamespace.ts +257 -0
- package/CHANGELOG.md +28 -0
- package/Client.ts +127 -76
- package/ClientDirectory.ts +40 -32
- package/ClientHandle.ts +9 -7
- package/Fn.ts +39 -0
- package/Tracing.ts +11 -3
- package/dist/Actor.d.ts +3 -5
- package/dist/Actor.js +5 -9
- package/dist/Actor.js.map +1 -1
- package/dist/{workerd/ActorHandle.d.ts → ActorHandle.d.ts} +6 -3
- package/dist/ActorHandle.js.map +1 -0
- package/dist/{workerd/WorkerdActorNamespace.d.ts → ActorNamespace.d.ts} +12 -10
- package/dist/{workerd/WorkerdActorNamespace.js → ActorNamespace.js} +16 -10
- package/dist/ActorNamespace.js.map +1 -0
- package/dist/{workerd/WorkerdActorRuntime.d.ts → ActorRuntime.d.ts} +10 -9
- package/dist/{workerd/WorkerdActorRuntime.js → ActorRuntime.js} +40 -34
- package/dist/ActorRuntime.js.map +1 -0
- package/dist/ActorTransport.d.ts +2 -2
- package/dist/Audition.js +1 -1
- package/dist/Audition.js.map +1 -1
- package/dist/BrowserActorNamespace.d.ts +39 -0
- package/dist/BrowserActorNamespace.js +134 -0
- package/dist/BrowserActorNamespace.js.map +1 -0
- package/dist/Client.d.ts +7 -4
- package/dist/Client.js +78 -48
- package/dist/Client.js.map +1 -1
- package/dist/ClientDirectory.d.ts +1 -1
- package/dist/ClientDirectory.js +11 -5
- package/dist/ClientDirectory.js.map +1 -1
- package/dist/ClientHandle.d.ts +5 -4
- package/dist/Fn.d.ts +8 -0
- package/dist/Tracing.js +6 -2
- package/dist/Tracing.js.map +1 -1
- package/dist/experimental/L/append.js +1 -1
- package/dist/experimental/L/append.js.map +1 -1
- package/dist/experimental/L/history.js +1 -1
- package/dist/experimental/L/history.js.map +1 -1
- package/dist/index.common.d.ts +12 -0
- package/dist/index.common.js +13 -0
- package/dist/index.common.js.map +1 -0
- package/dist/index.d.ts +4 -11
- package/dist/index.js +4 -11
- package/dist/index.js.map +1 -1
- package/dist/index.non-workerd.d.ts +1 -0
- package/dist/index.non-workerd.js +2 -0
- package/dist/index.non-workerd.js.map +1 -0
- package/dist/package.json +13 -7
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/experimental/L/append.ts +1 -1
- package/experimental/L/history.ts +1 -1
- package/index.common.ts +12 -0
- package/index.non-workerd.ts +1 -0
- package/index.ts +4 -11
- package/package.json +12 -9
- package/_util/schema.ts +0 -7
- package/browser/BrowserActorNamespace.ts +0 -248
- package/browser/index.ts +0 -1
- package/dist/_util/schema.d.ts +0 -4
- package/dist/_util/schema.js +0 -5
- package/dist/_util/schema.js.map +0 -1
- package/dist/browser/BrowserActorNamespace.d.ts +0 -16
- package/dist/browser/BrowserActorNamespace.js +0 -133
- package/dist/browser/BrowserActorNamespace.js.map +0 -1
- package/dist/browser/index.d.ts +0 -1
- package/dist/browser/index.js +0 -2
- package/dist/browser/index.js.map +0 -1
- package/dist/workerd/ActorHandle.js.map +0 -1
- package/dist/workerd/WorkerdActorNamespace.js.map +0 -1
- package/dist/workerd/WorkerdActorRuntime.js.map +0 -1
- package/dist/workerd/index.d.ts +0 -3
- package/dist/workerd/index.js +0 -4
- package/dist/workerd/index.js.map +0 -1
- package/workerd/index.ts +0 -3
- /package/dist/{workerd/ActorHandle.js → ActorHandle.js} +0 -0
package/ClientDirectory.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { Schema as S, Effect, Cause, Ref } from "effect"
|
|
2
|
-
import * as
|
|
2
|
+
import * as Boundary from "liminal-util/Boundary"
|
|
3
|
+
import type { TopFromString } from "liminal-util/schema"
|
|
3
4
|
|
|
4
5
|
import { phantom } from "./_util/phantom.ts"
|
|
5
|
-
import type { TopFromString } from "./_util/schema.ts"
|
|
6
6
|
import type { Actor } from "./Actor.ts"
|
|
7
7
|
import type { ActorTransport } from "./ActorTransport.ts"
|
|
8
8
|
import * as ClientHandle from "./ClientHandle.ts"
|
|
9
9
|
import type { ProtocolDefinition, Disconnect, Protocol } from "./Protocol.ts"
|
|
10
10
|
|
|
11
|
-
const span = Spanner.make(import.meta.url)
|
|
12
|
-
|
|
13
11
|
export interface ClientEntry<Client, Handle> {
|
|
14
12
|
readonly client: Client
|
|
15
13
|
|
|
@@ -86,33 +84,43 @@ export const make = <
|
|
|
86
84
|
entries.delete(key)
|
|
87
85
|
handles.delete(current.handle)
|
|
88
86
|
}
|
|
89
|
-
}).pipe(span("unregister"))
|
|
90
|
-
|
|
91
|
-
const register = Effect.fnUntraced(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
send: (_tag, payload) =>
|
|
102
|
-
send(client, {
|
|
103
|
-
_tag: "Event",
|
|
104
|
-
event: { _tag, ...payload } as never,
|
|
87
|
+
}).pipe(Boundary.span("unregister", import.meta.url))
|
|
88
|
+
|
|
89
|
+
const register = Effect.fnUntraced(
|
|
90
|
+
function* (client: Client, attachments: S.Struct<AttachmentFields>["Type"]) {
|
|
91
|
+
const clientKey = key(client)
|
|
92
|
+
yield* snapshot(client, attachments)
|
|
93
|
+
const attachmentsRef = yield* Ref.make(attachments)
|
|
94
|
+
const handle: Handle = {
|
|
95
|
+
attachments: Ref.get(attachmentsRef),
|
|
96
|
+
save: Effect.fnUntraced(function* (attachments) {
|
|
97
|
+
yield* Ref.set(attachmentsRef, attachments)
|
|
98
|
+
yield* snapshot(client, attachments)
|
|
105
99
|
}),
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
100
|
+
send: (_tag, payload) =>
|
|
101
|
+
send(client, {
|
|
102
|
+
_tag: "Event",
|
|
103
|
+
event: { _tag, ...payload } as never,
|
|
104
|
+
}),
|
|
105
|
+
disconnect: close(client).pipe(Effect.andThen(unregister(clientKey)), Effect.asVoid),
|
|
106
|
+
}
|
|
107
|
+
const previous = entries.get(clientKey)
|
|
108
|
+
if (previous) {
|
|
109
|
+
handles.delete(previous.handle)
|
|
110
|
+
}
|
|
111
|
+
entries.set(clientKey, { client, handle })
|
|
112
|
+
handles.add(handle)
|
|
113
|
+
return handle
|
|
114
|
+
},
|
|
115
|
+
Boundary.span("register", import.meta.url),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
...phantom,
|
|
120
|
+
handles,
|
|
121
|
+
register,
|
|
122
|
+
get,
|
|
123
|
+
entry,
|
|
124
|
+
unregister,
|
|
125
|
+
}
|
|
118
126
|
}
|
package/ClientHandle.ts
CHANGED
|
@@ -2,20 +2,22 @@ import { Schema as S, Effect } from "effect"
|
|
|
2
2
|
|
|
3
3
|
import type { ProtocolDefinition } from "./Protocol.ts"
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
) => Effect.Effect<void, S.SchemaError, ActorSelf | ReturnType<typeof S.TaggedUnion<D["events"]>>["EncodingServices"]>
|
|
5
|
+
export type Send<D extends ProtocolDefinition, RIn> = <K extends keyof D["events"]>(
|
|
6
|
+
tag: K,
|
|
7
|
+
payload: S.Struct<D["events"][K]>["Type"],
|
|
8
|
+
) => Effect.Effect<void, never, RIn | ReturnType<typeof S.TaggedUnion<D["events"]>>["EncodingServices"]>
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
export interface Sender<D extends ProtocolDefinition, R> {
|
|
11
|
+
readonly send: Send<D, R>
|
|
12
|
+
|
|
13
|
+
readonly disconnect: Effect.Effect<void, never, R>
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export interface ClientHandle<
|
|
15
17
|
ActorSelf,
|
|
16
18
|
AttachmentFields extends S.Struct.Fields,
|
|
17
19
|
D extends ProtocolDefinition,
|
|
18
|
-
> extends Sender<
|
|
20
|
+
> extends Sender<D, ActorSelf> {
|
|
19
21
|
readonly attachments: Effect.Effect<S.Struct<AttachmentFields>["Type"]>
|
|
20
22
|
|
|
21
23
|
readonly save: (
|
package/Fn.ts
CHANGED
|
@@ -53,3 +53,42 @@ export interface Fn<Self, Internal extends Methods> {
|
|
|
53
53
|
e: (value: D, payload: FnPayload<Internal, K>) => E,
|
|
54
54
|
): (payload: FnPayload<Internal, K>) => E
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
export interface FnNoSelf<Internal extends Methods> {
|
|
58
|
+
<K extends keyof Internal>(tag: K): (payload: FnPayload<Internal, K>) => FnEffect<never, Internal, K>
|
|
59
|
+
|
|
60
|
+
<K extends keyof Internal, A>(
|
|
61
|
+
tag: K,
|
|
62
|
+
a: (effect: FnEffect<never, Internal, K>, payload: FnPayload<Internal, K>) => A,
|
|
63
|
+
): (payload: FnPayload<Internal, K>) => A
|
|
64
|
+
|
|
65
|
+
<K extends keyof Internal, A, B>(
|
|
66
|
+
tag: K,
|
|
67
|
+
a: (effect: FnEffect<never, Internal, K>, payload: FnPayload<Internal, K>) => A,
|
|
68
|
+
b: (value: A, payload: FnPayload<Internal, K>) => B,
|
|
69
|
+
): (payload: FnPayload<Internal, K>) => B
|
|
70
|
+
|
|
71
|
+
<K extends keyof Internal, A, B, C>(
|
|
72
|
+
tag: K,
|
|
73
|
+
a: (effect: FnEffect<never, Internal, K>, payload: FnPayload<Internal, K>) => A,
|
|
74
|
+
b: (value: A, payload: FnPayload<Internal, K>) => B,
|
|
75
|
+
c: (value: B, payload: FnPayload<Internal, K>) => C,
|
|
76
|
+
): (payload: FnPayload<Internal, K>) => C
|
|
77
|
+
|
|
78
|
+
<K extends keyof Internal, A, B, C, D>(
|
|
79
|
+
tag: K,
|
|
80
|
+
a: (effect: FnEffect<never, Internal, K>, payload: FnPayload<Internal, K>) => A,
|
|
81
|
+
b: (value: A, payload: FnPayload<Internal, K>) => B,
|
|
82
|
+
c: (value: B, payload: FnPayload<Internal, K>) => C,
|
|
83
|
+
d: (value: C, payload: FnPayload<Internal, K>) => D,
|
|
84
|
+
): (payload: FnPayload<Internal, K>) => D
|
|
85
|
+
|
|
86
|
+
<K extends keyof Internal, A, B, C, D, E>(
|
|
87
|
+
tag: K,
|
|
88
|
+
a: (effect: FnEffect<never, Internal, K>, payload: FnPayload<Internal, K>) => A,
|
|
89
|
+
b: (value: A, payload: FnPayload<Internal, K>) => B,
|
|
90
|
+
c: (value: B, payload: FnPayload<Internal, K>) => C,
|
|
91
|
+
d: (value: C, payload: FnPayload<Internal, K>) => D,
|
|
92
|
+
e: (value: D, payload: FnPayload<Internal, K>) => E,
|
|
93
|
+
): (payload: FnPayload<Internal, K>) => E
|
|
94
|
+
}
|
package/Tracing.ts
CHANGED
|
@@ -19,9 +19,17 @@ export const Session = S.Struct({
|
|
|
19
19
|
trace: TraceEnvelope,
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
-
export const parent = Effect.currentParentSpan.pipe(
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
export const parent = Effect.currentParentSpan.pipe(
|
|
23
|
+
Effect.catchTags({
|
|
24
|
+
NoSuchElementError: () => Effect.undefined,
|
|
25
|
+
}),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
export const current = Effect.currentSpan.pipe(
|
|
29
|
+
Effect.catchTags({
|
|
30
|
+
NoSuchElementError: () => Effect.undefined,
|
|
31
|
+
}),
|
|
32
|
+
)
|
|
25
33
|
|
|
26
34
|
export const currentTrace = current.pipe(Effect.map((span) => (span ? toTraceEnvelope(span) : undefined)))
|
|
27
35
|
|
package/dist/Actor.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Context, Schema as S } from "effect";
|
|
2
|
-
import type { TopFromString } from "
|
|
2
|
+
import type { TopFromString } from "liminal-util/schema";
|
|
3
3
|
import type * as ActorClient from "./Client.ts";
|
|
4
4
|
import type { ClientHandle, Sender } from "./ClientHandle.ts";
|
|
5
|
-
import * as Method from "./Method.ts";
|
|
6
5
|
import { type ProtocolDefinition } from "./Protocol.ts";
|
|
7
6
|
export declare const TypeId: "~liminal/Actor";
|
|
8
7
|
export interface Service<ActorSelf, Name extends TopFromString, AttachmentFields extends S.Struct.Fields, D extends ProtocolDefinition> {
|
|
@@ -19,8 +18,7 @@ export interface Actor<ActorSelf, ActorId extends string, Name extends TopFromSt
|
|
|
19
18
|
new (_: never): Context.ServiceClass.Shape<ActorId, Service<ActorSelf, Name, AttachmentFields, D>>;
|
|
20
19
|
readonly [TypeId]: typeof TypeId;
|
|
21
20
|
readonly definition: ActorDefinition<Name, AttachmentFields, ActorClientSelf, ActorClientId, D>;
|
|
22
|
-
readonly all: Sender<
|
|
23
|
-
readonly others: Sender<
|
|
24
|
-
readonly handler: <K extends keyof D["external"], R>(tag: K, f: Method.Handler<D["external"][K], R>) => Method.Handler<D["external"][K], R>;
|
|
21
|
+
readonly all: Sender<D, ActorSelf>;
|
|
22
|
+
readonly others: Sender<D, ActorSelf>;
|
|
25
23
|
}
|
|
26
24
|
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,32 +1,28 @@
|
|
|
1
1
|
import { Context, Schema as S, Effect } from "effect";
|
|
2
|
-
import * as
|
|
3
|
-
import * as Method from "./Method.js";
|
|
2
|
+
import * as Boundary from "liminal-util/Boundary";
|
|
4
3
|
import {} from "./Protocol.js";
|
|
5
|
-
const span = Spanner.make(import.meta.url);
|
|
6
4
|
export const TypeId = "~liminal/Actor";
|
|
7
5
|
export const Service = () => (id, definition) => {
|
|
8
6
|
const tag = Context.Service()(id);
|
|
9
7
|
const all = {
|
|
10
|
-
send: (key, payload) => tag.
|
|
11
|
-
disconnect: tag.
|
|
8
|
+
send: (key, payload) => tag.pipe(Effect.flatMap(({ clients }) => Effect.forEach(clients, (client) => client.send(key, payload), { concurrency: "unbounded" })), Boundary.span("send-all", import.meta.url)),
|
|
9
|
+
disconnect: tag.pipe(Effect.flatMap(({ clients }) => Effect.forEach(clients, ({ disconnect }) => disconnect)), Boundary.span("disconnect-all", import.meta.url)),
|
|
12
10
|
};
|
|
13
11
|
const others = {
|
|
14
12
|
send: Effect.fnUntraced(function* (key, payload) {
|
|
15
13
|
const { clients, currentClient } = yield* tag;
|
|
16
14
|
yield* Effect.forEach(clients, (client) => (client === currentClient ? Effect.void : client.send(key, payload)), { concurrency: "unbounded" });
|
|
17
|
-
}, span("send-others")),
|
|
15
|
+
}, Boundary.span("send-others", import.meta.url)),
|
|
18
16
|
disconnect: Effect.gen(function* () {
|
|
19
17
|
const { clients, currentClient } = yield* tag;
|
|
20
18
|
yield* Effect.forEach(clients, (client) => (client === currentClient ? Effect.void : client.disconnect));
|
|
21
|
-
}).pipe(span("disconnect-others")),
|
|
19
|
+
}).pipe(Boundary.span("disconnect-others", import.meta.url)),
|
|
22
20
|
};
|
|
23
|
-
const handler = (_tag, f) => f;
|
|
24
21
|
return Object.assign(tag, {
|
|
25
22
|
[TypeId]: TypeId,
|
|
26
23
|
definition,
|
|
27
24
|
all,
|
|
28
25
|
others,
|
|
29
|
-
handler,
|
|
30
26
|
});
|
|
31
27
|
};
|
|
32
28
|
//# sourceMappingURL=Actor.js.map
|
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;AACrD,OAAO,KAAK,
|
|
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,QAAQ,MAAM,uBAAuB,CAAA;AAKjD,OAAO,EAA2B,MAAM,eAAe,CAAA;AAEvD,MAAM,CAAC,MAAM,MAAM,GAAG,gBAAyB,CAAA;AAiD/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,IAAI,CACN,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,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAC3C;QACH,UAAU,EAAE,GAAG,CAAC,IAAI,CAClB,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,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CACjD;KACF,CAAA;IAED,MAAM,MAAM,GAAyB;QACnC,IAAI,EAAE,MAAM,CAAC,UAAU,CACrB,QAAQ,CAAC,EAAE,GAAG,EAAE,OAAO;YACrB,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,EACD,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAC9C;QACD,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,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KAC7D,CAAA;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE;QACxB,CAAC,MAAM,CAAC,EAAE,MAAM;QAChB,UAAU;QACV,GAAG;QACH,MAAM;KACP,CAAC,CAAA;AACJ,CAAC,CAAA"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Schema as S, Effect, Cause, Encoding } from "effect";
|
|
2
2
|
import { NativeRequest } from "effect-workerd";
|
|
3
3
|
import { HttpServerResponse } from "effect/unstable/http";
|
|
4
|
-
import type { TopFromString } from "
|
|
5
|
-
import type {
|
|
6
|
-
|
|
4
|
+
import type { TopFromString } from "liminal-util/schema";
|
|
5
|
+
import type { Send } from "./ClientHandle.ts";
|
|
6
|
+
import type { Methods } from "./Method.ts";
|
|
7
|
+
import type { ProtocolDefinition } from "./Protocol.ts";
|
|
8
|
+
export interface ActorHandle<NamespaceSelf, Internal extends Methods, Name extends TopFromString, AttachmentFields extends S.Struct.Fields, D extends ProtocolDefinition> {
|
|
7
9
|
readonly upgrade: (attachments: S.Struct<AttachmentFields>["Type"]) => Effect.Effect<HttpServerResponse.HttpServerResponse, S.SchemaError | Encoding.EncodingError | Cause.NoSuchElementError, NamespaceSelf | NativeRequest.NativeRequest | Name["EncodingServices"] | S.Struct<AttachmentFields>["EncodingServices"]>;
|
|
8
10
|
readonly call: <K extends keyof Internal, M extends Internal[K]>(method: K, payload: M["payload"]["Type"]) => Effect.Effect<M["success"]["Type"], M["failure"]["Type"], NamespaceSelf>;
|
|
11
|
+
readonly proxySendAll: Send<D, NamespaceSelf>;
|
|
9
12
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActorHandle.js","sourceRoot":"","sources":["../ActorHandle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA"}
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import { Layer, Schema as S, Context, Exit } from "effect";
|
|
2
|
-
import {
|
|
3
|
-
import type
|
|
4
|
-
import type {
|
|
5
|
-
import type { ProtocolDefinition } from "../Protocol.ts";
|
|
2
|
+
import { Env } from "effect-workerd";
|
|
3
|
+
import { type TopFromString } from "liminal-util/schema";
|
|
4
|
+
import type { Actor } from "./Actor.ts";
|
|
6
5
|
import type { ActorHandle } from "./ActorHandle.ts";
|
|
6
|
+
import type { Methods } from "./Method.ts";
|
|
7
|
+
import type { ProtocolDefinition } from "./Protocol.ts";
|
|
7
8
|
export interface ActorNamespaceDefinition<Internal extends Methods, ActorSelf, ActorId extends string, Name extends TopFromString, AttachmentFields extends S.Struct.Fields, ClientSelf, ClientId extends string, D extends ProtocolDefinition> {
|
|
8
9
|
readonly binding: string;
|
|
9
10
|
readonly internal: Internal;
|
|
10
11
|
readonly actor: Actor<ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D>;
|
|
11
12
|
}
|
|
12
13
|
export interface ActorNamespace<NamespaceSelf, NamespaceId extends string, Internal extends Methods, ActorSelf, ActorId extends string, Name extends TopFromString, AttachmentFields extends S.Struct.Fields, ClientSelf, ClientId extends string, D extends ProtocolDefinition> {
|
|
13
|
-
new (_: never): Context.ServiceClass.Shape<NamespaceId, DurableObjectNamespace<Rpc.DurableObjectBranded &
|
|
14
|
+
new (_: never): Context.ServiceClass.Shape<NamespaceId, DurableObjectNamespace<Rpc.DurableObjectBranded & ActorNamespace.MakeRpc<Internal, D>>>;
|
|
14
15
|
readonly definition: ActorNamespaceDefinition<Methods, ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D>;
|
|
15
|
-
readonly bind: (name: Name["Type"]) => ActorHandle<NamespaceSelf, Internal, Name, AttachmentFields>;
|
|
16
|
-
readonly layer: Layer.Layer<NamespaceSelf, S.SchemaError,
|
|
16
|
+
readonly bind: (name: Name["Type"]) => ActorHandle<NamespaceSelf, Internal, Name, AttachmentFields, D>;
|
|
17
|
+
readonly layer: Layer.Layer<NamespaceSelf, S.SchemaError, Env>;
|
|
17
18
|
}
|
|
18
|
-
export declare namespace
|
|
19
|
-
type MakeRpc<
|
|
20
|
-
rpc: <K extends keyof
|
|
19
|
+
export declare namespace ActorNamespace {
|
|
20
|
+
type MakeRpc<Internal extends Methods, D extends ProtocolDefinition> = {
|
|
21
|
+
rpc: <K extends keyof Internal>(method: K, payload: Internal[K]["payload"]["Type"]) => Promise<Exit.Exit<Internal[K]["success"]["Type"], Internal[K]["failure"]["Type"]>>;
|
|
22
|
+
proxySendAll<K extends keyof D["events"]>(event: K, payload: S.Struct<D["events"][K]>["Type"]): void;
|
|
21
23
|
};
|
|
22
24
|
}
|
|
23
25
|
export declare const Service: <NamespaceSelf>() => <NamespaceId extends string, Internal extends Methods, ActorSelf, ActorId extends string, Name extends TopFromString, AttachmentFields extends S.Struct.Fields, ClientSelf, ClientId extends string, D extends ProtocolDefinition>(id: NamespaceId, definition: ActorNamespaceDefinition<Internal, ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D>) => ActorNamespace<NamespaceSelf, NamespaceId, Internal, ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D>;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Layer, Effect, Schema as S, Context, flow, String, Array, Encoding, Exit } from "effect";
|
|
2
|
-
import { Binding, NativeRequest } from "effect-workerd";
|
|
2
|
+
import { Binding, Env, NativeRequest } from "effect-workerd";
|
|
3
3
|
import { SecWebSocketProtocol, close } from "effect-workerd/socket_util";
|
|
4
4
|
import { HttpServerResponse, HttpTraceContext } from "effect/unstable/http";
|
|
5
|
-
import * as
|
|
6
|
-
import { encodeJsonString } from "
|
|
7
|
-
const span = Spanner.make(import.meta.url);
|
|
5
|
+
import * as Boundary from "liminal-util/Boundary";
|
|
6
|
+
import { encodeJsonString } from "liminal-util/schema";
|
|
8
7
|
export const Service = () => (id, definition) => {
|
|
9
8
|
const { binding, actor } = definition;
|
|
10
9
|
const { definition: { name: Name, client: { key: clientId, protocol: P }, attachments: AttachmentFields, }, } = actor;
|
|
@@ -22,8 +21,9 @@ export const Service = () => (id, definition) => {
|
|
|
22
21
|
const upgrade = (attachments) => Effect.gen({ self: this }, function* () {
|
|
23
22
|
const request = yield* NativeRequest.NativeRequest;
|
|
24
23
|
const protocols = yield* Effect.fromNullishOr(request.headers.get(SecWebSocketProtocol)).pipe(Effect.map(flow(String.split(","), Array.map(String.trim))));
|
|
25
|
-
const liminalTokenI = yield* Array.findFirstIndex(protocols, (v) => v === "liminal");
|
|
26
|
-
const
|
|
24
|
+
const liminalTokenI = yield* Array.findFirstIndex(protocols, (v) => v === "liminal").pipe(Effect.fromOption);
|
|
25
|
+
const liminalClientId = yield* Effect.fromNullishOr(protocols[liminalTokenI + 1]);
|
|
26
|
+
const requestClientId = yield* Effect.fromNullishOr(protocols[liminalTokenI + 2]).pipe(Effect.flatMap((v) => Encoding.decodeBase64UrlString(v).pipe(Effect.fromResult)));
|
|
27
27
|
if (requestClientId !== clientId) {
|
|
28
28
|
return close(yield* encodeAuditionFailure({
|
|
29
29
|
_tag: "Audition.Failure",
|
|
@@ -33,6 +33,7 @@ export const Service = () => (id, definition) => {
|
|
|
33
33
|
}
|
|
34
34
|
const url = new URL(request.url);
|
|
35
35
|
url.searchParams.set("__liminal_attachments", yield* encodeAttachmentsString(attachments));
|
|
36
|
+
url.searchParams.set("__liminal_client_id", liminalClientId);
|
|
36
37
|
const actorRequest = new Request(url, request);
|
|
37
38
|
const traceHeaders = yield* Effect.currentSpan.pipe(Effect.map(HttpTraceContext.toHeaders));
|
|
38
39
|
for (const [key, value] of Object.entries(traceHeaders)) {
|
|
@@ -40,15 +41,20 @@ export const Service = () => (id, definition) => {
|
|
|
40
41
|
}
|
|
41
42
|
const stub = yield* getStub;
|
|
42
43
|
return yield* Effect.promise(() => stub.fetch(actorRequest)).pipe(Effect.map(HttpServerResponse.raw));
|
|
43
|
-
}).pipe(span("upgrade", { kind: "client" }));
|
|
44
|
+
}).pipe(Boundary.span("upgrade", import.meta.url, { kind: "client" }));
|
|
44
45
|
const call = Effect.fnUntraced(function* (method, payload) {
|
|
45
46
|
const stub = yield* getStub;
|
|
46
47
|
const exit = yield* Effect.promise(() => stub.rpc(method, payload));
|
|
47
48
|
return yield* exit;
|
|
48
|
-
});
|
|
49
|
-
|
|
49
|
+
}, Boundary.span("call", import.meta.url));
|
|
50
|
+
// TODO:
|
|
51
|
+
const proxySendAll = Effect.fnUntraced(function* (event, payload) {
|
|
52
|
+
const stub = yield* getStub;
|
|
53
|
+
yield* Effect.promise(() => stub.proxySendAll(event, payload));
|
|
54
|
+
}, Boundary.span("proxySendAll", import.meta.url));
|
|
55
|
+
return { upgrade, call, proxySendAll };
|
|
50
56
|
};
|
|
51
57
|
const layer = Binding.layer(tag, ["idFromName", "idFromString", "newUniqueId", "get", "getByName"])(binding);
|
|
52
58
|
return Object.assign(tag, { definition, bind, layer });
|
|
53
59
|
};
|
|
54
|
-
//# sourceMappingURL=
|
|
60
|
+
//# sourceMappingURL=ActorNamespace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActorNamespace.js","sourceRoot":"","sources":["../ActorNamespace.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { DurableObject } from "cloudflare:workers";
|
|
2
2
|
import { Layer, Effect, Scope, Schema as S, Duration } from "effect";
|
|
3
|
+
import { Env } from "effect-workerd";
|
|
3
4
|
import { HttpClient } from "effect/unstable/http";
|
|
4
|
-
import { type TopFromString } from "
|
|
5
|
-
import type {
|
|
6
|
-
import type {
|
|
7
|
-
import type {
|
|
5
|
+
import { type TopFromString } from "liminal-util/schema";
|
|
6
|
+
import type { ActorNamespace } from "./ActorNamespace.ts";
|
|
7
|
+
import type { Handlers, Methods } from "./Method.ts";
|
|
8
|
+
import type { ProtocolDefinition } from "./Protocol.ts";
|
|
8
9
|
export interface ActorRuntimeDefinition<NamespaceSelf, NamespaceId extends string, Internal extends Methods, ActorSelf, ActorId extends string, Name extends TopFromString, AttachmentFields extends S.Struct.Fields, ClientSelf, ClientId extends string, D extends ProtocolDefinition, PreludeROut, PreludeE, RunROut, RunE> {
|
|
9
10
|
readonly ""?: this["namespace"]["definition"]["actor"]["definition"]["client"]["protocol"];
|
|
10
11
|
readonly namespace: ActorNamespace<NamespaceSelf, NamespaceId, Internal, ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D>;
|
|
11
|
-
readonly prelude: Layer.Layer<PreludeROut | NonNullable<this[""]>["F"]["Payload"]["DecodingServices"] | NonNullable<this[""]>["F"]["Success"]["EncodingServices"] | NonNullable<this[""]>["F"]["Failure"]["EncodingServices"] | NonNullable<this[""]>["Event"]["EncodingServices"] | S.Struct<AttachmentFields>["DecodingServices"] | S.Struct<AttachmentFields>["EncodingServices"] | Name["EncodingServices"] | Name["DecodingServices"], PreludeE, HttpClient.HttpClient>;
|
|
12
|
-
readonly layer: Layer.Layer<RunROut, RunE, ActorSelf | HttpClient.HttpClient | PreludeROut>;
|
|
13
|
-
readonly external: Handlers<D["external"], ActorSelf | HttpClient.HttpClient | PreludeROut | RunROut | Scope.Scope>;
|
|
12
|
+
readonly prelude: Layer.Layer<PreludeROut | NonNullable<this[""]>["F"]["Payload"]["DecodingServices"] | NonNullable<this[""]>["F"]["Success"]["EncodingServices"] | NonNullable<this[""]>["F"]["Failure"]["EncodingServices"] | NonNullable<this[""]>["Event"]["EncodingServices"] | S.Struct<AttachmentFields>["DecodingServices"] | S.Struct<AttachmentFields>["EncodingServices"] | Name["EncodingServices"] | Name["DecodingServices"], PreludeE, HttpClient.HttpClient | Env>;
|
|
13
|
+
readonly layer: Layer.Layer<RunROut, RunE, ActorSelf | HttpClient.HttpClient | Env | PreludeROut>;
|
|
14
|
+
readonly external: Handlers<D["external"], ActorSelf | HttpClient.HttpClient | Env | PreludeROut | RunROut | Scope.Scope>;
|
|
14
15
|
readonly internal: Handlers<Internal, ActorSelf | HttpClient.HttpClient | PreludeROut | RunROut | Scope.Scope>;
|
|
15
|
-
readonly hydrate: Effect.Effect<S.Struct<D["state"]>["Type"], never, ActorSelf | HttpClient.HttpClient | PreludeROut | RunROut | Scope.Scope>;
|
|
16
|
-
readonly onDisconnect: Effect.Effect<void, never, ActorSelf | HttpClient.HttpClient | PreludeROut | RunROut | Scope.Scope>;
|
|
16
|
+
readonly hydrate: Effect.Effect<S.Struct<D["state"]>["Type"], never, ActorSelf | HttpClient.HttpClient | Env | PreludeROut | RunROut | Scope.Scope>;
|
|
17
|
+
readonly onDisconnect: Effect.Effect<void, never, ActorSelf | HttpClient.HttpClient | Env | PreludeROut | RunROut | Scope.Scope>;
|
|
17
18
|
readonly hibernation?: Duration.Input | undefined;
|
|
18
19
|
}
|
|
19
20
|
export declare const make: <NamespaceSelf, NamespaceId extends string, Internal extends Methods, ActorSelf, ActorId extends string, Name extends TopFromString, AttachmentFields extends S.Struct.Fields, ClientSelf, ClientId extends string, D extends ProtocolDefinition, PreludeROut, PreludeE, RunROut, RunE>(definition: ActorRuntimeDefinition<NamespaceSelf, NamespaceId, Internal, ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D, PreludeROut, PreludeE, RunROut, RunE>) => new (state: DurableObjectState<{}>, env: Cloudflare.Env) => DurableObject;
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { DurableObject } from "cloudflare:workers";
|
|
2
2
|
import { Layer, Effect, Scope, Schema as S, Context, ManagedRuntime, ConfigProvider, Duration, flow, Option, Tracer, pipe, Exit, } from "effect";
|
|
3
3
|
import { DoState } from "effect-workerd";
|
|
4
|
+
import { Env } from "effect-workerd";
|
|
4
5
|
import { Clock } from "effect-workerd/platform";
|
|
5
6
|
import { SecWebSocketProtocol } from "effect-workerd/socket_util";
|
|
6
7
|
import { Headers, FetchHttpClient, HttpClient, HttpTraceContext } from "effect/unstable/http";
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import * as
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import * as Tracing from "../Tracing.js";
|
|
13
|
-
import { sessionAttributes, SessionId, sessionLink } from "../Tracing.js";
|
|
14
|
-
const span = Spanner.make(import.meta.url);
|
|
8
|
+
import * as Boundary from "liminal-util/Boundary";
|
|
9
|
+
import { encodeJsonString, decodeJsonString } from "liminal-util/schema";
|
|
10
|
+
import * as ClientDirectory from "./ClientDirectory.js";
|
|
11
|
+
import * as Tracing from "./Tracing.js";
|
|
12
|
+
import { sessionAttributes, SessionId, sessionLink } from "./Tracing.js";
|
|
15
13
|
export const make = (definition) => {
|
|
16
14
|
const { hibernation, prelude, external, layer, hydrate, onDisconnect, internal, namespace: { definition: { actor }, }, } = definition;
|
|
17
15
|
const { definition: { name: Name, client: { protocol: P }, attachments: AttachmentFields, }, } = actor;
|
|
@@ -34,26 +32,27 @@ export const make = (definition) => {
|
|
|
34
32
|
const { _tag } = event.event;
|
|
35
33
|
return Effect.gen(function* () {
|
|
36
34
|
const trace = yield* Tracing.currentTrace;
|
|
37
|
-
const encoded = yield* encodeEvent({
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
35
|
+
const encoded = yield* encodeEvent({ ...event, ...(trace && { trace }) }).pipe(Effect.catchTags({
|
|
36
|
+
SchemaError: Effect.die,
|
|
37
|
+
}));
|
|
41
38
|
// @effect-diagnostics-next-line tryCatchInEffectGen:off
|
|
42
39
|
try {
|
|
43
40
|
socket.send(encoded);
|
|
44
41
|
// oxlint-disable-next-line no-unused-vars
|
|
45
42
|
}
|
|
46
43
|
catch (_e) { }
|
|
47
|
-
}).pipe(span("send", {
|
|
44
|
+
}).pipe(Boundary.span("send", import.meta.url, {
|
|
48
45
|
attributes: { _tag, ...sessionAttributes(session) },
|
|
49
46
|
kind: "producer",
|
|
50
47
|
links: [sessionLink(session)],
|
|
51
48
|
}));
|
|
52
49
|
},
|
|
53
50
|
close: ({ socket }) => Effect.sync(() => socket.close(1000)),
|
|
54
|
-
snapshot: ({ socket, session }, attachments) => encodeSocketAttachment({ attachments, session }).pipe(Effect.
|
|
51
|
+
snapshot: ({ socket, session }, attachments) => encodeSocketAttachment({ attachments, session }).pipe(Effect.catchTags({
|
|
52
|
+
SchemaError: Effect.die,
|
|
53
|
+
}), Effect.andThen((v) => Effect.sync(() => socket.serializeAttachment(v)))),
|
|
55
54
|
};
|
|
56
|
-
class NameDecoded extends Context.Service()("liminal/
|
|
55
|
+
class NameDecoded extends Context.Service()("liminal/ActorNamespace/NameDecoded") {
|
|
57
56
|
}
|
|
58
57
|
return class extends DurableObject {
|
|
59
58
|
run;
|
|
@@ -71,7 +70,7 @@ export const make = (definition) => {
|
|
|
71
70
|
if (hibernation) {
|
|
72
71
|
Option.andThen(Duration.fromInput(hibernation), flow(Duration.toMillis, (timeout) => state.setHibernatableWebSocketEventTimeout(timeout)));
|
|
73
72
|
}
|
|
74
|
-
const Live = Layer.mergeAll(FetchHttpClient.layer, Layer.succeed(DoState.DoState, state), Layer.effect(NameDecoded, S.decodeUnknownEffect(Name)(state.id.name))).pipe(Layer.provideMerge(prelude.pipe(Layer.provideMerge(Layer.mergeAll(FetchHttpClient.layer, ConfigProvider.layer(ConfigProvider.fromUnknown(env)))))), Layer.provideMerge(Clock.layer));
|
|
73
|
+
const Live = Layer.mergeAll(FetchHttpClient.layer, Layer.succeed(DoState.DoState, state), Layer.succeed(Env, env), Layer.effect(NameDecoded, S.decodeUnknownEffect(Name)(state.id.name))).pipe(Layer.provideMerge(prelude.pipe(Layer.provideMerge(Layer.mergeAll(FetchHttpClient.layer, ConfigProvider.layer(ConfigProvider.fromUnknown(env)), Layer.succeed(Env, env))))), Layer.provideMerge(Clock.layer));
|
|
75
74
|
const HydrateClientsLive = Effect.gen({ self: this }, function* () {
|
|
76
75
|
for (const socket of state.getWebSockets()) {
|
|
77
76
|
const { attachments, session } = yield* decodeSocketAttachment(socket.deserializeAttachment());
|
|
@@ -79,23 +78,24 @@ export const make = (definition) => {
|
|
|
79
78
|
.register({ socket, session }, attachments)
|
|
80
79
|
.pipe(Effect.linkSpans(Tracer.externalSpan(session.trace), sessionLink(session).attributes));
|
|
81
80
|
}
|
|
82
|
-
}).pipe(span("hydrate"), Layer.effectDiscard);
|
|
83
|
-
const runtime = ManagedRuntime.make(HydrateClientsLive.pipe(Layer.provideMerge(Live),
|
|
84
|
-
this.run =
|
|
81
|
+
}).pipe(Boundary.span("hydrate", import.meta.url), Layer.effectDiscard);
|
|
82
|
+
const runtime = ManagedRuntime.make(HydrateClientsLive.pipe(Layer.provideMerge(Live), Boundary.layer("actor", import.meta.url)));
|
|
83
|
+
this.run = (effect) => Effect.onError(effect, Effect.logError).pipe(runtime.runPromise);
|
|
85
84
|
}
|
|
86
85
|
fetch(request) {
|
|
87
86
|
return Effect.gen({ self: this }, function* () {
|
|
88
87
|
const url = new URL(request.url);
|
|
89
88
|
const attachments = yield* decodeAttachmentsString(url.searchParams.get("__liminal_attachments"));
|
|
89
|
+
const clientId = yield* Effect.fromNullishOr(url.searchParams.get("__liminal_client_id"));
|
|
90
90
|
const { 0: webSocket, 1: server } = new WebSocketPair();
|
|
91
91
|
const state = yield* DoState.DoState;
|
|
92
92
|
const session = {
|
|
93
|
-
id: SessionId.make(
|
|
93
|
+
id: SessionId.make(clientId),
|
|
94
94
|
trace: yield* Effect.currentSpan.pipe(Effect.map(Tracing.toTraceEnvelope)),
|
|
95
95
|
};
|
|
96
96
|
const currentClient = yield* this.directory.register({ socket: server, session }, attachments);
|
|
97
97
|
state.acceptWebSocket(server);
|
|
98
|
-
const initial = yield* hydrate.pipe(this.provideActor(currentClient), span("hydrate", {
|
|
98
|
+
const initial = yield* hydrate.pipe(this.provideActor(currentClient), Boundary.span("hydrate", import.meta.url, {
|
|
99
99
|
attributes: sessionAttributes(session),
|
|
100
100
|
links: [sessionLink(session)],
|
|
101
101
|
}));
|
|
@@ -105,7 +105,7 @@ export const make = (definition) => {
|
|
|
105
105
|
webSocket,
|
|
106
106
|
headers: { [SecWebSocketProtocol]: "liminal" },
|
|
107
107
|
});
|
|
108
|
-
}).pipe(span("fetch", {
|
|
108
|
+
}).pipe(Boundary.span("fetch", import.meta.url, {
|
|
109
109
|
kind: "server",
|
|
110
110
|
parent: pipe(request.headers, Headers.fromInput, HttpTraceContext.fromHeaders, Option.getOrUndefined),
|
|
111
111
|
}), this.run);
|
|
@@ -121,7 +121,7 @@ export const make = (definition) => {
|
|
|
121
121
|
}
|
|
122
122
|
if (message._tag === "Disconnect") {
|
|
123
123
|
yield* currentClient.disconnect;
|
|
124
|
-
return yield* onDisconnect.pipe(this.provideActor(currentClient), span("disconnect", {
|
|
124
|
+
return yield* onDisconnect.pipe(this.provideActor(currentClient), Boundary.span("disconnect", import.meta.url, {
|
|
125
125
|
attributes: sessionAttributes(session),
|
|
126
126
|
links: [sessionLink(session)],
|
|
127
127
|
}));
|
|
@@ -158,47 +158,53 @@ export const make = (definition) => {
|
|
|
158
158
|
}), Effect.andThen((v) => Effect.try({
|
|
159
159
|
try: () => socket.send(v),
|
|
160
160
|
catch: () => { },
|
|
161
|
-
})), this.provideActor(currentClient), span("handler", {
|
|
161
|
+
})), this.provideActor(currentClient), Boundary.span("handler", import.meta.url, {
|
|
162
162
|
attributes: { _tag, ...sessionAttributes(session) },
|
|
163
163
|
kind: "server",
|
|
164
164
|
parent,
|
|
165
165
|
links,
|
|
166
166
|
}));
|
|
167
|
-
}).pipe(span("socket-message"), this.run);
|
|
167
|
+
}).pipe(Boundary.span("socket-message", import.meta.url), this.run);
|
|
168
168
|
}
|
|
169
169
|
webSocketClose(socket, _code, _reason, _wasClean) {
|
|
170
170
|
Effect.gen({ self: this }, function* () {
|
|
171
|
-
const entry = yield* this.directory
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
const entry = yield* this.directory.entry(socket).pipe(Effect.catchTags({
|
|
172
|
+
NoSuchElementError: () => Effect.undefined,
|
|
173
|
+
}));
|
|
174
174
|
if (!entry) {
|
|
175
175
|
return;
|
|
176
176
|
}
|
|
177
177
|
const { client: { session }, handle: currentClient, } = entry;
|
|
178
178
|
yield* Effect.annotateCurrentSpan(sessionAttributes(session));
|
|
179
179
|
yield* this.directory.unregister(socket);
|
|
180
|
-
yield* onDisconnect.pipe(this.provideActor(currentClient), span("disconnect", {
|
|
180
|
+
yield* onDisconnect.pipe(this.provideActor(currentClient), Boundary.span("disconnect", import.meta.url, {
|
|
181
181
|
attributes: sessionAttributes(session),
|
|
182
182
|
links: [sessionLink(session)],
|
|
183
183
|
}));
|
|
184
|
-
}).pipe(span("socket-close"), this.run);
|
|
184
|
+
}).pipe(Boundary.span("socket-close", import.meta.url), this.run);
|
|
185
185
|
}
|
|
186
186
|
webSocketError(socket, cause) {
|
|
187
187
|
Effect.gen({ self: this }, function* () {
|
|
188
188
|
const { client: { session }, handle: currentClient, } = yield* this.directory.entry(socket);
|
|
189
189
|
yield* Effect.annotateCurrentSpan(sessionAttributes(session));
|
|
190
190
|
yield* this.directory.unregister(socket);
|
|
191
|
-
yield* onDisconnect.pipe(this.provideActor(currentClient), span("disconnect", {
|
|
191
|
+
yield* onDisconnect.pipe(this.provideActor(currentClient), Boundary.span("disconnect", import.meta.url, {
|
|
192
192
|
attributes: sessionAttributes(session),
|
|
193
193
|
links: [sessionLink(session)],
|
|
194
194
|
}));
|
|
195
195
|
yield* Effect.annotateLogs(Effect.logDebug("SocketErrored"), { cause });
|
|
196
|
-
}).pipe(span("socket-error"), this.run);
|
|
196
|
+
}).pipe(Boundary.span("socket-error", import.meta.url), this.run);
|
|
197
197
|
}
|
|
198
198
|
async rpc(method, payload) {
|
|
199
199
|
const handler = internal[method];
|
|
200
|
-
return await handler(payload).pipe(this.provideActor(null), span("fn-internal"), Effect.exit, this.run);
|
|
200
|
+
return await handler(payload).pipe(this.provideActor(null), Boundary.span("fn-internal", import.meta.url), Effect.exit, this.run);
|
|
201
|
+
}
|
|
202
|
+
async proxySendAll(event, payload) {
|
|
203
|
+
await Effect.gen(function* () {
|
|
204
|
+
const { clients } = yield* actor;
|
|
205
|
+
yield* Effect.forEach(clients, ({ send }) => send(event, payload), { concurrency: "unbounded" });
|
|
206
|
+
}).pipe(this.provideActor(null), Boundary.span("fn-internal", import.meta.url), this.run);
|
|
201
207
|
}
|
|
202
208
|
};
|
|
203
209
|
};
|
|
204
|
-
//# sourceMappingURL=
|
|
210
|
+
//# sourceMappingURL=ActorRuntime.js.map
|