diff --git a/auth/oauth.py b/auth/oauth.py index ad361975..74b46127 100644 --- a/auth/oauth.py +++ b/auth/oauth.py @@ -787,7 +787,12 @@ async def oauth_callback_http(request: Request) -> JSONResponse | RedirectRespon logger.error(f"❌ Exception while creating session token for {provider}: {e}", exc_info=True) raise # Re-raise для обработки в основном except блоке + if not session_token: + logger.error(f"❌ Session token is empty for {provider}") + raise ValueError("Session token creation failed") + logger.info(f"✅ Session token created for {provider}: token_length={len(session_token)}") + logger.info(f"🔧 Session token preview: {session_token[:20]}..." if len(session_token) > 20 else f"🔧 Session token: {session_token}") # Получаем redirect_uri из OAuth данных redirect_uri = oauth_data.get("redirect_uri", FRONTEND_URL) @@ -844,6 +849,7 @@ async def oauth_callback_http(request: Request) -> JSONResponse | RedirectRespon response = RedirectResponse(url=final_redirect_url, status_code=307) # 🍪 Устанавливаем httpOnly cookie для безопасности + cookie_domain = ".discours.io" if "discours.io" in parsed_redirect.netloc else None response.set_cookie( SESSION_COOKIE_NAME, session_token, @@ -852,10 +858,12 @@ async def oauth_callback_http(request: Request) -> JSONResponse | RedirectRespon samesite=SESSION_COOKIE_SAMESITE, max_age=SESSION_COOKIE_MAX_AGE, path="/", # Важно: устанавливаем path="/" для доступности cookie во всех путях - domain=".discours.io" if "discours.io" in parsed_redirect.netloc else None, # Поддержка поддоменов + domain=cookie_domain, # Поддержка поддоменов ) - logger.info(f"OAuth успешно завершен для {provider}, user_id={author.id}") + logger.info(f"🍪 Cookie установлен: name={SESSION_COOKIE_NAME}, domain={cookie_domain}, secure={SESSION_COOKIE_SECURE}") + logger.info(f"🔗 Final redirect: {final_redirect_url}") + logger.info(f"✅ OAuth успешно завершен для {provider}, user_id={author.id}") return response except Exception as e: diff --git a/package-lock.json b/package-lock.json index 635ebd8b..199a2f26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "publy-panel", - "version": "0.9.25", + "version": "0.9.29", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "publy-panel", - "version": "0.9.25", + "version": "0.9.29", "devDependencies": { "@biomejs/biome": "^2.2.4", "@graphql-codegen/cli": "^6.0.0", diff --git a/package.json b/package.json index 22b41512..06488beb 100644 --- a/package.json +++ b/package.json @@ -5,14 +5,12 @@ "description": "Publy, a modern platform for collaborative text creation, offers a user-friendly interface for authors, editors, and readers, supporting real-time collaboration and structured feedback.", "scripts": { "dev": "vite", - "prebuild": "node scripts/check-graphql-server.js", - "build": "npm run codegen:all && vite build", + "build": "npm run codegen && vite build", "serve": "vite preview", "lint": "biome check . --fix", "format": "biome format . --write", "typecheck": "tsc --noEmit", - "codegen": "graphql-codegen --config codegen.ts", - "codegen:all": "npm run codegen" + "codegen": "graphql-codegen --config codegen.ts" }, "devDependencies": { "@biomejs/biome": "^2.2.4", @@ -38,4 +36,4 @@ "overrides": { "vite": "^7.1.7" } -} +} \ No newline at end of file diff --git a/scripts/check-graphql-server.js b/scripts/check-graphql-server.js deleted file mode 100644 index b4f74bac..00000000 --- a/scripts/check-graphql-server.js +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env node -/** - * 🔍 Проверка доступности GraphQL сервера для Code Generator - * - * Проверяет доступность v3.dscrs.site/graphql и переключается на локальные схемы - * если сервер недоступен (например, в CI окружении Vercel/Netlify) - */ - -import { readFileSync, writeFileSync, existsSync } from 'fs' -import { join } from 'path' - -const GRAPHQL_URL = 'https://v3.dscrs.site/graphql' -const TIMEOUT = 10000 // 10 секунд - -/** - * Проверяет доступность GraphQL сервера - */ -async function checkGraphQLServer() { - try { - console.log('🔍 Проверяем доступность GraphQL сервера...') - - const controller = new AbortController() - const timeoutId = setTimeout(() => controller.abort(), TIMEOUT) - - const response = await fetch(GRAPHQL_URL, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'User-Agent': 'GraphQL-Codegen-Check/1.0' - }, - body: JSON.stringify({ - query: '{ __typename }' - }), - signal: controller.signal - }) - - clearTimeout(timeoutId) - - if (response.ok) { - console.log('✅ GraphQL сервер доступен') - return true - } else { - console.log(`⚠️ GraphQL сервер вернул статус: ${response.status}`) - return false - } - } catch (error) { - if (error.name === 'AbortError') { - console.log('⏰ Таймаут подключения к GraphQL серверу') - } else { - console.log(`❌ Ошибка подключения к GraphQL серверу: ${error.message}`) - } - return false - } -} - -/** - * Создает fallback конфигурацию с локальными схемами - */ -function createFallbackConfig() { - console.log('🔄 Создаем fallback конфигурацию с локальными схемами...') - - const fallbackConfig = `import type { CodegenConfig } from '@graphql-codegen/cli' - -const config: CodegenConfig = { - overwrite: true, - // 🚨 FALLBACK: Используем локальные схемы вместо удаленного сервера - schema: ['schema/*.graphql'], - documents: ['panel/graphql/queries/**/*.ts', 'panel/**/*.{ts,tsx}', '!panel/graphql/generated/**'], - generates: { - './panel/graphql/generated/introspection.json': { - plugins: ['introspection'], - config: { - minify: true - } - }, - './panel/graphql/generated/schema.graphql': { - plugins: ['schema-ast'], - config: { - includeDirectives: false - } - }, - './panel/graphql/generated/': { - preset: 'client', - plugins: [], - presetConfig: { - gqlTagName: 'gql', - fragmentMasking: false - }, - config: { - scalars: { - DateTime: 'string', - JSON: 'Record' - }, - skipTypename: false, - useTypeImports: true, - dedupeOperationSuffix: true, - dedupeFragments: true, - avoidOptionals: false, - enumsAsTypes: false - } - } - }, - config: { - skipTypename: false, - useTypeImports: true, - dedupeOperationSuffix: true, - dedupeFragments: true, - avoidOptionals: false, - enumsAsTypes: false - } -} - -export default config` - - writeFileSync('codegen.fallback.ts', fallbackConfig) - console.log('✅ Fallback конфигурация создана: codegen.fallback.ts') -} - -/** - * Проверяет наличие локальных схем - */ -function checkLocalSchemas() { - const schemaFiles = [ - 'schema/admin.graphql', - 'schema/enum.graphql', - 'schema/input.graphql', - 'schema/mutation.graphql', - 'schema/query.graphql', - 'schema/type.graphql' - ] - - const missingFiles = schemaFiles.filter(file => !existsSync(file)) - - if (missingFiles.length > 0) { - console.log('❌ Отсутствуют локальные схемы:') - missingFiles.forEach(file => console.log(` - ${file}`)) - return false - } - - console.log('✅ Все локальные схемы найдены') - return true -} - -/** - * Основная функция - */ -async function main() { - const isCI = process.env.CI === 'true' || process.env.VERCEL || process.env.NETLIFY - - if (isCI) { - console.log('🏗️ CI окружение обнаружено, используем локальные схемы') - } - - const serverAvailable = await checkGraphQLServer() - - if (!serverAvailable || isCI) { - if (!checkLocalSchemas()) { - console.log('❌ Локальные схемы недоступны, сборка невозможна') - process.exit(1) - } - - createFallbackConfig() - - // Обновляем package.json для использования fallback конфигурации - const packageJson = JSON.parse(readFileSync('package.json', 'utf8')) - packageJson.scripts.codegen = 'graphql-codegen --config codegen.fallback.ts' - writeFileSync('package.json', JSON.stringify(packageJson, null, 2)) - - console.log('🔄 package.json обновлен для использования fallback конфигурации') - } else { - console.log('✅ Используем удаленный GraphQL сервер') - } -} - -main().catch(error => { - console.error('💥 Критическая ошибка:', error) - process.exit(1) -})