@effect/platform-node 4.0.0-beta.8 → 4.0.0-beta.81
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/dist/Mime.d.ts +9 -3
- package/dist/Mime.d.ts.map +1 -1
- package/dist/Mime.js +9 -3
- package/dist/Mime.js.map +1 -1
- package/dist/NodeChildProcessSpawner.d.ts +1 -1
- package/dist/NodeChildProcessSpawner.js +1 -1
- package/dist/NodeClusterHttp.d.ts +25 -7
- package/dist/NodeClusterHttp.d.ts.map +1 -1
- package/dist/NodeClusterHttp.js +20 -10
- package/dist/NodeClusterHttp.js.map +1 -1
- package/dist/NodeClusterSocket.d.ts +37 -11
- package/dist/NodeClusterSocket.d.ts.map +1 -1
- package/dist/NodeClusterSocket.js +37 -11
- package/dist/NodeClusterSocket.js.map +1 -1
- package/dist/NodeCrypto.d.ts +10 -0
- package/dist/NodeCrypto.d.ts.map +1 -0
- package/dist/NodeCrypto.js +22 -0
- package/dist/NodeCrypto.js.map +1 -0
- package/dist/NodeFileSystem.d.ts +4 -2
- package/dist/NodeFileSystem.d.ts.map +1 -1
- package/dist/NodeFileSystem.js +12 -3
- package/dist/NodeFileSystem.js.map +1 -1
- package/dist/NodeHttpClient.d.ts +98 -29
- package/dist/NodeHttpClient.d.ts.map +1 -1
- package/dist/NodeHttpClient.js +120 -33
- package/dist/NodeHttpClient.js.map +1 -1
- package/dist/NodeHttpIncomingMessage.d.ts +36 -9
- package/dist/NodeHttpIncomingMessage.d.ts.map +1 -1
- package/dist/NodeHttpIncomingMessage.js +40 -8
- package/dist/NodeHttpIncomingMessage.js.map +1 -1
- package/dist/NodeHttpPlatform.d.ts +10 -4
- package/dist/NodeHttpPlatform.d.ts.map +1 -1
- package/dist/NodeHttpPlatform.js +20 -7
- package/dist/NodeHttpPlatform.js.map +1 -1
- package/dist/NodeHttpServer.d.ts +59 -19
- package/dist/NodeHttpServer.d.ts.map +1 -1
- package/dist/NodeHttpServer.js +102 -52
- package/dist/NodeHttpServer.js.map +1 -1
- package/dist/NodeHttpServerRequest.d.ts +18 -5
- package/dist/NodeHttpServerRequest.d.ts.map +1 -1
- package/dist/NodeHttpServerRequest.js +11 -4
- package/dist/NodeHttpServerRequest.js.map +1 -1
- package/dist/NodeMultipart.d.ts +24 -4
- package/dist/NodeMultipart.d.ts.map +1 -1
- package/dist/NodeMultipart.js +24 -4
- package/dist/NodeMultipart.js.map +1 -1
- package/dist/NodePath.d.ts +15 -6
- package/dist/NodePath.d.ts.map +1 -1
- package/dist/NodePath.js +23 -7
- package/dist/NodePath.js.map +1 -1
- package/dist/NodeRedis.d.ts +27 -9
- package/dist/NodeRedis.d.ts.map +1 -1
- package/dist/NodeRedis.js +30 -12
- package/dist/NodeRedis.js.map +1 -1
- package/dist/NodeRuntime.d.ts +27 -36
- package/dist/NodeRuntime.d.ts.map +1 -1
- package/dist/NodeRuntime.js +17 -13
- package/dist/NodeRuntime.js.map +1 -1
- package/dist/NodeServices.d.ts +19 -5
- package/dist/NodeServices.d.ts.map +1 -1
- package/dist/NodeServices.js +7 -3
- package/dist/NodeServices.js.map +1 -1
- package/dist/NodeSink.d.ts +2 -2
- package/dist/NodeSink.js +2 -2
- package/dist/NodeSocket.d.ts +18 -3
- package/dist/NodeSocket.d.ts.map +1 -1
- package/dist/NodeSocket.js +27 -4
- package/dist/NodeSocket.js.map +1 -1
- package/dist/NodeSocketServer.d.ts +2 -2
- package/dist/NodeSocketServer.js +2 -2
- package/dist/NodeStdio.d.ts +5 -2
- package/dist/NodeStdio.d.ts.map +1 -1
- package/dist/NodeStdio.js +13 -3
- package/dist/NodeStdio.js.map +1 -1
- package/dist/NodeStream.d.ts +2 -2
- package/dist/NodeStream.js +2 -2
- package/dist/NodeTerminal.d.ts +8 -2
- package/dist/NodeTerminal.d.ts.map +1 -1
- package/dist/NodeTerminal.js +15 -3
- package/dist/NodeTerminal.js.map +1 -1
- package/dist/NodeWorker.d.ts +9 -2
- package/dist/NodeWorker.d.ts.map +1 -1
- package/dist/NodeWorker.js +22 -6
- package/dist/NodeWorker.js.map +1 -1
- package/dist/NodeWorkerRunner.d.ts +5 -1
- package/dist/NodeWorkerRunner.d.ts.map +1 -1
- package/dist/NodeWorkerRunner.js +18 -5
- package/dist/NodeWorkerRunner.js.map +1 -1
- package/dist/Undici.d.ts +18 -5
- package/dist/Undici.d.ts.map +1 -1
- package/dist/Undici.js +18 -5
- package/dist/Undici.js.map +1 -1
- package/dist/index.d.ts +28 -26
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -26
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/src/Mime.ts +10 -3
- package/src/NodeChildProcessSpawner.ts +1 -1
- package/src/NodeClusterHttp.ts +30 -11
- package/src/NodeClusterSocket.ts +37 -11
- package/src/NodeCrypto.ts +24 -0
- package/src/NodeFileSystem.ts +12 -3
- package/src/NodeHttpClient.ts +128 -38
- package/src/NodeHttpIncomingMessage.ts +48 -12
- package/src/NodeHttpPlatform.ts +21 -6
- package/src/NodeHttpServer.ts +124 -56
- package/src/NodeHttpServerRequest.ts +18 -5
- package/src/NodeMultipart.ts +24 -4
- package/src/NodePath.ts +23 -7
- package/src/NodeRedis.ts +32 -14
- package/src/NodeRuntime.ts +35 -37
- package/src/NodeServices.ts +21 -5
- package/src/NodeSink.ts +2 -2
- package/src/NodeSocket.ts +32 -4
- package/src/NodeSocketServer.ts +2 -2
- package/src/NodeStdio.ts +13 -3
- package/src/NodeStream.ts +2 -2
- package/src/NodeTerminal.ts +15 -3
- package/src/NodeWorker.ts +22 -6
- package/src/NodeWorkerRunner.ts +18 -5
- package/src/Undici.ts +18 -5
- package/src/index.ts +29 -26
package/src/NodeClusterSocket.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Node.js socket layers for Effect Cluster runners.
|
|
3
|
+
*
|
|
4
|
+
* The main `layer` builds a sharding layer for socket transport, choosing
|
|
5
|
+
* serialization, runner health checks, runner storage, message storage, and
|
|
6
|
+
* optional client-only mode from the supplied options. This module also
|
|
7
|
+
* re-exports the shared socket client and server protocol layers, and provides
|
|
8
|
+
* Kubernetes-aware Undici dispatcher and HTTP client layers for runner health
|
|
9
|
+
* checks.
|
|
10
|
+
*
|
|
11
|
+
* @since 4.0.0
|
|
3
12
|
*/
|
|
4
13
|
import { layerClientProtocol, layerSocketServer } from "@effect/platform-node-shared/NodeClusterSocket"
|
|
5
14
|
import type { ConfigError } from "effect/Config"
|
|
@@ -25,20 +34,30 @@ import * as Undici from "./Undici.ts"
|
|
|
25
34
|
|
|
26
35
|
export {
|
|
27
36
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
37
|
+
* Provides the cluster `RpcClientProtocol` using the shared socket client
|
|
38
|
+
* implementation.
|
|
39
|
+
*
|
|
40
|
+
* @category re-exports
|
|
41
|
+
* @since 4.0.0
|
|
30
42
|
*/
|
|
31
43
|
layerClientProtocol,
|
|
32
44
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
45
|
+
* Provides the socket server used by Node cluster runners through the shared
|
|
46
|
+
* socket server implementation.
|
|
47
|
+
*
|
|
48
|
+
* @category re-exports
|
|
49
|
+
* @since 4.0.0
|
|
35
50
|
*/
|
|
36
51
|
layerSocketServer
|
|
37
52
|
}
|
|
38
53
|
|
|
39
54
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
55
|
+
* Builds the Node cluster socket sharding layer, configuring RPC
|
|
56
|
+
* serialization, message storage, runner health checks, and optional
|
|
57
|
+
* client-only mode.
|
|
58
|
+
*
|
|
59
|
+
* @category layers
|
|
60
|
+
* @since 4.0.0
|
|
42
61
|
*/
|
|
43
62
|
export const layer = <
|
|
44
63
|
const ClientOnly extends boolean = false,
|
|
@@ -111,8 +130,12 @@ export const layer = <
|
|
|
111
130
|
}
|
|
112
131
|
|
|
113
132
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
133
|
+
* Provides an Undici dispatcher for Kubernetes API calls, using the service
|
|
134
|
+
* account CA certificate when it is available and falling back to the default
|
|
135
|
+
* dispatcher otherwise.
|
|
136
|
+
*
|
|
137
|
+
* @category layers
|
|
138
|
+
* @since 4.0.0
|
|
116
139
|
*/
|
|
117
140
|
export const layerDispatcherK8s: Layer.Layer<NodeHttpClient.Dispatcher> = Layer.effect(NodeHttpClient.Dispatcher)(
|
|
118
141
|
Effect.gen(function*() {
|
|
@@ -140,8 +163,11 @@ export const layerDispatcherK8s: Layer.Layer<NodeHttpClient.Dispatcher> = Layer.
|
|
|
140
163
|
)
|
|
141
164
|
|
|
142
165
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
166
|
+
* Provides a `K8sHttpClient` backed by the Undici HTTP client and the
|
|
167
|
+
* Kubernetes-aware dispatcher.
|
|
168
|
+
*
|
|
169
|
+
* @category layers
|
|
170
|
+
* @since 4.0.0
|
|
145
171
|
*/
|
|
146
172
|
export const layerK8sHttpClient: Layer.Layer<K8sHttpClient.K8sHttpClient> = K8sHttpClient.layer.pipe(
|
|
147
173
|
Layer.provide(Layer.fresh(NodeHttpClient.layerUndiciNoDispatcher)),
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `NodeCrypto` module provides the Node.js `Crypto` service layer for
|
|
3
|
+
* Effect programs. Provide {@link layer} at the edge of a Node application,
|
|
4
|
+
* CLI, script, or test to satisfy `effect/Crypto` with Node's `node:crypto`
|
|
5
|
+
* implementation for secure random bytes, UUID generation, random values, and
|
|
6
|
+
* SHA digest operations.
|
|
7
|
+
*
|
|
8
|
+
* This module is the public Node adapter around the shared Node-compatible
|
|
9
|
+
* implementation. Digest failures are reported as platform errors, and SHA-1
|
|
10
|
+
* remains available only for interoperability with existing protocols.
|
|
11
|
+
*
|
|
12
|
+
* @since 1.0.0
|
|
13
|
+
*/
|
|
14
|
+
import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
15
|
+
import type * as Crypto from "effect/Crypto"
|
|
16
|
+
import type * as Layer from "effect/Layer"
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Layer that provides the Node.js Crypto service implementation.
|
|
20
|
+
*
|
|
21
|
+
* @category layers
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
*/
|
|
24
|
+
export const layer: Layer.Layer<Crypto.Crypto> = NodeCrypto.layer
|
package/src/NodeFileSystem.ts
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Node.js `FileSystem` layer for programs that perform real filesystem I/O.
|
|
3
|
+
*
|
|
4
|
+
* The exported layer satisfies the platform-independent `FileSystem` service
|
|
5
|
+
* with Node-backed operations for files, directories, metadata, permissions,
|
|
6
|
+
* links, temporary paths, and path watching. Effects still call the service from
|
|
7
|
+
* `effect/FileSystem`; this module only chooses the Node implementation.
|
|
8
|
+
*
|
|
9
|
+
* @since 4.0.0
|
|
3
10
|
*/
|
|
4
11
|
import * as NodeFileSystem from "@effect/platform-node-shared/NodeFileSystem"
|
|
5
12
|
import type { FileSystem } from "effect/FileSystem"
|
|
6
13
|
import type * as Layer from "effect/Layer"
|
|
7
14
|
|
|
8
15
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
16
|
+
* Provides the `FileSystem` service backed by Node filesystem APIs.
|
|
17
|
+
*
|
|
18
|
+
* @category layers
|
|
19
|
+
* @since 4.0.0
|
|
11
20
|
*/
|
|
12
21
|
export const layer: Layer.Layer<FileSystem> = NodeFileSystem.layer
|
package/src/NodeHttpClient.ts
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Node.js implementations of the Effect `HttpClient`.
|
|
3
|
+
*
|
|
4
|
+
* This module supplies Node runtime backends for the platform-independent
|
|
5
|
+
* Effect HTTP client API. It re-exports the fetch-based `Fetch`, `RequestInit`,
|
|
6
|
+
* and `layerFetch` APIs, defines an Undici-backed client with dispatcher
|
|
7
|
+
* services and request options, and defines a lower-level `node:http` /
|
|
8
|
+
* `node:https` client with scoped HTTP agent layers.
|
|
9
|
+
*
|
|
10
|
+
* @since 4.0.0
|
|
3
11
|
*/
|
|
12
|
+
import * as Context from "effect/Context"
|
|
4
13
|
import * as Effect from "effect/Effect"
|
|
5
14
|
import { flow } from "effect/Function"
|
|
6
15
|
import * as Inspectable from "effect/Inspectable"
|
|
7
16
|
import * as Layer from "effect/Layer"
|
|
17
|
+
import * as Option from "effect/Option"
|
|
18
|
+
import { type Pipeable, pipeArguments } from "effect/Pipeable"
|
|
19
|
+
import type * as Schema from "effect/Schema"
|
|
8
20
|
import type * as Scope from "effect/Scope"
|
|
9
|
-
import * as ServiceMap from "effect/ServiceMap"
|
|
10
21
|
import * as Stream from "effect/Stream"
|
|
11
22
|
import * as Cookies from "effect/unstable/http/Cookies"
|
|
12
23
|
import * as Headers from "effect/unstable/http/Headers"
|
|
@@ -33,18 +44,33 @@ import * as Undici from "./Undici.ts"
|
|
|
33
44
|
|
|
34
45
|
export {
|
|
35
46
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
47
|
+
* Provides a fetch-based HTTP client implementation for Node.js.
|
|
48
|
+
*
|
|
49
|
+
* **When to use**
|
|
50
|
+
*
|
|
51
|
+
* Use to access or override the fetch implementation used by the Node
|
|
52
|
+
* fetch-based HTTP client.
|
|
53
|
+
*
|
|
54
|
+
* @category fetch
|
|
55
|
+
* @since 4.0.0
|
|
38
56
|
*/
|
|
39
57
|
Fetch,
|
|
40
58
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
59
|
+
* Layer that provides the fetch-based HTTP client implementation.
|
|
60
|
+
*
|
|
61
|
+
* @category fetch
|
|
62
|
+
* @since 4.0.0
|
|
43
63
|
*/
|
|
44
64
|
layer as layerFetch,
|
|
45
65
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
66
|
+
* Provides request initialization options accepted by the fetch-based HTTP client.
|
|
67
|
+
*
|
|
68
|
+
* **When to use**
|
|
69
|
+
*
|
|
70
|
+
* Use to provide default fetch request options for Node HTTP requests.
|
|
71
|
+
*
|
|
72
|
+
* @category fetch
|
|
73
|
+
* @since 4.0.0
|
|
48
74
|
*/
|
|
49
75
|
RequestInit
|
|
50
76
|
} from "effect/unstable/http/FetchHttpClient"
|
|
@@ -54,16 +80,22 @@ export {
|
|
|
54
80
|
// -----------------------------------------------------------------------------
|
|
55
81
|
|
|
56
82
|
/**
|
|
57
|
-
*
|
|
83
|
+
* Service tag for the Undici `Dispatcher` used by the Undici-backed HTTP
|
|
84
|
+
* client.
|
|
85
|
+
*
|
|
58
86
|
* @category Dispatcher
|
|
87
|
+
* @since 4.0.0
|
|
59
88
|
*/
|
|
60
|
-
export class Dispatcher extends
|
|
89
|
+
export class Dispatcher extends Context.Service<Dispatcher, Undici.Dispatcher>()(
|
|
61
90
|
"@effect/platform-node/NodeHttpClient/Dispatcher"
|
|
62
91
|
) {}
|
|
63
92
|
|
|
64
93
|
/**
|
|
65
|
-
*
|
|
94
|
+
* Acquires a new Undici `Agent` dispatcher and destroys it when the enclosing
|
|
95
|
+
* scope is finalized.
|
|
96
|
+
*
|
|
66
97
|
* @category Dispatcher
|
|
98
|
+
* @since 4.0.0
|
|
67
99
|
*/
|
|
68
100
|
export const makeDispatcher: Effect.Effect<Undici.Dispatcher, never, Scope.Scope> = Effect.acquireRelease(
|
|
69
101
|
Effect.sync(() => new Undici.Agent()),
|
|
@@ -71,29 +103,41 @@ export const makeDispatcher: Effect.Effect<Undici.Dispatcher, never, Scope.Scope
|
|
|
71
103
|
)
|
|
72
104
|
|
|
73
105
|
/**
|
|
74
|
-
*
|
|
106
|
+
* Provides the `Dispatcher` service using a scoped Undici `Agent`.
|
|
107
|
+
*
|
|
75
108
|
* @category Dispatcher
|
|
109
|
+
* @since 4.0.0
|
|
76
110
|
*/
|
|
77
111
|
export const layerDispatcher: Layer.Layer<Dispatcher> = Layer.effect(Dispatcher)(makeDispatcher)
|
|
78
112
|
|
|
79
113
|
/**
|
|
80
|
-
*
|
|
114
|
+
* Provides the `Dispatcher` service from Undici's process-global dispatcher,
|
|
115
|
+
* without creating or owning a new agent.
|
|
116
|
+
*
|
|
81
117
|
* @category Dispatcher
|
|
118
|
+
* @since 4.0.0
|
|
82
119
|
*/
|
|
83
120
|
export const dispatcherLayerGlobal: Layer.Layer<Dispatcher> = Layer.sync(Dispatcher)(() => Undici.getGlobalDispatcher())
|
|
84
121
|
|
|
85
122
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
123
|
+
* Fiber reference containing default Undici request options applied to requests
|
|
124
|
+
* sent by `makeUndici`.
|
|
125
|
+
*
|
|
126
|
+
* @category Undici
|
|
127
|
+
* @since 4.0.0
|
|
88
128
|
*/
|
|
89
|
-
export const UndiciOptions =
|
|
129
|
+
export const UndiciOptions = Context.Reference<Partial<Undici.Dispatcher.RequestOptions>>(
|
|
90
130
|
"@effect/platform-node/NodeHttpClient/UndiciOptions",
|
|
91
131
|
{ defaultValue: () => ({}) }
|
|
92
132
|
)
|
|
93
133
|
|
|
94
134
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
135
|
+
* Creates an `HttpClient` that sends requests through the current Undici
|
|
136
|
+
* `Dispatcher`, converts Effect HTTP bodies to Undici bodies, and maps
|
|
137
|
+
* transport and decode failures to `HttpClientError`.
|
|
138
|
+
*
|
|
139
|
+
* @category Undici
|
|
140
|
+
* @since 4.0.0
|
|
97
141
|
*/
|
|
98
142
|
export const makeUndici = Effect.gen(function*() {
|
|
99
143
|
const dispatcher = yield* Dispatcher
|
|
@@ -150,7 +194,7 @@ function convertBody(
|
|
|
150
194
|
|
|
151
195
|
function noopErrorHandler(_: any) {}
|
|
152
196
|
|
|
153
|
-
class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
197
|
+
class UndiciResponse extends Inspectable.Class implements HttpClientResponse, Pipeable {
|
|
154
198
|
readonly [IncomingMessage.TypeId]: typeof IncomingMessage.TypeId
|
|
155
199
|
readonly [Response.TypeId]: typeof Response.TypeId
|
|
156
200
|
readonly request: HttpClientRequest
|
|
@@ -189,8 +233,8 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
189
233
|
return this.cachedCookies = header ? Cookies.fromSetCookie(header) : Cookies.empty
|
|
190
234
|
}
|
|
191
235
|
|
|
192
|
-
get remoteAddress(): string
|
|
193
|
-
return
|
|
236
|
+
get remoteAddress(): Option.Option<string> {
|
|
237
|
+
return Option.none()
|
|
194
238
|
}
|
|
195
239
|
|
|
196
240
|
get stream(): Stream.Stream<Uint8Array, Error.HttpClientError> {
|
|
@@ -207,10 +251,10 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
207
251
|
})
|
|
208
252
|
}
|
|
209
253
|
|
|
210
|
-
get json(): Effect.Effect<
|
|
254
|
+
get json(): Effect.Effect<Schema.Json, Error.HttpClientError> {
|
|
211
255
|
return Effect.flatMap(this.text, (text) =>
|
|
212
256
|
Effect.try({
|
|
213
|
-
try: () => text === "" ? null : JSON.parse(text)
|
|
257
|
+
try: () => text === "" ? null : JSON.parse(text),
|
|
214
258
|
catch: (cause) =>
|
|
215
259
|
new Error.HttpClientError({
|
|
216
260
|
reason: new Error.DecodeError({
|
|
@@ -224,7 +268,10 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
224
268
|
|
|
225
269
|
private textBody?: Effect.Effect<string, Error.HttpClientError>
|
|
226
270
|
get text(): Effect.Effect<string, Error.HttpClientError> {
|
|
227
|
-
|
|
271
|
+
if (this.textBody) {
|
|
272
|
+
return this.textBody
|
|
273
|
+
}
|
|
274
|
+
this.textBody = Effect.tryPromise({
|
|
228
275
|
try: () => this.source.body.text(),
|
|
229
276
|
catch: (cause) =>
|
|
230
277
|
new Error.HttpClientError({
|
|
@@ -235,6 +282,8 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
235
282
|
})
|
|
236
283
|
})
|
|
237
284
|
}).pipe(Effect.cached, Effect.runSync)
|
|
285
|
+
this.arrayBufferBody = Effect.map(this.textBody, (_) => new TextEncoder().encode(_).buffer)
|
|
286
|
+
return this.textBody
|
|
238
287
|
}
|
|
239
288
|
|
|
240
289
|
get urlParamsBody(): Effect.Effect<UrlParams.UrlParams, Error.HttpClientError> {
|
|
@@ -269,7 +318,10 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
269
318
|
|
|
270
319
|
private arrayBufferBody?: Effect.Effect<ArrayBuffer, Error.HttpClientError>
|
|
271
320
|
get arrayBuffer(): Effect.Effect<ArrayBuffer, Error.HttpClientError> {
|
|
272
|
-
|
|
321
|
+
if (this.arrayBufferBody) {
|
|
322
|
+
return this.arrayBufferBody
|
|
323
|
+
}
|
|
324
|
+
this.arrayBufferBody = Effect.tryPromise({
|
|
273
325
|
try: () => this.source.body.arrayBuffer(),
|
|
274
326
|
catch: (cause) =>
|
|
275
327
|
new Error.HttpClientError({
|
|
@@ -280,6 +332,8 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
280
332
|
})
|
|
281
333
|
})
|
|
282
334
|
}).pipe(Effect.cached, Effect.runSync)
|
|
335
|
+
this.textBody = Effect.map(this.arrayBufferBody, (_) => new TextDecoder().decode(_))
|
|
336
|
+
return this.arrayBufferBody
|
|
283
337
|
}
|
|
284
338
|
|
|
285
339
|
toJSON(): unknown {
|
|
@@ -289,21 +343,31 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
289
343
|
status: this.status
|
|
290
344
|
})
|
|
291
345
|
}
|
|
346
|
+
|
|
347
|
+
pipe() {
|
|
348
|
+
return pipeArguments(this, arguments)
|
|
349
|
+
}
|
|
292
350
|
}
|
|
293
351
|
|
|
294
352
|
/**
|
|
295
|
-
*
|
|
353
|
+
* Provides an Undici-backed `HttpClient` using the current `Dispatcher`
|
|
354
|
+
* service.
|
|
355
|
+
*
|
|
296
356
|
* @category Undici
|
|
357
|
+
* @since 4.0.0
|
|
297
358
|
*/
|
|
298
359
|
export const layerUndiciNoDispatcher: Layer.Layer<
|
|
299
360
|
Client.HttpClient,
|
|
300
361
|
never,
|
|
301
362
|
Dispatcher
|
|
302
|
-
> = Client.
|
|
363
|
+
> = Client.layerMergedContext(makeUndici)
|
|
303
364
|
|
|
304
365
|
/**
|
|
305
|
-
*
|
|
366
|
+
* Provides an Undici-backed `HttpClient` together with a scoped default
|
|
367
|
+
* Undici `Agent` dispatcher.
|
|
368
|
+
*
|
|
306
369
|
* @category Undici
|
|
370
|
+
* @since 4.0.0
|
|
307
371
|
*/
|
|
308
372
|
export const layerUndici: Layer.Layer<Client.HttpClient> = Layer.provide(layerUndiciNoDispatcher, layerDispatcher)
|
|
309
373
|
|
|
@@ -312,17 +376,23 @@ export const layerUndici: Layer.Layer<Client.HttpClient> = Layer.provide(layerUn
|
|
|
312
376
|
// -----------------------------------------------------------------------------
|
|
313
377
|
|
|
314
378
|
/**
|
|
315
|
-
*
|
|
379
|
+
* Service tag for the paired Node `http` and `https` agents used by the
|
|
380
|
+
* node:http-backed HTTP client.
|
|
381
|
+
*
|
|
316
382
|
* @category HttpAgent
|
|
383
|
+
* @since 4.0.0
|
|
317
384
|
*/
|
|
318
|
-
export class HttpAgent extends
|
|
385
|
+
export class HttpAgent extends Context.Service<HttpAgent, {
|
|
319
386
|
readonly http: Http.Agent
|
|
320
387
|
readonly https: Https.Agent
|
|
321
388
|
}>()("@effect/platform-node/NodeHttpClient/HttpAgent") {}
|
|
322
389
|
|
|
323
390
|
/**
|
|
324
|
-
*
|
|
391
|
+
* Acquires Node `http` and `https` agents with the supplied options and
|
|
392
|
+
* destroys both agents when the enclosing scope is finalized.
|
|
393
|
+
*
|
|
325
394
|
* @category HttpAgent
|
|
395
|
+
* @since 4.0.0
|
|
326
396
|
*/
|
|
327
397
|
export const makeAgent = (options?: Https.AgentOptions): Effect.Effect<HttpAgent["Service"], never, Scope.Scope> =>
|
|
328
398
|
Effect.zipWith(
|
|
@@ -338,22 +408,32 @@ export const makeAgent = (options?: Https.AgentOptions): Effect.Effect<HttpAgent
|
|
|
338
408
|
)
|
|
339
409
|
|
|
340
410
|
/**
|
|
341
|
-
*
|
|
411
|
+
* Provides the `HttpAgent` service using scoped Node `http` and `https`
|
|
412
|
+
* agents configured with the supplied options.
|
|
413
|
+
*
|
|
342
414
|
* @category HttpAgent
|
|
415
|
+
* @since 4.0.0
|
|
343
416
|
*/
|
|
344
417
|
export const layerAgentOptions: (options?: Https.AgentOptions | undefined) => Layer.Layer<
|
|
345
418
|
HttpAgent
|
|
346
419
|
> = flow(makeAgent, Layer.effect(HttpAgent))
|
|
347
420
|
|
|
348
421
|
/**
|
|
349
|
-
*
|
|
422
|
+
* Provides the `HttpAgent` service using default scoped Node `http` and
|
|
423
|
+
* `https` agents.
|
|
424
|
+
*
|
|
350
425
|
* @category HttpAgent
|
|
426
|
+
* @since 4.0.0
|
|
351
427
|
*/
|
|
352
428
|
export const layerAgent: Layer.Layer<HttpAgent> = layerAgentOptions()
|
|
353
429
|
|
|
354
430
|
/**
|
|
355
|
-
*
|
|
431
|
+
* Creates an `HttpClient` backed by Node `http` and `https`, using the
|
|
432
|
+
* current `HttpAgent`, streaming request bodies, and wrapping Node responses
|
|
433
|
+
* as `HttpClientResponse` values.
|
|
434
|
+
*
|
|
356
435
|
* @category node:http
|
|
436
|
+
* @since 4.0.0
|
|
357
437
|
*/
|
|
358
438
|
export const makeNodeHttp = Effect.gen(function*() {
|
|
359
439
|
const agent = yield* HttpAgent
|
|
@@ -490,7 +570,7 @@ const waitForFinish = (nodeRequest: Http.ClientRequest, request: HttpClientReque
|
|
|
490
570
|
})
|
|
491
571
|
})
|
|
492
572
|
|
|
493
|
-
class NodeHttpResponse extends NodeHttpIncomingMessage<Error.HttpClientError> implements HttpClientResponse {
|
|
573
|
+
class NodeHttpResponse extends NodeHttpIncomingMessage<Error.HttpClientError> implements HttpClientResponse, Pipeable {
|
|
494
574
|
readonly [Response.TypeId]: typeof Response.TypeId
|
|
495
575
|
readonly request: HttpClientRequest
|
|
496
576
|
|
|
@@ -555,20 +635,30 @@ class NodeHttpResponse extends NodeHttpIncomingMessage<Error.HttpClientError> im
|
|
|
555
635
|
status: this.status
|
|
556
636
|
})
|
|
557
637
|
}
|
|
638
|
+
|
|
639
|
+
pipe() {
|
|
640
|
+
return pipeArguments(this, arguments)
|
|
641
|
+
}
|
|
558
642
|
}
|
|
559
643
|
|
|
560
644
|
/**
|
|
561
|
-
*
|
|
645
|
+
* Provides a node:http-backed `HttpClient` using the current `HttpAgent`
|
|
646
|
+
* service.
|
|
647
|
+
*
|
|
562
648
|
* @category node:http
|
|
649
|
+
* @since 4.0.0
|
|
563
650
|
*/
|
|
564
651
|
export const layerNodeHttpNoAgent: Layer.Layer<
|
|
565
652
|
Client.HttpClient,
|
|
566
653
|
never,
|
|
567
654
|
HttpAgent
|
|
568
|
-
> = Client.
|
|
655
|
+
> = Client.layerMergedContext(makeNodeHttp)
|
|
569
656
|
|
|
570
657
|
/**
|
|
571
|
-
*
|
|
658
|
+
* Provides a node:http-backed `HttpClient` together with default scoped Node
|
|
659
|
+
* `http` and `https` agents.
|
|
660
|
+
*
|
|
572
661
|
* @category node:http
|
|
662
|
+
* @since 4.0.0
|
|
573
663
|
*/
|
|
574
664
|
export const layerNodeHttp: Layer.Layer<Client.HttpClient> = Layer.provide(layerNodeHttpNoAgent, layerAgent)
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Adapter base for exposing Node `http.IncomingMessage` values as Effect HTTP
|
|
3
|
+
* incoming messages.
|
|
4
|
+
*
|
|
5
|
+
* Server requests and Node client responses both arrive as Node readable
|
|
6
|
+
* streams with raw header objects, socket metadata, and one-shot body
|
|
7
|
+
* consumption. This module's `NodeHttpIncomingMessage` class keeps the original
|
|
8
|
+
* Node message available while presenting Effect's `HttpIncomingMessage` shape:
|
|
9
|
+
* typed headers, remote address lookup, stream access, and text, JSON,
|
|
10
|
+
* URL-encoded, and array-buffer body readers.
|
|
11
|
+
*
|
|
12
|
+
* @since 4.0.0
|
|
3
13
|
*/
|
|
4
14
|
import * as Effect from "effect/Effect"
|
|
5
15
|
import * as Inspectable from "effect/Inspectable"
|
|
16
|
+
import * as Option from "effect/Option"
|
|
17
|
+
import type * as Schema from "effect/Schema"
|
|
6
18
|
import type * as Stream from "effect/Stream"
|
|
7
19
|
import * as Headers from "effect/unstable/http/Headers"
|
|
8
20
|
import * as IncomingMessage from "effect/unstable/http/HttpIncomingMessage"
|
|
@@ -11,24 +23,38 @@ import type * as Http from "node:http"
|
|
|
11
23
|
import * as NodeStream from "./NodeStream.ts"
|
|
12
24
|
|
|
13
25
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
26
|
+
* Adapts a Node `IncomingMessage` to Effect HTTP incoming messages.
|
|
27
|
+
*
|
|
28
|
+
* **When to use**
|
|
29
|
+
*
|
|
30
|
+
* Use to implement Node HTTP request or response adapters that expose the
|
|
31
|
+
* Effect HTTP incoming-message interface.
|
|
32
|
+
*
|
|
33
|
+
* **Details**
|
|
34
|
+
*
|
|
35
|
+
* The adapter exposes headers, remote address, stream access, and cached body
|
|
36
|
+
* decoders. Subclasses provide the error mapping for unknown Node errors.
|
|
37
|
+
*
|
|
38
|
+
* @category constructors
|
|
39
|
+
* @since 4.0.0
|
|
16
40
|
*/
|
|
17
41
|
export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
18
42
|
implements IncomingMessage.HttpIncomingMessage<E>
|
|
19
43
|
{
|
|
20
44
|
/**
|
|
21
|
-
*
|
|
45
|
+
* Marks this value as an HTTP incoming message for runtime guards.
|
|
46
|
+
*
|
|
47
|
+
* @since 4.0.0
|
|
22
48
|
*/
|
|
23
49
|
readonly [IncomingMessage.TypeId]: typeof IncomingMessage.TypeId
|
|
24
50
|
readonly source: Http.IncomingMessage
|
|
25
51
|
readonly onError: (error: unknown) => E
|
|
26
|
-
readonly remoteAddressOverride?: string | undefined
|
|
52
|
+
readonly remoteAddressOverride?: Option.Option<string> | undefined
|
|
27
53
|
|
|
28
54
|
constructor(
|
|
29
55
|
source: Http.IncomingMessage,
|
|
30
56
|
onError: (error: unknown) => E,
|
|
31
|
-
remoteAddressOverride?: string
|
|
57
|
+
remoteAddressOverride?: Option.Option<string>
|
|
32
58
|
) {
|
|
33
59
|
super()
|
|
34
60
|
this[IncomingMessage.TypeId] = IncomingMessage.TypeId
|
|
@@ -42,7 +68,7 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
42
68
|
}
|
|
43
69
|
|
|
44
70
|
get remoteAddress() {
|
|
45
|
-
return this.remoteAddressOverride ?? this.source.socket.remoteAddress
|
|
71
|
+
return this.remoteAddressOverride ?? Option.fromNullishOr(this.source.socket.remoteAddress)
|
|
46
72
|
}
|
|
47
73
|
|
|
48
74
|
private textEffect: Effect.Effect<string, E> | undefined
|
|
@@ -52,7 +78,7 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
52
78
|
}
|
|
53
79
|
this.textEffect = Effect.runSync(Effect.cached(
|
|
54
80
|
Effect.flatMap(
|
|
55
|
-
IncomingMessage.MaxBodySize
|
|
81
|
+
IncomingMessage.MaxBodySize,
|
|
56
82
|
(maxBodySize) =>
|
|
57
83
|
NodeStream.toString(() => this.source, {
|
|
58
84
|
onError: this.onError,
|
|
@@ -60,6 +86,7 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
60
86
|
})
|
|
61
87
|
)
|
|
62
88
|
))
|
|
89
|
+
this.arrayBufferEffect = Effect.map(this.textEffect, (_) => new TextEncoder().encode(_).buffer)
|
|
63
90
|
return this.textEffect
|
|
64
91
|
}
|
|
65
92
|
|
|
@@ -67,15 +94,15 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
67
94
|
return Effect.runSync(this.text)
|
|
68
95
|
}
|
|
69
96
|
|
|
70
|
-
get json(): Effect.Effect<
|
|
97
|
+
get json(): Effect.Effect<Schema.Json, E> {
|
|
71
98
|
return Effect.flatMap(this.text, (text) =>
|
|
72
99
|
Effect.try({
|
|
73
|
-
try: () => text === "" ? null : JSON.parse(text)
|
|
100
|
+
try: () => text === "" ? null : JSON.parse(text),
|
|
74
101
|
catch: this.onError
|
|
75
102
|
}))
|
|
76
103
|
}
|
|
77
104
|
|
|
78
|
-
get jsonUnsafe():
|
|
105
|
+
get jsonUnsafe(): Schema.Json {
|
|
79
106
|
return Effect.runSync(this.json)
|
|
80
107
|
}
|
|
81
108
|
|
|
@@ -94,12 +121,21 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
94
121
|
})
|
|
95
122
|
}
|
|
96
123
|
|
|
124
|
+
private arrayBufferEffect: Effect.Effect<ArrayBuffer, E> | undefined
|
|
97
125
|
get arrayBuffer(): Effect.Effect<ArrayBuffer, E> {
|
|
98
|
-
|
|
126
|
+
if (this.arrayBufferEffect) {
|
|
127
|
+
return this.arrayBufferEffect
|
|
128
|
+
}
|
|
129
|
+
this.arrayBufferEffect = Effect.withFiber((fiber) =>
|
|
99
130
|
NodeStream.toArrayBuffer(() => this.source, {
|
|
100
131
|
onError: this.onError,
|
|
101
132
|
maxBytes: fiber.getRef(IncomingMessage.MaxBodySize)
|
|
102
133
|
})
|
|
134
|
+
).pipe(
|
|
135
|
+
Effect.cached,
|
|
136
|
+
Effect.runSync
|
|
103
137
|
)
|
|
138
|
+
this.textEffect = Effect.map(this.arrayBufferEffect, (_) => new TextDecoder().decode(_))
|
|
139
|
+
return this.arrayBufferEffect
|
|
104
140
|
}
|
|
105
141
|
}
|
package/src/NodeHttpPlatform.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Node.js implementation of the Effect HTTP platform service.
|
|
3
|
+
*
|
|
4
|
+
* This module connects the portable `HttpPlatform` file response helpers to
|
|
5
|
+
* Node runtime primitives. It serves local files through Node readable streams,
|
|
6
|
+
* supports byte ranges, converts Web `File` values to readable streams, and
|
|
7
|
+
* fills in content type and content length headers when needed.
|
|
8
|
+
*
|
|
9
|
+
* @since 4.0.0
|
|
3
10
|
*/
|
|
4
11
|
import { pipe } from "effect/Function"
|
|
5
12
|
import * as Layer from "effect/Layer"
|
|
@@ -13,12 +20,17 @@ import Mime from "./Mime.ts"
|
|
|
13
20
|
import * as NodeFileSystem from "./NodeFileSystem.ts"
|
|
14
21
|
|
|
15
22
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
23
|
+
* Creates the Node `HttpPlatform`, serving file responses from Node readable
|
|
24
|
+
* streams and adding MIME type and content-length headers when needed.
|
|
25
|
+
*
|
|
26
|
+
* @category constructors
|
|
27
|
+
* @since 4.0.0
|
|
18
28
|
*/
|
|
19
29
|
export const make = Platform.make({
|
|
20
30
|
fileResponse(path, status, statusText, headers, start, end, contentLength) {
|
|
21
|
-
const stream =
|
|
31
|
+
const stream = contentLength === 0
|
|
32
|
+
? Readable.from([])
|
|
33
|
+
: Fs.createReadStream(path, { start, end: end === undefined ? undefined : end - 1 })
|
|
22
34
|
return ServerResponse.raw(stream, {
|
|
23
35
|
headers: {
|
|
24
36
|
...headers,
|
|
@@ -45,8 +57,11 @@ export const make = Platform.make({
|
|
|
45
57
|
})
|
|
46
58
|
|
|
47
59
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
60
|
+
* Provides the Node `HttpPlatform` together with the filesystem and ETag
|
|
61
|
+
* services it needs for file responses.
|
|
62
|
+
*
|
|
63
|
+
* @category layers
|
|
64
|
+
* @since 4.0.0
|
|
50
65
|
*/
|
|
51
66
|
export const layer: Layer.Layer<Platform.HttpPlatform> = pipe(
|
|
52
67
|
Layer.effect(Platform.HttpPlatform)(make),
|