@aitty/server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-token.d.ts +5 -0
- package/dist/cli-token.js +14 -0
- package/dist/frontend/browser-shell.d.ts +34 -0
- package/dist/frontend/browser-shell.html +218 -0
- package/dist/frontend/browser-shell.js +291 -0
- package/dist/frontend/terminal-app.js +4780 -0
- package/dist/frontend/terminal.css +268 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +15 -0
- package/dist/logging.d.ts +17 -0
- package/dist/logging.js +34 -0
- package/dist/network-policy.d.ts +10 -0
- package/dist/network-policy.js +88 -0
- package/dist/runtime/dependencies.d.ts +16 -0
- package/dist/runtime/dependencies.js +16 -0
- package/dist/runtime/output-buffer.d.ts +11 -0
- package/dist/runtime/output-buffer.js +202 -0
- package/dist/runtime/pty-session.d.ts +59 -0
- package/dist/runtime/pty-session.js +247 -0
- package/dist/runtime/websocket-transport.d.ts +32 -0
- package/dist/runtime/websocket-transport.js +465 -0
- package/dist/server.d.ts +51 -0
- package/dist/server.js +234 -0
- package/dist/theme-source.d.ts +2 -0
- package/dist/theme-source.js +2 -0
- package/package.json +73 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
.wterm {
|
|
2
|
+
--term-fg: #d4d4d4;
|
|
3
|
+
--term-bg: #1e1e1e;
|
|
4
|
+
--term-cursor: #aeafad;
|
|
5
|
+
|
|
6
|
+
--term-color-0: #1e1e1e;
|
|
7
|
+
--term-color-1: #f44747;
|
|
8
|
+
--term-color-2: #6a9955;
|
|
9
|
+
--term-color-3: #d7ba7d;
|
|
10
|
+
--term-color-4: #569cd6;
|
|
11
|
+
--term-color-5: #c586c0;
|
|
12
|
+
--term-color-6: #4ec9b0;
|
|
13
|
+
--term-color-7: #d4d4d4;
|
|
14
|
+
--term-color-8: #808080;
|
|
15
|
+
--term-color-9: #f44747;
|
|
16
|
+
--term-color-10: #6a9955;
|
|
17
|
+
--term-color-11: #d7ba7d;
|
|
18
|
+
--term-color-12: #569cd6;
|
|
19
|
+
--term-color-13: #c586c0;
|
|
20
|
+
--term-color-14: #4ec9b0;
|
|
21
|
+
--term-color-15: #ffffff;
|
|
22
|
+
|
|
23
|
+
--term-font-family: 'Menlo', 'Consolas', 'DejaVu Sans Mono', 'Courier New', monospace;
|
|
24
|
+
--term-font-size: 14px;
|
|
25
|
+
--term-line-height: 1.2;
|
|
26
|
+
--term-row-height: 17px;
|
|
27
|
+
|
|
28
|
+
position: relative;
|
|
29
|
+
background: var(--term-bg);
|
|
30
|
+
color: var(--term-fg);
|
|
31
|
+
font-family: var(--term-font-family);
|
|
32
|
+
font-size: var(--term-font-size);
|
|
33
|
+
line-height: var(--term-line-height);
|
|
34
|
+
padding: 12px;
|
|
35
|
+
border-radius: 8px;
|
|
36
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
37
|
+
outline: none;
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.wterm:focus,
|
|
42
|
+
.wterm:focus-visible {
|
|
43
|
+
outline: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.term-grid {
|
|
47
|
+
display: block;
|
|
48
|
+
white-space: pre;
|
|
49
|
+
contain: layout paint style;
|
|
50
|
+
will-change: contents;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.term-row {
|
|
54
|
+
display: block;
|
|
55
|
+
height: var(--term-row-height);
|
|
56
|
+
line-height: var(--term-row-height);
|
|
57
|
+
contain: layout style;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.term-row > span {
|
|
61
|
+
display: inline-block;
|
|
62
|
+
height: var(--term-row-height);
|
|
63
|
+
vertical-align: top;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.term-block {
|
|
67
|
+
width: 1ch;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.term-cursor {
|
|
72
|
+
outline: 1px solid var(--term-cursor);
|
|
73
|
+
outline-offset: -1px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.wterm.focused .term-cursor {
|
|
77
|
+
background: var(--term-cursor);
|
|
78
|
+
color: var(--term-bg);
|
|
79
|
+
outline: none;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.wterm.focused.cursor-blink .term-cursor {
|
|
83
|
+
animation: cursor-blink 1s step-end infinite;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@keyframes cursor-blink {
|
|
87
|
+
0%, 100% { background: var(--term-cursor); color: var(--term-bg); }
|
|
88
|
+
50% { background: transparent; color: inherit; }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.wterm.has-scrollback {
|
|
92
|
+
overflow-y: auto;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.wterm ::selection {
|
|
96
|
+
background: rgba(86, 156, 214, 0.3);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Solarized Dark */
|
|
100
|
+
.wterm.theme-solarized-dark {
|
|
101
|
+
--term-fg: #839496;
|
|
102
|
+
--term-bg: #002b36;
|
|
103
|
+
--term-cursor: #93a1a1;
|
|
104
|
+
--term-color-0: #073642;
|
|
105
|
+
--term-color-1: #dc322f;
|
|
106
|
+
--term-color-2: #859900;
|
|
107
|
+
--term-color-3: #b58900;
|
|
108
|
+
--term-color-4: #268bd2;
|
|
109
|
+
--term-color-5: #d33682;
|
|
110
|
+
--term-color-6: #2aa198;
|
|
111
|
+
--term-color-7: #eee8d5;
|
|
112
|
+
--term-color-8: #586e75;
|
|
113
|
+
--term-color-9: #cb4b16;
|
|
114
|
+
--term-color-10: #586e75;
|
|
115
|
+
--term-color-11: #657b83;
|
|
116
|
+
--term-color-12: #839496;
|
|
117
|
+
--term-color-13: #6c71c4;
|
|
118
|
+
--term-color-14: #93a1a1;
|
|
119
|
+
--term-color-15: #fdf6e3;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Monokai */
|
|
123
|
+
.wterm.theme-monokai {
|
|
124
|
+
--term-fg: #f8f8f2;
|
|
125
|
+
--term-bg: #272822;
|
|
126
|
+
--term-cursor: #f8f8f0;
|
|
127
|
+
--term-color-0: #272822;
|
|
128
|
+
--term-color-1: #f92672;
|
|
129
|
+
--term-color-2: #a6e22e;
|
|
130
|
+
--term-color-3: #f4bf75;
|
|
131
|
+
--term-color-4: #66d9ef;
|
|
132
|
+
--term-color-5: #ae81ff;
|
|
133
|
+
--term-color-6: #a1efe4;
|
|
134
|
+
--term-color-7: #f8f8f2;
|
|
135
|
+
--term-color-8: #75715e;
|
|
136
|
+
--term-color-9: #f92672;
|
|
137
|
+
--term-color-10: #a6e22e;
|
|
138
|
+
--term-color-11: #f4bf75;
|
|
139
|
+
--term-color-12: #66d9ef;
|
|
140
|
+
--term-color-13: #ae81ff;
|
|
141
|
+
--term-color-14: #a1efe4;
|
|
142
|
+
--term-color-15: #f9f8f5;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Light */
|
|
146
|
+
.wterm.theme-light {
|
|
147
|
+
--term-fg: #383a42;
|
|
148
|
+
--term-bg: #fafafa;
|
|
149
|
+
--term-cursor: #526eff;
|
|
150
|
+
--term-color-0: #383a42;
|
|
151
|
+
--term-color-1: #e45649;
|
|
152
|
+
--term-color-2: #50a14f;
|
|
153
|
+
--term-color-3: #c18401;
|
|
154
|
+
--term-color-4: #4078f2;
|
|
155
|
+
--term-color-5: #a626a4;
|
|
156
|
+
--term-color-6: #0184bc;
|
|
157
|
+
--term-color-7: #fafafa;
|
|
158
|
+
--term-color-8: #a0a1a7;
|
|
159
|
+
--term-color-9: #e45649;
|
|
160
|
+
--term-color-10: #50a14f;
|
|
161
|
+
--term-color-11: #c18401;
|
|
162
|
+
--term-color-12: #4078f2;
|
|
163
|
+
--term-color-13: #a626a4;
|
|
164
|
+
--term-color-14: #0184bc;
|
|
165
|
+
--term-color-15: #ffffff;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.aitty-embed,
|
|
169
|
+
.aitty-shell,
|
|
170
|
+
.aitty-scroll-target,
|
|
171
|
+
.aitty-scroll-viewport {
|
|
172
|
+
min-width: 0;
|
|
173
|
+
min-height: 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.aitty-embed {
|
|
177
|
+
height: 100%;
|
|
178
|
+
min-height: 240px;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.aitty-shell,
|
|
182
|
+
.aitty-scroll-target {
|
|
183
|
+
height: 100%;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.aitty-scroll-target {
|
|
187
|
+
overflow: hidden;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.aitty-scroll-viewport {
|
|
191
|
+
height: 100%;
|
|
192
|
+
outline: none;
|
|
193
|
+
overflow-x: hidden;
|
|
194
|
+
overflow-y: auto;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.aitty-scroll-content {
|
|
198
|
+
min-height: 100%;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.aitty-terminal-root {
|
|
202
|
+
position: relative;
|
|
203
|
+
min-width: 0;
|
|
204
|
+
min-height: 100%;
|
|
205
|
+
max-height: none;
|
|
206
|
+
background: transparent;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.aitty-terminal-root.wterm {
|
|
210
|
+
--term-bg: var(--theme-term-bg, transparent);
|
|
211
|
+
--term-fg: var(--theme-term-fg, #edf2ff);
|
|
212
|
+
--term-cursor: var(--theme-term-cursor, currentColor);
|
|
213
|
+
--term-color-0: var(--theme-term-color-0, #111724);
|
|
214
|
+
--term-color-1: var(--theme-term-color-1, #ff7b72);
|
|
215
|
+
--term-color-2: var(--theme-term-color-2, #8ddb8c);
|
|
216
|
+
--term-color-3: var(--theme-term-color-3, #ffd580);
|
|
217
|
+
--term-color-4: var(--theme-term-color-4, #7cc4ff);
|
|
218
|
+
--term-color-5: var(--theme-term-color-5, #d2a8ff);
|
|
219
|
+
--term-color-6: var(--theme-term-color-6, #77e0d2);
|
|
220
|
+
--term-color-7: var(--theme-term-color-7, #edf2ff);
|
|
221
|
+
--term-color-8: var(--theme-term-color-8, #5f6f86);
|
|
222
|
+
--term-color-9: var(--theme-term-color-9, #ffa198);
|
|
223
|
+
--term-color-10: var(--theme-term-color-10, #b0f2af);
|
|
224
|
+
--term-color-11: var(--theme-term-color-11, #ffe4a8);
|
|
225
|
+
--term-color-12: var(--theme-term-color-12, #a7d7ff);
|
|
226
|
+
--term-color-13: var(--theme-term-color-13, #e1c0ff);
|
|
227
|
+
--term-color-14: var(--theme-term-color-14, #9ff4ea);
|
|
228
|
+
--term-color-15: var(--theme-term-color-15, #ffffff);
|
|
229
|
+
--term-font-size: var(--theme-term-font-size, 15px);
|
|
230
|
+
--term-line-height: var(--theme-term-line-height, 1.28);
|
|
231
|
+
color: var(--term-fg);
|
|
232
|
+
padding: 0 0 var(--theme-term-padding-bottom, 24px);
|
|
233
|
+
border-radius: 0;
|
|
234
|
+
box-shadow: none;
|
|
235
|
+
overflow: visible;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.aitty-terminal-root.wterm.has-scrollback {
|
|
239
|
+
overflow-y: visible;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.aitty-terminal-root[data-session-interactive="false"] .term-cursor {
|
|
243
|
+
opacity: 0 !important;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.aitty-terminal-root[data-session-interactive="false"] textarea {
|
|
247
|
+
caret-color: transparent;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.aitty-terminal-root .term-transcript-archive {
|
|
251
|
+
margin: 0;
|
|
252
|
+
min-height: 0;
|
|
253
|
+
padding: 0;
|
|
254
|
+
color: inherit;
|
|
255
|
+
font: inherit;
|
|
256
|
+
line-height: var(--term-row-height);
|
|
257
|
+
pointer-events: none;
|
|
258
|
+
white-space: pre;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.aitty-terminal-root .term-transcript-archive:empty {
|
|
262
|
+
display: none;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.aitty-terminal-root[data-render-mode="screen"] .term-transcript-archive,
|
|
266
|
+
.aitty-terminal-root[data-render-mode="screen"] .term-scrollback-row {
|
|
267
|
+
display: none;
|
|
268
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createSessionToken } from "./cli-token.js";
|
|
2
|
+
import { NetworkPolicy, createNetworkPolicy, isHostAllowed, isOriginAllowed } from "./network-policy.js";
|
|
3
|
+
import { BrowserShellDocumentOptions, BrowserShellOptions, createBrowserShellHtml } from "./frontend/browser-shell.js";
|
|
4
|
+
import { DEFAULT_COLUMNS, DEFAULT_ROWS, DEFAULT_TERM, Disposable, PtyExitEvent, PtyModule, PtyProcess, PtySession, PtySessionOptions, PtySpawnOptions, createPtySession } from "./runtime/pty-session.js";
|
|
5
|
+
import { AittyTheme, AittyThemeSource, AittyThemeSubscription } from "./theme-source.js";
|
|
6
|
+
import { AittyPortlessIdentity, AittyPortlessOptions, AittyRunningServer, AittyRuntimeDependencies, AittyServerIo, AittyServerOptions, Writer, buildAittyOrigin, buildAittyUrl, createAittyServer } from "./server.js";
|
|
7
|
+
import { RuntimeDependencies, loadRuntimeDependencies } from "./runtime/dependencies.js";
|
|
8
|
+
import { WebSocketTransport, WebSocketTransportOptions, createWebSocketTransport } from "./runtime/websocket-transport.js";
|
|
9
|
+
import { DEFAULT_OUTPUT_BUFFER_LIMIT_BYTES, MAX_OUTPUT_BUFFER_LIMIT_BYTES, MIN_OUTPUT_BUFFER_LIMIT_BYTES, OutputBuffer, createOutputBuffer } from "./runtime/output-buffer.js";
|
|
10
|
+
|
|
11
|
+
//#region src/index.d.ts
|
|
12
|
+
declare const projectFoundation: Readonly<{
|
|
13
|
+
name: "aitty";
|
|
14
|
+
engineRange: ">=20";
|
|
15
|
+
}>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { type AittyPortlessIdentity, type AittyPortlessOptions, type AittyRunningServer, type AittyRuntimeDependencies, type AittyServerIo, type AittyServerOptions, type AittyTheme, type AittyThemeSource, type AittyThemeSubscription, type BrowserShellDocumentOptions, type BrowserShellOptions, DEFAULT_COLUMNS, DEFAULT_OUTPUT_BUFFER_LIMIT_BYTES, DEFAULT_ROWS, DEFAULT_TERM, type Disposable, MAX_OUTPUT_BUFFER_LIMIT_BYTES, MIN_OUTPUT_BUFFER_LIMIT_BYTES, type NetworkPolicy, type OutputBuffer, type PtyExitEvent, type PtyModule, type PtyProcess, type PtySession, type PtySessionOptions, type PtySpawnOptions, type RuntimeDependencies, type AittyTheme as TerminalTheme, type WebSocketTransport, type WebSocketTransportOptions, type Writer, buildAittyOrigin, buildAittyUrl, createAittyServer, createBrowserShellHtml, createNetworkPolicy, createOutputBuffer, createPtySession, createSessionToken, createWebSocketTransport, isHostAllowed, isOriginAllowed, loadRuntimeDependencies, projectFoundation };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createSessionToken } from "./cli-token.js";
|
|
2
|
+
import { createNetworkPolicy, isHostAllowed, isOriginAllowed } from "./network-policy.js";
|
|
3
|
+
import { createBrowserShellHtml } from "./frontend/browser-shell.js";
|
|
4
|
+
import { DEFAULT_OUTPUT_BUFFER_LIMIT_BYTES, MAX_OUTPUT_BUFFER_LIMIT_BYTES, MIN_OUTPUT_BUFFER_LIMIT_BYTES, createOutputBuffer } from "./runtime/output-buffer.js";
|
|
5
|
+
import { DEFAULT_COLUMNS, DEFAULT_ROWS, DEFAULT_TERM, createPtySession } from "./runtime/pty-session.js";
|
|
6
|
+
import { createWebSocketTransport } from "./runtime/websocket-transport.js";
|
|
7
|
+
import { buildAittyOrigin, buildAittyUrl, createAittyServer } from "./server.js";
|
|
8
|
+
import { loadRuntimeDependencies } from "./runtime/dependencies.js";
|
|
9
|
+
//#region src/index.ts
|
|
10
|
+
const projectFoundation = Object.freeze({
|
|
11
|
+
name: "aitty",
|
|
12
|
+
engineRange: ">=20"
|
|
13
|
+
});
|
|
14
|
+
//#endregion
|
|
15
|
+
export { DEFAULT_COLUMNS, DEFAULT_OUTPUT_BUFFER_LIMIT_BYTES, DEFAULT_ROWS, DEFAULT_TERM, MAX_OUTPUT_BUFFER_LIMIT_BYTES, MIN_OUTPUT_BUFFER_LIMIT_BYTES, buildAittyOrigin, buildAittyUrl, createAittyServer, createBrowserShellHtml, createNetworkPolicy, createOutputBuffer, createPtySession, createSessionToken, createWebSocketTransport, isHostAllowed, isOriginAllowed, loadRuntimeDependencies, projectFoundation };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/logging.d.ts
|
|
2
|
+
interface LogWriter {
|
|
3
|
+
write(chunk: string): boolean;
|
|
4
|
+
}
|
|
5
|
+
interface StructuredLogger {
|
|
6
|
+
debug(message: string): void;
|
|
7
|
+
error(message: string): void;
|
|
8
|
+
info(message: string): void;
|
|
9
|
+
warn(message: string): void;
|
|
10
|
+
}
|
|
11
|
+
declare function createStructuredLogger(options: {
|
|
12
|
+
token?: string;
|
|
13
|
+
verbose?: boolean;
|
|
14
|
+
writer: LogWriter;
|
|
15
|
+
}): StructuredLogger;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { LogWriter, StructuredLogger, createStructuredLogger };
|
package/dist/logging.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/logging.ts
|
|
2
|
+
function createStructuredLogger(options) {
|
|
3
|
+
const redactions = [options.token].filter((value) => typeof value === "string" && value.length > 0);
|
|
4
|
+
return {
|
|
5
|
+
debug(message) {
|
|
6
|
+
if (!options.verbose) return;
|
|
7
|
+
writeStructuredLog(options.writer, "DEBUG", message, redactions);
|
|
8
|
+
},
|
|
9
|
+
error(message) {
|
|
10
|
+
writeStructuredLog(options.writer, "ERROR", message, redactions);
|
|
11
|
+
},
|
|
12
|
+
info(message) {
|
|
13
|
+
writeStructuredLog(options.writer, "INFO", message, redactions);
|
|
14
|
+
},
|
|
15
|
+
warn(message) {
|
|
16
|
+
writeStructuredLog(options.writer, "WARN", message, redactions);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function writeStructuredLog(writer, level, message, redactions) {
|
|
21
|
+
for (const line of normalizeLogLines(redactSecrets(message, redactions))) writer.write(`[${level}] ${line}\n`);
|
|
22
|
+
}
|
|
23
|
+
function normalizeLogLines(message) {
|
|
24
|
+
const lines = message.replace(/\r\n/g, "\n").split("\n");
|
|
25
|
+
if (lines.at(-1) === "") lines.pop();
|
|
26
|
+
return lines.length > 0 ? lines : [""];
|
|
27
|
+
}
|
|
28
|
+
function redactSecrets(message, redactions) {
|
|
29
|
+
let redacted = message;
|
|
30
|
+
for (const secret of redactions) redacted = redacted.split(secret).join("[REDACTED]");
|
|
31
|
+
return redacted;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { createStructuredLogger };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/network-policy.d.ts
|
|
2
|
+
interface NetworkPolicy {
|
|
3
|
+
readonly allowedHosts: ReadonlySet<string>;
|
|
4
|
+
readonly port: number;
|
|
5
|
+
}
|
|
6
|
+
declare function createNetworkPolicy(bindHost: string, publicHost: string, port: number): NetworkPolicy;
|
|
7
|
+
declare function isHostAllowed(hostHeader: string | string[] | undefined, policy: NetworkPolicy): boolean;
|
|
8
|
+
declare function isOriginAllowed(originHeader: string | string[] | undefined, policy: NetworkPolicy): boolean;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { NetworkPolicy, createNetworkPolicy, isHostAllowed, isOriginAllowed };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
//#region src/network-policy.ts
|
|
2
|
+
const LOOPBACK_SCHEME = "http:";
|
|
3
|
+
function createNetworkPolicy(bindHost, publicHost, port) {
|
|
4
|
+
return {
|
|
5
|
+
allowedHosts: new Set([normalizeHost(bindHost), normalizeHost(publicHost)]),
|
|
6
|
+
port
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function isHostAllowed(hostHeader, policy) {
|
|
10
|
+
const authority = readSingleHeaderValue(hostHeader);
|
|
11
|
+
if (!authority) return false;
|
|
12
|
+
const parsed = parseAuthority(authority);
|
|
13
|
+
if (!parsed) return false;
|
|
14
|
+
return policy.allowedHosts.has(parsed.host) && (parsed.port === null || parsed.port === policy.port);
|
|
15
|
+
}
|
|
16
|
+
function isOriginAllowed(originHeader, policy) {
|
|
17
|
+
const origin = readSingleHeaderValue(originHeader);
|
|
18
|
+
if (!origin) return true;
|
|
19
|
+
let parsed;
|
|
20
|
+
try {
|
|
21
|
+
parsed = new URL(origin);
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (parsed.protocol !== LOOPBACK_SCHEME) return false;
|
|
26
|
+
const authority = readAuthority(origin);
|
|
27
|
+
if (!authority) return false;
|
|
28
|
+
const originAuthority = parseAuthority(authority);
|
|
29
|
+
if (!originAuthority || originAuthority.port === null) return false;
|
|
30
|
+
return isLoopbackHost(originAuthority.host) || policy.allowedHosts.has(originAuthority.host) && originAuthority.port === policy.port;
|
|
31
|
+
}
|
|
32
|
+
function readSingleHeaderValue(value) {
|
|
33
|
+
if (typeof value !== "string") return null;
|
|
34
|
+
const candidate = value.trim();
|
|
35
|
+
return candidate ? candidate : null;
|
|
36
|
+
}
|
|
37
|
+
function parseAuthority(authority) {
|
|
38
|
+
const candidate = authority.trim();
|
|
39
|
+
if (!candidate) return null;
|
|
40
|
+
let hostPart = candidate;
|
|
41
|
+
let portPart = null;
|
|
42
|
+
if (candidate.startsWith("[")) {
|
|
43
|
+
const closingBracketIndex = candidate.indexOf("]");
|
|
44
|
+
if (closingBracketIndex === -1) return null;
|
|
45
|
+
hostPart = candidate.slice(1, closingBracketIndex);
|
|
46
|
+
const remainder = candidate.slice(closingBracketIndex + 1);
|
|
47
|
+
if (remainder) {
|
|
48
|
+
if (!remainder.startsWith(":")) return null;
|
|
49
|
+
portPart = remainder.slice(1);
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
const firstColonIndex = candidate.indexOf(":");
|
|
53
|
+
if (firstColonIndex !== candidate.lastIndexOf(":")) return null;
|
|
54
|
+
if (firstColonIndex !== -1) {
|
|
55
|
+
hostPart = candidate.slice(0, firstColonIndex);
|
|
56
|
+
portPart = candidate.slice(firstColonIndex + 1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!hostPart) return null;
|
|
60
|
+
if (portPart === null) return {
|
|
61
|
+
host: normalizeHost(hostPart),
|
|
62
|
+
port: null
|
|
63
|
+
};
|
|
64
|
+
if (!/^\d+$/.test(portPart)) return null;
|
|
65
|
+
const port = Number.parseInt(portPart, 10);
|
|
66
|
+
if (port < 0 || port > 65535) return null;
|
|
67
|
+
return {
|
|
68
|
+
host: normalizeHost(hostPart),
|
|
69
|
+
port
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function readAuthority(url) {
|
|
73
|
+
const schemeSeparatorIndex = url.indexOf("://");
|
|
74
|
+
if (schemeSeparatorIndex === -1) return null;
|
|
75
|
+
const authorityStart = schemeSeparatorIndex + 3;
|
|
76
|
+
const remainder = url.slice(authorityStart);
|
|
77
|
+
const authorityLength = remainder.search(/[/?#]/);
|
|
78
|
+
return (authorityLength === -1 ? remainder : remainder.slice(0, authorityLength)) || null;
|
|
79
|
+
}
|
|
80
|
+
function normalizeHost(host) {
|
|
81
|
+
return host.replace(/^\[(.*)\]$/, "$1").toLowerCase();
|
|
82
|
+
}
|
|
83
|
+
function isLoopbackHost(host) {
|
|
84
|
+
const normalizedHost = normalizeHost(host);
|
|
85
|
+
return normalizedHost === "localhost" || normalizedHost === "::1" || normalizedHost.startsWith("127.");
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { createNetworkPolicy, isHostAllowed, isOriginAllowed };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as _$ws from "ws";
|
|
2
|
+
import * as _$node_pty0 from "node-pty";
|
|
3
|
+
import * as _$open from "open";
|
|
4
|
+
|
|
5
|
+
//#region src/runtime/dependencies.d.ts
|
|
6
|
+
interface RuntimeDependencies {
|
|
7
|
+
nodePty: {
|
|
8
|
+
spawn: typeof _$node_pty0.spawn;
|
|
9
|
+
};
|
|
10
|
+
WebSocket: typeof _$ws.WebSocket;
|
|
11
|
+
WebSocketServer: typeof _$ws.WebSocketServer;
|
|
12
|
+
openBrowser: (typeof _$open)["default"];
|
|
13
|
+
}
|
|
14
|
+
declare function loadRuntimeDependencies(): Promise<RuntimeDependencies>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { RuntimeDependencies, loadRuntimeDependencies };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/runtime/dependencies.ts
|
|
2
|
+
async function loadRuntimeDependencies() {
|
|
3
|
+
const [nodePtyModule, wsModule, openModule] = await Promise.all([
|
|
4
|
+
import("node-pty"),
|
|
5
|
+
import("ws"),
|
|
6
|
+
import("open")
|
|
7
|
+
]);
|
|
8
|
+
return {
|
|
9
|
+
nodePty: nodePtyModule,
|
|
10
|
+
WebSocket: wsModule.WebSocket,
|
|
11
|
+
WebSocketServer: wsModule.WebSocketServer,
|
|
12
|
+
openBrowser: openModule.default
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { loadRuntimeDependencies };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/runtime/output-buffer.d.ts
|
|
2
|
+
declare const DEFAULT_OUTPUT_BUFFER_LIMIT_BYTES: number;
|
|
3
|
+
declare const MIN_OUTPUT_BUFFER_LIMIT_BYTES = 1024;
|
|
4
|
+
declare const MAX_OUTPUT_BUFFER_LIMIT_BYTES: number;
|
|
5
|
+
interface OutputBuffer {
|
|
6
|
+
append(chunk: Buffer): void;
|
|
7
|
+
snapshot(): Buffer | null;
|
|
8
|
+
}
|
|
9
|
+
declare function createOutputBuffer(limitBytes?: number): OutputBuffer;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { DEFAULT_OUTPUT_BUFFER_LIMIT_BYTES, MAX_OUTPUT_BUFFER_LIMIT_BYTES, MIN_OUTPUT_BUFFER_LIMIT_BYTES, OutputBuffer, createOutputBuffer };
|