Improve portable launch, forge persistence, and operator auth UX.
Persist build extra_files for Build Manager history, print dashboard login on every start, add libp2p for Mesh P2P forge, defer WebSocket until login, and split devrun.bat from LAUNCH.bat with USB deck auto-detection.
This commit is contained in:
@@ -8,13 +8,19 @@ export function getStoredAuth(): string | null {
|
||||
}
|
||||
}
|
||||
|
||||
export function setStoredAuth(username: string, password: string) {
|
||||
export function setStoredAuth(username: string, password: string, opts?: { silent?: boolean }) {
|
||||
const token = btoa(`${username}:${password}`);
|
||||
sessionStorage.setItem(AUTH_KEY, token);
|
||||
if (!opts?.silent) {
|
||||
window.dispatchEvent(new Event('aetherforge-auth'));
|
||||
}
|
||||
}
|
||||
|
||||
export function clearStoredAuth() {
|
||||
export function clearStoredAuth(opts?: { silent?: boolean }) {
|
||||
sessionStorage.removeItem(AUTH_KEY);
|
||||
if (!opts?.silent) {
|
||||
window.dispatchEvent(new Event('aetherforge-auth'));
|
||||
}
|
||||
}
|
||||
|
||||
export function authHeaders(): Record<string, string> {
|
||||
|
||||
@@ -263,6 +263,16 @@ describe('api client', () => {
|
||||
expect(JSON.parse(lastFetch().init.body as string)).toEqual({ username: 'alice', password: 'secret' });
|
||||
});
|
||||
|
||||
it('rotateFleetSecret POSTs rotate endpoint', async () => {
|
||||
fetchMock.mockResolvedValueOnce(jsonResponse({ ok: true, hint: 'abcd1234...' }));
|
||||
|
||||
const res = await api.rotateFleetSecret();
|
||||
|
||||
expect(res.ok).toBe(true);
|
||||
expect(lastFetch().url).toBe('/api/v1/server/rotate-secret');
|
||||
expect(lastFetch().init.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('getXmrPrice and getServerInfo', async () => {
|
||||
fetchMock
|
||||
.mockResolvedValueOnce(jsonResponse({ usd: 200, updated_at: 'now' }))
|
||||
|
||||
@@ -3,6 +3,9 @@ import { authHeaders } from './auth';
|
||||
|
||||
const API_BASE = '/api/v1';
|
||||
|
||||
// Agent-only REST (/agent/decide, /agent/report, /agent/heartbeat) is intentionally
|
||||
// omitted here — forged agents call those with X-Fleet-Secret, not dashboard Basic Auth.
|
||||
|
||||
async function fetchJSON<T>(url: string, options?: RequestInit): Promise<T> {
|
||||
const { headers: extraHeaders, ...rest } = options ?? {};
|
||||
const res = await fetch(`${API_BASE}${url}`, {
|
||||
@@ -118,6 +121,8 @@ export const api = {
|
||||
// Health / server
|
||||
healthCheck: () => fetchJSON<{ status: string }>('/health'),
|
||||
getServerInfo: () => fetchJSON<ServerInfo>('/server/info'),
|
||||
rotateFleetSecret: () =>
|
||||
fetchJSON<{ ok: boolean; hint?: string }>('/server/rotate-secret', { method: 'POST' }),
|
||||
|
||||
// Fleet ops
|
||||
getAlerts: () => fetchJSON<FleetAlert[]>('/alerts'),
|
||||
|
||||
Reference in New Issue
Block a user