node-pty 1.2.0-beta.13 → 1.2.0-beta.14
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/lib/windowsPtyAgent.js +28 -3
- package/lib/windowsTerminal.js +6 -0
- package/package.json +3 -2
- package/prebuilds/darwin-arm64/pty.node +0 -0
- package/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/prebuilds/darwin-x64/pty.node +0 -0
- package/prebuilds/darwin-x64/spawn-helper +0 -0
- package/prebuilds/linux-arm64/pty.node +0 -0
- package/prebuilds/linux-x64/pty.node +0 -0
- package/prebuilds/win32-arm64/conpty.node +0 -0
- package/prebuilds/win32-arm64/conpty.pdb +0 -0
- package/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
- package/prebuilds/win32-x64/conpty.node +0 -0
- package/prebuilds/win32-x64/conpty.pdb +0 -0
- package/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
- package/src/unix/pty.cc +1 -0
- package/src/win/conpty.cc +37 -10
package/lib/windowsPtyAgent.js
CHANGED
|
@@ -12,6 +12,7 @@ var path = require("path");
|
|
|
12
12
|
var child_process_1 = require("child_process");
|
|
13
13
|
var net_1 = require("net");
|
|
14
14
|
var windowsConoutConnection_1 = require("./windowsConoutConnection");
|
|
15
|
+
var eventEmitter2_1 = require("./eventEmitter2");
|
|
15
16
|
var utils_1 = require("./utils");
|
|
16
17
|
var conptyNative;
|
|
17
18
|
/**
|
|
@@ -30,6 +31,7 @@ var WindowsPtyAgent = /** @class */ (function () {
|
|
|
30
31
|
var _this = this;
|
|
31
32
|
this._useConptyDll = _useConptyDll;
|
|
32
33
|
this._innerPid = 0;
|
|
34
|
+
this._onError = new eventEmitter2_1.EventEmitter2();
|
|
33
35
|
if (!conptyNative) {
|
|
34
36
|
conptyNative = (0, utils_1.loadNativeModule)('conpty').module;
|
|
35
37
|
}
|
|
@@ -81,6 +83,11 @@ var WindowsPtyAgent = /** @class */ (function () {
|
|
|
81
83
|
});
|
|
82
84
|
this._inSocket.setEncoding('utf8');
|
|
83
85
|
}
|
|
86
|
+
Object.defineProperty(WindowsPtyAgent.prototype, "onError", {
|
|
87
|
+
get: function () { return this._onError.event; },
|
|
88
|
+
enumerable: false,
|
|
89
|
+
configurable: true
|
|
90
|
+
});
|
|
84
91
|
Object.defineProperty(WindowsPtyAgent.prototype, "inSocket", {
|
|
85
92
|
get: function () { return this._inSocket; },
|
|
86
93
|
enumerable: false,
|
|
@@ -108,13 +115,31 @@ var WindowsPtyAgent = /** @class */ (function () {
|
|
|
108
115
|
});
|
|
109
116
|
WindowsPtyAgent.prototype._completePtyConnection = function () {
|
|
110
117
|
var _this = this;
|
|
118
|
+
var _a;
|
|
111
119
|
if (!this._pendingPtyInfo) {
|
|
112
120
|
return;
|
|
113
121
|
}
|
|
114
|
-
var
|
|
122
|
+
var _b = this._pendingPtyInfo, pty = _b.pty, commandLine = _b.commandLine, cwd = _b.cwd, env = _b.env;
|
|
115
123
|
this._pendingPtyInfo = undefined;
|
|
116
|
-
|
|
117
|
-
|
|
124
|
+
try {
|
|
125
|
+
var connect = conptyNative.connect(pty, commandLine, cwd, env, this._useConptyDll, function (c) { return _this._$onProcessExit(c); });
|
|
126
|
+
this._innerPid = connect.pid;
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
// connect() runs from the conout worker's onReady callback (or its
|
|
130
|
+
// timeout fallback), so a throw here would otherwise surface as an
|
|
131
|
+
// uncaughtException with no way for the consumer to observe it.
|
|
132
|
+
var code = (_a = /error code: (\d+)/.exec(err.message)) === null || _a === void 0 ? void 0 : _a[1];
|
|
133
|
+
this._exitCode = code ? parseInt(code, 10) : -1;
|
|
134
|
+
try {
|
|
135
|
+
this._ptyNative.kill(this._pty, this._useConptyDll);
|
|
136
|
+
}
|
|
137
|
+
catch ( /* already gone */_c) { /* already gone */ }
|
|
138
|
+
this._conoutSocketWorker.dispose();
|
|
139
|
+
this._inSocket.destroy();
|
|
140
|
+
this._outSocket.destroy();
|
|
141
|
+
this._onError.fire(err);
|
|
142
|
+
}
|
|
118
143
|
};
|
|
119
144
|
WindowsPtyAgent.prototype.resize = function (cols, rows) {
|
|
120
145
|
if (this._exitCode !== undefined) {
|
package/lib/windowsTerminal.js
CHANGED
|
@@ -52,6 +52,12 @@ var WindowsTerminal = /** @class */ (function (_super) {
|
|
|
52
52
|
// Create new termal.
|
|
53
53
|
_this._agent = new windowsPtyAgent_1.WindowsPtyAgent(file, args, parsedEnv, cwd, _this._cols, _this._rows, false, opt.useConptyDll, opt.conptyInheritCursor);
|
|
54
54
|
_this._socket = _this._agent.outSocket;
|
|
55
|
+
// The socket 'close' handler that drives 'exit' is only attached after
|
|
56
|
+
// ready_datapipe, which never fires when connect() fails.
|
|
57
|
+
_this._agent.onError(function () {
|
|
58
|
+
_this._close();
|
|
59
|
+
_this.emit('exit', _this._agent.exitCode);
|
|
60
|
+
});
|
|
55
61
|
// Not available until `ready` event emitted.
|
|
56
62
|
_this._pid = _this._agent.innerPid;
|
|
57
63
|
_this._fd = _this._agent.fd;
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Microsoft Corporation"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.2.0-beta.
|
|
7
|
+
"version": "1.2.0-beta.14",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"main": "./lib/index.js",
|
|
10
10
|
"types": "./typings/node-pty.d.ts",
|
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
57
57
|
"@typescript-eslint/parser": "^8.0.0",
|
|
58
58
|
"cross-env": "^5.1.4",
|
|
59
|
-
"eslint": "^
|
|
59
|
+
"eslint": "^10.4.0",
|
|
60
|
+
"globals": "^14.0.0",
|
|
60
61
|
"mocha": "10",
|
|
61
62
|
"node-gyp": "^11.4.2",
|
|
62
63
|
"ps-list": "^6.0.0",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/unix/pty.cc
CHANGED
package/src/win/conpty.cc
CHANGED
|
@@ -46,7 +46,7 @@ struct pty_baton {
|
|
|
46
46
|
HANDLE hOut;
|
|
47
47
|
HPCON hpc;
|
|
48
48
|
|
|
49
|
-
HANDLE hShell;
|
|
49
|
+
HANDLE hShell = nullptr;
|
|
50
50
|
|
|
51
51
|
pty_baton(int _id, HANDLE _hIn, HANDLE _hOut, HPCON _hpc) : id(_id), hIn(_hIn), hOut(_hOut), hpc(_hpc) {};
|
|
52
52
|
};
|
|
@@ -384,6 +384,14 @@ static Napi::Value PtyConnect(const Napi::CallbackInfo& info) {
|
|
|
384
384
|
ConnectNamedPipe(handle->hIn, nullptr);
|
|
385
385
|
ConnectNamedPipe(handle->hOut, nullptr);
|
|
386
386
|
|
|
387
|
+
// Close hIn/hOut on every exit so a throw doesn't leak the named-pipe server handles.
|
|
388
|
+
auto closePipeHandles = [handle]() {
|
|
389
|
+
CloseHandle(handle->hIn);
|
|
390
|
+
CloseHandle(handle->hOut);
|
|
391
|
+
handle->hIn = nullptr;
|
|
392
|
+
handle->hOut = nullptr;
|
|
393
|
+
};
|
|
394
|
+
|
|
387
395
|
// Attach the pseudoconsole to the client application we're creating
|
|
388
396
|
STARTUPINFOEXW siEx{0};
|
|
389
397
|
siEx.StartupInfo.cb = sizeof(STARTUPINFOEXW);
|
|
@@ -394,12 +402,14 @@ static Napi::Value PtyConnect(const Napi::CallbackInfo& info) {
|
|
|
394
402
|
|
|
395
403
|
SIZE_T size = 0;
|
|
396
404
|
InitializeProcThreadAttributeList(NULL, 1, 0, &size);
|
|
397
|
-
BYTE
|
|
398
|
-
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(attrList);
|
|
405
|
+
std::unique_ptr<BYTE[]> attrList = std::make_unique<BYTE[]>(size);
|
|
406
|
+
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(attrList.get());
|
|
399
407
|
|
|
400
408
|
fSuccess = InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size);
|
|
401
409
|
if (!fSuccess) {
|
|
402
|
-
|
|
410
|
+
Napi::Error error = errorWithCode(info, "InitializeProcThreadAttributeList failed");
|
|
411
|
+
closePipeHandles();
|
|
412
|
+
throw error;
|
|
403
413
|
}
|
|
404
414
|
fSuccess = UpdateProcThreadAttribute(siEx.lpAttributeList,
|
|
405
415
|
0,
|
|
@@ -409,7 +419,10 @@ static Napi::Value PtyConnect(const Napi::CallbackInfo& info) {
|
|
|
409
419
|
NULL,
|
|
410
420
|
NULL);
|
|
411
421
|
if (!fSuccess) {
|
|
412
|
-
|
|
422
|
+
Napi::Error error = errorWithCode(info, "UpdateProcThreadAttribute failed");
|
|
423
|
+
DeleteProcThreadAttributeList(siEx.lpAttributeList);
|
|
424
|
+
closePipeHandles();
|
|
425
|
+
throw error;
|
|
413
426
|
}
|
|
414
427
|
|
|
415
428
|
PROCESS_INFORMATION piClient{};
|
|
@@ -426,9 +439,14 @@ static Napi::Value PtyConnect(const Napi::CallbackInfo& info) {
|
|
|
426
439
|
&piClient // lpProcessInformation
|
|
427
440
|
);
|
|
428
441
|
if (!fSuccess) {
|
|
429
|
-
|
|
442
|
+
Napi::Error error = errorWithCode(info, "Cannot create process");
|
|
443
|
+
DeleteProcThreadAttributeList(siEx.lpAttributeList);
|
|
444
|
+
closePipeHandles();
|
|
445
|
+
throw error;
|
|
430
446
|
}
|
|
431
447
|
|
|
448
|
+
DeleteProcThreadAttributeList(siEx.lpAttributeList);
|
|
449
|
+
|
|
432
450
|
HANDLE hLibrary = LoadConptyDll(info, useConptyDll);
|
|
433
451
|
bool fLoadedDll = hLibrary != nullptr;
|
|
434
452
|
if (useConptyDll && fLoadedDll)
|
|
@@ -447,8 +465,7 @@ static Napi::Value PtyConnect(const Napi::CallbackInfo& info) {
|
|
|
447
465
|
// Close the thread handle to avoid resource leak
|
|
448
466
|
CloseHandle(piClient.hThread);
|
|
449
467
|
// Close the input read and output write handle of the pseudoconsole
|
|
450
|
-
|
|
451
|
-
CloseHandle(handle->hOut);
|
|
468
|
+
closePipeHandles();
|
|
452
469
|
|
|
453
470
|
SetupExitCallback(env, exitCallback, handle);
|
|
454
471
|
|
|
@@ -550,7 +567,7 @@ static Napi::Value PtyKill(const Napi::CallbackInfo& info) {
|
|
|
550
567
|
const bool useConptyDll = info[1].As<Napi::Boolean>().Value();
|
|
551
568
|
|
|
552
569
|
std::lock_guard<std::mutex> lock(g_ptyHandlesMutex);
|
|
553
|
-
|
|
570
|
+
pty_baton* handle = get_pty_baton(lock, id);
|
|
554
571
|
|
|
555
572
|
if (handle != nullptr) {
|
|
556
573
|
HANDLE hLibrary = LoadConptyDll(info, useConptyDll);
|
|
@@ -565,7 +582,17 @@ static Napi::Value PtyKill(const Napi::CallbackInfo& info) {
|
|
|
565
582
|
pfnClosePseudoConsole(handle->hpc);
|
|
566
583
|
}
|
|
567
584
|
}
|
|
568
|
-
if (
|
|
585
|
+
// Defensive: if PtyConnect was never called (or failed before closing the
|
|
586
|
+
// pipe handles), release the named pipe server handles here.
|
|
587
|
+
if (handle->hIn != nullptr) {
|
|
588
|
+
CloseHandle(handle->hIn);
|
|
589
|
+
handle->hIn = nullptr;
|
|
590
|
+
}
|
|
591
|
+
if (handle->hOut != nullptr) {
|
|
592
|
+
CloseHandle(handle->hOut);
|
|
593
|
+
handle->hOut = nullptr;
|
|
594
|
+
}
|
|
595
|
+
if (useConptyDll && handle->hShell != nullptr) {
|
|
569
596
|
TerminateProcess(handle->hShell, 1);
|
|
570
597
|
}
|
|
571
598
|
}
|