multica/apps/web/service/request.ts
Naiyuan Qing 242be23876 feat(utils): unify encrypted Device ID across all platforms
- Add common generateEncryptedId() utility in @multica/utils
- All Device IDs now use same encryption algorithm (40 hex chars)
- Web: store encrypted format directly in localStorage
- Desktop: use shared utility, accept encrypted ID from Web
- Hub: use shared utility for hub-id generation
- Telegram: use shared utility for device ID generation
- Gateway hook: use encrypted format for client connections

Algorithm: sha256(sha256(uuid).slice(0,32)).slice(0,8) + sha256(uuid).slice(0,32)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 17:34:23 +08:00

73 lines
2.1 KiB
TypeScript

import { API_HOST } from '@/lib/constant';
import { getOrCreateDeviceId } from '@/lib/device';
import { getSid } from '@/lib/auth';
// Fetch request wrapper
export async function request<T = unknown>(url: string, options: RequestInit = {}): Promise<T> {
// Get or generate Device ID (already encrypted 40-char format)
let deviceId = '';
let sid: string | null = null;
if (typeof window !== 'undefined') {
deviceId = await getOrCreateDeviceId();
sid = getSid();
}
const config: RequestInit = {
...options,
headers: {
'Content-Type': 'application/json',
'os-type': '3',
...(deviceId && { 'Device-Id': deviceId }),
...(sid && { 'Authorization': `Bearer ${sid}` }),
...options.headers,
},
};
const response = await fetch(`${API_HOST}${url}`, config);
let data: T;
const contentType = response.headers.get('content-type');
if (contentType?.includes('application/json')) {
data = await response.json();
} else {
const text = await response.text();
data = { message: text || response.statusText } as T;
}
if (!response.ok) {
console.error('API Error:', {
status: response.status,
url,
data,
});
throw new Error(
(data as { errMsg?: string; message?: string })?.errMsg ||
(data as { message?: string })?.message ||
`Request failed with status ${response.status}`
);
}
return data;
}
// GET request
export function get<T = unknown>(url: string, params?: Record<string, string | number | boolean>) {
const filteredParams = params
? Object.fromEntries(
Object.entries(params).filter(([, v]) => v !== undefined && v !== null)
)
: undefined;
const queryString =
filteredParams && Object.keys(filteredParams).length > 0
? `?${new URLSearchParams(filteredParams as Record<string, string>).toString()}`
: '';
return request<T>(url + queryString, { method: 'GET' });
}
// POST request
export function post<T = unknown>(url: string, data?: unknown) {
return request<T>(url, {
method: 'POST',
body: JSON.stringify(data),
});
}