Holded_Blog / lib /api.js
Shinhati2023's picture
Create lib/api.js
177c3f4 verified
/* ============================================================
GLASSGRID — API LAYER
All data operations go through this layer.
Zero UI modification. Returns structured data objects.
Uses Schema for validation.
============================================================ */
'use strict';
import { validate, applyDefaults } from '../data/schema.js';
const BASE_URL = '/api'; // Replace with your backend URL
async function request(method, endpoint, body = null, headers = {}) {
const token = localStorage.getItem('gg_auth_token');
const opts = {
method,
headers: {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
...headers,
},
...(body ? { body: JSON.stringify(body) } : {}),
};
const res = await fetch(`${BASE_URL}${endpoint}`, opts);
if (!res.ok) {
const err = await res.json().catch(() => ({ message: `HTTP ${res.status}` }));
throw new Error(err.message || `Request failed: ${res.status}`);
}
return res.json();
}
export const api = {
// ── Auth ──────────────────────────────
async login(identifier, password) {
const data = await request('POST', '/auth/login', { identifier, password });
if (data.token) localStorage.setItem('gg_auth_token', data.token);
return data;
},
async logout() {
localStorage.removeItem('gg_auth_token');
await request('POST', '/auth/logout').catch(() => {});
},
async register(username, email, password) {
return request('POST', '/auth/register', { username, email, password });
},
async getCurrentUser() {
return request('GET', '/auth/me');
},
// ── Posts ─────────────────────────────
async getFeed(cursor = null, limit = 20) {
const q = new URLSearchParams({ limit });
if (cursor) q.set('cursor', cursor);
return request('GET', `/posts/feed?${q}`);
},
async getExplorePosts(cursor = null, limit = 30) {
const q = new URLSearchParams({ limit });
if (cursor) q.set('cursor', cursor);
return request('GET', `/posts/explore?${q}`);
},
async getPost(postId) {
return request('GET', `/posts/${postId}`);
},
async createPost(formData) {
const token = localStorage.getItem('gg_auth_token');
const res = await fetch(`${BASE_URL}/posts`, {
method: 'POST',
headers: { ...(token ? { Authorization: `Bearer ${token}` } : {}) },
body: formData, // multipart/form-data for image upload
});
if (!res.ok) throw new Error(`Upload failed: ${res.status}`);
return res.json();
},
async deletePost(postId) {
return request('DELETE', `/posts/${postId}`);
},
// ── Likes ─────────────────────────────
async likePost(postId) {
return request('POST', `/posts/${postId}/like`);
},
async unlikePost(postId) {
return request('DELETE', `/posts/${postId}/like`);
},
async likeComment(commentId) {
return request('POST', `/comments/${commentId}/like`);
},
// ── Comments ──────────────────────────
async getComments(postId, cursor = null) {
const q = new URLSearchParams({ limit: 20 });
if (cursor) q.set('cursor', cursor);
return request('GET', `/posts/${postId}/comments?${q}`);
},
async addComment(postId, text, parentId = null) {
return request('POST', `/posts/${postId}/comments`, { text, parentId });
},
async deleteComment(commentId) {
return request('DELETE', `/comments/${commentId}`);
},
// ── Users ─────────────────────────────
async getUser(username) {
return request('GET', `/users/${username}`);
},
async getUserPosts(userId, cursor = null) {
const q = new URLSearchParams({ limit: 21 });
if (cursor) q.set('cursor', cursor);
return request('GET', `/users/${userId}/posts?${q}`);
},
async followUser(userId) {
return request('POST', `/users/${userId}/follow`);
},
async unfollowUser(userId) {
return request('DELETE', `/users/${userId}/follow`);
},
async updateProfile(data) {
return request('PATCH', '/users/me', data);
},
// ── Stories ───────────────────────────
async getStories() {
return request('GET', '/stories');
},
async viewStory(storyId) {
return request('POST', `/stories/${storyId}/view`);
},
// ── Config (Admin) ────────────────────
async getConfig() {
return request('GET', '/admin/config');
},
async updateConfig(config) {
return request('PATCH', '/admin/config', config);
},
async updateFeatureFlag(featureKey, enabled) {
return request('PATCH', `/admin/features/${featureKey}`, { enabled });
},
// ── Moderation (Admin) ────────────────
async getModerationQueue() {
return request('GET', '/admin/moderation');
},
async approvePost(postId) {
return request('POST', `/admin/posts/${postId}/approve`);
},
async removePost(postId, reason) {
return request('DELETE', `/admin/posts/${postId}`, { reason });
},
async banUser(userId, reason) {
return request('POST', `/admin/users/${userId}/ban`, { reason });
},
async unbanUser(userId) {
return request('DELETE', `/admin/users/${userId}/ban`);
},
};