Files
SnowLuma/.pnpm-store/v11/files/3c/521675b8f5ce890b7c595f89d723485e57cd98000291108d14b7f5b215ae4117f0d920f30335c27e2d8c49130514bd1469f35600bca397dc8feac02306e26a
T
TanTan 2a69b23b47
Dev Build / cleanup (push) Canceled after 0s
Dev Build / typecheck (push) Canceled after 0s
Dev Build / build (linux-arm64, ubuntu-24.04-arm, linux-arm64) (push) Canceled after 0s
Dev Build / build (linux-x64, ubuntu-latest, linux-x64) (push) Canceled after 0s
Dev Build / build (win-x64, windows-latest, win32-x64) (push) Canceled after 0s
Dev Build / dispatch-dev-docker (push) Canceled after 0s
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

218 lines
6.0 KiB
Plaintext

import { Nt as SdkError, Pt as SdkErrorCode, f as serializeMessage, l as ReadBuffer } from "./src-WCy6ifGf.mjs";
import process from "node:process";
import { PassThrough } from "node:stream";
import spawn from "cross-spawn";
//#region src/client/stdio.ts
/**
* Environment variables to inherit by default, if an environment is not explicitly given.
*/
const DEFAULT_INHERITED_ENV_VARS = process.platform === "win32" ? [
"APPDATA",
"COMSPEC",
"HOMEDRIVE",
"HOMEPATH",
"LOCALAPPDATA",
"PATH",
"PATHEXT",
"PROCESSOR_ARCHITECTURE",
"PROGRAMDATA",
"PROGRAMFILES",
"PROGRAMFILES(X86)",
"PROGRAMW6432",
"SYSTEMDRIVE",
"SYSTEMROOT",
"TEMP",
"USERNAME",
"USERPROFILE",
"WINDIR"
] : [
"HOME",
"LOGNAME",
"PATH",
"SHELL",
"TERM",
"USER"
];
/**
* Returns a default environment object including only environment variables deemed safe to inherit.
*/
function getDefaultEnvironment() {
const env = {};
for (const key of DEFAULT_INHERITED_ENV_VARS) {
const value = process.env[key];
if (value === void 0) continue;
if (value.startsWith("()")) continue;
env[key] = value;
}
return env;
}
/**
* Client transport for stdio: this will connect to a server by spawning a process and communicating with it over stdin/stdout.
*
* This transport is only available in Node.js environments.
*/
var StdioClientTransport = class {
_process;
_readBuffer;
_serverParams;
_stderrStream = null;
onclose;
onerror;
onmessage;
constructor(server) {
this._serverParams = server;
this._readBuffer = new ReadBuffer({ maxBufferSize: server.maxBufferSize });
if (server.stderr === "pipe" || server.stderr === "overlapped") this._stderrStream = new PassThrough();
}
/**
* Starts the server process and prepares to communicate with it.
*/
async start() {
if (this._process) throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
return new Promise((resolve, reject) => {
this._process = spawn(this._serverParams.command, this._serverParams.args ?? [], {
env: {
...getDefaultEnvironment(),
...this._serverParams.env
},
stdio: [
"pipe",
"pipe",
this._serverParams.stderr ?? "inherit"
],
shell: false,
windowsHide: process.platform === "win32",
cwd: this._serverParams.cwd
});
this._process.on("error", (error) => {
reject(error);
this.onerror?.(error);
});
this._process.on("spawn", () => {
resolve();
});
this._process.on("close", (_code) => {
this._process = void 0;
this.onclose?.();
});
this._process.stdin?.on("error", (error) => {
this.onerror?.(error);
});
this._process.stdout?.on("data", (chunk) => {
try {
this._readBuffer.append(chunk);
this.processReadBuffer();
} catch (error) {
this.onerror?.(error);
this.close().catch(() => {});
}
});
this._process.stdout?.on("error", (error) => {
this.onerror?.(error);
});
if (this._stderrStream && this._process.stderr) this._process.stderr.pipe(this._stderrStream);
});
}
/**
* The `stderr` stream of the child process, if {@linkcode StdioServerParameters.stderr} was set to `"pipe"` or `"overlapped"`.
*
* If `stderr` piping was requested, a `PassThrough` stream is returned _immediately_, allowing callers to
* attach listeners before the `start` method is invoked. This prevents loss of any early
* error output emitted by the child process.
*/
get stderr() {
if (this._stderrStream) return this._stderrStream;
return this._process?.stderr ?? null;
}
/**
* The child process pid spawned by this transport.
*
* This is only available after the transport has been started.
*/
get pid() {
return this._process?.pid ?? null;
}
processReadBuffer() {
while (true) try {
const message = this._readBuffer.readMessage();
if (message === null) break;
this.onmessage?.(message);
} catch (error) {
this.onerror?.(error);
}
}
/**
* Reap a disposable probe sibling (see the version-negotiation sibling
* flow): signal-first teardown awaiting process `exit` — never the `close`
* event, so a helper process holding the child's stdio pipes can never
* block disposal. Not part of the public transport lifecycle.
*
* @internal
*/
async _dispose() {
const proc = this._process;
this._process = void 0;
if (proc && proc.exitCode === null && proc.signalCode === null) {
const exited = new Promise((resolve) => proc.once("exit", () => resolve()));
try {
proc.stdin?.end();
} catch {}
try {
proc.kill("SIGTERM");
} catch {}
await Promise.race([exited, new Promise((resolve) => setTimeout(resolve, 1e3).unref())]);
if (proc.exitCode === null && proc.signalCode === null) try {
proc.kill("SIGKILL");
} catch {}
await exited;
}
try {
proc?.stdout?.destroy();
} catch {}
try {
proc?.stdin?.destroy();
} catch {}
try {
proc?.stderr?.destroy();
} catch {}
this._readBuffer.clear();
}
async close() {
if (this._process) {
const processToClose = this._process;
this._process = void 0;
const closePromise = new Promise((resolve) => {
processToClose.once("close", () => {
resolve();
});
});
try {
processToClose.stdin?.end();
} catch {}
await Promise.race([closePromise, new Promise((resolve) => setTimeout(resolve, 2e3).unref())]);
if (processToClose.exitCode === null) {
try {
processToClose.kill("SIGTERM");
} catch {}
await Promise.race([closePromise, new Promise((resolve) => setTimeout(resolve, 2e3).unref())]);
}
if (processToClose.exitCode === null) try {
processToClose.kill("SIGKILL");
} catch {}
}
this._readBuffer.clear();
}
send(message) {
return new Promise((resolve) => {
if (!this._process?.stdin) throw new SdkError(SdkErrorCode.NotConnected, "Not connected");
const json = serializeMessage(message);
if (this._process.stdin.write(json)) resolve();
else this._process.stdin.once("drain", resolve);
});
}
};
//#endregion
export { DEFAULT_INHERITED_ENV_VARS, StdioClientTransport, getDefaultEnvironment };
//# sourceMappingURL=stdio.mjs.map