refactor: migrate to eslint flat config and format codebase with prettier

- Remove legacy .eslintrc.cjs and .eslintignore
- Add eslint.config.js with flat config, security rules (no-eval, no-implied-eval, no-new-func, no-script-url)
- Add .prettierrc and .prettierignore
- Format entire codebase with prettier
This commit is contained in:
c0mrade
2026-01-27 17:37:31 +03:00
parent 111ccc4e7a
commit bc90ba3779
133 changed files with 19972 additions and 15523 deletions

View File

@@ -1,39 +1,44 @@
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import type { RegisterResponse, User } from '../types'
import { authApi } from '../api/auth'
import { apiClient } from '../api/client'
import { tokenStorage, isTokenValid, tokenRefreshManager } from '../utils/token'
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { RegisterResponse, User } from '../types';
import { authApi } from '../api/auth';
import { apiClient } from '../api/client';
import { tokenStorage, isTokenValid, tokenRefreshManager } from '../utils/token';
export interface TelegramWidgetData {
id: number
first_name: string
last_name?: string
username?: string
photo_url?: string
auth_date: number
hash: string
id: number;
first_name: string;
last_name?: string;
username?: string;
photo_url?: string;
auth_date: number;
hash: string;
}
interface AuthState {
accessToken: string | null
refreshToken: string | null
user: User | null
isAuthenticated: boolean
isLoading: boolean
isAdmin: boolean
accessToken: string | null;
refreshToken: string | null;
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
isAdmin: boolean;
setTokens: (accessToken: string, refreshToken: string) => void
setUser: (user: User) => void
setIsAdmin: (isAdmin: boolean) => void
logout: () => void
initialize: () => Promise<void>
refreshUser: () => Promise<void>
checkAdminStatus: () => Promise<void>
loginWithTelegram: (initData: string) => Promise<void>
loginWithTelegramWidget: (data: TelegramWidgetData) => Promise<void>
loginWithEmail: (email: string, password: string) => Promise<void>
registerWithEmail: (email: string, password: string, firstName?: string, referralCode?: string) => Promise<RegisterResponse>
setTokens: (accessToken: string, refreshToken: string) => void;
setUser: (user: User) => void;
setIsAdmin: (isAdmin: boolean) => void;
logout: () => void;
initialize: () => Promise<void>;
refreshUser: () => Promise<void>;
checkAdminStatus: () => Promise<void>;
loginWithTelegram: (initData: string) => Promise<void>;
loginWithTelegramWidget: (data: TelegramWidgetData) => Promise<void>;
loginWithEmail: (email: string, password: string) => Promise<void>;
registerWithEmail: (
email: string,
password: string,
firstName?: string,
referralCode?: string,
) => Promise<RegisterResponse>;
}
// Блокировка для предотвращения race condition при инициализации
@@ -42,7 +47,7 @@ const initState = {
promise: null as Promise<void> | null,
isInitializing: false,
isInitialized: false,
}
};
export const useAuthStore = create<AuthState>()(
persist(
@@ -55,59 +60,59 @@ export const useAuthStore = create<AuthState>()(
isAdmin: false,
setTokens: (accessToken, refreshToken) => {
tokenStorage.setTokens(accessToken, refreshToken)
tokenStorage.setTokens(accessToken, refreshToken);
set({
accessToken,
refreshToken,
isAuthenticated: true,
})
});
},
setUser: (user) => {
set({ user })
set({ user });
},
setIsAdmin: (isAdmin) => {
set({ isAdmin })
set({ isAdmin });
},
logout: () => {
// Get refresh token from secure storage, not zustand state
const refreshToken = tokenStorage.getRefreshToken()
const refreshToken = tokenStorage.getRefreshToken();
if (refreshToken) {
authApi.logout(refreshToken).catch(() => {
// Logout API call failed - ignore silently
})
});
}
tokenStorage.clearTokens()
tokenStorage.clearTokens();
set({
accessToken: null,
refreshToken: null,
user: null,
isAuthenticated: false,
isAdmin: false,
})
});
},
checkAdminStatus: async () => {
try {
const token = tokenStorage.getAccessToken()
const token = tokenStorage.getAccessToken();
if (!token || !isTokenValid(token)) {
set({ isAdmin: false })
return
set({ isAdmin: false });
return;
}
// Используем apiClient для единообразной обработки ошибок
const response = await apiClient.get<{ is_admin: boolean }>('/cabinet/auth/me/is-admin')
set({ isAdmin: response.data.is_admin })
const response = await apiClient.get<{ is_admin: boolean }>('/cabinet/auth/me/is-admin');
set({ isAdmin: response.data.is_admin });
} catch {
set({ isAdmin: false })
set({ isAdmin: false });
}
},
refreshUser: async () => {
try {
const user = await authApi.getMe()
set({ user })
const user = await authApi.getMe();
set({ user });
} catch {
// Failed to refresh user - ignore silently
}
@@ -116,150 +121,150 @@ export const useAuthStore = create<AuthState>()(
initialize: async () => {
// Защита от race condition - если уже инициализировано, выходим
if (initState.isInitialized) {
return
return;
}
// Если уже идёт инициализация, ждём её завершения
if (initState.isInitializing && initState.promise) {
return initState.promise
return initState.promise;
}
initState.isInitializing = true
initState.isInitializing = true;
initState.promise = (async () => {
try {
set({ isLoading: true })
set({ isLoading: true });
// Миграция токенов из localStorage (для обратной совместимости)
tokenStorage.migrateFromLocalStorage()
tokenStorage.migrateFromLocalStorage();
const accessToken = tokenStorage.getAccessToken()
const refreshToken = tokenStorage.getRefreshToken()
const accessToken = tokenStorage.getAccessToken();
const refreshToken = tokenStorage.getRefreshToken();
if (!accessToken || !refreshToken) {
set({ isLoading: false, isAuthenticated: false })
return
set({ isLoading: false, isAuthenticated: false });
return;
}
// Проверяем валидность токена перед использованием
if (!isTokenValid(accessToken)) {
// Используем централизованный менеджер для refresh
const newToken = await tokenRefreshManager.refreshAccessToken()
const newToken = await tokenRefreshManager.refreshAccessToken();
if (newToken) {
const user = await authApi.getMe()
const user = await authApi.getMe();
// Сначала проверяем admin статус, потом снимаем isLoading
await get().checkAdminStatus()
await get().checkAdminStatus();
set({
accessToken: newToken,
refreshToken,
user,
isAuthenticated: true,
isLoading: false,
})
});
} else {
tokenStorage.clearTokens()
tokenStorage.clearTokens();
set({
accessToken: null,
refreshToken: null,
user: null,
isAuthenticated: false,
isLoading: false,
})
});
}
return
return;
}
try {
const user = await authApi.getMe()
const user = await authApi.getMe();
// Сначала проверяем admin статус, потом снимаем isLoading
await get().checkAdminStatus()
await get().checkAdminStatus();
set({
accessToken,
refreshToken,
user,
isAuthenticated: true,
isLoading: false,
})
});
} catch {
// Token might be invalid on server, try to refresh
const newToken = await tokenRefreshManager.refreshAccessToken()
const newToken = await tokenRefreshManager.refreshAccessToken();
if (newToken) {
try {
const user = await authApi.getMe()
const user = await authApi.getMe();
// Сначала проверяем admin статус, потом снимаем isLoading
await get().checkAdminStatus()
await get().checkAdminStatus();
set({
accessToken: newToken,
refreshToken,
user,
isAuthenticated: true,
isLoading: false,
})
});
} catch {
tokenStorage.clearTokens()
tokenStorage.clearTokens();
set({
accessToken: null,
refreshToken: null,
user: null,
isAuthenticated: false,
isLoading: false,
})
});
}
} else {
// Refresh failed, logout
tokenStorage.clearTokens()
tokenStorage.clearTokens();
set({
accessToken: null,
refreshToken: null,
user: null,
isAuthenticated: false,
isLoading: false,
})
});
}
}
} finally {
initState.isInitializing = false
initState.isInitialized = true
initState.promise = null
initState.isInitializing = false;
initState.isInitialized = true;
initState.promise = null;
}
})()
})();
return initState.promise
return initState.promise;
},
loginWithTelegram: async (initData) => {
const response = await authApi.loginTelegram(initData)
tokenStorage.setTokens(response.access_token, response.refresh_token)
const response = await authApi.loginTelegram(initData);
tokenStorage.setTokens(response.access_token, response.refresh_token);
set({
accessToken: response.access_token,
refreshToken: response.refresh_token,
user: response.user,
isAuthenticated: true,
})
get().checkAdminStatus()
});
get().checkAdminStatus();
},
loginWithTelegramWidget: async (data) => {
const response = await authApi.loginTelegramWidget(data)
tokenStorage.setTokens(response.access_token, response.refresh_token)
const response = await authApi.loginTelegramWidget(data);
tokenStorage.setTokens(response.access_token, response.refresh_token);
set({
accessToken: response.access_token,
refreshToken: response.refresh_token,
user: response.user,
isAuthenticated: true,
})
get().checkAdminStatus()
});
get().checkAdminStatus();
},
loginWithEmail: async (email, password) => {
const response = await authApi.loginEmail(email, password)
tokenStorage.setTokens(response.access_token, response.refresh_token)
const response = await authApi.loginEmail(email, password);
tokenStorage.setTokens(response.access_token, response.refresh_token);
set({
accessToken: response.access_token,
refreshToken: response.refresh_token,
user: response.user,
isAuthenticated: true,
})
get().checkAdminStatus()
});
get().checkAdminStatus();
},
registerWithEmail: async (email, password, firstName, referralCode) => {
@@ -271,8 +276,8 @@ export const useAuthStore = create<AuthState>()(
first_name: firstName,
language: navigator.language.split('-')[0] || 'ru',
referral_code: referralCode,
})
return response
});
return response;
},
}),
{
@@ -282,9 +287,9 @@ export const useAuthStore = create<AuthState>()(
partialize: (state) => ({
user: state.user,
}),
}
)
)
},
),
);
// Initialize auth on app load
useAuthStore.getState().initialize()
useAuthStore.getState().initialize();

