157 lines
5.2 KiB
TypeScript
157 lines
5.2 KiB
TypeScript
import {
|
|
BookProject,
|
|
Chapter,
|
|
Entity,
|
|
Idea,
|
|
UserProfile
|
|
} from '../types';
|
|
|
|
const API_BASE_URL = '/api'; // Proxied by Vite
|
|
|
|
// --- API CLIENT GENERIC ---
|
|
|
|
const api = {
|
|
// Generic fetch with cookies
|
|
// Generic fetch with cookies
|
|
// Generic fetch with cookies
|
|
async request<T = any>(endpoint: string, options: RequestInit = {}) {
|
|
// Append Instance to query params
|
|
const instanceId = "54770_plumeia"; // Fallback if env missing in some contexts
|
|
const separator = endpoint.includes('?') ? '&' : '?';
|
|
const url = `${API_BASE_URL}${endpoint}${separator}Instance=${instanceId}`;
|
|
|
|
const headers = {
|
|
'Content-Type': 'application/json',
|
|
'X-Database-Instance': instanceId, // Keep header just in case
|
|
...options.headers,
|
|
};
|
|
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers,
|
|
credentials: 'include', // IMPORTANT: Send cookies
|
|
});
|
|
|
|
if (!response.ok) {
|
|
let errorMsg = `Error ${response.status}: ${response.statusText}`;
|
|
try {
|
|
const errorJson = await response.json();
|
|
console.error("API Error JSON:", errorJson);
|
|
if (errorJson.error) errorMsg = errorJson.error;
|
|
if (errorJson.message) errorMsg = errorJson.message;
|
|
} catch (e) {
|
|
// Ignore json parse error
|
|
}
|
|
throw new Error(errorMsg);
|
|
}
|
|
|
|
// Return null if 204 No Content
|
|
if (response.status === 204) return null;
|
|
|
|
return response.json();
|
|
},
|
|
|
|
// --- AUTH ENDPOINTS ---
|
|
auth: {
|
|
async getSession() {
|
|
try {
|
|
return await api.request('/user-auth/get-session');
|
|
} catch (e) {
|
|
return null; // No session
|
|
}
|
|
},
|
|
|
|
async signIn(email: string, password: string) {
|
|
return api.request('/user-auth/sign-in/email', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ email, password }),
|
|
});
|
|
},
|
|
|
|
async signUp(email: string, password: string, name: string) {
|
|
return api.request('/user-auth/sign-up/email', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ email, password, name }),
|
|
});
|
|
},
|
|
|
|
async signOut() {
|
|
return api.request('/user-auth/sign-out', {
|
|
method: 'POST',
|
|
});
|
|
}
|
|
},
|
|
|
|
// --- DATA ENDPOINTS ---
|
|
data: {
|
|
// Generic list (read all)
|
|
async list<T>(table: string) {
|
|
// Swagger: GET /read/{table} -> { status: "success", data: [...] }
|
|
const res = await api.request<{ data: T[] }>(`/data/read/${table}`);
|
|
return res.data || [];
|
|
},
|
|
|
|
// Generic get (read one)
|
|
async get<T>(table: string, id: string) {
|
|
// Swagger: GET /read/{table}/{id} -> { status: "success", data: { ... } }
|
|
const res = await api.request<{ data: T }>(`/data/read/${table}/${id}`);
|
|
return res.data;
|
|
},
|
|
|
|
// Generic create
|
|
async create<T>(table: string, data: any) {
|
|
// Swagger: POST /create/{table} -> { status: "success", id: 123 }
|
|
// Return the whole response so caller can get ID
|
|
return api.request(`/data/create/${table}`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
}) as Promise<T>;
|
|
},
|
|
|
|
// Generic update
|
|
async update<T>(table: string, id: string, data: any) {
|
|
// Swagger: PUT /update/{table}/{id}
|
|
// Note: Swagger for update usually expects "update" path prefix
|
|
return api.request(`/data/update/${table}/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(data),
|
|
}) as Promise<T>;
|
|
},
|
|
|
|
// Generic delete
|
|
async delete(table: string, id: string) {
|
|
// Swagger: DELETE /delete/{table}/{id}
|
|
return api.request(`/data/delete/${table}/${id}`, {
|
|
method: 'DELETE',
|
|
});
|
|
},
|
|
|
|
// --- Specialized Project Methods ---
|
|
|
|
// Fetch full project with related data (chapters, entities, etc)
|
|
// NOTE: In a real app, you might want to fetch these separately or use a join if supported.
|
|
// For now, we'll fetch the project and then fetch its children.
|
|
async getFullProject(projectId: string): Promise<BookProject> {
|
|
const project = await this.get<any>('projects', projectId);
|
|
|
|
// Fetch related data in parallel
|
|
const [chapters, entities, ideas] = await Promise.all([
|
|
api.request(`/data/chapters/list?project_id=${projectId}`),
|
|
api.request(`/data/entities/list?project_id=${projectId}`),
|
|
api.request(`/data/ideas/list?project_id=${projectId}`),
|
|
]);
|
|
|
|
return {
|
|
...project,
|
|
chapters: chapters || [],
|
|
entities: entities || [],
|
|
ideas: ideas || [],
|
|
// templates: [], // Not yet in DB
|
|
// workflow: null // Not yet in DB
|
|
};
|
|
}
|
|
}
|
|
};
|
|
|
|
export default api;
|