Changeset 0.37.3 (#215)

Co-authored-by: gobha <jasafpro@gmail.com>
Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
2026-03-21 00:34:36 +00:00
committed by xcaliber
parent 4f1abc6321
commit fc43618501
9 changed files with 1722 additions and 0 deletions

View File

@@ -0,0 +1,446 @@
// ==========================================
// Chat Switchboard — SDK: API Domain Namespaces
// ==========================================
// 18 namespaced domain clients wrapping restClient.
// Each domain is a plain object with typed methods.
//
// Factory: createDomains(restClient)
// ==========================================
/**
* Build query string from an options object. Skips null/undefined values.
* @param {object} [opts]
* @returns {string} — '' or '?key=val&...'
*/
function _qs(opts) {
if (!opts) return '';
const p = new URLSearchParams();
for (const [k, v] of Object.entries(opts)) {
if (v != null) p.set(k, String(v));
}
const s = p.toString();
return s ? '?' + s : '';
}
/**
* Standard CRUD factory.
* @param {object} rc — restClient
* @param {string} base — e.g. '/api/v1/channels'
* @returns {object} — { list, get, create, update, del }
*/
function crud(rc, base) {
return {
list: (opts) => rc.get(base + _qs(opts)),
get: (id) => rc.get(`${base}/${id}`),
create: (data) => rc.post(base, data),
update: (id, data) => rc.put(`${base}/${id}`, data),
del: (id) => rc.del(`${base}/${id}`),
};
}
/**
* Create all 18 domain namespaces.
*
* @param {object} restClient
* @returns {object} api — the full sw.api object
*/
export function createDomains(restClient) {
const rc = restClient;
return {
// ── Escape hatches (raw restClient) ─────
get: rc.get.bind(rc),
post: rc.post.bind(rc),
put: rc.put.bind(rc),
patch: rc.patch.bind(rc),
del: rc.del.bind(rc),
stream: rc.stream.bind(rc),
upload: rc.upload.bind(rc),
// ── 1. Auth ─────────────────────────────
auth: {
login: (login, password) => rc.post('/api/v1/auth/login', { login, password }),
register: (username, email, password) => rc.post('/api/v1/auth/register', { username, email, password }),
refresh: (refreshToken) => rc.post('/api/v1/auth/refresh', { refresh_token: refreshToken }),
logout: (refreshToken) => rc.post('/api/v1/auth/logout', { refresh_token: refreshToken }),
},
// ── 2. Channels ────────────────────────
channels: {
...crud(rc, '/api/v1/channels'),
messages: (id, opts) => rc.get(`/api/v1/channels/${id}/messages` + _qs(opts)),
send: (id, data) => rc.post(`/api/v1/channels/${id}/messages`, data),
complete: (data, signal) => rc.stream('/api/v1/chat/completions', data, signal),
regenerate: (id, msgId, data, signal) => rc.stream(`/api/v1/channels/${id}/messages/${msgId}/regenerate`, data, signal),
editMessage: (id, msgId, content) => rc.post(`/api/v1/channels/${id}/messages/${msgId}/edit`, { content }),
siblings: (id, msgId) => rc.get(`/api/v1/channels/${id}/messages/${msgId}/siblings`),
path: (id) => rc.get(`/api/v1/channels/${id}/path`),
cursor: (id, leafId) => rc.put(`/api/v1/channels/${id}/cursor`, { active_leaf_id: leafId }),
markRead: (id) => rc.post(`/api/v1/channels/${id}/mark-read`, {}),
generateTitle: (id) => rc.post(`/api/v1/channels/${id}/generate-title`, {}),
summarize: (id) => rc.post(`/api/v1/channels/${id}/summarize`, {}),
// Participants
participants: (id) => rc.get(`/api/v1/channels/${id}/participants`),
addParticipant: (id, data) => rc.post(`/api/v1/channels/${id}/participants`, data),
updateParticipant: (id, pid, data) => rc.patch(`/api/v1/channels/${id}/participants/${pid}`, data),
removeParticipant: (id, pid) => rc.del(`/api/v1/channels/${id}/participants/${pid}`),
// Channel models
models: (id) => rc.get(`/api/v1/channels/${id}/models`),
addModel: (id, data) => rc.post(`/api/v1/channels/${id}/models`, data),
updateModel: (id, modelId, data) => rc.patch(`/api/v1/channels/${id}/models/${modelId}`, data),
removeModel: (id, modelId) => rc.del(`/api/v1/channels/${id}/models/${modelId}`),
// Knowledge bases
kbs: (id) => rc.get(`/api/v1/channels/${id}/knowledge-bases`),
setKbs: (id, kbIds) => rc.put(`/api/v1/channels/${id}/knowledge-bases`, { kb_ids: kbIds }),
// Files
files: (id) => rc.get(`/api/v1/channels/${id}/files`),
uploadFile: (id, file) => rc.upload(`/api/v1/channels/${id}/files`, file),
},
// ── 3. Personas ────────────────────────
personas: {
...crud(rc, '/api/v1/personas'),
kbs: (id) => rc.get(`/api/v1/personas/${id}/knowledge-bases`),
setKbs: (id, data) => rc.put(`/api/v1/personas/${id}/knowledge-bases`, data),
},
// ── 4. Knowledge Bases ─────────────────
knowledge: {
...crud(rc, '/api/v1/knowledge-bases'),
discoverable: () => rc.get('/api/v1/knowledge-bases-discoverable'),
search: (id, query, limit) => rc.post(`/api/v1/knowledge-bases/${id}/search`, { query, limit }),
documents: (id) => rc.get(`/api/v1/knowledge-bases/${id}/documents`),
upload: (id, file) => rc.upload(`/api/v1/knowledge-bases/${id}/documents`, file),
docStatus: (id, docId) => rc.get(`/api/v1/knowledge-bases/${id}/documents/${docId}/status`),
delDoc: (id, docId) => rc.del(`/api/v1/knowledge-bases/${id}/documents/${docId}`),
},
// ── 5. Notes ───────────────────────────
notes: {
...crud(rc, '/api/v1/notes'),
search: (query, limit) => rc.get(`/api/v1/notes/search` + _qs({ q: query, limit })),
searchTitles: (query, limit) => rc.get(`/api/v1/notes/search-titles` + _qs({ q: query, limit })),
folders: () => rc.get('/api/v1/notes/folders'),
backlinks: (id) => rc.get(`/api/v1/notes/${id}/backlinks`),
graph: () => rc.get('/api/v1/notes/graph'),
bulkDelete: (ids) => rc.post('/api/v1/notes/bulk-delete', { ids }),
},
// ── 6. Projects ────────────────────────
projects: {
...crud(rc, '/api/v1/projects'),
channels: (id) => rc.get(`/api/v1/projects/${id}/channels`),
addChannel: (id, channelId, pos) => rc.post(`/api/v1/projects/${id}/channels`, { channel_id: channelId, position: pos || 0 }),
removeChannel: (id, channelId) => rc.del(`/api/v1/projects/${id}/channels/${channelId}`),
reorderChannels:(id, channelIds) => rc.put(`/api/v1/projects/${id}/channels/reorder`, { channel_ids: channelIds }),
kbs: (id) => rc.get(`/api/v1/projects/${id}/knowledge-bases`),
addKb: (id, kbId, autoSearch) => rc.post(`/api/v1/projects/${id}/knowledge-bases`, { kb_id: kbId, auto_search: autoSearch || false }),
removeKb: (id, kbId) => rc.del(`/api/v1/projects/${id}/knowledge-bases/${kbId}`),
notes: (id) => rc.get(`/api/v1/projects/${id}/notes`),
addNote: (id, noteId) => rc.post(`/api/v1/projects/${id}/notes`, { note_id: noteId }),
removeNote: (id, noteId) => rc.del(`/api/v1/projects/${id}/notes/${noteId}`),
files: (id) => rc.get(`/api/v1/projects/${id}/files`),
uploadFile: (id, file) => rc.upload(`/api/v1/projects/${id}/files`, file),
},
// ── 7. Workspaces ──────────────────────
workspaces: {
...crud(rc, '/api/v1/workspaces'),
files: (id, opts) => rc.get(`/api/v1/workspaces/${id}/files` + _qs(opts)),
readFile: (id, path) => rc.get(`/api/v1/workspaces/${id}/files/read` + _qs({ path })),
writeFile: (id, path, content) => rc.put(`/api/v1/workspaces/${id}/files/write` + _qs({ path }), content),
deleteFile: (id, path) => rc.del(`/api/v1/workspaces/${id}/files/delete` + _qs({ path })),
mkdir: (id, path) => rc.post(`/api/v1/workspaces/${id}/files/mkdir`, { path }),
gitStatus: (id) => rc.get(`/api/v1/workspaces/${id}/git/status`),
gitBranches: (id) => rc.get(`/api/v1/workspaces/${id}/git/branches`),
credentials: () => rc.get('/api/v1/git-credentials'),
},
// ── 8. Memory ──────────────────────────
memory: {
list: (opts) => rc.get('/api/v1/memories' + _qs(opts)),
get: (id) => rc.get(`/api/v1/memories/${id}`),
update: (id, data) => rc.put(`/api/v1/memories/${id}`, data),
del: (id) => rc.del(`/api/v1/memories/${id}`),
count: () => rc.get('/api/v1/memories/count'),
approve: (id) => rc.post(`/api/v1/memories/${id}/approve`, {}),
reject: (id) => rc.post(`/api/v1/memories/${id}/reject`, {}),
},
// ── 9. Models ──────────────────────────
models: {
enabled: () => rc.get('/api/v1/models/enabled'),
preferences: () => rc.get('/api/v1/models/preferences'),
setPref: (modelId, provId, hidden) => rc.put('/api/v1/models/preferences', { model_id: modelId, provider_config_id: provId, hidden }),
bulkSetPref: (entries, hidden) => rc.post('/api/v1/models/preferences/bulk', { entries, hidden }),
},
// ── 10. Providers (user BYOK) ──────────
providers: {
...crud(rc, '/api/v1/api-configs'),
models: (id) => rc.get(`/api/v1/api-configs/${id}/models`),
fetchModels: (id) => rc.post(`/api/v1/api-configs/${id}/models/fetch`),
},
// ── 11. Notifications ──────────────────
notifications: {
list: (opts) => rc.get('/api/v1/notifications' + _qs(opts)),
markRead: (id) => rc.post(`/api/v1/notifications/${id}/read`, {}),
prefs: () => rc.get('/api/v1/notifications/preferences'),
setPref: (type, data) => rc.put(`/api/v1/notifications/preferences/${encodeURIComponent(type)}`, data),
delPref: (type) => rc.del(`/api/v1/notifications/preferences/${encodeURIComponent(type)}`),
},
// ── 12. Extensions ─────────────────────
extensions: {
list: (opts) => rc.get('/api/v1/extensions' + _qs(opts)),
get: (id) => rc.get(`/api/v1/extensions/${id}`),
settings: (id) => rc.get(`/api/v1/extensions/${id}/settings`),
},
// ── 13. Profile ────────────────────────
profile: {
get: () => rc.get('/api/v1/profile'),
update: (data) => rc.put('/api/v1/profile', data),
avatar: (base64) => rc.post('/api/v1/profile/avatar', { image: base64 }),
deleteAvatar:() => rc.del('/api/v1/profile/avatar'),
password: (current, pw) => rc.post('/api/v1/profile/password', { current_password: current, new_password: pw }),
settings: () => rc.get('/api/v1/settings'),
updateSettings: (data) => rc.put('/api/v1/settings', data),
permissions: () => rc.get('/api/v1/profile/permissions'),
},
// ── 14. Teams ──────────────────────────
teams: {
mine: () => rc.get('/api/v1/teams/mine'),
get: (id) => rc.get(`/api/v1/teams/${id}`),
members: (id) => rc.get(`/api/v1/teams/${id}/members`),
addMember: (id, userId, role) => rc.post(`/api/v1/teams/${id}/members`, { user_id: userId, role }),
updateMember:(id, memberId, role) => rc.put(`/api/v1/teams/${id}/members/${memberId}`, { role }),
removeMember:(id, memberId) => rc.del(`/api/v1/teams/${id}/members/${memberId}`),
personas: (id) => rc.get(`/api/v1/teams/${id}/personas`),
createPersona:(id, data) => rc.post(`/api/v1/teams/${id}/personas`, data),
deletePersona:(id, pid) => rc.del(`/api/v1/teams/${id}/personas/${pid}`),
personaKbs: (id, pid) => rc.get(`/api/v1/teams/${id}/personas/${pid}/knowledge-bases`),
setPersonaKbs:(id, pid, data) => rc.put(`/api/v1/teams/${id}/personas/${pid}/knowledge-bases`, data),
models: (id) => rc.get(`/api/v1/teams/${id}/models`),
groups: (id) => rc.get(`/api/v1/teams/${id}/groups`),
providers: (id) => rc.get(`/api/v1/teams/${id}/providers`),
createProvider:(id, data) => rc.post(`/api/v1/teams/${id}/providers`, data),
updateProvider:(id, pid, data) => rc.put(`/api/v1/teams/${id}/providers/${pid}`, data),
deleteProvider:(id, pid) => rc.del(`/api/v1/teams/${id}/providers/${pid}`),
providerModels:(id, pid) => rc.get(`/api/v1/teams/${id}/providers/${pid}/models`),
roles: (id) => rc.get(`/api/v1/teams/${id}/roles`),
updateRole: (id, role, config) => rc.put(`/api/v1/teams/${id}/roles/${role}`, config),
deleteRole: (id, role) => rc.del(`/api/v1/teams/${id}/roles/${role}`),
audit: (id, opts) => rc.get(`/api/v1/teams/${id}/audit` + _qs(opts)),
auditActions:(id) => rc.get(`/api/v1/teams/${id}/audit/actions`),
usage: (id, opts) => rc.get(`/api/v1/teams/${id}/usage` + _qs(opts)),
},
// ── 15. Workflows ──────────────────────
workflows: {
...crud(rc, '/api/v1/workflows'),
instances: (id, opts) => rc.get(`/api/v1/workflows/${id}/instances` + _qs(opts)),
advance: (id, data) => rc.post(`/api/v1/workflows/${id}/advance`, data),
reject: (id, data) => rc.post(`/api/v1/workflows/${id}/reject`, data),
},
// ── 16. Tasks ──────────────────────────
tasks: {
...crud(rc, '/api/v1/tasks'),
runs: (id, opts) => rc.get(`/api/v1/tasks/${id}/runs` + _qs(opts)),
start: (id, data) => rc.post(`/api/v1/tasks/${id}/start`, data || {}),
stop: (id) => rc.post(`/api/v1/tasks/${id}/stop`, {}),
},
// ── 17. Surfaces ───────────────────────
surfaces: {
list: (opts) => rc.get('/api/v1/surfaces' + _qs(opts)),
get: (id) => rc.get(`/api/v1/surfaces/${id}`),
install: (id) => rc.post(`/api/v1/surfaces/${id}/install`, {}),
},
// ── 18. Admin ──────────────────────────
admin: {
stats: () => rc.get('/api/v1/admin/stats'),
dashboard: () => rc.get('/api/v1/admin/dashboard'),
users: {
list: (opts) => rc.get('/api/v1/admin/users' + _qs(opts)),
create: (data) => rc.post('/api/v1/admin/users', data),
del: (id) => rc.del(`/api/v1/admin/users/${id}`),
resetPassword: (id, pw) => rc.post(`/api/v1/admin/users/${id}/reset-password`, { password: pw }),
updateRole: (id, role) => rc.put(`/api/v1/admin/users/${id}/role`, { role }),
toggleActive: (id, active, opts) => rc.put(`/api/v1/admin/users/${id}/active`, { is_active: active, ...opts }),
permissions: (id) => rc.get(`/api/v1/admin/users/${id}/permissions`),
},
settings: {
get: () => rc.get('/api/v1/admin/settings'),
update: (key, val) => rc.put(`/api/v1/admin/settings/${key}`, val),
public: () => rc.get('/api/v1/settings/public'),
},
configs: {
list: () => rc.get('/api/v1/admin/configs'),
create: (data) => rc.post('/api/v1/admin/configs', data),
update: (id, data) => rc.put(`/api/v1/admin/configs/${id}`, data),
del: (id) => rc.del(`/api/v1/admin/configs/${id}`),
},
models: {
list: () => rc.get('/api/v1/admin/models'),
fetch: () => rc.post('/api/v1/admin/models/fetch', {}),
update: (id, data) => rc.put(`/api/v1/admin/models/${id}`, data),
bulkUpdate: (visibility) => rc.put('/api/v1/admin/models/bulk', { visibility, is_enabled: visibility === 'enabled' }),
del: (id) => rc.del(`/api/v1/admin/models/${id}`),
capabilities: (modelId) => rc.get(`/api/v1/admin/models/${encodeURIComponent(modelId)}/capabilities`),
setCapability: (modelId, d) => rc.put(`/api/v1/admin/models/${encodeURIComponent(modelId)}/capabilities`, d),
delCapability: (modelId, oId) => rc.del(`/api/v1/admin/models/${encodeURIComponent(modelId)}/capabilities/${oId}`),
overrides: () => rc.get('/api/v1/admin/capability-overrides'),
},
personas: {
list: () => rc.get('/api/v1/admin/personas'),
create: (data) => rc.post('/api/v1/admin/personas', data),
update: (id, data) => rc.put(`/api/v1/admin/personas/${id}`, data),
del: (id) => rc.del(`/api/v1/admin/personas/${id}`),
avatar: (id, base64) => rc.post(`/api/v1/admin/personas/${id}/avatar`, { image: base64 }),
delAvatar: (id) => rc.del(`/api/v1/admin/personas/${id}/avatar`),
kbs: (id) => rc.get(`/api/v1/admin/personas/${id}/knowledge-bases`),
setKbs: (id, data) => rc.put(`/api/v1/admin/personas/${id}/knowledge-bases`, data),
},
teams: {
list: () => rc.get('/api/v1/admin/teams'),
get: (id) => rc.get(`/api/v1/admin/teams/${id}`),
create: (data) => rc.post('/api/v1/admin/teams', data),
update: (id, data) => rc.put(`/api/v1/admin/teams/${id}`, data),
del: (id) => rc.del(`/api/v1/admin/teams/${id}`),
members: (id) => rc.get(`/api/v1/admin/teams/${id}/members`),
addMember: (id, userId, role) => rc.post(`/api/v1/admin/teams/${id}/members`, { user_id: userId, role }),
updateMember: (id, mid, role) => rc.put(`/api/v1/admin/teams/${id}/members/${mid}`, { role }),
removeMember: (id, mid) => rc.del(`/api/v1/admin/teams/${id}/members/${mid}`),
},
groups: {
list: () => rc.get('/api/v1/admin/groups'),
get: (id) => rc.get(`/api/v1/admin/groups/${id}`),
create: (data) => rc.post('/api/v1/admin/groups', data),
update: (id, data) => rc.put(`/api/v1/admin/groups/${id}`, data),
del: (id) => rc.del(`/api/v1/admin/groups/${id}`),
members: (id) => rc.get(`/api/v1/admin/groups/${id}/members`),
addMember: (id, userId) => rc.post(`/api/v1/admin/groups/${id}/members`, { user_id: userId }),
removeMember: (id, userId) => rc.del(`/api/v1/admin/groups/${id}/members/${userId}`),
},
grants: {
get: (type, id) => rc.get(`/api/v1/admin/grants/${type}/${id}`),
set: (type, id, scope, groups) => rc.put(`/api/v1/admin/grants/${type}/${id}`, { grant_scope: scope, granted_groups: groups || [] }),
del: (type, id) => rc.del(`/api/v1/admin/grants/${type}/${id}`),
},
permissions: {
list: () => rc.get('/api/v1/admin/permissions'),
},
audit: {
list: (opts) => rc.get('/api/v1/admin/audit' + _qs(opts)),
actions: () => rc.get('/api/v1/admin/audit/actions'),
},
roles: {
list: () => rc.get('/api/v1/admin/roles'),
get: (role) => rc.get(`/api/v1/admin/roles/${role}`),
update: (role, config) => rc.put(`/api/v1/admin/roles/${role}`, config),
test: (role) => rc.post(`/api/v1/admin/roles/${role}/test`, {}),
},
usage: {
get: (opts) => rc.get('/api/v1/admin/usage' + _qs(opts)),
user: (id, opts) => rc.get(`/api/v1/admin/usage/users/${id}` + _qs(opts)),
team: (id, opts) => rc.get(`/api/v1/admin/usage/teams/${id}` + _qs(opts)),
},
pricing: {
list: () => rc.get('/api/v1/admin/pricing'),
upsert: (entry) => rc.put('/api/v1/admin/pricing', entry),
del: (provId, modelId) => rc.del(`/api/v1/admin/pricing/${provId}/${encodeURIComponent(modelId)}`),
},
providers: {
health: () => rc.get('/api/v1/admin/providers/health'),
healthOne: (id) => rc.get(`/api/v1/admin/providers/${id}/health`),
types: () => rc.get('/api/v1/admin/provider-types'),
},
routing: {
policies: () => rc.get('/api/v1/admin/routing/policies'),
getPolicy: (id) => rc.get(`/api/v1/admin/routing/policies/${id}`),
createPolicy:(data) => rc.post('/api/v1/admin/routing/policies', data),
updatePolicy:(id, data) => rc.put(`/api/v1/admin/routing/policies/${id}`, data),
deletePolicy:(id) => rc.del(`/api/v1/admin/routing/policies/${id}`),
test: (data) => rc.post('/api/v1/admin/routing/test', data),
},
storage: {
status: () => rc.get('/api/v1/admin/storage/status'),
orphans: () => rc.get('/api/v1/admin/storage/orphans'),
cleanup: () => rc.post('/api/v1/admin/storage/cleanup', {}),
extraction: () => rc.get('/api/v1/admin/storage/extraction'),
},
vault: {
status: () => rc.get('/api/v1/admin/vault/status'),
},
projects: {
list: (opts) => rc.get('/api/v1/admin/projects' + _qs(opts)),
del: (id) => rc.del(`/api/v1/admin/projects/${id}`),
},
memories: {
pending: () => rc.get('/api/v1/admin/memories/pending'),
bulkApprove: (ids) => rc.post('/api/v1/admin/memories/bulk-approve', { ids }),
},
notifications: {
testEmail: () => rc.post('/api/v1/admin/notifications/test-email', {}),
},
},
// ── Misc (not domain-specific) ─────────
folders: {
list: () => rc.get('/api/v1/folders'),
create: (name, sort) => rc.post('/api/v1/folders', { name, sort_order: sort || 0 }),
update: (id, data) => rc.put(`/api/v1/folders/${id}`, data),
del: (id) => rc.del(`/api/v1/folders/${id}`),
},
files: {
get: (id) => rc.get(`/api/v1/files/${id}`),
del: (id) => rc.del(`/api/v1/files/${id}`),
},
tools: {
list: () => rc.get('/api/v1/tools'),
},
presence: {
heartbeat: () => rc.post('/api/v1/presence/heartbeat', {}),
},
usage: {
mine: (opts) => rc.get('/api/v1/usage' + _qs(opts)),
},
groups: {
mine: () => rc.get('/api/v1/groups/mine'),
},
health: () => rc.get('/api/v1/health'),
export: (content, format, filename) => rc.post('/api/v1/export', { content, format, filename }),
};
}