@effect/platform-node 4.0.0-beta.1 → 4.0.0-beta.100

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 (124) hide show
  1. package/README.md +1 -1
  2. package/dist/Mime.d.ts +9 -3
  3. package/dist/Mime.d.ts.map +1 -1
  4. package/dist/Mime.js +9 -3
  5. package/dist/Mime.js.map +1 -1
  6. package/dist/NodeChildProcessSpawner.d.ts +1 -1
  7. package/dist/NodeChildProcessSpawner.js +1 -1
  8. package/dist/NodeClusterHttp.d.ts +25 -7
  9. package/dist/NodeClusterHttp.d.ts.map +1 -1
  10. package/dist/NodeClusterHttp.js +20 -10
  11. package/dist/NodeClusterHttp.js.map +1 -1
  12. package/dist/NodeClusterSocket.d.ts +37 -11
  13. package/dist/NodeClusterSocket.d.ts.map +1 -1
  14. package/dist/NodeClusterSocket.js +37 -11
  15. package/dist/NodeClusterSocket.js.map +1 -1
  16. package/dist/NodeCrypto.d.ts +10 -0
  17. package/dist/NodeCrypto.d.ts.map +1 -0
  18. package/dist/NodeCrypto.js +22 -0
  19. package/dist/NodeCrypto.js.map +1 -0
  20. package/dist/NodeFileSystem.d.ts +4 -2
  21. package/dist/NodeFileSystem.d.ts.map +1 -1
  22. package/dist/NodeFileSystem.js +12 -3
  23. package/dist/NodeFileSystem.js.map +1 -1
  24. package/dist/NodeHttpClient.d.ts +98 -29
  25. package/dist/NodeHttpClient.d.ts.map +1 -1
  26. package/dist/NodeHttpClient.js +120 -33
  27. package/dist/NodeHttpClient.js.map +1 -1
  28. package/dist/NodeHttpIncomingMessage.d.ts +36 -9
  29. package/dist/NodeHttpIncomingMessage.d.ts.map +1 -1
  30. package/dist/NodeHttpIncomingMessage.js +40 -8
  31. package/dist/NodeHttpIncomingMessage.js.map +1 -1
  32. package/dist/NodeHttpPlatform.d.ts +10 -4
  33. package/dist/NodeHttpPlatform.d.ts.map +1 -1
  34. package/dist/NodeHttpPlatform.js +20 -7
  35. package/dist/NodeHttpPlatform.js.map +1 -1
  36. package/dist/NodeHttpServer.d.ts +60 -19
  37. package/dist/NodeHttpServer.d.ts.map +1 -1
  38. package/dist/NodeHttpServer.js +111 -54
  39. package/dist/NodeHttpServer.js.map +1 -1
  40. package/dist/NodeHttpServerRequest.d.ts +18 -5
  41. package/dist/NodeHttpServerRequest.d.ts.map +1 -1
  42. package/dist/NodeHttpServerRequest.js +11 -4
  43. package/dist/NodeHttpServerRequest.js.map +1 -1
  44. package/dist/NodeMultipart.d.ts +24 -4
  45. package/dist/NodeMultipart.d.ts.map +1 -1
  46. package/dist/NodeMultipart.js +24 -4
  47. package/dist/NodeMultipart.js.map +1 -1
  48. package/dist/NodePath.d.ts +15 -6
  49. package/dist/NodePath.d.ts.map +1 -1
  50. package/dist/NodePath.js +23 -7
  51. package/dist/NodePath.js.map +1 -1
  52. package/dist/NodeRedis.d.ts +27 -9
  53. package/dist/NodeRedis.d.ts.map +1 -1
  54. package/dist/NodeRedis.js +30 -12
  55. package/dist/NodeRedis.js.map +1 -1
  56. package/dist/NodeRuntime.d.ts +27 -36
  57. package/dist/NodeRuntime.d.ts.map +1 -1
  58. package/dist/NodeRuntime.js +17 -13
  59. package/dist/NodeRuntime.js.map +1 -1
  60. package/dist/NodeServices.d.ts +19 -5
  61. package/dist/NodeServices.d.ts.map +1 -1
  62. package/dist/NodeServices.js +7 -3
  63. package/dist/NodeServices.js.map +1 -1
  64. package/dist/NodeSink.d.ts +2 -2
  65. package/dist/NodeSink.js +2 -2
  66. package/dist/NodeSocket.d.ts +19 -4
  67. package/dist/NodeSocket.d.ts.map +1 -1
  68. package/dist/NodeSocket.js +27 -4
  69. package/dist/NodeSocket.js.map +1 -1
  70. package/dist/NodeSocketServer.d.ts +2 -2
  71. package/dist/NodeSocketServer.js +2 -2
  72. package/dist/NodeStdio.d.ts +5 -2
  73. package/dist/NodeStdio.d.ts.map +1 -1
  74. package/dist/NodeStdio.js +13 -3
  75. package/dist/NodeStdio.js.map +1 -1
  76. package/dist/NodeStream.d.ts +2 -2
  77. package/dist/NodeStream.js +2 -2
  78. package/dist/NodeTerminal.d.ts +8 -2
  79. package/dist/NodeTerminal.d.ts.map +1 -1
  80. package/dist/NodeTerminal.js +15 -3
  81. package/dist/NodeTerminal.js.map +1 -1
  82. package/dist/NodeWorker.d.ts +9 -2
  83. package/dist/NodeWorker.d.ts.map +1 -1
  84. package/dist/NodeWorker.js +22 -6
  85. package/dist/NodeWorker.js.map +1 -1
  86. package/dist/NodeWorkerRunner.d.ts +5 -1
  87. package/dist/NodeWorkerRunner.d.ts.map +1 -1
  88. package/dist/NodeWorkerRunner.js +18 -5
  89. package/dist/NodeWorkerRunner.js.map +1 -1
  90. package/dist/Undici.d.ts +18 -5
  91. package/dist/Undici.d.ts.map +1 -1
  92. package/dist/Undici.js +18 -5
  93. package/dist/Undici.js.map +1 -1
  94. package/dist/index.d.ts +28 -26
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +28 -26
  97. package/dist/index.js.map +1 -1
  98. package/package.json +11 -12
  99. package/src/Mime.ts +10 -3
  100. package/src/NodeChildProcessSpawner.ts +1 -1
  101. package/src/NodeClusterHttp.ts +30 -11
  102. package/src/NodeClusterSocket.ts +37 -11
  103. package/src/NodeCrypto.ts +24 -0
  104. package/src/NodeFileSystem.ts +12 -3
  105. package/src/NodeHttpClient.ts +128 -38
  106. package/src/NodeHttpIncomingMessage.ts +48 -12
  107. package/src/NodeHttpPlatform.ts +21 -6
  108. package/src/NodeHttpServer.ts +134 -59
  109. package/src/NodeHttpServerRequest.ts +18 -5
  110. package/src/NodeMultipart.ts +24 -4
  111. package/src/NodePath.ts +23 -7
  112. package/src/NodeRedis.ts +32 -14
  113. package/src/NodeRuntime.ts +35 -37
  114. package/src/NodeServices.ts +21 -5
  115. package/src/NodeSink.ts +2 -2
  116. package/src/NodeSocket.ts +33 -5
  117. package/src/NodeSocketServer.ts +2 -2
  118. package/src/NodeStdio.ts +13 -3
  119. package/src/NodeStream.ts +2 -2
  120. package/src/NodeTerminal.ts +15 -3
  121. package/src/NodeWorker.ts +22 -6
  122. package/src/NodeWorkerRunner.ts +18 -5
  123. package/src/Undici.ts +18 -5
  124. package/src/index.ts +29 -26
