diff --git a/surfsense_web/lib/apis/auth-api.service.ts b/surfsense_web/lib/apis/auth-api.service.ts index 3a8933d22..40d496354 100644 --- a/surfsense_web/lib/apis/auth-api.service.ts +++ b/surfsense_web/lib/apis/auth-api.service.ts @@ -9,7 +9,7 @@ import { import { ValidationError } from "../error"; import { baseApiService } from "./base-api.service"; -export class AuthApiService { + class AuthApiService { login = async (request: LoginRequest) => { // Validate the request const parsedRequest = loginRequest.safeParse(request); diff --git a/surfsense_web/lib/apis/base-api.service.ts b/surfsense_web/lib/apis/base-api.service.ts index d95d2e417..0d59a640a 100644 --- a/surfsense_web/lib/apis/base-api.service.ts +++ b/surfsense_web/lib/apis/base-api.service.ts @@ -6,13 +6,21 @@ import { NotFoundError, } from "../error"; +enum ResponseType { + JSON = "json", + TEXT = "text", + BLOB = "blob", + ARRAY_BUFFER = "arrayBuffer", + // Add more response types as needed +} + export type RequestOptions = { method: "GET" | "POST" | "PUT" | "DELETE"; headers?: Record; contentType?: "application/json" | "application/x-www-form-urlencoded"; signal?: AbortSignal; body?: any; - responseType?: "json" | "text" | "blob" | "arrayBuffer"; // Add more response types as needed + responseType?: ResponseType; // Add more options as needed }; @@ -35,11 +43,21 @@ class BaseApiService { this.bearerToken = bearerToken; } - async request( + async request( url: string, responseSchema?: z.ZodSchema, - options?: RequestOptions - ): Promise { + options?: RequestOptions & { responseType?: R } + ): Promise< + R extends ResponseType.JSON + ? T + : R extends ResponseType.TEXT + ? string + : R extends ResponseType.BLOB + ? Blob + : R extends ResponseType.ARRAY_BUFFER + ? ArrayBuffer + : unknown + > { try { const defaultOptions: RequestOptions = { headers: { @@ -47,7 +65,7 @@ class BaseApiService { Authorization: `Bearer ${this.bearerToken || ""}`, }, method: "GET", - responseType: "json", + responseType: ResponseType.JSON, }; const mergedOptions: RequestOptions = { @@ -125,20 +143,20 @@ class BaseApiService { // biome-ignore lint/suspicious: Unknown let data; - const responseType = mergedOptions.responseType || "json"; + const responseType = mergedOptions.responseType try { switch (responseType) { - case "json": + case ResponseType.JSON: data = await response.json(); break; - case "text": + case ResponseType.TEXT: data = await response.text(); break; - case "blob": + case ResponseType.BLOB: data = await response.blob(); break; - case "arrayBuffer": + case ResponseType.ARRAY_BUFFER: data = await response.arrayBuffer(); break; // Add more cases as needed @@ -154,7 +172,7 @@ class BaseApiService { ); } - if (responseType === "json") { + if (responseType === ResponseType.JSON) { if (!responseSchema) { return data; } @@ -181,44 +199,59 @@ class BaseApiService { async get( url: string, responseSchema?: z.ZodSchema, - options?: Omit + options?: Omit ) { return this.request(url, responseSchema, { ...options, method: "GET", + responseType: ResponseType.JSON, }); } async post( url: string, responseSchema?: z.ZodSchema, - options?: Omit + options?: Omit ) { return this.request(url, responseSchema, { method: "POST", ...options, + responseType: ResponseType.JSON, }); } async put( url: string, responseSchema?: z.ZodSchema, - options?: Omit + options?: Omit ) { return this.request(url, responseSchema, { method: "PUT", ...options, + responseType: ResponseType.JSON, }); } async delete( url: string, responseSchema?: z.ZodSchema, - options?: Omit + options?: Omit, ) { return this.request(url, responseSchema, { method: "DELETE", ...options, + responseType: ResponseType.JSON, + }); + } + + async getBlob( + url: string, + options?: Omit + ) { + return this.request(url, undefined, { + ...options, + method: "GET", + responseType: ResponseType.BLOB, }); } } diff --git a/surfsense_web/lib/apis/chats-api.service.ts b/surfsense_web/lib/apis/chats-api.service.ts index 69cfab831..d6d309106 100644 --- a/surfsense_web/lib/apis/chats-api.service.ts +++ b/surfsense_web/lib/apis/chats-api.service.ts @@ -17,7 +17,7 @@ import { import { ValidationError } from "../error"; import { baseApiService } from "./base-api.service"; -export class ChatApiService { + class ChatApiService { getChatDetails = async (request: GetChatDetailsRequest) => { // Validate the request const parsedRequest = getChatDetailsRequest.safeParse(request); @@ -127,4 +127,4 @@ export class ChatApiService { }; } -export const chatApiService = new ChatApiService(); +export const chatsApiService = new ChatApiService(); diff --git a/surfsense_web/lib/apis/podcasts.api.ts b/surfsense_web/lib/apis/podcasts.api.ts deleted file mode 100644 index beaa475ca..000000000 --- a/surfsense_web/lib/apis/podcasts.api.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { PodcastItem } from "@/app/dashboard/[search_space_id]/podcasts/podcasts-client"; -import type { GeneratePodcastRequest } from "@/components/chat/ChatPanel/ChatPanelContainer"; - -export const getPodcastByChatId = async (chatId: string, authToken: string) => { - const response = await fetch( - `${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/podcasts/by-chat/${Number(chatId)}`, - { - headers: { - Authorization: `Bearer ${authToken}`, - }, - method: "GET", - } - ); - - if (!response.ok) { - const errorData = await response.json().catch(() => ({})); - throw new Error(errorData.detail || "Failed to fetch podcast"); - } - - return (await response.json()) as PodcastItem | null; -}; - -export const generatePodcast = async (request: GeneratePodcastRequest, authToken: string) => { - const response = await fetch( - `${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/podcasts/generate/`, - { - method: "POST", - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - body: JSON.stringify(request), - } - ); - - if (!response.ok) { - const errorData = await response.json().catch(() => ({})); - throw new Error(errorData.detail || "Failed to generate podcast"); - } - - return await response.json(); -}; - -export const loadPodcast = async (podcast: PodcastItem, authToken: string) => { - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 30000); - - try { - const response = await fetch( - `${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/podcasts/${podcast.id}/stream`, - { - headers: { - Authorization: `Bearer ${authToken}`, - }, - signal: controller.signal, - } - ); - - if (!response.ok) { - throw new Error(`Failed to fetch audio stream: ${response.statusText}`); - } - - const blob = await response.blob(); - const objectUrl = URL.createObjectURL(blob); - return objectUrl; - } catch (error) { - if (error instanceof DOMException && error.name === "AbortError") { - throw new Error("Request timed out. Please try again."); - } - throw error; - } finally { - clearTimeout(timeoutId); - } -};