@imenam/self-register-proxy 1.0.46 → 1.0.48

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.
@@ -1,154 +1,154 @@
1
- const os = require('os');
2
- const { execSync } = require('child_process');
3
- const pty = require('node-pty');
4
- const { WebSocketServer } = require('ws');
5
-
6
- const DEFAULT_SHELL = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
7
-
8
- class TerminalServer {
9
- /**
10
- * @param {import('http').Server} httpServer
11
- * @param {object} [options]
12
- * @param {string} [options.shell] - Shell to spawn (default: auto-detected)
13
- * @param {string[]} [options.shellArgs] - Shell arguments (default: [])
14
- * @param {object} [options.ptyOptions] - node-pty spawn options overrides
15
- * @param {number} [options.ptyOptions.cols] - Initial columns (default: 80)
16
- * @param {number} [options.ptyOptions.rows] - Initial rows (default: 24)
17
- * @param {string} [options.ptyOptions.cwd] - Working directory (default: user home)
18
- * @param {object} [options.ptyOptions.env] - Environment variables (default: process.env)
19
- * @param {string} [options.command] - Command to execute automatically after spawn
20
- * @param {string} [options.path] - WebSocket endpoint path (default: '/terminal')
21
- * @param {object} [options.wsOptions] - WebSocketServer options overrides
22
- */
23
- constructor(httpServer, options = {}) {
24
- this.shell = options.shell || DEFAULT_SHELL;
25
- this.shellArgs = options.shellArgs || [];
26
- this.command = options.command || '';
27
- this.ptyOptions = {
28
- name: 'xterm-color',
29
- cols: 80,
30
- rows: 24,
31
- cwd: process.env.HOME || process.env.USERPROFILE,
32
- env: process.env,
33
- ...options.ptyOptions,
34
- };
35
-
36
- this.connections = new Set();
37
-
38
- this.wss = new WebSocketServer({
39
- server: httpServer,
40
- path: options.path || '/terminal',
41
- ...options.wsOptions,
42
- });
43
- this.wss.on('connection', (ws, req) => this._handleConnection(ws, req));
44
- }
45
-
46
- _handleConnection(ws, req) {
47
- const cwd = this.ptyOptions.cwd;
48
-
49
- let ptyProcess;
50
- try {
51
- ptyProcess = pty.spawn(this.shell, this.shellArgs, {
52
- ...this.ptyOptions,
53
- cwd,
54
- });
55
- } catch (err) {
56
- console.error(`[TERMINAL] Failed to spawn PTY (cwd: ${cwd}):`, err.message);
57
- ws.close(1011, 'Failed to spawn terminal');
58
- return;
59
- }
60
-
61
- const connection = { ws, ptyProcess };
62
- this.connections.add(connection);
63
-
64
- ptyProcess.onData((data) => {
65
- try {
66
- ws.send(data);
67
- } catch (e) {
68
- // WebSocket already closed
69
- }
70
- });
71
-
72
- ws.on('message', (data) => {
73
- const message = data.toString();
74
- try {
75
- const msg = JSON.parse(message);
76
- if (msg.type === 'resize') {
77
- ptyProcess.resize(msg.cols, msg.rows);
78
- return;
79
- }
80
- } catch (e) {
81
- // Not JSON, treat as terminal input
82
- }
83
- ptyProcess.write(message);
84
- });
85
-
86
- ws.on('close', () => {
87
- this._gracefulKill(ptyProcess);
88
- this.connections.delete(connection);
89
- });
90
-
91
- // Exécuter automatiquement la commande configurée
92
- if (this.command) {
93
- // Petit délai pour laisser le shell s'initialiser
94
- setTimeout(() => {
95
- ptyProcess.write(this.command + '\r');
96
- console.log(`[TERMINAL] Auto-executed command: ${this.command}`);
97
- }, 500);
98
- }
99
- }
100
-
101
- /**
102
- * Arrêt gracieux : envoie Ctrl+C deux fois pour interrompre proprement
103
- * le programme en cours, attend qu'il se termine, puis tue le shell.
104
- * @param {import('node-pty').IPty} ptyProcess
105
- */
106
- _gracefulKill(ptyProcess) {
107
- const pid = ptyProcess.pid;
108
- console.log(`[TERMINAL] Graceful shutdown (PID: ${pid})...`);
109
-
110
- // 1er Ctrl+C
111
- try { ptyProcess.write('\x03'); } catch (_) { /* ignore */ }
112
-
113
- setTimeout(() => {
114
- // 2e Ctrl+C
115
- try { ptyProcess.write('\x03'); } catch (_) { /* ignore */ }
116
-
117
- setTimeout(() => {
118
- // Tuer tout l'arbre de processus
119
- this._killProcessTree(pid);
120
- }, 1000);
121
- }, 500);
122
- }
123
-
124
- /**
125
- * Tue l'arbre de processus par PID.
126
- * Sur Windows : taskkill /F /T /PID
127
- * Sur Linux/macOS : kill du groupe de processus
128
- * @param {number} pid
129
- */
130
- _killProcessTree(pid) {
131
- try {
132
- if (os.platform() === 'win32') {
133
- execSync(`taskkill /F /T /PID ${pid}`, { stdio: 'ignore' });
134
- } else {
135
- process.kill(-pid, 'SIGKILL');
136
- }
137
- console.log(`[TERMINAL] Killed process tree (PID: ${pid})`);
138
- } catch (e) {
139
- // Le processus est peut-être déjà terminé
140
- console.log(`[TERMINAL] Process tree already exited (PID: ${pid})`);
141
- }
142
- }
143
-
144
- dispose() {
145
- for (const { ws, ptyProcess } of this.connections) {
146
- this._gracefulKill(ptyProcess);
147
- ws.close();
148
- }
149
- this.connections.clear();
150
- this.wss.close();
151
- }
152
- }
153
-
154
- module.exports = { TerminalServer };
1
+ const os = require('os');
2
+ const { execSync } = require('child_process');
3
+ const pty = require('node-pty');
4
+ const { WebSocketServer } = require('ws');
5
+
6
+ const DEFAULT_SHELL = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
7
+
8
+ class TerminalServer {
9
+ /**
10
+ * @param {import('http').Server} httpServer
11
+ * @param {object} [options]
12
+ * @param {string} [options.shell] - Shell to spawn (default: auto-detected)
13
+ * @param {string[]} [options.shellArgs] - Shell arguments (default: [])
14
+ * @param {object} [options.ptyOptions] - node-pty spawn options overrides
15
+ * @param {number} [options.ptyOptions.cols] - Initial columns (default: 80)
16
+ * @param {number} [options.ptyOptions.rows] - Initial rows (default: 24)
17
+ * @param {string} [options.ptyOptions.cwd] - Working directory (default: user home)
18
+ * @param {object} [options.ptyOptions.env] - Environment variables (default: process.env)
19
+ * @param {string} [options.command] - Command to execute automatically after spawn
20
+ * @param {string} [options.path] - WebSocket endpoint path (default: '/terminal')
21
+ * @param {object} [options.wsOptions] - WebSocketServer options overrides
22
+ */
23
+ constructor(httpServer, options = {}) {
24
+ this.shell = options.shell || DEFAULT_SHELL;
25
+ this.shellArgs = options.shellArgs || [];
26
+ this.command = options.command || '';
27
+ this.ptyOptions = {
28
+ name: 'xterm-color',
29
+ cols: 80,
30
+ rows: 24,
31
+ cwd: process.env.HOME || process.env.USERPROFILE,
32
+ env: process.env,
33
+ ...options.ptyOptions,
34
+ };
35
+
36
+ this.connections = new Set();
37
+
38
+ this.wss = new WebSocketServer({
39
+ server: httpServer,
40
+ path: options.path || '/terminal',
41
+ ...options.wsOptions,
42
+ });
43
+ this.wss.on('connection', (ws, req) => this._handleConnection(ws, req));
44
+ }
45
+
46
+ _handleConnection(ws, req) {
47
+ const cwd = this.ptyOptions.cwd;
48
+
49
+ let ptyProcess;
50
+ try {
51
+ ptyProcess = pty.spawn(this.shell, this.shellArgs, {
52
+ ...this.ptyOptions,
53
+ cwd,
54
+ });
55
+ } catch (err) {
56
+ console.error(`[TERMINAL] Failed to spawn PTY (cwd: ${cwd}):`, err.message);
57
+ ws.close(1011, 'Failed to spawn terminal');
58
+ return;
59
+ }
60
+
61
+ const connection = { ws, ptyProcess };
62
+ this.connections.add(connection);
63
+
64
+ ptyProcess.onData((data) => {
65
+ try {
66
+ ws.send(data);
67
+ } catch (e) {
68
+ // WebSocket already closed
69
+ }
70
+ });
71
+
72
+ ws.on('message', (data) => {
73
+ const message = data.toString();
74
+ try {
75
+ const msg = JSON.parse(message);
76
+ if (msg.type === 'resize') {
77
+ ptyProcess.resize(msg.cols, msg.rows);
78
+ return;
79
+ }
80
+ } catch (e) {
81
+ // Not JSON, treat as terminal input
82
+ }
83
+ ptyProcess.write(message);
84
+ });
85
+
86
+ ws.on('close', () => {
87
+ this._gracefulKill(ptyProcess);
88
+ this.connections.delete(connection);
89
+ });
90
+
91
+ // Exécuter automatiquement la commande configurée
92
+ if (this.command) {
93
+ // Petit délai pour laisser le shell s'initialiser
94
+ setTimeout(() => {
95
+ ptyProcess.write(this.command + '\r');
96
+ console.log(`[TERMINAL] Auto-executed command: ${this.command}`);
97
+ }, 500);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Arrêt gracieux : envoie Ctrl+C deux fois pour interrompre proprement
103
+ * le programme en cours, attend qu'il se termine, puis tue le shell.
104
+ * @param {import('node-pty').IPty} ptyProcess
105
+ */
106
+ _gracefulKill(ptyProcess) {
107
+ const pid = ptyProcess.pid;
108
+ console.log(`[TERMINAL] Graceful shutdown (PID: ${pid})...`);
109
+
110
+ // 1er Ctrl+C
111
+ try { ptyProcess.write('\x03'); } catch (_) { /* ignore */ }
112
+
113
+ setTimeout(() => {
114
+ // 2e Ctrl+C
115
+ try { ptyProcess.write('\x03'); } catch (_) { /* ignore */ }
116
+
117
+ setTimeout(() => {
118
+ // Tuer tout l'arbre de processus
119
+ this._killProcessTree(pid);
120
+ }, 1000);
121
+ }, 500);
122
+ }
123
+
124
+ /**
125
+ * Tue l'arbre de processus par PID.
126
+ * Sur Windows : taskkill /F /T /PID
127
+ * Sur Linux/macOS : kill du groupe de processus
128
+ * @param {number} pid
129
+ */
130
+ _killProcessTree(pid) {
131
+ try {
132
+ if (os.platform() === 'win32') {
133
+ execSync(`taskkill /F /T /PID ${pid}`, { stdio: 'ignore' });
134
+ } else {
135
+ process.kill(-pid, 'SIGKILL');
136
+ }
137
+ console.log(`[TERMINAL] Killed process tree (PID: ${pid})`);
138
+ } catch (e) {
139
+ // Le processus est peut-être déjà terminé
140
+ console.log(`[TERMINAL] Process tree already exited (PID: ${pid})`);
141
+ }
142
+ }
143
+
144
+ dispose() {
145
+ for (const { ws, ptyProcess } of this.connections) {
146
+ this._gracefulKill(ptyProcess);
147
+ ws.close();
148
+ }
149
+ this.connections.clear();
150
+ this.wss.close();
151
+ }
152
+ }
153
+
154
+ module.exports = { TerminalServer };