@@ -1,17 +1,31 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Node.js implementation of the Effect `HttpServer`.
3
+ *
4
+ * This module adapts a supplied Node `http.Server` into Effect's
5
+ * platform-independent HTTP server service. It starts the server with Node
6
+ * `listen` options, converts `request` events into `HttpServerRequest` values,
7
+ * writes `HttpServerResponse` bodies through Node's `ServerResponse`, and
8
+ * handles `upgrade` events by exposing the upgraded socket through
9
+ * `HttpServerRequest.upgrade`. It also exports request and upgrade handler
10
+ * constructors plus layers for the server alone, HTTP support services, the
11
+ * combined server, configurable options, and tests.
12
+ *
13
+ * @since 4.0.0
3
14
  */
4
15
  import * as Cause from "effect/Cause"
5
16
  import * as Config from "effect/Config"
17
+ import * as Context from "effect/Context"
18
+ import * as Duration from "effect/Duration"
6
19
  import * as Effect from "effect/Effect"
7
20
  import * as Fiber from "effect/Fiber"
8
21
  import type * as FileSystem from "effect/FileSystem"
9
22
  import { flow, type LazyArg } from "effect/Function"
23
+ import * as Latch from "effect/Latch"
10
24
  import * as Layer from "effect/Layer"
25
+ import type * as Option from "effect/Option"
11
26
  import type * as Path from "effect/Path"
