ci / api / api (push) Successful in 43s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m19s
ci / desktop / rust (desktop proxy) (push) Failing after 3m34s
ci / ts / ts (packages + web) (push) Failing after 2m49s
release / release (версия и заметки) (push) Successful in 5s
ci / db / db (push) Successful in 40s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m12s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m28s
release / android (APK в релиз) (push) Failing after 2m0s
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
2.5 KiB
TypeScript
87 lines
2.5 KiB
TypeScript
import './styles.css';
|
|
|
|
import { AuthSession } from '@pipu/core';
|
|
import { createI18n, pickLocale } from '@pipu/i18n';
|
|
import { StrictMode } from 'react';
|
|
import { createRoot } from 'react-dom/client';
|
|
import { I18nextProvider } from 'react-i18next';
|
|
|
|
import { App } from './App';
|
|
import { createAppRouter } from './app/router';
|
|
import { applyTheme } from './app/session';
|
|
import { createDesktop, DesktopProvider } from './desktop';
|
|
|
|
const LOCALE_KEY = 'pipu.locale';
|
|
|
|
function storedLocale(): string[] {
|
|
try {
|
|
const v = localStorage.getItem(LOCALE_KEY);
|
|
return v ? [v] : [];
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/** «Chrome / Windows» — подпись сессии в списке устройств. */
|
|
function deviceName(): string {
|
|
const ua = navigator.userAgent;
|
|
const browser = /Edg\//.test(ua)
|
|
? 'Edge'
|
|
: /Firefox\//.test(ua)
|
|
? 'Firefox'
|
|
: /Chrome\//.test(ua)
|
|
? 'Chrome'
|
|
: /Safari\//.test(ua)
|
|
? 'Safari'
|
|
: 'Browser';
|
|
const os = /Windows/.test(ua)
|
|
? 'Windows'
|
|
: /Android/.test(ua)
|
|
? 'Android'
|
|
: /iPhone|iPad/.test(ua)
|
|
? 'iOS'
|
|
: /Mac OS X/.test(ua)
|
|
? 'macOS'
|
|
: /Linux/.test(ua)
|
|
? 'Linux'
|
|
: '';
|
|
return os ? `${browser} / ${os}` : browser;
|
|
}
|
|
|
|
applyTheme(undefined);
|
|
if (import.meta.env.VITE_E2E === '1') {
|
|
const { installE2EFetch } = await import('./test/e2eBridge');
|
|
installE2EFetch();
|
|
}
|
|
const i18n = await createI18n(pickLocale([...storedLocale(), ...navigator.languages]));
|
|
document.documentElement.lang = i18n.language;
|
|
i18n.on('languageChanged', (l) => {
|
|
document.documentElement.lang = l;
|
|
try {
|
|
localStorage.setItem(LOCALE_KEY, l);
|
|
} catch {
|
|
// недоступное хранилище не мешает работе
|
|
}
|
|
});
|
|
|
|
const desktop = await createDesktop();
|
|
const session = new AuthSession({
|
|
clientType: desktop ? 'desktop' : 'web',
|
|
deviceName: desktop ? 'Pipu / Desktop' : deviceName(),
|
|
baseUrl: desktop?.proxyBase,
|
|
refreshStore: desktop?.refreshStore,
|
|
});
|
|
// До первого рендера узнаём, есть ли сессия (refresh-cookie), — guards роутера решают сразу.
|
|
await session.restore();
|
|
const router = createAppRouter(session, { desktop });
|
|
|
|
createRoot(document.getElementById('root')!).render(
|
|
<StrictMode>
|
|
<I18nextProvider i18n={i18n}>
|
|
<DesktopProvider value={desktop}>
|
|
<App session={session} router={router} />
|
|
</DesktopProvider>
|
|
</I18nextProvider>
|
|
</StrictMode>,
|
|
);
|