@monotykamary/localterm-server 0.0.15

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.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/dist/constants.d.ts +44 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +80 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/default-shell.d.ts +2 -0
  7. package/dist/default-shell.d.ts.map +1 -0
  8. package/dist/default-shell.js +44 -0
  9. package/dist/default-shell.js.map +1 -0
  10. package/dist/ensure-spawn-helper-executable.d.ts +2 -0
  11. package/dist/ensure-spawn-helper-executable.d.ts.map +1 -0
  12. package/dist/ensure-spawn-helper-executable.js +34 -0
  13. package/dist/ensure-spawn-helper-executable.js.map +1 -0
  14. package/dist/errors.d.ts +64 -0
  15. package/dist/errors.d.ts.map +1 -0
  16. package/dist/errors.js +84 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/index.d.ts +22 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +369 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/protocol.d.ts +5 -0
  23. package/dist/protocol.d.ts.map +1 -0
  24. package/dist/protocol.js +3 -0
  25. package/dist/protocol.js.map +1 -0
  26. package/dist/schemas.d.ts +36 -0
  27. package/dist/schemas.d.ts.map +1 -0
  28. package/dist/schemas.js +73 -0
  29. package/dist/schemas.js.map +1 -0
  30. package/dist/security.d.ts +5 -0
  31. package/dist/security.d.ts.map +1 -0
  32. package/dist/security.js +60 -0
  33. package/dist/security.js.map +1 -0
  34. package/dist/session-registry.d.ts +9 -0
  35. package/dist/session-registry.d.ts.map +1 -0
  36. package/dist/session-registry.js +19 -0
  37. package/dist/session-registry.js.map +1 -0
  38. package/dist/session.d.ts +61 -0
  39. package/dist/session.d.ts.map +1 -0
  40. package/dist/session.js +245 -0
  41. package/dist/session.js.map +1 -0
  42. package/dist/static-resolver.d.ts +7 -0
  43. package/dist/static-resolver.d.ts.map +1 -0
  44. package/dist/static-resolver.js +64 -0
  45. package/dist/static-resolver.js.map +1 -0
  46. package/dist/types.d.ts +12 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -0
  50. package/dist/utils/format-working-directory-title.d.ts +2 -0
  51. package/dist/utils/format-working-directory-title.d.ts.map +1 -0
  52. package/dist/utils/format-working-directory-title.js +28 -0
  53. package/dist/utils/format-working-directory-title.js.map +1 -0
  54. package/dist/utils/parse-osc7.d.ts +2 -0
  55. package/dist/utils/parse-osc7.d.ts.map +1 -0
  56. package/dist/utils/parse-osc7.js +50 -0
  57. package/dist/utils/parse-osc7.js.map +1 -0
  58. package/dist/utils/resolve-cwd-for-pid.d.ts +2 -0
  59. package/dist/utils/resolve-cwd-for-pid.d.ts.map +1 -0
  60. package/dist/utils/resolve-cwd-for-pid.js +29 -0
  61. package/dist/utils/resolve-cwd-for-pid.js.map +1 -0
  62. package/package.json +69 -0
