@effect/platform-node-shared 0.57.1 → 4.0.0-beta.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.
Files changed (218) hide show
  1. package/README.md +3 -3
  2. package/dist/NodeChildProcessSpawner.d.ts +37 -0
  3. package/dist/NodeChildProcessSpawner.d.ts.map +1 -0
  4. package/dist/NodeChildProcessSpawner.js +567 -0
  5. package/dist/NodeChildProcessSpawner.js.map +1 -0
  6. package/dist/{dts/NodeClusterSocket.d.ts → NodeClusterSocket.d.ts} +4 -7
  7. package/dist/NodeClusterSocket.d.ts.map +1 -0
  8. package/dist/{esm/NodeClusterSocket.js → NodeClusterSocket.js} +9 -10
  9. package/dist/NodeClusterSocket.js.map +1 -0
  10. package/dist/NodeFileSystem.d.ts +8 -0
  11. package/dist/NodeFileSystem.d.ts.map +1 -0
  12. package/dist/{esm/internal/fileSystem.js → NodeFileSystem.js} +125 -96
  13. package/dist/NodeFileSystem.js.map +1 -0
  14. package/dist/NodePath.d.ts +18 -0
  15. package/dist/NodePath.d.ts.map +1 -0
  16. package/dist/NodePath.js +56 -0
  17. package/dist/NodePath.js.map +1 -0
  18. package/dist/NodeRuntime.d.ts +28 -0
  19. package/dist/NodeRuntime.d.ts.map +1 -0
  20. package/dist/{esm/internal/runtime.js → NodeRuntime.js} +8 -8
  21. package/dist/NodeRuntime.js.map +1 -0
  22. package/dist/NodeSink.d.ts +40 -0
  23. package/dist/NodeSink.d.ts.map +1 -0
  24. package/dist/NodeSink.js +50 -0
  25. package/dist/NodeSink.js.map +1 -0
  26. package/dist/{dts/NodeSocket.d.ts → NodeSocket.d.ts} +10 -10
  27. package/dist/NodeSocket.d.ts.map +1 -0
  28. package/dist/{esm/NodeSocket.js → NodeSocket.js} +51 -39
  29. package/dist/NodeSocket.js.map +1 -0
  30. package/dist/{dts/NodeSocketServer.d.ts → NodeSocketServer.d.ts} +8 -10
  31. package/dist/NodeSocketServer.d.ts.map +1 -0
  32. package/dist/NodeSocketServer.js +192 -0
  33. package/dist/NodeSocketServer.js.map +1 -0
  34. package/dist/NodeStdio.d.ts +11 -0
  35. package/dist/NodeStdio.d.ts.map +1 -0
  36. package/dist/NodeStdio.js +43 -0
  37. package/dist/NodeStdio.js.map +1 -0
  38. package/dist/NodeStream.d.ts +127 -0
  39. package/dist/NodeStream.d.ts.map +1 -0
  40. package/dist/NodeStream.js +249 -0
  41. package/dist/NodeStream.js.map +1 -0
  42. package/dist/NodeTerminal.d.ts +15 -0
  43. package/dist/NodeTerminal.d.ts.map +1 -0
  44. package/dist/{esm/internal/terminal.js → NodeTerminal.js} +28 -25
  45. package/dist/NodeTerminal.js.map +1 -0
  46. package/dist/internal/utils.d.ts +2 -0
  47. package/dist/internal/utils.d.ts.map +1 -0
  48. package/dist/{esm/internal/error.js → internal/utils.js} +4 -5
  49. package/dist/internal/utils.js.map +1 -0
  50. package/package.json +53 -124
  51. package/src/NodeChildProcessSpawner.ts +713 -0
  52. package/src/NodeClusterSocket.ts +12 -13
  53. package/src/NodeFileSystem.ts +632 -5
  54. package/src/NodePath.ts +48 -9
  55. package/src/NodeRuntime.ts +53 -4
  56. package/src/NodeSink.ts +65 -62
  57. package/src/NodeSocket.ts +65 -49
  58. package/src/NodeSocketServer.ts +108 -88
  59. package/src/NodeStdio.ts +49 -0
  60. package/src/NodeStream.ts +324 -83
  61. package/src/NodeTerminal.ts +100 -9
  62. package/src/internal/{error.ts → utils.ts} +6 -7
  63. package/NodeClusterSocket/package.json +0 -6
  64. package/NodeCommandExecutor/package.json +0 -6
  65. package/NodeFileSystem/ParcelWatcher/package.json +0 -6
  66. package/NodeFileSystem/package.json +0 -6
  67. package/NodeKeyValueStore/package.json +0 -6
  68. package/NodeMultipart/package.json +0 -6
  69. package/NodePath/package.json +0 -6
  70. package/NodeRuntime/package.json +0 -6
  71. package/NodeSink/package.json +0 -6
  72. package/NodeSocket/package.json +0 -6
  73. package/NodeSocketServer/package.json +0 -6
  74. package/NodeStream/package.json +0 -6
  75. package/NodeTerminal/package.json +0 -6
  76. package/dist/cjs/NodeClusterSocket.js +0 -50
  77. package/dist/cjs/NodeClusterSocket.js.map +0 -1
  78. package/dist/cjs/NodeCommandExecutor.js +0 -14
  79. package/dist/cjs/NodeCommandExecutor.js.map +0 -1
  80. package/dist/cjs/NodeFileSystem/ParcelWatcher.js +0 -20
  81. package/dist/cjs/NodeFileSystem/ParcelWatcher.js.map +0 -1
  82. package/dist/cjs/NodeFileSystem.js +0 -18
  83. package/dist/cjs/NodeFileSystem.js.map +0 -1
  84. package/dist/cjs/NodeKeyValueStore.js +0 -18
  85. package/dist/cjs/NodeKeyValueStore.js.map +0 -1
  86. package/dist/cjs/NodeMultipart.js +0 -24
  87. package/dist/cjs/NodeMultipart.js.map +0 -1
  88. package/dist/cjs/NodePath.js +0 -28
  89. package/dist/cjs/NodePath.js.map +0 -1
  90. package/dist/cjs/NodeRuntime.js +0 -14
  91. package/dist/cjs/NodeRuntime.js.map +0 -1
  92. package/dist/cjs/NodeSink.js +0 -50
  93. package/dist/cjs/NodeSink.js.map +0 -1
  94. package/dist/cjs/NodeSocket.js +0 -153
  95. package/dist/cjs/NodeSocket.js.map +0 -1
  96. package/dist/cjs/NodeSocketServer.js +0 -178
  97. package/dist/cjs/NodeSocketServer.js.map +0 -1
  98. package/dist/cjs/NodeStream.js +0 -76
  99. package/dist/cjs/NodeStream.js.map +0 -1
  100. package/dist/cjs/NodeTerminal.js +0 -19
  101. package/dist/cjs/NodeTerminal.js.map +0 -1
  102. package/dist/cjs/internal/commandExecutor.js +0 -153
  103. package/dist/cjs/internal/commandExecutor.js.map +0 -1
  104. package/dist/cjs/internal/error.js +0 -45
  105. package/dist/cjs/internal/error.js.map +0 -1
  106. package/dist/cjs/internal/fileSystem/parcelWatcher.js +0 -68
  107. package/dist/cjs/internal/fileSystem/parcelWatcher.js.map +0 -1
  108. package/dist/cjs/internal/fileSystem.js +0 -400
  109. package/dist/cjs/internal/fileSystem.js.map +0 -1
  110. package/dist/cjs/internal/multipart.js +0 -147
  111. package/dist/cjs/internal/multipart.js.map +0 -1
  112. package/dist/cjs/internal/path.js +0 -53
  113. package/dist/cjs/internal/path.js.map +0 -1
  114. package/dist/cjs/internal/runtime.js +0 -37
  115. package/dist/cjs/internal/runtime.js.map +0 -1
  116. package/dist/cjs/internal/sink.js +0 -28
  117. package/dist/cjs/internal/sink.js.map +0 -1
  118. package/dist/cjs/internal/stream.js +0 -233
  119. package/dist/cjs/internal/stream.js.map +0 -1
  120. package/dist/cjs/internal/terminal.js +0 -90
  121. package/dist/cjs/internal/terminal.js.map +0 -1
  122. package/dist/dts/NodeClusterSocket.d.ts.map +0 -1
  123. package/dist/dts/NodeCommandExecutor.d.ts +0 -12
  124. package/dist/dts/NodeCommandExecutor.d.ts.map +0 -1
  125. package/dist/dts/NodeFileSystem/ParcelWatcher.d.ts +0 -13
  126. package/dist/dts/NodeFileSystem/ParcelWatcher.d.ts.map +0 -1
  127. package/dist/dts/NodeFileSystem.d.ts +0 -11
  128. package/dist/dts/NodeFileSystem.d.ts.map +0 -1
  129. package/dist/dts/NodeKeyValueStore.d.ts +0 -12
  130. package/dist/dts/NodeKeyValueStore.d.ts.map +0 -1
  131. package/dist/dts/NodeMultipart.d.ts +0 -27
  132. package/dist/dts/NodeMultipart.d.ts.map +0 -1
  133. package/dist/dts/NodePath.d.ts +0 -21
  134. package/dist/dts/NodePath.d.ts.map +0 -1
  135. package/dist/dts/NodeRuntime.d.ts +0 -10
  136. package/dist/dts/NodeRuntime.d.ts.map +0 -1
  137. package/dist/dts/NodeSink.d.ts +0 -36
  138. package/dist/dts/NodeSink.d.ts.map +0 -1
  139. package/dist/dts/NodeSocket.d.ts.map +0 -1
  140. package/dist/dts/NodeSocketServer.d.ts.map +0 -1
  141. package/dist/dts/NodeStream.d.ts +0 -119
  142. package/dist/dts/NodeStream.d.ts.map +0 -1
  143. package/dist/dts/NodeTerminal.d.ts +0 -18
  144. package/dist/dts/NodeTerminal.d.ts.map +0 -1
  145. package/dist/dts/internal/commandExecutor.d.ts +0 -2
  146. package/dist/dts/internal/commandExecutor.d.ts.map +0 -1
  147. package/dist/dts/internal/error.d.ts +0 -2
  148. package/dist/dts/internal/error.d.ts.map +0 -1
  149. package/dist/dts/internal/fileSystem/parcelWatcher.d.ts +0 -4
  150. package/dist/dts/internal/fileSystem/parcelWatcher.d.ts.map +0 -1
  151. package/dist/dts/internal/fileSystem.d.ts +0 -2
  152. package/dist/dts/internal/fileSystem.d.ts.map +0 -1
  153. package/dist/dts/internal/multipart.d.ts +0 -2
  154. package/dist/dts/internal/multipart.d.ts.map +0 -1
  155. package/dist/dts/internal/path.d.ts +0 -2
  156. package/dist/dts/internal/path.d.ts.map +0 -1
  157. package/dist/dts/internal/runtime.d.ts +0 -2
  158. package/dist/dts/internal/runtime.d.ts.map +0 -1
  159. package/dist/dts/internal/sink.d.ts +0 -2
  160. package/dist/dts/internal/sink.d.ts.map +0 -1
  161. package/dist/dts/internal/stream.d.ts +0 -2
  162. package/dist/dts/internal/stream.d.ts.map +0 -1
  163. package/dist/dts/internal/terminal.d.ts +0 -2
  164. package/dist/dts/internal/terminal.d.ts.map +0 -1
  165. package/dist/esm/NodeClusterSocket.js.map +0 -1
  166. package/dist/esm/NodeCommandExecutor.js +0 -7
  167. package/dist/esm/NodeCommandExecutor.js.map +0 -1
  168. package/dist/esm/NodeFileSystem/ParcelWatcher.js +0 -12
  169. package/dist/esm/NodeFileSystem/ParcelWatcher.js.map +0 -1
  170. package/dist/esm/NodeFileSystem.js +0 -10
  171. package/dist/esm/NodeFileSystem.js.map +0 -1
  172. package/dist/esm/NodeKeyValueStore.js +0 -10
  173. package/dist/esm/NodeKeyValueStore.js.map +0 -1
  174. package/dist/esm/NodeMultipart.js +0 -17
  175. package/dist/esm/NodeMultipart.js.map +0 -1
  176. package/dist/esm/NodePath.js +0 -20
  177. package/dist/esm/NodePath.js.map +0 -1
  178. package/dist/esm/NodeRuntime.js +0 -7
  179. package/dist/esm/NodeRuntime.js.map +0 -1
  180. package/dist/esm/NodeSink.js +0 -43
  181. package/dist/esm/NodeSink.js.map +0 -1
  182. package/dist/esm/NodeSocket.js.map +0 -1
  183. package/dist/esm/NodeSocketServer.js +0 -167
  184. package/dist/esm/NodeSocketServer.js.map +0 -1
  185. package/dist/esm/NodeStream.js +0 -69
  186. package/dist/esm/NodeStream.js.map +0 -1
  187. package/dist/esm/NodeTerminal.js +0 -12
  188. package/dist/esm/NodeTerminal.js.map +0 -1
  189. package/dist/esm/internal/commandExecutor.js +0 -146
  190. package/dist/esm/internal/commandExecutor.js.map +0 -1
  191. package/dist/esm/internal/error.js.map +0 -1
  192. package/dist/esm/internal/fileSystem/parcelWatcher.js +0 -61
  193. package/dist/esm/internal/fileSystem/parcelWatcher.js.map +0 -1
  194. package/dist/esm/internal/fileSystem.js.map +0 -1
  195. package/dist/esm/internal/multipart.js +0 -137
  196. package/dist/esm/internal/multipart.js.map +0 -1
  197. package/dist/esm/internal/path.js +0 -46
  198. package/dist/esm/internal/path.js.map +0 -1
  199. package/dist/esm/internal/runtime.js.map +0 -1
  200. package/dist/esm/internal/sink.js +0 -19
  201. package/dist/esm/internal/sink.js.map +0 -1
  202. package/dist/esm/internal/stream.js +0 -217
  203. package/dist/esm/internal/stream.js.map +0 -1
  204. package/dist/esm/internal/terminal.js.map +0 -1
  205. package/dist/esm/package.json +0 -4
  206. package/src/NodeCommandExecutor.ts +0 -13
  207. package/src/NodeFileSystem/ParcelWatcher.ts +0 -15
  208. package/src/NodeKeyValueStore.ts +0 -20
  209. package/src/NodeMultipart.ts +0 -40
  210. package/src/internal/commandExecutor.ts +0 -251
  211. package/src/internal/fileSystem/parcelWatcher.ts +0 -64
  212. package/src/internal/fileSystem.ts +0 -648
  213. package/src/internal/multipart.ts +0 -141
  214. package/src/internal/path.ts +0 -63
  215. package/src/internal/runtime.ts +0 -34
  216. package/src/internal/sink.ts +0 -57
  217. package/src/internal/stream.ts +0 -375
  218. package/src/internal/terminal.ts +0 -104
