This repository has been archived on 2026-05-11. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
autodeployer-old-version/dashboard/js/api.js
Giuseppe Raffa 87d698bc5c feat: add Docker and Gitea services, monitoring, queue, and Telegram notification functionalities
- Implemented Docker operations including image building, container management, and resource stats.
- Added Gitea API client for repository management and webhook handling.
- Introduced monitoring service to collect and store container metrics in InfluxDB.
- Created a queue system using BullMQ for managing deployment jobs with real-time log streaming.
- Developed Telegram notification service for deployment status updates.
- Added Traefik label generation for dynamic reverse proxy configuration.
- Implemented WebSocket endpoints for log streaming and terminal access to containers.
- Created an updater sidecar for self-updating the AutoDeployer container.
2026-04-13 23:23:18 +02:00

115 lines
4.9 KiB
JavaScript

// AutoDeployer API Client — vanilla JS (ES module)
const API_BASE = '/api';
let accessToken = localStorage.getItem('accessToken') || '';
function setToken(token) {
accessToken = token;
token ? localStorage.setItem('accessToken', token) : localStorage.removeItem('accessToken');
}
function getToken() { return accessToken; }
class ApiError extends Error {
constructor(status, body) { super(body.error || 'API Error'); this.status = status; this.body = body; }
}
async function request(path, opts = {}) {
const url = `${API_BASE}${path}`;
const headers = { 'Content-Type': 'application/json', ...opts.headers };
if (accessToken) headers['Authorization'] = `Bearer ${accessToken}`;
let res = await fetch(url, { ...opts, headers, credentials: 'include' });
if (res.status === 401 && path !== '/auth/login' && path !== '/auth/refresh') {
const refreshed = await refreshToken();
if (refreshed) {
headers['Authorization'] = `Bearer ${accessToken}`;
res = await fetch(url, { ...opts, headers, credentials: 'include' });
} else {
throw new ApiError(401, { error: 'Session expired' });
}
}
if (!res.ok) {
const body = await res.json().catch(() => ({ error: 'Unknown error' }));
throw new ApiError(res.status, body);
}
return res.json();
}
async function refreshToken() {
try {
const res = await fetch(`${API_BASE}/auth/refresh`, { method: 'POST', credentials: 'include' });
if (res.ok) { const d = await res.json(); setToken(d.accessToken); return true; }
} catch {}
return false;
}
export const auth = {
status: () => request('/auth/status'),
login: (u, p) => request('/auth/login', { method: 'POST', body: JSON.stringify({ username: u, password: p }) }).then(d => { setToken(d.accessToken); return d; }),
setup: (u, p) => request('/auth/setup', { method: 'POST', body: JSON.stringify({ username: u, password: p }) }).then(d => { setToken(d.accessToken); return d; }),
logout: () => request('/auth/logout', { method: 'POST' }).then(() => setToken('')).catch(() => setToken('')),
me: () => request('/auth/me'),
changePassword: (cur, nw) => request('/auth/password', { method: 'PUT', body: JSON.stringify({ currentPassword: cur, newPassword: nw }) }),
};
export const services = {
list: () => request('/services'),
get: (id) => request(`/services/${id}`),
create: (d) => request('/services', { method: 'POST', body: JSON.stringify(d) }),
update: (id, d) => request(`/services/${id}`, { method: 'PUT', body: JSON.stringify(d) }),
delete: (id) => request(`/services/${id}`, { method: 'DELETE' }),
deploy: (id) => request(`/services/${id}/deploy`, { method: 'POST' }),
stop: (id) => request(`/services/${id}/stop`, { method: 'POST' }),
restart: (id) => request(`/services/${id}/restart`, { method: 'POST' }),
inspect: (id) => request(`/services/${id}/inspect`),
cleanup: () => request('/services/cleanup', { method: 'POST' }),
pruneImages: (keep = 2) => request('/services/prune-images', { method: 'POST', body: JSON.stringify({ keep }) }),
traefikPreview: (id) => request(`/services/${id}/traefik-preview`),
traefikPreviewBody: (d) => request('/services/traefik-preview', { method: 'POST', body: JSON.stringify(d) }),
getEnv: (id) => request(`/services/${id}/env`),
setEnv: (id, vars) => request(`/services/${id}/env`, { method: 'PUT', body: JSON.stringify({ vars }) }),
};
export const deploys = {
list: () => request('/deploys'),
get: (id) => request(`/deploys/${id}`),
};
export const networks = {
list: () => request('/networks'),
create: (name, driver, internal) => request('/networks', { method: 'POST', body: JSON.stringify({ name, driver, internal }) }),
remove: (name) => request(`/networks/${name}`, { method: 'DELETE' }),
};
export const monitoring = {
realtime: () => request('/monitoring/realtime'),
stats: (name) => request(`/monitoring/${name}/stats`),
history: (name, range = '-1h', field = 'cpu_percent') => request(`/monitoring/${name}/history?range=${range}&field=${field}`),
};
export const settingsApi = {
get: () => request('/settings'),
update: (s) => request('/settings', { method: 'PUT', body: JSON.stringify({ settings: s }) }),
testGitea: () => request('/settings/test/gitea'),
testTelegram: () => request('/settings/test/telegram'),
queueStatus: () => request('/settings/queue'),
};
export const system = {
version: () => request('/system/version'),
selfUpdate: () => request('/system/self-update', { method: 'POST' }),
updateStatus: () => request('/system/update-status'),
};
export function createLogSocket(target) {
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
return new WebSocket(`${proto}//${location.host}/ws/logs/${target}?token=${accessToken}`);
}
export function createTerminalSocket(containerId) {
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
return new WebSocket(`${proto}//${location.host}/ws/terminal/${containerId}?token=${accessToken}`);
}
export { getToken, setToken };