nikcli-remote 1.0.8 → 1.0.10
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/chunk-GI5RMYH6.js +37 -0
- package/dist/chunk-TIYMAVGV.js +1126 -0
- package/dist/index.cjs +1820 -2881
- package/dist/index.d.cts +91 -65
- package/dist/index.d.ts +91 -65
- package/dist/index.js +228 -7
- package/dist/{localtunnel-XT32JGNN.js → localtunnel-6DCQIYU6.js} +1 -1
- package/dist/server-O3KTQ4KJ.js +7 -0
- package/package.json +1 -1
- package/src/index.ts +57 -12
- package/src/server.ts +83 -110
- package/src/tunnel.ts +24 -0
- package/src/web-client.ts +593 -236
- package/dist/chunk-FYVPBMXV.js +0 -2390
- package/dist/chunk-MCKGQKYU.js +0 -15
- package/dist/server-OYMSDTRP.js +0 -7
package/dist/index.cjs
CHANGED
|
@@ -83,1887 +83,1532 @@ var init_types = __esm({
|
|
|
83
83
|
}
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
//
|
|
87
|
-
var
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
86
|
+
// src/web-client.ts
|
|
87
|
+
var web_client_exports = {};
|
|
88
|
+
__export(web_client_exports, {
|
|
89
|
+
getWebClient: () => getWebClient
|
|
90
|
+
});
|
|
91
|
+
function getWebClient() {
|
|
92
|
+
return `<!DOCTYPE html>
|
|
93
|
+
<html lang="en">
|
|
94
|
+
<head>
|
|
95
|
+
<meta charset="UTF-8">
|
|
96
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
97
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
98
|
+
<meta name="mobile-web-app-capable" content="yes">
|
|
99
|
+
<meta name="theme-color" content="#0d1117">
|
|
100
|
+
<title>NikCLI Remote</title>
|
|
101
|
+
<style>
|
|
102
|
+
:root {
|
|
103
|
+
--bg: #0d1117;
|
|
104
|
+
--bg-secondary: #161b22;
|
|
105
|
+
--fg: #e6edf3;
|
|
106
|
+
--fg-muted: #8b949e;
|
|
107
|
+
--accent: #58a6ff;
|
|
108
|
+
--success: #3fb950;
|
|
109
|
+
--warning: #d29922;
|
|
110
|
+
--error: #f85149;
|
|
111
|
+
--border: #30363d;
|
|
112
|
+
--font-mono: 'SF Mono', 'Fira Code', 'Consolas', monospace;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
* {
|
|
116
|
+
box-sizing: border-box;
|
|
117
|
+
margin: 0;
|
|
118
|
+
padding: 0;
|
|
119
|
+
-webkit-tap-highlight-color: transparent;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
html, body {
|
|
123
|
+
height: 100%;
|
|
124
|
+
background: var(--bg);
|
|
125
|
+
color: var(--fg);
|
|
126
|
+
font-family: var(--font-mono);
|
|
127
|
+
font-size: 14px;
|
|
128
|
+
overflow: hidden;
|
|
129
|
+
touch-action: manipulation;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
#app {
|
|
133
|
+
display: flex;
|
|
134
|
+
flex-direction: column;
|
|
135
|
+
height: 100%;
|
|
136
|
+
height: 100dvh;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Header */
|
|
140
|
+
#header {
|
|
141
|
+
display: flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
justify-content: space-between;
|
|
144
|
+
padding: 12px 16px;
|
|
145
|
+
background: var(--bg-secondary);
|
|
146
|
+
border-bottom: 1px solid var(--border);
|
|
147
|
+
flex-shrink: 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
#header h1 {
|
|
151
|
+
font-size: 16px;
|
|
152
|
+
font-weight: 600;
|
|
153
|
+
color: var(--accent);
|
|
154
|
+
display: flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
gap: 8px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
#header h1::before {
|
|
160
|
+
content: '';
|
|
161
|
+
width: 10px;
|
|
162
|
+
height: 10px;
|
|
163
|
+
background: var(--accent);
|
|
164
|
+
border-radius: 2px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
#status {
|
|
168
|
+
display: flex;
|
|
169
|
+
align-items: center;
|
|
170
|
+
gap: 6px;
|
|
171
|
+
font-size: 12px;
|
|
172
|
+
color: var(--fg-muted);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
#status-dot {
|
|
176
|
+
width: 8px;
|
|
177
|
+
height: 8px;
|
|
178
|
+
border-radius: 50%;
|
|
179
|
+
background: var(--error);
|
|
180
|
+
transition: background 0.3s;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
#status-dot.connected {
|
|
184
|
+
background: var(--success);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
#status-dot.connecting {
|
|
188
|
+
background: var(--warning);
|
|
189
|
+
animation: pulse 1s infinite;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
@keyframes pulse {
|
|
193
|
+
0%, 100% { opacity: 1; }
|
|
194
|
+
50% { opacity: 0.5; }
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* Terminal */
|
|
198
|
+
#terminal-container {
|
|
199
|
+
flex: 1;
|
|
200
|
+
overflow: hidden;
|
|
201
|
+
position: relative;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
#terminal {
|
|
205
|
+
height: 100%;
|
|
206
|
+
padding: 12px;
|
|
207
|
+
overflow-y: auto;
|
|
208
|
+
overflow-x: hidden;
|
|
209
|
+
font-size: 13px;
|
|
210
|
+
line-height: 1.5;
|
|
211
|
+
white-space: pre-wrap;
|
|
212
|
+
word-break: break-all;
|
|
213
|
+
-webkit-overflow-scrolling: touch;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
#terminal::-webkit-scrollbar {
|
|
217
|
+
width: 6px;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
#terminal::-webkit-scrollbar-track {
|
|
221
|
+
background: var(--bg);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
#terminal::-webkit-scrollbar-thumb {
|
|
225
|
+
background: var(--border);
|
|
226
|
+
border-radius: 3px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.cursor {
|
|
230
|
+
display: inline-block;
|
|
231
|
+
width: 8px;
|
|
232
|
+
height: 16px;
|
|
233
|
+
background: var(--fg);
|
|
234
|
+
animation: blink 1s step-end infinite;
|
|
235
|
+
vertical-align: text-bottom;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@keyframes blink {
|
|
239
|
+
50% { opacity: 0; }
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/* Notifications */
|
|
243
|
+
#notifications {
|
|
244
|
+
position: fixed;
|
|
245
|
+
top: 60px;
|
|
246
|
+
left: 12px;
|
|
247
|
+
right: 12px;
|
|
248
|
+
z-index: 1000;
|
|
249
|
+
pointer-events: none;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.notification {
|
|
253
|
+
background: var(--bg-secondary);
|
|
254
|
+
border: 1px solid var(--border);
|
|
255
|
+
border-radius: 8px;
|
|
256
|
+
padding: 12px 16px;
|
|
257
|
+
margin-bottom: 8px;
|
|
258
|
+
animation: slideIn 0.3s ease;
|
|
259
|
+
pointer-events: auto;
|
|
260
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.notification.success { border-left: 3px solid var(--success); }
|
|
264
|
+
.notification.error { border-left: 3px solid var(--error); }
|
|
265
|
+
.notification.warning { border-left: 3px solid var(--warning); }
|
|
266
|
+
.notification.info { border-left: 3px solid var(--accent); }
|
|
267
|
+
|
|
268
|
+
.notification h4 {
|
|
269
|
+
font-size: 14px;
|
|
270
|
+
font-weight: 600;
|
|
271
|
+
margin-bottom: 4px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.notification p {
|
|
275
|
+
font-size: 12px;
|
|
276
|
+
color: var(--fg-muted);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
@keyframes slideIn {
|
|
280
|
+
from { transform: translateY(-20px); opacity: 0; }
|
|
281
|
+
to { transform: translateY(0); opacity: 1; }
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* Quick Keys */
|
|
285
|
+
#quickkeys {
|
|
286
|
+
display: grid;
|
|
287
|
+
grid-template-columns: repeat(6, 1fr);
|
|
288
|
+
gap: 6px;
|
|
289
|
+
padding: 8px 12px;
|
|
290
|
+
background: var(--bg-secondary);
|
|
291
|
+
border-top: 1px solid var(--border);
|
|
292
|
+
flex-shrink: 0;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.qkey {
|
|
296
|
+
background: var(--bg);
|
|
297
|
+
border: 1px solid var(--border);
|
|
298
|
+
border-radius: 6px;
|
|
299
|
+
padding: 10px 4px;
|
|
300
|
+
color: var(--fg);
|
|
301
|
+
font-size: 11px;
|
|
302
|
+
font-family: var(--font-mono);
|
|
303
|
+
text-align: center;
|
|
304
|
+
cursor: pointer;
|
|
305
|
+
user-select: none;
|
|
306
|
+
transition: background 0.1s, transform 0.1s;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.qkey:active {
|
|
310
|
+
background: var(--border);
|
|
311
|
+
transform: scale(0.95);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.qkey.wide {
|
|
315
|
+
grid-column: span 2;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.qkey.accent {
|
|
319
|
+
background: var(--accent);
|
|
320
|
+
border-color: var(--accent);
|
|
321
|
+
color: #fff;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* Input */
|
|
325
|
+
#input-container {
|
|
326
|
+
padding: 12px;
|
|
327
|
+
background: var(--bg-secondary);
|
|
328
|
+
border-top: 1px solid var(--border);
|
|
329
|
+
flex-shrink: 0;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
#input-row {
|
|
333
|
+
display: flex;
|
|
334
|
+
gap: 8px;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
#input {
|
|
338
|
+
flex: 1;
|
|
339
|
+
background: var(--bg);
|
|
340
|
+
border: 1px solid var(--border);
|
|
341
|
+
border-radius: 8px;
|
|
342
|
+
padding: 12px 14px;
|
|
343
|
+
color: var(--fg);
|
|
344
|
+
font-family: var(--font-mono);
|
|
345
|
+
font-size: 16px;
|
|
346
|
+
outline: none;
|
|
347
|
+
transition: border-color 0.2s;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
#input:focus {
|
|
351
|
+
border-color: var(--accent);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
#input::placeholder {
|
|
355
|
+
color: var(--fg-muted);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
#send {
|
|
359
|
+
background: var(--accent);
|
|
360
|
+
color: #fff;
|
|
361
|
+
border: none;
|
|
362
|
+
border-radius: 8px;
|
|
363
|
+
padding: 12px 20px;
|
|
364
|
+
font-size: 14px;
|
|
365
|
+
font-weight: 600;
|
|
366
|
+
font-family: var(--font-mono);
|
|
367
|
+
cursor: pointer;
|
|
368
|
+
transition: opacity 0.2s, transform 0.1s;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
#send:active {
|
|
372
|
+
opacity: 0.8;
|
|
373
|
+
transform: scale(0.98);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/* Auth Screen */
|
|
377
|
+
#auth-screen {
|
|
378
|
+
position: fixed;
|
|
379
|
+
inset: 0;
|
|
380
|
+
background: var(--bg);
|
|
381
|
+
display: flex;
|
|
382
|
+
flex-direction: column;
|
|
383
|
+
align-items: center;
|
|
384
|
+
justify-content: center;
|
|
385
|
+
gap: 20px;
|
|
386
|
+
z-index: 2000;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
#auth-screen.hidden {
|
|
390
|
+
display: none;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.spinner {
|
|
394
|
+
width: 40px;
|
|
395
|
+
height: 40px;
|
|
396
|
+
border: 3px solid var(--border);
|
|
397
|
+
border-top-color: var(--accent);
|
|
398
|
+
border-radius: 50%;
|
|
399
|
+
animation: spin 1s linear infinite;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
@keyframes spin {
|
|
403
|
+
to { transform: rotate(360deg); }
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
#auth-screen p {
|
|
407
|
+
color: var(--fg-muted);
|
|
408
|
+
font-size: 14px;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
#auth-screen .error {
|
|
412
|
+
color: var(--error);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/* Safe area padding for notched devices */
|
|
416
|
+
@supports (padding: env(safe-area-inset-bottom)) {
|
|
417
|
+
#input-container {
|
|
418
|
+
padding-bottom: calc(12px + env(safe-area-inset-bottom));
|
|
120
419
|
}
|
|
121
|
-
throw new Error("Failed to load native module: " + name + ".node, checked: " + dirs.join(", ") + ": " + lastError);
|
|
122
420
|
}
|
|
123
|
-
exports2.loadNativeModule = loadNativeModule;
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
421
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
422
|
+
/* Landscape adjustments */
|
|
423
|
+
@media (max-height: 500px) {
|
|
424
|
+
#quickkeys {
|
|
425
|
+
grid-template-columns: repeat(12, 1fr);
|
|
426
|
+
padding: 6px 8px;
|
|
427
|
+
}
|
|
428
|
+
.qkey {
|
|
429
|
+
padding: 8px 2px;
|
|
430
|
+
font-size: 10px;
|
|
431
|
+
}
|
|
432
|
+
#terminal {
|
|
433
|
+
font-size: 12px;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
</style>
|
|
437
|
+
</head>
|
|
438
|
+
<body>
|
|
439
|
+
<div id="app">
|
|
440
|
+
<div id="auth-screen">
|
|
441
|
+
<div class="spinner"></div>
|
|
442
|
+
<p id="auth-status">Connecting to NikCLI...</p>
|
|
443
|
+
</div>
|
|
444
|
+
|
|
445
|
+
<header id="header">
|
|
446
|
+
<h1>NikCLI Remote</h1>
|
|
447
|
+
<div id="status">
|
|
448
|
+
<span id="status-dot" class="connecting"></span>
|
|
449
|
+
<span id="status-text">Connecting</span>
|
|
450
|
+
</div>
|
|
451
|
+
</header>
|
|
452
|
+
|
|
453
|
+
<div id="terminal-container">
|
|
454
|
+
<div id="terminal"></div>
|
|
455
|
+
</div>
|
|
456
|
+
|
|
457
|
+
<div id="notifications"></div>
|
|
458
|
+
|
|
459
|
+
<div id="quickkeys">
|
|
460
|
+
<button class="qkey" data-key="\\t">Tab</button>
|
|
461
|
+
<button class="qkey" data-key="\\x1b[A">\u2191</button>
|
|
462
|
+
<button class="qkey" data-key="\\x1b[B">\u2193</button>
|
|
463
|
+
<button class="qkey" data-key="\\x1b[D">\u2190</button>
|
|
464
|
+
<button class="qkey" data-key="\\x1b[C">\u2192</button>
|
|
465
|
+
<button class="qkey" data-key="\\x1b">Esc</button>
|
|
466
|
+
<button class="qkey" data-key="\\x03">^C</button>
|
|
467
|
+
<button class="qkey" data-key="\\x04">^D</button>
|
|
468
|
+
<button class="qkey" data-key="\\x1a">^Z</button>
|
|
469
|
+
<button class="qkey" data-key="\\x0c">^L</button>
|
|
470
|
+
<button class="qkey wide accent" data-key="\\r">Enter \u23CE</button>
|
|
471
|
+
</div>
|
|
472
|
+
|
|
473
|
+
<div id="input-container">
|
|
474
|
+
<div id="input-row">
|
|
475
|
+
<input type="text" id="input" placeholder="Type command..." autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">
|
|
476
|
+
<button id="send">Send</button>
|
|
477
|
+
</div>
|
|
478
|
+
</div>
|
|
479
|
+
</div>
|
|
480
|
+
|
|
481
|
+
<script>
|
|
482
|
+
(function() {
|
|
483
|
+
'use strict';
|
|
484
|
+
|
|
485
|
+
// Parse URL params
|
|
486
|
+
const params = new URLSearchParams(location.search);
|
|
487
|
+
const token = params.get('t');
|
|
488
|
+
const sessionId = params.get('s');
|
|
489
|
+
|
|
490
|
+
// DOM elements
|
|
491
|
+
const terminal = document.getElementById('terminal');
|
|
492
|
+
const input = document.getElementById('input');
|
|
493
|
+
const sendBtn = document.getElementById('send');
|
|
494
|
+
const statusDot = document.getElementById('status-dot');
|
|
495
|
+
const statusText = document.getElementById('status-text');
|
|
496
|
+
const authScreen = document.getElementById('auth-screen');
|
|
497
|
+
const authStatus = document.getElementById('auth-status');
|
|
498
|
+
const notifications = document.getElementById('notifications');
|
|
499
|
+
|
|
500
|
+
// State
|
|
501
|
+
let ws = null;
|
|
502
|
+
let reconnectAttempts = 0;
|
|
503
|
+
const maxReconnectAttempts = 5;
|
|
504
|
+
let terminalEnabled = true;
|
|
505
|
+
|
|
506
|
+
// Connect to WebSocket
|
|
507
|
+
function connect() {
|
|
508
|
+
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
509
|
+
ws = new WebSocket(protocol + '//' + location.host);
|
|
510
|
+
|
|
511
|
+
ws.onopen = function() {
|
|
512
|
+
setStatus('connecting', 'Authenticating...');
|
|
513
|
+
ws.send(JSON.stringify({ type: 'auth', token: token }));
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
ws.onmessage = function(event) {
|
|
517
|
+
try {
|
|
518
|
+
const msg = JSON.parse(event.data);
|
|
519
|
+
handleMessage(msg);
|
|
520
|
+
} catch (e) {
|
|
521
|
+
console.error('Parse error:', e);
|
|
170
522
|
}
|
|
171
523
|
};
|
|
172
|
-
return EventEmitter23;
|
|
173
|
-
})()
|
|
174
|
-
);
|
|
175
|
-
exports2.EventEmitter2 = EventEmitter22;
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
524
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
var FLOW_CONTROL_PAUSE = "";
|
|
190
|
-
var FLOW_CONTROL_RESUME = "";
|
|
191
|
-
var Terminal = (
|
|
192
|
-
/** @class */
|
|
193
|
-
(function() {
|
|
194
|
-
function Terminal2(opt) {
|
|
195
|
-
this._pid = 0;
|
|
196
|
-
this._fd = 0;
|
|
197
|
-
this._cols = 0;
|
|
198
|
-
this._rows = 0;
|
|
199
|
-
this._readable = false;
|
|
200
|
-
this._writable = false;
|
|
201
|
-
this._onData = new eventEmitter2_1.EventEmitter2();
|
|
202
|
-
this._onExit = new eventEmitter2_1.EventEmitter2();
|
|
203
|
-
this._internalee = new events_1.EventEmitter();
|
|
204
|
-
this.handleFlowControl = !!(opt === null || opt === void 0 ? void 0 : opt.handleFlowControl);
|
|
205
|
-
this._flowControlPause = (opt === null || opt === void 0 ? void 0 : opt.flowControlPause) || FLOW_CONTROL_PAUSE;
|
|
206
|
-
this._flowControlResume = (opt === null || opt === void 0 ? void 0 : opt.flowControlResume) || FLOW_CONTROL_RESUME;
|
|
207
|
-
if (!opt) {
|
|
208
|
-
return;
|
|
525
|
+
ws.onclose = function() {
|
|
526
|
+
setStatus('disconnected', 'Disconnected');
|
|
527
|
+
if (reconnectAttempts < maxReconnectAttempts) {
|
|
528
|
+
reconnectAttempts++;
|
|
529
|
+
const delay = Math.min(2000 * reconnectAttempts, 10000);
|
|
530
|
+
setTimeout(connect, delay);
|
|
531
|
+
} else {
|
|
532
|
+
authStatus.textContent = 'Connection failed. Refresh to retry.';
|
|
533
|
+
authStatus.classList.add('error');
|
|
534
|
+
authScreen.classList.remove('hidden');
|
|
209
535
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
configurable: true
|
|
232
|
-
});
|
|
233
|
-
Object.defineProperty(Terminal2.prototype, "pid", {
|
|
234
|
-
get: function() {
|
|
235
|
-
return this._pid;
|
|
236
|
-
},
|
|
237
|
-
enumerable: false,
|
|
238
|
-
configurable: true
|
|
239
|
-
});
|
|
240
|
-
Object.defineProperty(Terminal2.prototype, "cols", {
|
|
241
|
-
get: function() {
|
|
242
|
-
return this._cols;
|
|
243
|
-
},
|
|
244
|
-
enumerable: false,
|
|
245
|
-
configurable: true
|
|
246
|
-
});
|
|
247
|
-
Object.defineProperty(Terminal2.prototype, "rows", {
|
|
248
|
-
get: function() {
|
|
249
|
-
return this._rows;
|
|
250
|
-
},
|
|
251
|
-
enumerable: false,
|
|
252
|
-
configurable: true
|
|
253
|
-
});
|
|
254
|
-
Terminal2.prototype.write = function(data) {
|
|
255
|
-
if (this.handleFlowControl) {
|
|
256
|
-
if (data === this._flowControlPause) {
|
|
257
|
-
this.pause();
|
|
258
|
-
return;
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
ws.onerror = function() {
|
|
539
|
+
console.error('WebSocket error');
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Handle incoming message
|
|
544
|
+
function handleMessage(msg) {
|
|
545
|
+
switch (msg.type) {
|
|
546
|
+
case 'auth:required':
|
|
547
|
+
// Already sent auth on open
|
|
548
|
+
break;
|
|
549
|
+
|
|
550
|
+
case 'auth:success':
|
|
551
|
+
authScreen.classList.add('hidden');
|
|
552
|
+
setStatus('connected', 'Connected');
|
|
553
|
+
reconnectAttempts = 0;
|
|
554
|
+
terminalEnabled = msg.payload?.terminalEnabled !== false;
|
|
555
|
+
if (terminalEnabled) {
|
|
556
|
+
appendOutput('\\x1b[32mConnected to NikCLI\\x1b[0m\\n\\n');
|
|
259
557
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
558
|
+
break;
|
|
559
|
+
|
|
560
|
+
case 'auth:failed':
|
|
561
|
+
authStatus.textContent = 'Authentication failed';
|
|
562
|
+
authStatus.classList.add('error');
|
|
563
|
+
break;
|
|
564
|
+
|
|
565
|
+
case 'terminal:output':
|
|
566
|
+
if (msg.payload?.data) {
|
|
567
|
+
appendOutput(msg.payload.data);
|
|
263
568
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
569
|
+
break;
|
|
570
|
+
|
|
571
|
+
case 'terminal:exit':
|
|
572
|
+
appendOutput('\\n\\x1b[33m[Process exited with code ' + (msg.payload?.code || 0) + ']\\x1b[0m\\n');
|
|
573
|
+
break;
|
|
574
|
+
|
|
575
|
+
case 'notification':
|
|
576
|
+
showNotification(msg.payload);
|
|
577
|
+
break;
|
|
578
|
+
|
|
579
|
+
case 'session:end':
|
|
580
|
+
appendOutput('\\n\\x1b[31m[Session ended]\\x1b[0m\\n');
|
|
581
|
+
setStatus('disconnected', 'Session ended');
|
|
582
|
+
break;
|
|
583
|
+
|
|
584
|
+
case 'pong':
|
|
585
|
+
// Heartbeat response
|
|
586
|
+
break;
|
|
587
|
+
|
|
588
|
+
default:
|
|
589
|
+
console.log('Unknown message:', msg.type);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Append text to terminal with ANSI support
|
|
594
|
+
function appendOutput(text) {
|
|
595
|
+
// Simple ANSI to HTML conversion
|
|
596
|
+
const html = ansiToHtml(text);
|
|
597
|
+
terminal.innerHTML += html;
|
|
598
|
+
terminal.scrollTop = terminal.scrollHeight;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Basic ANSI to HTML
|
|
602
|
+
function ansiToHtml(text) {
|
|
603
|
+
const ansiColors = {
|
|
604
|
+
'30': '#6e7681', '31': '#f85149', '32': '#3fb950', '33': '#d29922',
|
|
605
|
+
'34': '#58a6ff', '35': '#bc8cff', '36': '#76e3ea', '37': '#e6edf3',
|
|
606
|
+
'90': '#6e7681', '91': '#f85149', '92': '#3fb950', '93': '#d29922',
|
|
607
|
+
'94': '#58a6ff', '95': '#bc8cff', '96': '#76e3ea', '97': '#ffffff'
|
|
275
608
|
};
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
609
|
+
|
|
610
|
+
let result = '';
|
|
611
|
+
let currentStyle = '';
|
|
612
|
+
|
|
613
|
+
const parts = text.split(/\\x1b\\[([0-9;]+)m/);
|
|
614
|
+
for (let i = 0; i < parts.length; i++) {
|
|
615
|
+
if (i % 2 === 0) {
|
|
616
|
+
// Text content
|
|
617
|
+
result += escapeHtml(parts[i]);
|
|
618
|
+
} else {
|
|
619
|
+
// ANSI code
|
|
620
|
+
const codes = parts[i].split(';');
|
|
621
|
+
for (const code of codes) {
|
|
622
|
+
if (code === '0') {
|
|
623
|
+
if (currentStyle) {
|
|
624
|
+
result += '</span>';
|
|
625
|
+
currentStyle = '';
|
|
288
626
|
}
|
|
289
|
-
})
|
|
290
|
-
|
|
627
|
+
} else if (code === '1') {
|
|
628
|
+
currentStyle = 'font-weight:bold;';
|
|
629
|
+
result += '<span style="' + currentStyle + '">';
|
|
630
|
+
} else if (ansiColors[code]) {
|
|
631
|
+
if (currentStyle) result += '</span>';
|
|
632
|
+
currentStyle = 'color:' + ansiColors[code] + ';';
|
|
633
|
+
result += '<span style="' + currentStyle + '">';
|
|
634
|
+
}
|
|
291
635
|
}
|
|
292
636
|
}
|
|
293
|
-
|
|
294
|
-
throw new Error(name + " must be a " + type + " (not a " + typeof value + ")");
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
Terminal2.prototype.end = function(data) {
|
|
298
|
-
this._socket.end(data);
|
|
299
|
-
};
|
|
300
|
-
Terminal2.prototype.pipe = function(dest, options) {
|
|
301
|
-
return this._socket.pipe(dest, options);
|
|
302
|
-
};
|
|
303
|
-
Terminal2.prototype.pause = function() {
|
|
304
|
-
return this._socket.pause();
|
|
305
|
-
};
|
|
306
|
-
Terminal2.prototype.resume = function() {
|
|
307
|
-
return this._socket.resume();
|
|
308
|
-
};
|
|
309
|
-
Terminal2.prototype.setEncoding = function(encoding) {
|
|
310
|
-
if (this._socket._decoder) {
|
|
311
|
-
delete this._socket._decoder;
|
|
312
|
-
}
|
|
313
|
-
if (encoding) {
|
|
314
|
-
this._socket.setEncoding(encoding);
|
|
315
|
-
}
|
|
316
|
-
};
|
|
317
|
-
Terminal2.prototype.addListener = function(eventName, listener) {
|
|
318
|
-
this.on(eventName, listener);
|
|
319
|
-
};
|
|
320
|
-
Terminal2.prototype.on = function(eventName, listener) {
|
|
321
|
-
if (eventName === "close") {
|
|
322
|
-
this._internalee.on("close", listener);
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
this._socket.on(eventName, listener);
|
|
326
|
-
};
|
|
327
|
-
Terminal2.prototype.emit = function(eventName) {
|
|
328
|
-
var args = [];
|
|
329
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
330
|
-
args[_i - 1] = arguments[_i];
|
|
331
|
-
}
|
|
332
|
-
if (eventName === "close") {
|
|
333
|
-
return this._internalee.emit.apply(this._internalee, arguments);
|
|
334
|
-
}
|
|
335
|
-
return this._socket.emit.apply(this._socket, arguments);
|
|
336
|
-
};
|
|
337
|
-
Terminal2.prototype.listeners = function(eventName) {
|
|
338
|
-
return this._socket.listeners(eventName);
|
|
339
|
-
};
|
|
340
|
-
Terminal2.prototype.removeListener = function(eventName, listener) {
|
|
341
|
-
this._socket.removeListener(eventName, listener);
|
|
342
|
-
};
|
|
343
|
-
Terminal2.prototype.removeAllListeners = function(eventName) {
|
|
344
|
-
this._socket.removeAllListeners(eventName);
|
|
345
|
-
};
|
|
346
|
-
Terminal2.prototype.once = function(eventName, listener) {
|
|
347
|
-
this._socket.once(eventName, listener);
|
|
348
|
-
};
|
|
349
|
-
Terminal2.prototype._close = function() {
|
|
350
|
-
this._socket.readable = false;
|
|
351
|
-
this.write = function() {
|
|
352
|
-
};
|
|
353
|
-
this.end = function() {
|
|
354
|
-
};
|
|
355
|
-
this._writable = false;
|
|
356
|
-
this._readable = false;
|
|
357
|
-
};
|
|
358
|
-
Terminal2.prototype._parseEnv = function(env) {
|
|
359
|
-
var keys = Object.keys(env || {});
|
|
360
|
-
var pairs = [];
|
|
361
|
-
for (var i = 0; i < keys.length; i++) {
|
|
362
|
-
if (keys[i] === void 0) {
|
|
363
|
-
continue;
|
|
364
|
-
}
|
|
365
|
-
pairs.push(keys[i] + "=" + env[keys[i]]);
|
|
366
|
-
}
|
|
367
|
-
return pairs;
|
|
368
|
-
};
|
|
369
|
-
return Terminal2;
|
|
370
|
-
})()
|
|
371
|
-
);
|
|
372
|
-
exports2.Terminal = Terminal;
|
|
373
|
-
}
|
|
374
|
-
});
|
|
637
|
+
}
|
|
375
638
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
"use strict";
|
|
380
|
-
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
381
|
-
exports2.getWorkerPipeName = void 0;
|
|
382
|
-
function getWorkerPipeName(conoutPipeName) {
|
|
383
|
-
return conoutPipeName + "-worker";
|
|
384
|
-
}
|
|
385
|
-
exports2.getWorkerPipeName = getWorkerPipeName;
|
|
386
|
-
}
|
|
387
|
-
});
|
|
639
|
+
if (currentStyle) result += '</span>';
|
|
640
|
+
return result;
|
|
641
|
+
}
|
|
388
642
|
|
|
389
|
-
//
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
643
|
+
// Escape HTML
|
|
644
|
+
function escapeHtml(text) {
|
|
645
|
+
return text
|
|
646
|
+
.replace(/&/g, '&')
|
|
647
|
+
.replace(/</g, '<')
|
|
648
|
+
.replace(/>/g, '>')
|
|
649
|
+
.replace(/"/g, '"')
|
|
650
|
+
.replace(/\\n/g, '<br>')
|
|
651
|
+
.replace(/ /g, ' ');
|
|
398
652
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
function rejected(value) {
|
|
408
|
-
try {
|
|
409
|
-
step(generator["throw"](value));
|
|
410
|
-
} catch (e) {
|
|
411
|
-
reject(e);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
function step(result) {
|
|
415
|
-
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
416
|
-
}
|
|
417
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
418
|
-
});
|
|
419
|
-
};
|
|
420
|
-
var __generator = exports2 && exports2.__generator || function(thisArg, body) {
|
|
421
|
-
var _ = { label: 0, sent: function() {
|
|
422
|
-
if (t[0] & 1) throw t[1];
|
|
423
|
-
return t[1];
|
|
424
|
-
}, trys: [], ops: [] }, f, y, t, g;
|
|
425
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
|
|
426
|
-
return this;
|
|
427
|
-
}), g;
|
|
428
|
-
function verb(n) {
|
|
429
|
-
return function(v) {
|
|
430
|
-
return step([n, v]);
|
|
431
|
-
};
|
|
653
|
+
|
|
654
|
+
// Set connection status
|
|
655
|
+
function setStatus(state, text) {
|
|
656
|
+
statusDot.className = state === 'connected' ? 'connected' :
|
|
657
|
+
state === 'connecting' ? 'connecting' : '';
|
|
658
|
+
statusText.textContent = text;
|
|
432
659
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
switch (op[0]) {
|
|
439
|
-
case 0:
|
|
440
|
-
case 1:
|
|
441
|
-
t = op;
|
|
442
|
-
break;
|
|
443
|
-
case 4:
|
|
444
|
-
_.label++;
|
|
445
|
-
return { value: op[1], done: false };
|
|
446
|
-
case 5:
|
|
447
|
-
_.label++;
|
|
448
|
-
y = op[1];
|
|
449
|
-
op = [0];
|
|
450
|
-
continue;
|
|
451
|
-
case 7:
|
|
452
|
-
op = _.ops.pop();
|
|
453
|
-
_.trys.pop();
|
|
454
|
-
continue;
|
|
455
|
-
default:
|
|
456
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
457
|
-
_ = 0;
|
|
458
|
-
continue;
|
|
459
|
-
}
|
|
460
|
-
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
461
|
-
_.label = op[1];
|
|
462
|
-
break;
|
|
463
|
-
}
|
|
464
|
-
if (op[0] === 6 && _.label < t[1]) {
|
|
465
|
-
_.label = t[1];
|
|
466
|
-
t = op;
|
|
467
|
-
break;
|
|
468
|
-
}
|
|
469
|
-
if (t && _.label < t[2]) {
|
|
470
|
-
_.label = t[2];
|
|
471
|
-
_.ops.push(op);
|
|
472
|
-
break;
|
|
473
|
-
}
|
|
474
|
-
if (t[2]) _.ops.pop();
|
|
475
|
-
_.trys.pop();
|
|
476
|
-
continue;
|
|
477
|
-
}
|
|
478
|
-
op = body.call(thisArg, _);
|
|
479
|
-
} catch (e) {
|
|
480
|
-
op = [6, e];
|
|
481
|
-
y = 0;
|
|
482
|
-
} finally {
|
|
483
|
-
f = t = 0;
|
|
660
|
+
|
|
661
|
+
// Send data to terminal
|
|
662
|
+
function send(data) {
|
|
663
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
664
|
+
ws.send(JSON.stringify({ type: 'terminal:input', data: data }));
|
|
484
665
|
}
|
|
485
|
-
if (op[0] & 5) throw op[1];
|
|
486
|
-
return { value: op[0] ? op[1] : void 0, done: true };
|
|
487
666
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
var workerData = {
|
|
506
|
-
conoutPipeName: _conoutPipeName
|
|
507
|
-
};
|
|
508
|
-
var scriptPath = __dirname.replace("node_modules.asar", "node_modules.asar.unpacked");
|
|
509
|
-
this._worker = new worker_threads_1.Worker(path_1.join(scriptPath, "worker/conoutSocketWorker.js"), { workerData });
|
|
510
|
-
this._worker.on("message", function(message) {
|
|
511
|
-
switch (message) {
|
|
512
|
-
case 1:
|
|
513
|
-
_this._onReady.fire();
|
|
514
|
-
return;
|
|
515
|
-
default:
|
|
516
|
-
console.warn("Unexpected ConoutWorkerMessage", message);
|
|
517
|
-
}
|
|
518
|
-
});
|
|
667
|
+
|
|
668
|
+
// Show notification
|
|
669
|
+
function showNotification(n) {
|
|
670
|
+
if (!n) return;
|
|
671
|
+
const el = document.createElement('div');
|
|
672
|
+
el.className = 'notification ' + (n.type || 'info');
|
|
673
|
+
el.innerHTML = '<h4>' + escapeHtml(n.title || 'Notification') + '</h4>' +
|
|
674
|
+
'<p>' + escapeHtml(n.body || '') + '</p>';
|
|
675
|
+
notifications.appendChild(el);
|
|
676
|
+
setTimeout(function() { el.remove(); }, 5000);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Event: Send button
|
|
680
|
+
sendBtn.onclick = function() {
|
|
681
|
+
if (input.value) {
|
|
682
|
+
send(input.value + '\\r');
|
|
683
|
+
input.value = '';
|
|
519
684
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
return this._onReady.event;
|
|
523
|
-
},
|
|
524
|
-
enumerable: false,
|
|
525
|
-
configurable: true
|
|
526
|
-
});
|
|
527
|
-
ConoutConnection2.prototype.dispose = function() {
|
|
528
|
-
if (!this._useConptyDll && this._isDisposed) {
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
this._isDisposed = true;
|
|
532
|
-
this._drainDataAndClose();
|
|
533
|
-
};
|
|
534
|
-
ConoutConnection2.prototype.connectSocket = function(socket) {
|
|
535
|
-
socket.connect(conout_1.getWorkerPipeName(this._conoutPipeName));
|
|
536
|
-
};
|
|
537
|
-
ConoutConnection2.prototype._drainDataAndClose = function() {
|
|
538
|
-
var _this = this;
|
|
539
|
-
if (this._drainTimeout) {
|
|
540
|
-
clearTimeout(this._drainTimeout);
|
|
541
|
-
}
|
|
542
|
-
this._drainTimeout = setTimeout(function() {
|
|
543
|
-
return _this._destroySocket();
|
|
544
|
-
}, FLUSH_DATA_INTERVAL);
|
|
545
|
-
};
|
|
546
|
-
ConoutConnection2.prototype._destroySocket = function() {
|
|
547
|
-
return __awaiter(this, void 0, void 0, function() {
|
|
548
|
-
return __generator(this, function(_a) {
|
|
549
|
-
switch (_a.label) {
|
|
550
|
-
case 0:
|
|
551
|
-
return [4, this._worker.terminate()];
|
|
552
|
-
case 1:
|
|
553
|
-
_a.sent();
|
|
554
|
-
return [
|
|
555
|
-
2
|
|
556
|
-
/*return*/
|
|
557
|
-
];
|
|
558
|
-
}
|
|
559
|
-
});
|
|
560
|
-
});
|
|
561
|
-
};
|
|
562
|
-
return ConoutConnection2;
|
|
563
|
-
})()
|
|
564
|
-
);
|
|
565
|
-
exports2.ConoutConnection = ConoutConnection;
|
|
566
|
-
}
|
|
567
|
-
});
|
|
685
|
+
input.focus();
|
|
686
|
+
};
|
|
568
687
|
|
|
569
|
-
//
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
exports2.argsToCommandLine = exports2.WindowsPtyAgent = void 0;
|
|
575
|
-
var fs = require("fs");
|
|
576
|
-
var os2 = require("os");
|
|
577
|
-
var path = require("path");
|
|
578
|
-
var child_process_1 = require("child_process");
|
|
579
|
-
var net_1 = require("net");
|
|
580
|
-
var windowsConoutConnection_1 = require_windowsConoutConnection();
|
|
581
|
-
var utils_1 = require_utils();
|
|
582
|
-
var conptyNative;
|
|
583
|
-
var winptyNative;
|
|
584
|
-
var FLUSH_DATA_INTERVAL = 1e3;
|
|
585
|
-
var WindowsPtyAgent = (
|
|
586
|
-
/** @class */
|
|
587
|
-
(function() {
|
|
588
|
-
function WindowsPtyAgent2(file, args, env, cwd, cols, rows, debug, _useConpty, _useConptyDll, conptyInheritCursor) {
|
|
589
|
-
var _this = this;
|
|
590
|
-
if (_useConptyDll === void 0) {
|
|
591
|
-
_useConptyDll = false;
|
|
592
|
-
}
|
|
593
|
-
if (conptyInheritCursor === void 0) {
|
|
594
|
-
conptyInheritCursor = false;
|
|
595
|
-
}
|
|
596
|
-
this._useConpty = _useConpty;
|
|
597
|
-
this._useConptyDll = _useConptyDll;
|
|
598
|
-
this._pid = 0;
|
|
599
|
-
this._innerPid = 0;
|
|
600
|
-
if (this._useConpty === void 0 || this._useConpty === true) {
|
|
601
|
-
this._useConpty = this._getWindowsBuildNumber() >= 18309;
|
|
602
|
-
}
|
|
603
|
-
if (this._useConpty) {
|
|
604
|
-
if (!conptyNative) {
|
|
605
|
-
conptyNative = utils_1.loadNativeModule("conpty").module;
|
|
606
|
-
}
|
|
607
|
-
} else {
|
|
608
|
-
if (!winptyNative) {
|
|
609
|
-
winptyNative = utils_1.loadNativeModule("pty").module;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
this._ptyNative = this._useConpty ? conptyNative : winptyNative;
|
|
613
|
-
cwd = path.resolve(cwd);
|
|
614
|
-
var commandLine = argsToCommandLine(file, args);
|
|
615
|
-
var term;
|
|
616
|
-
if (this._useConpty) {
|
|
617
|
-
term = this._ptyNative.startProcess(file, cols, rows, debug, this._generatePipeName(), conptyInheritCursor, this._useConptyDll);
|
|
618
|
-
} else {
|
|
619
|
-
term = this._ptyNative.startProcess(file, commandLine, env, cwd, cols, rows, debug);
|
|
620
|
-
this._pid = term.pid;
|
|
621
|
-
this._innerPid = term.innerPid;
|
|
622
|
-
}
|
|
623
|
-
this._fd = term.fd;
|
|
624
|
-
this._pty = term.pty;
|
|
625
|
-
this._outSocket = new net_1.Socket();
|
|
626
|
-
this._outSocket.setEncoding("utf8");
|
|
627
|
-
this._conoutSocketWorker = new windowsConoutConnection_1.ConoutConnection(term.conout, this._useConptyDll);
|
|
628
|
-
this._conoutSocketWorker.onReady(function() {
|
|
629
|
-
_this._conoutSocketWorker.connectSocket(_this._outSocket);
|
|
630
|
-
});
|
|
631
|
-
this._outSocket.on("connect", function() {
|
|
632
|
-
_this._outSocket.emit("ready_datapipe");
|
|
633
|
-
});
|
|
634
|
-
var inSocketFD = fs.openSync(term.conin, "w");
|
|
635
|
-
this._inSocket = new net_1.Socket({
|
|
636
|
-
fd: inSocketFD,
|
|
637
|
-
readable: false,
|
|
638
|
-
writable: true
|
|
639
|
-
});
|
|
640
|
-
this._inSocket.setEncoding("utf8");
|
|
641
|
-
if (this._useConpty) {
|
|
642
|
-
var connect = this._ptyNative.connect(this._pty, commandLine, cwd, env, this._useConptyDll, function(c) {
|
|
643
|
-
return _this._$onProcessExit(c);
|
|
644
|
-
});
|
|
645
|
-
this._innerPid = connect.pid;
|
|
646
|
-
}
|
|
688
|
+
// Event: Enter key in input
|
|
689
|
+
input.onkeydown = function(e) {
|
|
690
|
+
if (e.key === 'Enter') {
|
|
691
|
+
e.preventDefault();
|
|
692
|
+
sendBtn.click();
|
|
647
693
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
get: function() {
|
|
664
|
-
return this._fd;
|
|
665
|
-
},
|
|
666
|
-
enumerable: false,
|
|
667
|
-
configurable: true
|
|
668
|
-
});
|
|
669
|
-
Object.defineProperty(WindowsPtyAgent2.prototype, "innerPid", {
|
|
670
|
-
get: function() {
|
|
671
|
-
return this._innerPid;
|
|
672
|
-
},
|
|
673
|
-
enumerable: false,
|
|
674
|
-
configurable: true
|
|
675
|
-
});
|
|
676
|
-
Object.defineProperty(WindowsPtyAgent2.prototype, "pty", {
|
|
677
|
-
get: function() {
|
|
678
|
-
return this._pty;
|
|
679
|
-
},
|
|
680
|
-
enumerable: false,
|
|
681
|
-
configurable: true
|
|
682
|
-
});
|
|
683
|
-
WindowsPtyAgent2.prototype.resize = function(cols, rows) {
|
|
684
|
-
if (this._useConpty) {
|
|
685
|
-
if (this._exitCode !== void 0) {
|
|
686
|
-
throw new Error("Cannot resize a pty that has already exited");
|
|
687
|
-
}
|
|
688
|
-
this._ptyNative.resize(this._pty, cols, rows, this._useConptyDll);
|
|
689
|
-
return;
|
|
690
|
-
}
|
|
691
|
-
this._ptyNative.resize(this._pid, cols, rows);
|
|
692
|
-
};
|
|
693
|
-
WindowsPtyAgent2.prototype.clear = function() {
|
|
694
|
-
if (this._useConpty) {
|
|
695
|
-
this._ptyNative.clear(this._pty, this._useConptyDll);
|
|
696
|
-
}
|
|
697
|
-
};
|
|
698
|
-
WindowsPtyAgent2.prototype.kill = function() {
|
|
699
|
-
var _this = this;
|
|
700
|
-
if (this._useConpty) {
|
|
701
|
-
if (!this._useConptyDll) {
|
|
702
|
-
this._inSocket.readable = false;
|
|
703
|
-
this._outSocket.readable = false;
|
|
704
|
-
this._getConsoleProcessList().then(function(consoleProcessList) {
|
|
705
|
-
consoleProcessList.forEach(function(pid) {
|
|
706
|
-
try {
|
|
707
|
-
process.kill(pid);
|
|
708
|
-
} catch (e) {
|
|
709
|
-
}
|
|
710
|
-
});
|
|
711
|
-
});
|
|
712
|
-
this._ptyNative.kill(this._pty, this._useConptyDll);
|
|
713
|
-
this._conoutSocketWorker.dispose();
|
|
714
|
-
} else {
|
|
715
|
-
this._inSocket.destroy();
|
|
716
|
-
this._ptyNative.kill(this._pty, this._useConptyDll);
|
|
717
|
-
this._outSocket.on("data", function() {
|
|
718
|
-
_this._conoutSocketWorker.dispose();
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
} else {
|
|
722
|
-
var processList = this._ptyNative.getProcessList(this._pid);
|
|
723
|
-
this._ptyNative.kill(this._pid, this._innerPid);
|
|
724
|
-
processList.forEach(function(pid) {
|
|
725
|
-
try {
|
|
726
|
-
process.kill(pid);
|
|
727
|
-
} catch (e) {
|
|
728
|
-
}
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
};
|
|
732
|
-
WindowsPtyAgent2.prototype._getConsoleProcessList = function() {
|
|
733
|
-
var _this = this;
|
|
734
|
-
return new Promise(function(resolve) {
|
|
735
|
-
var agent = child_process_1.fork(path.join(__dirname, "conpty_console_list_agent"), [_this._innerPid.toString()]);
|
|
736
|
-
agent.on("message", function(message) {
|
|
737
|
-
clearTimeout(timeout);
|
|
738
|
-
resolve(message.consoleProcessList);
|
|
739
|
-
});
|
|
740
|
-
var timeout = setTimeout(function() {
|
|
741
|
-
agent.kill();
|
|
742
|
-
resolve([_this._innerPid]);
|
|
743
|
-
}, 5e3);
|
|
744
|
-
});
|
|
745
|
-
};
|
|
746
|
-
Object.defineProperty(WindowsPtyAgent2.prototype, "exitCode", {
|
|
747
|
-
get: function() {
|
|
748
|
-
if (this._useConpty) {
|
|
749
|
-
return this._exitCode;
|
|
750
|
-
}
|
|
751
|
-
var winptyExitCode = this._ptyNative.getExitCode(this._innerPid);
|
|
752
|
-
return winptyExitCode === -1 ? void 0 : winptyExitCode;
|
|
753
|
-
},
|
|
754
|
-
enumerable: false,
|
|
755
|
-
configurable: true
|
|
756
|
-
});
|
|
757
|
-
WindowsPtyAgent2.prototype._getWindowsBuildNumber = function() {
|
|
758
|
-
var osVersion = /(\d+)\.(\d+)\.(\d+)/g.exec(os2.release());
|
|
759
|
-
var buildNumber = 0;
|
|
760
|
-
if (osVersion && osVersion.length === 4) {
|
|
761
|
-
buildNumber = parseInt(osVersion[3]);
|
|
762
|
-
}
|
|
763
|
-
return buildNumber;
|
|
764
|
-
};
|
|
765
|
-
WindowsPtyAgent2.prototype._generatePipeName = function() {
|
|
766
|
-
return "conpty-" + Math.random() * 1e7;
|
|
767
|
-
};
|
|
768
|
-
WindowsPtyAgent2.prototype._$onProcessExit = function(exitCode) {
|
|
769
|
-
var _this = this;
|
|
770
|
-
this._exitCode = exitCode;
|
|
771
|
-
if (!this._useConptyDll) {
|
|
772
|
-
this._flushDataAndCleanUp();
|
|
773
|
-
this._outSocket.on("data", function() {
|
|
774
|
-
return _this._flushDataAndCleanUp();
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
};
|
|
778
|
-
WindowsPtyAgent2.prototype._flushDataAndCleanUp = function() {
|
|
779
|
-
var _this = this;
|
|
780
|
-
if (this._useConptyDll) {
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
if (this._closeTimeout) {
|
|
784
|
-
clearTimeout(this._closeTimeout);
|
|
785
|
-
}
|
|
786
|
-
this._closeTimeout = setTimeout(function() {
|
|
787
|
-
return _this._cleanUpProcess();
|
|
788
|
-
}, FLUSH_DATA_INTERVAL);
|
|
789
|
-
};
|
|
790
|
-
WindowsPtyAgent2.prototype._cleanUpProcess = function() {
|
|
791
|
-
if (this._useConptyDll) {
|
|
792
|
-
return;
|
|
793
|
-
}
|
|
794
|
-
this._inSocket.readable = false;
|
|
795
|
-
this._outSocket.readable = false;
|
|
796
|
-
this._outSocket.destroy();
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
// Event: Quick keys
|
|
697
|
+
document.querySelectorAll('.qkey').forEach(function(btn) {
|
|
698
|
+
btn.onclick = function() {
|
|
699
|
+
const key = btn.dataset.key;
|
|
700
|
+
const decoded = key
|
|
701
|
+
.replace(/\\\\x([0-9a-f]{2})/gi, function(_, hex) {
|
|
702
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
703
|
+
})
|
|
704
|
+
.replace(/\\\\t/g, '\\t')
|
|
705
|
+
.replace(/\\\\r/g, '\\r')
|
|
706
|
+
.replace(/\\\\n/g, '\\n');
|
|
707
|
+
send(decoded);
|
|
708
|
+
input.focus();
|
|
797
709
|
};
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
if (args.length === 0) {
|
|
805
|
-
return file;
|
|
806
|
-
}
|
|
807
|
-
return argsToCommandLine(file, []) + " " + args;
|
|
808
|
-
}
|
|
809
|
-
var argv = [file];
|
|
810
|
-
Array.prototype.push.apply(argv, args);
|
|
811
|
-
var result = "";
|
|
812
|
-
for (var argIndex = 0; argIndex < argv.length; argIndex++) {
|
|
813
|
-
if (argIndex > 0) {
|
|
814
|
-
result += " ";
|
|
815
|
-
}
|
|
816
|
-
var arg = argv[argIndex];
|
|
817
|
-
var hasLopsidedEnclosingQuote = xOr(arg[0] !== '"', arg[arg.length - 1] !== '"');
|
|
818
|
-
var hasNoEnclosingQuotes = arg[0] !== '"' && arg[arg.length - 1] !== '"';
|
|
819
|
-
var quote = arg === "" || (arg.indexOf(" ") !== -1 || arg.indexOf(" ") !== -1) && (arg.length > 1 && (hasLopsidedEnclosingQuote || hasNoEnclosingQuotes));
|
|
820
|
-
if (quote) {
|
|
821
|
-
result += '"';
|
|
822
|
-
}
|
|
823
|
-
var bsCount = 0;
|
|
824
|
-
for (var i = 0; i < arg.length; i++) {
|
|
825
|
-
var p = arg[i];
|
|
826
|
-
if (p === "\\") {
|
|
827
|
-
bsCount++;
|
|
828
|
-
} else if (p === '"') {
|
|
829
|
-
result += repeatText("\\", bsCount * 2 + 1);
|
|
830
|
-
result += '"';
|
|
831
|
-
bsCount = 0;
|
|
832
|
-
} else {
|
|
833
|
-
result += repeatText("\\", bsCount);
|
|
834
|
-
bsCount = 0;
|
|
835
|
-
result += p;
|
|
836
|
-
}
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
// Heartbeat
|
|
713
|
+
setInterval(function() {
|
|
714
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
715
|
+
ws.send(JSON.stringify({ type: 'ping' }));
|
|
837
716
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
717
|
+
}, 25000);
|
|
718
|
+
|
|
719
|
+
// Handle resize
|
|
720
|
+
function sendResize() {
|
|
721
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
722
|
+
const cols = Math.floor(terminal.clientWidth / 8);
|
|
723
|
+
const rows = Math.floor(terminal.clientHeight / 18);
|
|
724
|
+
ws.send(JSON.stringify({ type: 'terminal:resize', cols: cols, rows: rows }));
|
|
843
725
|
}
|
|
844
726
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
727
|
+
|
|
728
|
+
window.addEventListener('resize', sendResize);
|
|
729
|
+
setTimeout(sendResize, 1000);
|
|
730
|
+
|
|
731
|
+
// Start connection
|
|
732
|
+
if (token) {
|
|
733
|
+
connect();
|
|
734
|
+
} else {
|
|
735
|
+
authStatus.textContent = 'Invalid session URL';
|
|
736
|
+
authStatus.classList.add('error');
|
|
855
737
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
738
|
+
})();
|
|
739
|
+
</script>
|
|
740
|
+
</body>
|
|
741
|
+
</html>`;
|
|
742
|
+
}
|
|
743
|
+
var init_web_client = __esm({
|
|
744
|
+
"src/web-client.ts"() {
|
|
745
|
+
"use strict";
|
|
861
746
|
}
|
|
862
747
|
});
|
|
863
748
|
|
|
864
|
-
//
|
|
865
|
-
var
|
|
866
|
-
|
|
749
|
+
// src/server.ts
|
|
750
|
+
var server_exports = {};
|
|
751
|
+
__export(server_exports, {
|
|
752
|
+
RemoteServer: () => RemoteServer
|
|
753
|
+
});
|
|
754
|
+
var import_node_events, import_node_http, import_ws, import_node_crypto, import_node_os, RemoteServer;
|
|
755
|
+
var init_server = __esm({
|
|
756
|
+
"src/server.ts"() {
|
|
867
757
|
"use strict";
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
758
|
+
import_node_events = require("events");
|
|
759
|
+
import_node_http = require("http");
|
|
760
|
+
import_ws = require("ws");
|
|
761
|
+
import_node_crypto = __toESM(require("crypto"), 1);
|
|
762
|
+
import_node_os = __toESM(require("os"), 1);
|
|
763
|
+
init_types();
|
|
764
|
+
RemoteServer = class extends import_node_events.EventEmitter {
|
|
765
|
+
config;
|
|
766
|
+
httpServer = null;
|
|
767
|
+
wss = null;
|
|
768
|
+
clients = /* @__PURE__ */ new Map();
|
|
769
|
+
session = null;
|
|
770
|
+
heartbeatTimer = null;
|
|
771
|
+
sessionTimeoutTimer = null;
|
|
772
|
+
isRunning = false;
|
|
773
|
+
sessionSecret;
|
|
774
|
+
// stdin/stdout proxy state
|
|
775
|
+
originalStdoutWrite = null;
|
|
776
|
+
originalStdinOn = null;
|
|
777
|
+
constructor(config = {}) {
|
|
778
|
+
super();
|
|
779
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
780
|
+
this.sessionSecret = config.sessionSecret || this.generateSecret();
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Generate a random secret
|
|
784
|
+
*/
|
|
785
|
+
generateSecret() {
|
|
786
|
+
return import_node_crypto.default.randomBytes(16).toString("hex");
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Start the remote server - creates WebSocket server that proxies stdin/stdout
|
|
790
|
+
*/
|
|
791
|
+
async start(options = {}) {
|
|
792
|
+
if (this.isRunning) {
|
|
793
|
+
throw new Error("Server already running");
|
|
794
|
+
}
|
|
795
|
+
const sessionId = this.generateSessionId();
|
|
796
|
+
this.httpServer = (0, import_node_http.createServer)((req, res) => this.handleHttpRequest(req, res));
|
|
797
|
+
this.wss = new import_ws.WebSocketServer({ server: this.httpServer });
|
|
798
|
+
this.setupWebSocketHandlers();
|
|
799
|
+
const port = await new Promise((resolve, reject) => {
|
|
800
|
+
this.httpServer.listen(this.config.port, this.config.host, () => {
|
|
801
|
+
const addr = this.httpServer.address();
|
|
802
|
+
resolve(typeof addr === "object" ? addr?.port || 0 : 0);
|
|
803
|
+
});
|
|
804
|
+
this.httpServer.on("error", reject);
|
|
805
|
+
});
|
|
806
|
+
const localIp = this.getLocalIP();
|
|
807
|
+
const localUrl = `http://${localIp}:${port}`;
|
|
808
|
+
this.session = {
|
|
809
|
+
id: sessionId,
|
|
810
|
+
name: options.name || `nikcli-${sessionId}`,
|
|
811
|
+
qrCode: "",
|
|
812
|
+
qrUrl: `${localUrl}?s=${sessionId}&t=${this.sessionSecret}`,
|
|
813
|
+
localUrl,
|
|
814
|
+
status: "waiting",
|
|
815
|
+
connectedDevices: [],
|
|
816
|
+
startedAt: /* @__PURE__ */ new Date(),
|
|
817
|
+
lastActivity: /* @__PURE__ */ new Date(),
|
|
818
|
+
port
|
|
874
819
|
};
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
return function(d, b) {
|
|
878
|
-
extendStatics(d, b);
|
|
879
|
-
function __() {
|
|
880
|
-
this.constructor = d;
|
|
820
|
+
if (options.processForStreaming) {
|
|
821
|
+
this.setupStdioProxy(options.processForStreaming.stdout, options.processForStreaming.stdin);
|
|
881
822
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
(
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
var cwd = opt.cwd || process.cwd();
|
|
910
|
-
var name = opt.name || env.TERM || DEFAULT_NAME;
|
|
911
|
-
var parsedEnv = _this._parseEnv(env);
|
|
912
|
-
_this._isReady = false;
|
|
913
|
-
_this._deferreds = [];
|
|
914
|
-
_this._agent = new windowsPtyAgent_1.WindowsPtyAgent(file, args, parsedEnv, cwd, _this._cols, _this._rows, false, opt.useConpty, opt.useConptyDll, opt.conptyInheritCursor);
|
|
915
|
-
_this._socket = _this._agent.outSocket;
|
|
916
|
-
_this._pid = _this._agent.innerPid;
|
|
917
|
-
_this._fd = _this._agent.fd;
|
|
918
|
-
_this._pty = _this._agent.pty;
|
|
919
|
-
_this._socket.on("ready_datapipe", function() {
|
|
920
|
-
_this._socket.once("data", function() {
|
|
921
|
-
if (!_this._isReady) {
|
|
922
|
-
_this._isReady = true;
|
|
923
|
-
_this._deferreds.forEach(function(fn) {
|
|
924
|
-
fn.run();
|
|
925
|
-
});
|
|
926
|
-
_this._deferreds = [];
|
|
927
|
-
}
|
|
928
|
-
});
|
|
929
|
-
_this._socket.on("error", function(err) {
|
|
930
|
-
_this._close();
|
|
931
|
-
if (err.code) {
|
|
932
|
-
if (~err.code.indexOf("errno 5") || ~err.code.indexOf("EIO"))
|
|
933
|
-
return;
|
|
934
|
-
}
|
|
935
|
-
if (_this.listeners("error").length < 2) {
|
|
936
|
-
throw err;
|
|
823
|
+
this.startHeartbeat();
|
|
824
|
+
if (this.config.sessionTimeout > 0) {
|
|
825
|
+
this.startSessionTimeout();
|
|
826
|
+
}
|
|
827
|
+
this.session.status = "waiting";
|
|
828
|
+
this.isRunning = true;
|
|
829
|
+
this.emit("started", this.session);
|
|
830
|
+
return this.session;
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Setup stdin/stdout proxy to forward to WebSocket clients
|
|
834
|
+
*/
|
|
835
|
+
setupStdioProxy(stdout, stdin) {
|
|
836
|
+
const originalWrite = stdout.write.bind(stdout);
|
|
837
|
+
stdout.write = ((data, encoding, cb) => {
|
|
838
|
+
const result = originalWrite(data, encoding, cb);
|
|
839
|
+
const text = data instanceof Buffer ? data.toString() : data;
|
|
840
|
+
this.broadcastToAll({ type: MessageTypes.TERMINAL_OUTPUT, payload: { data: text } });
|
|
841
|
+
return result;
|
|
842
|
+
});
|
|
843
|
+
this.wss?.on("connection", (ws) => {
|
|
844
|
+
ws.on("message", (rawData) => {
|
|
845
|
+
try {
|
|
846
|
+
const msg = JSON.parse(rawData.toString());
|
|
847
|
+
if (msg.type === MessageTypes.TERMINAL_INPUT && msg.data) {
|
|
848
|
+
const inputData = Buffer.from(msg.data);
|
|
849
|
+
stdin.emit("data", inputData);
|
|
937
850
|
}
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
_this.emit("exit", _this._agent.exitCode);
|
|
941
|
-
_this._close();
|
|
942
|
-
});
|
|
851
|
+
} catch {
|
|
852
|
+
}
|
|
943
853
|
});
|
|
944
|
-
_this._file = file;
|
|
945
|
-
_this._name = name;
|
|
946
|
-
_this._readable = true;
|
|
947
|
-
_this._writable = true;
|
|
948
|
-
_this._forwardEvents();
|
|
949
|
-
return _this;
|
|
950
|
-
}
|
|
951
|
-
WindowsTerminal2.prototype._write = function(data) {
|
|
952
|
-
this._defer(this._doWrite, data);
|
|
953
|
-
};
|
|
954
|
-
WindowsTerminal2.prototype._doWrite = function(data) {
|
|
955
|
-
this._agent.inSocket.write(data);
|
|
956
|
-
};
|
|
957
|
-
WindowsTerminal2.open = function(options) {
|
|
958
|
-
throw new Error("open() not supported on windows, use Fork() instead.");
|
|
959
|
-
};
|
|
960
|
-
WindowsTerminal2.prototype.resize = function(cols, rows) {
|
|
961
|
-
var _this = this;
|
|
962
|
-
if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {
|
|
963
|
-
throw new Error("resizing must be done using positive cols and rows");
|
|
964
|
-
}
|
|
965
|
-
this._deferNoArgs(function() {
|
|
966
|
-
_this._agent.resize(cols, rows);
|
|
967
|
-
_this._cols = cols;
|
|
968
|
-
_this._rows = rows;
|
|
969
|
-
});
|
|
970
|
-
};
|
|
971
|
-
WindowsTerminal2.prototype.clear = function() {
|
|
972
|
-
var _this = this;
|
|
973
|
-
this._deferNoArgs(function() {
|
|
974
|
-
_this._agent.clear();
|
|
975
|
-
});
|
|
976
|
-
};
|
|
977
|
-
WindowsTerminal2.prototype.destroy = function() {
|
|
978
|
-
var _this = this;
|
|
979
|
-
this._deferNoArgs(function() {
|
|
980
|
-
_this.kill();
|
|
981
|
-
});
|
|
982
|
-
};
|
|
983
|
-
WindowsTerminal2.prototype.kill = function(signal) {
|
|
984
|
-
var _this = this;
|
|
985
|
-
this._deferNoArgs(function() {
|
|
986
|
-
if (signal) {
|
|
987
|
-
throw new Error("Signals not supported on windows.");
|
|
988
|
-
}
|
|
989
|
-
_this._close();
|
|
990
|
-
_this._agent.kill();
|
|
991
|
-
});
|
|
992
|
-
};
|
|
993
|
-
WindowsTerminal2.prototype._deferNoArgs = function(deferredFn) {
|
|
994
|
-
var _this = this;
|
|
995
|
-
if (this._isReady) {
|
|
996
|
-
deferredFn.call(this);
|
|
997
|
-
return;
|
|
998
|
-
}
|
|
999
|
-
this._deferreds.push({
|
|
1000
|
-
run: function() {
|
|
1001
|
-
return deferredFn.call(_this);
|
|
1002
|
-
}
|
|
1003
|
-
});
|
|
1004
|
-
};
|
|
1005
|
-
WindowsTerminal2.prototype._defer = function(deferredFn, arg) {
|
|
1006
|
-
var _this = this;
|
|
1007
|
-
if (this._isReady) {
|
|
1008
|
-
deferredFn.call(this, arg);
|
|
1009
|
-
return;
|
|
1010
|
-
}
|
|
1011
|
-
this._deferreds.push({
|
|
1012
|
-
run: function() {
|
|
1013
|
-
return deferredFn.call(_this, arg);
|
|
1014
|
-
}
|
|
1015
|
-
});
|
|
1016
|
-
};
|
|
1017
|
-
Object.defineProperty(WindowsTerminal2.prototype, "process", {
|
|
1018
|
-
get: function() {
|
|
1019
|
-
return this._name;
|
|
1020
|
-
},
|
|
1021
|
-
enumerable: false,
|
|
1022
|
-
configurable: true
|
|
1023
|
-
});
|
|
1024
|
-
Object.defineProperty(WindowsTerminal2.prototype, "master", {
|
|
1025
|
-
get: function() {
|
|
1026
|
-
throw new Error("master is not supported on Windows");
|
|
1027
|
-
},
|
|
1028
|
-
enumerable: false,
|
|
1029
|
-
configurable: true
|
|
1030
|
-
});
|
|
1031
|
-
Object.defineProperty(WindowsTerminal2.prototype, "slave", {
|
|
1032
|
-
get: function() {
|
|
1033
|
-
throw new Error("slave is not supported on Windows");
|
|
1034
|
-
},
|
|
1035
|
-
enumerable: false,
|
|
1036
|
-
configurable: true
|
|
1037
854
|
});
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
var require_unixTerminal = __commonJS({
|
|
1047
|
-
"node_modules/node-pty/lib/unixTerminal.js"(exports2) {
|
|
1048
|
-
"use strict";
|
|
1049
|
-
var __extends = exports2 && exports2.__extends || /* @__PURE__ */ (function() {
|
|
1050
|
-
var extendStatics = function(d, b) {
|
|
1051
|
-
extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
|
|
1052
|
-
d2.__proto__ = b2;
|
|
1053
|
-
} || function(d2, b2) {
|
|
1054
|
-
for (var p in b2) if (b2.hasOwnProperty(p)) d2[p] = b2[p];
|
|
1055
|
-
};
|
|
1056
|
-
return extendStatics(d, b);
|
|
1057
|
-
};
|
|
1058
|
-
return function(d, b) {
|
|
1059
|
-
extendStatics(d, b);
|
|
1060
|
-
function __() {
|
|
1061
|
-
this.constructor = d;
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Stop the server
|
|
858
|
+
*/
|
|
859
|
+
async stop() {
|
|
860
|
+
if (!this.isRunning) return;
|
|
861
|
+
this.isRunning = false;
|
|
862
|
+
if (this.originalStdoutWrite && this.session) {
|
|
1062
863
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
1067
|
-
exports2.UnixTerminal = void 0;
|
|
1068
|
-
var fs = require("fs");
|
|
1069
|
-
var path = require("path");
|
|
1070
|
-
var tty = require("tty");
|
|
1071
|
-
var terminal_1 = require_terminal();
|
|
1072
|
-
var utils_1 = require_utils();
|
|
1073
|
-
var native = utils_1.loadNativeModule("pty");
|
|
1074
|
-
var pty2 = native.module;
|
|
1075
|
-
var helperPath = native.dir + "/spawn-helper";
|
|
1076
|
-
helperPath = path.resolve(__dirname, helperPath);
|
|
1077
|
-
helperPath = helperPath.replace("app.asar", "app.asar.unpacked");
|
|
1078
|
-
helperPath = helperPath.replace("node_modules.asar", "node_modules.asar.unpacked");
|
|
1079
|
-
var DEFAULT_FILE = "sh";
|
|
1080
|
-
var DEFAULT_NAME = "xterm";
|
|
1081
|
-
var DESTROY_SOCKET_TIMEOUT_MS = 200;
|
|
1082
|
-
var UnixTerminal = (
|
|
1083
|
-
/** @class */
|
|
1084
|
-
(function(_super) {
|
|
1085
|
-
__extends(UnixTerminal2, _super);
|
|
1086
|
-
function UnixTerminal2(file, args, opt) {
|
|
1087
|
-
var _a, _b;
|
|
1088
|
-
var _this = _super.call(this, opt) || this;
|
|
1089
|
-
_this._boundClose = false;
|
|
1090
|
-
_this._emittedClose = false;
|
|
1091
|
-
if (typeof args === "string") {
|
|
1092
|
-
throw new Error("args as a string is not supported on unix.");
|
|
1093
|
-
}
|
|
1094
|
-
args = args || [];
|
|
1095
|
-
file = file || DEFAULT_FILE;
|
|
1096
|
-
opt = opt || {};
|
|
1097
|
-
opt.env = opt.env || process.env;
|
|
1098
|
-
_this._cols = opt.cols || terminal_1.DEFAULT_COLS;
|
|
1099
|
-
_this._rows = opt.rows || terminal_1.DEFAULT_ROWS;
|
|
1100
|
-
var uid = (_a = opt.uid) !== null && _a !== void 0 ? _a : -1;
|
|
1101
|
-
var gid = (_b = opt.gid) !== null && _b !== void 0 ? _b : -1;
|
|
1102
|
-
var env = utils_1.assign({}, opt.env);
|
|
1103
|
-
if (opt.env === process.env) {
|
|
1104
|
-
_this._sanitizeEnv(env);
|
|
1105
|
-
}
|
|
1106
|
-
var cwd = opt.cwd || process.cwd();
|
|
1107
|
-
env.PWD = cwd;
|
|
1108
|
-
var name = opt.name || env.TERM || DEFAULT_NAME;
|
|
1109
|
-
env.TERM = name;
|
|
1110
|
-
var parsedEnv = _this._parseEnv(env);
|
|
1111
|
-
var encoding = opt.encoding === void 0 ? "utf8" : opt.encoding;
|
|
1112
|
-
var onexit = function(code, signal) {
|
|
1113
|
-
if (!_this._emittedClose) {
|
|
1114
|
-
if (_this._boundClose) {
|
|
1115
|
-
return;
|
|
1116
|
-
}
|
|
1117
|
-
_this._boundClose = true;
|
|
1118
|
-
var timeout_1 = setTimeout(function() {
|
|
1119
|
-
timeout_1 = null;
|
|
1120
|
-
_this._socket.destroy();
|
|
1121
|
-
}, DESTROY_SOCKET_TIMEOUT_MS);
|
|
1122
|
-
_this.once("close", function() {
|
|
1123
|
-
if (timeout_1 !== null) {
|
|
1124
|
-
clearTimeout(timeout_1);
|
|
1125
|
-
}
|
|
1126
|
-
_this.emit("exit", code, signal);
|
|
1127
|
-
});
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
_this.emit("exit", code, signal);
|
|
1131
|
-
};
|
|
1132
|
-
var term = pty2.fork(file, args, parsedEnv, cwd, _this._cols, _this._rows, uid, gid, encoding === "utf8", helperPath, onexit);
|
|
1133
|
-
_this._socket = new tty.ReadStream(term.fd);
|
|
1134
|
-
if (encoding !== null) {
|
|
1135
|
-
_this._socket.setEncoding(encoding);
|
|
1136
|
-
}
|
|
1137
|
-
_this._writeStream = new CustomWriteStream(term.fd, encoding || void 0);
|
|
1138
|
-
_this._socket.on("error", function(err) {
|
|
1139
|
-
if (err.code) {
|
|
1140
|
-
if (~err.code.indexOf("EAGAIN")) {
|
|
1141
|
-
return;
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
_this._close();
|
|
1145
|
-
if (!_this._emittedClose) {
|
|
1146
|
-
_this._emittedClose = true;
|
|
1147
|
-
_this.emit("close");
|
|
1148
|
-
}
|
|
1149
|
-
if (err.code) {
|
|
1150
|
-
if (~err.code.indexOf("errno 5") || ~err.code.indexOf("EIO")) {
|
|
1151
|
-
return;
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
if (_this.listeners("error").length < 2) {
|
|
1155
|
-
throw err;
|
|
1156
|
-
}
|
|
1157
|
-
});
|
|
1158
|
-
_this._pid = term.pid;
|
|
1159
|
-
_this._fd = term.fd;
|
|
1160
|
-
_this._pty = term.pty;
|
|
1161
|
-
_this._file = file;
|
|
1162
|
-
_this._name = name;
|
|
1163
|
-
_this._readable = true;
|
|
1164
|
-
_this._writable = true;
|
|
1165
|
-
_this._socket.on("close", function() {
|
|
1166
|
-
if (_this._emittedClose) {
|
|
1167
|
-
return;
|
|
1168
|
-
}
|
|
1169
|
-
_this._emittedClose = true;
|
|
1170
|
-
_this._close();
|
|
1171
|
-
_this.emit("close");
|
|
1172
|
-
});
|
|
1173
|
-
_this._forwardEvents();
|
|
1174
|
-
return _this;
|
|
864
|
+
if (this.heartbeatTimer) {
|
|
865
|
+
clearInterval(this.heartbeatTimer);
|
|
866
|
+
this.heartbeatTimer = null;
|
|
1175
867
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
};
|
|
1193
|
-
Object.defineProperty(UnixTerminal2.prototype, "fd", {
|
|
1194
|
-
/* Accessors */
|
|
1195
|
-
get: function() {
|
|
1196
|
-
return this._fd;
|
|
1197
|
-
},
|
|
1198
|
-
enumerable: false,
|
|
1199
|
-
configurable: true
|
|
1200
|
-
});
|
|
1201
|
-
Object.defineProperty(UnixTerminal2.prototype, "ptsName", {
|
|
1202
|
-
get: function() {
|
|
1203
|
-
return this._pty;
|
|
1204
|
-
},
|
|
1205
|
-
enumerable: false,
|
|
1206
|
-
configurable: true
|
|
1207
|
-
});
|
|
1208
|
-
UnixTerminal2.open = function(opt) {
|
|
1209
|
-
var self = Object.create(UnixTerminal2.prototype);
|
|
1210
|
-
opt = opt || {};
|
|
1211
|
-
if (arguments.length > 1) {
|
|
1212
|
-
opt = {
|
|
1213
|
-
cols: arguments[1],
|
|
1214
|
-
rows: arguments[2]
|
|
1215
|
-
};
|
|
1216
|
-
}
|
|
1217
|
-
var cols = opt.cols || terminal_1.DEFAULT_COLS;
|
|
1218
|
-
var rows = opt.rows || terminal_1.DEFAULT_ROWS;
|
|
1219
|
-
var encoding = opt.encoding === void 0 ? "utf8" : opt.encoding;
|
|
1220
|
-
var term = pty2.open(cols, rows);
|
|
1221
|
-
self._master = new tty.ReadStream(term.master);
|
|
1222
|
-
if (encoding !== null) {
|
|
1223
|
-
self._master.setEncoding(encoding);
|
|
1224
|
-
}
|
|
1225
|
-
self._master.resume();
|
|
1226
|
-
self._slave = new tty.ReadStream(term.slave);
|
|
1227
|
-
if (encoding !== null) {
|
|
1228
|
-
self._slave.setEncoding(encoding);
|
|
1229
|
-
}
|
|
1230
|
-
self._slave.resume();
|
|
1231
|
-
self._socket = self._master;
|
|
1232
|
-
self._pid = -1;
|
|
1233
|
-
self._fd = term.master;
|
|
1234
|
-
self._pty = term.pty;
|
|
1235
|
-
self._file = process.argv[0] || "node";
|
|
1236
|
-
self._name = process.env.TERM || "";
|
|
1237
|
-
self._readable = true;
|
|
1238
|
-
self._writable = true;
|
|
1239
|
-
self._socket.on("error", function(err) {
|
|
1240
|
-
self._close();
|
|
1241
|
-
if (self.listeners("error").length < 2) {
|
|
1242
|
-
throw err;
|
|
1243
|
-
}
|
|
1244
|
-
});
|
|
1245
|
-
self._socket.on("close", function() {
|
|
1246
|
-
self._close();
|
|
1247
|
-
});
|
|
1248
|
-
return self;
|
|
1249
|
-
};
|
|
1250
|
-
UnixTerminal2.prototype.destroy = function() {
|
|
1251
|
-
var _this = this;
|
|
1252
|
-
this._close();
|
|
1253
|
-
this._socket.once("close", function() {
|
|
1254
|
-
_this.kill("SIGHUP");
|
|
1255
|
-
});
|
|
1256
|
-
this._socket.destroy();
|
|
1257
|
-
this._writeStream.dispose();
|
|
1258
|
-
};
|
|
1259
|
-
UnixTerminal2.prototype.kill = function(signal) {
|
|
1260
|
-
try {
|
|
1261
|
-
process.kill(this.pid, signal || "SIGHUP");
|
|
1262
|
-
} catch (e) {
|
|
1263
|
-
}
|
|
1264
|
-
};
|
|
1265
|
-
Object.defineProperty(UnixTerminal2.prototype, "process", {
|
|
1266
|
-
/**
|
|
1267
|
-
* Gets the name of the process.
|
|
1268
|
-
*/
|
|
1269
|
-
get: function() {
|
|
1270
|
-
if (process.platform === "darwin") {
|
|
1271
|
-
var title = pty2.process(this._fd);
|
|
1272
|
-
return title !== "kernel_task" ? title : this._file;
|
|
1273
|
-
}
|
|
1274
|
-
return pty2.process(this._fd, this._pty) || this._file;
|
|
1275
|
-
},
|
|
1276
|
-
enumerable: false,
|
|
1277
|
-
configurable: true
|
|
1278
|
-
});
|
|
1279
|
-
UnixTerminal2.prototype.resize = function(cols, rows) {
|
|
1280
|
-
if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {
|
|
1281
|
-
throw new Error("resizing must be done using positive cols and rows");
|
|
1282
|
-
}
|
|
1283
|
-
pty2.resize(this._fd, cols, rows);
|
|
1284
|
-
this._cols = cols;
|
|
1285
|
-
this._rows = rows;
|
|
1286
|
-
};
|
|
1287
|
-
UnixTerminal2.prototype.clear = function() {
|
|
1288
|
-
};
|
|
1289
|
-
UnixTerminal2.prototype._sanitizeEnv = function(env) {
|
|
1290
|
-
delete env["TMUX"];
|
|
1291
|
-
delete env["TMUX_PANE"];
|
|
1292
|
-
delete env["STY"];
|
|
1293
|
-
delete env["WINDOW"];
|
|
1294
|
-
delete env["WINDOWID"];
|
|
1295
|
-
delete env["TERMCAP"];
|
|
1296
|
-
delete env["COLUMNS"];
|
|
1297
|
-
delete env["LINES"];
|
|
1298
|
-
};
|
|
1299
|
-
return UnixTerminal2;
|
|
1300
|
-
})(terminal_1.Terminal)
|
|
1301
|
-
);
|
|
1302
|
-
exports2.UnixTerminal = UnixTerminal;
|
|
1303
|
-
var CustomWriteStream = (
|
|
1304
|
-
/** @class */
|
|
1305
|
-
(function() {
|
|
1306
|
-
function CustomWriteStream2(_fd, _encoding) {
|
|
1307
|
-
this._fd = _fd;
|
|
1308
|
-
this._encoding = _encoding;
|
|
1309
|
-
this._writeQueue = [];
|
|
1310
|
-
}
|
|
1311
|
-
CustomWriteStream2.prototype.dispose = function() {
|
|
1312
|
-
clearImmediate(this._writeImmediate);
|
|
1313
|
-
this._writeImmediate = void 0;
|
|
1314
|
-
};
|
|
1315
|
-
CustomWriteStream2.prototype.write = function(data) {
|
|
1316
|
-
var buffer = typeof data === "string" ? Buffer.from(data, this._encoding) : Buffer.from(data);
|
|
1317
|
-
if (buffer.byteLength !== 0) {
|
|
1318
|
-
this._writeQueue.push({ buffer, offset: 0 });
|
|
1319
|
-
if (this._writeQueue.length === 1) {
|
|
1320
|
-
this._processWriteQueue();
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
CustomWriteStream2.prototype._processWriteQueue = function() {
|
|
1325
|
-
var _this = this;
|
|
1326
|
-
this._writeImmediate = void 0;
|
|
1327
|
-
if (this._writeQueue.length === 0) {
|
|
1328
|
-
return;
|
|
1329
|
-
}
|
|
1330
|
-
var task = this._writeQueue[0];
|
|
1331
|
-
fs.write(this._fd, task.buffer, task.offset, function(err, written) {
|
|
1332
|
-
if (err) {
|
|
1333
|
-
if ("code" in err && err.code === "EAGAIN") {
|
|
1334
|
-
_this._writeImmediate = setImmediate(function() {
|
|
1335
|
-
return _this._processWriteQueue();
|
|
1336
|
-
});
|
|
1337
|
-
} else {
|
|
1338
|
-
_this._writeQueue.length = 0;
|
|
1339
|
-
console.error("Unhandled pty write error", err);
|
|
1340
|
-
}
|
|
1341
|
-
return;
|
|
1342
|
-
}
|
|
1343
|
-
task.offset += written;
|
|
1344
|
-
if (task.offset >= task.buffer.byteLength) {
|
|
1345
|
-
_this._writeQueue.shift();
|
|
1346
|
-
}
|
|
1347
|
-
_this._processWriteQueue();
|
|
868
|
+
if (this.sessionTimeoutTimer) {
|
|
869
|
+
clearTimeout(this.sessionTimeoutTimer);
|
|
870
|
+
this.sessionTimeoutTimer = null;
|
|
871
|
+
}
|
|
872
|
+
this.broadcastToAll({ type: MessageTypes.SESSION_END, payload: {} });
|
|
873
|
+
for (const client of this.clients.values()) {
|
|
874
|
+
client.ws.close(1e3, "Server shutting down");
|
|
875
|
+
}
|
|
876
|
+
this.clients.clear();
|
|
877
|
+
if (this.wss) {
|
|
878
|
+
this.wss.close();
|
|
879
|
+
this.wss = null;
|
|
880
|
+
}
|
|
881
|
+
if (this.httpServer) {
|
|
882
|
+
await new Promise((resolve) => {
|
|
883
|
+
this.httpServer.close(() => resolve());
|
|
1348
884
|
});
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
// node_modules/node-pty/lib/index.js
|
|
1357
|
-
var require_lib = __commonJS({
|
|
1358
|
-
"node_modules/node-pty/lib/index.js"(exports2) {
|
|
1359
|
-
"use strict";
|
|
1360
|
-
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
1361
|
-
exports2.native = exports2.open = exports2.createTerminal = exports2.fork = exports2.spawn = void 0;
|
|
1362
|
-
var utils_1 = require_utils();
|
|
1363
|
-
var terminalCtor;
|
|
1364
|
-
if (process.platform === "win32") {
|
|
1365
|
-
terminalCtor = require_windowsTerminal().WindowsTerminal;
|
|
1366
|
-
} else {
|
|
1367
|
-
terminalCtor = require_unixTerminal().UnixTerminal;
|
|
1368
|
-
}
|
|
1369
|
-
function spawn3(file, args, opt) {
|
|
1370
|
-
return new terminalCtor(file, args, opt);
|
|
1371
|
-
}
|
|
1372
|
-
exports2.spawn = spawn3;
|
|
1373
|
-
function fork(file, args, opt) {
|
|
1374
|
-
return new terminalCtor(file, args, opt);
|
|
1375
|
-
}
|
|
1376
|
-
exports2.fork = fork;
|
|
1377
|
-
function createTerminal(file, args, opt) {
|
|
1378
|
-
return new terminalCtor(file, args, opt);
|
|
1379
|
-
}
|
|
1380
|
-
exports2.createTerminal = createTerminal;
|
|
1381
|
-
function open(options) {
|
|
1382
|
-
return terminalCtor.open(options);
|
|
1383
|
-
}
|
|
1384
|
-
exports2.open = open;
|
|
1385
|
-
exports2.native = process.platform !== "win32" ? utils_1.loadNativeModule("pty").module : null;
|
|
1386
|
-
}
|
|
1387
|
-
});
|
|
1388
|
-
|
|
1389
|
-
// src/terminal.ts
|
|
1390
|
-
var import_node_events, import_node_child_process, pty, TerminalManager;
|
|
1391
|
-
var init_terminal = __esm({
|
|
1392
|
-
"src/terminal.ts"() {
|
|
1393
|
-
"use strict";
|
|
1394
|
-
import_node_events = require("events");
|
|
1395
|
-
import_node_child_process = require("child_process");
|
|
1396
|
-
pty = null;
|
|
1397
|
-
try {
|
|
1398
|
-
pty = require_lib();
|
|
1399
|
-
} catch {
|
|
1400
|
-
}
|
|
1401
|
-
TerminalManager = class extends import_node_events.EventEmitter {
|
|
1402
|
-
config;
|
|
1403
|
-
ptyProcess = null;
|
|
1404
|
-
process = null;
|
|
1405
|
-
running = false;
|
|
1406
|
-
constructor(config) {
|
|
1407
|
-
super();
|
|
1408
|
-
this.config = config;
|
|
885
|
+
this.httpServer = null;
|
|
886
|
+
}
|
|
887
|
+
if (this.session) {
|
|
888
|
+
this.session.status = "stopped";
|
|
889
|
+
}
|
|
890
|
+
this.emit("stopped");
|
|
1409
891
|
}
|
|
1410
892
|
/**
|
|
1411
|
-
*
|
|
893
|
+
* Broadcast message to all authenticated clients
|
|
1412
894
|
*/
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
if (pty) {
|
|
1423
|
-
try {
|
|
1424
|
-
this.ptyProcess = pty.spawn(shell, [], {
|
|
1425
|
-
name: "xterm-256color",
|
|
1426
|
-
cols,
|
|
1427
|
-
rows,
|
|
1428
|
-
cwd: cwd || process.cwd(),
|
|
1429
|
-
env: termEnv
|
|
1430
|
-
});
|
|
1431
|
-
this.ptyProcess.onData((data) => {
|
|
1432
|
-
this.emit("data", data);
|
|
1433
|
-
});
|
|
1434
|
-
this.ptyProcess.onExit(({ exitCode }) => {
|
|
1435
|
-
this.running = false;
|
|
1436
|
-
this.emit("exit", exitCode);
|
|
1437
|
-
});
|
|
1438
|
-
this.running = true;
|
|
1439
|
-
return;
|
|
1440
|
-
} catch (error) {
|
|
1441
|
-
console.warn("node-pty failed, using fallback:", error.message);
|
|
895
|
+
broadcastToAll(message) {
|
|
896
|
+
const data = JSON.stringify({
|
|
897
|
+
type: message.type,
|
|
898
|
+
payload: message.payload,
|
|
899
|
+
timestamp: message.timestamp || Date.now()
|
|
900
|
+
});
|
|
901
|
+
for (const client of this.clients.values()) {
|
|
902
|
+
if (client.authenticated && client.ws.readyState === import_ws.WebSocket.OPEN) {
|
|
903
|
+
client.ws.send(data);
|
|
1442
904
|
}
|
|
1443
905
|
}
|
|
1444
|
-
this.process = (0, import_node_child_process.spawn)(shell, [], {
|
|
1445
|
-
cwd: cwd || process.cwd(),
|
|
1446
|
-
env: termEnv,
|
|
1447
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
1448
|
-
shell: true
|
|
1449
|
-
});
|
|
1450
|
-
this.process.stdout?.on("data", (data) => {
|
|
1451
|
-
this.emit("data", data.toString());
|
|
1452
|
-
});
|
|
1453
|
-
this.process.stderr?.on("data", (data) => {
|
|
1454
|
-
this.emit("data", data.toString());
|
|
1455
|
-
});
|
|
1456
|
-
this.process.on("exit", (code) => {
|
|
1457
|
-
this.running = false;
|
|
1458
|
-
this.emit("exit", code || 0);
|
|
1459
|
-
});
|
|
1460
|
-
this.process.on("error", (error) => {
|
|
1461
|
-
this.emit("error", error);
|
|
1462
|
-
});
|
|
1463
|
-
this.running = true;
|
|
1464
906
|
}
|
|
1465
907
|
/**
|
|
1466
|
-
*
|
|
908
|
+
* Send notification to clients
|
|
1467
909
|
*/
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
}
|
|
910
|
+
notify(notification) {
|
|
911
|
+
this.broadcastToAll({
|
|
912
|
+
type: MessageTypes.NOTIFICATION,
|
|
913
|
+
payload: notification
|
|
914
|
+
});
|
|
1474
915
|
}
|
|
1475
916
|
/**
|
|
1476
|
-
*
|
|
917
|
+
* Get current session
|
|
1477
918
|
*/
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
this.ptyProcess.resize(cols, rows);
|
|
1481
|
-
}
|
|
919
|
+
getSession() {
|
|
920
|
+
return this.session;
|
|
1482
921
|
}
|
|
1483
922
|
/**
|
|
1484
|
-
*
|
|
923
|
+
* Check if server is running
|
|
1485
924
|
*/
|
|
1486
|
-
|
|
1487
|
-
this.
|
|
925
|
+
isActive() {
|
|
926
|
+
return this.isRunning && this.session?.status !== "stopped";
|
|
1488
927
|
}
|
|
1489
928
|
/**
|
|
1490
|
-
*
|
|
929
|
+
* Get connected client count
|
|
1491
930
|
*/
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
this.ptyProcess = null;
|
|
1497
|
-
}
|
|
1498
|
-
if (this.process) {
|
|
1499
|
-
this.process.kill();
|
|
1500
|
-
this.process = null;
|
|
931
|
+
getConnectedCount() {
|
|
932
|
+
let count = 0;
|
|
933
|
+
for (const client of this.clients.values()) {
|
|
934
|
+
if (client.authenticated) count++;
|
|
1501
935
|
}
|
|
936
|
+
return count;
|
|
1502
937
|
}
|
|
1503
938
|
/**
|
|
1504
|
-
*
|
|
939
|
+
* Write data to all connected clients (for manual output streaming)
|
|
1505
940
|
*/
|
|
1506
|
-
|
|
1507
|
-
|
|
941
|
+
writeToClients(data) {
|
|
942
|
+
this.broadcastToAll({ type: MessageTypes.TERMINAL_OUTPUT, payload: { data } });
|
|
1508
943
|
}
|
|
1509
944
|
/**
|
|
1510
|
-
*
|
|
945
|
+
* Alias for writeToClients - for compatibility
|
|
1511
946
|
*/
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
}
|
|
1515
|
-
};
|
|
1516
|
-
}
|
|
1517
|
-
});
|
|
1518
|
-
|
|
1519
|
-
// node_modules/axios/lib/helpers/bind.js
|
|
1520
|
-
var require_bind = __commonJS({
|
|
1521
|
-
"node_modules/axios/lib/helpers/bind.js"(exports2, module2) {
|
|
1522
|
-
"use strict";
|
|
1523
|
-
module2.exports = function bind(fn, thisArg) {
|
|
1524
|
-
return function wrap() {
|
|
1525
|
-
var args = new Array(arguments.length);
|
|
1526
|
-
for (var i = 0; i < args.length; i++) {
|
|
1527
|
-
args[i] = arguments[i];
|
|
1528
|
-
}
|
|
1529
|
-
return fn.apply(thisArg, args);
|
|
1530
|
-
};
|
|
1531
|
-
};
|
|
1532
|
-
}
|
|
1533
|
-
});
|
|
1534
|
-
|
|
1535
|
-
// node_modules/axios/lib/utils.js
|
|
1536
|
-
var require_utils2 = __commonJS({
|
|
1537
|
-
"node_modules/axios/lib/utils.js"(exports2, module2) {
|
|
1538
|
-
"use strict";
|
|
1539
|
-
var bind = require_bind();
|
|
1540
|
-
var toString = Object.prototype.toString;
|
|
1541
|
-
function isArray(val) {
|
|
1542
|
-
return toString.call(val) === "[object Array]";
|
|
1543
|
-
}
|
|
1544
|
-
function isUndefined(val) {
|
|
1545
|
-
return typeof val === "undefined";
|
|
1546
|
-
}
|
|
1547
|
-
function isBuffer(val) {
|
|
1548
|
-
return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) && typeof val.constructor.isBuffer === "function" && val.constructor.isBuffer(val);
|
|
1549
|
-
}
|
|
1550
|
-
function isArrayBuffer(val) {
|
|
1551
|
-
return toString.call(val) === "[object ArrayBuffer]";
|
|
1552
|
-
}
|
|
1553
|
-
function isFormData(val) {
|
|
1554
|
-
return typeof FormData !== "undefined" && val instanceof FormData;
|
|
1555
|
-
}
|
|
1556
|
-
function isArrayBufferView(val) {
|
|
1557
|
-
var result;
|
|
1558
|
-
if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView) {
|
|
1559
|
-
result = ArrayBuffer.isView(val);
|
|
1560
|
-
} else {
|
|
1561
|
-
result = val && val.buffer && val.buffer instanceof ArrayBuffer;
|
|
1562
|
-
}
|
|
1563
|
-
return result;
|
|
1564
|
-
}
|
|
1565
|
-
function isString(val) {
|
|
1566
|
-
return typeof val === "string";
|
|
1567
|
-
}
|
|
1568
|
-
function isNumber(val) {
|
|
1569
|
-
return typeof val === "number";
|
|
1570
|
-
}
|
|
1571
|
-
function isObject(val) {
|
|
1572
|
-
return val !== null && typeof val === "object";
|
|
1573
|
-
}
|
|
1574
|
-
function isPlainObject(val) {
|
|
1575
|
-
if (toString.call(val) !== "[object Object]") {
|
|
1576
|
-
return false;
|
|
947
|
+
writeToTerminal(data) {
|
|
948
|
+
this.writeToClients(data);
|
|
1577
949
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
950
|
+
/**
|
|
951
|
+
* Setup WebSocket handlers
|
|
952
|
+
*/
|
|
953
|
+
setupWebSocketHandlers() {
|
|
954
|
+
this.wss.on("connection", (ws, req) => {
|
|
955
|
+
const clientId = this.generateClientId();
|
|
956
|
+
const client = {
|
|
957
|
+
id: clientId,
|
|
958
|
+
ws,
|
|
959
|
+
authenticated: false,
|
|
960
|
+
device: {
|
|
961
|
+
id: clientId,
|
|
962
|
+
userAgent: req.headers["user-agent"],
|
|
963
|
+
ip: req.socket.remoteAddress,
|
|
964
|
+
connectedAt: /* @__PURE__ */ new Date(),
|
|
965
|
+
lastActivity: /* @__PURE__ */ new Date()
|
|
966
|
+
},
|
|
967
|
+
lastPing: Date.now()
|
|
968
|
+
};
|
|
969
|
+
if (this.clients.size >= this.config.maxConnections) {
|
|
970
|
+
ws.close(1013, "Max connections reached");
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
this.clients.set(clientId, client);
|
|
974
|
+
ws.send(JSON.stringify({ type: MessageTypes.AUTH_REQUIRED, timestamp: Date.now() }));
|
|
975
|
+
ws.on("message", (data) => {
|
|
976
|
+
try {
|
|
977
|
+
const message = JSON.parse(data.toString());
|
|
978
|
+
this.handleClientMessage(client, message);
|
|
979
|
+
} catch {
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
ws.on("close", () => {
|
|
983
|
+
this.clients.delete(clientId);
|
|
984
|
+
if (this.session && client.authenticated) {
|
|
985
|
+
this.session.connectedDevices = this.session.connectedDevices.filter(
|
|
986
|
+
(d) => d.id !== clientId
|
|
987
|
+
);
|
|
988
|
+
if (this.session.connectedDevices.length === 0) {
|
|
989
|
+
this.session.status = "waiting";
|
|
990
|
+
}
|
|
991
|
+
this.emit("client:disconnected", client.device);
|
|
992
|
+
}
|
|
993
|
+
});
|
|
994
|
+
ws.on("error", (error) => {
|
|
995
|
+
this.emit("client:error", clientId, error);
|
|
996
|
+
});
|
|
997
|
+
ws.on("pong", () => {
|
|
998
|
+
client.lastPing = Date.now();
|
|
999
|
+
});
|
|
1000
|
+
});
|
|
1614
1001
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1002
|
+
/**
|
|
1003
|
+
* Handle client message
|
|
1004
|
+
*/
|
|
1005
|
+
handleClientMessage(client, message) {
|
|
1006
|
+
client.device.lastActivity = /* @__PURE__ */ new Date();
|
|
1007
|
+
if (this.session) {
|
|
1008
|
+
this.session.lastActivity = /* @__PURE__ */ new Date();
|
|
1618
1009
|
}
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1622
|
-
fn.call(null, obj[key], key, obj);
|
|
1623
|
-
}
|
|
1010
|
+
if (this.config.sessionTimeout > 0) {
|
|
1011
|
+
this.resetSessionTimeout();
|
|
1624
1012
|
}
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1013
|
+
switch (message.type) {
|
|
1014
|
+
case MessageTypes.AUTH:
|
|
1015
|
+
this.handleAuth(client, message.token);
|
|
1016
|
+
break;
|
|
1017
|
+
case MessageTypes.TERMINAL_INPUT:
|
|
1018
|
+
break;
|
|
1019
|
+
case MessageTypes.TERMINAL_RESIZE:
|
|
1020
|
+
this.emit("message", client, message);
|
|
1021
|
+
break;
|
|
1022
|
+
case MessageTypes.PING:
|
|
1023
|
+
client.ws.send(JSON.stringify({ type: MessageTypes.PONG, timestamp: Date.now() }));
|
|
1024
|
+
break;
|
|
1025
|
+
default:
|
|
1026
|
+
this.emit("message", client, message);
|
|
1638
1027
|
}
|
|
1639
1028
|
}
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1029
|
+
/**
|
|
1030
|
+
* Handle authentication
|
|
1031
|
+
*/
|
|
1032
|
+
handleAuth(client, token) {
|
|
1033
|
+
if (token === this.sessionSecret) {
|
|
1034
|
+
client.authenticated = true;
|
|
1035
|
+
if (this.session) {
|
|
1036
|
+
this.session.connectedDevices.push(client.device);
|
|
1037
|
+
this.session.status = "connected";
|
|
1038
|
+
}
|
|
1039
|
+
client.ws.send(
|
|
1040
|
+
JSON.stringify({
|
|
1041
|
+
type: MessageTypes.AUTH_SUCCESS,
|
|
1042
|
+
payload: {
|
|
1043
|
+
sessionId: this.session?.id
|
|
1044
|
+
},
|
|
1045
|
+
timestamp: Date.now()
|
|
1046
|
+
})
|
|
1047
|
+
);
|
|
1048
|
+
this.emit("client:connected", client.device);
|
|
1649
1049
|
} else {
|
|
1650
|
-
|
|
1050
|
+
client.ws.send(JSON.stringify({ type: MessageTypes.AUTH_FAILED, timestamp: Date.now() }));
|
|
1051
|
+
setTimeout(() => client.ws.close(1008, "Authentication failed"), 100);
|
|
1651
1052
|
}
|
|
1652
|
-
});
|
|
1653
|
-
return a;
|
|
1654
|
-
}
|
|
1655
|
-
function stripBOM(content) {
|
|
1656
|
-
if (content.charCodeAt(0) === 65279) {
|
|
1657
|
-
content = content.slice(1);
|
|
1658
|
-
}
|
|
1659
|
-
return content;
|
|
1660
|
-
}
|
|
1661
|
-
module2.exports = {
|
|
1662
|
-
isArray,
|
|
1663
|
-
isArrayBuffer,
|
|
1664
|
-
isBuffer,
|
|
1665
|
-
isFormData,
|
|
1666
|
-
isArrayBufferView,
|
|
1667
|
-
isString,
|
|
1668
|
-
isNumber,
|
|
1669
|
-
isObject,
|
|
1670
|
-
isPlainObject,
|
|
1671
|
-
isUndefined,
|
|
1672
|
-
isDate,
|
|
1673
|
-
isFile,
|
|
1674
|
-
isBlob,
|
|
1675
|
-
isFunction,
|
|
1676
|
-
isStream,
|
|
1677
|
-
isURLSearchParams,
|
|
1678
|
-
isStandardBrowserEnv,
|
|
1679
|
-
forEach,
|
|
1680
|
-
merge,
|
|
1681
|
-
extend,
|
|
1682
|
-
trim,
|
|
1683
|
-
stripBOM
|
|
1684
|
-
};
|
|
1685
|
-
}
|
|
1686
|
-
});
|
|
1687
|
-
|
|
1688
|
-
// node_modules/axios/lib/helpers/buildURL.js
|
|
1689
|
-
var require_buildURL = __commonJS({
|
|
1690
|
-
"node_modules/axios/lib/helpers/buildURL.js"(exports2, module2) {
|
|
1691
|
-
"use strict";
|
|
1692
|
-
var utils = require_utils2();
|
|
1693
|
-
function encode(val) {
|
|
1694
|
-
return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+").replace(/%5B/gi, "[").replace(/%5D/gi, "]");
|
|
1695
|
-
}
|
|
1696
|
-
module2.exports = function buildURL(url, params, paramsSerializer) {
|
|
1697
|
-
if (!params) {
|
|
1698
|
-
return url;
|
|
1699
1053
|
}
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
} else if (utils.isObject(v)) {
|
|
1720
|
-
v = JSON.stringify(v);
|
|
1721
|
-
}
|
|
1722
|
-
parts.push(encode(key) + "=" + encode(v));
|
|
1054
|
+
/**
|
|
1055
|
+
* Handle HTTP request
|
|
1056
|
+
*/
|
|
1057
|
+
handleHttpRequest(req, res) {
|
|
1058
|
+
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
1059
|
+
const path = url.pathname;
|
|
1060
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1061
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
1062
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
1063
|
+
if (req.method === "OPTIONS") {
|
|
1064
|
+
res.writeHead(204);
|
|
1065
|
+
res.end();
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
if (path === "/" || path === "/index.html") {
|
|
1069
|
+
const { getWebClient: getWebClient2 } = (init_web_client(), __toCommonJS(web_client_exports));
|
|
1070
|
+
res.writeHead(200, {
|
|
1071
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
1072
|
+
"Content-Security-Policy": "default-src 'self' 'unsafe-inline' 'unsafe-eval' https: data: ws: wss:"
|
|
1723
1073
|
});
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
}
|
|
1727
|
-
if (serializedParams) {
|
|
1728
|
-
var hashmarkIndex = url.indexOf("#");
|
|
1729
|
-
if (hashmarkIndex !== -1) {
|
|
1730
|
-
url = url.slice(0, hashmarkIndex);
|
|
1074
|
+
res.end(getWebClient2());
|
|
1075
|
+
return;
|
|
1731
1076
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
synchronous: options ? options.synchronous : false,
|
|
1752
|
-
runWhen: options ? options.runWhen : null
|
|
1753
|
-
});
|
|
1754
|
-
return this.handlers.length - 1;
|
|
1755
|
-
};
|
|
1756
|
-
InterceptorManager.prototype.eject = function eject(id) {
|
|
1757
|
-
if (this.handlers[id]) {
|
|
1758
|
-
this.handlers[id] = null;
|
|
1077
|
+
if (path === "/health") {
|
|
1078
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1079
|
+
res.end(JSON.stringify({ status: "ok", session: this.session?.id }));
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
if (path === "/api/session") {
|
|
1083
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1084
|
+
res.end(
|
|
1085
|
+
JSON.stringify({
|
|
1086
|
+
id: this.session?.id,
|
|
1087
|
+
name: this.session?.name,
|
|
1088
|
+
status: this.session?.status,
|
|
1089
|
+
connectedDevices: this.session?.connectedDevices.length
|
|
1090
|
+
})
|
|
1091
|
+
);
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1095
|
+
res.end("Not Found");
|
|
1759
1096
|
}
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1097
|
+
/**
|
|
1098
|
+
* Start heartbeat
|
|
1099
|
+
*/
|
|
1100
|
+
startHeartbeat() {
|
|
1101
|
+
this.heartbeatTimer = setInterval(() => {
|
|
1102
|
+
const now = Date.now();
|
|
1103
|
+
for (const [id, client] of this.clients) {
|
|
1104
|
+
if (now - client.lastPing > this.config.heartbeatInterval * 2) {
|
|
1105
|
+
client.ws.terminate();
|
|
1106
|
+
this.clients.delete(id);
|
|
1107
|
+
} else if (client.ws.readyState === import_ws.WebSocket.OPEN) {
|
|
1108
|
+
client.ws.ping();
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}, this.config.heartbeatInterval);
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* Start session timeout
|
|
1115
|
+
*/
|
|
1116
|
+
startSessionTimeout() {
|
|
1117
|
+
this.sessionTimeoutTimer = setTimeout(() => {
|
|
1118
|
+
if (this.session?.connectedDevices.length === 0) {
|
|
1119
|
+
this.stop();
|
|
1120
|
+
}
|
|
1121
|
+
}, this.config.sessionTimeout);
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Reset session timeout
|
|
1125
|
+
*/
|
|
1126
|
+
resetSessionTimeout() {
|
|
1127
|
+
if (this.sessionTimeoutTimer) {
|
|
1128
|
+
clearTimeout(this.sessionTimeoutTimer);
|
|
1765
1129
|
}
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
module2.exports = InterceptorManager;
|
|
1769
|
-
}
|
|
1770
|
-
});
|
|
1771
|
-
|
|
1772
|
-
// node_modules/axios/lib/helpers/normalizeHeaderName.js
|
|
1773
|
-
var require_normalizeHeaderName = __commonJS({
|
|
1774
|
-
"node_modules/axios/lib/helpers/normalizeHeaderName.js"(exports2, module2) {
|
|
1775
|
-
"use strict";
|
|
1776
|
-
var utils = require_utils2();
|
|
1777
|
-
module2.exports = function normalizeHeaderName(headers, normalizedName) {
|
|
1778
|
-
utils.forEach(headers, function processHeader(value, name) {
|
|
1779
|
-
if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
|
|
1780
|
-
headers[normalizedName] = value;
|
|
1781
|
-
delete headers[name];
|
|
1130
|
+
if (this.config.sessionTimeout > 0) {
|
|
1131
|
+
this.startSessionTimeout();
|
|
1782
1132
|
}
|
|
1783
|
-
});
|
|
1784
|
-
};
|
|
1785
|
-
}
|
|
1786
|
-
});
|
|
1787
|
-
|
|
1788
|
-
// node_modules/axios/lib/core/enhanceError.js
|
|
1789
|
-
var require_enhanceError = __commonJS({
|
|
1790
|
-
"node_modules/axios/lib/core/enhanceError.js"(exports2, module2) {
|
|
1791
|
-
"use strict";
|
|
1792
|
-
module2.exports = function enhanceError(error, config, code, request, response) {
|
|
1793
|
-
error.config = config;
|
|
1794
|
-
if (code) {
|
|
1795
|
-
error.code = code;
|
|
1796
1133
|
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1134
|
+
/**
|
|
1135
|
+
* Get local IP
|
|
1136
|
+
*/
|
|
1137
|
+
getLocalIP() {
|
|
1138
|
+
const interfaces = import_node_os.default.networkInterfaces();
|
|
1139
|
+
for (const name of Object.keys(interfaces)) {
|
|
1140
|
+
for (const iface of interfaces[name] || []) {
|
|
1141
|
+
if (iface.family === "IPv4" && !iface.internal) {
|
|
1142
|
+
return iface.address;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return "127.0.0.1";
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Generate session ID
|
|
1150
|
+
*/
|
|
1151
|
+
generateSessionId() {
|
|
1152
|
+
return import_node_crypto.default.randomBytes(4).toString("hex");
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Generate client ID
|
|
1156
|
+
*/
|
|
1157
|
+
generateClientId() {
|
|
1158
|
+
return "c_" + import_node_crypto.default.randomBytes(4).toString("hex");
|
|
1159
|
+
}
|
|
1819
1160
|
};
|
|
1820
1161
|
}
|
|
1821
1162
|
});
|
|
1822
1163
|
|
|
1823
|
-
// node_modules/axios/lib/
|
|
1824
|
-
var
|
|
1825
|
-
"node_modules/axios/lib/
|
|
1164
|
+
// node_modules/axios/lib/helpers/bind.js
|
|
1165
|
+
var require_bind = __commonJS({
|
|
1166
|
+
"node_modules/axios/lib/helpers/bind.js"(exports2, module2) {
|
|
1826
1167
|
"use strict";
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1168
|
+
module2.exports = function bind(fn, thisArg) {
|
|
1169
|
+
return function wrap() {
|
|
1170
|
+
var args = new Array(arguments.length);
|
|
1171
|
+
for (var i = 0; i < args.length; i++) {
|
|
1172
|
+
args[i] = arguments[i];
|
|
1173
|
+
}
|
|
1174
|
+
return fn.apply(thisArg, args);
|
|
1175
|
+
};
|
|
1831
1176
|
};
|
|
1832
1177
|
}
|
|
1833
1178
|
});
|
|
1834
1179
|
|
|
1835
|
-
// node_modules/axios/lib/
|
|
1836
|
-
var
|
|
1837
|
-
"node_modules/axios/lib/
|
|
1180
|
+
// node_modules/axios/lib/utils.js
|
|
1181
|
+
var require_utils = __commonJS({
|
|
1182
|
+
"node_modules/axios/lib/utils.js"(exports2, module2) {
|
|
1838
1183
|
"use strict";
|
|
1839
|
-
var
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1184
|
+
var bind = require_bind();
|
|
1185
|
+
var toString = Object.prototype.toString;
|
|
1186
|
+
function isArray(val) {
|
|
1187
|
+
return toString.call(val) === "[object Array]";
|
|
1188
|
+
}
|
|
1189
|
+
function isUndefined(val) {
|
|
1190
|
+
return typeof val === "undefined";
|
|
1191
|
+
}
|
|
1192
|
+
function isBuffer(val) {
|
|
1193
|
+
return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) && typeof val.constructor.isBuffer === "function" && val.constructor.isBuffer(val);
|
|
1194
|
+
}
|
|
1195
|
+
function isArrayBuffer(val) {
|
|
1196
|
+
return toString.call(val) === "[object ArrayBuffer]";
|
|
1197
|
+
}
|
|
1198
|
+
function isFormData(val) {
|
|
1199
|
+
return typeof FormData !== "undefined" && val instanceof FormData;
|
|
1200
|
+
}
|
|
1201
|
+
function isArrayBufferView(val) {
|
|
1202
|
+
var result;
|
|
1203
|
+
if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView) {
|
|
1204
|
+
result = ArrayBuffer.isView(val);
|
|
1844
1205
|
} else {
|
|
1845
|
-
|
|
1846
|
-
"Request failed with status code " + response.status,
|
|
1847
|
-
response.config,
|
|
1848
|
-
null,
|
|
1849
|
-
response.request,
|
|
1850
|
-
response
|
|
1851
|
-
));
|
|
1206
|
+
result = val && val.buffer && val.buffer instanceof ArrayBuffer;
|
|
1852
1207
|
}
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
)
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1208
|
+
return result;
|
|
1209
|
+
}
|
|
1210
|
+
function isString(val) {
|
|
1211
|
+
return typeof val === "string";
|
|
1212
|
+
}
|
|
1213
|
+
function isNumber(val) {
|
|
1214
|
+
return typeof val === "number";
|
|
1215
|
+
}
|
|
1216
|
+
function isObject(val) {
|
|
1217
|
+
return val !== null && typeof val === "object";
|
|
1218
|
+
}
|
|
1219
|
+
function isPlainObject(val) {
|
|
1220
|
+
if (toString.call(val) !== "[object Object]") {
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1223
|
+
var prototype = Object.getPrototypeOf(val);
|
|
1224
|
+
return prototype === null || prototype === Object.prototype;
|
|
1225
|
+
}
|
|
1226
|
+
function isDate(val) {
|
|
1227
|
+
return toString.call(val) === "[object Date]";
|
|
1228
|
+
}
|
|
1229
|
+
function isFile(val) {
|
|
1230
|
+
return toString.call(val) === "[object File]";
|
|
1231
|
+
}
|
|
1232
|
+
function isBlob(val) {
|
|
1233
|
+
return toString.call(val) === "[object Blob]";
|
|
1234
|
+
}
|
|
1235
|
+
function isFunction(val) {
|
|
1236
|
+
return toString.call(val) === "[object Function]";
|
|
1237
|
+
}
|
|
1238
|
+
function isStream(val) {
|
|
1239
|
+
return isObject(val) && isFunction(val.pipe);
|
|
1240
|
+
}
|
|
1241
|
+
function isURLSearchParams(val) {
|
|
1242
|
+
return typeof URLSearchParams !== "undefined" && val instanceof URLSearchParams;
|
|
1243
|
+
}
|
|
1244
|
+
function trim(str) {
|
|
1245
|
+
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, "");
|
|
1246
|
+
}
|
|
1247
|
+
function isStandardBrowserEnv() {
|
|
1248
|
+
if (typeof navigator !== "undefined" && (navigator.product === "ReactNative" || navigator.product === "NativeScript" || navigator.product === "NS")) {
|
|
1249
|
+
return false;
|
|
1250
|
+
}
|
|
1251
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
1252
|
+
}
|
|
1253
|
+
function forEach(obj, fn) {
|
|
1254
|
+
if (obj === null || typeof obj === "undefined") {
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
if (typeof obj !== "object") {
|
|
1258
|
+
obj = [obj];
|
|
1259
|
+
}
|
|
1260
|
+
if (isArray(obj)) {
|
|
1261
|
+
for (var i = 0, l = obj.length; i < l; i++) {
|
|
1262
|
+
fn.call(null, obj[i], i, obj);
|
|
1263
|
+
}
|
|
1264
|
+
} else {
|
|
1265
|
+
for (var key in obj) {
|
|
1266
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1267
|
+
fn.call(null, obj[key], key, obj);
|
|
1902
1268
|
}
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
function merge() {
|
|
1273
|
+
var result = {};
|
|
1274
|
+
function assignValue(val, key) {
|
|
1275
|
+
if (isPlainObject(result[key]) && isPlainObject(val)) {
|
|
1276
|
+
result[key] = merge(result[key], val);
|
|
1277
|
+
} else if (isPlainObject(val)) {
|
|
1278
|
+
result[key] = merge({}, val);
|
|
1279
|
+
} else if (isArray(val)) {
|
|
1280
|
+
result[key] = val.slice();
|
|
1281
|
+
} else {
|
|
1282
|
+
result[key] = val;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
for (var i = 0, l = arguments.length; i < l; i++) {
|
|
1286
|
+
forEach(arguments[i], assignValue);
|
|
1287
|
+
}
|
|
1288
|
+
return result;
|
|
1289
|
+
}
|
|
1290
|
+
function extend(a, b, thisArg) {
|
|
1291
|
+
forEach(b, function assignValue(val, key) {
|
|
1292
|
+
if (thisArg && typeof val === "function") {
|
|
1293
|
+
a[key] = bind(val, thisArg);
|
|
1294
|
+
} else {
|
|
1295
|
+
a[key] = val;
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1298
|
+
return a;
|
|
1299
|
+
}
|
|
1300
|
+
function stripBOM(content) {
|
|
1301
|
+
if (content.charCodeAt(0) === 65279) {
|
|
1302
|
+
content = content.slice(1);
|
|
1303
|
+
}
|
|
1304
|
+
return content;
|
|
1305
|
+
}
|
|
1306
|
+
module2.exports = {
|
|
1307
|
+
isArray,
|
|
1308
|
+
isArrayBuffer,
|
|
1309
|
+
isBuffer,
|
|
1310
|
+
isFormData,
|
|
1311
|
+
isArrayBufferView,
|
|
1312
|
+
isString,
|
|
1313
|
+
isNumber,
|
|
1314
|
+
isObject,
|
|
1315
|
+
isPlainObject,
|
|
1316
|
+
isUndefined,
|
|
1317
|
+
isDate,
|
|
1318
|
+
isFile,
|
|
1319
|
+
isBlob,
|
|
1320
|
+
isFunction,
|
|
1321
|
+
isStream,
|
|
1322
|
+
isURLSearchParams,
|
|
1323
|
+
isStandardBrowserEnv,
|
|
1324
|
+
forEach,
|
|
1325
|
+
merge,
|
|
1326
|
+
extend,
|
|
1327
|
+
trim,
|
|
1328
|
+
stripBOM
|
|
1329
|
+
};
|
|
1906
1330
|
}
|
|
1907
1331
|
});
|
|
1908
1332
|
|
|
1909
|
-
// node_modules/axios/lib/helpers/
|
|
1910
|
-
var
|
|
1911
|
-
"node_modules/axios/lib/helpers/
|
|
1333
|
+
// node_modules/axios/lib/helpers/buildURL.js
|
|
1334
|
+
var require_buildURL = __commonJS({
|
|
1335
|
+
"node_modules/axios/lib/helpers/buildURL.js"(exports2, module2) {
|
|
1912
1336
|
"use strict";
|
|
1913
|
-
|
|
1914
|
-
|
|
1337
|
+
var utils = require_utils();
|
|
1338
|
+
function encode(val) {
|
|
1339
|
+
return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+").replace(/%5B/gi, "[").replace(/%5D/gi, "]");
|
|
1340
|
+
}
|
|
1341
|
+
module2.exports = function buildURL(url, params, paramsSerializer) {
|
|
1342
|
+
if (!params) {
|
|
1343
|
+
return url;
|
|
1344
|
+
}
|
|
1345
|
+
var serializedParams;
|
|
1346
|
+
if (paramsSerializer) {
|
|
1347
|
+
serializedParams = paramsSerializer(params);
|
|
1348
|
+
} else if (utils.isURLSearchParams(params)) {
|
|
1349
|
+
serializedParams = params.toString();
|
|
1350
|
+
} else {
|
|
1351
|
+
var parts = [];
|
|
1352
|
+
utils.forEach(params, function serialize(val, key) {
|
|
1353
|
+
if (val === null || typeof val === "undefined") {
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
if (utils.isArray(val)) {
|
|
1357
|
+
key = key + "[]";
|
|
1358
|
+
} else {
|
|
1359
|
+
val = [val];
|
|
1360
|
+
}
|
|
1361
|
+
utils.forEach(val, function parseValue(v) {
|
|
1362
|
+
if (utils.isDate(v)) {
|
|
1363
|
+
v = v.toISOString();
|
|
1364
|
+
} else if (utils.isObject(v)) {
|
|
1365
|
+
v = JSON.stringify(v);
|
|
1366
|
+
}
|
|
1367
|
+
parts.push(encode(key) + "=" + encode(v));
|
|
1368
|
+
});
|
|
1369
|
+
});
|
|
1370
|
+
serializedParams = parts.join("&");
|
|
1371
|
+
}
|
|
1372
|
+
if (serializedParams) {
|
|
1373
|
+
var hashmarkIndex = url.indexOf("#");
|
|
1374
|
+
if (hashmarkIndex !== -1) {
|
|
1375
|
+
url = url.slice(0, hashmarkIndex);
|
|
1376
|
+
}
|
|
1377
|
+
url += (url.indexOf("?") === -1 ? "?" : "&") + serializedParams;
|
|
1378
|
+
}
|
|
1379
|
+
return url;
|
|
1915
1380
|
};
|
|
1916
1381
|
}
|
|
1917
1382
|
});
|
|
1918
1383
|
|
|
1919
|
-
// node_modules/axios/lib/
|
|
1920
|
-
var
|
|
1921
|
-
"node_modules/axios/lib/
|
|
1384
|
+
// node_modules/axios/lib/core/InterceptorManager.js
|
|
1385
|
+
var require_InterceptorManager = __commonJS({
|
|
1386
|
+
"node_modules/axios/lib/core/InterceptorManager.js"(exports2, module2) {
|
|
1922
1387
|
"use strict";
|
|
1923
|
-
|
|
1924
|
-
|
|
1388
|
+
var utils = require_utils();
|
|
1389
|
+
function InterceptorManager() {
|
|
1390
|
+
this.handlers = [];
|
|
1391
|
+
}
|
|
1392
|
+
InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
|
|
1393
|
+
this.handlers.push({
|
|
1394
|
+
fulfilled,
|
|
1395
|
+
rejected,
|
|
1396
|
+
synchronous: options ? options.synchronous : false,
|
|
1397
|
+
runWhen: options ? options.runWhen : null
|
|
1398
|
+
});
|
|
1399
|
+
return this.handlers.length - 1;
|
|
1400
|
+
};
|
|
1401
|
+
InterceptorManager.prototype.eject = function eject(id) {
|
|
1402
|
+
if (this.handlers[id]) {
|
|
1403
|
+
this.handlers[id] = null;
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
InterceptorManager.prototype.forEach = function forEach(fn) {
|
|
1407
|
+
utils.forEach(this.handlers, function forEachHandler(h) {
|
|
1408
|
+
if (h !== null) {
|
|
1409
|
+
fn(h);
|
|
1410
|
+
}
|
|
1411
|
+
});
|
|
1925
1412
|
};
|
|
1413
|
+
module2.exports = InterceptorManager;
|
|
1926
1414
|
}
|
|
1927
1415
|
});
|
|
1928
1416
|
|
|
1929
|
-
// node_modules/axios/lib/
|
|
1930
|
-
var
|
|
1931
|
-
"node_modules/axios/lib/
|
|
1417
|
+
// node_modules/axios/lib/helpers/normalizeHeaderName.js
|
|
1418
|
+
var require_normalizeHeaderName = __commonJS({
|
|
1419
|
+
"node_modules/axios/lib/helpers/normalizeHeaderName.js"(exports2, module2) {
|
|
1932
1420
|
"use strict";
|
|
1933
|
-
var
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1421
|
+
var utils = require_utils();
|
|
1422
|
+
module2.exports = function normalizeHeaderName(headers, normalizedName) {
|
|
1423
|
+
utils.forEach(headers, function processHeader(value, name) {
|
|
1424
|
+
if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
|
|
1425
|
+
headers[normalizedName] = value;
|
|
1426
|
+
delete headers[name];
|
|
1427
|
+
}
|
|
1428
|
+
});
|
|
1940
1429
|
};
|
|
1941
1430
|
}
|
|
1942
1431
|
});
|
|
1943
1432
|
|
|
1944
|
-
// node_modules/axios/lib/
|
|
1945
|
-
var
|
|
1946
|
-
"node_modules/axios/lib/
|
|
1433
|
+
// node_modules/axios/lib/core/enhanceError.js
|
|
1434
|
+
var require_enhanceError = __commonJS({
|
|
1435
|
+
"node_modules/axios/lib/core/enhanceError.js"(exports2, module2) {
|
|
1947
1436
|
"use strict";
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1437
|
+
module2.exports = function enhanceError(error, config, code, request, response) {
|
|
1438
|
+
error.config = config;
|
|
1439
|
+
if (code) {
|
|
1440
|
+
error.code = code;
|
|
1441
|
+
}
|
|
1442
|
+
error.request = request;
|
|
1443
|
+
error.response = response;
|
|
1444
|
+
error.isAxiosError = true;
|
|
1445
|
+
error.toJSON = function toJSON() {
|
|
1446
|
+
return {
|
|
1447
|
+
// Standard
|
|
1448
|
+
message: this.message,
|
|
1449
|
+
name: this.name,
|
|
1450
|
+
// Microsoft
|
|
1451
|
+
description: this.description,
|
|
1452
|
+
number: this.number,
|
|
1453
|
+
// Mozilla
|
|
1454
|
+
fileName: this.fileName,
|
|
1455
|
+
lineNumber: this.lineNumber,
|
|
1456
|
+
columnNumber: this.columnNumber,
|
|
1457
|
+
stack: this.stack,
|
|
1458
|
+
// Axios
|
|
1459
|
+
config: this.config,
|
|
1460
|
+
code: this.code
|
|
1461
|
+
};
|
|
1462
|
+
};
|
|
1463
|
+
return error;
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
});
|
|
1467
|
+
|
|
1468
|
+
// node_modules/axios/lib/core/createError.js
|
|
1469
|
+
var require_createError = __commonJS({
|
|
1470
|
+
"node_modules/axios/lib/core/createError.js"(exports2, module2) {
|
|
1471
|
+
"use strict";
|
|
1472
|
+
var enhanceError = require_enhanceError();
|
|
1473
|
+
module2.exports = function createError(message, config, code, request, response) {
|
|
1474
|
+
var error = new Error(message);
|
|
1475
|
+
return enhanceError(error, config, code, request, response);
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
|
|
1480
|
+
// node_modules/axios/lib/core/settle.js
|
|
1481
|
+
var require_settle = __commonJS({
|
|
1482
|
+
"node_modules/axios/lib/core/settle.js"(exports2, module2) {
|
|
1483
|
+
"use strict";
|
|
1484
|
+
var createError = require_createError();
|
|
1485
|
+
module2.exports = function settle(resolve, reject, response) {
|
|
1486
|
+
var validateStatus = response.config.validateStatus;
|
|
1487
|
+
if (!response.status || !validateStatus || validateStatus(response.status)) {
|
|
1488
|
+
resolve(response);
|
|
1489
|
+
} else {
|
|
1490
|
+
reject(createError(
|
|
1491
|
+
"Request failed with status code " + response.status,
|
|
1492
|
+
response.config,
|
|
1493
|
+
null,
|
|
1494
|
+
response.request,
|
|
1495
|
+
response
|
|
1496
|
+
));
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
});
|
|
1501
|
+
|
|
1502
|
+
// node_modules/axios/lib/helpers/cookies.js
|
|
1503
|
+
var require_cookies = __commonJS({
|
|
1504
|
+
"node_modules/axios/lib/helpers/cookies.js"(exports2, module2) {
|
|
1505
|
+
"use strict";
|
|
1506
|
+
var utils = require_utils();
|
|
1507
|
+
module2.exports = utils.isStandardBrowserEnv() ? (
|
|
1508
|
+
// Standard browser envs support document.cookie
|
|
1509
|
+
/* @__PURE__ */ (function standardBrowserEnv() {
|
|
1510
|
+
return {
|
|
1511
|
+
write: function write(name, value, expires, path, domain, secure) {
|
|
1512
|
+
var cookie = [];
|
|
1513
|
+
cookie.push(name + "=" + encodeURIComponent(value));
|
|
1514
|
+
if (utils.isNumber(expires)) {
|
|
1515
|
+
cookie.push("expires=" + new Date(expires).toGMTString());
|
|
1516
|
+
}
|
|
1517
|
+
if (utils.isString(path)) {
|
|
1518
|
+
cookie.push("path=" + path);
|
|
1519
|
+
}
|
|
1520
|
+
if (utils.isString(domain)) {
|
|
1521
|
+
cookie.push("domain=" + domain);
|
|
1522
|
+
}
|
|
1523
|
+
if (secure === true) {
|
|
1524
|
+
cookie.push("secure");
|
|
1525
|
+
}
|
|
1526
|
+
document.cookie = cookie.join("; ");
|
|
1527
|
+
},
|
|
1528
|
+
read: function read(name) {
|
|
1529
|
+
var match = document.cookie.match(new RegExp("(^|;\\s*)(" + name + ")=([^;]*)"));
|
|
1530
|
+
return match ? decodeURIComponent(match[3]) : null;
|
|
1531
|
+
},
|
|
1532
|
+
remove: function remove(name) {
|
|
1533
|
+
this.write(name, "", Date.now() - 864e5);
|
|
1534
|
+
}
|
|
1535
|
+
};
|
|
1536
|
+
})()
|
|
1537
|
+
) : (
|
|
1538
|
+
// Non standard browser env (web workers, react-native) lack needed support.
|
|
1539
|
+
/* @__PURE__ */ (function nonStandardBrowserEnv() {
|
|
1540
|
+
return {
|
|
1541
|
+
write: function write() {
|
|
1542
|
+
},
|
|
1543
|
+
read: function read() {
|
|
1544
|
+
return null;
|
|
1545
|
+
},
|
|
1546
|
+
remove: function remove() {
|
|
1547
|
+
}
|
|
1548
|
+
};
|
|
1549
|
+
})()
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1554
|
+
// node_modules/axios/lib/helpers/isAbsoluteURL.js
|
|
1555
|
+
var require_isAbsoluteURL = __commonJS({
|
|
1556
|
+
"node_modules/axios/lib/helpers/isAbsoluteURL.js"(exports2, module2) {
|
|
1557
|
+
"use strict";
|
|
1558
|
+
module2.exports = function isAbsoluteURL(url) {
|
|
1559
|
+
return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url);
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
});
|
|
1563
|
+
|
|
1564
|
+
// node_modules/axios/lib/helpers/combineURLs.js
|
|
1565
|
+
var require_combineURLs = __commonJS({
|
|
1566
|
+
"node_modules/axios/lib/helpers/combineURLs.js"(exports2, module2) {
|
|
1567
|
+
"use strict";
|
|
1568
|
+
module2.exports = function combineURLs(baseURL, relativeURL) {
|
|
1569
|
+
return relativeURL ? baseURL.replace(/\/+$/, "") + "/" + relativeURL.replace(/^\/+/, "") : baseURL;
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
|
|
1574
|
+
// node_modules/axios/lib/core/buildFullPath.js
|
|
1575
|
+
var require_buildFullPath = __commonJS({
|
|
1576
|
+
"node_modules/axios/lib/core/buildFullPath.js"(exports2, module2) {
|
|
1577
|
+
"use strict";
|
|
1578
|
+
var isAbsoluteURL = require_isAbsoluteURL();
|
|
1579
|
+
var combineURLs = require_combineURLs();
|
|
1580
|
+
module2.exports = function buildFullPath(baseURL, requestedURL) {
|
|
1581
|
+
if (baseURL && !isAbsoluteURL(requestedURL)) {
|
|
1582
|
+
return combineURLs(baseURL, requestedURL);
|
|
1583
|
+
}
|
|
1584
|
+
return requestedURL;
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1589
|
+
// node_modules/axios/lib/helpers/parseHeaders.js
|
|
1590
|
+
var require_parseHeaders = __commonJS({
|
|
1591
|
+
"node_modules/axios/lib/helpers/parseHeaders.js"(exports2, module2) {
|
|
1592
|
+
"use strict";
|
|
1593
|
+
var utils = require_utils();
|
|
1594
|
+
var ignoreDuplicateOf = [
|
|
1595
|
+
"age",
|
|
1596
|
+
"authorization",
|
|
1597
|
+
"content-length",
|
|
1598
|
+
"content-type",
|
|
1599
|
+
"etag",
|
|
1600
|
+
"expires",
|
|
1601
|
+
"from",
|
|
1602
|
+
"host",
|
|
1603
|
+
"if-modified-since",
|
|
1604
|
+
"if-unmodified-since",
|
|
1605
|
+
"last-modified",
|
|
1606
|
+
"location",
|
|
1607
|
+
"max-forwards",
|
|
1608
|
+
"proxy-authorization",
|
|
1609
|
+
"referer",
|
|
1610
|
+
"retry-after",
|
|
1611
|
+
"user-agent"
|
|
1967
1612
|
];
|
|
1968
1613
|
module2.exports = function parseHeaders(headers) {
|
|
1969
1614
|
var parsed = {};
|
|
@@ -1997,7 +1642,7 @@ var require_parseHeaders = __commonJS({
|
|
|
1997
1642
|
var require_isURLSameOrigin = __commonJS({
|
|
1998
1643
|
"node_modules/axios/lib/helpers/isURLSameOrigin.js"(exports2, module2) {
|
|
1999
1644
|
"use strict";
|
|
2000
|
-
var utils =
|
|
1645
|
+
var utils = require_utils();
|
|
2001
1646
|
module2.exports = utils.isStandardBrowserEnv() ? (
|
|
2002
1647
|
// Standard browser envs have full support of the APIs needed to test
|
|
2003
1648
|
// whether the request URL is of the same origin as current location.
|
|
@@ -2044,7 +1689,7 @@ var require_isURLSameOrigin = __commonJS({
|
|
|
2044
1689
|
var require_xhr = __commonJS({
|
|
2045
1690
|
"node_modules/axios/lib/adapters/xhr.js"(exports2, module2) {
|
|
2046
1691
|
"use strict";
|
|
2047
|
-
var utils =
|
|
1692
|
+
var utils = require_utils();
|
|
2048
1693
|
var settle = require_settle();
|
|
2049
1694
|
var cookies = require_cookies();
|
|
2050
1695
|
var buildURL = require_buildURL();
|
|
@@ -3549,7 +3194,7 @@ var require_package = __commonJS({
|
|
|
3549
3194
|
var require_http = __commonJS({
|
|
3550
3195
|
"node_modules/axios/lib/adapters/http.js"(exports2, module2) {
|
|
3551
3196
|
"use strict";
|
|
3552
|
-
var utils =
|
|
3197
|
+
var utils = require_utils();
|
|
3553
3198
|
var settle = require_settle();
|
|
3554
3199
|
var buildFullPath = require_buildFullPath();
|
|
3555
3200
|
var buildURL = require_buildURL();
|
|
@@ -3809,7 +3454,7 @@ var require_http = __commonJS({
|
|
|
3809
3454
|
var require_defaults = __commonJS({
|
|
3810
3455
|
"node_modules/axios/lib/defaults.js"(exports2, module2) {
|
|
3811
3456
|
"use strict";
|
|
3812
|
-
var utils =
|
|
3457
|
+
var utils = require_utils();
|
|
3813
3458
|
var normalizeHeaderName = require_normalizeHeaderName();
|
|
3814
3459
|
var enhanceError = require_enhanceError();
|
|
3815
3460
|
var DEFAULT_CONTENT_TYPE = {
|
|
@@ -3919,7 +3564,7 @@ var require_defaults = __commonJS({
|
|
|
3919
3564
|
var require_transformData = __commonJS({
|
|
3920
3565
|
"node_modules/axios/lib/core/transformData.js"(exports2, module2) {
|
|
3921
3566
|
"use strict";
|
|
3922
|
-
var utils =
|
|
3567
|
+
var utils = require_utils();
|
|
3923
3568
|
var defaults = require_defaults();
|
|
3924
3569
|
module2.exports = function transformData(data, headers, fns) {
|
|
3925
3570
|
var context = this || defaults;
|
|
@@ -3945,7 +3590,7 @@ var require_isCancel = __commonJS({
|
|
|
3945
3590
|
var require_dispatchRequest = __commonJS({
|
|
3946
3591
|
"node_modules/axios/lib/core/dispatchRequest.js"(exports2, module2) {
|
|
3947
3592
|
"use strict";
|
|
3948
|
-
var utils =
|
|
3593
|
+
var utils = require_utils();
|
|
3949
3594
|
var transformData = require_transformData();
|
|
3950
3595
|
var isCancel = require_isCancel();
|
|
3951
3596
|
var defaults = require_defaults();
|
|
@@ -4006,7 +3651,7 @@ var require_dispatchRequest = __commonJS({
|
|
|
4006
3651
|
var require_mergeConfig = __commonJS({
|
|
4007
3652
|
"node_modules/axios/lib/core/mergeConfig.js"(exports2, module2) {
|
|
4008
3653
|
"use strict";
|
|
4009
|
-
var utils =
|
|
3654
|
+
var utils = require_utils();
|
|
4010
3655
|
module2.exports = function mergeConfig(config1, config2) {
|
|
4011
3656
|
config2 = config2 || {};
|
|
4012
3657
|
var config = {};
|
|
@@ -4165,7 +3810,7 @@ var require_validator = __commonJS({
|
|
|
4165
3810
|
var require_Axios = __commonJS({
|
|
4166
3811
|
"node_modules/axios/lib/core/Axios.js"(exports2, module2) {
|
|
4167
3812
|
"use strict";
|
|
4168
|
-
var utils =
|
|
3813
|
+
var utils = require_utils();
|
|
4169
3814
|
var buildURL = require_buildURL();
|
|
4170
3815
|
var InterceptorManager = require_InterceptorManager();
|
|
4171
3816
|
var dispatchRequest = require_dispatchRequest();
|
|
@@ -4355,7 +4000,7 @@ var require_isAxiosError = __commonJS({
|
|
|
4355
4000
|
var require_axios = __commonJS({
|
|
4356
4001
|
"node_modules/axios/lib/axios.js"(exports2, module2) {
|
|
4357
4002
|
"use strict";
|
|
4358
|
-
var utils =
|
|
4003
|
+
var utils = require_utils();
|
|
4359
4004
|
var bind = require_bind();
|
|
4360
4005
|
var Axios = require_Axios();
|
|
4361
4006
|
var mergeConfig = require_mergeConfig();
|
|
@@ -5060,13 +4705,13 @@ var require_HeaderHostTransformer = __commonJS({
|
|
|
5060
4705
|
var require_TunnelCluster = __commonJS({
|
|
5061
4706
|
"node_modules/localtunnel/lib/TunnelCluster.js"(exports2, module2) {
|
|
5062
4707
|
"use strict";
|
|
5063
|
-
var { EventEmitter:
|
|
4708
|
+
var { EventEmitter: EventEmitter2 } = require("events");
|
|
5064
4709
|
var debug = require_src2()("localtunnel:client");
|
|
5065
4710
|
var fs = require("fs");
|
|
5066
4711
|
var net = require("net");
|
|
5067
4712
|
var tls = require("tls");
|
|
5068
4713
|
var HeaderHostTransformer = require_HeaderHostTransformer();
|
|
5069
|
-
module2.exports = class TunnelCluster extends
|
|
4714
|
+
module2.exports = class TunnelCluster extends EventEmitter2 {
|
|
5070
4715
|
constructor(opts = {}) {
|
|
5071
4716
|
super(opts);
|
|
5072
4717
|
this.opts = opts;
|
|
@@ -5138,1111 +4783,181 @@ var require_TunnelCluster = __commonJS({
|
|
|
5138
4783
|
});
|
|
5139
4784
|
local.once("connect", () => {
|
|
5140
4785
|
debug("connected locally");
|
|
5141
|
-
remote.resume();
|
|
5142
|
-
let stream = remote;
|
|
5143
|
-
if (opt.local_host) {
|
|
5144
|
-
debug("transform Host header to %s", opt.local_host);
|
|
5145
|
-
stream = remote.pipe(new HeaderHostTransformer({ host: opt.local_host }));
|
|
5146
|
-
}
|
|
5147
|
-
stream.pipe(local).pipe(remote);
|
|
5148
|
-
local.once("close", (hadError) => {
|
|
5149
|
-
debug("local connection closed [%s]", hadError);
|
|
5150
|
-
});
|
|
5151
|
-
});
|
|
5152
|
-
};
|
|
5153
|
-
remote.on("data", (data) => {
|
|
5154
|
-
const match = data.toString().match(/^(\w+) (\S+)/);
|
|
5155
|
-
if (match) {
|
|
5156
|
-
this.emit("request", {
|
|
5157
|
-
method: match[1],
|
|
5158
|
-
path: match[2]
|
|
5159
|
-
});
|
|
5160
|
-
}
|
|
5161
|
-
});
|
|
5162
|
-
remote.once("connect", () => {
|
|
5163
|
-
this.emit("open", remote);
|
|
5164
|
-
connLocal();
|
|
5165
|
-
});
|
|
5166
|
-
}
|
|
5167
|
-
};
|
|
5168
|
-
}
|
|
5169
|
-
});
|
|
5170
|
-
|
|
5171
|
-
// node_modules/localtunnel/lib/Tunnel.js
|
|
5172
|
-
var require_Tunnel = __commonJS({
|
|
5173
|
-
"node_modules/localtunnel/lib/Tunnel.js"(exports2, module2) {
|
|
5174
|
-
"use strict";
|
|
5175
|
-
var { parse } = require("url");
|
|
5176
|
-
var { EventEmitter: EventEmitter3 } = require("events");
|
|
5177
|
-
var axios = require_axios2();
|
|
5178
|
-
var debug = require_src2()("localtunnel:client");
|
|
5179
|
-
var TunnelCluster = require_TunnelCluster();
|
|
5180
|
-
module2.exports = class Tunnel extends EventEmitter3 {
|
|
5181
|
-
constructor(opts = {}) {
|
|
5182
|
-
super(opts);
|
|
5183
|
-
this.opts = opts;
|
|
5184
|
-
this.closed = false;
|
|
5185
|
-
if (!this.opts.host) {
|
|
5186
|
-
this.opts.host = "https://localtunnel.me";
|
|
5187
|
-
}
|
|
5188
|
-
}
|
|
5189
|
-
_getInfo(body) {
|
|
5190
|
-
const { id, ip, port, url, cached_url, max_conn_count } = body;
|
|
5191
|
-
const { host, port: local_port, local_host } = this.opts;
|
|
5192
|
-
const { local_https, local_cert, local_key, local_ca, allow_invalid_cert } = this.opts;
|
|
5193
|
-
return {
|
|
5194
|
-
name: id,
|
|
5195
|
-
url,
|
|
5196
|
-
cached_url,
|
|
5197
|
-
max_conn: max_conn_count || 1,
|
|
5198
|
-
remote_host: parse(host).hostname,
|
|
5199
|
-
remote_ip: ip,
|
|
5200
|
-
remote_port: port,
|
|
5201
|
-
local_port,
|
|
5202
|
-
local_host,
|
|
5203
|
-
local_https,
|
|
5204
|
-
local_cert,
|
|
5205
|
-
local_key,
|
|
5206
|
-
local_ca,
|
|
5207
|
-
allow_invalid_cert
|
|
5208
|
-
};
|
|
5209
|
-
}
|
|
5210
|
-
// initialize connection
|
|
5211
|
-
// callback with connection info
|
|
5212
|
-
_init(cb) {
|
|
5213
|
-
const opt = this.opts;
|
|
5214
|
-
const getInfo = this._getInfo.bind(this);
|
|
5215
|
-
const params = {
|
|
5216
|
-
responseType: "json"
|
|
5217
|
-
};
|
|
5218
|
-
const baseUri = `${opt.host}/`;
|
|
5219
|
-
const assignedDomain = opt.subdomain;
|
|
5220
|
-
const uri = baseUri + (assignedDomain || "?new");
|
|
5221
|
-
(function getUrl() {
|
|
5222
|
-
axios.get(uri, params).then((res) => {
|
|
5223
|
-
const body = res.data;
|
|
5224
|
-
debug("got tunnel information", res.data);
|
|
5225
|
-
if (res.status !== 200) {
|
|
5226
|
-
const err = new Error(
|
|
5227
|
-
body && body.message || "localtunnel server returned an error, please try again"
|
|
5228
|
-
);
|
|
5229
|
-
return cb(err);
|
|
5230
|
-
}
|
|
5231
|
-
cb(null, getInfo(body));
|
|
5232
|
-
}).catch((err) => {
|
|
5233
|
-
debug(`tunnel server offline: ${err.message}, retry 1s`);
|
|
5234
|
-
return setTimeout(getUrl, 1e3);
|
|
5235
|
-
});
|
|
5236
|
-
})();
|
|
5237
|
-
}
|
|
5238
|
-
_establish(info) {
|
|
5239
|
-
this.setMaxListeners(info.max_conn + (EventEmitter3.defaultMaxListeners || 10));
|
|
5240
|
-
this.tunnelCluster = new TunnelCluster(info);
|
|
5241
|
-
this.tunnelCluster.once("open", () => {
|
|
5242
|
-
this.emit("url", info.url);
|
|
5243
|
-
});
|
|
5244
|
-
this.tunnelCluster.on("error", (err) => {
|
|
5245
|
-
debug("got socket error", err.message);
|
|
5246
|
-
this.emit("error", err);
|
|
5247
|
-
});
|
|
5248
|
-
let tunnelCount = 0;
|
|
5249
|
-
this.tunnelCluster.on("open", (tunnel) => {
|
|
5250
|
-
tunnelCount++;
|
|
5251
|
-
debug("tunnel open [total: %d]", tunnelCount);
|
|
5252
|
-
const closeHandler = () => {
|
|
5253
|
-
tunnel.destroy();
|
|
5254
|
-
};
|
|
5255
|
-
if (this.closed) {
|
|
5256
|
-
return closeHandler();
|
|
5257
|
-
}
|
|
5258
|
-
this.once("close", closeHandler);
|
|
5259
|
-
tunnel.once("close", () => {
|
|
5260
|
-
this.removeListener("close", closeHandler);
|
|
5261
|
-
});
|
|
5262
|
-
});
|
|
5263
|
-
this.tunnelCluster.on("dead", () => {
|
|
5264
|
-
tunnelCount--;
|
|
5265
|
-
debug("tunnel dead [total: %d]", tunnelCount);
|
|
5266
|
-
if (this.closed) {
|
|
5267
|
-
return;
|
|
5268
|
-
}
|
|
5269
|
-
this.tunnelCluster.open();
|
|
5270
|
-
});
|
|
5271
|
-
this.tunnelCluster.on("request", (req) => {
|
|
5272
|
-
this.emit("request", req);
|
|
5273
|
-
});
|
|
5274
|
-
for (let count = 0; count < info.max_conn; ++count) {
|
|
5275
|
-
this.tunnelCluster.open();
|
|
5276
|
-
}
|
|
5277
|
-
}
|
|
5278
|
-
open(cb) {
|
|
5279
|
-
this._init((err, info) => {
|
|
5280
|
-
if (err) {
|
|
5281
|
-
return cb(err);
|
|
5282
|
-
}
|
|
5283
|
-
this.clientId = info.name;
|
|
5284
|
-
this.url = info.url;
|
|
5285
|
-
if (info.cached_url) {
|
|
5286
|
-
this.cachedUrl = info.cached_url;
|
|
5287
|
-
}
|
|
5288
|
-
this._establish(info);
|
|
5289
|
-
cb();
|
|
5290
|
-
});
|
|
5291
|
-
}
|
|
5292
|
-
close() {
|
|
5293
|
-
this.closed = true;
|
|
5294
|
-
this.emit("close");
|
|
5295
|
-
}
|
|
5296
|
-
};
|
|
5297
|
-
}
|
|
5298
|
-
});
|
|
5299
|
-
|
|
5300
|
-
// node_modules/localtunnel/localtunnel.js
|
|
5301
|
-
var require_localtunnel = __commonJS({
|
|
5302
|
-
"node_modules/localtunnel/localtunnel.js"(exports2, module2) {
|
|
5303
|
-
"use strict";
|
|
5304
|
-
var Tunnel = require_Tunnel();
|
|
5305
|
-
module2.exports = function localtunnel(arg1, arg2, arg3) {
|
|
5306
|
-
const options = typeof arg1 === "object" ? arg1 : { ...arg2, port: arg1 };
|
|
5307
|
-
const callback = typeof arg1 === "object" ? arg2 : arg3;
|
|
5308
|
-
const client = new Tunnel(options);
|
|
5309
|
-
if (callback) {
|
|
5310
|
-
client.open((err) => err ? callback(err) : callback(null, client));
|
|
5311
|
-
return client;
|
|
5312
|
-
}
|
|
5313
|
-
return new Promise(
|
|
5314
|
-
(resolve, reject) => client.open((err) => err ? reject(err) : resolve(client))
|
|
5315
|
-
);
|
|
5316
|
-
};
|
|
5317
|
-
}
|
|
5318
|
-
});
|
|
5319
|
-
|
|
5320
|
-
// src/tunnel.ts
|
|
5321
|
-
var import_node_child_process2, TunnelManager;
|
|
5322
|
-
var init_tunnel = __esm({
|
|
5323
|
-
"src/tunnel.ts"() {
|
|
5324
|
-
"use strict";
|
|
5325
|
-
import_node_child_process2 = require("child_process");
|
|
5326
|
-
TunnelManager = class {
|
|
5327
|
-
provider;
|
|
5328
|
-
process = null;
|
|
5329
|
-
url = null;
|
|
5330
|
-
tunnelInstance = null;
|
|
5331
|
-
constructor(provider) {
|
|
5332
|
-
this.provider = provider;
|
|
5333
|
-
}
|
|
5334
|
-
/**
|
|
5335
|
-
* Create tunnel and return public URL
|
|
5336
|
-
*/
|
|
5337
|
-
async create(port) {
|
|
5338
|
-
switch (this.provider) {
|
|
5339
|
-
case "localtunnel":
|
|
5340
|
-
return this.createLocaltunnel(port);
|
|
5341
|
-
case "cloudflared":
|
|
5342
|
-
return this.createCloudflared(port);
|
|
5343
|
-
case "ngrok":
|
|
5344
|
-
return this.createNgrok(port);
|
|
5345
|
-
default:
|
|
5346
|
-
throw new Error(`Unknown tunnel provider: ${this.provider}`);
|
|
5347
|
-
}
|
|
5348
|
-
}
|
|
5349
|
-
/**
|
|
5350
|
-
* Close tunnel
|
|
5351
|
-
*/
|
|
5352
|
-
async close() {
|
|
5353
|
-
if (this.tunnelInstance?.close) {
|
|
5354
|
-
this.tunnelInstance.close();
|
|
5355
|
-
this.tunnelInstance = null;
|
|
5356
|
-
}
|
|
5357
|
-
if (this.process) {
|
|
5358
|
-
this.process.kill();
|
|
5359
|
-
this.process = null;
|
|
5360
|
-
}
|
|
5361
|
-
this.url = null;
|
|
5362
|
-
}
|
|
5363
|
-
/**
|
|
5364
|
-
* Get tunnel URL
|
|
5365
|
-
*/
|
|
5366
|
-
getUrl() {
|
|
5367
|
-
return this.url;
|
|
5368
|
-
}
|
|
5369
|
-
/**
|
|
5370
|
-
* Create localtunnel
|
|
5371
|
-
*/
|
|
5372
|
-
async createLocaltunnel(port) {
|
|
5373
|
-
try {
|
|
5374
|
-
const localtunnel = await Promise.resolve().then(() => __toESM(require_localtunnel(), 1));
|
|
5375
|
-
const tunnel = await localtunnel.default({ port });
|
|
5376
|
-
this.tunnelInstance = tunnel;
|
|
5377
|
-
this.url = tunnel.url;
|
|
5378
|
-
tunnel.on("close", () => {
|
|
5379
|
-
this.url = null;
|
|
5380
|
-
});
|
|
5381
|
-
return tunnel.url;
|
|
5382
|
-
} catch {
|
|
5383
|
-
return this.createLocaltunnelCli(port);
|
|
5384
|
-
}
|
|
5385
|
-
}
|
|
5386
|
-
/**
|
|
5387
|
-
* Create localtunnel via CLI
|
|
5388
|
-
*/
|
|
5389
|
-
createLocaltunnelCli(port) {
|
|
5390
|
-
return new Promise((resolve, reject) => {
|
|
5391
|
-
this.process = (0, import_node_child_process2.spawn)("npx", ["localtunnel", "--port", port.toString(), "--print-requests", "false"], {
|
|
5392
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
5393
|
-
shell: true
|
|
5394
|
-
});
|
|
5395
|
-
let output = "";
|
|
5396
|
-
const timeout = setTimeout(() => {
|
|
5397
|
-
reject(new Error("Localtunnel timeout"));
|
|
5398
|
-
}, 3e4);
|
|
5399
|
-
this.process.stdout?.on("data", (data) => {
|
|
5400
|
-
output += data.toString();
|
|
5401
|
-
const match = output.match(/your url is:\s*(https?:\/\/[^\s]+)/i);
|
|
5402
|
-
if (match) {
|
|
5403
|
-
clearTimeout(timeout);
|
|
5404
|
-
this.url = match[1];
|
|
5405
|
-
resolve(match[1]);
|
|
5406
|
-
}
|
|
5407
|
-
});
|
|
5408
|
-
this.process.stderr?.on("data", () => {
|
|
5409
|
-
});
|
|
5410
|
-
this.process.on("error", (error) => {
|
|
5411
|
-
clearTimeout(timeout);
|
|
5412
|
-
reject(error);
|
|
5413
|
-
});
|
|
5414
|
-
this.process.on("exit", (code) => {
|
|
5415
|
-
if (code !== 0 && !this.url) {
|
|
5416
|
-
clearTimeout(timeout);
|
|
5417
|
-
reject(new Error(`Localtunnel exited with code ${code}`));
|
|
5418
|
-
}
|
|
5419
|
-
});
|
|
5420
|
-
});
|
|
5421
|
-
}
|
|
5422
|
-
/**
|
|
5423
|
-
* Create cloudflared tunnel
|
|
5424
|
-
*/
|
|
5425
|
-
createCloudflared(port) {
|
|
5426
|
-
return new Promise((resolve, reject) => {
|
|
5427
|
-
this.process = (0, import_node_child_process2.spawn)(
|
|
5428
|
-
"cloudflared",
|
|
5429
|
-
["tunnel", "--url", `http://localhost:${port}`, "--metrics", "localhost:0"],
|
|
5430
|
-
{
|
|
5431
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
5432
|
-
}
|
|
5433
|
-
);
|
|
5434
|
-
let output = "";
|
|
5435
|
-
const timeout = setTimeout(() => {
|
|
5436
|
-
reject(new Error("Cloudflared timeout"));
|
|
5437
|
-
}, 3e4);
|
|
5438
|
-
const handleData = (data) => {
|
|
5439
|
-
output += data.toString();
|
|
5440
|
-
const match = output.match(/(https:\/\/[^\s]+\.trycloudflare\.com)/i);
|
|
5441
|
-
if (match) {
|
|
5442
|
-
clearTimeout(timeout);
|
|
5443
|
-
this.url = match[1];
|
|
5444
|
-
resolve(match[1]);
|
|
5445
|
-
}
|
|
5446
|
-
};
|
|
5447
|
-
this.process.stdout?.on("data", handleData);
|
|
5448
|
-
this.process.stderr?.on("data", handleData);
|
|
5449
|
-
this.process.on("error", (error) => {
|
|
5450
|
-
clearTimeout(timeout);
|
|
5451
|
-
reject(error);
|
|
5452
|
-
});
|
|
5453
|
-
this.process.on("exit", (code) => {
|
|
5454
|
-
if (code !== 0 && !this.url) {
|
|
5455
|
-
clearTimeout(timeout);
|
|
5456
|
-
reject(new Error(`Cloudflared exited with code ${code}`));
|
|
5457
|
-
}
|
|
5458
|
-
});
|
|
5459
|
-
});
|
|
5460
|
-
}
|
|
5461
|
-
/**
|
|
5462
|
-
* Create ngrok tunnel
|
|
5463
|
-
*/
|
|
5464
|
-
createNgrok(port) {
|
|
5465
|
-
return new Promise((resolve, reject) => {
|
|
5466
|
-
this.process = (0, import_node_child_process2.spawn)("ngrok", ["http", port.toString(), "--log=stdout", "--log-level=info"], {
|
|
5467
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
5468
|
-
});
|
|
5469
|
-
let output = "";
|
|
5470
|
-
const timeout = setTimeout(() => {
|
|
5471
|
-
reject(new Error("Ngrok timeout"));
|
|
5472
|
-
}, 3e4);
|
|
5473
|
-
this.process.stdout?.on("data", (data) => {
|
|
5474
|
-
output += data.toString();
|
|
5475
|
-
const match = output.match(/url=(https?:\/\/[^\s]+)/i);
|
|
5476
|
-
if (match) {
|
|
5477
|
-
clearTimeout(timeout);
|
|
5478
|
-
this.url = match[1];
|
|
5479
|
-
resolve(match[1]);
|
|
5480
|
-
}
|
|
5481
|
-
});
|
|
5482
|
-
this.process.stderr?.on("data", () => {
|
|
5483
|
-
});
|
|
5484
|
-
this.process.on("error", (error) => {
|
|
5485
|
-
clearTimeout(timeout);
|
|
5486
|
-
reject(error);
|
|
5487
|
-
});
|
|
5488
|
-
this.process.on("exit", (code) => {
|
|
5489
|
-
if (code !== 0 && !this.url) {
|
|
5490
|
-
clearTimeout(timeout);
|
|
5491
|
-
reject(new Error(`Ngrok exited with code ${code}`));
|
|
5492
|
-
}
|
|
5493
|
-
});
|
|
5494
|
-
});
|
|
5495
|
-
}
|
|
5496
|
-
};
|
|
5497
|
-
}
|
|
5498
|
-
});
|
|
5499
|
-
|
|
5500
|
-
// src/web-client.ts
|
|
5501
|
-
function getWebClient() {
|
|
5502
|
-
return `<!DOCTYPE html>
|
|
5503
|
-
<html lang="en">
|
|
5504
|
-
<head>
|
|
5505
|
-
<meta charset="UTF-8">
|
|
5506
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
|
5507
|
-
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
5508
|
-
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
5509
|
-
<title>NikCLI Remote</title>
|
|
5510
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
|
|
5511
|
-
<style>
|
|
5512
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
5513
|
-
:root {
|
|
5514
|
-
--bg-primary: #0d1117;
|
|
5515
|
-
--bg-secondary: #161b22;
|
|
5516
|
-
--accent: #58a6ff;
|
|
5517
|
-
--success: #3fb950;
|
|
5518
|
-
--border: #30363d;
|
|
5519
|
-
}
|
|
5520
|
-
html, body { height: 100%; overflow: hidden; touch-action: manipulation; }
|
|
5521
|
-
body {
|
|
5522
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
5523
|
-
background: var(--bg-primary);
|
|
5524
|
-
color: #e6edf3;
|
|
5525
|
-
display: flex;
|
|
5526
|
-
flex-direction: column;
|
|
5527
|
-
}
|
|
5528
|
-
#terminal { flex: 1; overflow: hidden; background: var(--bg-primary); padding: 8px; }
|
|
5529
|
-
#input-area {
|
|
5530
|
-
background: var(--bg-secondary);
|
|
5531
|
-
border-top: 1px solid var(--border);
|
|
5532
|
-
padding: 12px 16px;
|
|
5533
|
-
flex-shrink: 0;
|
|
5534
|
-
padding-bottom: env(safe-area-inset-bottom, 12px);
|
|
5535
|
-
}
|
|
5536
|
-
.input-row { display: flex; gap: 8px; align-items: center; }
|
|
5537
|
-
.prompt { color: var(--success); font-family: 'SF Mono', Monaco, monospace; font-size: 14px; white-space: nowrap; }
|
|
5538
|
-
#cmd-input {
|
|
5539
|
-
flex: 1;
|
|
5540
|
-
background: #21262d;
|
|
5541
|
-
border: 1px solid var(--border);
|
|
5542
|
-
border-radius: 12px;
|
|
5543
|
-
padding: 12px 16px;
|
|
5544
|
-
color: #e6edf3;
|
|
5545
|
-
font-size: 16px;
|
|
5546
|
-
font-family: 'SF Mono', Monaco, monospace;
|
|
5547
|
-
outline: none;
|
|
5548
|
-
-webkit-appearance: none;
|
|
5549
|
-
}
|
|
5550
|
-
#cmd-input:focus { border-color: var(--accent); }
|
|
5551
|
-
#send-btn {
|
|
5552
|
-
background: var(--accent);
|
|
5553
|
-
color: white;
|
|
5554
|
-
border: none;
|
|
5555
|
-
border-radius: 12px;
|
|
5556
|
-
padding: 12px 24px;
|
|
5557
|
-
font-size: 16px;
|
|
5558
|
-
font-weight: 600;
|
|
5559
|
-
cursor: pointer;
|
|
5560
|
-
-webkit-tap-highlight-color: transparent;
|
|
5561
|
-
}
|
|
5562
|
-
#send-btn:active { opacity: 0.7; }
|
|
5563
|
-
#status-bar {
|
|
5564
|
-
background: var(--bg-secondary);
|
|
5565
|
-
border-bottom: 1px solid var(--border);
|
|
5566
|
-
padding: 8px 16px;
|
|
5567
|
-
display: flex;
|
|
5568
|
-
justify-content: space-between;
|
|
5569
|
-
align-items: center;
|
|
5570
|
-
font-size: 12px;
|
|
5571
|
-
padding-top: env(safe-area-inset-top, 8px);
|
|
5572
|
-
}
|
|
5573
|
-
.status-row { display: flex; align-items: center; gap: 8px; }
|
|
5574
|
-
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: #8b949e; }
|
|
5575
|
-
.status-dot.connected { background: var(--success); box-shadow: 0 0 8px var(--success); }
|
|
5576
|
-
.status-dot.connecting { background: var(--accent); animation: pulse 1s infinite; }
|
|
5577
|
-
.status-dot.disconnected { background: #f85149; }
|
|
5578
|
-
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
|
|
5579
|
-
#auth-overlay {
|
|
5580
|
-
position: fixed; inset: 0; background: var(--bg-primary);
|
|
5581
|
-
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
5582
|
-
padding: 20px; z-index: 100;
|
|
5583
|
-
}
|
|
5584
|
-
#auth-overlay.hidden { display: none; }
|
|
5585
|
-
.auth-title { font-size: 28px; font-weight: 700; margin-bottom: 8px; }
|
|
5586
|
-
.auth-subtitle { color: #8b949e; font-size: 16px; margin-bottom: 24px; }
|
|
5587
|
-
.auth-msg {
|
|
5588
|
-
background: var(--bg-secondary); padding: 20px 28px;
|
|
5589
|
-
border-radius: 16px; border: 1px solid var(--border); text-align: center;
|
|
5590
|
-
}
|
|
5591
|
-
.auth-msg.error { color: #f85149; border-color: #f85149; }
|
|
5592
|
-
.quick-btns {
|
|
5593
|
-
display: flex; gap: 8px; margin-top: 20px; flex-wrap: wrap; justify-content: center;
|
|
5594
|
-
}
|
|
5595
|
-
.quick-btn {
|
|
5596
|
-
background: #21262d; border: 1px solid var(--border); color: #e6edf3;
|
|
5597
|
-
padding: 10px 16px; border-radius: 8px; font-size: 14px;
|
|
5598
|
-
font-family: 'SF Mono', Monaco, monospace; cursor: pointer;
|
|
5599
|
-
}
|
|
5600
|
-
.quick-btn:active { background: #30363d; }
|
|
5601
|
-
.hint { font-size: 12px; color: #8b949e; margin-top: 12px; }
|
|
5602
|
-
@media (max-width: 600px) {
|
|
5603
|
-
#input-area { padding: 10px 12px; }
|
|
5604
|
-
.quick-btn { padding: 8px 12px; font-size: 12px; }
|
|
5605
|
-
}
|
|
5606
|
-
</style>
|
|
5607
|
-
</head>
|
|
5608
|
-
<body>
|
|
5609
|
-
<div id="auth-overlay">
|
|
5610
|
-
<div class="auth-title">\u{1F4F1} NikCLI Remote</div>
|
|
5611
|
-
<div class="auth-subtitle">Full terminal emulation</div>
|
|
5612
|
-
<div id="auth-msg" class="auth-msg">
|
|
5613
|
-
<div id="auth-text">Connecting...</div>
|
|
5614
|
-
</div>
|
|
5615
|
-
<div class="quick-btns">
|
|
5616
|
-
<button class="quick-btn" onclick="send('help')">/help</button>
|
|
5617
|
-
<button class="quick-btn" onclick="send('ls -la')">ls -la</button>
|
|
5618
|
-
<button class="quick-btn" onclick="send('pwd')">pwd</button>
|
|
5619
|
-
<button class="quick-btn" onclick="send('whoami')">whoami</button>
|
|
5620
|
-
<button class="quick-btn" onclick="send('clear')">clear</button>
|
|
5621
|
-
</div>
|
|
5622
|
-
<div class="hint">Mobile keyboard to type commands</div>
|
|
5623
|
-
</div>
|
|
5624
|
-
|
|
5625
|
-
<div id="status-bar">
|
|
5626
|
-
<div class="status-row">
|
|
5627
|
-
<span class="status-dot" id="status-dot"></span>
|
|
5628
|
-
<span id="status-text">Disconnected</span>
|
|
5629
|
-
</div>
|
|
5630
|
-
<span id="session-id" style="color: #8b949e;"></span>
|
|
5631
|
-
</div>
|
|
5632
|
-
|
|
5633
|
-
<div id="terminal"></div>
|
|
5634
|
-
|
|
5635
|
-
<div id="input-area">
|
|
5636
|
-
<form class="input-row" onsubmit="return handleSubmit(event)">
|
|
5637
|
-
<span class="prompt">$</span>
|
|
5638
|
-
<input type="text" id="cmd-input" placeholder="Type command..." autocomplete="off" enterkeyhint="send" inputmode="text">
|
|
5639
|
-
<button type="submit" id="send-btn">Send</button>
|
|
5640
|
-
</form>
|
|
5641
|
-
</div>
|
|
5642
|
-
|
|
5643
|
-
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script>
|
|
5644
|
-
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
|
|
5645
|
-
<script>
|
|
5646
|
-
let ws = null, term = null, fitAddon = null, connected = false, reconnectAttempts = 0;
|
|
5647
|
-
const token = new URLSearchParams(location.search).get('t') || '';
|
|
5648
|
-
const sessionId = new URLSearchParams(location.search).get('s') || '';
|
|
5649
|
-
|
|
5650
|
-
const authOverlay = document.getElementById('auth-overlay');
|
|
5651
|
-
const authMsg = document.getElementById('auth-msg');
|
|
5652
|
-
const authText = document.getElementById('auth-text');
|
|
5653
|
-
const statusDot = document.getElementById('status-dot');
|
|
5654
|
-
const statusText = document.getElementById('status-text');
|
|
5655
|
-
const sessionSpan = document.getElementById('session-id');
|
|
5656
|
-
const cmdInput = document.getElementById('cmd-input');
|
|
5657
|
-
|
|
5658
|
-
// Initialize xterm.js
|
|
5659
|
-
term = new Terminal({
|
|
5660
|
-
cursorBlink: true,
|
|
5661
|
-
fontSize: 14,
|
|
5662
|
-
fontFamily: '"SF Mono", Monaco, Consolas, monospace',
|
|
5663
|
-
theme: {
|
|
5664
|
-
background: '#0d1117',
|
|
5665
|
-
foreground: '#e6edf3',
|
|
5666
|
-
cursor: '#3fb950',
|
|
5667
|
-
selectionBackground: '#264f78',
|
|
5668
|
-
black: '#484f58',
|
|
5669
|
-
red: '#f85149',
|
|
5670
|
-
green: '#3fb950',
|
|
5671
|
-
yellow: '#d29922',
|
|
5672
|
-
blue: '#58a6ff',
|
|
5673
|
-
magenta: '#a371f7',
|
|
5674
|
-
cyan: '#39c5cf',
|
|
5675
|
-
white: '#e6edf3',
|
|
5676
|
-
brightBlack: '#6e7681',
|
|
5677
|
-
brightRed: '#ffa198',
|
|
5678
|
-
brightGreen: '#7ee787',
|
|
5679
|
-
brightYellow: '#f0883e',
|
|
5680
|
-
brightBlue: '#79c0ff',
|
|
5681
|
-
brightMagenta: '#d2a8ff',
|
|
5682
|
-
brightCyan: '#56d4db',
|
|
5683
|
-
brightWhite: '#f0f6fc'
|
|
5684
|
-
},
|
|
5685
|
-
convertEol: true
|
|
5686
|
-
});
|
|
5687
|
-
|
|
5688
|
-
fitAddon = new FitAddon.FitAddon();
|
|
5689
|
-
term.loadAddon(fitAddon);
|
|
5690
|
-
term.open(document.getElementById('terminal'));
|
|
5691
|
-
fitAddon.fit();
|
|
5692
|
-
term.writeln('Initializing NikCLI Remote...');
|
|
5693
|
-
term.writeln('Type commands below');
|
|
5694
|
-
|
|
5695
|
-
// Resize handler
|
|
5696
|
-
window.addEventListener('resize', () => {
|
|
5697
|
-
clearTimeout(window.resizeTimer);
|
|
5698
|
-
window.resizeTimer = setTimeout(() => fitAddon.fit(), 100);
|
|
5699
|
-
});
|
|
5700
|
-
|
|
5701
|
-
// Visual viewport for mobile keyboard
|
|
5702
|
-
if (window.visualViewport) {
|
|
5703
|
-
window.visualViewport.addEventListener('resize', () => {
|
|
5704
|
-
clearTimeout(window.resizeTimer);
|
|
5705
|
-
window.resizeTimer = setTimeout(() => fitAddon.fit(), 100);
|
|
5706
|
-
});
|
|
5707
|
-
}
|
|
5708
|
-
|
|
5709
|
-
function connect() {
|
|
5710
|
-
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
5711
|
-
ws = new WebSocket(protocol + '//' + location.host + '/ws');
|
|
5712
|
-
|
|
5713
|
-
ws.onopen = () => {
|
|
5714
|
-
setStatus('connecting', 'Authenticating...');
|
|
5715
|
-
ws.send(JSON.stringify({ type: 'auth', token }));
|
|
5716
|
-
reconnectAttempts = 0;
|
|
5717
|
-
};
|
|
5718
|
-
|
|
5719
|
-
ws.onmessage = (e) => {
|
|
5720
|
-
try { handleMessage(JSON.parse(e.data)); } catch (err) { console.error(err); }
|
|
5721
|
-
};
|
|
5722
|
-
|
|
5723
|
-
ws.onclose = () => {
|
|
5724
|
-
setStatus('disconnected', 'Disconnected');
|
|
5725
|
-
connected = false;
|
|
5726
|
-
reconnectAttempts++;
|
|
5727
|
-
setTimeout(connect, Math.min(3000, reconnectAttempts * 500));
|
|
5728
|
-
};
|
|
5729
|
-
|
|
5730
|
-
ws.onerror = () => setStatus('disconnected', 'Connection error');
|
|
5731
|
-
}
|
|
5732
|
-
|
|
5733
|
-
function handleMessage(msg) {
|
|
5734
|
-
switch (msg.type) {
|
|
5735
|
-
case 'auth:required':
|
|
5736
|
-
ws.send(JSON.stringify({ type: 'auth', token }));
|
|
5737
|
-
break;
|
|
5738
|
-
case 'auth:success':
|
|
5739
|
-
connected = true;
|
|
5740
|
-
authOverlay.classList.add('hidden');
|
|
5741
|
-
setStatus('connected', 'Connected');
|
|
5742
|
-
sessionSpan.textContent = sessionId ? 'Session: ' + sessionId : '';
|
|
5743
|
-
term.writeln('\u2713 Connected to NikCLI');
|
|
5744
|
-
break;
|
|
5745
|
-
case 'auth:failed':
|
|
5746
|
-
authMsg.classList.add('error');
|
|
5747
|
-
authText.textContent = 'Authentication failed';
|
|
5748
|
-
break;
|
|
5749
|
-
case 'terminal:output':
|
|
5750
|
-
if (msg.payload?.data) term.write(msg.payload.data);
|
|
5751
|
-
break;
|
|
5752
|
-
case 'terminal:exit':
|
|
5753
|
-
term.writeln('Process exited: ' + (msg.payload?.code || 0) + '');
|
|
5754
|
-
break;
|
|
5755
|
-
}
|
|
5756
|
-
}
|
|
5757
|
-
|
|
5758
|
-
function setStatus(state, text) {
|
|
5759
|
-
statusDot.className = 'status-dot ' + state;
|
|
5760
|
-
statusText.textContent = text;
|
|
5761
|
-
}
|
|
5762
|
-
|
|
5763
|
-
function handleSubmit(e) {
|
|
5764
|
-
if (e) e.preventDefault();
|
|
5765
|
-
const value = cmdInput.value.trim();
|
|
5766
|
-
if (!value || !connected) return;
|
|
5767
|
-
cmdInput.value = '';
|
|
5768
|
-
term.write('$ ' + value );
|
|
5769
|
-
ws.send(JSON.stringify({ type: 'terminal:input', data: value + '\r' }));
|
|
5770
|
-
setTimeout(() => cmdInput.focus(), 50);
|
|
5771
|
-
return false;
|
|
5772
|
-
}
|
|
5773
|
-
|
|
5774
|
-
function send(cmd) {
|
|
5775
|
-
if (!connected) return;
|
|
5776
|
-
term.write('$ ' + cmd + );
|
|
5777
|
-
ws.send(JSON.stringify({ type: 'terminal:input', data: cmd + '\r' }));
|
|
5778
|
-
}
|
|
5779
|
-
|
|
5780
|
-
cmdInput.addEventListener('keydown', (e) => {
|
|
5781
|
-
if (e.key === 'Enter' && !e.shiftKey) {
|
|
5782
|
-
e.preventDefault();
|
|
5783
|
-
handleSubmit();
|
|
5784
|
-
}
|
|
5785
|
-
});
|
|
5786
|
-
|
|
5787
|
-
document.getElementById('terminal')?.addEventListener('click', () => {
|
|
5788
|
-
if (connected) cmdInput.focus();
|
|
5789
|
-
});
|
|
5790
|
-
|
|
5791
|
-
connect();
|
|
5792
|
-
</script>
|
|
5793
|
-
</body>
|
|
5794
|
-
</html>`;
|
|
5795
|
-
}
|
|
5796
|
-
var init_web_client = __esm({
|
|
5797
|
-
"src/web-client.ts"() {
|
|
5798
|
-
"use strict";
|
|
5799
|
-
}
|
|
5800
|
-
});
|
|
5801
|
-
|
|
5802
|
-
// src/server.ts
|
|
5803
|
-
var server_exports = {};
|
|
5804
|
-
__export(server_exports, {
|
|
5805
|
-
RemoteServer: () => RemoteServer
|
|
5806
|
-
});
|
|
5807
|
-
var import_node_events2, import_node_http, import_ws, import_node_crypto, import_node_os, RemoteServer;
|
|
5808
|
-
var init_server = __esm({
|
|
5809
|
-
"src/server.ts"() {
|
|
5810
|
-
"use strict";
|
|
5811
|
-
import_node_events2 = require("events");
|
|
5812
|
-
import_node_http = require("http");
|
|
5813
|
-
import_ws = require("ws");
|
|
5814
|
-
import_node_crypto = __toESM(require("crypto"), 1);
|
|
5815
|
-
import_node_os = __toESM(require("os"), 1);
|
|
5816
|
-
init_types();
|
|
5817
|
-
init_terminal();
|
|
5818
|
-
init_tunnel();
|
|
5819
|
-
init_web_client();
|
|
5820
|
-
RemoteServer = class extends import_node_events2.EventEmitter {
|
|
5821
|
-
config;
|
|
5822
|
-
httpServer = null;
|
|
5823
|
-
wss = null;
|
|
5824
|
-
clients = /* @__PURE__ */ new Map();
|
|
5825
|
-
session = null;
|
|
5826
|
-
terminal = null;
|
|
5827
|
-
tunnel = null;
|
|
5828
|
-
heartbeatTimer = null;
|
|
5829
|
-
sessionTimeoutTimer = null;
|
|
5830
|
-
isRunning = false;
|
|
5831
|
-
sessionSecret;
|
|
5832
|
-
constructor(config = {}) {
|
|
5833
|
-
super();
|
|
5834
|
-
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
5835
|
-
this.sessionSecret = config.sessionSecret || this.generateSecret();
|
|
5836
|
-
}
|
|
5837
|
-
/**
|
|
5838
|
-
* Start the remote server
|
|
5839
|
-
*/
|
|
5840
|
-
async start(options = {}) {
|
|
5841
|
-
if (this.isRunning) {
|
|
5842
|
-
throw new Error("Server already running");
|
|
5843
|
-
}
|
|
5844
|
-
const sessionId = this.generateSessionId();
|
|
5845
|
-
this.httpServer = (0, import_node_http.createServer)((req, res) => this.handleHttpRequest(req, res));
|
|
5846
|
-
this.wss = new import_ws.WebSocketServer({ server: this.httpServer });
|
|
5847
|
-
this.setupWebSocketHandlers();
|
|
5848
|
-
const port = await new Promise((resolve, reject) => {
|
|
5849
|
-
this.httpServer.listen(this.config.port, this.config.host, () => {
|
|
5850
|
-
const addr = this.httpServer.address();
|
|
5851
|
-
resolve(typeof addr === "object" ? addr?.port || 0 : 0);
|
|
5852
|
-
});
|
|
5853
|
-
this.httpServer.on("error", reject);
|
|
5854
|
-
});
|
|
5855
|
-
const localIp = this.getLocalIP();
|
|
5856
|
-
const localUrl = `http://${localIp}:${port}`;
|
|
5857
|
-
this.session = {
|
|
5858
|
-
id: sessionId,
|
|
5859
|
-
name: options.name || `nikcli-${sessionId}`,
|
|
5860
|
-
qrCode: "",
|
|
5861
|
-
qrUrl: localUrl,
|
|
5862
|
-
localUrl,
|
|
5863
|
-
status: "starting",
|
|
5864
|
-
connectedDevices: [],
|
|
5865
|
-
startedAt: /* @__PURE__ */ new Date(),
|
|
5866
|
-
lastActivity: /* @__PURE__ */ new Date(),
|
|
5867
|
-
port
|
|
5868
|
-
};
|
|
5869
|
-
if (this.config.enableTunnel && this.config.tunnelProvider !== "none") {
|
|
5870
|
-
try {
|
|
5871
|
-
this.tunnel = new TunnelManager(this.config.tunnelProvider);
|
|
5872
|
-
const tunnelUrl = await this.tunnel.create(port);
|
|
5873
|
-
this.session.tunnelUrl = tunnelUrl;
|
|
5874
|
-
this.session.qrUrl = `${tunnelUrl}?s=${sessionId}&t=${this.sessionSecret}`;
|
|
5875
|
-
this.emit("tunnel:connected", tunnelUrl);
|
|
5876
|
-
} catch (error) {
|
|
5877
|
-
this.emit("tunnel:error", error);
|
|
5878
|
-
this.session.qrUrl = `${localUrl}?s=${sessionId}&t=${this.sessionSecret}`;
|
|
5879
|
-
}
|
|
5880
|
-
} else {
|
|
5881
|
-
this.session.qrUrl = `${localUrl}?s=${sessionId}&t=${this.sessionSecret}`;
|
|
5882
|
-
}
|
|
5883
|
-
if (this.config.enableTerminal) {
|
|
5884
|
-
this.terminal = new TerminalManager({
|
|
5885
|
-
shell: this.config.shell,
|
|
5886
|
-
cols: this.config.cols,
|
|
5887
|
-
rows: this.config.rows,
|
|
5888
|
-
cwd: this.config.cwd,
|
|
5889
|
-
env: this.config.env
|
|
5890
|
-
});
|
|
5891
|
-
this.terminal.on("data", (data) => {
|
|
5892
|
-
this.broadcast({ type: MessageTypes.TERMINAL_OUTPUT, payload: { data } });
|
|
5893
|
-
this.emit("terminal:output", data);
|
|
5894
|
-
});
|
|
5895
|
-
this.terminal.on("exit", (code) => {
|
|
5896
|
-
this.broadcast({ type: MessageTypes.TERMINAL_EXIT, payload: { code } });
|
|
5897
|
-
});
|
|
5898
|
-
}
|
|
5899
|
-
this.startHeartbeat();
|
|
5900
|
-
if (this.config.sessionTimeout > 0) {
|
|
5901
|
-
this.startSessionTimeout();
|
|
5902
|
-
}
|
|
5903
|
-
this.session.status = "waiting";
|
|
5904
|
-
this.isRunning = true;
|
|
5905
|
-
this.emit("started", this.session);
|
|
5906
|
-
return this.session;
|
|
5907
|
-
}
|
|
5908
|
-
/**
|
|
5909
|
-
* Stop the server
|
|
5910
|
-
*/
|
|
5911
|
-
async stop() {
|
|
5912
|
-
if (!this.isRunning) return;
|
|
5913
|
-
this.isRunning = false;
|
|
5914
|
-
if (this.heartbeatTimer) {
|
|
5915
|
-
clearInterval(this.heartbeatTimer);
|
|
5916
|
-
this.heartbeatTimer = null;
|
|
5917
|
-
}
|
|
5918
|
-
if (this.sessionTimeoutTimer) {
|
|
5919
|
-
clearTimeout(this.sessionTimeoutTimer);
|
|
5920
|
-
this.sessionTimeoutTimer = null;
|
|
5921
|
-
}
|
|
5922
|
-
this.broadcast({ type: MessageTypes.SESSION_END, payload: {} });
|
|
5923
|
-
for (const client of this.clients.values()) {
|
|
5924
|
-
client.ws.close(1e3, "Server shutting down");
|
|
5925
|
-
}
|
|
5926
|
-
this.clients.clear();
|
|
5927
|
-
if (this.terminal) {
|
|
5928
|
-
this.terminal.destroy();
|
|
5929
|
-
this.terminal = null;
|
|
5930
|
-
}
|
|
5931
|
-
if (this.tunnel) {
|
|
5932
|
-
await this.tunnel.close();
|
|
5933
|
-
this.tunnel = null;
|
|
5934
|
-
}
|
|
5935
|
-
if (this.wss) {
|
|
5936
|
-
this.wss.close();
|
|
5937
|
-
this.wss = null;
|
|
5938
|
-
}
|
|
5939
|
-
if (this.httpServer) {
|
|
5940
|
-
await new Promise((resolve) => {
|
|
5941
|
-
this.httpServer.close(() => resolve());
|
|
5942
|
-
});
|
|
5943
|
-
this.httpServer = null;
|
|
5944
|
-
}
|
|
5945
|
-
if (this.session) {
|
|
5946
|
-
this.session.status = "stopped";
|
|
5947
|
-
}
|
|
5948
|
-
this.emit("stopped");
|
|
5949
|
-
}
|
|
5950
|
-
/**
|
|
5951
|
-
* Broadcast message to all authenticated clients
|
|
5952
|
-
*/
|
|
5953
|
-
broadcast(message) {
|
|
5954
|
-
const data = JSON.stringify({
|
|
5955
|
-
type: message.type,
|
|
5956
|
-
payload: message.payload,
|
|
5957
|
-
timestamp: message.timestamp || Date.now()
|
|
5958
|
-
});
|
|
5959
|
-
for (const client of this.clients.values()) {
|
|
5960
|
-
if (client.authenticated && client.ws.readyState === import_ws.WebSocket.OPEN) {
|
|
5961
|
-
client.ws.send(data);
|
|
5962
|
-
}
|
|
5963
|
-
}
|
|
5964
|
-
}
|
|
5965
|
-
/**
|
|
5966
|
-
* Send notification to clients
|
|
5967
|
-
*/
|
|
5968
|
-
notify(notification) {
|
|
5969
|
-
this.broadcast({
|
|
5970
|
-
type: MessageTypes.NOTIFICATION,
|
|
5971
|
-
payload: notification
|
|
5972
|
-
});
|
|
5973
|
-
}
|
|
5974
|
-
/**
|
|
5975
|
-
* Get current session
|
|
5976
|
-
*/
|
|
5977
|
-
getSession() {
|
|
5978
|
-
return this.session;
|
|
5979
|
-
}
|
|
5980
|
-
/**
|
|
5981
|
-
* Check if server is running
|
|
5982
|
-
*/
|
|
5983
|
-
isActive() {
|
|
5984
|
-
return this.isRunning && this.session?.status !== "stopped";
|
|
5985
|
-
}
|
|
5986
|
-
/**
|
|
5987
|
-
* Get connected client count
|
|
5988
|
-
*/
|
|
5989
|
-
getConnectedCount() {
|
|
5990
|
-
let count = 0;
|
|
5991
|
-
for (const client of this.clients.values()) {
|
|
5992
|
-
if (client.authenticated) count++;
|
|
5993
|
-
}
|
|
5994
|
-
return count;
|
|
5995
|
-
}
|
|
5996
|
-
/**
|
|
5997
|
-
* Write to terminal
|
|
5998
|
-
*/
|
|
5999
|
-
writeToTerminal(data) {
|
|
6000
|
-
this.terminal?.write(data);
|
|
6001
|
-
}
|
|
6002
|
-
/**
|
|
6003
|
-
* Resize terminal
|
|
6004
|
-
*/
|
|
6005
|
-
resizeTerminal(cols, rows) {
|
|
6006
|
-
this.terminal?.resize(cols, rows);
|
|
6007
|
-
}
|
|
6008
|
-
/**
|
|
6009
|
-
* Setup WebSocket handlers
|
|
6010
|
-
*/
|
|
6011
|
-
setupWebSocketHandlers() {
|
|
6012
|
-
this.wss.on("connection", (ws, req) => {
|
|
6013
|
-
const clientId = this.generateClientId();
|
|
6014
|
-
const client = {
|
|
6015
|
-
id: clientId,
|
|
6016
|
-
ws,
|
|
6017
|
-
authenticated: false,
|
|
6018
|
-
device: {
|
|
6019
|
-
id: clientId,
|
|
6020
|
-
userAgent: req.headers["user-agent"],
|
|
6021
|
-
ip: req.socket.remoteAddress,
|
|
6022
|
-
connectedAt: /* @__PURE__ */ new Date(),
|
|
6023
|
-
lastActivity: /* @__PURE__ */ new Date()
|
|
6024
|
-
},
|
|
6025
|
-
lastPing: Date.now()
|
|
6026
|
-
};
|
|
6027
|
-
if (this.clients.size >= this.config.maxConnections) {
|
|
6028
|
-
ws.close(1013, "Max connections reached");
|
|
6029
|
-
return;
|
|
6030
|
-
}
|
|
6031
|
-
this.clients.set(clientId, client);
|
|
6032
|
-
ws.send(JSON.stringify({ type: MessageTypes.AUTH_REQUIRED, timestamp: Date.now() }));
|
|
6033
|
-
ws.on("message", (data) => {
|
|
6034
|
-
try {
|
|
6035
|
-
const message = JSON.parse(data.toString());
|
|
6036
|
-
this.handleClientMessage(client, message);
|
|
6037
|
-
} catch {
|
|
6038
|
-
}
|
|
6039
|
-
});
|
|
6040
|
-
ws.on("close", () => {
|
|
6041
|
-
this.clients.delete(clientId);
|
|
6042
|
-
if (this.session && client.authenticated) {
|
|
6043
|
-
this.session.connectedDevices = this.session.connectedDevices.filter(
|
|
6044
|
-
(d) => d.id !== clientId
|
|
6045
|
-
);
|
|
6046
|
-
if (this.session.connectedDevices.length === 0) {
|
|
6047
|
-
this.session.status = "waiting";
|
|
6048
|
-
}
|
|
6049
|
-
this.emit("client:disconnected", client.device);
|
|
6050
|
-
}
|
|
6051
|
-
});
|
|
6052
|
-
ws.on("error", (error) => {
|
|
6053
|
-
this.emit("client:error", clientId, error);
|
|
6054
|
-
});
|
|
6055
|
-
ws.on("pong", () => {
|
|
6056
|
-
client.lastPing = Date.now();
|
|
6057
|
-
});
|
|
6058
|
-
});
|
|
6059
|
-
}
|
|
6060
|
-
/**
|
|
6061
|
-
* Handle client message
|
|
6062
|
-
*/
|
|
6063
|
-
handleClientMessage(client, message) {
|
|
6064
|
-
client.device.lastActivity = /* @__PURE__ */ new Date();
|
|
6065
|
-
if (this.session) {
|
|
6066
|
-
this.session.lastActivity = /* @__PURE__ */ new Date();
|
|
6067
|
-
}
|
|
6068
|
-
if (this.config.sessionTimeout > 0) {
|
|
6069
|
-
this.resetSessionTimeout();
|
|
6070
|
-
}
|
|
6071
|
-
switch (message.type) {
|
|
6072
|
-
case MessageTypes.AUTH:
|
|
6073
|
-
this.handleAuth(client, message.token);
|
|
6074
|
-
break;
|
|
6075
|
-
case MessageTypes.TERMINAL_INPUT:
|
|
6076
|
-
if (client.authenticated && message.data) {
|
|
6077
|
-
this.terminal?.write(message.data);
|
|
6078
|
-
}
|
|
6079
|
-
break;
|
|
6080
|
-
case MessageTypes.TERMINAL_RESIZE:
|
|
6081
|
-
if (client.authenticated && message.cols && message.rows) {
|
|
6082
|
-
this.terminal?.resize(message.cols, message.rows);
|
|
6083
|
-
}
|
|
6084
|
-
break;
|
|
6085
|
-
case MessageTypes.TERMINAL_CLEAR:
|
|
6086
|
-
if (client.authenticated) {
|
|
6087
|
-
this.terminal?.clear();
|
|
6088
|
-
}
|
|
6089
|
-
break;
|
|
6090
|
-
case MessageTypes.PING:
|
|
6091
|
-
client.ws.send(JSON.stringify({ type: MessageTypes.PONG, timestamp: Date.now() }));
|
|
6092
|
-
break;
|
|
6093
|
-
case MessageTypes.COMMAND:
|
|
6094
|
-
if (client.authenticated) {
|
|
6095
|
-
this.emit("command", {
|
|
6096
|
-
clientId: client.id,
|
|
6097
|
-
command: message.command,
|
|
6098
|
-
args: message.args
|
|
6099
|
-
});
|
|
6100
|
-
}
|
|
6101
|
-
break;
|
|
6102
|
-
default:
|
|
6103
|
-
this.emit("message", client, message);
|
|
6104
|
-
}
|
|
6105
|
-
}
|
|
6106
|
-
/**
|
|
6107
|
-
* Handle authentication
|
|
6108
|
-
*/
|
|
6109
|
-
handleAuth(client, token) {
|
|
6110
|
-
if (token === this.sessionSecret) {
|
|
6111
|
-
client.authenticated = true;
|
|
6112
|
-
if (this.session) {
|
|
6113
|
-
this.session.connectedDevices.push(client.device);
|
|
6114
|
-
this.session.status = "connected";
|
|
6115
|
-
}
|
|
6116
|
-
client.ws.send(
|
|
6117
|
-
JSON.stringify({
|
|
6118
|
-
type: MessageTypes.AUTH_SUCCESS,
|
|
6119
|
-
payload: {
|
|
6120
|
-
sessionId: this.session?.id,
|
|
6121
|
-
terminalEnabled: this.config.enableTerminal
|
|
6122
|
-
},
|
|
6123
|
-
timestamp: Date.now()
|
|
6124
|
-
})
|
|
6125
|
-
);
|
|
6126
|
-
if (this.config.enableTerminal && !this.terminal?.isRunning()) {
|
|
6127
|
-
this.terminal?.start();
|
|
6128
|
-
}
|
|
6129
|
-
this.emit("client:connected", client.device);
|
|
6130
|
-
} else {
|
|
6131
|
-
client.ws.send(JSON.stringify({ type: MessageTypes.AUTH_FAILED, timestamp: Date.now() }));
|
|
6132
|
-
setTimeout(() => client.ws.close(1008, "Authentication failed"), 100);
|
|
6133
|
-
}
|
|
6134
|
-
}
|
|
6135
|
-
/**
|
|
6136
|
-
* Handle HTTP request
|
|
6137
|
-
*/
|
|
6138
|
-
handleHttpRequest(req, res) {
|
|
6139
|
-
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
6140
|
-
const path = url.pathname;
|
|
6141
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
6142
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
6143
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
6144
|
-
if (req.method === "OPTIONS") {
|
|
6145
|
-
res.writeHead(204);
|
|
6146
|
-
res.end();
|
|
6147
|
-
return;
|
|
6148
|
-
}
|
|
6149
|
-
if (path === "/" || path === "/index.html") {
|
|
6150
|
-
res.writeHead(200, {
|
|
6151
|
-
"Content-Type": "text/html; charset=utf-8",
|
|
6152
|
-
"Content-Security-Policy": "default-src 'self' 'unsafe-inline' 'unsafe-eval' https: data: ws: wss:"
|
|
6153
|
-
});
|
|
6154
|
-
res.end(getWebClient());
|
|
6155
|
-
return;
|
|
6156
|
-
}
|
|
6157
|
-
if (path === "/health") {
|
|
6158
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6159
|
-
res.end(JSON.stringify({ status: "ok", session: this.session?.id }));
|
|
6160
|
-
return;
|
|
6161
|
-
}
|
|
6162
|
-
if (path === "/api/session") {
|
|
6163
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6164
|
-
res.end(
|
|
6165
|
-
JSON.stringify({
|
|
6166
|
-
id: this.session?.id,
|
|
6167
|
-
name: this.session?.name,
|
|
6168
|
-
status: this.session?.status,
|
|
6169
|
-
connectedDevices: this.session?.connectedDevices.length
|
|
6170
|
-
})
|
|
6171
|
-
);
|
|
6172
|
-
return;
|
|
6173
|
-
}
|
|
6174
|
-
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
6175
|
-
res.end("Not Found");
|
|
6176
|
-
}
|
|
6177
|
-
/**
|
|
6178
|
-
* Start heartbeat
|
|
6179
|
-
*/
|
|
6180
|
-
startHeartbeat() {
|
|
6181
|
-
this.heartbeatTimer = setInterval(() => {
|
|
6182
|
-
const now = Date.now();
|
|
6183
|
-
for (const [id, client] of this.clients) {
|
|
6184
|
-
if (now - client.lastPing > this.config.heartbeatInterval * 2) {
|
|
6185
|
-
client.ws.terminate();
|
|
6186
|
-
this.clients.delete(id);
|
|
6187
|
-
} else if (client.ws.readyState === import_ws.WebSocket.OPEN) {
|
|
6188
|
-
client.ws.ping();
|
|
6189
|
-
}
|
|
6190
|
-
}
|
|
6191
|
-
}, this.config.heartbeatInterval);
|
|
6192
|
-
}
|
|
6193
|
-
/**
|
|
6194
|
-
* Start session timeout
|
|
6195
|
-
*/
|
|
6196
|
-
startSessionTimeout() {
|
|
6197
|
-
this.sessionTimeoutTimer = setTimeout(() => {
|
|
6198
|
-
if (this.session?.connectedDevices.length === 0) {
|
|
6199
|
-
this.stop();
|
|
4786
|
+
remote.resume();
|
|
4787
|
+
let stream = remote;
|
|
4788
|
+
if (opt.local_host) {
|
|
4789
|
+
debug("transform Host header to %s", opt.local_host);
|
|
4790
|
+
stream = remote.pipe(new HeaderHostTransformer({ host: opt.local_host }));
|
|
4791
|
+
}
|
|
4792
|
+
stream.pipe(local).pipe(remote);
|
|
4793
|
+
local.once("close", (hadError) => {
|
|
4794
|
+
debug("local connection closed [%s]", hadError);
|
|
4795
|
+
});
|
|
4796
|
+
});
|
|
4797
|
+
};
|
|
4798
|
+
remote.on("data", (data) => {
|
|
4799
|
+
const match = data.toString().match(/^(\w+) (\S+)/);
|
|
4800
|
+
if (match) {
|
|
4801
|
+
this.emit("request", {
|
|
4802
|
+
method: match[1],
|
|
4803
|
+
path: match[2]
|
|
4804
|
+
});
|
|
6200
4805
|
}
|
|
6201
|
-
}
|
|
4806
|
+
});
|
|
4807
|
+
remote.once("connect", () => {
|
|
4808
|
+
this.emit("open", remote);
|
|
4809
|
+
connLocal();
|
|
4810
|
+
});
|
|
6202
4811
|
}
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
4812
|
+
};
|
|
4813
|
+
}
|
|
4814
|
+
});
|
|
4815
|
+
|
|
4816
|
+
// node_modules/localtunnel/lib/Tunnel.js
|
|
4817
|
+
var require_Tunnel = __commonJS({
|
|
4818
|
+
"node_modules/localtunnel/lib/Tunnel.js"(exports2, module2) {
|
|
4819
|
+
"use strict";
|
|
4820
|
+
var { parse } = require("url");
|
|
4821
|
+
var { EventEmitter: EventEmitter2 } = require("events");
|
|
4822
|
+
var axios = require_axios2();
|
|
4823
|
+
var debug = require_src2()("localtunnel:client");
|
|
4824
|
+
var TunnelCluster = require_TunnelCluster();
|
|
4825
|
+
module2.exports = class Tunnel extends EventEmitter2 {
|
|
4826
|
+
constructor(opts = {}) {
|
|
4827
|
+
super(opts);
|
|
4828
|
+
this.opts = opts;
|
|
4829
|
+
this.closed = false;
|
|
4830
|
+
if (!this.opts.host) {
|
|
4831
|
+
this.opts.host = "https://localtunnel.me";
|
|
6212
4832
|
}
|
|
6213
4833
|
}
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
4834
|
+
_getInfo(body) {
|
|
4835
|
+
const { id, ip, port, url, cached_url, max_conn_count } = body;
|
|
4836
|
+
const { host, port: local_port, local_host } = this.opts;
|
|
4837
|
+
const { local_https, local_cert, local_key, local_ca, allow_invalid_cert } = this.opts;
|
|
4838
|
+
return {
|
|
4839
|
+
name: id,
|
|
4840
|
+
url,
|
|
4841
|
+
cached_url,
|
|
4842
|
+
max_conn: max_conn_count || 1,
|
|
4843
|
+
remote_host: parse(host).hostname,
|
|
4844
|
+
remote_ip: ip,
|
|
4845
|
+
remote_port: port,
|
|
4846
|
+
local_port,
|
|
4847
|
+
local_host,
|
|
4848
|
+
local_https,
|
|
4849
|
+
local_cert,
|
|
4850
|
+
local_key,
|
|
4851
|
+
local_ca,
|
|
4852
|
+
allow_invalid_cert
|
|
4853
|
+
};
|
|
4854
|
+
}
|
|
4855
|
+
// initialize connection
|
|
4856
|
+
// callback with connection info
|
|
4857
|
+
_init(cb) {
|
|
4858
|
+
const opt = this.opts;
|
|
4859
|
+
const getInfo = this._getInfo.bind(this);
|
|
4860
|
+
const params = {
|
|
4861
|
+
responseType: "json"
|
|
4862
|
+
};
|
|
4863
|
+
const baseUri = `${opt.host}/`;
|
|
4864
|
+
const assignedDomain = opt.subdomain;
|
|
4865
|
+
const uri = baseUri + (assignedDomain || "?new");
|
|
4866
|
+
(function getUrl() {
|
|
4867
|
+
axios.get(uri, params).then((res) => {
|
|
4868
|
+
const body = res.data;
|
|
4869
|
+
debug("got tunnel information", res.data);
|
|
4870
|
+
if (res.status !== 200) {
|
|
4871
|
+
const err = new Error(
|
|
4872
|
+
body && body.message || "localtunnel server returned an error, please try again"
|
|
4873
|
+
);
|
|
4874
|
+
return cb(err);
|
|
6223
4875
|
}
|
|
4876
|
+
cb(null, getInfo(body));
|
|
4877
|
+
}).catch((err) => {
|
|
4878
|
+
debug(`tunnel server offline: ${err.message}, retry 1s`);
|
|
4879
|
+
return setTimeout(getUrl, 1e3);
|
|
4880
|
+
});
|
|
4881
|
+
})();
|
|
4882
|
+
}
|
|
4883
|
+
_establish(info) {
|
|
4884
|
+
this.setMaxListeners(info.max_conn + (EventEmitter2.defaultMaxListeners || 10));
|
|
4885
|
+
this.tunnelCluster = new TunnelCluster(info);
|
|
4886
|
+
this.tunnelCluster.once("open", () => {
|
|
4887
|
+
this.emit("url", info.url);
|
|
4888
|
+
});
|
|
4889
|
+
this.tunnelCluster.on("error", (err) => {
|
|
4890
|
+
debug("got socket error", err.message);
|
|
4891
|
+
this.emit("error", err);
|
|
4892
|
+
});
|
|
4893
|
+
let tunnelCount = 0;
|
|
4894
|
+
this.tunnelCluster.on("open", (tunnel) => {
|
|
4895
|
+
tunnelCount++;
|
|
4896
|
+
debug("tunnel open [total: %d]", tunnelCount);
|
|
4897
|
+
const closeHandler = () => {
|
|
4898
|
+
tunnel.destroy();
|
|
4899
|
+
};
|
|
4900
|
+
if (this.closed) {
|
|
4901
|
+
return closeHandler();
|
|
4902
|
+
}
|
|
4903
|
+
this.once("close", closeHandler);
|
|
4904
|
+
tunnel.once("close", () => {
|
|
4905
|
+
this.removeListener("close", closeHandler);
|
|
4906
|
+
});
|
|
4907
|
+
});
|
|
4908
|
+
this.tunnelCluster.on("dead", () => {
|
|
4909
|
+
tunnelCount--;
|
|
4910
|
+
debug("tunnel dead [total: %d]", tunnelCount);
|
|
4911
|
+
if (this.closed) {
|
|
4912
|
+
return;
|
|
6224
4913
|
}
|
|
4914
|
+
this.tunnelCluster.open();
|
|
4915
|
+
});
|
|
4916
|
+
this.tunnelCluster.on("request", (req) => {
|
|
4917
|
+
this.emit("request", req);
|
|
4918
|
+
});
|
|
4919
|
+
for (let count = 0; count < info.max_conn; ++count) {
|
|
4920
|
+
this.tunnelCluster.open();
|
|
6225
4921
|
}
|
|
6226
|
-
return "127.0.0.1";
|
|
6227
4922
|
}
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
4923
|
+
open(cb) {
|
|
4924
|
+
this._init((err, info) => {
|
|
4925
|
+
if (err) {
|
|
4926
|
+
return cb(err);
|
|
4927
|
+
}
|
|
4928
|
+
this.clientId = info.name;
|
|
4929
|
+
this.url = info.url;
|
|
4930
|
+
if (info.cached_url) {
|
|
4931
|
+
this.cachedUrl = info.cached_url;
|
|
4932
|
+
}
|
|
4933
|
+
this._establish(info);
|
|
4934
|
+
cb();
|
|
4935
|
+
});
|
|
6233
4936
|
}
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
generateClientId() {
|
|
6238
|
-
return "c_" + import_node_crypto.default.randomBytes(4).toString("hex");
|
|
4937
|
+
close() {
|
|
4938
|
+
this.closed = true;
|
|
4939
|
+
this.emit("close");
|
|
6239
4940
|
}
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
4941
|
+
};
|
|
4942
|
+
}
|
|
4943
|
+
});
|
|
4944
|
+
|
|
4945
|
+
// node_modules/localtunnel/localtunnel.js
|
|
4946
|
+
var require_localtunnel = __commonJS({
|
|
4947
|
+
"node_modules/localtunnel/localtunnel.js"(exports2, module2) {
|
|
4948
|
+
"use strict";
|
|
4949
|
+
var Tunnel = require_Tunnel();
|
|
4950
|
+
module2.exports = function localtunnel(arg1, arg2, arg3) {
|
|
4951
|
+
const options = typeof arg1 === "object" ? arg1 : { ...arg2, port: arg1 };
|
|
4952
|
+
const callback = typeof arg1 === "object" ? arg2 : arg3;
|
|
4953
|
+
const client = new Tunnel(options);
|
|
4954
|
+
if (callback) {
|
|
4955
|
+
client.open((err) => err ? callback(err) : callback(null, client));
|
|
4956
|
+
return client;
|
|
6245
4957
|
}
|
|
4958
|
+
return new Promise(
|
|
4959
|
+
(resolve, reject) => client.open((err) => err ? reject(err) : resolve(client))
|
|
4960
|
+
);
|
|
6246
4961
|
};
|
|
6247
4962
|
}
|
|
6248
4963
|
});
|
|
@@ -6253,18 +4968,239 @@ __export(index_exports, {
|
|
|
6253
4968
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
|
|
6254
4969
|
MessageTypes: () => MessageTypes,
|
|
6255
4970
|
RemoteServer: () => RemoteServer,
|
|
6256
|
-
|
|
4971
|
+
TunnelManager: () => TunnelManager,
|
|
4972
|
+
checkTunnelAvailability: () => checkTunnelAvailability,
|
|
6257
4973
|
createRemoteServer: () => createRemoteServer,
|
|
4974
|
+
createTunnel: () => createTunnel,
|
|
4975
|
+
findAvailableTunnel: () => findAvailableTunnel,
|
|
6258
4976
|
getWebClient: () => getWebClient
|
|
6259
4977
|
});
|
|
6260
4978
|
module.exports = __toCommonJS(index_exports);
|
|
6261
4979
|
init_server();
|
|
6262
|
-
|
|
4980
|
+
|
|
4981
|
+
// src/tunnel.ts
|
|
4982
|
+
var import_node_child_process = require("child_process");
|
|
4983
|
+
async function createTunnel(port, provider = "cloudflared") {
|
|
4984
|
+
const manager = new TunnelManager(provider);
|
|
4985
|
+
const url = await manager.create(port);
|
|
4986
|
+
return {
|
|
4987
|
+
url,
|
|
4988
|
+
provider,
|
|
4989
|
+
close: () => manager.close()
|
|
4990
|
+
};
|
|
4991
|
+
}
|
|
4992
|
+
var TunnelManager = class {
|
|
4993
|
+
provider;
|
|
4994
|
+
process = null;
|
|
4995
|
+
url = null;
|
|
4996
|
+
tunnelInstance = null;
|
|
4997
|
+
constructor(provider) {
|
|
4998
|
+
this.provider = provider;
|
|
4999
|
+
}
|
|
5000
|
+
/**
|
|
5001
|
+
* Create tunnel and return public URL
|
|
5002
|
+
*/
|
|
5003
|
+
async create(port) {
|
|
5004
|
+
switch (this.provider) {
|
|
5005
|
+
case "localtunnel":
|
|
5006
|
+
return this.createLocaltunnel(port);
|
|
5007
|
+
case "cloudflared":
|
|
5008
|
+
return this.createCloudflared(port);
|
|
5009
|
+
case "ngrok":
|
|
5010
|
+
return this.createNgrok(port);
|
|
5011
|
+
default:
|
|
5012
|
+
throw new Error(`Unknown tunnel provider: ${this.provider}`);
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
5015
|
+
/**
|
|
5016
|
+
* Close tunnel
|
|
5017
|
+
*/
|
|
5018
|
+
async close() {
|
|
5019
|
+
if (this.tunnelInstance?.close) {
|
|
5020
|
+
this.tunnelInstance.close();
|
|
5021
|
+
this.tunnelInstance = null;
|
|
5022
|
+
}
|
|
5023
|
+
if (this.process) {
|
|
5024
|
+
this.process.kill();
|
|
5025
|
+
this.process = null;
|
|
5026
|
+
}
|
|
5027
|
+
this.url = null;
|
|
5028
|
+
}
|
|
5029
|
+
/**
|
|
5030
|
+
* Get tunnel URL
|
|
5031
|
+
*/
|
|
5032
|
+
getUrl() {
|
|
5033
|
+
return this.url;
|
|
5034
|
+
}
|
|
5035
|
+
/**
|
|
5036
|
+
* Create localtunnel
|
|
5037
|
+
*/
|
|
5038
|
+
async createLocaltunnel(port) {
|
|
5039
|
+
try {
|
|
5040
|
+
const localtunnel = await Promise.resolve().then(() => __toESM(require_localtunnel(), 1));
|
|
5041
|
+
const tunnel = await localtunnel.default({ port });
|
|
5042
|
+
this.tunnelInstance = tunnel;
|
|
5043
|
+
this.url = tunnel.url;
|
|
5044
|
+
tunnel.on("close", () => {
|
|
5045
|
+
this.url = null;
|
|
5046
|
+
});
|
|
5047
|
+
return tunnel.url;
|
|
5048
|
+
} catch {
|
|
5049
|
+
return this.createLocaltunnelCli(port);
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
5052
|
+
/**
|
|
5053
|
+
* Create localtunnel via CLI
|
|
5054
|
+
*/
|
|
5055
|
+
createLocaltunnelCli(port) {
|
|
5056
|
+
return new Promise((resolve, reject) => {
|
|
5057
|
+
this.process = (0, import_node_child_process.spawn)("npx", ["localtunnel", "--port", port.toString(), "--print-requests", "false"], {
|
|
5058
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
5059
|
+
shell: true
|
|
5060
|
+
});
|
|
5061
|
+
let output = "";
|
|
5062
|
+
const timeout = setTimeout(() => {
|
|
5063
|
+
reject(new Error("Localtunnel timeout"));
|
|
5064
|
+
}, 3e4);
|
|
5065
|
+
this.process.stdout?.on("data", (data) => {
|
|
5066
|
+
output += data.toString();
|
|
5067
|
+
const match = output.match(/your url is:\s*(https?:\/\/[^\s]+)/i);
|
|
5068
|
+
if (match) {
|
|
5069
|
+
clearTimeout(timeout);
|
|
5070
|
+
this.url = match[1];
|
|
5071
|
+
resolve(match[1]);
|
|
5072
|
+
}
|
|
5073
|
+
});
|
|
5074
|
+
this.process.stderr?.on("data", () => {
|
|
5075
|
+
});
|
|
5076
|
+
this.process.on("error", (error) => {
|
|
5077
|
+
clearTimeout(timeout);
|
|
5078
|
+
reject(error);
|
|
5079
|
+
});
|
|
5080
|
+
this.process.on("exit", (code) => {
|
|
5081
|
+
if (code !== 0 && !this.url) {
|
|
5082
|
+
clearTimeout(timeout);
|
|
5083
|
+
reject(new Error(`Localtunnel exited with code ${code}`));
|
|
5084
|
+
}
|
|
5085
|
+
});
|
|
5086
|
+
});
|
|
5087
|
+
}
|
|
5088
|
+
/**
|
|
5089
|
+
* Create cloudflared tunnel
|
|
5090
|
+
*/
|
|
5091
|
+
createCloudflared(port) {
|
|
5092
|
+
return new Promise((resolve, reject) => {
|
|
5093
|
+
this.process = (0, import_node_child_process.spawn)(
|
|
5094
|
+
"cloudflared",
|
|
5095
|
+
["tunnel", "--url", `http://localhost:${port}`, "--metrics", "localhost:0"],
|
|
5096
|
+
{
|
|
5097
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5098
|
+
}
|
|
5099
|
+
);
|
|
5100
|
+
let output = "";
|
|
5101
|
+
const timeout = setTimeout(() => {
|
|
5102
|
+
reject(new Error("Cloudflared timeout"));
|
|
5103
|
+
}, 3e4);
|
|
5104
|
+
const handleData = (data) => {
|
|
5105
|
+
output += data.toString();
|
|
5106
|
+
const match = output.match(/(https:\/\/[^\s]+\.trycloudflare\.com)/i);
|
|
5107
|
+
if (match) {
|
|
5108
|
+
clearTimeout(timeout);
|
|
5109
|
+
this.url = match[1];
|
|
5110
|
+
resolve(match[1]);
|
|
5111
|
+
}
|
|
5112
|
+
};
|
|
5113
|
+
this.process.stdout?.on("data", handleData);
|
|
5114
|
+
this.process.stderr?.on("data", handleData);
|
|
5115
|
+
this.process.on("error", (error) => {
|
|
5116
|
+
clearTimeout(timeout);
|
|
5117
|
+
reject(error);
|
|
5118
|
+
});
|
|
5119
|
+
this.process.on("exit", (code) => {
|
|
5120
|
+
if (code !== 0 && !this.url) {
|
|
5121
|
+
clearTimeout(timeout);
|
|
5122
|
+
reject(new Error(`Cloudflared exited with code ${code}`));
|
|
5123
|
+
}
|
|
5124
|
+
});
|
|
5125
|
+
});
|
|
5126
|
+
}
|
|
5127
|
+
/**
|
|
5128
|
+
* Create ngrok tunnel
|
|
5129
|
+
*/
|
|
5130
|
+
createNgrok(port) {
|
|
5131
|
+
return new Promise((resolve, reject) => {
|
|
5132
|
+
this.process = (0, import_node_child_process.spawn)("ngrok", ["http", port.toString(), "--log=stdout", "--log-level=info"], {
|
|
5133
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5134
|
+
});
|
|
5135
|
+
let output = "";
|
|
5136
|
+
const timeout = setTimeout(() => {
|
|
5137
|
+
reject(new Error("Ngrok timeout"));
|
|
5138
|
+
}, 3e4);
|
|
5139
|
+
this.process.stdout?.on("data", (data) => {
|
|
5140
|
+
output += data.toString();
|
|
5141
|
+
const match = output.match(/url=(https?:\/\/[^\s]+)/i);
|
|
5142
|
+
if (match) {
|
|
5143
|
+
clearTimeout(timeout);
|
|
5144
|
+
this.url = match[1];
|
|
5145
|
+
resolve(match[1]);
|
|
5146
|
+
}
|
|
5147
|
+
});
|
|
5148
|
+
this.process.stderr?.on("data", () => {
|
|
5149
|
+
});
|
|
5150
|
+
this.process.on("error", (error) => {
|
|
5151
|
+
clearTimeout(timeout);
|
|
5152
|
+
reject(error);
|
|
5153
|
+
});
|
|
5154
|
+
this.process.on("exit", (code) => {
|
|
5155
|
+
if (code !== 0 && !this.url) {
|
|
5156
|
+
clearTimeout(timeout);
|
|
5157
|
+
reject(new Error(`Ngrok exited with code ${code}`));
|
|
5158
|
+
}
|
|
5159
|
+
});
|
|
5160
|
+
});
|
|
5161
|
+
}
|
|
5162
|
+
};
|
|
5163
|
+
async function checkTunnelAvailability(provider) {
|
|
5164
|
+
try {
|
|
5165
|
+
const { execSync } = await import("child_process");
|
|
5166
|
+
switch (provider) {
|
|
5167
|
+
case "localtunnel":
|
|
5168
|
+
try {
|
|
5169
|
+
await Promise.resolve().then(() => __toESM(require_localtunnel(), 1));
|
|
5170
|
+
return true;
|
|
5171
|
+
} catch {
|
|
5172
|
+
execSync("npx localtunnel --version", { stdio: "pipe" });
|
|
5173
|
+
return true;
|
|
5174
|
+
}
|
|
5175
|
+
case "cloudflared":
|
|
5176
|
+
execSync("cloudflared --version", { stdio: "pipe" });
|
|
5177
|
+
return true;
|
|
5178
|
+
case "ngrok":
|
|
5179
|
+
execSync("ngrok version", { stdio: "pipe" });
|
|
5180
|
+
return true;
|
|
5181
|
+
default:
|
|
5182
|
+
return false;
|
|
5183
|
+
}
|
|
5184
|
+
} catch {
|
|
5185
|
+
return false;
|
|
5186
|
+
}
|
|
5187
|
+
}
|
|
5188
|
+
async function findAvailableTunnel() {
|
|
5189
|
+
const providers = ["localtunnel", "cloudflared", "ngrok"];
|
|
5190
|
+
for (const provider of providers) {
|
|
5191
|
+
if (await checkTunnelAvailability(provider)) {
|
|
5192
|
+
return provider;
|
|
5193
|
+
}
|
|
5194
|
+
}
|
|
5195
|
+
return null;
|
|
5196
|
+
}
|
|
5197
|
+
|
|
5198
|
+
// src/index.ts
|
|
6263
5199
|
init_web_client();
|
|
6264
5200
|
init_types();
|
|
6265
5201
|
async function createRemoteServer(config = {}) {
|
|
6266
|
-
const { RemoteServer:
|
|
6267
|
-
const server = new
|
|
5202
|
+
const { RemoteServer: RemoteServerCls } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
5203
|
+
const server = new RemoteServerCls(config);
|
|
6268
5204
|
const session = await server.start();
|
|
6269
5205
|
return { server, session };
|
|
6270
5206
|
}
|
|
@@ -6273,7 +5209,10 @@ async function createRemoteServer(config = {}) {
|
|
|
6273
5209
|
DEFAULT_CONFIG,
|
|
6274
5210
|
MessageTypes,
|
|
6275
5211
|
RemoteServer,
|
|
6276
|
-
|
|
5212
|
+
TunnelManager,
|
|
5213
|
+
checkTunnelAvailability,
|
|
6277
5214
|
createRemoteServer,
|
|
5215
|
+
createTunnel,
|
|
5216
|
+
findAvailableTunnel,
|
|
6278
5217
|
getWebClient
|
|
6279
5218
|
});
|