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 */
12import { NodeWS as WS } from "@effect/platform-node-shared/NodeSocket"
13import type * as Duration from "effect/Duration"
14import type * as Effect from "effect/Effect"
15import { flow } from "effect/Function"
16import * as Layer from "effect/Layer"
17import * as Socket from "effect/socket/Socket"
18
19/**
20 * @since 4.0.0
21 */
22export * from "@effect/platform-node-shared/NodeSocket"
23
24const 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 */
34export 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 */
55export 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 */
67export 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)