@effect/platform-node 0.21.0 → 0.22.1
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/CommandExecutor/dist/effect-platform-node-CommandExecutor.cjs.dev.js +7 -2
- package/CommandExecutor/dist/effect-platform-node-CommandExecutor.cjs.prod.js +7 -2
- package/CommandExecutor/dist/effect-platform-node-CommandExecutor.esm.js +7 -2
- package/Http/FormData/dist/effect-platform-node-Http-FormData.cjs.dev.js +8 -3
- package/Http/FormData/dist/effect-platform-node-Http-FormData.cjs.prod.js +8 -3
- package/Http/FormData/dist/effect-platform-node-Http-FormData.esm.js +8 -3
- package/Http/NodeClient/dist/effect-platform-node-Http-NodeClient.cjs.dev.js +10 -4
- package/Http/NodeClient/dist/effect-platform-node-Http-NodeClient.cjs.prod.js +10 -4
- package/Http/NodeClient/dist/effect-platform-node-Http-NodeClient.esm.js +10 -4
- package/Http/Server/dist/effect-platform-node-Http-Server.cjs.dev.js +12 -8
- package/Http/Server/dist/effect-platform-node-Http-Server.cjs.prod.js +12 -8
- package/Http/Server/dist/effect-platform-node-Http-Server.esm.js +12 -8
- package/HttpClient/dist/effect-platform-node-HttpClient.cjs.dev.js +10 -4
- package/HttpClient/dist/effect-platform-node-HttpClient.cjs.prod.js +10 -4
- package/HttpClient/dist/effect-platform-node-HttpClient.esm.js +10 -4
- package/HttpServer/dist/effect-platform-node-HttpServer.cjs.dev.js +11 -7
- package/HttpServer/dist/effect-platform-node-HttpServer.cjs.prod.js +11 -7
- package/HttpServer/dist/effect-platform-node-HttpServer.esm.js +11 -7
- package/NodeContext/dist/effect-platform-node-NodeContext.cjs.dev.js +7 -2
- package/NodeContext/dist/effect-platform-node-NodeContext.cjs.prod.js +7 -2
- package/NodeContext/dist/effect-platform-node-NodeContext.esm.js +7 -2
- package/Sink/dist/effect-platform-node-Sink.cjs.dev.js +10 -8
- package/Sink/dist/effect-platform-node-Sink.cjs.prod.js +10 -8
- package/Sink/dist/effect-platform-node-Sink.esm.js +10 -8
- package/Stream/dist/effect-platform-node-Stream.cjs.dev.js +33 -2
- package/Stream/dist/effect-platform-node-Stream.cjs.mjs +3 -0
- package/Stream/dist/effect-platform-node-Stream.cjs.prod.js +33 -2
- package/Stream/dist/effect-platform-node-Stream.esm.js +31 -3
- package/dist/{FormData-d91e8016.cjs.prod.js → FormData-33600671.cjs.prod.js} +1 -1
- package/dist/{FormData-5ea8a8b6.esm.js → FormData-aba95773.esm.js} +1 -1
- package/dist/{FormData-15af6672.cjs.dev.js → FormData-b905ea51.cjs.dev.js} +1 -1
- package/dist/{NodeClient-3432a6a8.cjs.prod.js → NodeClient-174ebaf2.cjs.prod.js} +1 -1
- package/dist/{NodeClient-ebd71893.cjs.dev.js → NodeClient-86d70074.cjs.dev.js} +1 -1
- package/dist/{NodeClient-cd56cae8.esm.js → NodeClient-f1038dc6.esm.js} +1 -1
- package/dist/{Server-5dbcee7b.cjs.prod.js → Server-015ebdb2.cjs.prod.js} +2 -2
- package/dist/{Server-c08c825c.esm.js → Server-07db176b.esm.js} +2 -2
- package/dist/{Server-5f055bfd.cjs.dev.js → Server-d00836e3.cjs.dev.js} +2 -2
- package/dist/declarations/src/Sink.d.ts +1 -9
- package/dist/declarations/src/Sink.d.ts.map +1 -1
- package/dist/declarations/src/Stream.d.ts +34 -2
- package/dist/declarations/src/Stream.d.ts.map +1 -1
- package/dist/sink-5526bd6c.cjs.prod.js +52 -0
- package/dist/sink-a2069d86.cjs.dev.js +52 -0
- package/dist/sink-f7795af1.esm.js +28 -0
- package/dist/stream-36ca9d0a.esm.js +176 -0
- package/dist/stream-c01737c4.cjs.prod.js +210 -0
- package/dist/stream-c0c7bc20.cjs.dev.js +210 -0
- package/package.json +5 -5
- package/src/Sink.ts +1 -9
- package/src/Stream.ts +52 -3
- package/src/internal/sink.ts +28 -48
- package/src/internal/stream.ts +230 -49
- package/src/tsconfig.json +48 -0
- package/dist/sink-bd7ef408.esm.js +0 -34
- package/dist/sink-da49e187.cjs.prod.js +0 -57
- package/dist/sink-daf9e0e5.cjs.dev.js +0 -57
- package/dist/stream-1456ece0.cjs.dev.js +0 -120
- package/dist/stream-860139d3.esm.js +0 -94
- package/dist/stream-ef8b6a66.cjs.prod.js +0 -120
- /package/dist/{formData-632b1146.cjs.dev.js → formData-00b767b9.cjs.dev.js} +0 -0
- /package/dist/{formData-dd75bbe1.esm.js → formData-3a02d09f.esm.js} +0 -0
- /package/dist/{formData-ecf6742b.cjs.prod.js → formData-59e5f494.cjs.prod.js} +0 -0
- /package/dist/{incomingMessage-86bcf94d.cjs.dev.js → incomingMessage-587c8285.cjs.dev.js} +0 -0
- /package/dist/{incomingMessage-11c9bea6.esm.js → incomingMessage-6970f455.esm.js} +0 -0
- /package/dist/{incomingMessage-f56be93e.cjs.prod.js → incomingMessage-890fef7a.cjs.prod.js} +0 -0
package/src/Stream.ts
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
4
|
import type { SizeInput } from "@effect/platform/FileSystem"
|
|
5
|
+
import type { Channel } from "effect/Channel"
|
|
6
|
+
import type { Chunk } from "effect/Chunk"
|
|
5
7
|
import type { Effect } from "effect/Effect"
|
|
6
8
|
import type { LazyArg } from "effect/Function"
|
|
7
9
|
import type { Stream } from "effect/Stream"
|
|
8
|
-
import type { Readable } from "stream"
|
|
10
|
+
import type { Duplex, Readable } from "stream"
|
|
11
|
+
import type { PlatformError } from "./Error"
|
|
9
12
|
import * as internal from "./internal/stream"
|
|
10
13
|
|
|
11
14
|
/**
|
|
@@ -17,16 +20,62 @@ export interface FromReadableOptions {
|
|
|
17
20
|
readonly chunkSize?: SizeInput
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @category model
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
*/
|
|
27
|
+
export interface FromWritableOptions {
|
|
28
|
+
readonly endOnDone?: boolean
|
|
29
|
+
readonly encoding?: BufferEncoding
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
/**
|
|
21
33
|
* @category constructors
|
|
22
34
|
* @since 1.0.0
|
|
23
35
|
*/
|
|
24
|
-
export const fromReadable: <E, A>(
|
|
36
|
+
export const fromReadable: <E, A = Uint8Array>(
|
|
25
37
|
evaluate: LazyArg<Readable>,
|
|
26
38
|
onError: (error: unknown) => E,
|
|
27
|
-
|
|
39
|
+
{ chunkSize }?: FromReadableOptions
|
|
28
40
|
) => Stream<never, E, A> = internal.fromReadable
|
|
29
41
|
|
|
42
|
+
/**
|
|
43
|
+
* @category constructors
|
|
44
|
+
* @since 1.0.0
|
|
45
|
+
*/
|
|
46
|
+
export const fromDuplex: <IE, E, I = Uint8Array, O = Uint8Array>(
|
|
47
|
+
evaluate: LazyArg<Duplex>,
|
|
48
|
+
onError: (error: unknown) => E,
|
|
49
|
+
options?: FromReadableOptions & FromWritableOptions
|
|
50
|
+
) => Channel<never, IE, Chunk<I>, unknown, IE | E, Chunk<O>, void> = internal.fromDuplex
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @category combinators
|
|
54
|
+
* @since 1.0.0
|
|
55
|
+
*/
|
|
56
|
+
export const pipeThroughDuplex: {
|
|
57
|
+
<E2, B = Uint8Array>(
|
|
58
|
+
duplex: LazyArg<Duplex>,
|
|
59
|
+
onError: (error: unknown) => E2,
|
|
60
|
+
options?: FromReadableOptions & FromWritableOptions
|
|
61
|
+
): <R, E, A>(self: Stream<R, E, A>) => Stream<R, E2 | E, B>
|
|
62
|
+
<R, E, A, E2, B = Uint8Array>(
|
|
63
|
+
self: Stream<R, E, A>,
|
|
64
|
+
duplex: LazyArg<Duplex>,
|
|
65
|
+
onError: (error: unknown) => E2,
|
|
66
|
+
options?: FromReadableOptions & FromWritableOptions
|
|
67
|
+
): Stream<R, E | E2, B>
|
|
68
|
+
} = internal.pipeThroughDuplex
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @category combinators
|
|
72
|
+
* @since 1.0.0
|
|
73
|
+
*/
|
|
74
|
+
export const pipeThroughSimple: {
|
|
75
|
+
(duplex: LazyArg<Duplex>): <R, E>(self: Stream<R, E, string | Uint8Array>) => Stream<R, E | PlatformError, Uint8Array>
|
|
76
|
+
<R, E>(self: Stream<R, E, string | Uint8Array>, duplex: LazyArg<Duplex>): Stream<R, PlatformError | E, Uint8Array>
|
|
77
|
+
} = internal.pipeThroughSimple
|
|
78
|
+
|
|
30
79
|
/**
|
|
31
80
|
* @since 1.0.0
|
|
32
81
|
* @category conversions
|
package/src/internal/sink.ts
CHANGED
|
@@ -1,61 +1,41 @@
|
|
|
1
|
+
import * as Channel from "effect/Channel"
|
|
2
|
+
import type * as Chunk from "effect/Chunk"
|
|
1
3
|
import * as Effect from "effect/Effect"
|
|
2
4
|
import type { LazyArg } from "effect/Function"
|
|
3
|
-
import { pipe } from "effect/Function"
|
|
4
5
|
import * as Sink from "effect/Sink"
|
|
5
6
|
import type { Writable } from "node:stream"
|
|
6
|
-
import type { FromWritableOptions } from "../
|
|
7
|
+
import type { FromWritableOptions } from "../Stream"
|
|
8
|
+
import { writeEffect } from "./stream"
|
|
7
9
|
|
|
8
10
|
/** @internal */
|
|
9
|
-
export const fromWritable = <E, A>(
|
|
11
|
+
export const fromWritable = <E, A = Uint8Array>(
|
|
10
12
|
evaluate: LazyArg<Writable>,
|
|
11
13
|
onError: (error: unknown) => E,
|
|
12
|
-
|
|
14
|
+
options: FromWritableOptions = {}
|
|
13
15
|
): Sink.Sink<never, E, A, never, void> =>
|
|
14
|
-
|
|
15
|
-
makeSinkWithRelease<E, A>(evaluate, onError, encoding) :
|
|
16
|
-
makeSink<E, A>(evaluate, onError, encoding)
|
|
16
|
+
Sink.suspend(() => Sink.fromChannel(writeChannel(evaluate(), onError, options)))
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
onError: (error: unknown) => E,
|
|
28
|
-
encoding?: BufferEncoding
|
|
29
|
-
) =>
|
|
30
|
-
pipe(
|
|
31
|
-
Effect.acquireRelease(Effect.sync(stream), endWritable),
|
|
32
|
-
Effect.map((stream) => Sink.forEach(write<E, A>(stream, onError, encoding))),
|
|
33
|
-
Sink.unwrapScoped
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
const endWritable = (stream: Writable) =>
|
|
37
|
-
Effect.async<never, never, void>((resume) => {
|
|
38
|
-
if (stream.closed) {
|
|
39
|
-
resume(Effect.unit)
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
stream.end(() => resume(Effect.unit))
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
const write = <E, A>(stream: Writable, onError: (error: unknown) => E, encoding?: BufferEncoding) => (_: A) =>
|
|
47
|
-
Effect.async<never, E, void>((resume) => {
|
|
48
|
-
const cb = (err?: Error | null) => {
|
|
49
|
-
if (err) {
|
|
50
|
-
resume(Effect.fail(onError(err)))
|
|
51
|
-
} else {
|
|
18
|
+
const writeChannel = <IE, OE, A>(
|
|
19
|
+
writable: Writable,
|
|
20
|
+
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) {
|
|
52
27
|
resume(Effect.unit)
|
|
28
|
+
} else {
|
|
29
|
+
writable.end(() => resume(Effect.unit))
|
|
53
30
|
}
|
|
54
|
-
}
|
|
31
|
+
}) :
|
|
32
|
+
Channel.unit
|
|
55
33
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
+
}
|
package/src/internal/stream.ts
CHANGED
|
@@ -1,62 +1,26 @@
|
|
|
1
1
|
import type { SizeInput } from "@effect/platform/FileSystem"
|
|
2
|
+
import * as Channel from "effect/Channel"
|
|
3
|
+
import type * as AsyncInput from "effect/ChannelSingleProducerAsyncInput"
|
|
4
|
+
import * as Chunk from "effect/Chunk"
|
|
2
5
|
import * as Effect from "effect/Effect"
|
|
6
|
+
import * as Either from "effect/Either"
|
|
7
|
+
import * as Exit from "effect/Exit"
|
|
3
8
|
import type { LazyArg } from "effect/Function"
|
|
4
|
-
import { pipe } from "effect/Function"
|
|
5
|
-
import * as
|
|
9
|
+
import { dual, pipe } from "effect/Function"
|
|
10
|
+
import * as Queue from "effect/Queue"
|
|
6
11
|
import * as Stream from "effect/Stream"
|
|
7
|
-
import type { Readable } from "node:stream"
|
|
8
|
-
import type
|
|
12
|
+
import type { Duplex, Readable, Writable } from "node:stream"
|
|
13
|
+
import { type PlatformError, SystemError } from "../Error"
|
|
14
|
+
import type { FromReadableOptions, FromWritableOptions } from "../Stream"
|
|
9
15
|
|
|
10
16
|
/** @internal */
|
|
11
|
-
export const fromReadable = <E, A>(
|
|
17
|
+
export const fromReadable = <E, A = Uint8Array>(
|
|
12
18
|
evaluate: LazyArg<Readable>,
|
|
13
19
|
onError: (error: unknown) => E,
|
|
14
20
|
{ chunkSize }: FromReadableOptions = {}
|
|
15
21
|
): Stream.Stream<never, E, A> =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Effect.sync(() => {
|
|
19
|
-
stream.removeAllListeners()
|
|
20
|
-
|
|
21
|
-
if (!stream.closed) {
|
|
22
|
-
stream.destroy()
|
|
23
|
-
}
|
|
24
|
-
})),
|
|
25
|
-
Effect.map((stream) =>
|
|
26
|
-
Stream.async<never, E, Readable>((emit) => {
|
|
27
|
-
stream.once("error", (err) => {
|
|
28
|
-
emit.fail(onError(err))
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
// The 'close' event is emitted after a process has ended and the stdio
|
|
32
|
-
// streams of a child process have been closed. This is distinct from
|
|
33
|
-
// the 'exit' event, since multiple processes might share the same
|
|
34
|
-
// stdio streams. The 'close' event will always emit after 'exit' was
|
|
35
|
-
// already emitted, or 'error' if the child failed to spawn.
|
|
36
|
-
stream.once("close", () => {
|
|
37
|
-
emit.end()
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
stream.on("readable", () => {
|
|
41
|
-
emit.single(stream)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
if (stream.readable) {
|
|
45
|
-
emit.single(stream)
|
|
46
|
-
}
|
|
47
|
-
}, 1)
|
|
48
|
-
),
|
|
49
|
-
Stream.unwrapScoped,
|
|
50
|
-
Stream.flatMap((_) => Stream.repeatEffectOption(readChunk<A>(_, chunkSize)))
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
const readChunk = <A>(
|
|
54
|
-
stream: Readable,
|
|
55
|
-
size: SizeInput | undefined
|
|
56
|
-
): Effect.Effect<never, Option.Option<never>, A> =>
|
|
57
|
-
pipe(
|
|
58
|
-
Effect.sync(() => (size ? stream.read(Number(size)) : stream.read()) as A | null),
|
|
59
|
-
Effect.flatMap((_) => (_ ? Effect.succeed(_) : Effect.fail(Option.none())))
|
|
22
|
+
Stream.fromChannel(
|
|
23
|
+
readChannel<E, A>(evaluate, onError, chunkSize ? Number(chunkSize) : undefined)
|
|
60
24
|
)
|
|
61
25
|
|
|
62
26
|
/** @internal */
|
|
@@ -141,3 +105,220 @@ export const toUint8Array = <E>(
|
|
|
141
105
|
})
|
|
142
106
|
)
|
|
143
107
|
}
|
|
108
|
+
|
|
109
|
+
/** @internal */
|
|
110
|
+
export const fromDuplex = <IE, E, I = Uint8Array, O = Uint8Array>(
|
|
111
|
+
evaluate: LazyArg<Duplex>,
|
|
112
|
+
onError: (error: unknown) => E,
|
|
113
|
+
options: FromReadableOptions & FromWritableOptions = {}
|
|
114
|
+
): Channel.Channel<never, IE, Chunk.Chunk<I>, unknown, IE | E, Chunk.Chunk<O>, void> =>
|
|
115
|
+
Channel.acquireUseRelease(
|
|
116
|
+
Effect.tap(
|
|
117
|
+
Effect.zip(
|
|
118
|
+
Effect.sync(evaluate),
|
|
119
|
+
Queue.unbounded<Either.Either<Exit.Exit<IE | E, void>, void>>()
|
|
120
|
+
),
|
|
121
|
+
([duplex, queue]) => readableOffer(duplex, queue, onError)
|
|
122
|
+
),
|
|
123
|
+
([duplex, queue]) =>
|
|
124
|
+
Channel.embedInput(
|
|
125
|
+
readableTake(duplex, queue, options.chunkSize ? Number(options.chunkSize) : undefined),
|
|
126
|
+
writeInput(duplex, queue, onError, options)
|
|
127
|
+
),
|
|
128
|
+
([duplex, queue]) =>
|
|
129
|
+
Effect.zipRight(
|
|
130
|
+
Effect.sync(() => {
|
|
131
|
+
duplex.removeAllListeners()
|
|
132
|
+
if (!duplex.closed) {
|
|
133
|
+
duplex.destroy()
|
|
134
|
+
}
|
|
135
|
+
}),
|
|
136
|
+
Queue.shutdown(queue)
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
/** @internal */
|
|
141
|
+
export const pipeThroughDuplex = dual<
|
|
142
|
+
<E2, B = Uint8Array>(
|
|
143
|
+
duplex: LazyArg<Duplex>,
|
|
144
|
+
onError: (error: unknown) => E2,
|
|
145
|
+
options?: FromReadableOptions & FromWritableOptions
|
|
146
|
+
) => <R, E, A>(self: Stream.Stream<R, E, A>) => Stream.Stream<R, E | E2, B>,
|
|
147
|
+
<R, E, A, E2, B = Uint8Array>(
|
|
148
|
+
self: Stream.Stream<R, E, A>,
|
|
149
|
+
duplex: LazyArg<Duplex>,
|
|
150
|
+
onError: (error: unknown) => E2,
|
|
151
|
+
options?: FromReadableOptions & FromWritableOptions
|
|
152
|
+
) => Stream.Stream<R, E | E2, B>
|
|
153
|
+
>(
|
|
154
|
+
(args) => Stream.StreamTypeId in args[0],
|
|
155
|
+
(self, duplex, onError, options) =>
|
|
156
|
+
Stream.pipeThroughChannelOrFail(
|
|
157
|
+
self,
|
|
158
|
+
fromDuplex(duplex, onError, options)
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
/** @internal */
|
|
163
|
+
export const pipeThroughSimple = dual<
|
|
164
|
+
(
|
|
165
|
+
duplex: LazyArg<Duplex>
|
|
166
|
+
) => <R, E>(self: Stream.Stream<R, E, string | Uint8Array>) => Stream.Stream<R, E | PlatformError, Uint8Array>,
|
|
167
|
+
<R, E>(
|
|
168
|
+
self: Stream.Stream<R, E, string | Uint8Array>,
|
|
169
|
+
duplex: LazyArg<Duplex>
|
|
170
|
+
) => Stream.Stream<R, E | PlatformError, Uint8Array>
|
|
171
|
+
>(
|
|
172
|
+
2,
|
|
173
|
+
(self, duplex) =>
|
|
174
|
+
Stream.pipeThroughChannelOrFail(
|
|
175
|
+
self,
|
|
176
|
+
fromDuplex(duplex, (error) =>
|
|
177
|
+
SystemError({
|
|
178
|
+
module: "Stream",
|
|
179
|
+
method: "pipeThroughSimple",
|
|
180
|
+
pathOrDescriptor: "",
|
|
181
|
+
reason: "Unknown",
|
|
182
|
+
message: String(error)
|
|
183
|
+
}))
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
const readChannel = <E, A = Uint8Array>(
|
|
188
|
+
evaluate: LazyArg<Readable>,
|
|
189
|
+
onError: (error: unknown) => E,
|
|
190
|
+
chunkSize: number | undefined
|
|
191
|
+
): Channel.Channel<never, unknown, unknown, unknown, E, Chunk.Chunk<A>, void> =>
|
|
192
|
+
Channel.acquireUseRelease(
|
|
193
|
+
Effect.tap(
|
|
194
|
+
Effect.zip(
|
|
195
|
+
Effect.sync(evaluate),
|
|
196
|
+
Queue.unbounded<Either.Either<Exit.Exit<E, void>, void>>()
|
|
197
|
+
),
|
|
198
|
+
([readable, queue]) => readableOffer(readable, queue, onError)
|
|
199
|
+
),
|
|
200
|
+
([readable, queue]) => readableTake(readable, queue, chunkSize),
|
|
201
|
+
([readable, queue]) =>
|
|
202
|
+
Effect.zipRight(
|
|
203
|
+
Effect.sync(() => {
|
|
204
|
+
readable.removeAllListeners()
|
|
205
|
+
if (!readable.closed) {
|
|
206
|
+
readable.destroy()
|
|
207
|
+
}
|
|
208
|
+
}),
|
|
209
|
+
Queue.shutdown(queue)
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
const writeInput = <IE, E, A>(
|
|
214
|
+
writable: Writable,
|
|
215
|
+
queue: Queue.Queue<Either.Either<Exit.Exit<IE | E, void>, void>>,
|
|
216
|
+
onError: (error: unknown) => E,
|
|
217
|
+
{ encoding, endOnDone = true }: FromWritableOptions = {}
|
|
218
|
+
): AsyncInput.AsyncInputProducer<IE, Chunk.Chunk<A>, unknown> => {
|
|
219
|
+
const write = writeEffect(writable, onError, encoding)
|
|
220
|
+
const close = endOnDone ?
|
|
221
|
+
Effect.async<never, never, void>((resume) => {
|
|
222
|
+
if (writable.closed) {
|
|
223
|
+
resume(Effect.unit)
|
|
224
|
+
} else {
|
|
225
|
+
writable.end(() => resume(Effect.unit))
|
|
226
|
+
}
|
|
227
|
+
}) :
|
|
228
|
+
Effect.unit
|
|
229
|
+
return {
|
|
230
|
+
awaitRead: () => Effect.unit,
|
|
231
|
+
emit: (chunk) =>
|
|
232
|
+
Effect.catchAllCause(
|
|
233
|
+
write(chunk),
|
|
234
|
+
(cause) => Queue.offer(queue, Either.left(Exit.failCause(cause)))
|
|
235
|
+
),
|
|
236
|
+
error: (cause) =>
|
|
237
|
+
Effect.zipRight(
|
|
238
|
+
close,
|
|
239
|
+
Queue.offer(queue, Either.left(Exit.failCause(cause)))
|
|
240
|
+
),
|
|
241
|
+
done: (_) => close
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** @internal */
|
|
246
|
+
export const writeEffect =
|
|
247
|
+
<E, A>(writable: Writable, onError: (error: unknown) => E, encoding?: BufferEncoding) => (chunk: Chunk.Chunk<A>) =>
|
|
248
|
+
Effect.async<never, E, void>((resume) => {
|
|
249
|
+
const iterator = chunk[Symbol.iterator]()
|
|
250
|
+
function loop() {
|
|
251
|
+
const item = iterator.next()
|
|
252
|
+
if (item.done) {
|
|
253
|
+
resume(Effect.unit)
|
|
254
|
+
} else if (encoding) {
|
|
255
|
+
writable.write(item.value, encoding, onDone)
|
|
256
|
+
} else {
|
|
257
|
+
writable.write(item.value, onDone)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function onDone(err: unknown) {
|
|
261
|
+
if (err) {
|
|
262
|
+
resume(Effect.fail(onError(err)))
|
|
263
|
+
} else {
|
|
264
|
+
loop()
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
loop()
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
const readableOffer = <E>(
|
|
271
|
+
readable: Readable,
|
|
272
|
+
queue: Queue.Queue<Either.Either<Exit.Exit<E, void>, void>>,
|
|
273
|
+
onError: (error: unknown) => E
|
|
274
|
+
) =>
|
|
275
|
+
Effect.sync(() => {
|
|
276
|
+
readable.on("readable", () => {
|
|
277
|
+
const size = queue.unsafeSize()
|
|
278
|
+
if (size._tag === "Some" && size.value <= 0) {
|
|
279
|
+
queue.unsafeOffer(Either.right(void 0))
|
|
280
|
+
}
|
|
281
|
+
})
|
|
282
|
+
readable.on("error", (err) => {
|
|
283
|
+
queue.unsafeOffer(Either.left(Exit.fail(onError(err))))
|
|
284
|
+
})
|
|
285
|
+
readable.on("end", () => {
|
|
286
|
+
queue.unsafeOffer(Either.left(Exit.unit))
|
|
287
|
+
})
|
|
288
|
+
if (readable.readable) {
|
|
289
|
+
queue.unsafeOffer(Either.right(void 0))
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
const readableTake = <E, A>(
|
|
294
|
+
readable: Readable,
|
|
295
|
+
queue: Queue.Queue<Either.Either<Exit.Exit<E, void>, void>>,
|
|
296
|
+
chunkSize: number | undefined
|
|
297
|
+
) => {
|
|
298
|
+
const read = readChunkChannel<A>(readable, chunkSize)
|
|
299
|
+
const loop: Channel.Channel<never, unknown, unknown, unknown, E, Chunk.Chunk<A>, void> = pipe(
|
|
300
|
+
Channel.fromEffect(Queue.take(queue)),
|
|
301
|
+
Channel.flatMap(Either.match({
|
|
302
|
+
onLeft: Channel.fromEffect,
|
|
303
|
+
onRight: (_) => Channel.flatMap(read, () => loop)
|
|
304
|
+
}))
|
|
305
|
+
)
|
|
306
|
+
return loop
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const readChunkChannel = <A>(
|
|
310
|
+
readable: Readable,
|
|
311
|
+
chunkSize: number | undefined
|
|
312
|
+
) =>
|
|
313
|
+
Channel.flatMap(
|
|
314
|
+
Channel.sync(() => {
|
|
315
|
+
const arr: Array<A> = []
|
|
316
|
+
let chunk = readable.read(chunkSize)
|
|
317
|
+
while (chunk !== null) {
|
|
318
|
+
arr.push(chunk)
|
|
319
|
+
chunk = readable.read(chunkSize)
|
|
320
|
+
}
|
|
321
|
+
return Chunk.unsafeFromArray(arr)
|
|
322
|
+
}),
|
|
323
|
+
Channel.write
|
|
324
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"moduleDetection": "force",
|
|
4
|
+
"downlevelIteration": true,
|
|
5
|
+
"resolveJsonModule": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"emitDecoratorMetadata": true,
|
|
9
|
+
"experimentalDecorators": true,
|
|
10
|
+
"preserveSymlinks": true,
|
|
11
|
+
"moduleResolution": "NodeNext",
|
|
12
|
+
"lib": [
|
|
13
|
+
"ES2021",
|
|
14
|
+
"DOM",
|
|
15
|
+
"DOM.Iterable"
|
|
16
|
+
],
|
|
17
|
+
"sourceMap": true,
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noImplicitReturns": false,
|
|
20
|
+
"noUnusedLocals": true,
|
|
21
|
+
"noUnusedParameters": false,
|
|
22
|
+
"noFallthroughCasesInSwitch": true,
|
|
23
|
+
"noEmitOnError": false,
|
|
24
|
+
"allowJs": false,
|
|
25
|
+
"checkJs": false,
|
|
26
|
+
"forceConsistentCasingInFileNames": true,
|
|
27
|
+
"stripInternal": true,
|
|
28
|
+
"noImplicitAny": true,
|
|
29
|
+
"noImplicitThis": true,
|
|
30
|
+
"noUncheckedIndexedAccess": false,
|
|
31
|
+
"strictNullChecks": true,
|
|
32
|
+
"target": "ES2021",
|
|
33
|
+
"module": "NodeNext",
|
|
34
|
+
"incremental": true,
|
|
35
|
+
"removeComments": false,
|
|
36
|
+
"paths": {
|
|
37
|
+
"@effect/platform-node": [
|
|
38
|
+
"./index.ts"
|
|
39
|
+
],
|
|
40
|
+
"@effect/platform-node/*": [
|
|
41
|
+
"./*.ts"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"include": [
|
|
46
|
+
"**/*"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import * as Effect from 'effect/Effect';
|
|
2
|
-
import { pipe } from 'effect/Function';
|
|
3
|
-
import * as Sink from 'effect/Sink';
|
|
4
|
-
|
|
5
|
-
/** @internal */
|
|
6
|
-
const fromWritable = (evaluate, onError, {
|
|
7
|
-
encoding,
|
|
8
|
-
endOnClose = true
|
|
9
|
-
} = {}) => endOnClose ? makeSinkWithRelease(evaluate, onError, encoding) : makeSink(evaluate, onError, encoding);
|
|
10
|
-
const makeSink = (stream, onError, encoding) => pipe(Effect.sync(stream), Effect.map(stream => Sink.forEach(write(stream, onError, encoding))), Sink.unwrap);
|
|
11
|
-
const makeSinkWithRelease = (stream, onError, encoding) => pipe(Effect.acquireRelease(Effect.sync(stream), endWritable), Effect.map(stream => Sink.forEach(write(stream, onError, encoding))), Sink.unwrapScoped);
|
|
12
|
-
const endWritable = stream => Effect.async(resume => {
|
|
13
|
-
if (stream.closed) {
|
|
14
|
-
resume(Effect.unit);
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
stream.end(() => resume(Effect.unit));
|
|
18
|
-
});
|
|
19
|
-
const write = (stream, onError, encoding) => _ => Effect.async(resume => {
|
|
20
|
-
const cb = err => {
|
|
21
|
-
if (err) {
|
|
22
|
-
resume(Effect.fail(onError(err)));
|
|
23
|
-
} else {
|
|
24
|
-
resume(Effect.unit);
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
if (encoding) {
|
|
28
|
-
stream.write(_, encoding, cb);
|
|
29
|
-
} else {
|
|
30
|
-
stream.write(_, cb);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
export { fromWritable as f };
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var Effect = require('effect/Effect');
|
|
4
|
-
var Function = require('effect/Function');
|
|
5
|
-
var Sink = require('effect/Sink');
|
|
6
|
-
|
|
7
|
-
function _interopNamespace(e) {
|
|
8
|
-
if (e && e.__esModule) return e;
|
|
9
|
-
var n = Object.create(null);
|
|
10
|
-
if (e) {
|
|
11
|
-
Object.keys(e).forEach(function (k) {
|
|
12
|
-
if (k !== 'default') {
|
|
13
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
-
enumerable: true,
|
|
16
|
-
get: function () { return e[k]; }
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
n["default"] = e;
|
|
22
|
-
return Object.freeze(n);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
var Effect__namespace = /*#__PURE__*/_interopNamespace(Effect);
|
|
26
|
-
var Sink__namespace = /*#__PURE__*/_interopNamespace(Sink);
|
|
27
|
-
|
|
28
|
-
/** @internal */
|
|
29
|
-
const fromWritable = (evaluate, onError, {
|
|
30
|
-
encoding,
|
|
31
|
-
endOnClose = true
|
|
32
|
-
} = {}) => endOnClose ? makeSinkWithRelease(evaluate, onError, encoding) : makeSink(evaluate, onError, encoding);
|
|
33
|
-
const makeSink = (stream, onError, encoding) => Function.pipe(Effect__namespace.sync(stream), Effect__namespace.map(stream => Sink__namespace.forEach(write(stream, onError, encoding))), Sink__namespace.unwrap);
|
|
34
|
-
const makeSinkWithRelease = (stream, onError, encoding) => Function.pipe(Effect__namespace.acquireRelease(Effect__namespace.sync(stream), endWritable), Effect__namespace.map(stream => Sink__namespace.forEach(write(stream, onError, encoding))), Sink__namespace.unwrapScoped);
|
|
35
|
-
const endWritable = stream => Effect__namespace.async(resume => {
|
|
36
|
-
if (stream.closed) {
|
|
37
|
-
resume(Effect__namespace.unit);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
stream.end(() => resume(Effect__namespace.unit));
|
|
41
|
-
});
|
|
42
|
-
const write = (stream, onError, encoding) => _ => Effect__namespace.async(resume => {
|
|
43
|
-
const cb = err => {
|
|
44
|
-
if (err) {
|
|
45
|
-
resume(Effect__namespace.fail(onError(err)));
|
|
46
|
-
} else {
|
|
47
|
-
resume(Effect__namespace.unit);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
if (encoding) {
|
|
51
|
-
stream.write(_, encoding, cb);
|
|
52
|
-
} else {
|
|
53
|
-
stream.write(_, cb);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
exports.fromWritable = fromWritable;
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var Effect = require('effect/Effect');
|
|
4
|
-
var Function = require('effect/Function');
|
|
5
|
-
var Sink = require('effect/Sink');
|
|
6
|
-
|
|
7
|
-
function _interopNamespace(e) {
|
|
8
|
-
if (e && e.__esModule) return e;
|
|
9
|
-
var n = Object.create(null);
|
|
10
|
-
if (e) {
|
|
11
|
-
Object.keys(e).forEach(function (k) {
|
|
12
|
-
if (k !== 'default') {
|
|
13
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
-
enumerable: true,
|
|
16
|
-
get: function () { return e[k]; }
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
n["default"] = e;
|
|
22
|
-
return Object.freeze(n);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
var Effect__namespace = /*#__PURE__*/_interopNamespace(Effect);
|
|
26
|
-
var Sink__namespace = /*#__PURE__*/_interopNamespace(Sink);
|
|
27
|
-
|
|
28
|
-
/** @internal */
|
|
29
|
-
const fromWritable = (evaluate, onError, {
|
|
30
|
-
encoding,
|
|
31
|
-
endOnClose = true
|
|
32
|
-
} = {}) => endOnClose ? makeSinkWithRelease(evaluate, onError, encoding) : makeSink(evaluate, onError, encoding);
|
|
33
|
-
const makeSink = (stream, onError, encoding) => Function.pipe(Effect__namespace.sync(stream), Effect__namespace.map(stream => Sink__namespace.forEach(write(stream, onError, encoding))), Sink__namespace.unwrap);
|
|
34
|
-
const makeSinkWithRelease = (stream, onError, encoding) => Function.pipe(Effect__namespace.acquireRelease(Effect__namespace.sync(stream), endWritable), Effect__namespace.map(stream => Sink__namespace.forEach(write(stream, onError, encoding))), Sink__namespace.unwrapScoped);
|
|
35
|
-
const endWritable = stream => Effect__namespace.async(resume => {
|
|
36
|
-
if (stream.closed) {
|
|
37
|
-
resume(Effect__namespace.unit);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
stream.end(() => resume(Effect__namespace.unit));
|
|
41
|
-
});
|
|
42
|
-
const write = (stream, onError, encoding) => _ => Effect__namespace.async(resume => {
|
|
43
|
-
const cb = err => {
|
|
44
|
-
if (err) {
|
|
45
|
-
resume(Effect__namespace.fail(onError(err)));
|
|
46
|
-
} else {
|
|
47
|
-
resume(Effect__namespace.unit);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
if (encoding) {
|
|
51
|
-
stream.write(_, encoding, cb);
|
|
52
|
-
} else {
|
|
53
|
-
stream.write(_, cb);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
exports.fromWritable = fromWritable;
|