import { TinyRpcClientAdapter, TinyRpcError } from "@hiogawa/tiny-rpc"; import { Result } from "@hiogawa/utils"; const GET_PAYLOAD_PARAM = "payload"; export function httpClientAdapter(opts: { url: string; pathsForGET?: string[]; JSON?: Partial; headers?: () => Promise> | Record; }): TinyRpcClientAdapter { const JSON: JsonTransformer = { parse: globalThis.JSON.parse, stringify: globalThis.JSON.stringify, ...opts.JSON, }; return { send: async (data) => { const url = [opts.url, data.path].join("/"); const payload = JSON.stringify(data.args); console.log("RPC Request:", payload); const method = opts.pathsForGET?.includes(data.path) ? "GET" : "POST"; const extraHeaders = opts.headers ? await opts.headers() : {}; let req: Request; if (method === "GET") { req = new Request( url + "?" + new URLSearchParams({ [GET_PAYLOAD_PARAM]: payload }), { headers: extraHeaders } ); } else { req = new Request(url, { method: "POST", body: payload, headers: { "content-type": "application/json; charset=utf-8", ...extraHeaders }, credentials: "include", }); } let res: Response; res = await fetch(req); if (!res.ok) { // throw new Error(`HTTP error: ${res.status}`); throw new Error( JSON.stringify({ status: res.status, statusText: res.statusText, data: { message: await res.text() }, internal: true, }) ); // throw TinyRpcError.deserialize(res.status); } const result: Result = JSON.parse( await res.text() ); if (!result.ok) { throw TinyRpcError.deserialize(result.value); } return result.value; }, }; }