@volter/tabnode 0.4.0 → 0.5.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.
- package/dist/__sw__.js +259 -5
- package/dist/assets/{runtime-worker-DoV8lqBn.js → runtime-worker-B9buriZs.js} +4021 -2961
- package/dist/fetch-transport.d.ts +20 -0
- package/dist/guest-timers.d.ts +15 -0
- package/dist/http-client-transport.d.ts +19 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.mjs +5204 -3057
- package/dist/native-stream-binding.d.ts +57 -0
- package/dist/native-stream-owner.d.ts +121 -0
- package/dist/node-lib/binding/duplex_stream.d.ts +26 -0
- package/dist/node-lib/binding/fds.d.ts +8 -0
- package/dist/node-lib/binding/fs.d.ts +311 -78
- package/dist/node-lib/binding/misc.d.ts +1 -0
- package/dist/node-lib/binding/pipe_wrap.d.ts +4 -4
- package/dist/node-lib/binding/process_wrap.d.ts +13 -2
- package/dist/node-lib/binding/stream_wrap.d.ts +27 -18
- package/dist/node-lib/binding/tcp_wrap.d.ts +0 -1
- package/dist/node-lib/binding/tty_wrap.d.ts +43 -2
- package/dist/node-lib/binding/util.d.ts +83 -0
- package/dist/node-lib/binding/uv.d.ts +4 -0
- package/dist/node-lib/fs-module.d.ts +1 -0
- package/dist/node-lib/internals/buffer-and-streams.d.ts +30 -17
- package/dist/node-lib/internals/index.d.ts +1 -1
- package/dist/node-lib/load.d.ts +17 -3
- package/dist/node-lib/module-hooks.d.ts +1 -0
- package/dist/node-lib/public-modules.d.ts +1 -1
- package/dist/node-lib/timers.d.ts +38 -0
- package/dist/node-process-host.d.ts +41 -0
- package/dist/process-registry.d.ts +39 -0
- package/dist/process-tokens.d.ts +16 -0
- package/dist/promise-ownership.d.ts +3 -0
- package/dist/runtime.d.ts +10 -9
- package/dist/shims/child_process.d.ts +2 -0
- package/dist/shims/crypto.d.ts +660 -119
- package/dist/shims/dns.d.ts +76 -2
- package/dist/shims/process.d.ts +1 -0
- package/dist/shims/string_decoder.d.ts +19 -3
- package/dist/shims/tls.d.ts +853 -31
- package/dist/source-edits.d.ts +7 -0
- package/package.json +1 -1
- package/src/code-transforms.ts +2 -3
- package/src/fetch-transport.ts +98 -0
- package/src/guest-timers.ts +89 -0
- package/src/http-client-transport.ts +169 -0
- package/src/index.ts +12 -0
- package/src/native-stream-binding.ts +393 -0
- package/src/native-stream-owner.ts +317 -0
- package/src/node-lib/binding/duplex_stream.ts +95 -0
- package/src/node-lib/binding/fds.ts +18 -1
- package/src/node-lib/binding/fs.ts +45 -17
- package/src/node-lib/binding/misc.ts +2 -0
- package/src/node-lib/binding/pipe_wrap.ts +35 -12
- package/src/node-lib/binding/process_wrap.ts +72 -18
- package/src/node-lib/binding/stream_wrap.ts +196 -72
- package/src/node-lib/binding/tcp_wrap.ts +43 -8
- package/src/node-lib/binding/tty_wrap.ts +135 -8
- package/src/node-lib/binding/util.ts +24 -15
- package/src/node-lib/binding/uv.ts +4 -0
- package/src/node-lib/fs-module.ts +2 -18
- package/src/node-lib/internal/navigator.js +149 -0
- package/src/node-lib/internals/buffer-and-streams.ts +50 -11
- package/src/node-lib/internals/events-util.ts +5 -0
- package/src/node-lib/internals/index.ts +12 -2
- package/src/node-lib/load.ts +170 -62
- package/src/node-lib/module-hooks.ts +5 -2
- package/src/node-lib/public-modules.ts +12 -48
- package/src/node-lib/sources.ts +4 -0
- package/src/node-lib/timers.ts +93 -0
- package/src/node-process-host.ts +124 -0
- package/src/process-registry.ts +144 -0
- package/src/process-tokens.ts +60 -6
- package/src/promise-ownership.ts +28 -0
- package/src/runtime.ts +90 -214
- package/src/shims/child_process.ts +313 -80
- package/src/shims/crypto.ts +115 -100
- package/src/shims/dns.ts +17 -1
- package/src/shims/process.ts +33 -11
- package/src/shims/string_decoder.ts +10 -6
- package/src/shims/tls.ts +49 -19
- package/src/source-edits.ts +20 -0
|
@@ -15,6 +15,7 @@ import { LibuvStreamWrap, type WriteWrap } from './stream_wrap';
|
|
|
15
15
|
import { UV_EADDRINUSE, UV_ENOENT, UV_EBADF } from './uv';
|
|
16
16
|
import { handleForFd, registerFd, releaseFd } from './fds';
|
|
17
17
|
import { __adoptHandle, ownerOf } from './handles';
|
|
18
|
+
import { nativeStreamFor, registerNativeStreamConstructor } from '../../native-stream-binding';
|
|
18
19
|
|
|
19
20
|
/** libuv's `uv_pipe_t` flavours, and the two chmod bits `listen` reads. */
|
|
20
21
|
export const constants = {
|
|
@@ -51,9 +52,12 @@ export class Pipe extends LibuvStreamWrap {
|
|
|
51
52
|
constructor(type: number = constants.SOCKET) {
|
|
52
53
|
super();
|
|
53
54
|
this.type = type;
|
|
55
|
+
this.attachNative('pipe', type);
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
bind(path: string): number {
|
|
59
|
+
const native = nativeStreamFor(this);
|
|
60
|
+
if (native) return native.call({ operation: 'bind', id: native.descriptor.id, address: path }).status;
|
|
57
61
|
const held = boundPaths.get(path);
|
|
58
62
|
if (held && held !== this) return UV_EADDRINUSE;
|
|
59
63
|
this.path = path;
|
|
@@ -62,12 +66,20 @@ export class Pipe extends LibuvStreamWrap {
|
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
listen(_backlog: number): number {
|
|
69
|
+
const native = nativeStreamFor(this);
|
|
70
|
+
if (native) {
|
|
71
|
+
const status = native.call({ operation: 'listen', id: native.descriptor.id, backlog: _backlog }).status;
|
|
72
|
+
if (status === 0) this.listening = true;
|
|
73
|
+
return status;
|
|
74
|
+
}
|
|
65
75
|
if (this.path === null) return UV_EBADF;
|
|
66
76
|
this.listening = true;
|
|
67
77
|
return 0;
|
|
68
78
|
}
|
|
69
79
|
|
|
70
80
|
connect(req: PipeConnectWrap, path: string): number {
|
|
81
|
+
const native = nativeStreamFor(this);
|
|
82
|
+
if (native) return native.connect(path, undefined, false, status => req.oncomplete?.(status, this, req, true, true));
|
|
71
83
|
// libuv answers a connect through the request, never from the call.
|
|
72
84
|
queueMicrotask(() => {
|
|
73
85
|
if (this.closed) return;
|
|
@@ -76,7 +88,7 @@ export class Pipe extends LibuvStreamWrap {
|
|
|
76
88
|
req.oncomplete?.(UV_ENOENT, this, req, true, true);
|
|
77
89
|
return;
|
|
78
90
|
}
|
|
79
|
-
const accepted = new Pipe(server.type === constants.IPC ? constants.IPC : constants.SOCKET);
|
|
91
|
+
const accepted = new (server.constructor as typeof Pipe)(server.type === constants.IPC ? constants.IPC : constants.SOCKET);
|
|
80
92
|
accepted.path = path;
|
|
81
93
|
// The serving run owns what it accepted, not the connecting one.
|
|
82
94
|
__adoptHandle(accepted, ownerOf(server));
|
|
@@ -95,6 +107,12 @@ export class Pipe extends LibuvStreamWrap {
|
|
|
95
107
|
* opened it, because a child's channel is written to before the child runs.
|
|
96
108
|
*/
|
|
97
109
|
open(fd: number): number {
|
|
110
|
+
const native = nativeStreamFor(this);
|
|
111
|
+
if (native) {
|
|
112
|
+
const status = native.call({ operation: 'open', id: native.descriptor.id, fd }).status;
|
|
113
|
+
if (status === 0) this.fd = fd;
|
|
114
|
+
return status;
|
|
115
|
+
}
|
|
98
116
|
const held = handleForFd(fd) as LibuvStreamWrap | undefined;
|
|
99
117
|
if (!held) return UV_EBADF;
|
|
100
118
|
this.takeOverFrom(held);
|
|
@@ -111,8 +129,9 @@ export class Pipe extends LibuvStreamWrap {
|
|
|
111
129
|
|
|
112
130
|
/** libuv's `dup()`: the same pairing, under the same flavour. */
|
|
113
131
|
override duplicate(): Pipe {
|
|
114
|
-
const
|
|
115
|
-
copy.
|
|
132
|
+
const native = nativeStreamFor(this);
|
|
133
|
+
const copy = native ? native.duplicate() as Pipe : new (this.constructor as typeof Pipe)(this.type);
|
|
134
|
+
if (!native) copy.shareConnectionFrom(this);
|
|
116
135
|
return copy;
|
|
117
136
|
}
|
|
118
137
|
|
|
@@ -133,14 +152,16 @@ export class Pipe extends LibuvStreamWrap {
|
|
|
133
152
|
*
|
|
134
153
|
* The handle becomes the receiving run's. Node's `send(message, socket)`
|
|
135
154
|
* duplicates the sender's descriptor into the other process, and from then
|
|
136
|
-
* on the socket is an active handle of that process's loop
|
|
137
|
-
*
|
|
138
|
-
*
|
|
155
|
+
* on the socket is an active handle of that process's loop. The binding
|
|
156
|
+
* duplicates the wrapper and assigns that reference to the receiver.
|
|
157
|
+
* Without that ownership, openvscode-server's extension
|
|
139
158
|
* host -- a program whose only handle is the socket its parent sent it --
|
|
140
159
|
* read as idle and was settled with exit 0.
|
|
141
160
|
*/
|
|
142
|
-
override
|
|
143
|
-
|
|
161
|
+
protected override dispatchWrite(req: WriteWrap, bytes: Uint8Array, handle?: unknown): number {
|
|
162
|
+
const native = nativeStreamFor(this);
|
|
163
|
+
if (native) return native.write(req, [bytes], handle);
|
|
164
|
+
if (handle === undefined || handle === null) return super.dispatchWrite(req, bytes);
|
|
144
165
|
// A descriptor crosses as a duplicate, as `SCM_RIGHTS` hands one over: the
|
|
145
166
|
// receiver gets its own handle on the same connection, so the sender's
|
|
146
167
|
// close on `NODE_HANDLE_ACK` -- which Node's `child_process.js` does the
|
|
@@ -148,11 +169,12 @@ export class Pipe extends LibuvStreamWrap {
|
|
|
148
169
|
// a listening server's, has nothing to duplicate and crosses as it is.
|
|
149
170
|
const sent = handle as LibuvStreamWrap;
|
|
150
171
|
const given = sent.peer !== null ? sent.duplicate() : sent;
|
|
151
|
-
// The receiving run owns
|
|
152
|
-
//
|
|
153
|
-
// engine keeps of what holds a run open.
|
|
172
|
+
// The receiving run owns this reference; the sender retains its own until
|
|
173
|
+
// Node closes it on acknowledgement, or continues using it with keepOpen.
|
|
154
174
|
__adoptHandle(given, ownerOf(this.peer ?? this));
|
|
155
|
-
|
|
175
|
+
const status = super.dispatchWrite(req, bytes, given);
|
|
176
|
+
if (status !== 0 && given !== sent) given.close();
|
|
177
|
+
return status;
|
|
156
178
|
}
|
|
157
179
|
|
|
158
180
|
protected override onCloseHandle(): void {
|
|
@@ -163,4 +185,5 @@ export class Pipe extends LibuvStreamWrap {
|
|
|
163
185
|
}
|
|
164
186
|
}
|
|
165
187
|
|
|
188
|
+
registerNativeStreamConstructor('pipe', Pipe);
|
|
166
189
|
export default { Pipe, PipeConnectWrap, constants };
|
|
@@ -25,9 +25,11 @@ import { Pipe, constants as pipeConstants } from './pipe_wrap';
|
|
|
25
25
|
import { UV_ENOENT, UV_ESRCH } from './uv';
|
|
26
26
|
import {
|
|
27
27
|
registerHandle, refHandle, unrefHandle, handleHasRef, releaseHandle, __adoptHandle,
|
|
28
|
-
type OwnedHandle,
|
|
28
|
+
ownerOf, type OwnedHandle,
|
|
29
29
|
} from './handles';
|
|
30
|
-
import type
|
|
30
|
+
import { __runFor, mintPid, type ProcessToken } from '../../process-tokens';
|
|
31
|
+
import { handleForFd } from './fds';
|
|
32
|
+
import { TTY, type TerminalState } from './tty_wrap';
|
|
31
33
|
|
|
32
34
|
/** One entry of Node's `options.stdio`, as `getValidStdio` builds it. */
|
|
33
35
|
export interface StdioEntry {
|
|
@@ -85,8 +87,14 @@ export interface RunRequest {
|
|
|
85
87
|
stderrIsPipe: boolean;
|
|
86
88
|
/** True when the child's fd 0 is a pipe whose writer has not closed. */
|
|
87
89
|
stdinIsPipe: boolean;
|
|
90
|
+
terminal?: TerminalState;
|
|
88
91
|
/** The IPC channel the child is started with, where it has one. */
|
|
89
92
|
channel?: RunChannel;
|
|
93
|
+
/**
|
|
94
|
+
* The child's pipes past fd 2 (`stdio: [..., 'pipe', 'pipe']`), each at the
|
|
95
|
+
* number the child reads or writes it by, with the child's end of it.
|
|
96
|
+
*/
|
|
97
|
+
descriptors: { fd: number; pipe: Pipe }[];
|
|
90
98
|
/** Called once, when the run has ended. */
|
|
91
99
|
exit(code: number, signal: string | null): void;
|
|
92
100
|
}
|
|
@@ -100,7 +108,7 @@ export interface StartedRun {
|
|
|
100
108
|
/** libuv's `uv_process_kill`: 0, or `UV_ESRCH` for a run already over. */
|
|
101
109
|
kill(signal: string): number;
|
|
102
110
|
/** Bytes the parent wrote to the child's fd 0. */
|
|
103
|
-
writeStdin(bytes: Uint8Array): void
|
|
111
|
+
writeStdin(bytes: Uint8Array): void | Promise<void>;
|
|
104
112
|
/** The parent closed the child's fd 0. */
|
|
105
113
|
endStdin(): void;
|
|
106
114
|
}
|
|
@@ -123,7 +131,6 @@ export function setProcessRunner(next: ProcessRunner): void {
|
|
|
123
131
|
runner = next;
|
|
124
132
|
}
|
|
125
133
|
|
|
126
|
-
let nextPid = 1001 + Math.floor(Math.random() * 30000);
|
|
127
134
|
let nextAsyncId = 1;
|
|
128
135
|
|
|
129
136
|
/** `envPairs` is `KEY=value` strings; the engine's shell takes a record. */
|
|
@@ -154,18 +161,31 @@ function signalNameOf(signal: number | string): string {
|
|
|
154
161
|
* `/work` means `/work/child.js`, and resolved against the engine's shell's
|
|
155
162
|
* own root it meant `/child.js` and a child that exited 1.
|
|
156
163
|
*/
|
|
157
|
-
|
|
158
|
-
|
|
164
|
+
// A shared realm's process global is whichever guest ran last. The spawning
|
|
165
|
+
// handle belongs to the parent: inherited stdio and cwd must come from that
|
|
166
|
+
// parent's process, even while a sibling starts or exits. A failed fork was
|
|
167
|
+
// replaying stderr into its own closed IPC-backed stream (write EBADF).
|
|
168
|
+
function parentProcess(token: ProcessToken | null) {
|
|
169
|
+
return token !== null ? __runFor(token)?.process
|
|
170
|
+
: (globalThis as unknown as { process?: { cwd?: () => string; stdout?: { write(text: string): unknown }; stderr?: { write(text: string): unknown } } }).process;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function spawningDirectory(token: ProcessToken | null): string | undefined {
|
|
174
|
+
const realm = parentProcess(token);
|
|
159
175
|
if (typeof realm?.cwd !== 'function') return undefined;
|
|
160
176
|
try { return realm.cwd(); } catch { return undefined; }
|
|
161
177
|
}
|
|
162
178
|
|
|
163
179
|
/** Where an `inherit` entry's bytes go: the spawning program's own stream. */
|
|
164
|
-
function inheritedWriter(fd: number): ((text: string) => void) | null {
|
|
180
|
+
function inheritedWriter(fd: number, token: ProcessToken | null): ((text: string) => void) | null {
|
|
165
181
|
if (fd !== 1 && fd !== 2) return null;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
182
|
+
// Inherit the descriptor's original sink, not a guest replacement of
|
|
183
|
+
// process.stderr.write (a child commonly redirects its console over IPC).
|
|
184
|
+
if (token !== null) {
|
|
185
|
+
const parent = __runFor(token);
|
|
186
|
+
return (fd === 1 ? parent?.stdout : parent?.stderr) ?? null;
|
|
187
|
+
}
|
|
188
|
+
const realm = parentProcess(token);
|
|
169
189
|
const stream = fd === 1 ? realm?.stdout : realm?.stderr;
|
|
170
190
|
if (!stream || typeof stream.write !== 'function') return null;
|
|
171
191
|
return (text: string) => {
|
|
@@ -195,6 +215,7 @@ export class Process implements OwnedHandle {
|
|
|
195
215
|
private closed = false;
|
|
196
216
|
/** The stdio entries this run was started with, and their far ends. */
|
|
197
217
|
private stdio: StdioEntry[] = [];
|
|
218
|
+
private terminalEnds = new Map<number, TTY>();
|
|
198
219
|
private readonly asyncId = nextAsyncId++;
|
|
199
220
|
|
|
200
221
|
constructor() {
|
|
@@ -230,20 +251,37 @@ export class Process implements OwnedHandle {
|
|
|
230
251
|
const request: RunRequest = {
|
|
231
252
|
file: options.file,
|
|
232
253
|
args: options.args ?? [options.file],
|
|
233
|
-
cwd: options.cwd ?? spawningDirectory(),
|
|
254
|
+
cwd: options.cwd ?? spawningDirectory(ownerOf(this)),
|
|
234
255
|
env,
|
|
235
256
|
detached: options.detached === true,
|
|
236
257
|
stdout: null,
|
|
237
258
|
stderr: null,
|
|
238
259
|
stderrIsPipe: false,
|
|
239
260
|
stdinIsPipe: false,
|
|
261
|
+
descriptors: [],
|
|
240
262
|
exit: (code, signal) => { this.reportExit(code, signal); },
|
|
241
263
|
};
|
|
242
264
|
|
|
243
|
-
let stdinFar:
|
|
265
|
+
let stdinFar: LibuvStreamWrap | null = null;
|
|
244
266
|
for (let index = 0; index < this.stdio.length; index += 1) {
|
|
245
267
|
const entry = this.stdio[index];
|
|
246
268
|
if (!entry) continue;
|
|
269
|
+
if (index < 3 && !entry.ipc) {
|
|
270
|
+
const descriptor = entry.type === 'fd' || entry.type === 'inherit'
|
|
271
|
+
? handleForFd(entry.fd ?? index) : entry.handle;
|
|
272
|
+
if (descriptor instanceof TTY && descriptor.slave) {
|
|
273
|
+
// Inherit an independent descriptor reference, never the parent's
|
|
274
|
+
// wrapper. Failed spawn and child exit release only this copy.
|
|
275
|
+
const inherited = descriptor.duplicate();
|
|
276
|
+
__adoptHandle(inherited, null);
|
|
277
|
+
this.terminalEnds.set(index, inherited);
|
|
278
|
+
request.terminal = inherited.terminal;
|
|
279
|
+
if (index === 0) { stdinFar = inherited; request.stdinIsPipe = true; }
|
|
280
|
+
else if (index === 1) request.stdout = text => this.toPipe(index, text);
|
|
281
|
+
else request.stderr = text => this.toPipe(index, text);
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
247
285
|
const far = this.pairFarEnd(entry);
|
|
248
286
|
if (entry.ipc) {
|
|
249
287
|
if (far) {
|
|
@@ -260,7 +298,12 @@ export class Process implements OwnedHandle {
|
|
|
260
298
|
request.stdinIsPipe = far !== null;
|
|
261
299
|
continue;
|
|
262
300
|
}
|
|
263
|
-
if (index
|
|
301
|
+
if (index > 2) {
|
|
302
|
+
// A pipe past fd 2 is the child's too, at its own number: libuv
|
|
303
|
+
// hands a child every `UV_CREATE_PIPE` entry, not only stdio's three.
|
|
304
|
+
if (far) request.descriptors.push({ fd: index, pipe: far });
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
264
307
|
if (far) {
|
|
265
308
|
const to = index;
|
|
266
309
|
const write = (text: string): void => { this.toPipe(to, text); };
|
|
@@ -270,7 +313,7 @@ export class Process implements OwnedHandle {
|
|
|
270
313
|
request.stderrIsPipe = true;
|
|
271
314
|
}
|
|
272
315
|
} else if (entry.type === 'inherit' || entry.type === 'fd') {
|
|
273
|
-
const inherited = inheritedWriter(entry.fd ?? index);
|
|
316
|
+
const inherited = inheritedWriter(entry.fd ?? index, ownerOf(this));
|
|
274
317
|
if (index === 1) request.stdout = inherited;
|
|
275
318
|
else request.stderr = inherited;
|
|
276
319
|
}
|
|
@@ -284,7 +327,7 @@ export class Process implements OwnedHandle {
|
|
|
284
327
|
this.run = runner.start(request);
|
|
285
328
|
// The number the parent reads off the handle is the child's own
|
|
286
329
|
// `process.pid`, as it is in Node; a runner that names none is given one.
|
|
287
|
-
this.pid = this.run.pid ??
|
|
330
|
+
this.pid = this.run.pid ?? mintPid();
|
|
288
331
|
if (stdinFar) this.readStdinFrom(stdinFar);
|
|
289
332
|
return 0;
|
|
290
333
|
}
|
|
@@ -324,7 +367,7 @@ export class Process implements OwnedHandle {
|
|
|
324
367
|
|
|
325
368
|
/** The far end of fd `index`, whoever holds it now. */
|
|
326
369
|
private farEndAt(index: number): LibuvStreamWrap | null {
|
|
327
|
-
return this.stdio[index]?.handle?.peer ?? null;
|
|
370
|
+
return this.terminalEnds.get(index) ?? this.stdio[index]?.handle?.peer ?? null;
|
|
328
371
|
}
|
|
329
372
|
|
|
330
373
|
private closeFarEnds(): void {
|
|
@@ -343,11 +386,22 @@ export class Process implements OwnedHandle {
|
|
|
343
386
|
}
|
|
344
387
|
|
|
345
388
|
/** Bytes the parent writes reach the child's fd 0; the parent's EOF ends it. */
|
|
346
|
-
private readStdinFrom(far:
|
|
389
|
+
private readStdinFrom(far: LibuvStreamWrap): void {
|
|
347
390
|
far.onread = (arrayBuffer: ArrayBuffer | null): void => {
|
|
348
391
|
const length = streamBaseState[kReadBytesOrError];
|
|
349
392
|
if (length <= 0 || arrayBuffer === null) { this.run?.endStdin(); return; }
|
|
350
|
-
|
|
393
|
+
const run = this.run;
|
|
394
|
+
const consumed = run?.writeStdin(new Uint8Array(arrayBuffer, streamBaseState[kArrayBufferOffset], length).slice());
|
|
395
|
+
if (consumed) {
|
|
396
|
+
far.readStop();
|
|
397
|
+
void consumed.then(() => {
|
|
398
|
+
if (this.run === run && !this.ended && !far.closed) far.readStart();
|
|
399
|
+
}, () => {
|
|
400
|
+
// A stopped receiver closes its input pipe. Do not resume a reader
|
|
401
|
+
// or deliver its queued bytes to a later run.
|
|
402
|
+
if (this.run === run && !this.ended) { far.close(); run?.endStdin(); }
|
|
403
|
+
});
|
|
404
|
+
}
|
|
351
405
|
};
|
|
352
406
|
far.readStart();
|
|
353
407
|
}
|