DiffWeave / studio /src /api /client.js
shak3008's picture
feat: two-tier workspace templates, professional policy CI rules, dynamic truth register, and public/private access management
03ed280
Raw History Blame Contribute Delete
12.5 kB
/**
* DiffWeave Studio API Client
* Talks directly to the FastAPI bridge, which delegates to DocWeave MCP Server.
* Supports Bearer token authentication and user sessions.
*/
export const CLOUD_BACKEND_URL = 'https://shak3008-diffweave.hf.space';
export function getApiBase() {
if (typeof window !== 'undefined') {
// If running on Vercel or any external static preview, route to HF Space backend
if (window.location.hostname.includes('vercel.app')) {
return `${CLOUD_BACKEND_URL}/api`;
}
}
return '/api';
}
export const API_BASE = getApiBase();
function getHeaders(custom = {}) {
const token = localStorage.getItem('diffweave_token');
const headers = { 'Content-Type': 'application/json', ...custom };
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
return headers;
}
export const api = {
// -------------------------------------------------------------------------
// Authentication & Session
// -------------------------------------------------------------------------
async signup(username, email, password) {
const res = await fetch(`${API_BASE}/auth/signup`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, email, password }),
});
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
if (data.access_token) {
localStorage.setItem('diffweave_token', data.access_token);
localStorage.setItem('diffweave_user', JSON.stringify(data));
}
return data;
},
async login(username, password) {
const res = await fetch(`${API_BASE}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
if (data.access_token) {
localStorage.setItem('diffweave_token', data.access_token);
localStorage.setItem('diffweave_user', JSON.stringify(data));
}
return data;
},
async demoLogin() {
const res = await fetch(`${API_BASE}/auth/demo-login`, { method: 'POST' });
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
if (data.access_token) {
localStorage.setItem('diffweave_token', data.access_token);
localStorage.setItem('diffweave_user', JSON.stringify(data));
}
return data;
},
setApiKey(token) {
localStorage.setItem('diffweave_token', token);
localStorage.setItem('diffweave_user', JSON.stringify({ email: 'api-key-user', username: 'API Key User' }));
},
logout() {
localStorage.removeItem('diffweave_token');
localStorage.removeItem('diffweave_user');
},
async generateKey(name = 'CLI Personal Access Token', expiresInDays = 90) {
const res = await fetch(`${API_BASE}/auth/generate-key`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ name, expires_in_days: expiresInDays }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async syncCLI(token, email, username) {
const res = await fetch(`${API_BASE}/auth/sync-cli`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ access_token: token, email, username }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async getWhoami() {
try {
const res = await fetch(`${API_BASE}/auth/whoami`, { headers: getHeaders() });
if (res.ok) return await res.json();
return null;
} catch {
return null;
}
},
getCurrentUser() {
try {
const u = localStorage.getItem('diffweave_user');
return u ? JSON.parse(u) : null;
} catch {
return null;
}
},
// -------------------------------------------------------------------------
// Health & MCP
// -------------------------------------------------------------------------
async getHealth() {
const res = await fetch(`${API_BASE}/health`, { headers: getHeaders() });
return res.json();
},
async getMCPTools() {
const res = await fetch(`${API_BASE}/mcp/tools`, { headers: getHeaders() });
return res.json();
},
// -------------------------------------------------------------------------
// Workspaces
// -------------------------------------------------------------------------
async getWorkspaces() {
const res = await fetch(`${API_BASE}/workspaces`, { headers: getHeaders() });
return res.json();
},
async createWorkspace(name, description = '', template = 'empty', visibility = 'private') {
const res = await fetch(`${API_BASE}/workspaces`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ name, description, template, visibility }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async deleteWorkspace(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}`, {
method: 'DELETE',
headers: getHeaders(),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async batchDeleteWorkspaces(workspaceIds = [], deleteAll = false) {
const res = await fetch(`${API_BASE}/workspaces/batch-delete`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ workspace_ids: workspaceIds, delete_all: deleteAll }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async getWorkspaceStatus(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/status`, { headers: getHeaders() });
return res.json();
},
// -------------------------------------------------------------------------
// Access & Collaborators
// -------------------------------------------------------------------------
async getWorkspaceAccess(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/access`, { headers: getHeaders() });
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async updateWorkspaceVisibility(workspaceId, visibility) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/access/visibility`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ visibility }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async addWorkspaceMember(workspaceId, email, role = 'EDITOR') {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/access/members`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ email, role }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async removeWorkspaceMember(workspaceId, memberId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/access/members/${memberId}`, {
method: 'DELETE',
headers: getHeaders(),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async updateWorkspaceMemberRole(workspaceId, memberId, role) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/access/members/${memberId}`, {
method: 'PATCH',
headers: getHeaders(),
body: JSON.stringify({ role }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
// -------------------------------------------------------------------------
// Documents
// -------------------------------------------------------------------------
async getDocuments(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/documents`, { headers: getHeaders() });
return res.json();
},
async uploadDocument(workspaceId, file) {
const formData = new FormData();
formData.append('file', file);
const token = localStorage.getItem('diffweave_token');
const headers = {};
if (token) headers['Authorization'] = `Bearer ${token}`;
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/upload`, {
method: 'POST',
headers,
body: formData,
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
// -------------------------------------------------------------------------
// Proposals & PRs
// -------------------------------------------------------------------------
async getProposals(workspaceId, status) {
const url = status
? `${API_BASE}/workspaces/${workspaceId}/proposals?status=${status}`
: `${API_BASE}/workspaces/${workspaceId}/proposals`;
const res = await fetch(url, { headers: getHeaders() });
return res.json();
},
async createProposal(workspaceId, payload) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/proposals`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify(payload),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async reviewProposal(workspaceId, proposalId, decision, comments = '') {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/proposals/${proposalId}/review`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ decision, comments }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async batchReview(workspaceId, decision, proposalIds = null, comments = '') {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/proposals/batch-review`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ decision, proposal_ids: proposalIds, comments }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
// -------------------------------------------------------------------------
// Semantic Diff
// -------------------------------------------------------------------------
async getSemanticDiff(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/diff`, { headers: getHeaders() });
return res.json();
},
// -------------------------------------------------------------------------
// Policy Rules
// -------------------------------------------------------------------------
async getRules(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/rules`, { headers: getHeaders() });
return res.json();
},
async createRule(workspaceId, name, operator, configuration) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/rules`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ name, operator, configuration }),
});
if (!res.ok) throw new Error(await res.text());
return res.json();
},
async deleteRule(ruleId) {
const res = await fetch(`${API_BASE}/rules/${ruleId}`, {
method: 'DELETE',
headers: getHeaders(),
});
return res.json();
},
async validateProposals(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/validate`, { headers: getHeaders() });
return res.json();
},
// -------------------------------------------------------------------------
// Knowledge Register & Graph
// -------------------------------------------------------------------------
async getKnowledgeItems(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/knowledge`, { headers: getHeaders() });
return res.json();
},
async searchKnowledge(workspaceId, query) {
const res = await fetch(
`${API_BASE}/workspaces/${workspaceId}/knowledge/search?q=${encodeURIComponent(query)}`,
{ headers: getHeaders() }
);
return res.json();
},
async getKnowledgeGraph(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/graph`, { headers: getHeaders() });
return res.json();
},
// -------------------------------------------------------------------------
// Audit Trail & Metrics
// -------------------------------------------------------------------------
async getActivityFeed(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/activity`, { headers: getHeaders() });
return res.json();
},
async getWorkflows(workspaceId) {
const res = await fetch(`${API_BASE}/workspaces/${workspaceId}/workflows`, { headers: getHeaders() });
return res.json();
},
};