@effect/platform-node-shared 4.0.0-beta.99 → 4.0.0-rc.109
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/AGENTS.md +395 -0
- package/CLAUDE.md +395 -0
- package/README.md +10 -3
- package/ai-docs/README.md +44 -0
- package/ai-docs/package.json +36 -0
- package/ai-docs/src/01_effect/01_basics/01_effect-gen.ts +30 -0
- package/ai-docs/src/01_effect/01_basics/02_effect-fn.ts +39 -0
- package/ai-docs/src/01_effect/01_basics/10_creating-effects.ts +74 -0
- package/ai-docs/src/01_effect/01_basics/index.md +5 -0
- package/ai-docs/src/01_effect/02_schema/10_schema-basics.ts +43 -0
- package/ai-docs/src/01_effect/02_schema/index.md +7 -0
- package/ai-docs/src/01_effect/03_services/01_service.ts +45 -0
- package/ai-docs/src/01_effect/03_services/10_reference.ts +10 -0
- package/ai-docs/src/01_effect/03_services/20_layer-composition.ts +70 -0
- package/ai-docs/src/01_effect/03_services/20_layer-unwrap.ts +66 -0
- package/ai-docs/src/01_effect/03_services/index.md +5 -0
- package/ai-docs/src/01_effect/04_errors/01_error-handling.ts +30 -0
- package/ai-docs/src/01_effect/04_errors/10_catch-tags.ts +24 -0
- package/ai-docs/src/01_effect/04_errors/20_reason-errors.ts +64 -0
- package/ai-docs/src/01_effect/04_errors/index.md +1 -0
- package/ai-docs/src/01_effect/05_resources/10_acquire-release.ts +105 -0
- package/ai-docs/src/01_effect/05_resources/20_layer-side-effects.ts +31 -0
- package/ai-docs/src/01_effect/05_resources/30_layer-map.ts +86 -0
- package/ai-docs/src/01_effect/05_resources/index.md +3 -0
- package/ai-docs/src/01_effect/06_running/10_run-main.ts +30 -0
- package/ai-docs/src/01_effect/06_running/20_layer-launch.ts +27 -0
- package/ai-docs/src/01_effect/06_running/index.md +1 -0
- package/ai-docs/src/01_effect/07_pubsub/10_pubsub.ts +56 -0
- package/ai-docs/src/01_effect/07_pubsub/index.md +3 -0
- package/ai-docs/src/03_stream/10_creating-streams.ts +103 -0
- package/ai-docs/src/03_stream/20_consuming-streams.ts +137 -0
- package/ai-docs/src/03_stream/30_encoding.ts +165 -0
- package/ai-docs/src/03_stream/index.md +4 -0
- package/ai-docs/src/04_integration/10_managed-runtime.ts +129 -0
- package/ai-docs/src/04_integration/index.md +5 -0
- package/ai-docs/src/05_batching/10_request-resolver.ts +89 -0
- package/ai-docs/src/05_batching/index.md +3 -0
- package/ai-docs/src/06_schedule/10_schedules.ts +110 -0
- package/ai-docs/src/06_schedule/index.md +3 -0
- package/ai-docs/src/07_datetime/10_creating-and-formatting.ts +30 -0
- package/ai-docs/src/07_datetime/20_time-zones.ts +44 -0
- package/ai-docs/src/07_datetime/index.md +5 -0
- package/ai-docs/src/08_observability/10_logging.ts +66 -0
- package/ai-docs/src/08_observability/20_otlp-tracing.ts +95 -0
- package/ai-docs/src/08_observability/index.md +7 -0
- package/ai-docs/src/09_testing/10_effect-tests.ts +55 -0
- package/ai-docs/src/09_testing/20_layer-tests.ts +138 -0
- package/ai-docs/src/09_testing/index.md +1 -0
- package/ai-docs/src/10_predicate/01_basics.ts +14 -0
- package/ai-docs/src/10_predicate/index.md +9 -0
- package/ai-docs/src/40_sql/10_basics.ts +175 -0
- package/ai-docs/src/40_sql/index.md +6 -0
- package/ai-docs/src/50_http-client/10_basics.ts +102 -0
- package/ai-docs/src/50_http-client/index.md +3 -0
- package/ai-docs/src/51_http-server/10_basics.ts +118 -0
- package/ai-docs/src/51_http-server/20_testing.ts +100 -0
- package/ai-docs/src/51_http-server/fixtures/api/Api.ts +14 -0
- package/ai-docs/src/51_http-server/fixtures/api/Authorization.ts +36 -0
- package/ai-docs/src/51_http-server/fixtures/api/System.ts +10 -0
- package/ai-docs/src/51_http-server/fixtures/api/Users.ts +107 -0
- package/ai-docs/src/51_http-server/fixtures/domain/User.ts +21 -0
- package/ai-docs/src/51_http-server/fixtures/domain/UserErrors.ts +22 -0
- package/ai-docs/src/51_http-server/fixtures/server/Authorization.ts +37 -0
- package/ai-docs/src/51_http-server/fixtures/server/Users/http.ts +80 -0
- package/ai-docs/src/51_http-server/fixtures/server/Users.ts +183 -0
- package/ai-docs/src/51_http-server/index.md +3 -0
- package/ai-docs/src/60_child-process/10_working-with-child-processes.ts +117 -0
- package/ai-docs/src/60_child-process/index.md +3 -0
- package/ai-docs/src/70_cli/10_basics.ts +160 -0
- package/ai-docs/src/70_cli/index.md +5 -0
- package/ai-docs/src/71_ai/10_language-model.ts +156 -0
- package/ai-docs/src/71_ai/20_tools.ts +226 -0
- package/ai-docs/src/71_ai/30_chat.ts +158 -0
- package/ai-docs/src/71_ai/fixtures/domain/LaunchPlan.ts +9 -0
- package/ai-docs/src/71_ai/index.md +5 -0
- package/ai-docs/src/80_cluster/10_entities.ts +97 -0
- package/ai-docs/src/80_cluster/index.md +4 -0
- package/ai-docs/src/index.md +10 -0
- package/ai-docs/tsconfig.json +24 -0
- package/dist/NodeChildProcessSpawner.d.ts.map +1 -1
- package/dist/NodeChildProcessSpawner.js +14 -10
- package/dist/NodeChildProcessSpawner.js.map +1 -1
- package/dist/NodeClusterSocket.js.map +1 -1
- package/dist/NodeCrypto.js.map +1 -1
- package/dist/NodeFileSystem.d.ts.map +1 -1
- package/dist/NodeFileSystem.js +7 -7
- package/dist/NodeFileSystem.js.map +1 -1
- package/dist/NodeHttpCompression.d.ts +36 -0
- package/dist/NodeHttpCompression.d.ts.map +1 -0
- package/dist/NodeHttpCompression.js +146 -0
- package/dist/NodeHttpCompression.js.map +1 -0
- package/dist/NodePath.d.ts.map +1 -1
- package/dist/NodePath.js +23 -20
- package/dist/NodePath.js.map +1 -1
- package/dist/NodeRuntime.js.map +1 -1
- package/dist/NodeSink.js.map +1 -1
- package/dist/NodeSocket.js.map +1 -1
- package/dist/NodeSocketServer.d.ts.map +1 -1
- package/dist/NodeSocketServer.js +29 -19
- package/dist/NodeSocketServer.js.map +1 -1
- package/dist/NodeStdio.d.ts.map +1 -1
- package/dist/NodeStdio.js +2 -0
- package/dist/NodeStdio.js.map +1 -1
- package/dist/NodeStream.d.ts.map +1 -1
- package/dist/NodeStream.js +10 -7
- package/dist/NodeStream.js.map +1 -1
- package/dist/NodeTerminal.d.ts.map +1 -1
- package/dist/NodeTerminal.js +63 -11
- package/dist/NodeTerminal.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/nodeChildProcessSpawner.d.ts +4 -0
- package/dist/internal/nodeChildProcessSpawner.d.ts.map +1 -0
- package/dist/internal/nodeChildProcessSpawner.js +10 -0
- package/dist/internal/nodeChildProcessSpawner.js.map +1 -0
- package/dist/internal/utils.js.map +1 -1
- package/package.json +11 -9
- package/src/NodeChildProcessSpawner.ts +19 -12
- package/src/NodeFileSystem.ts +16 -12
- package/src/NodeHttpCompression.ts +153 -0
- package/src/NodePath.ts +25 -27
- package/src/NodeSocketServer.ts +32 -19
- package/src/NodeStdio.ts +2 -0
- package/src/NodeStream.ts +10 -7
- package/src/NodeTerminal.ts +62 -13
- package/src/index.ts +5 -0
- package/src/internal/nodeChildProcessSpawner.ts +16 -0
- package/src/internal/utils.ts +1 -1
package/src/NodeSocketServer.ts
CHANGED
|
@@ -52,12 +52,14 @@ export const make = Effect.fnUntraced(function*(
|
|
|
52
52
|
options: Net.ServerOpts & Net.ListenOptions
|
|
53
53
|
) {
|
|
54
54
|
const errorDeferred = Deferred.makeUnsafe<never, Error>()
|
|
55
|
-
const pending = new
|
|
55
|
+
const pending = new Map<Net.Socket, () => void>()
|
|
56
56
|
function defaultOnConnection(conn: Net.Socket) {
|
|
57
|
-
pending.add(conn)
|
|
58
57
|
const remove = () => {
|
|
59
58
|
pending.delete(conn)
|
|
59
|
+
conn.off("close", remove)
|
|
60
|
+
conn.off("error", remove)
|
|
60
61
|
}
|
|
62
|
+
pending.set(conn, remove)
|
|
61
63
|
conn.on("close", remove)
|
|
62
64
|
conn.on("error", remove)
|
|
63
65
|
}
|
|
@@ -66,6 +68,10 @@ export const make = Effect.fnUntraced(function*(
|
|
|
66
68
|
let server: Net.Server | undefined
|
|
67
69
|
yield* Effect.addFinalizer(() =>
|
|
68
70
|
Effect.callback<void>((resume) => {
|
|
71
|
+
pending.forEach((remove, conn) => {
|
|
72
|
+
remove()
|
|
73
|
+
conn.destroy()
|
|
74
|
+
})
|
|
69
75
|
server?.close(() => resume(Effect.void))
|
|
70
76
|
})
|
|
71
77
|
)
|
|
@@ -129,12 +135,10 @@ export const make = Effect.fnUntraced(function*(
|
|
|
129
135
|
trackFiber
|
|
130
136
|
)
|
|
131
137
|
}
|
|
132
|
-
pending.forEach((conn) => {
|
|
133
|
-
|
|
134
|
-
conn.removeAllListeners("close")
|
|
138
|
+
pending.forEach((remove, conn) => {
|
|
139
|
+
remove()
|
|
135
140
|
onConnection(conn)
|
|
136
141
|
})
|
|
137
|
-
pending.clear()
|
|
138
142
|
return yield* Effect.callback<never>((_resume) => {
|
|
139
143
|
return Effect.suspend(() => {
|
|
140
144
|
onConnection = prevOnConnection
|
|
@@ -190,20 +194,29 @@ export const makeWebSocket: (
|
|
|
190
194
|
> = Effect.fnUntraced(function*(
|
|
191
195
|
options: NodeWS.ServerOptions
|
|
192
196
|
) {
|
|
197
|
+
const pendingConnections = new Map<
|
|
198
|
+
globalThis.WebSocket,
|
|
199
|
+
readonly [request: Http.IncomingMessage, remove: () => void]
|
|
200
|
+
>()
|
|
193
201
|
const server = yield* Effect.acquireRelease(
|
|
194
202
|
Effect.sync(() => new NodeWS.WebSocketServer(options)),
|
|
195
203
|
(server) =>
|
|
196
204
|
Effect.callback<void>((resume) => {
|
|
205
|
+
pendingConnections.forEach(([, remove], conn) => {
|
|
206
|
+
remove()
|
|
207
|
+
const socket = conn as unknown as NodeWS.WebSocket
|
|
208
|
+
socket.terminate()
|
|
209
|
+
})
|
|
197
210
|
server.close(() => resume(Effect.void))
|
|
198
211
|
})
|
|
199
212
|
)
|
|
200
|
-
const pendingConnections = new Set<readonly [globalThis.WebSocket, Http.IncomingMessage]>()
|
|
201
213
|
function defaultHandler(conn: globalThis.WebSocket, req: Http.IncomingMessage) {
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
214
|
+
const remove = () => {
|
|
215
|
+
pendingConnections.delete(conn)
|
|
216
|
+
conn.removeEventListener("close", remove)
|
|
217
|
+
}
|
|
218
|
+
pendingConnections.set(conn, [req, remove])
|
|
219
|
+
conn.addEventListener("close", remove)
|
|
207
220
|
}
|
|
208
221
|
let onConnection = defaultHandler
|
|
209
222
|
server.on("connection", (conn, req) => onConnection(conn as any, req))
|
|
@@ -229,9 +242,9 @@ export const makeWebSocket: (
|
|
|
229
242
|
const trackFiber = Fiber.runIn(scope)
|
|
230
243
|
const prevOnConnection = onConnection
|
|
231
244
|
onConnection = function(conn: globalThis.WebSocket, req: Http.IncomingMessage) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
245
|
+
let context = services
|
|
246
|
+
context = Context.add(context, IncomingMessage, req)
|
|
247
|
+
context = Context.add(context, Socket.WebSocket, conn as any)
|
|
235
248
|
pipe(
|
|
236
249
|
Socket.fromWebSocket(
|
|
237
250
|
Effect.acquireRelease(
|
|
@@ -244,14 +257,14 @@ export const makeWebSocket: (
|
|
|
244
257
|
),
|
|
245
258
|
Effect.flatMap(handler),
|
|
246
259
|
Effect.catchCause(reportUnhandledError),
|
|
247
|
-
Effect.runForkWith(
|
|
260
|
+
Effect.runForkWith(context),
|
|
248
261
|
trackFiber
|
|
249
262
|
)
|
|
250
263
|
}
|
|
251
|
-
|
|
264
|
+
pendingConnections.forEach(([req, remove], conn) => {
|
|
265
|
+
remove()
|
|
252
266
|
onConnection(conn, req)
|
|
253
|
-
}
|
|
254
|
-
pendingConnections.clear()
|
|
267
|
+
})
|
|
255
268
|
return yield* Effect.callback<never>((_resume) => {
|
|
256
269
|
return Effect.sync(() => {
|
|
257
270
|
onConnection = prevOnConnection
|
package/src/NodeStdio.ts
CHANGED
|
@@ -28,6 +28,8 @@ export const layer: Layer.Layer<Stdio.Stdio> = Layer.succeed(
|
|
|
28
28
|
Stdio.Stdio,
|
|
29
29
|
Stdio.make({
|
|
30
30
|
args: Effect.sync(() => process.argv.slice(2)),
|
|
31
|
+
stdinIsTerminal: Effect.sync(() => process.stdin.isTTY === true),
|
|
32
|
+
stdoutIsTerminal: Effect.sync(() => process.stdout.isTTY === true),
|
|
31
33
|
stdout: (options) =>
|
|
32
34
|
fromWritable({
|
|
33
35
|
evaluate: () => process.stdout,
|
package/src/NodeStream.ts
CHANGED
|
@@ -245,7 +245,7 @@ export const toString = <E = Cause.UnknownError>(
|
|
|
245
245
|
readonly maxBytes?: SizeInput | undefined
|
|
246
246
|
}
|
|
247
247
|
): Effect.Effect<string, E> => {
|
|
248
|
-
const maxBytesNumber = options?.maxBytes ? Number(options.maxBytes) : undefined
|
|
248
|
+
const maxBytesNumber = options?.maxBytes !== undefined ? Number(options.maxBytes) : undefined
|
|
249
249
|
const onError = options?.onError ?? defaultOnError
|
|
250
250
|
const encoding = options?.encoding ?? "utf8"
|
|
251
251
|
return Effect.callback((resume) => {
|
|
@@ -258,9 +258,6 @@ export const toString = <E = Cause.UnknownError>(
|
|
|
258
258
|
}
|
|
259
259
|
resume(Effect.fail(onError(err) as E))
|
|
260
260
|
})
|
|
261
|
-
stream.once("error", (err) => {
|
|
262
|
-
resume(Effect.fail(onError(err) as E))
|
|
263
|
-
})
|
|
264
261
|
|
|
265
262
|
let string = ""
|
|
266
263
|
let bytes = 0
|
|
@@ -270,7 +267,10 @@ export const toString = <E = Cause.UnknownError>(
|
|
|
270
267
|
stream.on("data", (chunk) => {
|
|
271
268
|
string += chunk
|
|
272
269
|
bytes += Buffer.byteLength(chunk)
|
|
273
|
-
if (maxBytesNumber && bytes > maxBytesNumber) {
|
|
270
|
+
if (maxBytesNumber !== undefined && bytes > maxBytesNumber) {
|
|
271
|
+
if ("closed" in stream && !stream.closed) {
|
|
272
|
+
stream.destroy()
|
|
273
|
+
}
|
|
274
274
|
resume(Effect.fail(onError(new Error("maxBytes exceeded")) as E))
|
|
275
275
|
}
|
|
276
276
|
})
|
|
@@ -297,7 +297,7 @@ export const toArrayBuffer = <E = Cause.UnknownError>(
|
|
|
297
297
|
readonly maxBytes?: SizeInput | undefined
|
|
298
298
|
}
|
|
299
299
|
): Effect.Effect<ArrayBuffer, E> => {
|
|
300
|
-
const maxBytesNumber = options?.maxBytes ? Number(options.maxBytes) : undefined
|
|
300
|
+
const maxBytesNumber = options?.maxBytes !== undefined ? Number(options.maxBytes) : undefined
|
|
301
301
|
const onError = options?.onError ?? defaultOnError
|
|
302
302
|
return Effect.callback((resume) => {
|
|
303
303
|
const stream = readable() as Readable
|
|
@@ -321,7 +321,10 @@ export const toArrayBuffer = <E = Cause.UnknownError>(
|
|
|
321
321
|
stream.on("data", (chunk) => {
|
|
322
322
|
buffers.push(chunk)
|
|
323
323
|
bytes += chunk.length
|
|
324
|
-
if (maxBytesNumber && bytes > maxBytesNumber) {
|
|
324
|
+
if (maxBytesNumber !== undefined && bytes > maxBytesNumber) {
|
|
325
|
+
if ("closed" in stream && !stream.closed) {
|
|
326
|
+
stream.destroy()
|
|
327
|
+
}
|
|
325
328
|
resume(Effect.fail(onError(new Error("maxBytes exceeded")) as E))
|
|
326
329
|
}
|
|
327
330
|
})
|
package/src/NodeTerminal.ts
CHANGED
|
@@ -35,34 +35,61 @@ export const make: (
|
|
|
35
35
|
function*(shouldQuit: (input: Terminal.UserInput) => boolean = defaultShouldQuit) {
|
|
36
36
|
const stdin = process.stdin
|
|
37
37
|
const stdout = process.stdout
|
|
38
|
+
const lines = yield* Queue.make<string, Cause.Done>()
|
|
39
|
+
|
|
40
|
+
// stdin "end" fires once per process, so remember end-of-input for readers
|
|
41
|
+
// created after the event (Bun never sets `readableEnded`).
|
|
42
|
+
let inputEnded = stdin.readableEnded
|
|
43
|
+
let readlineActive = false
|
|
44
|
+
const onStdinEnd = () => {
|
|
45
|
+
inputEnded = true
|
|
46
|
+
if (!readlineActive) {
|
|
47
|
+
Queue.endUnsafe(lines)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
stdin.once("end", onStdinEnd)
|
|
51
|
+
yield* Effect.addFinalizer(() => Effect.sync(() => stdin.off("end", onStdinEnd)))
|
|
38
52
|
|
|
39
|
-
// Acquire readline interface with TTY setup/cleanup inside the scope
|
|
40
53
|
const rlRef = yield* RcRef.make({
|
|
41
54
|
acquire: Effect.acquireRelease(
|
|
42
55
|
Effect.sync(() => {
|
|
43
56
|
const rl = readline.createInterface({ input: stdin, escapeCodeTimeout: 50 })
|
|
57
|
+
const onLine = (line: string) => Queue.offerUnsafe(lines, line)
|
|
58
|
+
const onClose = () => {
|
|
59
|
+
readlineActive = false
|
|
60
|
+
Queue.endUnsafe(lines)
|
|
61
|
+
}
|
|
62
|
+
readlineActive = true
|
|
44
63
|
readline.emitKeypressEvents(stdin, rl)
|
|
64
|
+
rl.on("line", onLine)
|
|
65
|
+
rl.once("close", onClose)
|
|
45
66
|
|
|
46
67
|
if (stdin.isTTY) {
|
|
47
68
|
stdin.setRawMode(true)
|
|
48
69
|
}
|
|
49
|
-
return rl
|
|
70
|
+
return { rl, onClose, onLine }
|
|
50
71
|
}),
|
|
51
|
-
(rl) =>
|
|
72
|
+
({ rl, onClose, onLine }) =>
|
|
52
73
|
Effect.sync(() => {
|
|
74
|
+
readlineActive = false
|
|
75
|
+
rl.off("line", onLine)
|
|
76
|
+
rl.off("close", onClose)
|
|
53
77
|
if (stdin.isTTY) {
|
|
54
78
|
stdin.setRawMode(false)
|
|
55
79
|
}
|
|
56
80
|
rl.close()
|
|
81
|
+
if (inputEnded) {
|
|
82
|
+
Queue.endUnsafe(lines)
|
|
83
|
+
}
|
|
57
84
|
})
|
|
58
|
-
)
|
|
85
|
+
),
|
|
86
|
+
idleTimeToLive: "10 millis"
|
|
59
87
|
})
|
|
60
88
|
|
|
61
89
|
const columns = Effect.sync(() => stdout.columns ?? 0)
|
|
62
90
|
const rows = Effect.sync(() => stdout.rows ?? 0)
|
|
63
91
|
|
|
64
92
|
const readInput = Effect.gen(function*() {
|
|
65
|
-
yield* RcRef.get(rlRef)
|
|
66
93
|
const queue = yield* Queue.make<Terminal.UserInput, Cause.Done>()
|
|
67
94
|
const handleKeypress = (s: string | undefined, k: readline.Key) => {
|
|
68
95
|
const userInput = {
|
|
@@ -74,18 +101,40 @@ export const make: (
|
|
|
74
101
|
Queue.endUnsafe(queue)
|
|
75
102
|
}
|
|
76
103
|
}
|
|
77
|
-
|
|
104
|
+
// Deno's `process.stdin` shim does not keep the event loop alive, so a
|
|
105
|
+
// program blocked on input can exit before `end` is ever delivered. A
|
|
106
|
+
// timer holds the loop open for as long as this reader is active.
|
|
107
|
+
const keepAlive = setInterval(() => {}, 2147483647)
|
|
108
|
+
// Without this, consumers (e.g. `Prompt.run`) hang forever on closed stdin.
|
|
109
|
+
const handleEnd = () => {
|
|
110
|
+
clearInterval(keepAlive)
|
|
111
|
+
Queue.endUnsafe(queue)
|
|
112
|
+
}
|
|
113
|
+
yield* Effect.addFinalizer(() =>
|
|
114
|
+
Effect.sync(() => {
|
|
115
|
+
clearInterval(keepAlive)
|
|
116
|
+
stdin.off("keypress", handleKeypress)
|
|
117
|
+
stdin.off("end", handleEnd)
|
|
118
|
+
})
|
|
119
|
+
)
|
|
78
120
|
stdin.on("keypress", handleKeypress)
|
|
121
|
+
if (inputEnded) {
|
|
122
|
+
handleEnd()
|
|
123
|
+
} else {
|
|
124
|
+
yield* RcRef.get(rlRef)
|
|
125
|
+
stdin.once("end", handleEnd)
|
|
126
|
+
}
|
|
79
127
|
return queue as Queue.Dequeue<Terminal.UserInput, Cause.Done>
|
|
80
128
|
})
|
|
81
129
|
|
|
82
|
-
const readLine = Effect.
|
|
83
|
-
|
|
84
|
-
Effect.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}))
|
|
130
|
+
const readLine = Effect.suspend(() =>
|
|
131
|
+
Queue.poll(lines).pipe(
|
|
132
|
+
Effect.flatMap(Option.match({
|
|
133
|
+
onNone: () => Effect.scoped(Effect.andThen(RcRef.get(rlRef), Queue.take(lines))),
|
|
134
|
+
onSome: Effect.succeed
|
|
135
|
+
})),
|
|
136
|
+
Effect.mapError(() => new Terminal.QuitError({}))
|
|
137
|
+
)
|
|
89
138
|
)
|
|
90
139
|
|
|
91
140
|
const display = (prompt: string) =>
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type * as ChildProcess from "effect/unstable/process/ChildProcess"
|
|
2
|
+
import type * as NodeChildProcess from "node:child_process"
|
|
3
|
+
|
|
4
|
+
export const buildSpawnOptions = (
|
|
5
|
+
options: ChildProcess.CommandOptions,
|
|
6
|
+
base: Pick<NodeChildProcess.SpawnOptions, "cwd" | "env" | "stdio">,
|
|
7
|
+
platform: NodeJS.Platform
|
|
8
|
+
): NodeChildProcess.SpawnOptions => {
|
|
9
|
+
const detached = options.detached ?? platform !== "win32"
|
|
10
|
+
return {
|
|
11
|
+
...base,
|
|
12
|
+
detached,
|
|
13
|
+
shell: options.shell,
|
|
14
|
+
windowsHide: options.windowsHide ?? !detached
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/internal/utils.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { PathLike } from "node:fs"
|
|
|
6
6
|
export const handleErrnoException = (module: SystemError["module"], method: string) =>
|
|
7
7
|
(
|
|
8
8
|
err: NodeJS.ErrnoException,
|
|
9
|
-
[path]: [path: PathLike | number | string |
|
|
9
|
+
[path]: [path: PathLike | number | string | ReadonlyArray<string>, ...args: Array<any>]
|
|
10
10
|
): PlatformError.PlatformError => {
|
|
11
11
|
let reason: SystemErrorTag = "Unknown"
|
|
12
12
|
|