John Costa 3ebc0810e7 Revert "frontend method to refresh image"
This reverts commit ce2cd977ac18c498e0601b3a5f631587f7cd5272.
2025-09-14 18:04:00 +01:00

299 lines
7.4 KiB
TypeScript

import { fetch } from "@tauri-apps/plugin-http";
import {
type InferOutput,
array,
literal,
null_,
nullable,
pipe,
safeParse,
strictObject,
string,
transform,
union,
uuid,
} from "valibot";
type BaseRequestParams = Partial<{
path: string;
body: RequestInit["body"];
method: "GET" | "POST" | "DELETE";
}>;
// export const base = "https://haystack.johncosta.tech";
export const base = "http://localhost:3040";
const getBaseRequest = ({ path, body, method }: BaseRequestParams): Request => {
return new Request(`${base}/${path}`, {
body,
method,
});
};
const getBaseAuthorizedRequest = ({
path,
body,
method,
}: BaseRequestParams): Request => {
return new Request(`${base}/${path}`, {
headers: {
Authorization: `Bearer ${localStorage.getItem("access")?.toString()}`,
},
body,
method,
});
};
const sendImageResponseValidator = strictObject({
ID: pipe(string(), uuid()),
ImageID: pipe(string(), uuid()),
UserID: pipe(string(), uuid()),
Status: string(),
});
export const sendImageFile = async (
imageName: string,
file: File,
): Promise<InferOutput<typeof sendImageResponseValidator>> => {
const request = getBaseAuthorizedRequest({
path: `images/${imageName}`,
body: file,
method: "POST",
});
request.headers.set("Content-Type", "application/oclet-stream");
const res = await fetch(request).then((res) => res.json());
const parsedRes = safeParse(sendImageResponseValidator, res);
if (!parsedRes.success) {
console.log(parsedRes.issues)
throw new Error(JSON.stringify(parsedRes.issues));
}
return parsedRes.output;
};
export const deleteImage = async (
imageID: string
): Promise<void> => {
const request = getBaseAuthorizedRequest({
path: `images/${imageID}`,
method: "DELETE",
});
await fetch(request);
}
export const deleteImageFromStack = async (listID: string, imageID: string): Promise<void> => {
const request = getBaseAuthorizedRequest({
path: `stacks/${listID}/${imageID}`,
method: "DELETE",
});
await fetch(request);
}
export class ImageLimitReached extends Error {
constructor() {
super();
}
}
export const sendImage = async (
imageName: string,
base64Image: string,
): Promise<InferOutput<typeof sendImageResponseValidator>> => {
const request = getBaseAuthorizedRequest({
path: `images/${imageName}`,
body: base64Image,
method: "POST",
});
request.headers.set("Content-Type", "application/base64");
const rawRes = await fetch(request);
if (!rawRes.ok && rawRes.status == 429) {
throw new ImageLimitReached()
}
const res = await rawRes.json();
const parsedRes = safeParse(sendImageResponseValidator, res);
if (!parsedRes.success) {
console.log(parsedRes.issues)
throw new Error(JSON.stringify(parsedRes.issues));
}
return parsedRes.output;
};
const imageMetaValidator = strictObject({
ID: pipe(string(), uuid()),
ImageName: string(),
Description: string(),
Image: null_(),
});
const userImageValidator = strictObject({
ID: pipe(string(), uuid()),
CreatedAt: pipe(string()),
ImageID: pipe(string(), uuid()),
UserID: pipe(string(), uuid()),
Image: strictObject({
...imageMetaValidator.entries,
ImageLists: pipe(nullable(array(
strictObject({
ID: pipe(string(), uuid()),
ImageID: pipe(string(), uuid()),
ListID: pipe(string(), uuid()),
}),
)), transform(l => l ?? [])),
}),
});
const userProcessingImageValidator = strictObject({
ID: pipe(string(), uuid()),
ImageID: pipe(string(), uuid()),
UserID: pipe(string(), uuid()),
Image: imageMetaValidator,
Status: union([
literal("not-started"),
literal("in-progress"),
literal("complete"),
]),
});
const listValidator = strictObject({
ID: pipe(string(), uuid()),
UserID: pipe(string(), uuid()),
CreatedAt: pipe(string()),
Name: string(),
Description: nullable(string()),
Images: pipe(
nullable(
array(
strictObject({
ID: pipe(string(), uuid()),
ImageID: pipe(string(), uuid()),
ListID: pipe(string(), uuid()),
Items: array(
strictObject({
ID: pipe(string(), uuid()),
ImageID: pipe(string(), uuid()),
SchemaItemID: pipe(string(), uuid()),
Value: string(),
}),
),
}),
),
),
transform((n) => n ?? []),
),
Schema: strictObject({
ID: pipe(string(), uuid()),
ListID: pipe(string(), uuid()),
SchemaItems: array(
strictObject({
ID: pipe(string(), uuid()),
SchemaID: pipe(string(), uuid()),
Item: string(),
Value: nullable(string()),
Description: string(),
}),
),
}),
});
export type List = InferOutput<typeof listValidator>;
const imageRequestValidator = strictObject({
userImages: array(userImageValidator),
processingImages: array(userProcessingImageValidator),
lists: array(listValidator),
});
export type JustTheImageWhatAreTheseNames = InferOutput<
typeof userImageValidator
>[];
export const getUserImages = async (): Promise<
InferOutput<typeof imageRequestValidator>
> => {
const request = getBaseAuthorizedRequest({ path: "images" });
const res = await fetch(request).then((res) => res.json());
console.log("Backend response: ", res);
const parsedRes = safeParse(imageRequestValidator, res);
if (!parsedRes.success) {
console.log(parsedRes.issues)
throw new Error(JSON.stringify(parsedRes.issues));
}
return parsedRes.output;
};
export const postLogin = async (email: string): Promise<void> => {
const request = getBaseRequest({
path: "auth/login",
body: JSON.stringify({ email }),
method: "POST",
});
await fetch(request);
};
const codeValidator = strictObject({
access: string(),
refresh: string(),
});
export const postCode = async (
email: string,
code: string,
): Promise<InferOutput<typeof codeValidator>> => {
const request = getBaseRequest({
path: "auth/code",
body: JSON.stringify({ email, code }),
method: "POST",
});
const res = await fetch(request).then((res) => res.json());
const parsedRes = safeParse(codeValidator, res);
if (!parsedRes.success) {
console.log(parsedRes.issues)
throw new Error(JSON.stringify(parsedRes.issues));
}
return parsedRes.output;
};
export class ReachedListLimit extends Error {
constructor() {
super();
}
}
export const createList = async (
title: string,
description: string,
): Promise<void> => {
const request = getBaseAuthorizedRequest({
path: "stacks",
method: "POST",
body: JSON.stringify({ title, description }),
});
request.headers.set("Content-Type", "application/json");
const res = await fetch(request);
if (!res.ok && res.status == 429) {
throw new ReachedListLimit();
}
};