@effect/platform-node 0.22.1 → 0.23.0

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 (62) hide show
  1. package/CommandExecutor/dist/effect-platform-node-CommandExecutor.cjs.dev.js +3 -2
  2. package/CommandExecutor/dist/effect-platform-node-CommandExecutor.cjs.prod.js +3 -2
  3. package/CommandExecutor/dist/effect-platform-node-CommandExecutor.esm.js +3 -2
  4. package/Http/FormData/dist/effect-platform-node-Http-FormData.cjs.dev.js +3 -3
  5. package/Http/FormData/dist/effect-platform-node-Http-FormData.cjs.prod.js +3 -3
  6. package/Http/FormData/dist/effect-platform-node-Http-FormData.esm.js +3 -3
  7. package/Http/NodeClient/dist/effect-platform-node-Http-NodeClient.cjs.dev.js +5 -4
  8. package/Http/NodeClient/dist/effect-platform-node-Http-NodeClient.cjs.prod.js +5 -4
  9. package/Http/NodeClient/dist/effect-platform-node-Http-NodeClient.esm.js +5 -4
  10. package/Http/Server/dist/effect-platform-node-Http-Server.cjs.dev.js +6 -5
  11. package/Http/Server/dist/effect-platform-node-Http-Server.cjs.prod.js +6 -5
  12. package/Http/Server/dist/effect-platform-node-Http-Server.esm.js +6 -5
  13. package/HttpClient/dist/effect-platform-node-HttpClient.cjs.dev.js +5 -4
  14. package/HttpClient/dist/effect-platform-node-HttpClient.cjs.prod.js +5 -4
  15. package/HttpClient/dist/effect-platform-node-HttpClient.esm.js +5 -4
  16. package/HttpServer/dist/effect-platform-node-HttpServer.cjs.dev.js +7 -6
  17. package/HttpServer/dist/effect-platform-node-HttpServer.cjs.prod.js +7 -6
  18. package/HttpServer/dist/effect-platform-node-HttpServer.esm.js +7 -6
  19. package/NodeContext/dist/effect-platform-node-NodeContext.cjs.dev.js +3 -2
  20. package/NodeContext/dist/effect-platform-node-NodeContext.cjs.prod.js +3 -2
  21. package/NodeContext/dist/effect-platform-node-NodeContext.esm.js +3 -2
  22. package/Sink/dist/effect-platform-node-Sink.cjs.dev.js +3 -2
  23. package/Sink/dist/effect-platform-node-Sink.cjs.prod.js +3 -2
  24. package/Sink/dist/effect-platform-node-Sink.esm.js +3 -2
  25. package/Stream/dist/effect-platform-node-Stream.cjs.dev.js +1 -1
  26. package/Stream/dist/effect-platform-node-Stream.cjs.prod.js +1 -1
  27. package/Stream/dist/effect-platform-node-Stream.esm.js +1 -1
  28. package/dist/{FormData-b905ea51.cjs.dev.js → FormData-1b197f9f.cjs.dev.js} +1 -1
  29. package/dist/{FormData-aba95773.esm.js → FormData-9c8077af.esm.js} +1 -1
  30. package/dist/{FormData-33600671.cjs.prod.js → FormData-b4b59ecb.cjs.prod.js} +1 -1
  31. package/dist/{NodeClient-f1038dc6.esm.js → NodeClient-1b5f7152.esm.js} +2 -2
  32. package/dist/{NodeClient-86d70074.cjs.dev.js → NodeClient-433f41ed.cjs.dev.js} +2 -2
  33. package/dist/{NodeClient-174ebaf2.cjs.prod.js → NodeClient-8d8ff956.cjs.prod.js} +2 -2
  34. package/dist/{Server-015ebdb2.cjs.prod.js → Server-2dd836bc.cjs.prod.js} +3 -3
  35. package/dist/{Server-d00836e3.cjs.dev.js → Server-66eb964d.cjs.dev.js} +3 -3
  36. package/dist/{Server-07db176b.esm.js → Server-913d7080.esm.js} +3 -3
  37. package/dist/declarations/src/Sink.d.ts +2 -1
  38. package/dist/declarations/src/Sink.d.ts.map +1 -1
  39. package/dist/declarations/src/Stream.d.ts +9 -10
  40. package/dist/declarations/src/Stream.d.ts.map +1 -1
  41. package/dist/{formData-59e5f494.cjs.prod.js → formData-2d4168a3.cjs.prod.js} +1 -2
  42. package/dist/{formData-00b767b9.cjs.dev.js → formData-5d873a90.cjs.dev.js} +1 -2
  43. package/dist/{formData-3a02d09f.esm.js → formData-b50a3c9f.esm.js} +1 -2
  44. package/dist/{incomingMessage-890fef7a.cjs.prod.js → incomingMessage-4526b216.cjs.prod.js} +2 -4
  45. package/dist/{incomingMessage-6970f455.esm.js → incomingMessage-a56317f6.esm.js} +2 -4
  46. package/dist/{incomingMessage-587c8285.cjs.dev.js → incomingMessage-ac1817d4.cjs.dev.js} +2 -4
  47. package/dist/{sink-5526bd6c.cjs.prod.js → sink-3a150604.cjs.dev.js} +15 -19
  48. package/dist/{sink-a2069d86.cjs.dev.js → sink-570c8582.cjs.prod.js} +15 -19
  49. package/dist/sink-5dfcc09e.esm.js +23 -0
  50. package/dist/{stream-c01737c4.cjs.prod.js → stream-1667e8bf.cjs.prod.js} +29 -30
  51. package/dist/{stream-c0c7bc20.cjs.dev.js → stream-8bbecb96.cjs.dev.js} +29 -30
  52. package/dist/{stream-36ca9d0a.esm.js → stream-faaffb40.esm.js} +29 -30
  53. package/package.json +5 -3
  54. package/src/Sink.ts +2 -2
  55. package/src/Stream.ts +7 -10
  56. package/src/internal/http/formData.ts +1 -2
  57. package/src/internal/http/incomingMessage.ts +2 -4
  58. package/src/internal/http/nodeClient.ts +1 -1
  59. package/src/internal/http/server.ts +3 -1
  60. package/src/internal/sink.ts +39 -24
  61. package/src/internal/stream.ts +57 -57
  62. package/dist/sink-f7795af1.esm.js +0 -28
