diff --git a/agents/antigravity/done/TASK-2026-08-21-11-dead-code-cleanup.md b/agents/antigravity/done/TASK-2026-08-21-11-dead-code-cleanup.md new file mode 100644 index 0000000..b06bfc4 --- /dev/null +++ b/agents/antigravity/done/TASK-2026-08-21-11-dead-code-cleanup.md @@ -0,0 +1,71 @@ +# Task 11: Удаление мёртвого кода Report + +**Date:** 2026-08-21 +**Base Commit SHA:** `1883a864023b0b10fe6674a035fbcffa7461c3c8` +**Status:** COMPLETED / PASS +**Assigned Agent:** Antigravity (Implementation Orchestrator) + +--- + +## 1. Executive Summary + +Проведена чистка мертвого и дублирующего кода, устранен технический долг без изменения боевых инвариантов: + +1. **Удален неиспользуемый импорт:** + - `generateCryptoSecureSeed` удален из `src/app/api/giveaways/[id]/draw/route.ts`. +2. **Ликвидация дублирующей фабрики `ProviderRegistry` (`src/providers/registry.ts`):** + - Файл `src/providers/registry.ts` удален. + - Метод `getProvider(platform)` перенесен в каноническую фабрику `ProviderFactory` (`src/providers/factory.ts`), реализующую строгий fail-closed контроль наличия `VK_SERVICE_TOKEN` в production. + - Все тестовые вызовы (`tests/concurrency.test.ts`, `tests/payload-summary-regression.test.ts`, `tests/winner-count-contract.test.ts`, `tests/security.test.ts`) и документация `docs/ARCHITECTURE.md` переведены на `ProviderFactory`. +3. **Объединение валидации возможностей провайдера (`validateProviderCapabilities`):** + - Проверка `requireSubscription` перенесена в канонический валидатор `validateProviderCapabilities` (`src/core/validation/giveaway-schemas.ts`). + - Дублирующий модуль `src/core/filtering/rule-validation.ts` удален. + - Тестовый набор `tests/provider-capabilities.test.ts` перенастроен на тестирование `validateProviderCapabilities` (все 11 тестов успешны). +4. **Удаление `GiveawayStore.listAll` (`src/lib/giveaway-store.ts`):** + - Неиспользуемый метод `listAll` удален из класса `GiveawayStore`. +5. **Упрощение `getOAuthClient()` (`src/integrations/vk/vk-oauth-client.ts`):** + - Удалены избыточные тождественные ветви `if/else`, возвращавшие одну и ту же переменную `defaultVkOAuthClient`. +6. **Сохранение статусов FSM (`DRAFT`, `FETCHING`, `PUBLISHED`, `CANCELLED`):** + - Статусы сохранены в `GiveawayStatusType` и таблице переходов FSM согласно контракту (являются заделом под фичи публикации итогов в группу VK и отмены конкурса). + +--- + +## 2. Modified & Deleted Files + +| File | Status | Description | +|------|--------|-------------| +| `src/core/filtering/rule-validation.ts` | DELETED | Удален дублирующий валидатор правил. | +| `src/providers/registry.ts` | DELETED | Удалена неконсистентная фабрика `ProviderRegistry`. | +| `src/app/api/giveaways/[id]/draw/route.ts` | MODIFIED | Удален неиспользуемый импорт `generateCryptoSecureSeed`. | +| `src/providers/factory.ts` | MODIFIED | Добавлен метод `getProvider(platform: PlatformType)` с fail-fast проверкой неподдерживаемых платформ. | +| `src/core/validation/giveaway-schemas.ts` | MODIFIED | В `validateProviderCapabilities` добавлена проверка `requireSubscription`. | +| `src/lib/giveaway-store.ts` | MODIFIED | Удален неиспользуемый метод `listAll`. | +| `src/integrations/vk/vk-oauth-client.ts` | MODIFIED | Упрощена функция `getOAuthClient()`. | +| `tests/provider-capabilities.test.ts` | MODIFIED | Переведен на `validateProviderCapabilities` и `ProviderFactory`. | +| `tests/concurrency.test.ts` | MODIFIED | Удален импорт и вызовы `ProviderRegistry`. | +| `tests/payload-summary-regression.test.ts` | MODIFIED | Удален импорт и вызовы `ProviderRegistry`. | +| `tests/winner-count-contract.test.ts` | MODIFIED | Удален импорт и вызовы `ProviderRegistry`. | +| `tests/security.test.ts` | MODIFIED | Переведен на `ProviderFactory`. | +| `docs/ARCHITECTURE.md` | MODIFIED | Обновлена ссылка на `ProviderFactory`. | + +--- + +## 3. Предложение следующей задачи (FSM Statuses Lifecycle) + +Статусы `DRAFT`, `FETCHING`, `PUBLISHED`, `CANCELLED` сохранены в `src/core/fsm/giveaway-fsm.ts`. +Рекомендуется оформить отдельную задачу на реализацию недостающих пользовательских сценариев: +1. `POST /api/giveaways/[id]/cancel` — отмена активного розыгрыша организатором с фиксацией аудиторного события (`status: 'CANCELLED'`). +2. `POST /api/giveaways/[id]/publish` — автоматическая публикация карточки с итогами и победителями на стену сообщества через VK API (`status: 'PUBLISHED'`). + +--- + +## 4. Verification Evidence + +```text +npx prisma generate -> EXIT 0 +npx tsc --noEmit -> EXIT 0 +npm test -> EXIT 0 (57 suites, 333 tests passed) +npm run lint -> EXIT 0 (0 errors, 6 warnings on no-img-element) +npm run build -> EXIT 0 (All 17 routes compiled successfully) +npm audit --omit=dev -> EXIT 0 (0 vulnerabilities) +``` diff --git a/agents/antigravity/inbox/TASK-2026-08-21-11-dead-code-cleanup.md b/agents/antigravity/inbox/TASK-2026-08-21-11-dead-code-cleanup.md new file mode 100644 index 0000000..f704246 --- /dev/null +++ b/agents/antigravity/inbox/TASK-2026-08-21-11-dead-code-cleanup.md @@ -0,0 +1,26 @@ +# Task 11: Удаление мёртвого кода + +**Assigned to:** Antigravity (Implementation Orchestrator) +**Priority:** LOW (tech debt cleanup) +**Date:** 2026-08-21 +**Base SHA:** `1883a864023b0b10fe6674a035fbcffa7461c3c8` + +## Scope +1. **Unused import in `src/app/api/giveaways/[id]/draw/route.ts`**: + - Remove unused import `generateCryptoSecureSeed`. +2. **`ProviderRegistry` (`src/providers/registry.ts`)**: + - Delete dead `src/providers/registry.ts` which duplicates `ProviderFactory` with inconsistent token lengths and non-fail-fast behavior. +3. **`rule-validation.ts` (`src/core/filtering/rule-validation.ts`) vs `validateProviderCapabilities`**: + - Inspect `requireSubscription` check in `src/core/filtering/rule-validation.ts`. + - Transfer required capability checks (including `requireSubscription` checking `supportsSubscriptions`) into canonical `validateProviderCapabilities` in `src/core/validation/giveaway-schemas.ts`. + - Remove redundant `src/core/filtering/rule-validation.ts`. + - Update `tests/provider-capabilities.test.ts` to test canonical `validateProviderCapabilities`. +4. **`GiveawayStore.listAll` (`src/lib/giveaway-store.ts`)**: + - Remove unused `listAll` method. +5. **`getOAuthClient()` in `src/integrations/vk/vk-oauth-client.ts`**: + - Clean up redundant branches in `getOAuthClient()`. +6. **FSM unreachable statuses (`DRAFT`, `FETCHING`, `PUBLISHED`, `CANCELLED`)**: + - Per instructions, **DO NOT delete** from `GiveawayStatusType` or FSM transitions. Document them as reserved for future publication & cancellation features. +7. Verification gate: + - `npm test`, `npx prisma generate`, `npx tsc --noEmit`, `npm run lint`, `npm run build`, `npm audit --omit=dev`. + - Save report to `agents/antigravity/done/TASK-2026-08-21-11-dead-code-cleanup.md`. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 6557896..2f20c81 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -33,7 +33,7 @@ graph TD - `checkSubscription(userIds: string[], groupId: string)`: Проверка подписки на сообщество. - **`VkProvider`**: Боевой клиент к VK API с поддержкой пакетных запросов `execute`. - **`VkMockProvider`**: Тестовый провайдер для демонстрации, локальной разработки и оффлайн-тестирования. -- **`ProviderRegistry`**: Фабрика для получения провайдера по типу платформы (`vk`, `telegram`, `youtube`). +- **`ProviderFactory`**: Фабрика для получения провайдера по типу платформы (`VK`, `TELEGRAM`, `YOUTUBE`). ### 2.3. Data & Persistence Layer (`prisma/` + `src/lib/`) - **PostgreSQL** в качестве надежного реляционного хранилища. diff --git a/src/app/api/giveaways/[id]/draw/route.ts b/src/app/api/giveaways/[id]/draw/route.ts index 0795013..39ead35 100644 --- a/src/app/api/giveaways/[id]/draw/route.ts +++ b/src/app/api/giveaways/[id]/draw/route.ts @@ -1,6 +1,5 @@ import { NextRequest, NextResponse } from 'next/server'; import { GiveawayStore } from '@/lib/giveaway-store'; -import { generateCryptoSecureSeed } from '@/core/randomizer/hasher'; import { executeDeterministicDrawV1 } from '@/core/randomizer/deterministic'; import { executeDrawSchema } from '@/core/validation/giveaway-schemas'; import { diff --git a/src/core/filtering/rule-validation.ts b/src/core/filtering/rule-validation.ts deleted file mode 100644 index 9d48da2..0000000 --- a/src/core/filtering/rule-validation.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { FilterRules } from '../types/giveaway'; -import { ProviderCapabilities } from '../../providers/types'; - -export interface RuleValidationResult { - valid: boolean; - errors: string[]; -} - -/** - * Validates that the requested filter rules can actually be verified by the - * selected social-media provider. This prevents organizers from configuring - * giveaways with conditions (e.g. reposts) that the provider cannot check. - */ -export function validateFilterRulesAgainstProviderCapabilities( - rules: FilterRules, - capabilities: ProviderCapabilities -): RuleValidationResult { - const errors: string[] = []; - - if (rules.requireRepost && !capabilities.reposts) { - errors.push( - `requireRepost is not supported by the ${capabilities.repostsNote || 'current provider'}` - ); - } - - if (rules.requireSubscription && !capabilities.subscriptions) { - errors.push('requireSubscription is not supported by the current provider'); - } - - if (rules.excludeAdmins && !capabilities.adminDetection) { - errors.push( - `excludeAdmins is not supported by the ${capabilities.adminDetectionNote || 'current provider'}` - ); - } - - // likes/comments are considered universally supported by providers that have - // them declared; the engine itself still needs a provider to fetch them. - - return { - valid: errors.length === 0, - errors, - }; -} diff --git a/src/core/validation/giveaway-schemas.ts b/src/core/validation/giveaway-schemas.ts index 271e480..565e484 100644 --- a/src/core/validation/giveaway-schemas.ts +++ b/src/core/validation/giveaway-schemas.ts @@ -80,6 +80,13 @@ export function validateProviderCapabilities( ); } + if (rules.requireSubscription && !capabilities.subscriptions) { + throw new ValidationError( + 'Subscription verification is not supported by the current provider', + { condition: 'requireSubscription' } + ); + } + if (rules.excludeAdmins && !capabilities.adminDetection) { throw new ValidationError( 'Admin detection requires VK ID organizer authorization', diff --git a/src/integrations/vk/vk-oauth-client.ts b/src/integrations/vk/vk-oauth-client.ts index 961c08e..eb4b926 100644 --- a/src/integrations/vk/vk-oauth-client.ts +++ b/src/integrations/vk/vk-oauth-client.ts @@ -271,8 +271,5 @@ export function setOAuthClient(client: IVkOAuthClient): void { } export function getOAuthClient(): IVkOAuthClient { - if (process.env.USE_VK_MOCK === 'true' || (process.env.NODE_ENV === 'test' && !process.env.VK_APP_ID)) { - return defaultVkOAuthClient; - } return defaultVkOAuthClient; } diff --git a/src/lib/giveaway-store.ts b/src/lib/giveaway-store.ts index c57cd10..addd190 100644 --- a/src/lib/giveaway-store.ts +++ b/src/lib/giveaway-store.ts @@ -44,10 +44,6 @@ export class GiveawayStore { return await activeRepository.getGiveawayById(id); } - static async listAll(organizerId?: string): Promise { - return await activeRepository.listGiveaways(organizerId); - } - static async listSummaries(organizerId?: string): Promise { return await activeRepository.listGiveawaysSummary(organizerId); } diff --git a/src/providers/factory.ts b/src/providers/factory.ts index 424d303..68e8981 100644 --- a/src/providers/factory.ts +++ b/src/providers/factory.ts @@ -1,7 +1,8 @@ +import { PlatformType } from '../core/types/giveaway'; import { SocialMediaProvider } from './types'; import { VkProvider } from './vk/vk-provider'; import { VkMockProvider } from './vk/vk-mock-provider'; -import { DependencyUnavailableError } from '../core/errors/http-errors'; +import { DependencyUnavailableError, ValidationError } from '../core/errors/http-errors'; export class ProviderFactory { public static getVkProvider(): SocialMediaProvider { @@ -26,4 +27,16 @@ export class ProviderFactory { 'VK provider credentials are not configured. Configure VK_SERVICE_TOKEN or set USE_VK_MOCK=true for staging/test.' ); } + + public static getProvider(platform: PlatformType): SocialMediaProvider { + switch (platform) { + case 'VK': + return this.getVkProvider(); + case 'TELEGRAM': + case 'YOUTUBE': + throw new ValidationError(`Platform "${platform}" is not currently supported`); + default: + throw new ValidationError(`Unknown platform: ${platform}`); + } + } } diff --git a/src/providers/registry.ts b/src/providers/registry.ts deleted file mode 100644 index 4b89328..0000000 --- a/src/providers/registry.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { PlatformType } from '../core/types/giveaway'; -import { SocialMediaProvider } from './types'; -import { VkMockProvider } from './vk/vk-mock-provider'; -import { VkProvider } from './vk/vk-provider'; - -export class ProviderRegistry { - private static providers: Map = new Map(); - - static { - // Determine whether to use real VK provider or mock provider - const useRealVk = Boolean(process.env.VK_SERVICE_TOKEN && process.env.VK_SERVICE_TOKEN.trim().length > 10); - const vkProvider = useRealVk ? new VkProvider() : new VkMockProvider(); - - this.providers.set('VK', vkProvider); - } - - /** - * Register or override a provider for a platform - */ - static registerProvider(platform: PlatformType, provider: SocialMediaProvider): void { - this.providers.set(platform, provider); - } - - /** - * Get provider by platform type - */ - static getProvider(platform: PlatformType): SocialMediaProvider { - const provider = this.providers.get(platform); - if (!provider) { - throw new Error(`Provider for platform "${platform}" is not registered`); - } - return provider; - } - - /** - * Force set mock provider for testing purposes - */ - static useMockVk(): void { - this.providers.set('VK', new VkMockProvider()); - } -} diff --git a/tests/concurrency.test.ts b/tests/concurrency.test.ts index 44af2be..c983290 100644 --- a/tests/concurrency.test.ts +++ b/tests/concurrency.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { NextRequest } from 'next/server'; import { GiveawayStore } from '../src/lib/giveaway-store'; import { MemoryGiveawayRepository } from '../src/lib/repository/memory-repository'; -import { ProviderRegistry } from '../src/providers/registry'; import { POST as drawPost } from '../src/app/api/giveaways/[id]/draw/route'; import { POST as participantsPost } from '../src/app/api/giveaways/[id]/participants/route'; import { POST as snapshotPost } from '../src/app/api/giveaways/[id]/snapshot/route'; @@ -55,7 +54,6 @@ async function createReadyGiveaway() { describe('Concurrency analysis', () => { beforeEach(async () => { GiveawayStore.setRepository(new MemoryGiveawayRepository()); - ProviderRegistry.useMockVk(); defaultSessionStore.clear(); sessionId = await defaultSessionStore.createSession(testUser); }); diff --git a/tests/payload-summary-regression.test.ts b/tests/payload-summary-regression.test.ts index 6a7ee76..a93a849 100644 --- a/tests/payload-summary-regression.test.ts +++ b/tests/payload-summary-regression.test.ts @@ -4,7 +4,6 @@ import { GiveawayStore } from '../src/lib/giveaway-store'; import { MemoryGiveawayRepository } from '../src/lib/repository/memory-repository'; import { POST as participantsPost } from '../src/app/api/giveaways/[id]/participants/route'; import { DEFAULT_FILTER_RULES } from '../src/core/types/giveaway'; -import { ProviderRegistry } from '../src/providers/registry'; import { defaultSessionStore, SESSION_COOKIE_NAME } from '../src/lib/auth/session'; describe('POST /participants Payload Summary Regression Test', () => { @@ -13,7 +12,6 @@ describe('POST /participants Payload Summary Regression Test', () => { beforeEach(async () => { GiveawayStore.setRepository(new MemoryGiveawayRepository()); - ProviderRegistry.useMockVk(); defaultSessionStore.clear(); sessionId = await defaultSessionStore.createSession(user); }); diff --git a/tests/provider-capabilities.test.ts b/tests/provider-capabilities.test.ts index d9fe029..c8ee82f 100644 --- a/tests/provider-capabilities.test.ts +++ b/tests/provider-capabilities.test.ts @@ -1,14 +1,14 @@ import { describe, it, expect, beforeEach } from 'vitest'; -import { validateFilterRulesAgainstProviderCapabilities } from '../src/core/filtering/rule-validation'; +import { validateProviderCapabilities } from '../src/core/validation/giveaway-schemas'; import { VkMockProvider } from '../src/providers/vk/vk-mock-provider'; import { VkProvider } from '../src/providers/vk/vk-provider'; -import { ProviderRegistry } from '../src/providers/registry'; import { FilterRules } from '../src/core/types/giveaway'; import { NextRequest } from 'next/server'; import { POST as participantsPost } from '../src/app/api/giveaways/[id]/participants/route'; import { GiveawayStore } from '../src/lib/giveaway-store'; import { MemoryGiveawayRepository } from '../src/lib/repository/memory-repository'; import { defaultSessionStore, SESSION_COOKIE_NAME } from '../src/lib/auth/session'; +import { ValidationError } from '../src/core/errors/http-errors'; const testUser = { id: 'usr_capabilities_tester', vkUserId: '77777' }; let sessionId: string; @@ -34,7 +34,6 @@ async function createGiveaway(store: typeof GiveawayStore) { requireSubscription: false, excludeAdmins: false, excludeBlacklistedIds: [], - excludeDuplicateComments: true, }, winnersCount: 1, reserveWinnersCount: 0, @@ -56,7 +55,6 @@ function buildReq(id: string, body: object): NextRequest { describe('Provider capabilities', () => { beforeEach(async () => { GiveawayStore.setRepository(new MemoryGiveawayRepository()); - ProviderRegistry.useMockVk(); defaultSessionStore.clear(); sessionId = await defaultSessionStore.createSession(testUser); }); @@ -95,12 +93,10 @@ describe('Provider capabilities', () => { requireSubscription: false, excludeAdmins: false, excludeBlacklistedIds: [], - excludeDuplicateComments: true, }; const provider = new VkMockProvider(); - const result = validateFilterRulesAgainstProviderCapabilities(rules, provider.capabilities); - expect(result.valid).toBe(false); - expect(result.errors.some(e => e.includes('requireRepost'))).toBe(true); + expect(() => validateProviderCapabilities(rules, provider.capabilities)).toThrow(ValidationError); + expect(() => validateProviderCapabilities(rules, provider.capabilities)).toThrow(/repost/i); }); it('validation rejects excludeAdmins when provider cannot detect admins', () => { @@ -111,12 +107,24 @@ describe('Provider capabilities', () => { requireSubscription: false, excludeAdmins: true, excludeBlacklistedIds: [], - excludeDuplicateComments: true, }; const provider = new VkMockProvider(); - const result = validateFilterRulesAgainstProviderCapabilities(rules, provider.capabilities); - expect(result.valid).toBe(false); - expect(result.errors.some(e => e.includes('excludeAdmins'))).toBe(true); + expect(() => validateProviderCapabilities(rules, provider.capabilities)).toThrow(ValidationError); + expect(() => validateProviderCapabilities(rules, provider.capabilities)).toThrow(/admin/i); + }); + + it('validation rejects requireSubscription when provider does not support subscriptions', () => { + const rules: FilterRules = { + requireLike: false, + requireComment: false, + requireRepost: false, + requireSubscription: true, + excludeAdmins: false, + excludeBlacklistedIds: [], + }; + const capabilities = { ...new VkMockProvider().capabilities, subscriptions: false }; + expect(() => validateProviderCapabilities(rules, capabilities)).toThrow(ValidationError); + expect(() => validateProviderCapabilities(rules, capabilities)).toThrow(/subscription/i); }); it('validation accepts supported combinations', () => { @@ -128,12 +136,9 @@ describe('Provider capabilities', () => { targetGroupId: '-100', excludeAdmins: false, excludeBlacklistedIds: [], - excludeDuplicateComments: true, }; const provider = new VkMockProvider(); - const result = validateFilterRulesAgainstProviderCapabilities(rules, provider.capabilities); - expect(result.valid).toBe(true); - expect(result.errors).toHaveLength(0); + expect(() => validateProviderCapabilities(rules, provider.capabilities)).not.toThrow(); }); it('participants route returns 400 when requireRepost is requested for VK', async () => { @@ -146,7 +151,6 @@ describe('Provider capabilities', () => { requireSubscription: false, excludeAdmins: false, excludeBlacklistedIds: [], - excludeDuplicateComments: true, }, }); @@ -167,7 +171,6 @@ describe('Provider capabilities', () => { requireSubscription: false, excludeAdmins: true, excludeBlacklistedIds: [], - excludeDuplicateComments: true, }, }); @@ -189,7 +192,6 @@ describe('Provider capabilities', () => { targetGroupId: '-100', excludeAdmins: false, excludeBlacklistedIds: [], - excludeDuplicateComments: true, }, }); diff --git a/tests/security.test.ts b/tests/security.test.ts index abf3cf7..746d669 100644 --- a/tests/security.test.ts +++ b/tests/security.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach } from 'vitest'; -import { ProviderRegistry } from '../src/providers/registry'; +import { ProviderFactory } from '../src/providers/factory'; import { VkProvider } from '../src/providers/vk/vk-provider'; import { GiveawayStore } from '../src/lib/giveaway-store'; import { MemoryGiveawayRepository } from '../src/lib/repository/memory-repository'; @@ -14,13 +14,11 @@ describe('Security: VK_SERVICE_TOKEN handling', () => { beforeEach(() => { GiveawayStore.setRepository(new MemoryGiveawayRepository()); - ProviderRegistry.useMockVk(); }); - it('ProviderRegistry does not expose VK_SERVICE_TOKEN in public API', () => { + it('ProviderFactory does not expose VK_SERVICE_TOKEN in public API', () => { process.env.VK_SERVICE_TOKEN = secretToken; - // Re-initialize registry (static block already ran, but we can inspect provider) - const provider = ProviderRegistry.getProvider('VK'); + const provider = ProviderFactory.getProvider('VK'); expect(provider.platform).toBe('VK'); expect(provider).not.toHaveProperty('serviceToken'); delete process.env.VK_SERVICE_TOKEN; @@ -63,7 +61,6 @@ describe('Security: VK_SERVICE_TOKEN handling', () => { it('Post preview response does not contain VK_SERVICE_TOKEN', async () => { process.env.VK_SERVICE_TOKEN = secretToken; - ProviderRegistry.useMockVk(); // mock so no real API call const req = new NextRequest('http://localhost/api/posts/preview', { method: 'POST', body: JSON.stringify({ url: 'https://vk.com/wall-1_1' }), diff --git a/tests/winner-count-contract.test.ts b/tests/winner-count-contract.test.ts index ff178f4..cd2dcf2 100644 --- a/tests/winner-count-contract.test.ts +++ b/tests/winner-count-contract.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { NextRequest } from 'next/server'; import { GiveawayStore } from '../src/lib/giveaway-store'; import { MemoryGiveawayRepository } from '../src/lib/repository/memory-repository'; -import { ProviderRegistry } from '../src/providers/registry'; import { POST as drawPost } from '../src/app/api/giveaways/[id]/draw/route'; import { DEFAULT_FILTER_RULES } from '../src/core/types/giveaway'; import { FilteredParticipant } from '../src/core/types/participant'; @@ -15,7 +14,6 @@ describe('Winner Count Contract & Draw Retry Invariants', () => { beforeEach(async () => { GiveawayStore.setRepository(new MemoryGiveawayRepository()); - ProviderRegistry.useMockVk(); defaultSessionStore.clear(); sessionId = await defaultSessionStore.createSession(testUser); });