Changeset 0.6.0 (#36)
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
// ==========================================
|
||||
// Chat Switchboard – API Client (v0.5.0)
|
||||
// Chat Switchboard – API Client (v0.6.2)
|
||||
// ==========================================
|
||||
// Backend-only mode. Handles auth tokens and
|
||||
// all HTTP calls. No offline fallback.
|
||||
//
|
||||
// BASE_PATH: injected via index.html <script>
|
||||
// at container startup. All API paths are
|
||||
// prefixed automatically.
|
||||
// ==========================================
|
||||
|
||||
const BASE = window.__BASE__ || '';
|
||||
const _storageKey = BASE ? `sb_auth_${BASE.replace(/\//g, '')}` : 'sb_auth';
|
||||
|
||||
const API = {
|
||||
accessToken: null,
|
||||
refreshToken: null,
|
||||
@@ -15,7 +22,7 @@ const API = {
|
||||
|
||||
loadTokens() {
|
||||
try {
|
||||
const saved = JSON.parse(localStorage.getItem('sb_auth') || 'null');
|
||||
const saved = JSON.parse(localStorage.getItem(_storageKey) || 'null');
|
||||
if (saved) {
|
||||
this.accessToken = saved.accessToken || null;
|
||||
this.refreshToken = saved.refreshToken || null;
|
||||
@@ -25,7 +32,7 @@ const API = {
|
||||
},
|
||||
|
||||
saveTokens() {
|
||||
localStorage.setItem('sb_auth', JSON.stringify({
|
||||
localStorage.setItem(_storageKey, JSON.stringify({
|
||||
accessToken: this.accessToken,
|
||||
refreshToken: this.refreshToken,
|
||||
user: this.user
|
||||
@@ -36,7 +43,7 @@ const API = {
|
||||
this.accessToken = null;
|
||||
this.refreshToken = null;
|
||||
this.user = null;
|
||||
localStorage.removeItem('sb_auth');
|
||||
localStorage.removeItem(_storageKey);
|
||||
},
|
||||
|
||||
get isAuthed() { return !!this.accessToken; },
|
||||
@@ -45,7 +52,7 @@ const API = {
|
||||
// ── Auth ─────────────────────────────────
|
||||
|
||||
async health() {
|
||||
const resp = await fetch('/api/v1/health', { signal: AbortSignal.timeout(8000) });
|
||||
const resp = await fetch(BASE + '/api/v1/health', { signal: AbortSignal.timeout(8000) });
|
||||
if (!resp.ok) throw new Error(`Health: ${resp.status}`);
|
||||
return resp.json();
|
||||
},
|
||||
@@ -58,7 +65,7 @@ const API = {
|
||||
|
||||
async register(username, email, password) {
|
||||
const data = await this._post('/api/v1/auth/register', { username, email, password }, true);
|
||||
this._setAuth(data);
|
||||
if (!data.pending) this._setAuth(data);
|
||||
return data;
|
||||
},
|
||||
|
||||
@@ -92,36 +99,39 @@ const API = {
|
||||
this.saveTokens();
|
||||
},
|
||||
|
||||
// ── Chats ────────────────────────────────
|
||||
// ── Channels ──────────────────────────────
|
||||
|
||||
listChats(page = 1, perPage = 100) {
|
||||
return this._get(`/api/v1/chats?page=${page}&per_page=${perPage}`);
|
||||
listChannels(page = 1, perPage = 100, type = '') {
|
||||
let url = `/api/v1/channels?page=${page}&per_page=${perPage}`;
|
||||
if (type) url += `&type=${type}`;
|
||||
return this._get(url);
|
||||
},
|
||||
createChat(title, model, systemPrompt) {
|
||||
const body = { title };
|
||||
createChannel(title, model, systemPrompt, type = 'direct') {
|
||||
const body = { title, type };
|
||||
if (model) body.model = model;
|
||||
if (systemPrompt) body.system_prompt = systemPrompt;
|
||||
return this._post('/api/v1/chats', body);
|
||||
return this._post('/api/v1/channels', body);
|
||||
},
|
||||
getChat(id) { return this._get(`/api/v1/chats/${id}`); },
|
||||
updateChat(id, updates) { return this._put(`/api/v1/chats/${id}`, updates); },
|
||||
deleteChat(id) { return this._del(`/api/v1/chats/${id}`); },
|
||||
getChannel(id) { return this._get(`/api/v1/channels/${id}`); },
|
||||
updateChannel(id, updates) { return this._put(`/api/v1/channels/${id}`, updates); },
|
||||
deleteChannel(id) { return this._del(`/api/v1/channels/${id}`); },
|
||||
|
||||
// ── Messages ─────────────────────────────
|
||||
|
||||
listMessages(chatId, page = 1, perPage = 200) {
|
||||
return this._get(`/api/v1/chats/${chatId}/messages?page=${page}&per_page=${perPage}`);
|
||||
listMessages(channelId, page = 1, perPage = 200) {
|
||||
return this._get(`/api/v1/channels/${channelId}/messages?page=${page}&per_page=${perPage}`);
|
||||
},
|
||||
|
||||
// ── Completions ──────────────────────────
|
||||
|
||||
async streamCompletion(chatId, content, model, signal) {
|
||||
const body = { chat_id: chatId, content, stream: true };
|
||||
async streamCompletion(channelId, content, model, signal, apiConfigId) {
|
||||
const body = { channel_id: channelId, content, stream: true };
|
||||
if (model) body.model = model;
|
||||
if (apiConfigId) body.api_config_id = apiConfigId;
|
||||
// Only send max_tokens if user explicitly set it (non-zero = override)
|
||||
if (App.settings.maxTokens > 0) body.max_tokens = App.settings.maxTokens;
|
||||
|
||||
let resp = await fetch('/api/v1/chat/completions', {
|
||||
let resp = await fetch(BASE + '/api/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: this._authHeaders(),
|
||||
body: JSON.stringify(body),
|
||||
@@ -130,7 +140,7 @@ const API = {
|
||||
|
||||
if (resp.status === 401 && this.refreshToken) {
|
||||
if (await this.refresh()) {
|
||||
resp = await fetch('/api/v1/chat/completions', {
|
||||
resp = await fetch(BASE + '/api/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: this._authHeaders(),
|
||||
body: JSON.stringify(body),
|
||||
@@ -182,6 +192,7 @@ const API = {
|
||||
adminToggleActive(id, active) { return this._put(`/api/v1/admin/users/${id}/active`, { is_active: active }); },
|
||||
adminDeleteUser(id) { return this._del(`/api/v1/admin/users/${id}`); },
|
||||
adminGetSettings() { return this._get('/api/v1/admin/settings'); },
|
||||
getPublicSettings() { return this._get('/api/v1/settings/public'); },
|
||||
adminUpdateSetting(key, value) { return this._put(`/api/v1/admin/settings/${key}`, value); },
|
||||
adminGetStats() { return this._get('/api/v1/admin/stats'); },
|
||||
|
||||
@@ -196,8 +207,12 @@ const API = {
|
||||
adminListModels() { return this._get('/api/v1/admin/models'); },
|
||||
adminFetchModels() { return this._post('/api/v1/admin/models/fetch', {}); },
|
||||
adminUpdateModel(id, updates) { return this._put(`/api/v1/admin/models/${id}`, updates); },
|
||||
adminBulkUpdateModels(isEnabled) { return this._put('/api/v1/admin/models/bulk', { is_enabled: isEnabled }); },
|
||||
adminDeleteModel(id) { return this._del(`/api/v1/admin/models/${id}`); },
|
||||
|
||||
// ── User Models ──────────────────────────
|
||||
listEnabledModels() { return this._get('/api/v1/models/enabled'); },
|
||||
|
||||
// ── HTTP Internals ───────────────────────
|
||||
|
||||
_authHeaders() {
|
||||
@@ -230,7 +245,7 @@ const API = {
|
||||
if (auth) opts.headers['Authorization'] = `Bearer ${this.accessToken}`;
|
||||
if (body) opts.body = JSON.stringify(body);
|
||||
|
||||
const resp = await fetch(path, opts);
|
||||
const resp = await fetch(BASE + path, opts);
|
||||
if (!resp.ok) {
|
||||
const data = await resp.json().catch(() => ({}));
|
||||
const err = new Error(data.error || `HTTP ${resp.status}`);
|
||||
|
||||
Reference in New Issue
Block a user