feat(conversation-assistant): add authentication support to API client
- Add token and device ID storage utilities - Add Authorization header to API requests - Add skipAuth parameter for unauthenticated endpoints - Add authApi object with register, verify, and checkStatus methods - Improve error handling with status code attachment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
bcaa005e64
commit
8b37391c1e
1 changed files with 56 additions and 11 deletions
|
|
@ -1,35 +1,80 @@
|
|||
const API_BASE = '/api';
|
||||
const TOKEN_KEY = 'conversation-assistant-token';
|
||||
const DEVICE_ID_KEY = 'conversation-assistant-device-id';
|
||||
|
||||
export function getStoredToken(): string | null {
|
||||
return localStorage.getItem(TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function setStoredToken(token: string): void {
|
||||
localStorage.setItem(TOKEN_KEY, token);
|
||||
}
|
||||
|
||||
export function getStoredDeviceId(): string | null {
|
||||
return localStorage.getItem(DEVICE_ID_KEY);
|
||||
}
|
||||
|
||||
export function setStoredDeviceId(deviceId: string): void {
|
||||
localStorage.setItem(DEVICE_ID_KEY, deviceId);
|
||||
}
|
||||
|
||||
export function clearAuth(): void {
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
localStorage.removeItem(DEVICE_ID_KEY);
|
||||
}
|
||||
|
||||
async function request<T>(
|
||||
endpoint: string,
|
||||
options: RequestInit = {}
|
||||
options: RequestInit = {},
|
||||
skipAuth = false
|
||||
): Promise<T> {
|
||||
const token = getStoredToken();
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
...(options.headers as Record<string, string>),
|
||||
};
|
||||
|
||||
if (token && !skipAuth) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE}${endpoint}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers,
|
||||
},
|
||||
headers,
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok || !data.success) {
|
||||
throw new Error(data.error?.message || 'Request failed');
|
||||
const error = new Error(data.error?.message || data.message || 'Request failed');
|
||||
(error as Error & { status?: number }).status = response.status;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return data.data;
|
||||
}
|
||||
|
||||
export const api = {
|
||||
get: <T>(endpoint: string) => request<T>(endpoint),
|
||||
get: <T>(endpoint: string, skipAuth = false) => request<T>(endpoint, {}, skipAuth),
|
||||
|
||||
post: <T>(endpoint: string, body?: unknown) =>
|
||||
post: <T>(endpoint: string, body?: unknown, skipAuth = false) =>
|
||||
request<T>(endpoint, {
|
||||
method: 'POST',
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
}),
|
||||
}, skipAuth),
|
||||
|
||||
delete: <T>(endpoint: string) =>
|
||||
request<T>(endpoint, { method: 'DELETE' }),
|
||||
delete: <T>(endpoint: string, skipAuth = false) =>
|
||||
request<T>(endpoint, { method: 'DELETE' }, skipAuth),
|
||||
};
|
||||
|
||||
// Auth-specific API calls (no auth required)
|
||||
export const authApi = {
|
||||
register: (data: { name: string; hardwareId: string; platform: string; osVersion: string }) =>
|
||||
api.post<{ deviceId: string; code: string; expiresAt: string }>('/devices/register', data, true),
|
||||
|
||||
verify: (deviceId: string, code: string) =>
|
||||
api.post<{ token: string }>('/devices/verify', { deviceId, code }, true),
|
||||
|
||||
checkStatus: (deviceId: string) =>
|
||||
api.get<{ isActive: boolean; token?: string }>(`/devices/${deviceId}/status`, true),
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue