106 lines
2.7 KiB
TypeScript
106 lines
2.7 KiB
TypeScript
/**
|
|
* S-03 — send-keys input route.
|
|
*
|
|
* POST /sessions/:id/input
|
|
*
|
|
* Body (IC-1 ClientToServer subset, but as HTTP POST for non-WS clients):
|
|
* { type: "key"; name: string }
|
|
* { type: "keys"; data: string }
|
|
* { type: "paste"; data: string }
|
|
*
|
|
* Response: 204 No Content on success, 400 on bad input, 404 if session missing.
|
|
*
|
|
* Note: the primary path for send-keys is via WS (T-1.5 stream route handles
|
|
* key/keys/paste messages inline). This HTTP endpoint is for clients that
|
|
* don't have an open stream (e.g. one-shot CLI tools).
|
|
*
|
|
* Owner: T-1.5
|
|
*/
|
|
|
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
import { sendKey, sendKeys, sendPaste } from "../../tmux/input.js";
|
|
import { getSession } from "../../tmux/manager.js";
|
|
import { readBody, sendJson } from "../util.js";
|
|
|
|
export async function handleInput(
|
|
req: IncomingMessage,
|
|
res: ServerResponse,
|
|
sessionId: string,
|
|
): Promise<void> {
|
|
const session = await getSession(sessionId).catch(() => null);
|
|
if (!session) {
|
|
sendJson(res, 404, {
|
|
error: "session_not_found",
|
|
message: `Session "${sessionId}" not found`,
|
|
});
|
|
return;
|
|
}
|
|
|
|
let body: unknown;
|
|
try {
|
|
body = JSON.parse(await readBody(req));
|
|
} catch {
|
|
sendJson(res, 400, { error: "bad_request", message: "Invalid JSON body" });
|
|
return;
|
|
}
|
|
|
|
if (!body || typeof body !== "object") {
|
|
sendJson(res, 400, {
|
|
error: "bad_request",
|
|
message: "Body must be a JSON object",
|
|
});
|
|
return;
|
|
}
|
|
|
|
const m = body as Record<string, unknown>;
|
|
|
|
try {
|
|
switch (m.type) {
|
|
case "key": {
|
|
if (typeof m.name !== "string") {
|
|
sendJson(res, 400, {
|
|
error: "bad_request",
|
|
message: "key.name must be a string",
|
|
});
|
|
return;
|
|
}
|
|
await sendKey(sessionId, m.name);
|
|
break;
|
|
}
|
|
case "keys": {
|
|
if (typeof m.data !== "string") {
|
|
sendJson(res, 400, {
|
|
error: "bad_request",
|
|
message: "keys.data must be a string",
|
|
});
|
|
return;
|
|
}
|
|
await sendKeys(sessionId, m.data);
|
|
break;
|
|
}
|
|
case "paste": {
|
|
if (typeof m.data !== "string") {
|
|
sendJson(res, 400, {
|
|
error: "bad_request",
|
|
message: "paste.data must be a string",
|
|
});
|
|
return;
|
|
}
|
|
await sendPaste(sessionId, m.data);
|
|
break;
|
|
}
|
|
default:
|
|
sendJson(res, 400, {
|
|
error: "bad_request",
|
|
message: `Unknown type: ${String(m.type)}`,
|
|
});
|
|
return;
|
|
}
|
|
} catch (err) {
|
|
sendJson(res, 500, { error: "internal_error", message: String(err) });
|
|
return;
|
|
}
|
|
|
|
res.writeHead(204).end();
|
|
}
|