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