chore: Task 11 dead code cleanup and capability validation unification
This commit is contained in:
parent
1883a86402
commit
906148813e
15 changed files with 143 additions and 125 deletions
|
|
@ -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)
|
||||
```
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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** в качестве надежного реляционного хранилища.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,10 +44,6 @@ export class GiveawayStore {
|
|||
return await activeRepository.getGiveawayById(id);
|
||||
}
|
||||
|
||||
static async listAll(organizerId?: string): Promise<StoredGiveaway[]> {
|
||||
return await activeRepository.listGiveaways(organizerId);
|
||||
}
|
||||
|
||||
static async listSummaries(organizerId?: string): Promise<GiveawaySummary[]> {
|
||||
return await activeRepository.listGiveawaysSummary(organizerId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<PlatformType, SocialMediaProvider> = 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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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' }),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue