@effect/platform-node 4.0.0-beta.6 → 4.0.0-beta.62
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/NodeClusterHttp.d.ts.map +1 -1
- package/dist/NodeClusterHttp.js +5 -4
- package/dist/NodeClusterHttp.js.map +1 -1
- package/dist/NodeHttpClient.d.ts +4 -4
- package/dist/NodeHttpClient.d.ts.map +1 -1
- package/dist/NodeHttpClient.js +27 -9
- package/dist/NodeHttpClient.js.map +1 -1
- package/dist/NodeHttpIncomingMessage.d.ts +8 -5
- package/dist/NodeHttpIncomingMessage.d.ts.map +1 -1
- package/dist/NodeHttpIncomingMessage.js +11 -3
- package/dist/NodeHttpIncomingMessage.js.map +1 -1
- package/dist/NodeHttpPlatform.d.ts.map +1 -1
- package/dist/NodeHttpPlatform.js +2 -2
- package/dist/NodeHttpPlatform.js.map +1 -1
- package/dist/NodeHttpServer.d.ts +17 -4
- package/dist/NodeHttpServer.d.ts.map +1 -1
- package/dist/NodeHttpServer.js +47 -35
- package/dist/NodeHttpServer.js.map +1 -1
- package/dist/NodeRedis.d.ts +2 -2
- package/dist/NodeRedis.d.ts.map +1 -1
- package/dist/NodeRedis.js +5 -5
- package/dist/NodeRedis.js.map +1 -1
- package/dist/NodeRuntime.d.ts +0 -3
- package/dist/NodeRuntime.d.ts.map +1 -1
- package/dist/NodeRuntime.js +0 -1
- package/dist/NodeRuntime.js.map +1 -1
- package/dist/NodeSocket.d.ts +6 -1
- package/dist/NodeSocket.d.ts.map +1 -1
- package/dist/NodeSocket.js +5 -0
- package/dist/NodeSocket.js.map +1 -1
- package/dist/NodeWorkerRunner.js +1 -1
- package/dist/NodeWorkerRunner.js.map +1 -1
- package/package.json +9 -9
- package/src/NodeClusterHttp.ts +5 -4
- package/src/NodeHttpClient.ts +35 -14
- package/src/NodeHttpIncomingMessage.ts +19 -7
- package/src/NodeHttpPlatform.ts +3 -1
- package/src/NodeHttpServer.ts +69 -39
- package/src/NodeRedis.ts +6 -6
- package/src/NodeRuntime.ts +0 -3
- package/src/NodeSocket.ts +11 -1
- package/src/NodeWorkerRunner.ts +1 -1
package/src/NodeHttpClient.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
+
import * as Context from "effect/Context"
|
|
4
5
|
import * as Effect from "effect/Effect"
|
|
5
6
|
import { flow } from "effect/Function"
|
|
6
7
|
import * as Inspectable from "effect/Inspectable"
|
|
7
8
|
import * as Layer from "effect/Layer"
|
|
9
|
+
import * as Option from "effect/Option"
|
|
10
|
+
import { type Pipeable, pipeArguments } from "effect/Pipeable"
|
|
11
|
+
import type * as Schema from "effect/Schema"
|
|
8
12
|
import type * as Scope from "effect/Scope"
|
|
9
|
-
import * as ServiceMap from "effect/ServiceMap"
|
|
10
13
|
import * as Stream from "effect/Stream"
|
|
11
14
|
import * as Cookies from "effect/unstable/http/Cookies"
|
|
12
15
|
import * as Headers from "effect/unstable/http/Headers"
|
|
@@ -57,7 +60,7 @@ export {
|
|
|
57
60
|
* @since 1.0.0
|
|
58
61
|
* @category Dispatcher
|
|
59
62
|
*/
|
|
60
|
-
export class Dispatcher extends
|
|
63
|
+
export class Dispatcher extends Context.Service<Dispatcher, Undici.Dispatcher>()(
|
|
61
64
|
"@effect/platform-node/NodeHttpClient/Dispatcher"
|
|
62
65
|
) {}
|
|
63
66
|
|
|
@@ -86,7 +89,7 @@ export const dispatcherLayerGlobal: Layer.Layer<Dispatcher> = Layer.sync(Dispatc
|
|
|
86
89
|
* @since 1.0.0
|
|
87
90
|
* @category undici
|
|
88
91
|
*/
|
|
89
|
-
export const UndiciOptions =
|
|
92
|
+
export const UndiciOptions = Context.Reference<Partial<Undici.Dispatcher.RequestOptions>>(
|
|
90
93
|
"@effect/platform-node/NodeHttpClient/UndiciOptions",
|
|
91
94
|
{ defaultValue: () => ({}) }
|
|
92
95
|
)
|
|
@@ -150,7 +153,7 @@ function convertBody(
|
|
|
150
153
|
|
|
151
154
|
function noopErrorHandler(_: any) {}
|
|
152
155
|
|
|
153
|
-
class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
156
|
+
class UndiciResponse extends Inspectable.Class implements HttpClientResponse, Pipeable {
|
|
154
157
|
readonly [IncomingMessage.TypeId]: typeof IncomingMessage.TypeId
|
|
155
158
|
readonly [Response.TypeId]: typeof Response.TypeId
|
|
156
159
|
readonly request: HttpClientRequest
|
|
@@ -189,8 +192,8 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
189
192
|
return this.cachedCookies = header ? Cookies.fromSetCookie(header) : Cookies.empty
|
|
190
193
|
}
|
|
191
194
|
|
|
192
|
-
get remoteAddress(): string
|
|
193
|
-
return
|
|
195
|
+
get remoteAddress(): Option.Option<string> {
|
|
196
|
+
return Option.none()
|
|
194
197
|
}
|
|
195
198
|
|
|
196
199
|
get stream(): Stream.Stream<Uint8Array, Error.HttpClientError> {
|
|
@@ -207,10 +210,10 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
207
210
|
})
|
|
208
211
|
}
|
|
209
212
|
|
|
210
|
-
get json(): Effect.Effect<
|
|
213
|
+
get json(): Effect.Effect<Schema.Json, Error.HttpClientError> {
|
|
211
214
|
return Effect.flatMap(this.text, (text) =>
|
|
212
215
|
Effect.try({
|
|
213
|
-
try: () => text === "" ? null : JSON.parse(text)
|
|
216
|
+
try: () => text === "" ? null : JSON.parse(text),
|
|
214
217
|
catch: (cause) =>
|
|
215
218
|
new Error.HttpClientError({
|
|
216
219
|
reason: new Error.DecodeError({
|
|
@@ -224,7 +227,10 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
224
227
|
|
|
225
228
|
private textBody?: Effect.Effect<string, Error.HttpClientError>
|
|
226
229
|
get text(): Effect.Effect<string, Error.HttpClientError> {
|
|
227
|
-
|
|
230
|
+
if (this.textBody) {
|
|
231
|
+
return this.textBody
|
|
232
|
+
}
|
|
233
|
+
this.textBody = Effect.tryPromise({
|
|
228
234
|
try: () => this.source.body.text(),
|
|
229
235
|
catch: (cause) =>
|
|
230
236
|
new Error.HttpClientError({
|
|
@@ -235,6 +241,8 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
235
241
|
})
|
|
236
242
|
})
|
|
237
243
|
}).pipe(Effect.cached, Effect.runSync)
|
|
244
|
+
this.arrayBufferBody = Effect.map(this.textBody, (_) => new TextEncoder().encode(_).buffer)
|
|
245
|
+
return this.textBody
|
|
238
246
|
}
|
|
239
247
|
|
|
240
248
|
get urlParamsBody(): Effect.Effect<UrlParams.UrlParams, Error.HttpClientError> {
|
|
@@ -269,7 +277,10 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
269
277
|
|
|
270
278
|
private arrayBufferBody?: Effect.Effect<ArrayBuffer, Error.HttpClientError>
|
|
271
279
|
get arrayBuffer(): Effect.Effect<ArrayBuffer, Error.HttpClientError> {
|
|
272
|
-
|
|
280
|
+
if (this.arrayBufferBody) {
|
|
281
|
+
return this.arrayBufferBody
|
|
282
|
+
}
|
|
283
|
+
this.arrayBufferBody = Effect.tryPromise({
|
|
273
284
|
try: () => this.source.body.arrayBuffer(),
|
|
274
285
|
catch: (cause) =>
|
|
275
286
|
new Error.HttpClientError({
|
|
@@ -280,6 +291,8 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
280
291
|
})
|
|
281
292
|
})
|
|
282
293
|
}).pipe(Effect.cached, Effect.runSync)
|
|
294
|
+
this.textBody = Effect.map(this.arrayBufferBody, (_) => new TextDecoder().decode(_))
|
|
295
|
+
return this.arrayBufferBody
|
|
283
296
|
}
|
|
284
297
|
|
|
285
298
|
toJSON(): unknown {
|
|
@@ -289,6 +302,10 @@ class UndiciResponse extends Inspectable.Class implements HttpClientResponse {
|
|
|
289
302
|
status: this.status
|
|
290
303
|
})
|
|
291
304
|
}
|
|
305
|
+
|
|
306
|
+
pipe() {
|
|
307
|
+
return pipeArguments(this, arguments)
|
|
308
|
+
}
|
|
292
309
|
}
|
|
293
310
|
|
|
294
311
|
/**
|
|
@@ -299,7 +316,7 @@ export const layerUndiciNoDispatcher: Layer.Layer<
|
|
|
299
316
|
Client.HttpClient,
|
|
300
317
|
never,
|
|
301
318
|
Dispatcher
|
|
302
|
-
> = Client.
|
|
319
|
+
> = Client.layerMergedContext(makeUndici)
|
|
303
320
|
|
|
304
321
|
/**
|
|
305
322
|
* @since 1.0.0
|
|
@@ -315,7 +332,7 @@ export const layerUndici: Layer.Layer<Client.HttpClient> = Layer.provide(layerUn
|
|
|
315
332
|
* @since 1.0.0
|
|
316
333
|
* @category HttpAgent
|
|
317
334
|
*/
|
|
318
|
-
export class HttpAgent extends
|
|
335
|
+
export class HttpAgent extends Context.Service<HttpAgent, {
|
|
319
336
|
readonly http: Http.Agent
|
|
320
337
|
readonly https: Https.Agent
|
|
321
338
|
}>()("@effect/platform-node/NodeHttpClient/HttpAgent") {}
|
|
@@ -490,7 +507,7 @@ const waitForFinish = (nodeRequest: Http.ClientRequest, request: HttpClientReque
|
|
|
490
507
|
})
|
|
491
508
|
})
|
|
492
509
|
|
|
493
|
-
class NodeHttpResponse extends NodeHttpIncomingMessage<Error.HttpClientError> implements HttpClientResponse {
|
|
510
|
+
class NodeHttpResponse extends NodeHttpIncomingMessage<Error.HttpClientError> implements HttpClientResponse, Pipeable {
|
|
494
511
|
readonly [Response.TypeId]: typeof Response.TypeId
|
|
495
512
|
readonly request: HttpClientRequest
|
|
496
513
|
|
|
@@ -555,6 +572,10 @@ class NodeHttpResponse extends NodeHttpIncomingMessage<Error.HttpClientError> im
|
|
|
555
572
|
status: this.status
|
|
556
573
|
})
|
|
557
574
|
}
|
|
575
|
+
|
|
576
|
+
pipe() {
|
|
577
|
+
return pipeArguments(this, arguments)
|
|
578
|
+
}
|
|
558
579
|
}
|
|
559
580
|
|
|
560
581
|
/**
|
|
@@ -565,7 +586,7 @@ export const layerNodeHttpNoAgent: Layer.Layer<
|
|
|
565
586
|
Client.HttpClient,
|
|
566
587
|
never,
|
|
567
588
|
HttpAgent
|
|
568
|
-
> = Client.
|
|
589
|
+
> = Client.layerMergedContext(makeNodeHttp)
|
|
569
590
|
|
|
570
591
|
/**
|
|
571
592
|
* @since 1.0.0
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import * as Effect from "effect/Effect"
|
|
5
5
|
import * as Inspectable from "effect/Inspectable"
|
|
6
|
+
import * as Option from "effect/Option"
|
|
7
|
+
import type * as Schema from "effect/Schema"
|
|
6
8
|
import type * as Stream from "effect/Stream"
|
|
7
9
|
import * as Headers from "effect/unstable/http/Headers"
|
|
8
10
|
import * as IncomingMessage from "effect/unstable/http/HttpIncomingMessage"
|
|
@@ -23,12 +25,12 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
23
25
|
readonly [IncomingMessage.TypeId]: typeof IncomingMessage.TypeId
|
|
24
26
|
readonly source: Http.IncomingMessage
|
|
25
27
|
readonly onError: (error: unknown) => E
|
|
26
|
-
readonly remoteAddressOverride?: string | undefined
|
|
28
|
+
readonly remoteAddressOverride?: Option.Option<string> | undefined
|
|
27
29
|
|
|
28
30
|
constructor(
|
|
29
31
|
source: Http.IncomingMessage,
|
|
30
32
|
onError: (error: unknown) => E,
|
|
31
|
-
remoteAddressOverride?: string
|
|
33
|
+
remoteAddressOverride?: Option.Option<string>
|
|
32
34
|
) {
|
|
33
35
|
super()
|
|
34
36
|
this[IncomingMessage.TypeId] = IncomingMessage.TypeId
|
|
@@ -42,7 +44,7 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
get remoteAddress() {
|
|
45
|
-
return this.remoteAddressOverride ?? this.source.socket.remoteAddress
|
|
47
|
+
return this.remoteAddressOverride ?? Option.fromNullishOr(this.source.socket.remoteAddress)
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
private textEffect: Effect.Effect<string, E> | undefined
|
|
@@ -60,6 +62,7 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
60
62
|
})
|
|
61
63
|
)
|
|
62
64
|
))
|
|
65
|
+
this.arrayBufferEffect = Effect.map(this.textEffect, (_) => new TextEncoder().encode(_).buffer)
|
|
63
66
|
return this.textEffect
|
|
64
67
|
}
|
|
65
68
|
|
|
@@ -67,15 +70,15 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
67
70
|
return Effect.runSync(this.text)
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
get json(): Effect.Effect<
|
|
73
|
+
get json(): Effect.Effect<Schema.Json, E> {
|
|
71
74
|
return Effect.flatMap(this.text, (text) =>
|
|
72
75
|
Effect.try({
|
|
73
|
-
try: () => text === "" ? null : JSON.parse(text)
|
|
76
|
+
try: () => text === "" ? null : JSON.parse(text),
|
|
74
77
|
catch: this.onError
|
|
75
78
|
}))
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
get jsonUnsafe():
|
|
81
|
+
get jsonUnsafe(): Schema.Json {
|
|
79
82
|
return Effect.runSync(this.json)
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -94,12 +97,21 @@ export abstract class NodeHttpIncomingMessage<E> extends Inspectable.Class
|
|
|
94
97
|
})
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
private arrayBufferEffect: Effect.Effect<ArrayBuffer, E> | undefined
|
|
97
101
|
get arrayBuffer(): Effect.Effect<ArrayBuffer, E> {
|
|
98
|
-
|
|
102
|
+
if (this.arrayBufferEffect) {
|
|
103
|
+
return this.arrayBufferEffect
|
|
104
|
+
}
|
|
105
|
+
this.arrayBufferEffect = Effect.withFiber((fiber) =>
|
|
99
106
|
NodeStream.toArrayBuffer(() => this.source, {
|
|
100
107
|
onError: this.onError,
|
|
101
108
|
maxBytes: fiber.getRef(IncomingMessage.MaxBodySize)
|
|
102
109
|
})
|
|
110
|
+
).pipe(
|
|
111
|
+
Effect.cached,
|
|
112
|
+
Effect.runSync
|
|
103
113
|
)
|
|
114
|
+
this.textEffect = Effect.map(this.arrayBufferEffect, (_) => new TextDecoder().decode(_))
|
|
115
|
+
return this.arrayBufferEffect
|
|
104
116
|
}
|
|
105
117
|
}
|
package/src/NodeHttpPlatform.ts
CHANGED
|
@@ -18,7 +18,9 @@ import * as NodeFileSystem from "./NodeFileSystem.ts"
|
|
|
18
18
|
*/
|
|
19
19
|
export const make = Platform.make({
|
|
20
20
|
fileResponse(path, status, statusText, headers, start, end, contentLength) {
|
|
21
|
-
const stream =
|
|
21
|
+
const stream = contentLength === 0
|
|
22
|
+
? Readable.from([])
|
|
23
|
+
: Fs.createReadStream(path, { start, end: end === undefined ? undefined : end - 1 })
|
|
22
24
|
return ServerResponse.raw(stream, {
|
|
23
25
|
headers: {
|
|
24
26
|
...headers,
|
package/src/NodeHttpServer.ts
CHANGED
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import * as Cause from "effect/Cause"
|
|
5
5
|
import * as Config from "effect/Config"
|
|
6
|
+
import * as Context from "effect/Context"
|
|
7
|
+
import * as Duration from "effect/Duration"
|
|
6
8
|
import * as Effect from "effect/Effect"
|
|
7
9
|
import * as Fiber from "effect/Fiber"
|
|
8
10
|
import type * as FileSystem from "effect/FileSystem"
|
|
9
11
|
import { flow, type LazyArg } from "effect/Function"
|
|
10
12
|
import * as Latch from "effect/Latch"
|
|
11
13
|
import * as Layer from "effect/Layer"
|
|
14
|
+
import type * as Option from "effect/Option"
|
|
12
15
|
import type * as Path from "effect/Path"
|
|
13
16
|
import type * as Record from "effect/Record"
|
|
14
17
|
import * as Scope from "effect/Scope"
|
|
15
|
-
import * as ServiceMap from "effect/ServiceMap"
|
|
16
18
|
import * as Stream from "effect/Stream"
|
|
17
19
|
import * as Cookies from "effect/unstable/http/Cookies"
|
|
18
20
|
import * as Etag from "effect/unstable/http/Etag"
|
|
@@ -27,7 +29,7 @@ import type * as HttpPlatform from "effect/unstable/http/HttpPlatform"
|
|
|
27
29
|
import * as HttpServer from "effect/unstable/http/HttpServer"
|
|
28
30
|
import {
|
|
29
31
|
causeResponse,
|
|
30
|
-
|
|
32
|
+
ClientAbort,
|
|
31
33
|
HttpServerError,
|
|
32
34
|
RequestParseError,
|
|
33
35
|
ResponseError,
|
|
@@ -55,25 +57,35 @@ import { NodeWS } from "./NodeSocket.ts"
|
|
|
55
57
|
*/
|
|
56
58
|
export const make = Effect.fnUntraced(function*(
|
|
57
59
|
evaluate: LazyArg<Http.Server>,
|
|
58
|
-
options: Net.ListenOptions
|
|
60
|
+
options: Net.ListenOptions & {
|
|
61
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
62
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
63
|
+
}
|
|
59
64
|
) {
|
|
60
65
|
const scope = yield* Effect.scope
|
|
61
66
|
const server = evaluate()
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
|
|
68
|
+
const shutdown = yield* Effect.callback<void>((resume) => {
|
|
69
|
+
if (!server.listening) {
|
|
70
|
+
return resume(Effect.void)
|
|
71
|
+
}
|
|
72
|
+
server.close((error) => {
|
|
73
|
+
if (error) {
|
|
74
|
+
resume(Effect.die(error))
|
|
75
|
+
} else {
|
|
76
|
+
resume(Effect.void)
|
|
67
77
|
}
|
|
68
|
-
server.close((error) => {
|
|
69
|
-
if (error) {
|
|
70
|
-
resume(Effect.die(error))
|
|
71
|
-
} else {
|
|
72
|
-
resume(Effect.void)
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
78
|
})
|
|
76
|
-
)
|
|
79
|
+
}).pipe(Effect.cached)
|
|
80
|
+
|
|
81
|
+
const preemptiveShutdown = options.disablePreemptiveShutdown ?
|
|
82
|
+
Effect.void :
|
|
83
|
+
Effect.timeoutOrElse(shutdown, {
|
|
84
|
+
duration: options.gracefulShutdownTimeout ?? Duration.seconds(20),
|
|
85
|
+
orElse: () => Effect.void
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
yield* Scope.addFinalizer(scope, shutdown)
|
|
77
89
|
|
|
78
90
|
yield* Effect.callback<void, ServeError>((resume) => {
|
|
79
91
|
function onError(cause: Error) {
|
|
@@ -111,7 +123,8 @@ export const make = Effect.fnUntraced(function*(
|
|
|
111
123
|
port: address.port
|
|
112
124
|
},
|
|
113
125
|
serve: Effect.fnUntraced(function*(httpApp, middleware) {
|
|
114
|
-
const
|
|
126
|
+
const serveScope = yield* Effect.scope
|
|
127
|
+
const scope = Scope.forkUnsafe(serveScope, "parallel")
|
|
115
128
|
const handler = yield* (makeHandler(httpApp, {
|
|
116
129
|
middleware: middleware as any,
|
|
117
130
|
scope
|
|
@@ -120,12 +133,11 @@ export const make = Effect.fnUntraced(function*(
|
|
|
120
133
|
middleware: middleware as any,
|
|
121
134
|
scope
|
|
122
135
|
})
|
|
123
|
-
yield*
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
)
|
|
136
|
+
yield* Scope.addFinalizerExit(serveScope, () => {
|
|
137
|
+
server.off("request", handler)
|
|
138
|
+
server.off("upgrade", upgradeHandler)
|
|
139
|
+
return preemptiveShutdown
|
|
140
|
+
})
|
|
129
141
|
server.on("request", handler)
|
|
130
142
|
server.on("upgrade", upgradeHandler)
|
|
131
143
|
})
|
|
@@ -152,20 +164,21 @@ export const makeHandler = <
|
|
|
152
164
|
Exclude<Effect.Services<App>, HttpServerRequest | Scope.Scope>
|
|
153
165
|
> => {
|
|
154
166
|
const handled = HttpEffect.toHandled(httpEffect, handleResponse, options.middleware as any)
|
|
155
|
-
return Effect.
|
|
156
|
-
|
|
167
|
+
return Effect.withFiber((parent) => {
|
|
168
|
+
const services = parent.context
|
|
169
|
+
return Effect.succeed(function handler(
|
|
157
170
|
nodeRequest: Http.IncomingMessage,
|
|
158
171
|
nodeResponse: Http.ServerResponse
|
|
159
172
|
) {
|
|
160
173
|
const map = new Map(services.mapUnsafe)
|
|
161
174
|
map.set(HttpServerRequest.key, new ServerRequestImpl(nodeRequest, nodeResponse))
|
|
162
|
-
const fiber = Fiber.runIn(Effect.runForkWith(
|
|
175
|
+
const fiber = Fiber.runIn(Effect.runForkWith(Context.makeUnsafe<any>(map))(handled), options.scope)
|
|
163
176
|
nodeResponse.on("close", () => {
|
|
164
177
|
if (!nodeResponse.writableEnded) {
|
|
165
|
-
fiber.interruptUnsafe(
|
|
178
|
+
fiber.interruptUnsafe(parent.id, ClientAbort.annotation)
|
|
166
179
|
}
|
|
167
180
|
})
|
|
168
|
-
}
|
|
181
|
+
})
|
|
169
182
|
})
|
|
170
183
|
}
|
|
171
184
|
|
|
@@ -190,8 +203,13 @@ export const makeUpgradeHandler = <
|
|
|
190
203
|
Exclude<Effect.Services<App>, HttpServerRequest | Scope.Scope>
|
|
191
204
|
> => {
|
|
192
205
|
const handledApp = HttpEffect.toHandled(httpEffect, handleResponse, options.middleware as any)
|
|
193
|
-
return Effect.
|
|
194
|
-
|
|
206
|
+
return Effect.withFiber((parent) => {
|
|
207
|
+
const services = parent.context
|
|
208
|
+
return Effect.succeed(function handler(
|
|
209
|
+
nodeRequest: Http.IncomingMessage,
|
|
210
|
+
socket: Duplex,
|
|
211
|
+
head: Buffer
|
|
212
|
+
) {
|
|
195
213
|
let nodeResponse_: Http.ServerResponse | undefined = undefined
|
|
196
214
|
const nodeResponse = () => {
|
|
197
215
|
if (nodeResponse_ === undefined) {
|
|
@@ -217,13 +235,14 @@ export const makeUpgradeHandler = <
|
|
|
217
235
|
))
|
|
218
236
|
const map = new Map(services.mapUnsafe)
|
|
219
237
|
map.set(HttpServerRequest.key, new ServerRequestImpl(nodeRequest, nodeResponse, upgradeEffect))
|
|
220
|
-
const fiber = Fiber.runIn(Effect.runForkWith(
|
|
238
|
+
const fiber = Fiber.runIn(Effect.runForkWith(Context.makeUnsafe<any>(map))(handledApp), options.scope)
|
|
221
239
|
socket.on("close", () => {
|
|
222
240
|
if (!socket.writableEnded) {
|
|
223
|
-
fiber.interruptUnsafe(
|
|
241
|
+
fiber.interruptUnsafe(parent.id, ClientAbort.annotation)
|
|
224
242
|
}
|
|
225
243
|
})
|
|
226
|
-
})
|
|
244
|
+
})
|
|
245
|
+
})
|
|
227
246
|
}
|
|
228
247
|
|
|
229
248
|
class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> implements HttpServerRequest {
|
|
@@ -239,7 +258,7 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
|
|
|
239
258
|
upgradeEffect?: Effect.Effect<Socket.Socket, HttpServerError>,
|
|
240
259
|
url = source.url!,
|
|
241
260
|
headersOverride?: Headers.Headers,
|
|
242
|
-
remoteAddressOverride?: string
|
|
261
|
+
remoteAddressOverride?: Option.Option<string>
|
|
243
262
|
) {
|
|
244
263
|
super(source, (cause) =>
|
|
245
264
|
new HttpServerError({
|
|
@@ -271,7 +290,7 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
|
|
|
271
290
|
options: {
|
|
272
291
|
readonly url?: string | undefined
|
|
273
292
|
readonly headers?: Headers.Headers | undefined
|
|
274
|
-
readonly remoteAddress?: string | undefined
|
|
293
|
+
readonly remoteAddress?: Option.Option<string> | undefined
|
|
275
294
|
}
|
|
276
295
|
) {
|
|
277
296
|
return new ServerRequestImpl(
|
|
@@ -280,7 +299,7 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
|
|
|
280
299
|
this.upgradeEffect,
|
|
281
300
|
options.url ?? this.url,
|
|
282
301
|
options.headers ?? this.headersOverride,
|
|
283
|
-
options.remoteAddress
|
|
302
|
+
"remoteAddress" in options ? options.remoteAddress : this.remoteAddressOverride
|
|
284
303
|
)
|
|
285
304
|
}
|
|
286
305
|
|
|
@@ -352,7 +371,10 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
|
|
|
352
371
|
*/
|
|
353
372
|
export const layerServer: (
|
|
354
373
|
evaluate: LazyArg<Http.Server<typeof Http.IncomingMessage, typeof Http.ServerResponse>>,
|
|
355
|
-
options: Net.ListenOptions
|
|
374
|
+
options: Net.ListenOptions & {
|
|
375
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
376
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
377
|
+
}
|
|
356
378
|
) => Layer.Layer<HttpServer.HttpServer, ServeError> = flow(make, Layer.effect(HttpServer.HttpServer))
|
|
357
379
|
|
|
358
380
|
/**
|
|
@@ -373,7 +395,10 @@ export const layerHttpServices: Layer.Layer<
|
|
|
373
395
|
*/
|
|
374
396
|
export const layer = (
|
|
375
397
|
evaluate: LazyArg<Http.Server>,
|
|
376
|
-
options: Net.ListenOptions
|
|
398
|
+
options: Net.ListenOptions & {
|
|
399
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
400
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
401
|
+
}
|
|
377
402
|
): Layer.Layer<
|
|
378
403
|
HttpServer.HttpServer | NodeServices.NodeServices | HttpPlatform.HttpPlatform | Etag.Generator,
|
|
379
404
|
ServeError
|
|
@@ -389,7 +414,12 @@ export const layer = (
|
|
|
389
414
|
*/
|
|
390
415
|
export const layerConfig = (
|
|
391
416
|
evaluate: LazyArg<Http.Server>,
|
|
392
|
-
options: Config.Wrap<
|
|
417
|
+
options: Config.Wrap<
|
|
418
|
+
Net.ListenOptions & {
|
|
419
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
420
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
421
|
+
}
|
|
422
|
+
>
|
|
393
423
|
): Layer.Layer<
|
|
394
424
|
HttpServer.HttpServer | FileSystem.FileSystem | Path.Path | HttpPlatform.HttpPlatform | Etag.Generator,
|
|
395
425
|
ServeError | Config.ConfigError
|
package/src/NodeRedis.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
4
|
import * as Config from "effect/Config"
|
|
5
|
+
import * as Context from "effect/Context"
|
|
5
6
|
import * as Effect from "effect/Effect"
|
|
6
7
|
import * as Fn from "effect/Function"
|
|
7
8
|
import * as Layer from "effect/Layer"
|
|
8
9
|
import * as Scope from "effect/Scope"
|
|
9
|
-
import * as ServiceMap from "effect/ServiceMap"
|
|
10
10
|
import * as Redis from "effect/unstable/persistence/Redis"
|
|
11
11
|
import * as IoRedis from "ioredis"
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ import * as IoRedis from "ioredis"
|
|
|
14
14
|
* @since 1.0.0
|
|
15
15
|
* @category Service
|
|
16
16
|
*/
|
|
17
|
-
export class NodeRedis extends
|
|
17
|
+
export class NodeRedis extends Context.Service<NodeRedis, {
|
|
18
18
|
readonly client: IoRedis.Redis
|
|
19
19
|
readonly use: <A>(f: (client: IoRedis.Redis) => Promise<A>) => Effect.Effect<A, Redis.RedisError>
|
|
20
20
|
}>()("@effect/platform-node/NodeRedis") {}
|
|
@@ -45,8 +45,8 @@ const make = Effect.fnUntraced(function*(
|
|
|
45
45
|
use
|
|
46
46
|
})
|
|
47
47
|
|
|
48
|
-
return
|
|
49
|
-
|
|
48
|
+
return Context.make(NodeRedis, nodeRedis).pipe(
|
|
49
|
+
Context.add(Redis.Redis, redis)
|
|
50
50
|
)
|
|
51
51
|
})
|
|
52
52
|
|
|
@@ -56,7 +56,7 @@ const make = Effect.fnUntraced(function*(
|
|
|
56
56
|
*/
|
|
57
57
|
export const layer = (
|
|
58
58
|
options?: IoRedis.RedisOptions | undefined
|
|
59
|
-
): Layer.Layer<Redis.Redis | NodeRedis> => Layer.
|
|
59
|
+
): Layer.Layer<Redis.Redis | NodeRedis> => Layer.effectContext(make(options))
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* @since 1.0.0
|
|
@@ -67,7 +67,7 @@ export const layerConfig: (
|
|
|
67
67
|
) => Layer.Layer<Redis.Redis | NodeRedis, Config.ConfigError> = (
|
|
68
68
|
options: Config.Wrap<IoRedis.RedisOptions>
|
|
69
69
|
): Layer.Layer<Redis.Redis | NodeRedis, Config.ConfigError> =>
|
|
70
|
-
Layer.
|
|
70
|
+
Layer.effectContext(
|
|
71
71
|
Config.unwrap(options).asEffect().pipe(
|
|
72
72
|
Effect.flatMap(make)
|
|
73
73
|
)
|
package/src/NodeRuntime.ts
CHANGED
|
@@ -20,7 +20,6 @@ import type * as Runtime from "effect/Runtime"
|
|
|
20
20
|
*
|
|
21
21
|
* An optional object that can include:
|
|
22
22
|
* - `disableErrorReporting`: Turn off automatic error logging.
|
|
23
|
-
* - `disablePrettyLogger`: Avoid adding the pretty logger.
|
|
24
23
|
* - `teardown`: Provide custom finalization logic.
|
|
25
24
|
*
|
|
26
25
|
* **When to Use**
|
|
@@ -48,7 +47,6 @@ export const runMain: {
|
|
|
48
47
|
*
|
|
49
48
|
* An optional object that can include:
|
|
50
49
|
* - `disableErrorReporting`: Turn off automatic error logging.
|
|
51
|
-
* - `disablePrettyLogger`: Avoid adding the pretty logger.
|
|
52
50
|
* - `teardown`: Provide custom finalization logic.
|
|
53
51
|
*
|
|
54
52
|
* **When to Use**
|
|
@@ -81,7 +79,6 @@ export const runMain: {
|
|
|
81
79
|
*
|
|
82
80
|
* An optional object that can include:
|
|
83
81
|
* - `disableErrorReporting`: Turn off automatic error logging.
|
|
84
|
-
* - `disablePrettyLogger`: Avoid adding the pretty logger.
|
|
85
82
|
* - `teardown`: Provide custom finalization logic.
|
|
86
83
|
*
|
|
87
84
|
* **When to Use**
|
package/src/NodeSocket.ts
CHANGED
|
@@ -26,6 +26,16 @@ export const layerWebSocketConstructor: Layer.Layer<
|
|
|
26
26
|
return (url, protocols) => new WS.WebSocket(url, protocols) as unknown as globalThis.WebSocket
|
|
27
27
|
})
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* @since 1.0.0
|
|
31
|
+
* @category layers
|
|
32
|
+
*/
|
|
33
|
+
export const layerWebSocketConstructorWS: Layer.Layer<
|
|
34
|
+
Socket.WebSocketConstructor
|
|
35
|
+
> = Layer.succeed(Socket.WebSocketConstructor)(
|
|
36
|
+
(url, protocols) => new WS.WebSocket(url, protocols) as unknown as globalThis.WebSocket
|
|
37
|
+
)
|
|
38
|
+
|
|
29
39
|
/**
|
|
30
40
|
* @since 1.0.0
|
|
31
41
|
* @category layers
|
|
@@ -34,7 +44,7 @@ export const layerWebSocket: (
|
|
|
34
44
|
url: string | Effect.Effect<string>,
|
|
35
45
|
options?: {
|
|
36
46
|
readonly closeCodeIsError?: ((code: number) => boolean) | undefined
|
|
37
|
-
readonly openTimeout?: Duration.
|
|
47
|
+
readonly openTimeout?: Duration.Input | undefined
|
|
38
48
|
readonly protocols?: string | Array<string> | undefined
|
|
39
49
|
} | undefined
|
|
40
50
|
) => Layer.Layer<Socket.Socket, never, never> = flow(
|
package/src/NodeWorkerRunner.ts
CHANGED
|
@@ -36,7 +36,7 @@ export const layer: Layer.Layer<WorkerRunner.WorkerRunnerPlatform> = Layer.succe
|
|
|
36
36
|
Effect.scopedWith(Effect.fnUntraced(function*(scope) {
|
|
37
37
|
const closeLatch = Deferred.makeUnsafe<void, WorkerError>()
|
|
38
38
|
const trackFiber = Fiber.runIn(scope)
|
|
39
|
-
const services = yield* Effect.
|
|
39
|
+
const services = yield* Effect.context<R>()
|
|
40
40
|
const runFork = Effect.runForkWith(services)
|
|
41
41
|
const onExit = (exit: Exit.Exit<any, E>) => {
|
|
42
42
|
if (exit._tag === "Failure" && !Cause.hasInterruptsOnly(exit.cause)) {
|