liminal 0.17.14 → 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 +8 -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 -20
- package/dist/workerd/WorkerdActorNamespace.js +30 -122
- 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 +7 -22
- package/tsconfig.json +1 -1
- package/vitest.config.ts +7 -0
- package/workerd/ActorHandle.ts +29 -0
- package/workerd/WorkerdActorNamespace.ts +72 -260
- 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/tsconfig.json
CHANGED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Schema as S, Effect, Cause, Encoding } from "effect"
|
|
2
|
+
import { NativeRequest } from "effect-workerd"
|
|
3
|
+
import { HttpServerResponse } from "effect/unstable/http"
|
|
4
|
+
|
|
5
|
+
import type { TopFromString } from "../_util/schema.ts"
|
|
6
|
+
import type { Methods } from "../Method.ts"
|
|
7
|
+
|
|
8
|
+
export interface ActorHandle<
|
|
9
|
+
NamespaceSelf,
|
|
10
|
+
Internal extends Methods,
|
|
11
|
+
Name extends TopFromString,
|
|
12
|
+
AttachmentFields extends S.Struct.Fields,
|
|
13
|
+
> {
|
|
14
|
+
readonly upgrade: (
|
|
15
|
+
attachments: S.Struct<AttachmentFields>["Type"],
|
|
16
|
+
) => Effect.Effect<
|
|
17
|
+
HttpServerResponse.HttpServerResponse,
|
|
18
|
+
S.SchemaError | Encoding.EncodingError | Cause.NoSuchElementError,
|
|
19
|
+
| NamespaceSelf
|
|
20
|
+
| NativeRequest.NativeRequest
|
|
21
|
+
| Name["EncodingServices"]
|
|
22
|
+
| S.Struct<AttachmentFields>["EncodingServices"]
|
|
23
|
+
>
|
|
24
|
+
|
|
25
|
+
readonly call: <K extends keyof Internal, M extends Internal[K]>(
|
|
26
|
+
method: K,
|
|
27
|
+
payload: M["payload"]["Type"],
|
|
28
|
+
) => Effect.Effect<M["success"]["Type"], M["failure"]["Type"], NamespaceSelf>
|
|
29
|
+
}
|
|
@@ -1,39 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
Layer,
|
|
4
|
-
Effect,
|
|
5
|
-
Scope,
|
|
6
|
-
Schema as S,
|
|
7
|
-
Context,
|
|
8
|
-
ManagedRuntime,
|
|
9
|
-
ConfigProvider,
|
|
10
|
-
Duration,
|
|
11
|
-
flow,
|
|
12
|
-
String,
|
|
13
|
-
Array,
|
|
14
|
-
Encoding,
|
|
15
|
-
Option,
|
|
16
|
-
Cause,
|
|
17
|
-
} from "effect"
|
|
18
|
-
import { Binding, DoState, NativeRequest } from "effect-workerd"
|
|
1
|
+
import { Layer, Effect, Schema as S, Context, flow, String, Array, Encoding, Exit } from "effect"
|
|
2
|
+
import { Binding, NativeRequest } from "effect-workerd"
|
|
19
3
|
import { SecWebSocketProtocol, close } from "effect-workerd/socket_util"
|
|
20
|
-
import { HttpServerResponse,
|
|
21
|
-
import
|
|
22
|
-
import { logCause } from "liminal-util/logCause"
|
|
4
|
+
import { HttpServerResponse, HttpTraceContext } from "effect/unstable/http"
|
|
5
|
+
import * as Spanner from "liminal-util/Spanner"
|
|
23
6
|
|
|
7
|
+
import { type TopFromString, encodeJsonString } from "../_util/schema.ts"
|
|
24
8
|
import type { Actor } from "../Actor.ts"
|
|
25
|
-
import type {
|
|
9
|
+
import type { Methods } from "../Method.ts"
|
|
26
10
|
import type { ProtocolDefinition } from "../Protocol.ts"
|
|
11
|
+
import type { ActorHandle } from "./ActorHandle.ts"
|
|
27
12
|
|
|
28
|
-
|
|
29
|
-
import * as Mutex from "../_util/Mutex.ts"
|
|
30
|
-
import { type TopFromString, encodeJsonString, decodeJsonString } from "../_util/schema.ts"
|
|
31
|
-
import * as ClientDirectory from "../ClientDirectory.ts"
|
|
32
|
-
import * as Method from "../Method.ts"
|
|
33
|
-
|
|
34
|
-
const { debug, span } = diagnostic("workerd.WorkerdActorNamespace")
|
|
13
|
+
const span = Spanner.make(import.meta.url)
|
|
35
14
|
|
|
36
15
|
export interface ActorNamespaceDefinition<
|
|
16
|
+
Internal extends Methods,
|
|
37
17
|
ActorSelf,
|
|
38
18
|
ActorId extends string,
|
|
39
19
|
Name extends TopFromString,
|
|
@@ -41,47 +21,18 @@ export interface ActorNamespaceDefinition<
|
|
|
41
21
|
ClientSelf,
|
|
42
22
|
ClientId extends string,
|
|
43
23
|
D extends ProtocolDefinition,
|
|
44
|
-
PreludeROut,
|
|
45
|
-
PreludeE,
|
|
46
|
-
RunROut,
|
|
47
|
-
RunE,
|
|
48
24
|
> {
|
|
49
|
-
readonly
|
|
50
|
-
|
|
51
|
-
readonly actor: Actor<ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D>
|
|
52
|
-
|
|
53
|
-
readonly prelude: Layer.Layer<
|
|
54
|
-
| PreludeROut
|
|
55
|
-
| NonNullable<this[""]>["F"]["Payload"]["DecodingServices"]
|
|
56
|
-
| NonNullable<this[""]>["F"]["Success"]["EncodingServices"]
|
|
57
|
-
| NonNullable<this[""]>["F"]["Failure"]["EncodingServices"]
|
|
58
|
-
| NonNullable<this[""]>["Event"]["EncodingServices"]
|
|
59
|
-
| S.Struct<AttachmentFields>["DecodingServices"]
|
|
60
|
-
| S.Struct<AttachmentFields>["EncodingServices"]
|
|
61
|
-
| Name["EncodingServices"]
|
|
62
|
-
| Name["DecodingServices"],
|
|
63
|
-
PreludeE
|
|
64
|
-
>
|
|
65
|
-
|
|
66
|
-
readonly layer: Layer.Layer<RunROut, RunE, ActorSelf | HttpClient.HttpClient | PreludeROut>
|
|
25
|
+
readonly binding: string
|
|
67
26
|
|
|
68
|
-
readonly
|
|
69
|
-
D["methods"],
|
|
70
|
-
ActorSelf | HttpClient.HttpClient | PreludeROut | RunROut | Scope.Scope
|
|
71
|
-
>
|
|
72
|
-
|
|
73
|
-
readonly onConnect: Effect.Effect<
|
|
74
|
-
void,
|
|
75
|
-
never,
|
|
76
|
-
ActorSelf | HttpClient.HttpClient | PreludeROut | RunROut | Scope.Scope
|
|
77
|
-
>
|
|
27
|
+
readonly internal: Internal
|
|
78
28
|
|
|
79
|
-
readonly
|
|
29
|
+
readonly actor: Actor<ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D>
|
|
80
30
|
}
|
|
81
31
|
|
|
82
32
|
export interface ActorNamespace<
|
|
83
33
|
NamespaceSelf,
|
|
84
34
|
NamespaceId extends string,
|
|
35
|
+
Internal extends Methods,
|
|
85
36
|
ActorSelf,
|
|
86
37
|
ActorId extends string,
|
|
87
38
|
Name extends TopFromString,
|
|
@@ -89,48 +40,44 @@ export interface ActorNamespace<
|
|
|
89
40
|
ClientSelf,
|
|
90
41
|
ClientId extends string,
|
|
91
42
|
D extends ProtocolDefinition,
|
|
92
|
-
PreludeROut,
|
|
93
|
-
PreludeE,
|
|
94
|
-
RunROut,
|
|
95
|
-
RunE,
|
|
96
43
|
> {
|
|
97
|
-
new (
|
|
98
|
-
|
|
99
|
-
|
|
44
|
+
new (
|
|
45
|
+
_: never,
|
|
46
|
+
): Context.ServiceClass.Shape<
|
|
47
|
+
NamespaceId,
|
|
48
|
+
DurableObjectNamespace<Rpc.DurableObjectBranded & WorkerdActorNamespace.MakeRpc<Internal>>
|
|
49
|
+
>
|
|
100
50
|
|
|
101
51
|
readonly definition: ActorNamespaceDefinition<
|
|
52
|
+
Methods,
|
|
102
53
|
ActorSelf,
|
|
103
54
|
ActorId,
|
|
104
55
|
Name,
|
|
105
56
|
AttachmentFields,
|
|
106
57
|
ClientSelf,
|
|
107
58
|
ClientId,
|
|
108
|
-
D
|
|
109
|
-
PreludeROut,
|
|
110
|
-
PreludeE,
|
|
111
|
-
RunROut,
|
|
112
|
-
RunE
|
|
59
|
+
D
|
|
113
60
|
>
|
|
114
61
|
|
|
115
|
-
readonly
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
HttpServerResponse.HttpServerResponse,
|
|
120
|
-
S.SchemaError | Encoding.EncodingError | Cause.NoSuchElementError,
|
|
121
|
-
| NamespaceSelf
|
|
122
|
-
| NativeRequest.NativeRequest
|
|
123
|
-
| Name["EncodingServices"]
|
|
124
|
-
| S.Struct<AttachmentFields>["EncodingServices"]
|
|
125
|
-
>
|
|
62
|
+
readonly bind: (name: Name["Type"]) => ActorHandle<NamespaceSelf, Internal, Name, AttachmentFields>
|
|
63
|
+
|
|
64
|
+
readonly layer: Layer.Layer<NamespaceSelf, S.SchemaError, never>
|
|
65
|
+
}
|
|
126
66
|
|
|
127
|
-
|
|
67
|
+
export declare namespace WorkerdActorNamespace {
|
|
68
|
+
export type MakeRpc<External extends Methods> = {
|
|
69
|
+
rpc: <K extends keyof External>(
|
|
70
|
+
method: K,
|
|
71
|
+
payload: External[K]["payload"]["Type"],
|
|
72
|
+
) => Promise<Exit.Exit<External[K]["success"]["Type"], External[K]["failure"]["Type"]>>
|
|
73
|
+
}
|
|
128
74
|
}
|
|
129
75
|
|
|
130
76
|
export const Service =
|
|
131
77
|
<NamespaceSelf>() =>
|
|
132
78
|
<
|
|
133
79
|
NamespaceId extends string,
|
|
80
|
+
Internal extends Methods,
|
|
134
81
|
ActorSelf,
|
|
135
82
|
ActorId extends string,
|
|
136
83
|
Name extends TopFromString,
|
|
@@ -138,41 +85,22 @@ export const Service =
|
|
|
138
85
|
ClientSelf,
|
|
139
86
|
ClientId extends string,
|
|
140
87
|
D extends ProtocolDefinition,
|
|
141
|
-
PreludeROut,
|
|
142
|
-
PreludeE,
|
|
143
|
-
RunROut,
|
|
144
|
-
RunE,
|
|
145
88
|
>(
|
|
146
89
|
id: NamespaceId,
|
|
147
|
-
definition: ActorNamespaceDefinition<
|
|
148
|
-
ActorSelf,
|
|
149
|
-
ActorId,
|
|
150
|
-
Name,
|
|
151
|
-
AttachmentFields,
|
|
152
|
-
ClientSelf,
|
|
153
|
-
ClientId,
|
|
154
|
-
D,
|
|
155
|
-
PreludeROut,
|
|
156
|
-
PreludeE,
|
|
157
|
-
RunROut,
|
|
158
|
-
RunE
|
|
159
|
-
>,
|
|
90
|
+
definition: ActorNamespaceDefinition<Internal, ActorSelf, ActorId, Name, AttachmentFields, ClientSelf, ClientId, D>,
|
|
160
91
|
): ActorNamespace<
|
|
161
92
|
NamespaceSelf,
|
|
162
93
|
NamespaceId,
|
|
94
|
+
Internal,
|
|
163
95
|
ActorSelf,
|
|
164
96
|
ActorId,
|
|
165
97
|
Name,
|
|
166
98
|
AttachmentFields,
|
|
167
99
|
ClientSelf,
|
|
168
100
|
ClientId,
|
|
169
|
-
D
|
|
170
|
-
PreludeROut,
|
|
171
|
-
PreludeE,
|
|
172
|
-
RunROut,
|
|
173
|
-
RunE
|
|
101
|
+
D
|
|
174
102
|
> => {
|
|
175
|
-
const {
|
|
103
|
+
const { binding, actor } = definition
|
|
176
104
|
const {
|
|
177
105
|
definition: {
|
|
178
106
|
name: Name,
|
|
@@ -181,160 +109,25 @@ export const Service =
|
|
|
181
109
|
},
|
|
182
110
|
} = actor
|
|
183
111
|
|
|
184
|
-
const
|
|
112
|
+
const tag = Context.Service<
|
|
113
|
+
NamespaceSelf,
|
|
114
|
+
DurableObjectNamespace<Rpc.DurableObjectBranded & WorkerdActorNamespace.MakeRpc<Internal>>
|
|
115
|
+
>()(id)
|
|
185
116
|
|
|
117
|
+
const encodeName = S.encodeEffect(Name)
|
|
186
118
|
const Attachments = S.Struct(AttachmentFields)
|
|
187
|
-
const encodeAttachments = S.encodeEffect(S.toCodecJson(Attachments))
|
|
188
|
-
const decodeAttachments = S.decodeUnknownEffect(S.toCodecJson(Attachments))
|
|
189
119
|
const encodeAttachmentsString = encodeJsonString(Attachments)
|
|
190
|
-
const decodeAttachmentsString = decodeJsonString(Attachments)
|
|
191
|
-
|
|
192
|
-
const encodeAuditionSuccess = encodeJsonString(P.Audition.Success)
|
|
193
120
|
const encodeAuditionFailure = encodeJsonString(P.Audition.Failure)
|
|
194
|
-
const decodeClientM = decodeJsonString(P.Client)
|
|
195
|
-
const encodeFSuccess = encodeJsonString(P.F.Success)
|
|
196
|
-
const encodeFFailure = encodeJsonString(P.F.Failure)
|
|
197
|
-
|
|
198
|
-
const encodeEvent = encodeJsonString(P.Event)
|
|
199
|
-
|
|
200
|
-
const transport: ActorTransport<WebSocket, AttachmentFields, D> = {
|
|
201
|
-
send: (socket, event) => encodeEvent(event).pipe(Effect.andThen((v) => Effect.sync(() => socket.send(v)))),
|
|
202
|
-
close: (socket) => Effect.sync(() => socket.close(1000)),
|
|
203
|
-
snapshot: (socket, attachments) =>
|
|
204
|
-
encodeAttachments(attachments).pipe(Effect.andThen((v) => Effect.sync(() => socket.serializeAttachment(v)))),
|
|
205
|
-
}
|
|
206
121
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
122
|
+
const bind = (name: Name["Type"]): ActorHandle<NamespaceSelf, Internal, Name, AttachmentFields> => {
|
|
123
|
+
const getStub = Effect.gen(function* () {
|
|
124
|
+
const namespace = yield* tag
|
|
125
|
+
const nameEncoded = yield* encodeName(name)
|
|
126
|
+
return namespace.getByName(nameEncoded)
|
|
127
|
+
})
|
|
210
128
|
|
|
211
|
-
|
|
212
|
-
static definition = definition
|
|
213
|
-
static service = Context.Service<NamespaceSelf, DurableObjectNamespace>()(id)
|
|
214
|
-
static layer = Binding.layer(this.service, ["idFromName", "idFromString", "newUniqueId", "get"])
|
|
215
|
-
|
|
216
|
-
readonly runtime
|
|
217
|
-
readonly directory = ClientDirectory.make(actor, transport)
|
|
218
|
-
|
|
219
|
-
constructor(state: DurableObjectState<{}>, env: Cloudflare.Env) {
|
|
220
|
-
super(state, env)
|
|
221
|
-
if (hibernation) {
|
|
222
|
-
Option.andThen(
|
|
223
|
-
Duration.fromInput(hibernation),
|
|
224
|
-
flow(Duration.toMillis, state.setHibernatableWebSocketEventTimeout),
|
|
225
|
-
)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const Live = Layer.mergeAll(
|
|
229
|
-
FetchHttpClient.layer,
|
|
230
|
-
Layer.succeed(DoState.DoState, state),
|
|
231
|
-
Mutex.layer,
|
|
232
|
-
Layer.effect(NameDecoded, S.decodeUnknownEffect(Name)(state.id.name)).pipe(
|
|
233
|
-
Layer.provideMerge(prelude.pipe(Layer.provideMerge(ConfigProvider.layer(ConfigProvider.fromUnknown(env))))),
|
|
234
|
-
),
|
|
235
|
-
).pipe(boundLayer("actor"))
|
|
236
|
-
|
|
237
|
-
const hydrateAttachments = Effect.gen({ self: this }, function* () {
|
|
238
|
-
for (const socket of state.getWebSockets()) {
|
|
239
|
-
const attachments = yield* decodeAttachments(socket.deserializeAttachment())
|
|
240
|
-
yield* this.directory.register(socket, attachments)
|
|
241
|
-
}
|
|
242
|
-
}).pipe(span("hydrateAttachments"), Effect.tapCause(logCause))
|
|
243
|
-
|
|
244
|
-
this.runtime = hydrateAttachments.pipe(Layer.effectDiscard, Layer.provideMerge(Live), ManagedRuntime.make)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
override fetch(request: Request): Promise<Response> {
|
|
248
|
-
return Effect.gen({ self: this }, function* () {
|
|
249
|
-
const url = new URL(request.url)
|
|
250
|
-
const attachments = yield* decodeAttachmentsString(url.searchParams.get("__liminal_attachments"))
|
|
251
|
-
const { 0: webSocket, 1: server } = new WebSocketPair()
|
|
252
|
-
const state = yield* DoState.DoState
|
|
253
|
-
state.acceptWebSocket(server)
|
|
254
|
-
server.send(yield* encodeAuditionSuccess({ _tag: "Audition.Success" }))
|
|
255
|
-
const currentClient = yield* this.directory.register(server, attachments)
|
|
256
|
-
const name = yield* NameDecoded
|
|
257
|
-
const ActorLive = Layer.succeed(actor, {
|
|
258
|
-
name,
|
|
259
|
-
clients: this.directory.handles,
|
|
260
|
-
currentClient,
|
|
261
|
-
})
|
|
262
|
-
yield* onConnect.pipe(
|
|
263
|
-
Effect.scoped,
|
|
264
|
-
span("onConnect"),
|
|
265
|
-
Effect.scoped,
|
|
266
|
-
Effect.provide(Layer.provideMerge(layer, ActorLive)),
|
|
267
|
-
)
|
|
268
|
-
yield* debug("ClientRegistered")
|
|
269
|
-
return new Response(null, {
|
|
270
|
-
status: 101,
|
|
271
|
-
webSocket,
|
|
272
|
-
headers: { [SecWebSocketProtocol]: "liminal" },
|
|
273
|
-
})
|
|
274
|
-
}).pipe(Effect.tapCause(logCause), span("fetch"), this.runtime.runPromise)
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
override webSocketMessage(socket: WebSocket, raw: string | ArrayBuffer) {
|
|
129
|
+
const upgrade = (attachments: S.Struct<AttachmentFields>["Type"]) =>
|
|
278
130
|
Effect.gen({ self: this }, function* () {
|
|
279
|
-
const currentClient = yield* this.directory.get(socket)
|
|
280
|
-
const name = yield* NameDecoded
|
|
281
|
-
const ActorLive = Layer.succeed(actor, {
|
|
282
|
-
name,
|
|
283
|
-
clients: this.directory.handles,
|
|
284
|
-
currentClient,
|
|
285
|
-
})
|
|
286
|
-
const message = yield* decodeClientM(raw instanceof ArrayBuffer ? new TextDecoder().decode(raw) : raw)
|
|
287
|
-
yield* debug("MessageReceived", { message })
|
|
288
|
-
if (message._tag === "Audition.Payload") {
|
|
289
|
-
return yield* Effect.die(undefined)
|
|
290
|
-
}
|
|
291
|
-
if (message._tag === "Disconnect") {
|
|
292
|
-
return yield* currentClient.disconnect
|
|
293
|
-
}
|
|
294
|
-
const { id, payload } = message
|
|
295
|
-
const { _tag, value } = payload as never
|
|
296
|
-
yield* handlers[_tag]!(value).pipe(
|
|
297
|
-
Effect.matchEffect({
|
|
298
|
-
onSuccess: (value) =>
|
|
299
|
-
encodeFSuccess({
|
|
300
|
-
_tag: "F.Success",
|
|
301
|
-
id,
|
|
302
|
-
success: { _tag, value } as never,
|
|
303
|
-
}),
|
|
304
|
-
onFailure: (value) =>
|
|
305
|
-
encodeFFailure({
|
|
306
|
-
_tag: "F.Failure",
|
|
307
|
-
id,
|
|
308
|
-
failure: { _tag, value } as never,
|
|
309
|
-
}),
|
|
310
|
-
}),
|
|
311
|
-
span("handler", { attributes: { _tag } }),
|
|
312
|
-
Effect.andThen((v) => Effect.sync(() => socket.send(v))),
|
|
313
|
-
Effect.scoped,
|
|
314
|
-
Effect.provide(Layer.provideMerge(layer, ActorLive)),
|
|
315
|
-
)
|
|
316
|
-
}).pipe(Effect.scoped, Mutex.task, Effect.tapCause(logCause), span("webSocketMessage"), this.runtime.runFork)
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
override webSocketClose(socket: WebSocket, _code: number, _reason: string, _wasClean: boolean) {
|
|
320
|
-
this.directory
|
|
321
|
-
.unregister(socket)
|
|
322
|
-
.pipe(Effect.tap(debug("SocketClosed")), Effect.tapCause(logCause), this.runtime.runFork)
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
override webSocketError(socket: WebSocket, cause: unknown) {
|
|
326
|
-
Effect.gen({ self: this }, function* () {
|
|
327
|
-
yield* debug("SocketErrored", { cause })
|
|
328
|
-
yield* this.directory.unregister(socket)
|
|
329
|
-
}).pipe(Effect.tapCause(logCause), span("SocketErrored", { attributes: { cause } }), this.runtime.runFork)
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
static readonly upgrade = (name: Name["Type"], attachments: (typeof Attachments)["Type"]) =>
|
|
333
|
-
Effect.gen({ self: this }, function* () {
|
|
334
|
-
yield* debug("UpgradeInitiated", { attachments })
|
|
335
|
-
const namespace = yield* this.service
|
|
336
|
-
const nameEncoded = yield* encodeName(name)
|
|
337
|
-
const stub = namespace.getByName(nameEncoded)
|
|
338
131
|
const request = yield* NativeRequest.NativeRequest
|
|
339
132
|
const protocols = yield* Effect.fromNullishOr(request.headers.get(SecWebSocketProtocol)).pipe(
|
|
340
133
|
Effect.map(flow(String.split(","), Array.map(String.trim))),
|
|
@@ -354,9 +147,28 @@ export const Service =
|
|
|
354
147
|
}
|
|
355
148
|
const url = new URL(request.url)
|
|
356
149
|
url.searchParams.set("__liminal_attachments", yield* encodeAttachmentsString(attachments))
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
)
|
|
360
|
-
|
|
150
|
+
const actorRequest = new Request(url, request)
|
|
151
|
+
const traceHeaders = yield* Effect.currentSpan.pipe(Effect.map(HttpTraceContext.toHeaders))
|
|
152
|
+
for (const [key, value] of Object.entries(traceHeaders)) {
|
|
153
|
+
actorRequest.headers.set(key, value)
|
|
154
|
+
}
|
|
155
|
+
const stub = yield* getStub
|
|
156
|
+
return yield* Effect.promise(() => stub.fetch(actorRequest)).pipe(Effect.map(HttpServerResponse.raw))
|
|
157
|
+
}).pipe(span("upgrade", { kind: "client" }))
|
|
158
|
+
|
|
159
|
+
const call = Effect.fnUntraced(function* <K extends keyof Internal, M extends Internal[K]>(
|
|
160
|
+
method: K,
|
|
161
|
+
payload: M["payload"]["Type"],
|
|
162
|
+
): Effect.fn.Return<M["success"]["Type"], M["failure"]["Type"], NamespaceSelf> {
|
|
163
|
+
const stub = yield* getStub
|
|
164
|
+
const exit = yield* Effect.promise(() => stub.rpc(method as never, payload as never))
|
|
165
|
+
return yield* exit as any
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
return { upgrade, call }
|
|
361
169
|
}
|
|
170
|
+
|
|
171
|
+
const layer = Binding.layer(tag, ["idFromName", "idFromString", "newUniqueId", "get", "getByName"])(binding)
|
|
172
|
+
|
|
173
|
+
return Object.assign(tag, { definition, bind, layer })
|
|
362
174
|
}
|