package/dist/index.js ADDED
@@ -0,0 +1,369 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { serve } from "@hono/node-server";
4
+ import { createNodeWebSocket } from "@hono/node-ws";
5
+ import { Hono } from "hono";
6
+ import { DEFAULT_HOST, DEFAULT_PORT, HTTP_STATUS_NOT_FOUND, MAX_CONCURRENT_SESSIONS, SERVER_STOP_GRACE_MS, WS_BACKPRESSURE_THRESHOLD_BYTES, WS_CLOSE_BACKPRESSURE, WS_CLOSE_CAPACITY_REACHED, WS_HEARTBEAT_INTERVAL_MS, WS_HEARTBEAT_TIMEOUT_MS, WS_OUTBOUND_DRAIN_POLL_MS, WS_OUTBOUND_PAUSE_HIGH_WATER_BYTES, WS_OUTBOUND_RESUME_LOW_WATER_BYTES, WS_READY_STATE_OPEN, } from "./constants.js";
7
+ import { ServerErrorException, serverError } from "./errors.js";
8
+ import { clientToServerMessageSchema } from "./schemas.js";
9
+ import { Session } from "./session.js";
10
+ import { SessionRegistry } from "./session-registry.js";
11
+ import { resolveStaticAsset } from "./static-resolver.js";
12
+ const getRawBufferedAmount = (raw) => {
13
+ if (!raw || typeof raw !== "object")
14
+ return 0;
15
+ const candidate = Reflect.get(raw, "bufferedAmount");
16
+ return typeof candidate === "number" ? candidate : 0;
17
+ };
18
+ const callRawMethod = (raw, method) => {
19
+ if (!raw || typeof raw !== "object")
20
+ return false;
21
+ const candidate = Reflect.get(raw, method);
22
+ if (typeof candidate !== "function")
23
+ return false;
24
+ try {
25
+ candidate.call(raw);
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ };
32
+ const onRawEvent = (raw, event, listener) => {
33
+ if (!raw || typeof raw !== "object")
34
+ return null;
35
+ const on = Reflect.get(raw, "on");
36
+ const off = Reflect.get(raw, "off");
37
+ if (typeof on !== "function" || typeof off !== "function")
38
+ return null;
39
+ on.call(raw, event, listener);
40
+ return () => {
41
+ try {
42
+ off.call(raw, event, listener);
43
+ }
44
+ catch {
45
+ /* socket already torn down */
46
+ }
47
+ };
48
+ };
49
+ const safeSend = (ws, payload) => {
50
+ if (ws.readyState !== WS_READY_STATE_OPEN)
51
+ return;
52
+ if (getRawBufferedAmount(ws.raw) > WS_BACKPRESSURE_THRESHOLD_BYTES) {
53
+ ws.close(WS_CLOSE_BACKPRESSURE, "backpressure");
54
+ return;
55
+ }
56
+ try {
57
+ ws.send(JSON.stringify(payload));
58
+ }
59
+ catch {
60
+ /* socket closed between readyState check and send */
61
+ }
62
+ };
63
+ export const createServer = async (options = {}) => {
64
+ const port = options.port ?? DEFAULT_PORT;
65
+ const host = options.host ?? DEFAULT_HOST;
66
+ const staticRoot = typeof options.staticRoot === "string" ? path.resolve(options.staticRoot) : null;
67
+ const registry = new SessionRegistry();
68
+ const app = new Hono();
69
+ const { injectWebSocket, upgradeWebSocket, wss } = createNodeWebSocket({ app });
70
+ const api = new Hono();
71
+ api.get("/health", (context) => context.json({ ok: true, sessions: registry.size() }));
72
+ api.notFound((context) => context.json({ error: "not_found" }, HTTP_STATUS_NOT_FOUND));
73
+ app.route("/api", api);
74
+ app.get("/ws", upgradeWebSocket((context) => {
75
+ let session = null;
76
+ let activeWs = null;
77
+ let drainPollTimer = null;
78
+ let heartbeatTimer = null;
79
+ let stopHeartbeat = null;
80
+ let outputBatch = "";
81
+ let outputBatchTimer = null;
82
+ const stopDrainPoll = () => {
83
+ if (drainPollTimer === null)
84
+ return;
85
+ clearInterval(drainPollTimer);
86
+ drainPollTimer = null;
87
+ };
88
+ const stopHeartbeatChecks = () => {
89
+ if (heartbeatTimer !== null) {
90
+ clearInterval(heartbeatTimer);
91
+ heartbeatTimer = null;
92
+ }
93
+ if (stopHeartbeat) {
94
+ stopHeartbeat();
95
+ stopHeartbeat = null;
96
+ }
97
+ };
98
+ const rawCwd = context.req.query("cwd");
99
+ let requestedCwd;
100
+ if (rawCwd) {
101
+ try {
102
+ const stat = fs.statSync(rawCwd);
103
+ if (stat.isDirectory())
104
+ requestedCwd = rawCwd;
105
+ }
106
+ catch {
107
+ /* invalid or inaccessible path; fall back to default cwd */
108
+ }
109
+ }
110
+ return {
111
+ onOpen(_event, ws) {
112
+ activeWs = ws;
113
+ if (registry.size() >= MAX_CONCURRENT_SESSIONS) {
114
+ ws.close(WS_CLOSE_CAPACITY_REACHED, "session capacity reached");
115
+ return;
116
+ }
117
+ const newSession = new Session({ cwd: requestedCwd });
118
+ session = newSession;
119
+ registry.register(newSession);
120
+ // Heartbeat. Without this, half-open sockets (laptop sleep, network
121
+ // dropout) never surface as a `close` event and the daemon keeps
122
+ // streaming PTY output into the void. We only enable it if the raw
123
+ // socket exposes `on("pong")` — otherwise the timer would tick with
124
+ // no pongs ever observed and kill healthy connections after the
125
+ // first idle window.
126
+ let lastPongAt = Date.now();
127
+ stopHeartbeat = onRawEvent(ws.raw, "pong", () => {
128
+ lastPongAt = Date.now();
129
+ });
130
+ if (stopHeartbeat) {
131
+ heartbeatTimer = setInterval(() => {
132
+ if (ws.readyState !== WS_READY_STATE_OPEN)
133
+ return;
134
+ const idleMs = Date.now() - lastPongAt;
135
+ if (idleMs > WS_HEARTBEAT_TIMEOUT_MS) {
136
+ console.warn(`ws heartbeat timeout: no pong for ${idleMs}ms (pid ${newSession.pid}); terminating`);
137
+ stopHeartbeatChecks();
138
+ if (!callRawMethod(ws.raw, "terminate"))
139
+ ws.close();
140
+ return;
141
+ }
142
+ callRawMethod(ws.raw, "ping");
143
+ }, WS_HEARTBEAT_INTERVAL_MS);
144
+ heartbeatTimer.unref?.();
145
+ }
146
+ // Outbound flow control. When the WS buffer climbs past the high
147
+ // water mark we pause the PTY (OS pipe back-pressure stops the
148
+ // child process producing more output) and start polling for the
149
+ // buffer to drain back below the low water mark. This way bursty
150
+ // output (`cat`, build logs, npm install) doesn't kill the
151
+ // connection — only a genuinely wedged receiver eventually trips
152
+ // the WS_BACKPRESSURE_THRESHOLD_BYTES emergency in safeSend.
153
+ const ensureDrainPoll = () => {
154
+ if (drainPollTimer !== null)
155
+ return;
156
+ drainPollTimer = setInterval(() => {
157
+ if (!newSession.isPaused) {
158
+ stopDrainPoll();
159
+ return;
160
+ }
161
+ if (getRawBufferedAmount(ws.raw) <= WS_OUTBOUND_RESUME_LOW_WATER_BYTES) {
162
+ newSession.resume();
163
+ stopDrainPoll();
164
+ }
165
+ }, WS_OUTBOUND_DRAIN_POLL_MS);
166
+ drainPollTimer.unref?.();
167
+ };
168
+ const flushOutputBatch = () => {
169
+ outputBatchTimer = null;
170
+ if (!outputBatch)
171
+ return;
172
+ safeSend(ws, { type: "output", data: outputBatch });
173
+ outputBatch = "";
174
+ if (!newSession.isPaused &&
175
+ getRawBufferedAmount(ws.raw) >= WS_OUTBOUND_PAUSE_HIGH_WATER_BYTES) {
176
+ newSession.pause();
177
+ ensureDrainPoll();
178
+ }
179
+ };
180
+ // Wire listeners BEFORE the first safeSend so any synchronous emit
181
+ // from Session (current or future) reaches the client. Today
182
+ // node-pty's data/exit are async, but this guards against drift.
183
+ const onOutput = (data) => {
184
+ outputBatch += data;
185
+ if (outputBatchTimer === null) {
186
+ outputBatchTimer = setImmediate(flushOutputBatch);
187
+ }
188
+ };
189
+ const onTitle = (title) => safeSend(ws, { type: "title", title });
190
+ const onCwd = (cwd) => safeSend(ws, { type: "cwd", cwd });
191
+ const onForeground = (process) => safeSend(ws, { type: "foreground", process });
192
+ const onExit = (code) => {
193
+ if (outputBatchTimer !== null) {
194
+ clearImmediate(outputBatchTimer);
195
+ outputBatchTimer = null;
196
+ }
197
+ flushOutputBatch();
198
+ stopDrainPoll();
199
+ stopHeartbeatChecks();
200
+ safeSend(ws, { type: "exit", code });
201
+ ws.close();
202
+ };
203
+ newSession.on("output", onOutput);
204
+ newSession.on("title", onTitle);
205
+ newSession.on("cwd", onCwd);
206
+ newSession.on("foreground", onForeground);
207
+ newSession.on("exit", onExit);
208
+ safeSend(ws, {
209
+ type: "session",
210
+ shell: newSession.shell,
211
+ shellName: newSession.shellBaseName,
212
+ pid: newSession.pid,
213
+ cwd: newSession.cwd,
214
+ });
215
+ },
216
+ onMessage(event) {
217
+ if (!session)
218
+ return;
219
+ let rawPayload;
220
+ try {
221
+ const raw = typeof event.data === "string" ? event.data : event.data.toString();
222
+ rawPayload = JSON.parse(raw);
223
+ }
224
+ catch {
225
+ return;
226
+ }
227
+ const parsed = clientToServerMessageSchema.safeParse(rawPayload);
228
+ if (!parsed.success)
229
+ return;
230
+ if (parsed.data.type === "input") {
231
+ session.write(parsed.data.data);
232
+ }
233
+ else {
234
+ session.resize(parsed.data.cols, parsed.data.rows);
235
+ }
236
+ },
237
+ onClose(event) {
238
+ if (outputBatchTimer !== null) {
239
+ clearImmediate(outputBatchTimer);
240
+ outputBatchTimer = null;
241
+ }
242
+ if (outputBatch && activeWs) {
243
+ safeSend(activeWs, { type: "output", data: outputBatch });
244
+ outputBatch = "";
245
+ }
246
+ stopDrainPoll();
247
+ stopHeartbeatChecks();
248
+ // Most "the terminal randomly died" reports are actually the WS
249
+ // closing for a reason we never surfaced; logging code+reason+
250
+ // wasClean here makes the next incident a 1-line lookup in
251
+ // ~/.localterm/server.log.
252
+ const pidLabel = session ? ` pid ${session.pid}` : "";
253
+ console.info(`ws closed${pidLabel}: code=${event.code} reason=${JSON.stringify(event.reason)} wasClean=${event.wasClean}`);
254
+ if (!session)
255
+ return;
256
+ registry.unregister(session);
257
+ session.dispose();
258
+ session = null;
259
+ activeWs = null;
260
+ },
261
+ onError(event) {
262
+ if (outputBatchTimer !== null) {
263
+ clearImmediate(outputBatchTimer);
264
+ outputBatchTimer = null;
265
+ }
266
+ if (outputBatch && activeWs) {
267
+ safeSend(activeWs, { type: "output", data: outputBatch });
268
+ outputBatch = "";
269
+ }
270
+ stopDrainPoll();
271
+ stopHeartbeatChecks();
272
+ const errorValue = event && typeof event === "object" ? (Reflect.get(event, "error") ?? event) : event;
273
+ const message = errorValue instanceof Error ? errorValue.message : String(errorValue);
274
+ const pidLabel = session ? ` pid ${session.pid}` : "";
275
+ console.error(`ws error${pidLabel}: ${message}`);
276
+ if (!session)
277
+ return;
278
+ registry.unregister(session);
279
+ session.dispose();
280
+ session = null;
281
+ activeWs = null;
282
+ },
283
+ };
284
+ }));
285
+ if (staticRoot) {
286
+ app.get("*", (context) => {
287
+ const requestPath = context.req.path;
288
+ if (requestPath.startsWith("/api/") || requestPath.startsWith("/ws")) {
289
+ return context.json({ error: "not_found" }, HTTP_STATUS_NOT_FOUND);
290
+ }
291
+ const asset = resolveStaticAsset(staticRoot, requestPath);
292
+ if (!asset)
293
+ return context.text("not found", HTTP_STATUS_NOT_FOUND);
294
+ return new Response(new Uint8Array(asset.body), {
295
+ status: asset.status,
296
+ headers: { "content-type": asset.contentType },
297
+ });
298
+ });
299
+ }
300
+ let httpServer = null;
301
+ await new Promise((resolve, reject) => {
302
+ const handleError = (error) => {
303
+ reject(new ServerErrorException(serverError.listenFailed(host, port, error)));
304
+ };
305
+ const node = serve({
306
+ fetch: app.fetch,
307
+ hostname: host,
308
+ port,
309
+ }, () => {
310
+ node.removeListener("error", handleError);
311
+ resolve();
312
+ });
313
+ node.once("error", handleError);
314
+ httpServer = node;
315
+ });
316
+ if (!httpServer) {
317
+ throw new ServerErrorException(serverError.listenFailed(host, port, new Error("hono serve() resolved without binding an http server")));
318
+ }
319
+ injectWebSocket(httpServer);
320
+ const stop = async () => {
321
+ registry.disposeAll();
322
+ // Forcibly tear down every WS first. node-pty + ws upgraded sockets
323
+ // aren't tracked in http.Server's keep-alive set, so target.close() would
324
+ // otherwise wait forever for them and the CLI's force-exit fallback would
325
+ // fire on every shutdown.
326
+ for (const client of wss.clients) {
327
+ try {
328
+ client.terminate();
329
+ }
330
+ catch {
331
+ /* socket already torn down */
332
+ }
333
+ }
334
+ try {
335
+ wss.close();
336
+ }
337
+ catch {
338
+ /* idempotent close — wss may already be closed */
339
+ }
340
+ if (!httpServer)
341
+ return;
342
+ const target = httpServer;
343
+ const closeAllConnections = Reflect.get(target, "closeAllConnections");
344
+ if (typeof closeAllConnections === "function") {
345
+ closeAllConnections.call(target);
346
+ }
347
+ await new Promise((resolve) => {
348
+ let settled = false;
349
+ const settle = () => {
350
+ if (settled)
351
+ return;
352
+ settled = true;
353
+ resolve();
354
+ };
355
+ const grace = setTimeout(settle, SERVER_STOP_GRACE_MS);
356
+ grace.unref?.();
357
+ target.close(() => {
358
+ clearTimeout(grace);
359
+ settle();
360
+ });
361
+ });
362
+ };
363
+ return { port, host, registry, stop };
364
+ };
365
+ export { DEFAULT_HOST, DEFAULT_PORT, WS_CLOSE_BACKPRESSURE } from "./constants.js";
366
+ export { isLoopbackHost } from "./security.js";
367
+ export { healthSchema } from "./schemas.js";
368
+ export { ServerErrorException, formatServerError, isServerErrorException, serverError, } from "./errors.js";
369
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { MAX_COLS, MAX_CONCURRENT_SESSIONS, MAX_INPUT_BYTES, MAX_OUTPUT_BYTES, MAX_ROWS, MAX_TITLE_LENGTH, WS_BACKPRESSURE_THRESHOLD_BYTES, WS_CLOSE_BACKPRESSURE, WS_CLOSE_CAPACITY_REACHED, WS_CLOSE_POLICY_VIOLATION, WS_READY_STATE_OPEN, } from "./constants.js";
2
+ export { clientToServerMessageSchema, healthSchema, serverToClientMessageSchema, } from "./schemas.js";
3
+ export type { ClientToServerMessage, ServerToClientMessage } from "./types.js";
4
+ export type { ServerError, ServerErrorCode, ServerErrorKind } from "./errors.js";
5
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,EAChB,+BAA+B,EAC/B,qBAAqB,EACrB,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,2BAA2B,EAC3B,YAAY,EACZ,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAC/E,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { MAX_COLS, MAX_CONCURRENT_SESSIONS, MAX_INPUT_BYTES, MAX_OUTPUT_BYTES, MAX_ROWS, MAX_TITLE_LENGTH, WS_BACKPRESSURE_THRESHOLD_BYTES, WS_CLOSE_BACKPRESSURE, WS_CLOSE_CAPACITY_REACHED, WS_CLOSE_POLICY_VIOLATION, WS_READY_STATE_OPEN, } from "./constants.js";
2
+ export { clientToServerMessageSchema, healthSchema, serverToClientMessageSchema, } from "./schemas.js";
3
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,EAChB,+BAA+B,EAC/B,qBAAqB,EACrB,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,2BAA2B,EAC3B,YAAY,EACZ,2BAA2B,GAC5B,MAAM,cAAc,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ export declare const healthSchema: z.ZodObject<{
3
+ ok: z.ZodBoolean;
4
+ sessions: z.ZodNumber;
5
+ }, z.core.$strict>;
6
+ export declare const clientToServerMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7
+ type: z.ZodLiteral<"input">;
8
+ data: z.ZodString;
9
+ }, z.core.$strict>, z.ZodObject<{
10
+ type: z.ZodLiteral<"resize">;
11
+ cols: z.ZodNumber;
12
+ rows: z.ZodNumber;
13
+ }, z.core.$strict>], "type">;
14
+ export declare const serverToClientMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
15
+ type: z.ZodLiteral<"output">;
16
+ data: z.ZodString;
17
+ }, z.core.$strict>, z.ZodObject<{
18
+ type: z.ZodLiteral<"exit">;
19
+ code: z.ZodNullable<z.ZodNumber>;
20
+ }, z.core.$strict>, z.ZodObject<{
21
+ type: z.ZodLiteral<"title">;
22
+ title: z.ZodString;
23
+ }, z.core.$strict>, z.ZodObject<{
24
+ type: z.ZodLiteral<"session">;
25
+ shell: z.ZodString;
26
+ shellName: z.ZodString;
27
+ pid: z.ZodNumber;
28
+ cwd: z.ZodString;
29
+ }, z.core.$strict>, z.ZodObject<{
30
+ type: z.ZodLiteral<"cwd">;
31
+ cwd: z.ZodString;
32
+ }, z.core.$strict>, z.ZodObject<{
33
+ type: z.ZodLiteral<"foreground">;
34
+ process: z.ZodNullable<z.ZodString>;
35
+ }, z.core.$strict>], "type">;
36
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,eAAO,MAAM,YAAY;;;kBAKd,CAAC;AAiBZ,eAAO,MAAM,2BAA2B;;;;;;;4BAGtC,CAAC;AA+CH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;4BAOtC,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { z } from "zod";
2
+ import { MAX_COLS, MAX_FOREGROUND_LENGTH, MAX_INPUT_BYTES, MAX_OUTPUT_BYTES, MAX_ROWS, MAX_TITLE_LENGTH, } from "./constants.js";
3
+ export const healthSchema = z
4
+ .object({
5
+ ok: z.boolean(),
6
+ sessions: z.number().int().nonnegative(),
7
+ })
8
+ .strict();
9
+ const inputMessageSchema = z
10
+ .object({
11
+ type: z.literal("input"),
12
+ data: z.string().max(MAX_INPUT_BYTES),
13
+ })
14
+ .strict();
15
+ const resizeMessageSchema = z
16
+ .object({
17
+ type: z.literal("resize"),
18
+ cols: z.number().int().positive().max(MAX_COLS),
19
+ rows: z.number().int().positive().max(MAX_ROWS),
20
+ })
21
+ .strict();
22
+ export const clientToServerMessageSchema = z.discriminatedUnion("type", [
23
+ inputMessageSchema,
24
+ resizeMessageSchema,
25
+ ]);
26
+ const outputMessageSchema = z
27
+ .object({
28
+ type: z.literal("output"),
29
+ data: z.string().max(MAX_OUTPUT_BYTES),
30
+ })
31
+ .strict();
32
+ const exitMessageSchema = z
33
+ .object({
34
+ type: z.literal("exit"),
35
+ code: z.number().int().nullable(),
36
+ })
37
+ .strict();
38
+ const titleMessageSchema = z
39
+ .object({
40
+ type: z.literal("title"),
41
+ title: z.string().max(MAX_TITLE_LENGTH),
42
+ })
43
+ .strict();
44
+ const sessionMessageSchema = z
45
+ .object({
46
+ type: z.literal("session"),
47
+ shell: z.string().min(1),
48
+ shellName: z.string().min(1),
49
+ pid: z.number().int().nonnegative(),
50
+ cwd: z.string().min(1),
51
+ })
52
+ .strict();
53
+ const cwdMessageSchema = z
54
+ .object({
55
+ type: z.literal("cwd"),
56
+ cwd: z.string().min(1),
57
+ })
58
+ .strict();
59
+ const foregroundMessageSchema = z
60
+ .object({
61
+ type: z.literal("foreground"),
62
+ process: z.string().max(MAX_FOREGROUND_LENGTH).nullable(),
63
+ })
64
+ .strict();
65
+ export const serverToClientMessageSchema = z.discriminatedUnion("type", [
66
+ outputMessageSchema,
67
+ exitMessageSchema,
68
+ titleMessageSchema,
69
+ sessionMessageSchema,
70
+ cwdMessageSchema,
71
+ foregroundMessageSchema,
72
+ ]);
73
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Context, MiddlewareHandler } from "hono";
2
+ export declare const isLoopbackHost: (host: string) => boolean;
3
+ export declare const enforceLoopback: (context: Context) => Response | null;
4
+ export declare const loopbackMiddleware: MiddlewareHandler;
5
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAiCvD,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,KAAG,OAA2B,CAAC;AAE1E,eAAO,MAAM,eAAe,GAAI,SAAS,OAAO,KAAG,QAAQ,GAAG,IAc7D,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,iBAIhC,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { LOOPBACK_HOSTS } from "./constants.js";
2
+ const stripPort = (hostHeader) => {
3
+ if (!hostHeader)
4
+ return null;
5
+ const trimmed = hostHeader.trim();
6
+ if (!trimmed)
7
+ return null;
8
+ if (trimmed.startsWith("[")) {
9
+ const end = trimmed.indexOf("]");
10
+ return end === -1 ? trimmed : trimmed.slice(0, end + 1);
11
+ }
12
+ const colon = trimmed.lastIndexOf(":");
13
+ if (colon === -1)
14
+ return trimmed;
15
+ return trimmed.slice(0, colon);
16
+ };
17
+ const originHostname = (originHeader) => {
18
+ if (!originHeader)
19
+ return null;
20
+ if (originHeader === "null")
21
+ return null;
22
+ try {
23
+ return new URL(originHeader).hostname;
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ };
29
+ const isLoopback = (hostname) => {
30
+ if (!hostname)
31
+ return false;
32
+ if (LOOPBACK_HOSTS.has(hostname))
33
+ return true;
34
+ if (hostname === "localhost" || hostname.endsWith(".localhost"))
35
+ return true;
36
+ return false;
37
+ };
38
+ export const isLoopbackHost = (host) => isLoopback(host);
39
+ export const enforceLoopback = (context) => {
40
+ const hostHeader = context.req.header("host");
41
+ const hostname = stripPort(hostHeader);
42
+ if (!isLoopback(hostname)) {
43
+ return new Response("forbidden: non-loopback host", { status: 403 });
44
+ }
45
+ const origin = context.req.header("origin");
46
+ if (origin !== undefined) {
47
+ const originHost = originHostname(origin);
48
+ if (!isLoopback(originHost)) {
49
+ return new Response("forbidden: cross-origin", { status: 403 });
50
+ }
51
+ }
52
+ return null;
53
+ };
54
+ export const loopbackMiddleware = async (context, next) => {
55
+ const blocked = enforceLoopback(context);
56
+ if (blocked)
57
+ return blocked;
58
+ await next();
59
+ };
60
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Session } from "./session.js";
2
+ export declare class SessionRegistry {
3
+ private readonly sessions;
4
+ register(session: Session): void;
5
+ unregister(session: Session): void;
6
+ size(): number;
7
+ disposeAll(): void;
8
+ }
9
+ //# sourceMappingURL=session-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-registry.d.ts","sourceRoot":"","sources":["../src/session-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAE/C,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIhC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIlC,IAAI,IAAI,MAAM;IAId,UAAU,IAAI,IAAI;CAMnB"}
@@ -0,0 +1,19 @@
1
+ export class SessionRegistry {
2
+ sessions = new Set();
3
+ register(session) {
4
+ this.sessions.add(session);
5
+ }
6
+ unregister(session) {
7
+ this.sessions.delete(session);
8
+ }
9
+ size() {
10
+ return this.sessions.size;
11
+ }
12
+ disposeAll() {
13
+ for (const session of this.sessions) {
14
+ session.dispose();
15
+ }
16
+ this.sessions.clear();
17
+ }
18
+ }
19
+ //# sourceMappingURL=session-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../src/session-registry.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,eAAe;IACT,QAAQ,GAAG,IAAI,GAAG,EAAW,CAAC;IAE/C,QAAQ,CAAC,OAAgB;QACvB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAED,UAAU,CAAC,OAAgB;QACzB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,UAAU;QACR,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}