View File

@@ -1,25 +1,25 @@
import { create } from 'zustand'
import { create } from 'zustand';
export type BlockingType = 'maintenance' | 'channel_subscription' | null
export type BlockingType = 'maintenance' | 'channel_subscription' | null;
interface MaintenanceInfo {
message: string
reason?: string
message: string;
reason?: string;
}
interface ChannelSubscriptionInfo {
message: string
channel_link?: string
message: string;
channel_link?: string;
}
interface BlockingState {
blockingType: BlockingType
maintenanceInfo: MaintenanceInfo | null
channelInfo: ChannelSubscriptionInfo | null
blockingType: BlockingType;
maintenanceInfo: MaintenanceInfo | null;
channelInfo: ChannelSubscriptionInfo | null;
setMaintenance: (info: MaintenanceInfo) => void
setChannelSubscription: (info: ChannelSubscriptionInfo) => void
clearBlocking: () => void
setMaintenance: (info: MaintenanceInfo) => void;
setChannelSubscription: (info: ChannelSubscriptionInfo) => void;
clearBlocking: () => void;
}
export const useBlockingStore = create<BlockingState>((set) => ({
@@ -27,21 +27,24 @@ export const useBlockingStore = create<BlockingState>((set) => ({
maintenanceInfo: null,
channelInfo: null,
setMaintenance: (info) => set({
blockingType: 'maintenance',
maintenanceInfo: info,
channelInfo: null,
}),
setMaintenance: (info) =>
set({
blockingType: 'maintenance',
maintenanceInfo: info,
channelInfo: null,
}),
setChannelSubscription: (info) => set({
blockingType: 'channel_subscription',
channelInfo: info,
maintenanceInfo: null,
}),
setChannelSubscription: (info) =>
set({
blockingType: 'channel_subscription',
channelInfo: info,
maintenanceInfo: null,
}),
clearBlocking: () => set({
blockingType: null,
maintenanceInfo: null,
channelInfo: null,
}),
}))
clearBlocking: () =>
set({
blockingType: null,
maintenanceInfo: null,
channelInfo: null,
}),
}));