@@ -42,10 +42,10 @@ const fromReadable = (evaluate, onError, {
42
42
  } = {}) => Stream__namespace.fromChannel(readChannel(evaluate, onError, chunkSize ? Number(chunkSize) : undefined));
43
43
 
44
44
  /** @internal */
45
- const toString = options => {
45
+ const toString = (readable, options) => {
46
46
  const maxBytesNumber = options.maxBytes ? Number(options.maxBytes) : undefined;
47
47
  return Effect__namespace.acquireUseRelease(Effect__namespace.sync(() => {
48
- const stream = options.readable();
48
+ const stream = readable();
49
49
  stream.setEncoding(options.encoding ?? "utf8");
50
50
  return stream;
51
51
  }), stream => Effect__namespace.async(resume => {
@@ -66,16 +66,16 @@ const toString = options => {
66
66
  });
67
67
  }), stream => Effect__namespace.sync(() => {
68
68
  stream.removeAllListeners();
69
- if (!stream.closed) {
69
+ if ("closed" in stream && !stream.closed) {
70
70
  stream.destroy();
71
71
  }
72
72
  }));
73
73
  };
74
74
 
75
75
  /** @internal */
76
- const toUint8Array = options => {
76
+ const toUint8Array = (readable, options) => {
77
77
  const maxBytesNumber = options.maxBytes ? Number(options.maxBytes) : undefined;
78
- return Effect__namespace.acquireUseRelease(Effect__namespace.sync(options.readable), stream => Effect__namespace.async(resume => {
78
+ return Effect__namespace.acquireUseRelease(Effect__namespace.sync(readable), stream => Effect__namespace.async(resume => {
79
79
  let buffer = Buffer.alloc(0);
80
80
  let bytes = 0;
81
81
  stream.once("error", err => {
@@ -93,14 +93,14 @@ const toUint8Array = options => {
93
93
  });
94
94
  }), stream => Effect__namespace.sync(() => {
95
95
  stream.removeAllListeners();
96
- if (!stream.closed) {
96
+ if ("closed" in stream && !stream.closed) {
97
97
  stream.destroy();
98
98
  }
99
99
  }));
100
100
  };
101
101
 
102
102
  /** @internal */
103
- const fromDuplex = (evaluate, onError, options = {}) => Channel__namespace.acquireUseRelease(Effect__namespace.tap(Effect__namespace.zip(Effect__namespace.sync(evaluate), Queue__namespace.unbounded()), ([duplex, queue]) => readableOffer(duplex, queue, onError)), ([duplex, queue]) => Channel__namespace.embedInput(readableTake(duplex, queue, options.chunkSize ? Number(options.chunkSize) : undefined), writeInput(duplex, queue, onError, options)), ([duplex, queue]) => Effect__namespace.zipRight(Effect__namespace.sync(() => {
103
+ const fromDuplex = (evaluate, onError, options = {}) => Channel__namespace.acquireUseRelease(Effect__namespace.tap(Effect__namespace.zip(Effect__namespace.sync(evaluate), Queue__namespace.unbounded()), ([duplex, queue]) => readableOffer(duplex, queue, onError)), ([duplex, queue]) => Channel__namespace.embedInput(readableTake(duplex, queue, options.chunkSize ? Number(options.chunkSize) : undefined), writeInput(duplex, cause => Queue__namespace.offer(queue, Either__namespace.left(Exit__namespace.failCause(cause))), options)), ([duplex, queue]) => Effect__namespace.zipRight(Effect__namespace.sync(() => {
104
104
  duplex.removeAllListeners();
105
105
  if (!duplex.closed) {
106
106
  duplex.destroy();
@@ -120,48 +120,47 @@ const pipeThroughSimple = /*#__PURE__*/Function.dual(2, (self, duplex) => Stream
120
120
  }))));
121
121
  const readChannel = (evaluate, onError, chunkSize) => Channel__namespace.acquireUseRelease(Effect__namespace.tap(Effect__namespace.zip(Effect__namespace.sync(evaluate), Queue__namespace.unbounded()), ([readable, queue]) => readableOffer(readable, queue, onError)), ([readable, queue]) => readableTake(readable, queue, chunkSize), ([readable, queue]) => Effect__namespace.zipRight(Effect__namespace.sync(() => {
122
122
  readable.removeAllListeners();
123
- if (!readable.closed) {
123
+ if ("closed" in readable && !readable.closed) {
124
124
  readable.destroy();
125
125
  }
126
126
  }), Queue__namespace.shutdown(queue)));
127
- const writeInput = (writable, queue, onError, {
127
+
128
+ /** @internal */
129
+ const writeInput = (writable, onFailure, {
128
130
  encoding,
129
131
  endOnDone = true
130
- } = {}) => {
131
- const write = writeEffect(writable, onError, encoding);
132
+ }, onDone = Effect__namespace.unit) => {
133
+ const write = writeEffect(writable, encoding);
132
134
  const close = endOnDone ? Effect__namespace.async(resume => {
133
- if (writable.closed) {
135
+ if ("closed" in writable && writable.closed) {
134
136
  resume(Effect__namespace.unit);
135
137
  } else {
136
- writable.end(() => resume(Effect__namespace.unit));
138
+ writable.once("finish", () => resume(Effect__namespace.unit));
139
+ writable.end();
137
140
  }
138
141
  }) : Effect__namespace.unit;
139
142
  return {
140
143
  awaitRead: () => Effect__namespace.unit,
141
- emit: chunk => Effect__namespace.catchAllCause(write(chunk), cause => Queue__namespace.offer(queue, Either__namespace.left(Exit__namespace.failCause(cause)))),
142
- error: cause => Effect__namespace.zipRight(close, Queue__namespace.offer(queue, Either__namespace.left(Exit__namespace.failCause(cause)))),
143
- done: _ => close
144
+ emit: write,
145
+ error: cause => Effect__namespace.zipRight(close, onFailure(cause)),
146
+ done: _ => Effect__namespace.zipRight(close, onDone)
144
147
  };
145
148
  };
146
149
 
147
150
  /** @internal */
148
- const writeEffect = (writable, onError, encoding) => chunk => Effect__namespace.async(resume => {
151
+ const writeEffect = (writable, encoding) => chunk => chunk.length === 0 ? Effect__namespace.unit : Effect__namespace.async(resume => {
149
152
  const iterator = chunk[Symbol.iterator]();
153
+ let next = iterator.next();
150
154
  function loop() {
151
- const item = iterator.next();
152
- if (item.done) {
155
+ const item = next;
156
+ next = iterator.next();
157
+ const success = writable.write(item.value, encoding);
158
+ if (next.done) {
153
159
  resume(Effect__namespace.unit);
154
- } else if (encoding) {
155
- writable.write(item.value, encoding, onDone);
156
- } else {
157
- writable.write(item.value, onDone);
158
- }
159
- }
160
- function onDone(err) {
161
- if (err) {
162
- resume(Effect__namespace.fail(onError(err)));
163
- } else {
160
+ } else if (success) {
164
161
  loop();
162
+ } else {
163
+ writable.once("drain", loop);
165
164
  }
166
165
  }
167
166
  loop();
@@ -207,4 +206,4 @@ exports.pipeThroughDuplex = pipeThroughDuplex;
207
206
  exports.pipeThroughSimple = pipeThroughSimple;
208
207
  exports.toString = toString;
209
208
  exports.toUint8Array = toUint8Array;
210
- exports.writeEffect = writeEffect;
209
+ exports.writeInput = writeInput;
@@ -14,10 +14,10 @@ const fromReadable = (evaluate, onError, {
14
14
  } = {}) => Stream.fromChannel(readChannel(evaluate, onError, chunkSize ? Number(chunkSize) : undefined));
15
15
 
16
16
  /** @internal */
17
- const toString = options => {
17
+ const toString = (readable, options) => {
18
18
  const maxBytesNumber = options.maxBytes ? Number(options.maxBytes) : undefined;
19
19
  return Effect.acquireUseRelease(Effect.sync(() => {
20
- const stream = options.readable();
20
+ const stream = readable();
21
21
  stream.setEncoding(options.encoding ?? "utf8");
22
22
  return stream;
23
23
  }), stream => Effect.async(resume => {
@@ -38,16 +38,16 @@ const toString = options => {
38
38
  });
39
39
  }), stream => Effect.sync(() => {
40
40
  stream.removeAllListeners();
41
- if (!stream.closed) {
41
+ if ("closed" in stream && !stream.closed) {
42
42
  stream.destroy();
43
43
  }
44
44
  }));
45
45
  };
46
46
 
47
47
  /** @internal */
48
- const toUint8Array = options => {
48
+ const toUint8Array = (readable, options) => {
49
49
  const maxBytesNumber = options.maxBytes ? Number(options.maxBytes) : undefined;
50
- return Effect.acquireUseRelease(Effect.sync(options.readable), stream => Effect.async(resume => {
50
+ return Effect.acquireUseRelease(Effect.sync(readable), stream => Effect.async(resume => {
51
51
  let buffer = Buffer.alloc(0);
52
52
  let bytes = 0;
53
53
  stream.once("error", err => {
@@ -65,14 +65,14 @@ const toUint8Array = options => {
65
65
  });
66
66
  }), stream => Effect.sync(() => {
67
67
  stream.removeAllListeners();
68
- if (!stream.closed) {
68
+ if ("closed" in stream && !stream.closed) {
69
69
  stream.destroy();
70
70
  }
71
71
  }));
72
72
  };
73
73
 
74
74
  /** @internal */
75
- const fromDuplex = (evaluate, onError, options = {}) => Channel.acquireUseRelease(Effect.tap(Effect.zip(Effect.sync(evaluate), Queue.unbounded()), ([duplex, queue]) => readableOffer(duplex, queue, onError)), ([duplex, queue]) => Channel.embedInput(readableTake(duplex, queue, options.chunkSize ? Number(options.chunkSize) : undefined), writeInput(duplex, queue, onError, options)), ([duplex, queue]) => Effect.zipRight(Effect.sync(() => {
75
+ const fromDuplex = (evaluate, onError, options = {}) => Channel.acquireUseRelease(Effect.tap(Effect.zip(Effect.sync(evaluate), Queue.unbounded()), ([duplex, queue]) => readableOffer(duplex, queue, onError)), ([duplex, queue]) => Channel.embedInput(readableTake(duplex, queue, options.chunkSize ? Number(options.chunkSize) : undefined), writeInput(duplex, cause => Queue.offer(queue, Either.left(Exit.failCause(cause))), options)), ([duplex, queue]) => Effect.zipRight(Effect.sync(() => {
76
76
  duplex.removeAllListeners();
77
77
  if (!duplex.closed) {
78
78
  duplex.destroy();
@@ -92,48 +92,47 @@ const pipeThroughSimple = /*#__PURE__*/dual(2, (self, duplex) => Stream.pipeThro
92
92
  }))));
93
93
  const readChannel = (evaluate, onError, chunkSize) => Channel.acquireUseRelease(Effect.tap(Effect.zip(Effect.sync(evaluate), Queue.unbounded()), ([readable, queue]) => readableOffer(readable, queue, onError)), ([readable, queue]) => readableTake(readable, queue, chunkSize), ([readable, queue]) => Effect.zipRight(Effect.sync(() => {
94
94
  readable.removeAllListeners();
95
- if (!readable.closed) {
95
+ if ("closed" in readable && !readable.closed) {
96
96
  readable.destroy();
97
97
  }
98
98
  }), Queue.shutdown(queue)));
99
- const writeInput = (writable, queue, onError, {
99
+
100
+ /** @internal */
101
+ const writeInput = (writable, onFailure, {
100
102
  encoding,
101
103
  endOnDone = true
102
- } = {}) => {
103
- const write = writeEffect(writable, onError, encoding);
104
+ }, onDone = Effect.unit) => {
105
+ const write = writeEffect(writable, encoding);
104
106
  const close = endOnDone ? Effect.async(resume => {
105
- if (writable.closed) {
107
+ if ("closed" in writable && writable.closed) {
106
108
  resume(Effect.unit);
107
109
  } else {
108
- writable.end(() => resume(Effect.unit));
110
+ writable.once("finish", () => resume(Effect.unit));
111
+ writable.end();
109
112
  }
110
113
  }) : Effect.unit;
111
114
  return {
112
115
  awaitRead: () => Effect.unit,
113
- emit: chunk => Effect.catchAllCause(write(chunk), cause => Queue.offer(queue, Either.left(Exit.failCause(cause)))),
114
- error: cause => Effect.zipRight(close, Queue.offer(queue, Either.left(Exit.failCause(cause)))),
115
- done: _ => close
116
+ emit: write,
117
+ error: cause => Effect.zipRight(close, onFailure(cause)),
118
+ done: _ => Effect.zipRight(close, onDone)
116
119
  };
117
120
  };
118
121
 
119
122
  /** @internal */
120
- const writeEffect = (writable, onError, encoding) => chunk => Effect.async(resume => {
123
+ const writeEffect = (writable, encoding) => chunk => chunk.length === 0 ? Effect.unit : Effect.async(resume => {
121
124
  const iterator = chunk[Symbol.iterator]();
125
+ let next = iterator.next();
122
126
  function loop() {
123
- const item = iterator.next();
124
- if (item.done) {
127
+ const item = next;
128
+ next = iterator.next();
129
+ const success = writable.write(item.value, encoding);
130
+ if (next.done) {
125
131
  resume(Effect.unit);
126
- } else if (encoding) {
127
- writable.write(item.value, encoding, onDone);
128
- } else {
129
- writable.write(item.value, onDone);
130
- }
131
- }
132
- function onDone(err) {
133
- if (err) {
134
- resume(Effect.fail(onError(err)));
135
- } else {
132
+ } else if (success) {
136
133
  loop();
134
+ } else {
135
+ writable.once("drain", loop);
137
136
  }
138
137
  }
139
138
  loop();
@@ -173,4 +172,4 @@ const readChunkChannel = (readable, chunkSize) => Channel.flatMap(Channel.sync((
173
172
  return Chunk.unsafeFromArray(arr);
174
173
  }), Channel.write);
175
174
 
176
- export { fromDuplex as a, pipeThroughSimple as b, toUint8Array as c, fromReadable as f, pipeThroughDuplex as p, toString as t, writeEffect as w };
175
+ export { fromDuplex as a, pipeThroughSimple as b, toUint8Array as c, fromReadable as f, pipeThroughDuplex as p, toString as t, writeInput as w };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/platform-node",
3
- "version": "0.22.1",
3
+ "version": "0.23.0",
4
4
  "description": "Unified interfaces for common platform-specific services",
5
5
  "main": "dist/effect-platform-node.cjs.js",
6
6
  "module": "dist/effect-platform-node.esm.js",
@@ -36,7 +36,9 @@
36
36
  "@effect/schema": "^0.43.0",
37
37
  "@types/busboy": "^1.5.1",
38
38
  "@types/mime": "^3.0.2",
39
- "effect": "2.0.0-next.48"
39
+ "@types/tar": "^6.1.6",
40
+ "effect": "2.0.0-next.48",
41
+ "tar": "^6.2.0"
40
42
  },
41
43
  "peerDependencies": {
42
44
  "effect": "2.0.0-next.48"
@@ -44,7 +46,7 @@
44
46
  "dependencies": {
45
47
  "busboy": "^1.6.0",
46
48
  "mime": "^3.0.0",
47
- "@effect/platform": "^0.21.0"
49
+ "@effect/platform": "^0.22.0"
48
50
  },
49
51
  "files": [
50
52
  "src",
package/src/Sink.ts CHANGED
@@ -12,8 +12,8 @@ import type { FromWritableOptions } from "./Stream"
12
12
  * @category constructor
13
13
  * @since 1.0.0
14
14
  */
15
- export const fromWritable: <E, A>(
16
- evaluate: LazyArg<Writable>,
15
+ export const fromWritable: <E, A = string | Uint8Array>(
16
+ evaluate: LazyArg<Writable | NodeJS.WritableStream>,
17
17
  onError: (error: unknown) => E,
18
18
  options?: FromWritableOptions
19
19
  ) => Sink<never, E, A, never, void> = internal.fromWritable
package/src/Stream.ts CHANGED
@@ -34,7 +34,7 @@ export interface FromWritableOptions {
34
34
  * @since 1.0.0
35
35
  */
36
36
  export const fromReadable: <E, A = Uint8Array>(
37
- evaluate: LazyArg<Readable>,
37
+ evaluate: LazyArg<Readable | NodeJS.ReadableStream>,
38
38
  onError: (error: unknown) => E,
39
39
  { chunkSize }?: FromReadableOptions
40
40
  ) => Stream<never, E, A> = internal.fromReadable
@@ -81,11 +81,11 @@ export const pipeThroughSimple: {
81
81
  * @category conversions
82
82
  */
83
83
  export const toString: <E>(
84
+ readable: LazyArg<Readable | NodeJS.ReadableStream>,
84
85
  options: {
85
- readable: LazyArg<Readable>
86
- onFailure: (error: unknown) => E
87
- encoding?: BufferEncoding
88
- maxBytes?: SizeInput
86
+ readonly onFailure: (error: unknown) => E
87
+ readonly encoding?: BufferEncoding | undefined
88
+ readonly maxBytes?: SizeInput | undefined
89
89
  }
90
90
  ) => Effect<never, E, string> = internal.toString
91
91
 
@@ -94,9 +94,6 @@ export const toString: <E>(
94
94
  * @category conversions
95
95
  */
96
96
  export const toUint8Array: <E>(
97
- options: {
98
- readable: LazyArg<Readable>
99
- onFailure: (error: unknown) => E
100
- maxBytes?: SizeInput
101
- }
97
+ readable: LazyArg<Readable | NodeJS.ReadableStream>,
98
+ options: { readonly onFailure: (error: unknown) => E; readonly maxBytes?: SizeInput | undefined }
102
99
  ) => Effect<never, E, Uint8Array> = internal.toUint8Array
@@ -88,8 +88,7 @@ export const stream = (
88
88
  (part) =>
89
89
  part._tag === "File" && Chunk.some(fieldMimeTypes, (_) => part.contentType.includes(_)) ?
90
90
  Effect.map(
91
- NodeStream.toString({
92
- readable: () => part.source,
91
+ NodeStream.toString(() => part.source, {
93
92
  onFailure: (error) => FormData.FormDataError("InternalError", error)
94
93
  }),
95
94
  (content) => new FieldImpl(part.key, part.contentType, content)
@@ -37,8 +37,7 @@ export class IncomingMessageImpl<E> implements IncomingMessage.IncomingMessage<E
37
37
  Effect.flatMap(
38
38
  FiberRef.get(IncomingMessage.maxBodySize),
39
39
  (maxBodySize) =>
40
- NodeStream.toString({
41
- readable: () => this.source,
40
+ NodeStream.toString(() => this.source, {
42
41
  onFailure: this.onError,
43
42
  maxBytes: Option.getOrUndefined(maxBodySize)
44
43
  })
@@ -73,8 +72,7 @@ export class IncomingMessageImpl<E> implements IncomingMessage.IncomingMessage<E
73
72
  return Effect.flatMap(
74
73
  FiberRef.get(IncomingMessage.maxBodySize),
75
74
  (maxBodySize) =>
76
- NodeStream.toUint8Array({
77
- readable: () => this.source,
75
+ NodeStream.toUint8Array(() => this.source, {
78
76
  onFailure: this.onError,
79
77
  maxBytes: Option.getOrUndefined(maxBodySize)
80
78
  })
@@ -54,7 +54,7 @@ export const makeAgentLayer = (options?: Https.AgentOptions): Layer.Layer<never,
54
54
  export const agentLayer = makeAgentLayer()
55
55
 
56
56
  const fromAgent = (agent: NodeClient.HttpAgent): Client.Client.Default =>
57
- Client.make((request) =>
57
+ Client.makeDefault((request) =>
58
58
  Effect.flatMap(
59
59
  UrlParams.makeUrl(request.url, request.urlParams, (_) =>
60
60
  Error.RequestError({
@@ -79,7 +79,9 @@ export const make = (
79
79
  port: address.port
80
80
  },
81
81
  serve: (httpApp, middleware) => {
82
- const handledApp = middleware ? middleware(respond(httpApp)) : respond(httpApp)
82
+ const handledApp = middleware
83
+ ? middleware(App.withDefaultMiddleware(respond(httpApp)))
84
+ : App.withDefaultMiddleware(respond(httpApp))
83
85
  return Effect.flatMap(Effect.all([Effect.runtime(), Effect.fiberId]), ([runtime, fiberId]) => {
84
86
  const runFork = Runtime.runFork(runtime)
85
87
  function handler(nodeRequest: Http.IncomingMessage, nodeResponse: Http.ServerResponse) {
@@ -1,41 +1,56 @@
1
1
  import * as Channel from "effect/Channel"
2
2
  import type * as Chunk from "effect/Chunk"
3
+ import * as Deferred from "effect/Deferred"
3
4
  import * as Effect from "effect/Effect"
4
5
  import type { LazyArg } from "effect/Function"
5
6
  import * as Sink from "effect/Sink"
6
7
  import type { Writable } from "node:stream"
7
8
  import type { FromWritableOptions } from "../Stream"
8
- import { writeEffect } from "./stream"
9
+ import { writeInput } from "./stream"
9
10
 
10
11
  /** @internal */
11
- export const fromWritable = <E, A = Uint8Array>(
12
- evaluate: LazyArg<Writable>,
12
+ export const fromWritable = <E, A = Uint8Array | string>(
13
+ evaluate: LazyArg<Writable | NodeJS.WritableStream>,
13
14
  onError: (error: unknown) => E,
14
15
  options: FromWritableOptions = {}
15
16
  ): Sink.Sink<never, E, A, never, void> =>
16
17
  Sink.suspend(() => Sink.fromChannel(writeChannel(evaluate(), onError, options)))
17
18
 
18
19
  const writeChannel = <IE, OE, A>(
19
- writable: Writable,
20
+ writable: Writable | NodeJS.WritableStream,
20
21
  onError: (error: unknown) => OE,
21
- { encoding, endOnDone = true }: FromWritableOptions = {}
22
- ): Channel.Channel<never, IE, Chunk.Chunk<A>, unknown, IE | OE, Chunk.Chunk<never>, void> => {
23
- const write = writeEffect(writable, onError, encoding)
24
- const close = endOnDone ?
25
- Effect.async<never, never, void>((resume) => {
26
- if (writable.closed) {
27
- resume(Effect.unit)
28
- } else {
29
- writable.end(() => resume(Effect.unit))
30
- }
31
- }) :
32
- Channel.unit
22
+ options: FromWritableOptions = {}
23
+ ): Channel.Channel<never, IE, Chunk.Chunk<A>, unknown, IE | OE, Chunk.Chunk<never>, void> =>
24
+ Channel.flatMap(
25
+ Deferred.make<IE, void>(),
26
+ (deferred) => {
27
+ const input = writeInput<IE, A>(
28
+ writable,
29
+ (_) => Deferred.failCause(deferred, _),
30
+ options,
31
+ Deferred.complete(deferred, Effect.unit)
32
+ )
33
+ return Channel.embedInput(
34
+ writableOutput(writable, deferred, onError),
35
+ input
36
+ )
37
+ }
38
+ )
33
39
 
34
- const loop: Channel.Channel<never, IE, Chunk.Chunk<A>, unknown, OE | IE, Chunk.Chunk<never>, void> = Channel
35
- .readWithCause({
36
- onInput: (chunk: Chunk.Chunk<A>) => Channel.flatMap(Channel.fromEffect(write(chunk)), () => loop),
37
- onFailure: (cause) => Channel.zipRight(close, Channel.failCause(cause)),
38
- onDone: (_done) => close
39
- })
40
- return loop
41
- }
40
+ const writableOutput = <IE, E>(
41
+ writable: Writable | NodeJS.WritableStream,
42
+ deferred: Deferred.Deferred<IE, void>,
43
+ onError: (error: unknown) => E
44
+ ) =>
45
+ Effect.raceFirst(
46
+ Effect.async<never, E, never>((resume) => {
47
+ function handleError(err: unknown) {
48
+ resume(Effect.fail(onError(err)))
49
+ }
50
+ writable.on("error", handleError)
51
+ return Effect.sync(() => {
52
+ writable.off("error", handleError)
53
+ })
54
+ }),
55
+ Deferred.await(deferred)
56
+ )