@@ -1,141 +0,0 @@
1
- import * as Multipart from "@effect/platform/Multipart"
2
- import * as Effect from "effect/Effect"
3
- import { pipe } from "effect/Function"
4
- import * as Inspectable from "effect/Inspectable"
5
- import * as Stream from "effect/Stream"
6
- import type { MultipartError, PartInfo } from "multipasta"
7
- import { decodeField } from "multipasta"
8
- import * as MP from "multipasta/node"
9
- import * as NFS from "node:fs"
10
- import type { IncomingHttpHeaders } from "node:http"
11
- import type { Readable } from "node:stream"
12
- import * as NodeStreamP from "node:stream/promises"
13
- import * as NodeStream from "./stream.js"
14
-
15
- /** @internal */
16
- export const stream = (
17
- source: Readable,
18
- headers: IncomingHttpHeaders
19
- ): Stream.Stream<Multipart.Part, Multipart.MultipartError> =>
20
- pipe(
21
- Multipart.makeConfig(headers as any),
22
- Effect.map(
23
- (config) =>
24
- NodeStream.fromReadable<Multipart.MultipartError, MP.Part>(() => {
25
- const parser = MP.make(config)
26
- source.pipe(parser)
27
- return parser
28
- }, (error) => convertError(error as any))
29
- ),
30
- Stream.unwrap,
31
- Stream.map(convertPart)
32
- )
33
-
34
- /** @internal */
35
- export const persisted = (
36
- source: Readable,
37
- headers: IncomingHttpHeaders
38
- ) =>
39
- Multipart.toPersisted(stream(source, headers), (path, file) =>
40
- Effect.tryPromise({
41
- try: (signal) => NodeStreamP.pipeline((file as FileImpl).file, NFS.createWriteStream(path), { signal }),
42
- catch: (cause) => new Multipart.MultipartError({ reason: "InternalError", cause })
43
- }))
44
-
45
- const convertPart = (part: MP.Part): Multipart.Part =>
46
- part._tag === "Field" ? new FieldImpl(part.info, part.value) : new FileImpl(part)
47
-
48
- abstract class PartBase extends Inspectable.Class {
49
- readonly [Multipart.TypeId]: Multipart.TypeId
50
- constructor() {
51
- super()
52
- this[Multipart.TypeId] = Multipart.TypeId
53
- }
54
- }
55
-
56
- class FieldImpl extends PartBase implements Multipart.Field {
57
- readonly _tag = "Field"
58
- readonly key: string
59
- readonly contentType: string
60
- readonly value: string
61
-
62
- constructor(
63
- info: PartInfo,
64
- value: Uint8Array
65
- ) {
66
- super()
67
- this.key = info.name
68
- this.contentType = info.contentType
69
- this.value = decodeField(info, value)
70
- }
71
-
72
- toJSON(): unknown {
73
- return {
74
- _id: "@effect/platform/Multipart/Part",
75
- _tag: "Field",
76
- key: this.key,
77
- value: this.value,
78
- contentType: this.contentType
79
- }
80
- }
81
- }
82
-
83
- class FileImpl extends PartBase implements Multipart.File {
84
- readonly _tag = "File"
85
- readonly key: string
86
- readonly name: string
87
- readonly contentType: string
88
- readonly content: Stream.Stream<Uint8Array, Multipart.MultipartError>
89
- readonly contentEffect: Effect.Effect<Uint8Array, Multipart.MultipartError>
90
-
91
- constructor(readonly file: MP.FileStream) {
92
- super()
93
- this.key = file.info.name
94
- this.name = file.filename ?? file.info.name
95
- this.contentType = file.info.contentType
96
- this.content = NodeStream.fromReadable(
97
- () => file,
98
- (cause) => new Multipart.MultipartError({ reason: "InternalError", cause })
99
- )
100
- this.contentEffect = NodeStream.toUint8Array(() => file, {
101
- onFailure: (cause) => new Multipart.MultipartError({ reason: "InternalError", cause })
102
- })
103
- }
104
-
105
- toJSON(): unknown {
106
- return {
107
- _id: "@effect/platform/Multipart/Part",
108
- _tag: "File",
109
- key: this.key,
110
- name: this.name,
111
- contentType: this.contentType
112
- }
113
- }
114
- }
115
-
116
- /** @internal */
117
- export const fileToReadable = (file: Multipart.File): Readable => (file as FileImpl).file
118
-
119
- function convertError(cause: MultipartError): Multipart.MultipartError {
120
- switch (cause._tag) {
121
- case "ReachedLimit": {
122
- switch (cause.limit) {
123
- case "MaxParts": {
124
- return new Multipart.MultipartError({ reason: "TooManyParts", cause })
125
- }
126
- case "MaxFieldSize": {
127
- return new Multipart.MultipartError({ reason: "FieldTooLarge", cause })
128
- }
129
- case "MaxPartSize": {
130
- return new Multipart.MultipartError({ reason: "FileTooLarge", cause })
131
- }
132
- case "MaxTotalSize": {
133
- return new Multipart.MultipartError({ reason: "BodyTooLarge", cause })
134
- }
135
- }
136
- }
137
- default: {
138
- return new Multipart.MultipartError({ reason: "Parse", cause })
139
- }
140
- }
141
- }
@@ -1,63 +0,0 @@
1
- import { BadArgument } from "@effect/platform/Error"
2
- import { Path, TypeId } from "@effect/platform/Path"
3
- import * as Effect from "effect/Effect"
4
- import * as Layer from "effect/Layer"
5
- import * as NodePath from "node:path"
6
- import * as NodeUrl from "node:url"
7
-
8
- const fromFileUrl = (url: URL): Effect.Effect<string, BadArgument> =>
9
- Effect.try({
10
- try: () => NodeUrl.fileURLToPath(url),
11
- catch: (error) =>
12
- new BadArgument({
13
- module: "Path",
14
- method: "fromFileUrl",
15
- description: `Invalid file URL: ${url}`,
16
- cause: error
17
- })
18
- })
19
-
20
- const toFileUrl = (path: string): Effect.Effect<URL, BadArgument> =>
21
- Effect.try({
22
- try: () => NodeUrl.pathToFileURL(path),
23
- catch: (error) =>
24
- new BadArgument({
25
- module: "Path",
26
- method: "toFileUrl",
27
- description: `Invalid path: ${path}`,
28
- cause: error
29
- })
30
- })
31
-
32
- /** @internal */
33
- export const layerPosix = Layer.succeed(
34
- Path,
35
- Path.of({
36
- [TypeId]: TypeId,
37
- ...NodePath.posix,
38
- fromFileUrl,
39
- toFileUrl
40
- })
41
- )
42
-
43
- /** @internal */
44
- export const layerWin32 = Layer.succeed(
45
- Path,
46
- Path.of({
47
- [TypeId]: TypeId,
48
- ...NodePath.win32,
49
- fromFileUrl,
50
- toFileUrl
51
- })
52
- )
53
-
54
- /** @internal */
55
- export const layer = Layer.succeed(
56
- Path,
57
- Path.of({
58
- [TypeId]: TypeId,
59
- ...NodePath,
60
- fromFileUrl,
61
- toFileUrl
62
- })
63
- )
@@ -1,34 +0,0 @@
1
- import { makeRunMain } from "@effect/platform/Runtime"
2
- import { constVoid } from "effect/Function"
3
-
4
- /** @internal */
5
- export const runMain = makeRunMain(({
6
- fiber,
7
- teardown
8
- }) => {
9
- const keepAlive = setInterval(constVoid, 2 ** 31 - 1)
10
- let receivedSignal = false
11
-
12
- fiber.addObserver((exit) => {
13
- if (!receivedSignal) {
14
- process.removeListener("SIGINT", onSigint)
15
- process.removeListener("SIGTERM", onSigint)
16
- }
17
- clearInterval(keepAlive)
18
- teardown(exit, (code) => {
19
- if (receivedSignal || code !== 0) {
20
- process.exit(code)
21
- }
22
- })
23
- })
24
-
25
- function onSigint() {
26
- receivedSignal = true
27
- process.removeListener("SIGINT", onSigint)
28
- process.removeListener("SIGTERM", onSigint)
29
- fiber.unsafeInterruptAsFork(fiber.id())
30
- }
31
-
32
- process.on("SIGINT", onSigint)
33
- process.on("SIGTERM", onSigint)
34
- })
@@ -1,57 +0,0 @@
1
- import * as Channel from "effect/Channel"
2
- import type * as Chunk from "effect/Chunk"
3
- import * as Deferred from "effect/Deferred"
4
- import * as Effect from "effect/Effect"
5
- import type { LazyArg } from "effect/Function"
6
- import * as Sink from "effect/Sink"
7
- import type { Writable } from "node:stream"
8
- import type { FromWritableOptions } from "../NodeStream.js"
9
- import { writeInput } from "./stream.js"
10
-
11
- /** @internal */
12
- export const fromWritable = <E, A = Uint8Array | string>(
13
- evaluate: LazyArg<Writable | NodeJS.WritableStream>,
14
- onError: (error: unknown) => E,
15
- options?: FromWritableOptions
16
- ): Sink.Sink<void, A, never, E> => Sink.fromChannel(fromWritableChannel(evaluate, onError, options))
17
-
18
- /** @internal */
19
- export const fromWritableChannel = <IE, OE, A>(
20
- writable: LazyArg<Writable | NodeJS.WritableStream>,
21
- onError: (error: unknown) => OE,
22
- options?: FromWritableOptions
23
- ): Channel.Channel<Chunk.Chunk<never>, Chunk.Chunk<A>, IE | OE, IE, void, unknown> =>
24
- Channel.flatMap(
25
- Effect.zip(
26
- Effect.sync(() => writable()),
27
- Deferred.make<void, IE | OE>()
28
- ),
29
- ([writable, deferred]) =>
30
- Channel.embedInput(
31
- writableOutput(writable, deferred, onError),
32
- writeInput<IE, A>(
33
- writable,
34
- (cause) => Deferred.failCause(deferred, cause),
35
- options,
36
- Deferred.complete(deferred, Effect.void)
37
- )
38
- )
39
- )
40
-
41
- const writableOutput = <IE, E>(
42
- writable: Writable | NodeJS.WritableStream,
43
- deferred: Deferred.Deferred<void, IE | E>,
44
- onError: (error: unknown) => E
45
- ) =>
46
- Effect.suspend(() => {
47
- function handleError(err: unknown) {
48
- Deferred.unsafeDone(deferred, Effect.fail(onError(err)))
49
- }
50
- writable.on("error", handleError)
51
- return Effect.ensuring(
52
- Deferred.await(deferred),
53
- Effect.sync(() => {
54
- writable.removeListener("error", handleError)
55
- })
56
- )
57
- })
@@ -1,375 +0,0 @@
1
- import { type PlatformError, SystemError } from "@effect/platform/Error"
2
- import type { SizeInput } from "@effect/platform/FileSystem"
3
- import * as Cause from "effect/Cause"
4
- import * as Channel from "effect/Channel"
5
- import * as Chunk from "effect/Chunk"
6
- import * as Effect from "effect/Effect"
7
- import * as Exit from "effect/Exit"
8
- import * as Fiber from "effect/Fiber"
9
- import type { LazyArg } from "effect/Function"
10
- import { dual } from "effect/Function"
11
- import * as MutableRef from "effect/MutableRef"
12
- import * as Runtime from "effect/Runtime"
13
- import type * as AsyncInput from "effect/SingleProducerAsyncInput"
14
- import * as Stream from "effect/Stream"
15
- import type { Duplex, Writable } from "node:stream"
16
- import { Readable } from "node:stream"
17
- import type { FromReadableOptions, FromWritableOptions } from "../NodeStream.js"
18
-
19
- /** @internal */
20
- export const fromReadable = <E, A = Uint8Array>(
21
- evaluate: LazyArg<Readable | NodeJS.ReadableStream>,
22
- onError: (error: unknown) => E,
23
- options?: FromReadableOptions
24
- ): Stream.Stream<A, E> =>
25
- Stream.fromChannel(
26
- fromReadableChannel<E, A>(evaluate, onError, options)
27
- )
28
-
29
- /** @internal */
30
- export const toString = <E>(
31
- readable: LazyArg<Readable | NodeJS.ReadableStream>,
32
- options: {
33
- readonly onFailure: (error: unknown) => E
34
- readonly encoding?: BufferEncoding | undefined
35
- readonly maxBytes?: SizeInput | undefined
36
- }
37
- ): Effect.Effect<string, E> => {
38
- const maxBytesNumber = options.maxBytes ? Number(options.maxBytes) : undefined
39
- return Effect.acquireUseRelease(
40
- Effect.sync(() => {
41
- const stream = readable()
42
- stream.setEncoding(options.encoding ?? "utf8")
43
- return stream
44
- }),
45
- (stream) =>
46
- Effect.async((resume) => {
47
- let string = ""
48
- let bytes = 0
49
- stream.once("error", (err) => {
50
- resume(Effect.fail(options.onFailure(err)))
51
- })
52
- stream.once("end", () => {
53
- resume(Effect.succeed(string))
54
- })
55
- stream.on("data", (chunk) => {
56
- string += chunk
57
- bytes += Buffer.byteLength(chunk)
58
- if (maxBytesNumber && bytes > maxBytesNumber) {
59
- resume(Effect.fail(options.onFailure(new Error("maxBytes exceeded"))))
60
- }
61
- })
62
- }),
63
- (stream) =>
64
- Effect.sync(() => {
65
- if ("closed" in stream && !stream.closed) {
66
- stream.destroy()
67
- }
68
- })
69
- )
70
- }
71
-
72
- /** @internal */
73
- export const toUint8Array = <E>(
74
- readable: LazyArg<Readable | NodeJS.ReadableStream>,
75
- options: {
76
- readonly onFailure: (error: unknown) => E
77
- readonly maxBytes?: SizeInput | undefined
78
- }
79
- ): Effect.Effect<Uint8Array, E> => {
80
- const maxBytesNumber = options.maxBytes ? Number(options.maxBytes) : undefined
81
- return Effect.acquireUseRelease(
82
- Effect.sync(readable),
83
- (stream) =>
84
- Effect.async((resume) => {
85
- let buffer = Buffer.alloc(0)
86
- let bytes = 0
87
- stream.once("error", (err) => {
88
- resume(Effect.fail(options.onFailure(err)))
89
- })
90
- stream.once("end", () => {
91
- resume(Effect.succeed(buffer))
92
- })
93
- stream.on("data", (chunk) => {
94
- buffer = Buffer.concat([buffer, chunk])
95
- bytes += chunk.length
96
- if (maxBytesNumber && bytes > maxBytesNumber) {
97
- resume(Effect.fail(options.onFailure(new Error("maxBytes exceeded"))))
98
- }
99
- })
100
- }),
101
- (stream) =>
102
- Effect.sync(() => {
103
- if ("closed" in stream && !stream.closed) {
104
- stream.destroy()
105
- }
106
- })
107
- )
108
- }
109
-
110
- /** @internal */
111
- export const fromDuplex = <IE, E, I = string | Uint8Array<ArrayBufferLike>, O = Uint8Array<ArrayBufferLike>>(
112
- evaluate: LazyArg<Duplex>,
113
- onError: (error: unknown) => E,
114
- options?: FromReadableOptions & FromWritableOptions
115
- ): Channel.Channel<
116
- Chunk.Chunk<O>,
117
- Chunk.Chunk<I>,
118
- IE | E,
119
- IE
120
- > =>
121
- Channel.suspend(() => {
122
- const duplex = evaluate()
123
- if (!duplex.readable) {
124
- return Channel.void
125
- }
126
- const exit = MutableRef.make<Exit.Exit<void, IE | E> | undefined>(undefined)
127
- return Channel.embedInput(
128
- unsafeReadableRead<O, IE | E>(duplex, onError, exit, options),
129
- writeInput<IE, I>(
130
- duplex,
131
- (cause) => Effect.sync(() => MutableRef.set(exit, Exit.failCause(cause))),
132
- options
133
- )
134
- )
135
- })
136
-
137
- /** @internal */
138
- export const pipeThroughDuplex = dual<
139
- <E2, B = Uint8Array>(
140
- duplex: LazyArg<Duplex>,
141
- onError: (error: unknown) => E2,
142
- options?: FromReadableOptions & FromWritableOptions
143
- ) => <R, E, A>(self: Stream.Stream<A, E, R>) => Stream.Stream<B, E | E2, R>,
144
- <R, E, A, E2, B = Uint8Array>(
145
- self: Stream.Stream<A, E, R>,
146
- duplex: LazyArg<Duplex>,
147
- onError: (error: unknown) => E2,
148
- options?: FromReadableOptions & FromWritableOptions
149
- ) => Stream.Stream<B, E | E2, R>
150
- >(
151
- (args) => Stream.StreamTypeId in args[0],
152
- (self, duplex, onError, options) =>
153
- Stream.pipeThroughChannelOrFail(
154
- self,
155
- fromDuplex(duplex, onError, options)
156
- )
157
- )
158
-
159
- /** @internal */
160
- export const pipeThroughSimple = dual<
161
- (
162
- duplex: LazyArg<Duplex>
163
- ) => <R, E>(self: Stream.Stream<string | Uint8Array, E, R>) => Stream.Stream<Uint8Array, E | PlatformError, R>,
164
- <R, E>(
165
- self: Stream.Stream<string | Uint8Array, E, R>,
166
- duplex: LazyArg<Duplex>
167
- ) => Stream.Stream<Uint8Array, E | PlatformError, R>
168
- >(
169
- 2,
170
- (self, duplex) =>
171
- Stream.pipeThroughChannelOrFail(
172
- self,
173
- fromDuplex(duplex, (cause) =>
174
- new SystemError({
175
- module: "Stream",
176
- method: "pipeThroughSimple",
177
- reason: "Unknown",
178
- cause
179
- }))
180
- )
181
- )
182
-
183
- /** @internal */
184
- export const fromReadableChannel = <E, A = Uint8Array>(
185
- evaluate: LazyArg<Readable | NodeJS.ReadableStream>,
186
- onError: (error: unknown) => E,
187
- options?: FromReadableOptions | undefined
188
- ): Channel.Channel<
189
- Chunk.Chunk<A>,
190
- unknown,
191
- E
192
- > =>
193
- Channel.suspend(() =>
194
- unsafeReadableRead(
195
- evaluate(),
196
- onError,
197
- MutableRef.make(undefined),
198
- options
199
- )
200
- )
201
-
202
- /** @internal */
203
- export const writeInput = <IE, A>(
204
- writable: Writable | NodeJS.WritableStream,
205
- onFailure: (cause: Cause.Cause<IE>) => Effect.Effect<void>,
206
- { encoding, endOnDone = true }: FromWritableOptions = {},
207
- onDone = Effect.void
208
- ): AsyncInput.AsyncInputProducer<IE, Chunk.Chunk<A>, unknown> => {
209
- const write = writeEffect(writable, encoding)
210
- const close = endOnDone
211
- ? Effect.async<void>((resume) => {
212
- if ("closed" in writable && writable.closed) {
213
- resume(Effect.void)
214
- } else {
215
- writable.once("finish", () => resume(Effect.void))
216
- writable.end()
217
- }
218
- })
219
- : Effect.void
220
- return {
221
- awaitRead: () => Effect.void,
222
- emit: write,
223
- error: (cause) => Effect.zipRight(close, onFailure(cause)),
224
- done: (_) => Effect.zipRight(close, onDone)
225
- }
226
- }
227
-
228
- /** @internal */
229
- export const writeEffect = <A>(
230
- writable: Writable | NodeJS.WritableStream,
231
- encoding?: BufferEncoding
232
- ) =>
233
- (chunk: Chunk.Chunk<A>) =>
234
- chunk.length === 0 ?
235
- Effect.void :
236
- Effect.async<void>((resume) => {
237
- const iterator = chunk[Symbol.iterator]()
238
- let next = iterator.next()
239
- function loop() {
240
- const item = next
241
- next = iterator.next()
242
- const success = writable.write(item.value, encoding as any)
243
- if (next.done) {
244
- resume(Effect.void)
245
- } else if (success) {
246
- loop()
247
- } else {
248
- writable.once("drain", loop)
249
- }
250
- }
251
- loop()
252
- })
253
-
254
- const unsafeReadableRead = <A, E>(
255
- readable: Readable | NodeJS.ReadableStream,
256
- onError: (error: unknown) => E,
257
- exit: MutableRef.MutableRef<Exit.Exit<void, E> | undefined>,
258
- options: FromReadableOptions | undefined
259
- ) => {
260
- if (!readable.readable) {
261
- return Channel.void
262
- }
263
-
264
- const latch = Effect.unsafeMakeLatch(false)
265
- function onReadable() {
266
- latch.unsafeOpen()
267
- }
268
- function onErr(err: unknown) {
269
- exit.current = Exit.fail(onError(err))
270
- latch.unsafeOpen()
271
- }
272
- function onEnd() {
273
- exit.current = Exit.void
274
- latch.unsafeOpen()
275
- }
276
- readable.on("readable", onReadable)
277
- readable.on("error", onErr)
278
- readable.on("end", onEnd)
279
-
280
- const chunkSize = options?.chunkSize ? Number(options.chunkSize) : undefined
281
- const read = Channel.suspend(function loop(): Channel.Channel<Chunk.Chunk<A>, unknown, E> {
282
- let item = readable.read(chunkSize) as A | null
283
- if (item === null) {
284
- if (exit.current) {
285
- return Channel.fromEffect(exit.current)
286
- }
287
- latch.unsafeClose()
288
- return Channel.flatMap(latch.await, loop)
289
- }
290
- const arr = [item as A]
291
- while (true) {
292
- item = readable.read(chunkSize)
293
- if (item === null) {
294
- return Channel.flatMap(Channel.write(Chunk.unsafeFromArray(arr)), loop)
295
- }
296
- arr.push(item as A)
297
- }
298
- })
299
-
300
- return Channel.ensuring(
301
- read,
302
- Effect.sync(() => {
303
- readable.off("readable", onReadable)
304
- readable.off("error", onErr)
305
- readable.off("end", onEnd)
306
- if (options?.closeOnDone !== false && "closed" in readable && !readable.closed) {
307
- readable.destroy()
308
- }
309
- })
310
- )
311
- }
312
-
313
- class StreamAdapter<E, R> extends Readable {
314
- readonly readLatch: Effect.Latch
315
- fiber: Fiber.RuntimeFiber<void, E> | undefined = undefined
316
-
317
- constructor(
318
- runtime: Runtime.Runtime<R>,
319
- stream: Stream.Stream<Uint8Array | string, E, R>
320
- ) {
321
- super({})
322
- this.readLatch = Effect.unsafeMakeLatch(false)
323
- this.fiber = Runtime.runFork(runtime)(
324
- this.readLatch.whenOpen(
325
- Stream.runForEachChunk(stream, (chunk) =>
326
- this.readLatch.whenOpen(Effect.sync(() => {
327
- if (chunk.length === 0) return
328
- this.readLatch.unsafeClose()
329
- for (const item of chunk) {
330
- if (typeof item === "string") {
331
- this.push(item, "utf8")
332
- } else {
333
- this.push(item)
334
- }
335
- }
336
- })))
337
- )
338
- )
339
- this.fiber.addObserver((exit) => {
340
- this.fiber = undefined
341
- if (Exit.isSuccess(exit)) {
342
- this.push(null)
343
- } else {
344
- this.destroy(Cause.squash(exit.cause) as any)
345
- }
346
- })
347
- }
348
-
349
- _read(_size: number): void {
350
- this.readLatch.unsafeOpen()
351
- }
352
-
353
- _destroy(error: Error | null, callback: (error?: Error | null | undefined) => void): void {
354
- if (!this.fiber) {
355
- return callback(error)
356
- }
357
- Effect.runFork(Fiber.interrupt(this.fiber)).addObserver((exit) => {
358
- callback(exit._tag === "Failure" ? Cause.squash(exit.cause) as any : error)
359
- })
360
- }
361
- }
362
-
363
- /** @internal */
364
- export const toReadable = <E, R>(
365
- stream: Stream.Stream<Uint8Array | string, E, R>
366
- ): Effect.Effect<Readable, never, R> =>
367
- Effect.map(
368
- Effect.runtime<R>(),
369
- (runtime) => new StreamAdapter(runtime, stream)
370
- )
371
-
372
- /** @internal */
373
- export const toReadableNever = <E>(
374
- stream: Stream.Stream<Uint8Array | string, E>
375
- ): Readable => new StreamAdapter(Runtime.defaultRuntime, stream)