Something went wrong. Try again.
Starship Simulator Controls thoriumsim.com
Something went wrong. Try again.
4.3 kB · 162 lines
TypeScript
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163import { NETREQUEST_PATH, NETSEND_PATH } from "../constants";
type HTTPHeaders = Record<string, string>;
export type HeadersResolver = HTTPHeaders | (() => HTTPHeaders | Promise<HTTPHeaders>);export type LiveQueryClientOptions = { baseUrl?: string; netSendPath?: string; netRequestPath?: string; headers?: HeadersResolver;};type RequestOptions = { signal?: AbortSignal; headers?: HeadersResolver; path: string; input: any;};
export class LiveQueryError extends Error { error: string; constructor(message: string, remoteError: string) { super(message); this.error = remoteError; }}/** * Thrown when a system fails the stability check. * The client-side checks for this error and displays * the proper toast message to the user. */export class SystemStabilityError extends Error { public error: string; public readonly errorType = "SystemStabilityError";
constructor( message: string, public title: string, ) { super(message); this.error = message; }}
export class LiveQueryClient { requestUrl: URL; sendUrl: URL; headers: HTTPHeaders | (() => HTTPHeaders | Promise<HTTPHeaders>); constructor({ baseUrl = typeof window === "undefined" ? "http://localhost:4444" : window.location.origin, netRequestPath = NETREQUEST_PATH, netSendPath = NETSEND_PATH, headers = {}, }: LiveQueryClientOptions = {}) { this.requestUrl = new URL(netRequestPath, baseUrl); this.sendUrl = new URL(netSendPath, baseUrl); this.headers = headers; } private async makeRequest( url: URL, body: any, signal?: AbortSignal, inputHeaders?: HeadersResolver, ) { const headers = new Headers(); Object.entries( typeof this.headers === "function" ? await this.headers() : this.headers, ).forEach(([key, val]) => { headers.append(key, val); }); Object.entries( typeof inputHeaders === "function" ? await inputHeaders() : inputHeaders || {}, ).forEach(([key, val]) => { headers.append(key, val); });
if (typeof body === "string") { headers.append("content-type", "application/json"); } let result: any = await fetch(url, { method: "POST", headers, body, signal, }).then(async (res) => { const response = await res.text();
if (!res.ok) { try { const parsed = JSON.parse(response); if (parsed.errorType === "SystemStabilityError") { throw new SystemStabilityError(parsed.error, parsed.title); } throw new LiveQueryError(`Error in request ${parsed.error}`, parsed.error); } catch (error) { if (error instanceof SystemStabilityError) { // We dynamically load this module so Playwright // doesn't get upset about loading an SVG later in // the dependency tree (await import("@thorium/context/ToastContext")).toast({ title: error.title, body: error.message, color: "error", }); } if (error instanceof LiveQueryError) throw error; throw new Error( `${res.status} Error in request: ${res.statusText}, Url: ${url}, Body: ${JSON.stringify( body, )}, Response: ${response}`, ); } } return response; });
try { result = JSON.parse(result); } catch { // Not JSON, apparently } if (result?.error) { throw new Error(result.error); }
return result; } async netRequest(opts: RequestOptions) { return await this.makeRequest( this.requestUrl, JSON.stringify({ path: opts.path, ...opts.input }), opts.signal, opts.headers, ); } async netSend(opts: RequestOptions) { const body = new FormData(); body.append("path", opts.path); let count = 0; for (const key in opts.input) { const value = opts.input[key]; if (value instanceof File) { body.append(key, value); opts.input[key] = {} as any; } else if (value instanceof Blob) { body.append(key, value, `blob-${count++}`); opts.input[key] = {} as any; } // Duck type the value into a FileList else if (value && typeof value === "object" && value.length && "item" in value) { for (let i = 0; i < value.length; i++) { body.append(`${key}[]`, value[i]); } opts.input[key] = [] as any; } } if (opts.input) { body.append("params", JSON.stringify(opts.input)); }
return await this.makeRequest(this.sendUrl, body, opts.signal, opts.headers); }}