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.
Files changed (94) hide show
  1. package/Actor.ts +12 -13
  2. package/ActorTransport.ts +6 -4
  3. package/Audition.ts +87 -40
  4. package/CHANGELOG.md +16 -0
  5. package/Client.ts +260 -134
  6. package/ClientDirectory.ts +50 -36
  7. package/ClientHandleEncoders.ts +15 -0
  8. package/Fn.ts +55 -0
  9. package/Method.ts +11 -21
  10. package/Protocol.ts +44 -36
  11. package/Reducer.ts +22 -0
  12. package/Tracing.ts +37 -0
  13. package/browser/BrowserActorNamespace.ts +65 -30
  14. package/dist/Actor.d.ts +1 -1
  15. package/dist/Actor.js +6 -6
  16. package/dist/Actor.js.map +1 -1
  17. package/dist/ActorTransport.d.ts +5 -4
  18. package/dist/Audition.d.ts +16 -9
  19. package/dist/Audition.js +25 -9
  20. package/dist/Audition.js.map +1 -1
  21. package/dist/Client.d.ts +21 -14
  22. package/dist/Client.js +147 -100
  23. package/dist/Client.js.map +1 -1
  24. package/dist/ClientDirectory.d.ts +14 -6
  25. package/dist/ClientDirectory.js +25 -22
  26. package/dist/ClientDirectory.js.map +1 -1
  27. package/dist/ClientHandleEncoders.d.ts +7 -0
  28. package/dist/ClientHandleEncoders.js +2 -0
  29. package/dist/ClientHandleEncoders.js.map +1 -0
  30. package/dist/Fn.d.ts +16 -0
  31. package/dist/Fn.js +2 -0
  32. package/dist/Fn.js.map +1 -0
  33. package/dist/Method.d.ts +9 -14
  34. package/dist/Method.js +0 -1
  35. package/dist/Method.js.map +1 -1
  36. package/dist/Protocol.d.ts +19 -22
  37. package/dist/Protocol.js +20 -15
  38. package/dist/Protocol.js.map +1 -1
  39. package/dist/Reducer.d.ts +11 -0
  40. package/dist/Reducer.js +2 -0
  41. package/dist/Reducer.js.map +1 -0
  42. package/dist/Tracing.d.ts +37 -0
  43. package/dist/Tracing.js +29 -0
  44. package/dist/Tracing.js.map +1 -0
  45. package/dist/browser/BrowserActorNamespace.d.ts +5 -5
  46. package/dist/browser/BrowserActorNamespace.js +41 -20
  47. package/dist/browser/BrowserActorNamespace.js.map +1 -1
  48. package/dist/errors.d.ts +0 -4
  49. package/dist/errors.js.map +1 -1
  50. package/dist/experimental/TaggedTemplateFunction.js +1 -1
  51. package/dist/experimental/TaggedTemplateFunction.js.map +1 -1
  52. package/dist/index.d.ts +3 -3
  53. package/dist/index.js +3 -3
  54. package/dist/index.js.map +1 -1
  55. package/dist/package.json +16 -21
  56. package/dist/tsconfig.tsbuildinfo +1 -1
  57. package/dist/workerd/ActorHandle.d.ts +9 -0
  58. package/dist/workerd/ActorHandle.js +4 -0
  59. package/dist/workerd/ActorHandle.js.map +1 -0
  60. package/dist/workerd/WorkerdActorNamespace.d.ts +18 -18
  61. package/dist/workerd/WorkerdActorNamespace.js +43 -141
  62. package/dist/workerd/WorkerdActorNamespace.js.map +1 -1
  63. package/dist/workerd/WorkerdActorRuntime.d.ts +19 -0
  64. package/dist/workerd/WorkerdActorRuntime.js +204 -0
  65. package/dist/workerd/WorkerdActorRuntime.js.map +1 -0
  66. package/dist/workerd/index.d.ts +2 -0
  67. package/dist/workerd/index.js +2 -0
  68. package/dist/workerd/index.js.map +1 -1
  69. package/errors.ts +0 -6
  70. package/experimental/TaggedTemplateFunction.ts +1 -1
  71. package/index.ts +3 -3
  72. package/package.json +10 -25
  73. package/tsconfig.json +1 -1
  74. package/vitest.config.ts +7 -0
  75. package/workerd/ActorHandle.ts +29 -0
  76. package/workerd/WorkerdActorNamespace.ts +86 -273
  77. package/workerd/WorkerdActorRuntime.ts +422 -0
  78. package/workerd/index.ts +2 -0
  79. package/Accumulator.ts +0 -103
  80. package/F.ts +0 -10
  81. package/_diagnostic.ts +0 -3
  82. package/_util/Mutex.ts +0 -13
  83. package/dist/Accumulator.d.ts +0 -22
  84. package/dist/Accumulator.js +0 -37
  85. package/dist/Accumulator.js.map +0 -1
  86. package/dist/F.d.ts +0 -4
  87. package/dist/F.js +0 -2
  88. package/dist/F.js.map +0 -1
  89. package/dist/_diagnostic.d.ts +0 -4
  90. package/dist/_diagnostic.js +0 -3
  91. package/dist/_diagnostic.js.map +0 -1
  92. package/dist/_util/Mutex.d.ts +0 -7
  93. package/dist/_util/Mutex.js +0 -9
  94. 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.13",
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
- "types": "./index.ts",
19
- "default": "./dist/index.js"
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.50",
42
- "@effect/sql-d1": "4.0.0-beta.50",
43
- "effect": "4.0.0-beta.50",
44
- "effect-workerd": "0.0.3",
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
@@ -6,6 +6,6 @@
6
6
  "types": ["@cloudflare/workers-types"]
