fix and update

This commit is contained in:
lendry
2026-07-05 18:28:25 +03:00
parent ef7f0c5380
commit adbd32fea0
621 changed files with 49 additions and 49691 deletions

View File

@@ -1,6 +1,22 @@
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(/\/$/, '');
const MOBILE_API_URL_KEY = 'lendry_mobile_api_url';
declare global {
interface Window {
__LENDRY_DIRECT_API_URL__?: string;
}
}
function resolveDirectApiOverride(): string | null {
if (typeof window === 'undefined') return null;
const fromWindow = window.__LENDRY_DIRECT_API_URL__?.trim();
if (fromWindow) return fromWindow.replace(/\/$/, '');
const fromStorage = window.localStorage.getItem(MOBILE_API_URL_KEY)?.trim();
if (fromStorage) return fromStorage.replace(/\/$/, '');
return null;
}
function getServerApiUrl(): string {
return (process.env.INTERNAL_API_URL ?? configuredApiUrl).replace(/\/$/, '');
@@ -26,6 +42,9 @@ function isLocalDevApiUrl(url: string): boolean {
}
function resolveBrowserApiBaseUrl(): string {
const directApi = resolveDirectApiOverride();
if (directApi) return directApi;
// SSR: внутренний URL Docker-сети (api-gateway), не публичный домен.
if (typeof window === 'undefined') {
return getServerApiUrl();
@@ -261,7 +280,7 @@ export async function uploadMediaObject(
const apiBase = getApiUrl().replace(/\/$/, '');
const formData = new FormData();
formData.append('file', file, file instanceof File ? file.name : 'upload.bin');
const response = await fetch(`${apiBase}/media/upload`, {
const response = await platformFetch(`${apiBase}/media/upload`, {
method: 'POST',
headers: { 'X-Upload-Token': presigned.uploadToken },
body: formData
@@ -272,7 +291,7 @@ export async function uploadMediaObject(
return;
}
const response = await fetch(presigned.uploadUrl, {
const response = await platformFetch(presigned.uploadUrl, {
method: 'PUT',
headers: { 'Content-Type': contentType },
body: file
@@ -473,6 +492,17 @@ export function resetPinRequiredNotification() {
pinNotificationSent = false;
}
let customFetchImpl: typeof fetch | null = null;
/** Tauri/mobile: native HTTP (bypasses WebView CORS and self-signed TLS). */
export function setCustomFetch(fetchImpl: typeof fetch | null) {
customFetchImpl = fetchImpl;
}
function platformFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
return (customFetchImpl ?? fetch)(input, init);
}
function notifyPinRequired(sessionId: string) {
if (!pinRequiredHandler || pinNotificationSent) return;
pinNotificationSent = true;
@@ -909,7 +939,7 @@ function releaseApiSlot(): void {
/** Liveness: nginx → api-gateway HTTP. */
async function probeGatewayAlive(): Promise<boolean> {
try {
const response = await fetch(`${getApiUrl()}/health`, {
const response = await platformFetch(`${getApiUrl()}/health`, {
method: 'GET',
cache: 'no-store',
signal: AbortSignal.timeout(4500)
@@ -956,7 +986,7 @@ async function fetchWithGatewayRetry(
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
assertGatewayCircuitClosed(behavior);
const response = await fetch(url, init);
const response = await platformFetch(url, init);
if (GATEWAY_RETRY_STATUS.has(response.status) && attempt + 1 < maxAttempts) {
await sleep(gatewayRetryDelay(attempt));
continue;