| 1 | /** |
| 2 | * Node.js socket constructors and layers for Effect sockets. |
| 3 | * |
| 4 | * This module re-exports the shared Node socket support for TCP connections, |
| 5 | * Unix domain socket connections, and Node `Duplex` streams. It also provides |
| 6 | * WebSocket constructor layers: one that uses `globalThis.WebSocket` when |
| 7 | * present and falls back to `ws`, one that always uses `ws`, and one that |
| 8 | * creates a `Socket.Socket` layer for a WebSocket URL. |
| 9 | * |
| 10 | * @since 4.0.0 |
| 11 | */ |
| 12 | import { NodeWS as WS } from "@effect/platform-node-shared/NodeSocket" |
| 13 | import type * as Duration from "effect/Duration" |
| 14 | import type * as Effect from "effect/Effect" |
| 15 | import { flow } from "effect/Function" |
| 16 | import * as Layer from "effect/Layer" |
| 17 | import * as Socket from "effect/socket/Socket" |
| 18 | |
| 19 | /** |
| 20 | * @since 4.0.0 |
| 21 | */ |
| 22 | export * from "@effect/platform-node-shared/NodeSocket" |
| 23 | |
| 24 | const makeWebSocketWS: Socket.WebSocketConstructor["Service"] = (url, options) => |
| 25 | new WS.WebSocket(url, options as WS.ClientOptions) |
| 26 | |
| 27 | /** |
| 28 | * Provides a `Socket.WebSocketConstructor`, using `globalThis.WebSocket` when |
| 29 | * available and falling back to the `ws` package otherwise. |
| 30 | * |
| 31 | * @category layers |
| 32 | * @since 4.0.0 |
| 33 | */ |
| 34 | export const layerWebSocketConstructor: Layer.Layer< |
| 35 | Socket.WebSocketConstructor |
| 36 | > = Layer.sync(Socket.WebSocketConstructor)(() => { |
| 37 | if ("WebSocket" in globalThis) { |
| 38 | return (url, options) => { |
| 39 | if (options === undefined || typeof options === "string" || Array.isArray(options)) { |
| 40 | return new globalThis.WebSocket(url, options) |
| 41 | } |
| 42 | return makeWebSocketWS(url, options) |
| 43 | } |
| 44 | } |
| 45 | return makeWebSocketWS |
| 46 | }) |
| 47 | |
| 48 | /** |
| 49 | * Provides a `Socket.WebSocketConstructor` backed explicitly by the `ws` |
| 50 | * package. |
| 51 | * |
| 52 | * @category layers |
| 53 | * @since 4.0.0 |
| 54 | */ |
| 55 | export const layerWebSocketConstructorWS: Layer.Layer< |
| 56 | Socket.WebSocketConstructor |
| 57 | > = Layer.succeed(Socket.WebSocketConstructor)(makeWebSocketWS) |
| 58 | |
| 59 | /** |
| 60 | * Creates a `Socket.Socket` layer for a WebSocket URL using the Node WebSocket |
| 61 | * constructor layer, honoring protocol, open-timeout, and high-water-mark |
| 62 | * options. |
| 63 | * |
| 64 | * @category layers |
| 65 | * @since 4.0.0 |
| 66 | */ |
| 67 | export const layerWebSocket: ( |
| 68 | url: string | Effect.Effect<string>, |
| 69 | options?: { |
| 70 | readonly openTimeout?: Duration.Input | undefined |
| 71 | readonly protocols?: string | Array<string> | undefined |
| 72 | readonly highWaterMark?: number | undefined |
| 73 | } | undefined |
| 74 | ) => Layer.Layer<Socket.Socket, never, never> = flow( |
| 75 | Socket.makeWebSocket, |
| 76 | Layer.effect(Socket.Socket), |
| 77 | Layer.provide(layerWebSocketConstructor) |
| 78 | ) |