@effect/platform-node 4.0.0-beta.8 → 4.0.0-beta.80

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 (123) hide show
  1. package/dist/Mime.d.ts +9 -3
  2. package/dist/Mime.d.ts.map +1 -1
  3. package/dist/Mime.js +9 -3
  4. package/dist/Mime.js.map +1 -1
  5. package/dist/NodeChildProcessSpawner.d.ts +1 -1
  6. package/dist/NodeChildProcessSpawner.js +1 -1
  7. package/dist/NodeClusterHttp.d.ts +25 -7
  8. package/dist/NodeClusterHttp.d.ts.map +1 -1
  9. package/dist/NodeClusterHttp.js +20 -10
  10. package/dist/NodeClusterHttp.js.map +1 -1
  11. package/dist/NodeClusterSocket.d.ts +37 -11
  12. package/dist/NodeClusterSocket.d.ts.map +1 -1
  13. package/dist/NodeClusterSocket.js +37 -11
  14. package/dist/NodeClusterSocket.js.map +1 -1
  15. package/dist/NodeCrypto.d.ts +10 -0
  16. package/dist/NodeCrypto.d.ts.map +1 -0
  17. package/dist/NodeCrypto.js +22 -0
  18. package/dist/NodeCrypto.js.map +1 -0
  19. package/dist/NodeFileSystem.d.ts +4 -2
  20. package/dist/NodeFileSystem.d.ts.map +1 -1
  21. package/dist/NodeFileSystem.js +12 -3
  22. package/dist/NodeFileSystem.js.map +1 -1
  23. package/dist/NodeHttpClient.d.ts +98 -29
  24. package/dist/NodeHttpClient.d.ts.map +1 -1
  25. package/dist/NodeHttpClient.js +120 -33
  26. package/dist/NodeHttpClient.js.map +1 -1
  27. package/dist/NodeHttpIncomingMessage.d.ts +36 -9
  28. package/dist/NodeHttpIncomingMessage.d.ts.map +1 -1
  29. package/dist/NodeHttpIncomingMessage.js +40 -8
  30. package/dist/NodeHttpIncomingMessage.js.map +1 -1
  31. package/dist/NodeHttpPlatform.d.ts +10 -4
  32. package/dist/NodeHttpPlatform.d.ts.map +1 -1
  33. package/dist/NodeHttpPlatform.js +20 -7
  34. package/dist/NodeHttpPlatform.js.map +1 -1
  35. package/dist/NodeHttpServer.d.ts +59 -19
  36. package/dist/NodeHttpServer.d.ts.map +1 -1
  37. package/dist/NodeHttpServer.js +102 -52
  38. package/dist/NodeHttpServer.js.map +1 -1
  39. package/dist/NodeHttpServerRequest.d.ts +18 -5
  40. package/dist/NodeHttpServerRequest.d.ts.map +1 -1
  41. package/dist/NodeHttpServerRequest.js +11 -4
  42. package/dist/NodeHttpServerRequest.js.map +1 -1
  43. package/dist/NodeMultipart.d.ts +24 -4
  44. package/dist/NodeMultipart.d.ts.map +1 -1
  45. package/dist/NodeMultipart.js +24 -4
  46. package/dist/NodeMultipart.js.map +1 -1
  47. package/dist/NodePath.d.ts +15 -6
  48. package/dist/NodePath.d.ts.map +1 -1
  49. package/dist/NodePath.js +23 -7
  50. package/dist/NodePath.js.map +1 -1
  51. package/dist/NodeRedis.d.ts +27 -9
  52. package/dist/NodeRedis.d.ts.map +1 -1
  53. package/dist/NodeRedis.js +30 -12
  54. package/dist/NodeRedis.js.map +1 -1
  55. package/dist/NodeRuntime.d.ts +27 -36
  56. package/dist/NodeRuntime.d.ts.map +1 -1
  57. package/dist/NodeRuntime.js +17 -13
  58. package/dist/NodeRuntime.js.map +1 -1
  59. package/dist/NodeServices.d.ts +19 -5
  60. package/dist/NodeServices.d.ts.map +1 -1
  61. package/dist/NodeServices.js +7 -3
  62. package/dist/NodeServices.js.map +1 -1
  63. package/dist/NodeSink.d.ts +2 -2
  64. package/dist/NodeSink.js +2 -2
  65. package/dist/NodeSocket.d.ts +18 -3
  66. package/dist/NodeSocket.d.ts.map +1 -1
  67. package/dist/NodeSocket.js +27 -4
  68. package/dist/NodeSocket.js.map +1 -1
  69. package/dist/NodeSocketServer.d.ts +2 -2
  70. package/dist/NodeSocketServer.js +2 -2
  71. package/dist/NodeStdio.d.ts +5 -2
  72. package/dist/NodeStdio.d.ts.map +1 -1
  73. package/dist/NodeStdio.js +13 -3
  74. package/dist/NodeStdio.js.map +1 -1
  75. package/dist/NodeStream.d.ts +2 -2
  76. package/dist/NodeStream.js +2 -2
  77. package/dist/NodeTerminal.d.ts +8 -2
  78. package/dist/NodeTerminal.d.ts.map +1 -1
  79. package/dist/NodeTerminal.js +15 -3
  80. package/dist/NodeTerminal.js.map +1 -1
  81. package/dist/NodeWorker.d.ts +9 -2
  82. package/dist/NodeWorker.d.ts.map +1 -1
  83. package/dist/NodeWorker.js +22 -6
  84. package/dist/NodeWorker.js.map +1 -1
  85. package/dist/NodeWorkerRunner.d.ts +5 -1
  86. package/dist/NodeWorkerRunner.d.ts.map +1 -1
  87. package/dist/NodeWorkerRunner.js +18 -5
  88. package/dist/NodeWorkerRunner.js.map +1 -1
  89. package/dist/Undici.d.ts +18 -5
  90. package/dist/Undici.d.ts.map +1 -1
  91. package/dist/Undici.js +18 -5
  92. package/dist/Undici.js.map +1 -1
  93. package/dist/index.d.ts +28 -26
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +28 -26
  96. package/dist/index.js.map +1 -1
  97. package/package.json +9 -9
  98. package/src/Mime.ts +10 -3
  99. package/src/NodeChildProcessSpawner.ts +1 -1
  100. package/src/NodeClusterHttp.ts +30 -11
  101. package/src/NodeClusterSocket.ts +37 -11
  102. package/src/NodeCrypto.ts +24 -0
  103. package/src/NodeFileSystem.ts +12 -3
  104. package/src/NodeHttpClient.ts +128 -38
  105. package/src/NodeHttpIncomingMessage.ts +48 -12
  106. package/src/NodeHttpPlatform.ts +21 -6
  107. package/src/NodeHttpServer.ts +124 -56
  108. package/src/NodeHttpServerRequest.ts +18 -5
  109. package/src/NodeMultipart.ts +24 -4
  110. package/src/NodePath.ts +23 -7
  111. package/src/NodeRedis.ts +32 -14
  112. package/src/NodeRuntime.ts +35 -37
  113. package/src/NodeServices.ts +21 -5
  114. package/src/NodeSink.ts +2 -2
  115. package/src/NodeSocket.ts +32 -4
  116. package/src/NodeSocketServer.ts +2 -2
  117. package/src/NodeStdio.ts +13 -3
  118. package/src/NodeStream.ts +2 -2
  119. package/src/NodeTerminal.ts +15 -3
  120. package/src/NodeWorker.ts +22 -6
  121. package/src/NodeWorkerRunner.ts +18 -5
  122. package/src/Undici.ts +18 -5
  123. package/src/index.ts +29 -26
