Spaces:
Running
Running
File size: 5,572 Bytes
177c3f4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | /* ============================================================
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`);
},
};
|