import useSWR, { SWRResponse } from "swr" import { RunnerApi, ExampleApi } from "slam-types" import { useState } from "react" const RUNNER_API_URL = String(import.meta.env.VITE_RUNNER_API_URL) const EXAMPLE_API_URL = String(import.meta.env.VITE_EXAMPLE_API_URL) const fetcher = (baseUrl: string) => (path: string) => fetch(`${baseUrl}${path}`) .then(res => res.json()) .catch((err) => { console.error(`An error occurred when fetching API path ${path}`) console.error(err) throw err }) export interface APISuccess { readonly type: "success" data: D } export interface APILoading { readonly type: "loading" } export interface APIFailed { readonly type: "failed" error: E } export interface APINotYetRequested { readonly type: "not_yet_requested" } export type APIResult = APISuccess | APILoading | APIFailed | APINotYetRequested const mapSWRResult = ({ data, error }: SWRResponse): APIResult => { if (error !== undefined) { return { type: "failed", error } } const isLoading = data === undefined if (isLoading) { return { type: "loading" } } return { type: "success", data } } interface BasePostRequest { baseUrl: string path: string body: R } const postRequest = async ({ baseUrl, path, body }: BasePostRequest, opts?: any): Promise> => { const url = `${baseUrl}${path}` const body_ = typeof body === "string" ? body : JSON.stringify(body) try { const resp = await fetch(url, { method: "POST", body: body_, headers: { "Content-Type": "application/json", }, ...opts }) if (resp.status >= 400) { throw new Error(`${url} responded with ${resp.status}: ${resp.text}`) } const data = await resp.json() return { type: "success", data } } catch (err: any) { console.error(`An error occurred when POSTing to API path ${path}`) console.error(err) return { type: "failed", error: err } } } export const useExamples = () => mapSWRResult( useSWR(ExampleApi.ListRequest.path, fetcher(EXAMPLE_API_URL)), ) export type SubmitResult = APIResult const postSource = async (text: string): Promise => { const apiResult = await postRequest( { baseUrl: RUNNER_API_URL, path: RunnerApi.SubmitRequest.path, body: { source: text, }, }, ) switch (apiResult.type) { case "success": return { type: "success", data: apiResult.data.result } case "failed": return { type: "failed", error: apiResult.error } case "not_yet_requested": case "loading": return apiResult } } export const useSubmitSource = () => { const [result, setResult] = useState({ type: "not_yet_requested" }) const submitSource = async (text: string) => { try { setResult({ type: "loading" }) const apiResult = await postRequest( { baseUrl: RUNNER_API_URL, path: RunnerApi.SubmitRequest.path, body: { source: text, }, }, ) switch (apiResult.type) { case "success": setResult({ type: "success", data: apiResult.data.result }) break case "failed": setResult({ type: "failed", error: apiResult.error }) break default: break } } catch (err: any) { setResult({ type: "failed", error: err }) } } return { result, submitSource } }