@@ -1,18 +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"
10
23
  import * as Latch from "effect/Latch"
11
24
  import * as Layer from "effect/Layer"
25
+ import type * as Option from "effect/Option"
12
26
  import type * as Path from "effect/Path"
13
27
  import type * as Record from "effect/Record"
14
28
  import * as Scope from "effect/Scope"
15
- import * as ServiceMap from "effect/ServiceMap"
16
29
  import * as Stream from "effect/Stream"
17
30
  import * as Cookies from "effect/unstable/http/Cookies"
18
31
  import * as Etag from "effect/unstable/http/Etag"
@@ -27,7 +40,7 @@ import type * as HttpPlatform from "effect/unstable/http/HttpPlatform"
27
40
  import * as HttpServer from "effect/unstable/http/HttpServer"
28
41
  import {
29
42
  causeResponse,
30
- clientAbortFiberId,
43
+ ClientAbort,
31
44
  HttpServerError,
32
45
  RequestParseError,
33
46
  ResponseError,
@@ -50,30 +63,44 @@ import * as NodeServices from "./NodeServices.ts"
50
63
  import { NodeWS } from "./NodeSocket.ts"
51
64
 
52
65
  /**
53
- * @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
+ *
54
70
  * @category constructors
71
+ * @since 4.0.0
55
72
  */
56
73
  export const make = Effect.fnUntraced(function*(
57
74
  evaluate: LazyArg<Http.Server>,
58
- options: Net.ListenOptions
75
+ options: Net.ListenOptions & {
76
+ readonly disablePreemptiveShutdown?: boolean | undefined
77
+ readonly gracefulShutdownTimeout?: Duration.Input | undefined
78
+ }
59
79
  ) {
60
80
  const scope = yield* Effect.scope
61
81
  const server = evaluate()
62
- yield* Scope.addFinalizer(
63
- scope,
64
- Effect.callback<void>((resume) => {
65
- if (!server.listening) {
66
- 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)
67
92
  }
68
- server.close((error) => {
69
- if (error) {
70
- resume(Effect.die(error))
71
- } else {
72
- resume(Effect.void)
73
- }
74
- })
75
93
  })
76
- )
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)
77
104
 
78
105
  yield* Effect.callback<void, ServeError>((resume) => {
79
106
  function onError(cause: Error) {
@@ -111,7 +138,8 @@ export const make = Effect.fnUntraced(function*(
111
138
  port: address.port
112
139
  },
113
140
  serve: Effect.fnUntraced(function*(httpApp, middleware) {
114
- const scope = yield* Effect.scope
141
+ const serveScope = yield* Effect.scope
142
+ const scope = Scope.forkUnsafe(serveScope, "parallel")
115
143
  const handler = yield* (makeHandler(httpApp, {
116
144
  middleware: middleware as any,
117
145
  scope
@@ -120,12 +148,11 @@ export const make = Effect.fnUntraced(function*(
120
148
  middleware: middleware as any,
121
149
  scope
122
150
  })
123
- yield* Effect.addFinalizer(() =>
124
- Effect.sync(() => {
125
- server.off("request", handler)
126
- server.off("upgrade", upgradeHandler)
127
- })
128
- )
151
+ yield* Scope.addFinalizerExit(serveScope, () => {
152
+ server.off("request", handler)
153
+ server.off("upgrade", upgradeHandler)
154
+ return preemptiveShutdown
155
+ })
129
156
  server.on("request", handler)
130
157
  server.on("upgrade", upgradeHandler)
131
158
  })
@@ -133,8 +160,12 @@ export const make = Effect.fnUntraced(function*(
133
160
  })
134
161
 
135
162
  /**
136
- * @since 1.0.0
137
- * @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
138
169
  */
139
170
  export const makeHandler = <
140
171
  R,
@@ -152,26 +183,31 @@ export const makeHandler = <
152
183
  Exclude<Effect.Services<App>, HttpServerRequest | Scope.Scope>
153
184
  > => {
154
185
  const handled = HttpEffect.toHandled(httpEffect, handleResponse, options.middleware as any)
155
- return Effect.map(Effect.services<any>(), (services) => {
156
- return function handler(
186
+ return Effect.withFiber((parent) => {
187
+ const services = parent.context
188
+ return Effect.succeed(function handler(
157
189
  nodeRequest: Http.IncomingMessage,
158
190
  nodeResponse: Http.ServerResponse
159
191
  ) {
160
192
  const map = new Map(services.mapUnsafe)
161
193
  map.set(HttpServerRequest.key, new ServerRequestImpl(nodeRequest, nodeResponse))
162
- 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)
163
195
  nodeResponse.on("close", () => {
164
196
  if (!nodeResponse.writableEnded) {
165
- fiber.interruptUnsafe(clientAbortFiberId)
197
+ fiber.interruptUnsafe(parent.id, ClientAbort.annotation)
166
198
  }
167
199
  })
168
- }
200
+ })
169
201
  })
170
202
  }
171
203
 
172
204
  /**
173
- * @since 1.0.0
174
- * @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
175
211
  */
176
212
  export const makeUpgradeHandler = <
177
213
  R,
@@ -190,8 +226,13 @@ export const makeUpgradeHandler = <
190
226
  Exclude<Effect.Services<App>, HttpServerRequest | Scope.Scope>
191
227
  > => {
192
228
  const handledApp = HttpEffect.toHandled(httpEffect, handleResponse, options.middleware as any)
193
- return Effect.map(Effect.services<any>(), (services) =>
194
- (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
+ ) {
195
236
  let nodeResponse_: Http.ServerResponse | undefined = undefined
196
237
  const nodeResponse = () => {
197
238
  if (nodeResponse_ === undefined) {
@@ -217,13 +258,14 @@ export const makeUpgradeHandler = <
217
258
  ))
218
259
  const map = new Map(services.mapUnsafe)
219
260
  map.set(HttpServerRequest.key, new ServerRequestImpl(nodeRequest, nodeResponse, upgradeEffect))
220
- 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)
221
262
  socket.on("close", () => {
222
263
  if (!socket.writableEnded) {
223
- fiber.interruptUnsafe(clientAbortFiberId)
264
+ fiber.interruptUnsafe(parent.id, ClientAbort.annotation)
224
265
  }
225
266
  })
226
- }));
267
+ })
268
+ })
227
269
  }
228
270
 
229
271
  class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> implements HttpServerRequest {
@@ -239,7 +281,7 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
239
281
  upgradeEffect?: Effect.Effect<Socket.Socket, HttpServerError>,
240
282
  url = source.url!,
241
283
  headersOverride?: Headers.Headers,
242
- remoteAddressOverride?: string
284
+ remoteAddressOverride?: Option.Option<string>
243
285
  ) {
244
286
  super(source, (cause) =>
245
287
  new HttpServerError({
@@ -271,7 +313,7 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
271
313
  options: {
272
314
  readonly url?: string | undefined
273
315
  readonly headers?: Headers.Headers | undefined
274
- readonly remoteAddress?: string | undefined
316
+ readonly remoteAddress?: Option.Option<string> | undefined
275
317
  }
276
318
  ) {
277
319
  return new ServerRequestImpl(
@@ -280,7 +322,7 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
280
322
  this.upgradeEffect,
281
323
  options.url ?? this.url,
282
324
  options.headers ?? this.headersOverride,
283
- options.remoteAddress ?? this.remoteAddressOverride
325
+ "remoteAddress" in options ? options.remoteAddress : this.remoteAddressOverride
284
326
  )
285
327
  }
286
328
 
@@ -347,17 +389,26 @@ class ServerRequestImpl extends NodeHttpIncomingMessage<HttpServerError> impleme
347
389
  }
348
390
 
349
391
  /**
350
- * @since 1.0.0
351
- * @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
352
397
  */
353
398
  export const layerServer: (
354
399
  evaluate: LazyArg<Http.Server<typeof Http.IncomingMessage, typeof Http.ServerResponse>>,
355
- options: Net.ListenOptions
400
+ options: Net.ListenOptions & {
401
+ readonly disablePreemptiveShutdown?: boolean | undefined
402
+ readonly gracefulShutdownTimeout?: Duration.Input | undefined
403
+ }
356
404
  ) => Layer.Layer<HttpServer.HttpServer, ServeError> = flow(make, Layer.effect(HttpServer.HttpServer))
357
405
 
358
406
  /**
359
- * @since 1.0.0
360
- * @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
361
412
  */
362
413
  export const layerHttpServices: Layer.Layer<
363
414
  NodeServices.NodeServices | HttpPlatform.HttpPlatform | Etag.Generator
@@ -368,12 +419,18 @@ export const layerHttpServices: Layer.Layer<
368
419
  )
369
420
 
370
421
  /**
371
- * @since 1.0.0
372
- * @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
373
427
  */
374
428
  export const layer = (
375
429
  evaluate: LazyArg<Http.Server>,
376
- options: Net.ListenOptions
430
+ options: Net.ListenOptions & {
431
+ readonly disablePreemptiveShutdown?: boolean | undefined
432
+ readonly gracefulShutdownTimeout?: Duration.Input | undefined
433
+ }
377
434
  ): Layer.Layer<
378
435
  HttpServer.HttpServer | NodeServices.NodeServices | HttpPlatform.HttpPlatform | Etag.Generator,
379
436
  ServeError
@@ -384,26 +441,37 @@ export const layer = (
384
441
  )
385
442
 
386
443
  /**
387
- * @since 1.0.0
388
- * @category Layers
444
+ * Provides a Node `HttpServer` and HTTP support services, reading the listen
445
+ * and shutdown options from a `Config` value.
446
+ *
447
+ * @category layers
448
+ * @since 4.0.0
389
449
  */
390
450
  export const layerConfig = (
391
451
  evaluate: LazyArg<Http.Server>,
392
- options: Config.Wrap<Net.ListenOptions>
452
+ options: Config.Wrap<
453
+ Net.ListenOptions & {
454
+ readonly disablePreemptiveShutdown?: boolean | undefined
455
+ readonly gracefulShutdownTimeout?: Duration.Input | undefined
456
+ }
457
+ >
393
458
  ): Layer.Layer<
394
459
  HttpServer.HttpServer | FileSystem.FileSystem | Path.Path | HttpPlatform.HttpPlatform | Etag.Generator,
395
460
  ServeError | Config.ConfigError
396
461
  > =>
397
462
  Layer.mergeAll(
398
463
  Layer.effect(HttpServer.HttpServer)(
399
- Effect.flatMap(Config.unwrap(options).asEffect(), (options) => make(evaluate, options))
464
+ Effect.flatMap(Config.unwrap(options), (options) => make(evaluate, options))
400
465
  ),
401
466
  layerHttpServices
402
467
  )
403
468
 
404
469
  /**
405
- * @since 1.0.0
406
- * @category Testing
470
+ * Provides a test HTTP server listening on an ephemeral port together with a
471
+ * Fetch-backed `HttpClient` configured for server integration tests.
472
+ *
473
+ * @category testing
474
+ * @since 4.0.0
407
475
  */
408
476
  export const layerTest: Layer.Layer<
409
477
  | HttpServer.HttpServer
@@ -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
  )
@@ -1,5 +1,12 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Node.js process runner for Effect programs.
3
+ *
4
+ * This module exports `runMain`, which runs one Effect as the main process
5
+ * fiber in Node.js. It reuses the shared Node runtime runner, including its
6
+ * error reporting, `SIGINT` / `SIGTERM` interruption, and optional teardown
7
+ * behavior.
8
+ *
9
+ * @since 4.0.0
3
10
  */
4
11
  import * as NodeRuntime from "@effect/platform-node-shared/NodeRuntime"
5
12
  import type { Effect } from "effect/Effect"
@@ -8,6 +15,12 @@ import type * as Runtime from "effect/Runtime"
8
15
  /**
9
16
  * Helps you run a main effect with built-in error handling, logging, and signal management.
10
17
  *
18
+ * **When to use**
19
+ *
20
+ * Use to run a Node.js application's main Effect with structured error
21
+ * handling, log management, interrupt support, or advanced teardown
22
+ * capabilities.
23
+ *
11
24
  * **Details**
12
25
  *
13
26
  * This function launches an Effect as the main entry point, setting exit codes
@@ -16,26 +29,23 @@ import type * as Runtime from "effect/Runtime"
16
29
  * behaviors can be turned off. You can also provide custom teardown logic to
17
30
  * finalize resources or produce different exit codes.
18
31
  *
19
- * **Options**
20
- *
21
- * An optional object that can include:
32
+ * The optional configuration object can include:
22
33
  * - `disableErrorReporting`: Turn off automatic error logging.
23
- * - `disablePrettyLogger`: Avoid adding the pretty logger.
24
34
  * - `teardown`: Provide custom finalization logic.
25
35
  *
26
- * **When to Use**
27
- *
28
- * Use this function to run an Effect as your application’s main program, especially
29
- * when you need structured error handling, log management, interrupt support,
30
- * or advanced teardown capabilities.
31
- *
32
- * @since 1.0.0
33
- * @category Run main
36
+ * @category running
37
+ * @since 4.0.0
34
38
  */
35
39
  export const runMain: {
36
40
  /**
37
41
  * Helps you run a main effect with built-in error handling, logging, and signal management.
38
42
  *
43
+ * **When to use**
44
+ *
45
+ * Use to run a Node.js application's main Effect with structured error
46
+ * handling, log management, interrupt support, or advanced teardown
47
+ * capabilities.
48
+ *
39
49
  * **Details**
40
50
  *
41
51
  * This function launches an Effect as the main entry point, setting exit codes
@@ -44,21 +54,12 @@ export const runMain: {
44
54
  * behaviors can be turned off. You can also provide custom teardown logic to
45
55
  * finalize resources or produce different exit codes.
46
56
  *
47
- * **Options**
48
- *
49
- * An optional object that can include:
57
+ * The optional configuration object can include:
50
58
  * - `disableErrorReporting`: Turn off automatic error logging.
51
- * - `disablePrettyLogger`: Avoid adding the pretty logger.
52
59
  * - `teardown`: Provide custom finalization logic.
53
60
  *
54
- * **When to Use**
55
- *
56
- * Use this function to run an Effect as your application’s main program, especially
57
- * when you need structured error handling, log management, interrupt support,
58
- * or advanced teardown capabilities.
59
- *
60
- * @since 1.0.0
61
- * @category Run main
61
+ * @category running
62
+ * @since 4.0.0
62
63
  */
63
64
  (
64
65
  options?: {
@@ -69,6 +70,12 @@ export const runMain: {
69
70
  /**
70
71
  * Helps you run a main effect with built-in error handling, logging, and signal management.
71
72
  *
73
+ * **When to use**
74
+ *
75
+ * Use to run a Node.js application's main Effect with structured error
76
+ * handling, log management, interrupt support, or advanced teardown
77
+ * capabilities.
78
+ *
72
79
  * **Details**
73
80
  *
74
81
  * This function launches an Effect as the main entry point, setting exit codes
@@ -77,21 +84,12 @@ export const runMain: {
77
84
  * behaviors can be turned off. You can also provide custom teardown logic to
78
85
  * finalize resources or produce different exit codes.
79
86
  *
80
- * **Options**
81
- *
82
- * An optional object that can include:
87
+ * The optional configuration object can include:
83
88
  * - `disableErrorReporting`: Turn off automatic error logging.
84
- * - `disablePrettyLogger`: Avoid adding the pretty logger.
85
89
  * - `teardown`: Provide custom finalization logic.
86
90
  *
87
- * **When to Use**
88
- *
89
- * Use this function to run an Effect as your application’s main program, especially
90
- * when you need structured error handling, log management, interrupt support,
91
- * or advanced teardown capabilities.
92
- *
93
- * @since 1.0.0
94
- * @category Run main
91
+ * @category running
92
+ * @since 4.0.0
95
93
  */
96
94
  <E, A>(
97
95
  effect: Effect<A, E>,