7
7
  },
8
8
  "include": [".", "package.json"],
9
- "exclude": ["dist"],
9
+ "exclude": ["dist", "vitest.config.ts"],
10
10
  "references": [{ "path": "../effect-workerd" }, { "path": "../liminal-util" }]
11
11
  }
@@ -0,0 +1,7 @@
1
+ import { mergeConfig, type ViteUserConfig } from "vitest/config"
2
+
3
+ import config from "../konfik/vitest.ts"
4
+
5
+ export default mergeConfig(config, {
6
+ test: { name: "liminal" },
7
+ } satisfies ViteUserConfig)
@@ -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
- Layer,
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, HttpClient, FetchHttpClient } from "effect/unstable/http"
19
- import { boundLayer } from "liminal-util/boundLayer"
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 { ActorTransport } from "../ActorTransport.ts"
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
- import { diagnostic } from "../_diagnostic.ts"
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 ""?: this["actor"]["definition"]["client"]["protocol"]
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 layer: Layer.Layer<RunROut, RunE, ActorSelf | HttpClient.HttpClient | PreludeROut>
27
+ readonly internal: Internal
65
28
 
66
- readonly handlers: Method.Handlers<
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
- PreludeROut,
91
- PreludeE,
92
- RunROut,
93
- RunE,
94
- > extends Context.Service<NamespaceSelf, DurableObjectNamespace> {
95
- new (state: globalThis.DurableObjectState<{}>): Context.ServiceClass.Shape<NamespaceId, DurableObjectNamespace>
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 upgrade: (
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: (binding: string) => Layer.Layer<NamespaceSelf, S.SchemaError, never>
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 { hibernation, actor, prelude, handlers, layer: runLayer, onConnect } = definition
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 encodeName = S.encodeEffect(Name)
174
- const decodeName = S.decodeUnknownEffect(Name)
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 encodeEvent = encodeJsonString(P.Event)
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
- const transport: ActorTransport<WebSocket, AttachmentFields, D> = {
191
- send: (socket, event) => encodeEvent(event).pipe(Effect.andThen((v) => Effect.sync(() => socket.send(v)))),
192
- close: (socket) => Effect.sync(() => socket.close(1000)),
193
- snapshot: (socket, attachments) =>
194
- encodeAttachments(attachments).pipe(Effect.andThen((v) => Effect.sync(() => socket.serializeAttachment(v)))),
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
- const baseLayer = Layer.mergeAll(
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
- for (const socket of state.getWebSockets()) {
224
- const attachments = yield* decodeAttachments(socket.deserializeAttachment())
225
- yield* this.directory.register(socket, attachments)
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
- const name = yield* decodeName(url.searchParams.get("__liminal_name"))
242
- const attachments = yield* decodeAttachmentsString(url.searchParams.get("__liminal_attachments"))
243
- if (!this.#name) {
244
- this.#name = name
245
- const state = yield* DoState.DoState
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
- if (message._tag === "Disconnect") {
289
- return yield* currentClient.disconnect
290
- }
291
- const { id, payload } = message
292
- const { _tag, value } = payload as never
293
- yield* handlers[_tag]!(value).pipe(
294
- Effect.matchEffect({
295
- onSuccess: (value) =>
296
- encodeFSuccess({
297
- _tag: "F.Success",
298
- id,
299
- success: { _tag, value } as never,
300
- }),
301
- onFailure: (value) =>
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 upgrade = Effect.fnUntraced(function* (name: Name["Type"], attachments: (typeof Attachments)["Type"]) {
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, upgrade, layer }) as never
173
+ return Object.assign(tag, { definition, bind, layer })
361
174
  }