feat: uv config other feats

- add uv configuration for the backend
- update frontend to make auth work
- add new auth endpoints
- add bookmars feat
- add reader feat
This commit is contained in:
2026-06-03 22:06:01 -05:00
parent 730c748f5f
commit 6b4c0c43f8
137 changed files with 20319 additions and 2340 deletions
+40
View File
@@ -0,0 +1,40 @@
import axios from "axios";
function messagesFromValue(value: unknown): string[] {
if (value == null) return [];
if (typeof value === "string") return [value];
if (Array.isArray(value)) return value.flatMap(messagesFromValue);
if (typeof value === "object") {
const record = value as Record<string, unknown>;
if ("detail" in record) {
const fromDetail = messagesFromValue(record.detail);
if (fromDetail.length > 0) return fromDetail;
}
const messages: string[] = [];
for (const [key, nested] of Object.entries(record)) {
if (key === "detail") continue;
for (const part of messagesFromValue(nested)) {
messages.push(key === "non_field_errors" ? part : `${key}: ${part}`);
}
}
return messages;
}
return [];
}
/** Extract human-readable message(s) from a Django REST Framework / axios error response. */
export function getApiErrorMessage(err: unknown, fallback = "Something went wrong"): string {
if (axios.isAxiosError(err)) {
const data = err.response?.data;
if (data !== undefined) {
const messages = messagesFromValue(data);
if (messages.length > 0) return messages.join(". ");
}
if (err.response?.status && err.message.startsWith("Request failed")) {
return fallback;
}
return err.message || fallback;
}
if (err instanceof Error) return err.message;
return fallback;
}