Add per-task terminals over WebSocket with an xterm.js Terminal tab

This commit is contained in:
Ian Gulliver
2026-10-15 12:06:50 -07:00
parent 37bf1b60a7
commit ff22f33025
33 changed files with 1600 additions and 167 deletions
+15 -5
View File
@@ -52,11 +52,7 @@ export class ApiError extends Error {
}
}
export async function request<M extends Method, P extends PathsWith<M>>(
method: M,
path: P,
opts: Options<Op<P, M>> = {},
): Promise<Result<Op<P, M>>> {
function target(path: string, opts: { path?: unknown; query?: unknown }): string {
const pathParams = (opts.path ?? {}) as Record<string, unknown>;
let url: string = path.replace(/\{(\w+)\}/g, (_, key: string) => {
const value = pathParams[key];
@@ -75,7 +71,15 @@ export async function request<M extends Method, P extends PathsWith<M>>(
if (query.size > 0) {
url += `?${query}`;
}
return url;
}
export async function request<M extends Method, P extends PathsWith<M>>(
method: M,
path: P,
opts: Options<Op<P, M>> = {},
): Promise<Result<Op<P, M>>> {
const url = target(path, opts);
const init: RequestInit = { method: method.toUpperCase(), keepalive: opts.keepalive ?? false };
if (opts.body instanceof Blob) {
init.headers = { "Content-Type": opts.body.type || "application/octet-stream" };
@@ -105,6 +109,12 @@ export const post = <P extends PathsWith<"post">>(path: P, opts?: Options<Op<P,
export const put = <P extends PathsWith<"put">>(path: P, opts?: Options<Op<P, "put">>) => request("put", path, opts);
export const del = <P extends PathsWith<"delete">>(path: P, opts?: Options<Op<P, "delete">>) => request("delete", path, opts);
export function socket<P extends PathsWith<"get">>(path: P, opts: Options<Op<P, "get">>): WebSocket {
const ws = new WebSocket(`${location.protocol === "https:" ? "wss:" : "ws:"}//${location.host}${target(path, opts)}`);
ws.binaryType = "arraybuffer";
return ws;
}
const staleAfterMs = 40_000;
const retryAfterMs = 2_000;