fix idp on started
This commit is contained in:
@@ -1,4 +1,52 @@
|
||||
export const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:3000';
|
||||
const API_ORIGIN_PROXY_PREFIX = '/idp-api';
|
||||
const configuredApiUrl = (process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:3000').replace(/\/$/, '');
|
||||
const configuredWsUrl = (process.env.NEXT_PUBLIC_WS_URL ?? 'ws://localhost:8085/ws').replace(/\/$/, '');
|
||||
|
||||
function resolveBrowserApiBaseUrl(): string {
|
||||
if (typeof window === 'undefined') {
|
||||
return configuredApiUrl;
|
||||
}
|
||||
|
||||
try {
|
||||
const configured = new URL(configuredApiUrl);
|
||||
if (configured.origin !== window.location.origin) {
|
||||
return `${window.location.origin}${API_ORIGIN_PROXY_PREFIX}`;
|
||||
}
|
||||
} catch {
|
||||
// keep configured URL
|
||||
}
|
||||
|
||||
return configuredApiUrl;
|
||||
}
|
||||
|
||||
function resolveBrowserWsBaseUrl(): string {
|
||||
if (typeof window === 'undefined') {
|
||||
return configuredWsUrl;
|
||||
}
|
||||
|
||||
try {
|
||||
const configured = new URL(configuredWsUrl);
|
||||
if (configured.origin !== window.location.origin) {
|
||||
const scheme = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
return `${scheme}//${window.location.host}${API_ORIGIN_PROXY_PREFIX}/ws`;
|
||||
}
|
||||
} catch {
|
||||
// keep configured URL
|
||||
}
|
||||
|
||||
return configuredWsUrl;
|
||||
}
|
||||
|
||||
export function getApiUrl(): string {
|
||||
return resolveBrowserApiBaseUrl();
|
||||
}
|
||||
|
||||
export function getWsUrl(): string {
|
||||
return resolveBrowserWsBaseUrl();
|
||||
}
|
||||
|
||||
/** @deprecated Используйте getApiUrl() — URL может переключаться на same-origin /idp-api в браузере */
|
||||
export const API_URL = configuredApiUrl;
|
||||
|
||||
export interface PublicUser {
|
||||
id: string;
|
||||
@@ -141,6 +189,23 @@ export class ApiError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
function mapFetchError(error: unknown): ApiError {
|
||||
if (error instanceof TypeError) {
|
||||
const message = error.message.toLowerCase();
|
||||
if (message.includes('failed to fetch') || message.includes('networkerror')) {
|
||||
return new ApiError(
|
||||
'Нет связи с сервером. При самоподписанном HTTPS примите сертификат сайта или выполните ./install.sh --fix-proxy на сервере.',
|
||||
0,
|
||||
'NETWORK_ERROR'
|
||||
);
|
||||
}
|
||||
}
|
||||
if (error instanceof ApiError) {
|
||||
return error;
|
||||
}
|
||||
return new ApiError(error instanceof Error ? error.message : 'Не удалось выполнить запрос', 0, 'UNKNOWN');
|
||||
}
|
||||
|
||||
type PinRequiredHandler = (sessionId: string) => void;
|
||||
|
||||
export function setPinRequiredHandler(handler: PinRequiredHandler | null) {
|
||||
@@ -212,7 +277,7 @@ export async function refreshAuthSession(): Promise<RefreshSessionResponse> {
|
||||
throw new ApiError('Refresh token отсутствует', 401, 'NO_REFRESH');
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}/auth/refresh`, {
|
||||
const response = await fetch(`${getApiUrl()}/auth/refresh`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ refreshToken, sessionId: sessionId ?? undefined })
|
||||
@@ -320,14 +385,19 @@ export function buildSystemSettingPayload(setting: Pick<SystemSetting, 'key' | '
|
||||
export async function apiFetch<T>(path: string, options: RequestInit = {}, token?: string | null, allowRetry = true): Promise<T> {
|
||||
const resolvedToken = token ?? (typeof window !== 'undefined' ? window.localStorage.getItem(AUTH_TOKEN_KEY) : null);
|
||||
|
||||
const response = await fetch(`${API_URL}${path}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(resolvedToken ? { Authorization: `Bearer ${resolvedToken}` } : {}),
|
||||
...options.headers
|
||||
}
|
||||
});
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(`${getApiUrl()}${path}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(resolvedToken ? { Authorization: `Bearer ${resolvedToken}` } : {}),
|
||||
...options.headers
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
throw mapFetchError(error);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await parseErrorResponse(response);
|
||||
@@ -579,4 +649,5 @@ export async function setChatRoomMuted(roomId: string, muted: boolean, token?: s
|
||||
return apiFetch(`/chat/rooms/${roomId}/mute`, { method: 'POST', body: JSON.stringify({ muted }) }, token);
|
||||
}
|
||||
|
||||
export const WS_URL = process.env.NEXT_PUBLIC_WS_URL ?? 'ws://localhost:8085/ws';
|
||||
/** @deprecated Используйте getWsUrl() — URL может переключаться на same-origin /idp-api/ws в браузере */
|
||||
export const WS_URL = configuredWsUrl;
|
||||
|
||||
@@ -109,6 +109,14 @@ function parseBooleanValue(value: string) {
|
||||
|
||||
export const MESSAGING_SETTING_KEYS = SYSTEM_SETTING_CATALOG.filter((item) => item.group === 'messaging').map((item) => item.key);
|
||||
|
||||
export const EMAIL_SETTING_KEYS = SYSTEM_SETTING_CATALOG.filter((item) =>
|
||||
item.key.startsWith('EMAIL_')
|
||||
).map((item) => item.key);
|
||||
|
||||
export const SMS_SETTING_KEYS = SYSTEM_SETTING_CATALOG.filter((item) =>
|
||||
item.key.startsWith('SMS_')
|
||||
).map((item) => item.key);
|
||||
|
||||
export function sortSettingsByCatalog<T extends { key: string }>(settings: T[]) {
|
||||
const order = new Map(SYSTEM_SETTING_CATALOG.map((item, index) => [item.key, index]));
|
||||
return [...settings].sort((a, b) => (order.get(a.key) ?? 999) - (order.get(b.key) ?? 999));
|
||||
|
||||
Reference in New Issue
Block a user