12
27
  import type * as Record from "effect/Record"
13
28
  import * as Scope from "effect/Scope"
14
- import * as ServiceMap from "effect/ServiceMap"
15
29
  import * as Stream from "effect/Stream"
16
30
  import * as Cookies from "effect/unstable/http/Cookies"
17
31
  import * as Etag from "effect/unstable/http/Etag"
@@ -26,7 +40,7 @@ import type * as HttpPlatform from "effect/unstable/http/HttpPlatform"
26
40
  import * as HttpServer from "effect/unstable/http/HttpServer"
27
41
  import {
28
42
  causeResponse,
29
- clientAbortFiberId,
43
+ ClientAbort,
30
44
  HttpServerError,
31
45
  RequestParseError,
32
46
  ResponseError,
@@ -49,30 +63,44 @@ import * as NodeServices from "./NodeServices.ts"
49
63
  import { NodeWS } from "./NodeSocket.ts"
50
64
 
51
65
  /**
52
- * @since 1.0.0
66
+ * Creates a scoped `HttpServer` from a Node `http.Server`, starts listening
67
+ * with the supplied options, registers request and upgrade handling, and closes
68
+ * the server during scope finalization with optional graceful-shutdown control.
69
+ *
53
70
  * @category constructors
71
+ * @since 4.0.0
54
72
  */
55
73
  export const make = Effect.fnUntraced(function*(
56
74
  evaluate: LazyArg<Http.Server>,
57
- options: Net.ListenOptions
75
+ options: Net.ListenOptions & {
76
+ readonly disablePreemptiveShutdown?: boolean | undefined
77
+ readonly gracefulShutdownTimeout?: Duration.Input | undefined
78
+ }
58
79
  ) {
59
80
  const scope = yield* Effect.scope
60
81
  const server = evaluate()
61
- yield* Scope.addFinalizer(
62
- scope,
63
- Effect.callback<void>((resume) => {
64
- if (!server.listening) {
65
- return resume(Effect.void)
82
+
83
+ const shutdown = yield* Effect.callback<void>((resume) => {
84
+ if (!server.listening) {
85
+ return resume(Effect.void)
86
+ }
87
+ server.close((error) => {
88
+ if (error) {
89
+ resume(Effect.die(error))
90
+ } else {
91
+ resume(Effect.void)
66
92
  }
67
- server.close((error) => {
68
- if (error) {
69
- resume(Effect.die(error))
70
- } else {
71
- resume(Effect.void)
72
- }
73
- })
74
93
  })
75
- )
94
+ }).pipe(Effect.cached)
95
+
96
+ const preemptiveShutdown = options.disablePreemptiveShutdown ?
97
+ Effect.void :
98
+ Effect.timeoutOrElse(shutdown, {
99
+ duration: options.gracefulShutdownTimeout ?? Duration.seconds(20),
100
+ orElse: () => Effect.void
101
+ })
102
+
103
+ yield* Scope.addFinalizer(scope, shutdown)
76
104
 
77
105
  yield* Effect.callback<void, ServeError>((resume) => {
78
106
  function onError(cause: Error) {
@@ -110,7 +138,8 @@ export const make = Effect.fnUntraced(function*(
110
138
  port: address.port
111
139
  },
112
140
  serve: Effect.fnUntraced(function*(httpApp, middleware) {
113
- const scope = yield* Effect.scope
141
+ const serveScope = yield* Effect.scope
142
+ const scope = Scope.forkUnsafe(serveScope, "parallel")
114
143
  const handler = yield* (makeHandler(httpApp, {
115
144
  middleware: middleware as any,
116
145
  scope
@@ -119,12 +148,11 @@ export const make = Effect.fnUntraced(function*(
119
148
  middleware: middleware as any,
120
149
  scope
121
150
  })
122
- yield* Effect.addFinalizer(() =>
123
- Effect.sync(() => {
124
- server.off("request", handler)
125
- server.off("upgrade", upgradeHandler)
126
- })
127
- )
151
+ yield* Scope.addFinalizerExit(serveScope, () => {
152
+ server.off("request", handler)
153
+ server.off("upgrade", upgradeHandler)
154
+ return preemptiveShutdown
155
+ })
128
156
  server.on("request", handler)
129
157
  server.on("upgrade", upgradeHandler)
130
158
  })
@@ -132,8 +160,12 @@ export const make = Effect.fnUntraced(function*(
132
160
  })
133
161
 
134
162
  /**
135
- * @since 1.0.0
136
- * @category Handlers
163
+ * Creates a Node `request` event handler for an Effect HTTP application,
164
+ * injecting a `HttpServerRequest` and interrupting the request fiber if the
165
+ * client closes the response before it finishes.
166
+ *
167
+ * @category handlers
168
+ * @since 4.0.0
137
169
  */
138
170
  export const makeHandler = <
139
171
  R,
@@ -151,26 +183,31 @@ export const makeHandler = <
151
183
  Exclude<Effect.Services<App>, HttpServerRequest | Scope.Scope>
152
184
  > => {
153
185
  const handled = HttpEffect.toHandled(httpEffect, handleResponse, options.middleware as any)
154
- return Effect.map(Effect.services<any>(), (services) => {
155
- return function handler(
186
+ return Effect.withFiber((parent) => {
187
+ const services = parent.context
188
+ return Effect.succeed(function handler(
156
189
  nodeRequest: Http.IncomingMessage,
157
190
  nodeResponse: Http.ServerResponse
158
191
  ) {
159
192
  const map = new Map(services.mapUnsafe)
160
193
  map.set(HttpServerRequest.key, new ServerRequestImpl(nodeRequest, nodeResponse))
161
- const fiber = Fiber.runIn(Effect.runForkWith(ServiceMap.makeUnsafe<any>(map))(handled), options.scope)
194
+ const fiber = Fiber.runIn(Effect.runForkWith(Context.makeUnsafe<any>(map))(handled), options.scope)
162
195
  nodeResponse.on("close", () => {
163
196
  if (!nodeResponse.writableEnded) {
164
- fiber.interruptUnsafe(clientAbortFiberId)
197
+ fiber.interruptUnsafe(parent.id, ClientAbort.annotation)
165
198
  }
166
199
  })
167
- }
200
+ })
168
201
  })
169
202
  }
170
203
 
171
204
  /**
172
- * @since 1.0.0
173
- * @category Handlers
205
+ * Creates a Node `upgrade` event handler for an Effect HTTP application,
206
+ * exposing the upgraded WebSocket as the request's `upgrade` effect and
207
+ * interrupting the request fiber when the socket closes early.
208
+ *
209
+ * @category handlers
210
+ * @since 4.0.0
174
211
  */
175
212
  export const makeUpgradeHandler = <
176
213
  R,
@@ -189,8 +226,13 @@ export const makeUpgradeHandler = <
189
226
  Exclude<Effect.Services<App>, HttpServerRequest | Scope.Scope>
190
227
  > => {
191
228
  const handledApp = HttpEffect.toHandled(httpEffect, handleResponse, options.middleware as any)
192
- return Effect.map(Effect.services<any>(), (services) =>
193
- (function handler(nodeRequest: Http.IncomingMessage, socket: Duplex, head: Buffer) {
229
+ return Effect.withFiber((parent) => {
230
+ const services = parent.context
231
+ return Effect.succeed(function handler(
232
+ nodeRequest: Http.IncomingMessage,
233
+ socket: Duplex,
234
+ head: Buffer
235
+ ) {
194
236
  let nodeResponse_: Http.ServerResponse | undefined = undefined
195
237
  const nodeResponse = () => {
196
238
  if (nodeResponse_ === undefined) {
@@ -216,13 +258,14 @@ export const makeUpgradeHandler = <
216
258
  ))
217
259
  const map = new Map(services.mapUnsafe)
218
260
  map.set(HttpServerRequest.key, new ServerRequestImpl(nodeRequest, nodeResponse, upgradeEffect))
219
- const fiber = Fiber.runIn(Effect.runForkWith(ServiceMap.makeUnsafe<any>(map))(handledApp), options.scope)
261
+ const fiber = Fiber.runIn(Effect.runForkWith(Context.makeUnsafe<any>(map))(handledApp), options.scope)
220
262
  socket.on("close", () => {
221
263
  if (!socket.writableEnded) {
222
- fiber.interruptUnsafe(clientAbortFiberId)
264
+ fiber.interruptUnsafe(parent.id, ClientAbort.annotation)
223
265
  }
224
266
  })
225
- }));
267
+ })
268
+ })
226
269
  }
227
270
 
228
271
  class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> implements HttpServerRequest {
@@ -238,7 +281,7 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
238
281
  upgradeEffect?: Effect.Effect<Socket.Socket, HttpServerError>,
239
282
  url = source.url!,
240
283
  headersOverride?: Headers.Headers,
241
- remoteAddressOverride?: string
284
+ remoteAddressOverride?: Option.Option<string>
242
285
  ) {
243
286
  super(source, (cause) =>
244
287
  new HttpServerError({
@@ -270,7 +313,7 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
270
313
  options: {
271
314
  readonly url?: string | undefined
272
315
  readonly headers?: Headers.Headers | undefined
273
- readonly remoteAddress?: string | undefined
316
+ readonly remoteAddress?: Option.Option<string> | undefined
274
317
  }
275
318
  ) {
276
319
  return new ServerRequestImpl(
@@ -279,7 +322,7 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
279
322
  this.upgradeEffect,
280
323
  options.url ?? this.url,
281
324
  options.headers ?? this.headersOverride,
282
- options.remoteAddress ?? this.remoteAddressOverride
325
+ "remoteAddress" in options ? options.remoteAddress : this.remoteAddressOverride
283
326
  )
284
327
  }
285
328
 
@@ -346,17 +389,26 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
346
389
  }
347
390
 
348
391
  /**
349
- * @since 1.0.0
350
- * @category Layers
392
+ * Provides an `HttpServer` by creating and managing a scoped Node
393
+ * `http.Server` with the supplied listen and shutdown options.
394
+ *
395
+ * @category layers
396
+ * @since 4.0.0
351
397
  */
352
398
  export const layerServer: (
353
399
  evaluate: LazyArg<Http.Server<typeof Http.IncomingMessage, typeof Http.ServerResponse>>,
354
- options: Net.ListenOptions
400
+ options: Net.ListenOptions & {
401
+ readonly disablePreemptiveShutdown?: boolean | undefined
402
+ readonly gracefulShutdownTimeout?: Duration.Input | undefined
403
+ }
355
404
  ) => Layer.Layer<HttpServer.HttpServer, ServeError> = flow(make, Layer.effect(HttpServer.HttpServer))
356
405
 
357
406
  /**
358
- * @since 1.0.0
359
- * @category Layers
407
+ * Provides the Node HTTP support services used by `NodeHttpServer`, including
408
+ * the HTTP platform, ETag generator, and core Node platform services.
409
+ *
410
+ * @category layers
411
+ * @since 4.0.0
360
412
  */
361
413
  export const layerHttpServices: Layer.Layer<
362
414
  NodeServices.NodeServices | HttpPlatform.HttpPlatform | Etag.Generator
@@ -367,12 +419,18 @@ export const layerHttpServices: Layer.Layer<
367
419
  )
368
420
 
369
421
  /**
370
- * @since 1.0.0
371
- * @category Layers
422
+ * Provides a Node `HttpServer` together with the Node HTTP platform, ETag, and
423
+ * core platform services required to serve requests.
424
+ *
425
+ * @category layers
426
+ * @since 4.0.0
372
427
  */
373
428
  export const layer = (
374
429
  evaluate: LazyArg<Http.Server>,
375
- options: Net.ListenOptions
430
+ options: Net.ListenOptions & {
431
+ readonly disablePreemptiveShutdown?: boolean | undefined
432
+ readonly gracefulShutdownTimeout?: Duration.Input | undefined
433
+ }
376
434
  ): Layer.Layer<
377
435
  HttpServer.HttpServer | NodeServices.NodeServices | HttpPlatform.HttpPlatform | Etag.Generator,
378
436
  ServeError
@@ -383,26 +441,38 @@ export const layer = (
383
441
  )
384
442
 
385
443
  /**
386
- * @since 1.0.0
387
- * @category Layers
444
+ * Provides a Node `HttpServer` together with the Node HTTP platform, ETag,
445
+ * and core Node platform services, reading the listen and shutdown options from
446
+ * a `Config` value.
447
+ *
448
+ * @category layers
449
+ * @since 4.0.0
388
450
  */
389
451
  export const layerConfig = (
390
452
  evaluate: LazyArg<Http.Server>,
391
- options: Config.Wrap<Net.ListenOptions>
453
+ options: Config.Wrap<
454
+ Net.ListenOptions & {
455
+ readonly disablePreemptiveShutdown?: boolean | undefined
456
+ readonly gracefulShutdownTimeout?: Duration.Input | undefined
457
+ }
458
+ >
392
459
  ): Layer.Layer<
393
- HttpServer.HttpServer | FileSystem.FileSystem | Path.Path | HttpPlatform.HttpPlatform | Etag.Generator,
460
+ HttpServer.HttpServer | NodeServices.NodeServices | HttpPlatform.HttpPlatform | Etag.Generator,
394
461
  ServeError | Config.ConfigError
395
462
  > =>
396
463
  Layer.mergeAll(
397
464
  Layer.effect(HttpServer.HttpServer)(
398
- Effect.flatMap(Config.unwrap(options).asEffect(), (options) => make(evaluate, options))
465
+ Effect.flatMap(Config.unwrap(options), (options) => make(evaluate, options))
399
466
  ),
400
467
  layerHttpServices
401
468
  )
402
469
 
403
470
  /**
404
- * @since 1.0.0
405
- * @category Testing
471
+ * Provides a test HTTP server listening on an ephemeral port together with a
472
+ * Fetch-backed `HttpClient` configured for server integration tests.
473
+ *
474
+ * @category testing
475
+ * @since 4.0.0
406
476
  */
407
477
  export const layerTest: Layer.Layer<
408
478
  | HttpServer.HttpServer
@@ -448,7 +518,12 @@ const handleResponse = (
448
518
  if (request.method === "HEAD") {
449
519
  nodeResponse.writeHead(response.status, headers)
450
520
  return Effect.callback<void>((resume) => {
451
- nodeResponse.end(() => resume(Effect.void))
521
+ const done = () => {
522
+ nodeResponse.off("close", done)
523
+ resume(Effect.void)
524
+ }
525
+ nodeResponse.once("close", done)
526
+ nodeResponse.end(done)
452
527
  })
453
528
  }
454
529
  const body = response.body
@@ -528,7 +603,7 @@ const handleResponse = (
528
603
  }
529
604
  case "Stream": {
530
605
  nodeResponse.writeHead(response.status, headers)
531
- const drainLatch = Effect.makeLatchUnsafe()
606
+ const drainLatch = Latch.makeUnsafe()
532
607
  nodeResponse.on("drain", () => drainLatch.openUnsafe())
533
608
  return body.stream.pipe(
534
609
  Stream.orDie,
@@ -1,18 +1,31 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Accessors for the Node.js objects behind an Effect HTTP server request.
3
+ *
4
+ * `toIncomingMessage` returns the underlying Node `http.IncomingMessage`.
5
+ * `toServerResponse` returns the underlying Node `http.ServerResponse`,
6
+ * evaluating the stored response thunk when the response was created lazily.
7
+ *
8
+ * @since 4.0.0
3
9
  */
4
10
  import type { HttpServerRequest } from "effect/unstable/http/HttpServerRequest"
5
11
  import type * as Http from "node:http"
6
12
 
7
13
  /**
8
- * @since 1.0.0
9
- * @category Accessors
14
+ * Returns the underlying Node `IncomingMessage` for a platform Node
15
+ * `HttpServerRequest`.
16
+ *
17
+ * @category accessors
18
+ * @since 4.0.0
10
19
  */
11
20
  export const toIncomingMessage = (self: HttpServerRequest): Http.IncomingMessage => self.source as any
12
21
 
13
22
  /**
14
- * @since 1.0.0
15
- * @category Accessors
23
+ * Returns the underlying Node `ServerResponse` for a platform Node
24
+ * `HttpServerRequest`, evaluating the stored response thunk when the response
25
+ * was created lazily.
26
+ *
27
+ * @category accessors
28
+ * @since 4.0.0
16
29
  */
17
30
  export const toServerResponse = (self: HttpServerRequest): Http.ServerResponse => {
18
31
  const res = (self as any).response
@@ -1,5 +1,14 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Node.js multipart parsing for HTTP `multipart/form-data` request bodies.
3
+ *
4
+ * `NodeMultipart` adapts a Node `Readable` plus incoming HTTP headers into
5
+ * Effect's shared multipart model. It can expose form parts as a stream or
6
+ * collect a complete persisted form by writing file uploads to scoped temporary
7
+ * files through the current `FileSystem` and `Path` services. `fileToReadable`
8
+ * returns the underlying Node readable stream for file parts produced by this
9
+ * parser.
10
+ *
11
+ * @since 4.0.0
3
12
  */
4
13
  import * as Effect from "effect/Effect"
5
14
  import type * as FileSystem from "effect/FileSystem"
@@ -16,8 +25,12 @@ import * as NodeStreamP from "node:stream/promises"
16
25
  import * as NodeStream from "./NodeStream.ts"
17
26
 
18
27
  /**
19
- * @since 1.0.0
28
+ * Parses multipart data from a Node readable request body and headers into a
29
+ * stream of `Multipart.Part` values, converting parser failures to
30
+ * `MultipartError`.
31
+ *
20
32
  * @category constructors
33
+ * @since 4.0.0
21
34
  */
22
35
  export const stream = (
23
36
  source: Readable,
@@ -39,8 +52,11 @@ export const stream = (
39
52
  )
40
53
 
41
54
  /**
42
- * @since 1.0.0
55
+ * Parses multipart data from a Node readable request body and persists file
56
+ * parts using the current `FileSystem`, `Path`, and `Scope` services.
57
+ *
43
58
  * @category constructors
59
+ * @since 4.0.0
44
60
  */
45
61
  export const persisted = (
46
62
  source: Readable,
@@ -57,7 +73,11 @@ export const persisted = (
57
73
  }))
58
74
 
59
75
  /**
60
- * @since 1.0.0
76
+ * Returns the underlying Node readable stream for a multipart file produced by
77
+ * the Node multipart parser.
78
+ *
79
+ * @category converting
80
+ * @since 4.0.0
61
81
  */
62
82
  export const fileToReadable = (file: Multipart.File): Readable => (file as FileImpl).file
63
83
 
package/src/NodePath.ts CHANGED
@@ -1,24 +1,40 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Node.js layers for Effect's `Path` service.
3
+ *
4
+ * This module provides the default, POSIX, and Windows variants of the
5
+ * platform-independent `Path` service by reusing the shared Node path
6
+ * implementation. The provided path services include Node file URL conversion
7
+ * behavior.
8
+ *
9
+ * @since 4.0.0
3
10
  */
4
11
  import * as NodePath from "@effect/platform-node-shared/NodePath"
5
12
  import type * as Layer from "effect/Layer"
6
13
  import type { Path } from "effect/Path"
7
14
 
8
15
  /**
9
- * @since 1.0.0
10
- * @category layer
16
+ * Provides the default Node `Path` service using the platform's `node:path`
17
+ * implementation.
18
+ *
19
+ * @category layers
20
+ * @since 4.0.0
11
21
  */
12
22
  export const layer: Layer.Layer<Path> = NodePath.layer
13
23
 
14
24
  /**
15
- * @since 1.0.0
16
- * @category layer
25
+ * Provides the `Path` service using Node's POSIX path implementation,
26
+ * regardless of the host platform.
27
+ *
28
+ * @category layers
29
+ * @since 4.0.0
17
30
  */
18
31
  export const layerPosix: Layer.Layer<Path> = NodePath.layerPosix
19
32
 
20
33
  /**
21
- * @since 1.0.0
22
- * @category layer
34
+ * Provides the `Path` service using Node's Windows path implementation,
35
+ * regardless of the host platform.
36
+ *
37
+ * @category layers
38
+ * @since 4.0.0
23
39
  */
24
40
  export const layerWin32: Layer.Layer<Path> = NodePath.layerWin32
package/src/NodeRedis.ts CHANGED
@@ -1,20 +1,32 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Node.js Redis integration backed by `ioredis`.
3
+ *
4
+ * This module creates a scoped `ioredis` client and exposes it in two forms:
5
+ * the generic `Redis` service and the {@link NodeRedis} service for direct
6
+ * access to the underlying client. `layer` accepts ioredis options directly,
7
+ * while `layerConfig` reads them from Effect config. Both layers close the
8
+ * client when the layer scope ends.
9
+ *
10
+ * @since 4.0.0
3
11
  */
4
12
  import * as Config from "effect/Config"
13
+ import * as Context from "effect/Context"
5
14
  import * as Effect from "effect/Effect"
6
15
  import * as Fn from "effect/Function"
7
16
  import * as Layer from "effect/Layer"
8
17
  import * as Scope from "effect/Scope"
9
- import * as ServiceMap from "effect/ServiceMap"
10
18
  import * as Redis from "effect/unstable/persistence/Redis"
11
19
  import * as IoRedis from "ioredis"
12
20
 
13
21
  /**
14
- * @since 1.0.0
15
- * @category Service
22
+ * Service tag for the Node Redis integration, exposing the underlying
23
+ * `ioredis` client and a `use` helper that maps client failures to
24
+ * `RedisError`.
25
+ *
26
+ * @category services
27
+ * @since 4.0.0
16
28
  */
17
- export class NodeRedis extends ServiceMap.Service<NodeRedis, {
29
+ export class NodeRedis extends Context.Service<NodeRedis, {
18
30
  readonly client: IoRedis.Redis
19
31
  readonly use: <A>(f: (client: IoRedis.Redis) => Promise<A>) => Effect.Effect<A, Redis.RedisError>
20
32
  }>()("@effect/platform-node/NodeRedis") {}
@@ -45,30 +57,36 @@ const make = Effect.fnUntraced(function*(
45
57
  use
46
58
  })
47
59
 
48
- return ServiceMap.make(NodeRedis, nodeRedis).pipe(
49
- ServiceMap.add(Redis.Redis, redis)
60
+ return Context.make(NodeRedis, nodeRedis).pipe(
61
+ Context.add(Redis.Redis, redis)
50
62
  )
51
63
  })
52
64
 
53
65
  /**
54
- * @since 1.0.0
55
- * @category Layers
66
+ * Provides `Redis` and `NodeRedis` services backed by an `ioredis` client
67
+ * created with the supplied options and closed when the layer scope ends.
68
+ *
69
+ * @category layers
70
+ * @since 4.0.0
56
71
  */
57
72
  export const layer = (
58
73
  options?: IoRedis.RedisOptions | undefined
59
- ): Layer.Layer<Redis.Redis | NodeRedis> => Layer.effectServices(make(options))
74
+ ): Layer.Layer<Redis.Redis | NodeRedis> => Layer.effectContext(make(options))
60
75
 
61
76
  /**
62
- * @since 1.0.0
63
- * @category Layers
77
+ * Provides `Redis` and `NodeRedis` services from `Config`-backed ioredis
78
+ * options, closing the client when the layer scope ends.
79
+ *
80
+ * @category layers
81
+ * @since 4.0.0
64
82
  */
65
83
  export const layerConfig: (
66
84
  options: Config.Wrap<IoRedis.RedisOptions>
67
85
  ) => Layer.Layer<Redis.Redis | NodeRedis, Config.ConfigError> = (
68
86
  options: Config.Wrap<IoRedis.RedisOptions>
69
87
  ): Layer.Layer<Redis.Redis | NodeRedis, Config.ConfigError> =>
70
- Layer.effectServices(
71
- Config.unwrap(options).asEffect().pipe(
88
+ Layer.effectContext(
89
+ Config.unwrap(options).pipe(
72
90
  Effect.flatMap(make)
73
91
  )
74
92
  )