@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.
@@ -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
+ }
@@ -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 };
@@ -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 };