algokit-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -0
- package/dist/api/boj-scraper.d.ts +68 -0
- package/dist/api/boj-scraper.d.ts.map +1 -0
- package/dist/api/boj-scraper.js +197 -0
- package/dist/api/boj-scraper.js.map +1 -0
- package/dist/api/programmers-scraper.d.ts +70 -0
- package/dist/api/programmers-scraper.d.ts.map +1 -0
- package/dist/api/programmers-scraper.js +303 -0
- package/dist/api/programmers-scraper.js.map +1 -0
- package/dist/api/solvedac-client.d.ts +67 -0
- package/dist/api/solvedac-client.d.ts.map +1 -0
- package/dist/api/solvedac-client.js +220 -0
- package/dist/api/solvedac-client.js.map +1 -0
- package/dist/api/types.d.ts +125 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +110 -0
- package/dist/api/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +594 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/hint-guide.d.ts +73 -0
- package/dist/prompts/hint-guide.d.ts.map +1 -0
- package/dist/prompts/hint-guide.js +174 -0
- package/dist/prompts/hint-guide.js.map +1 -0
- package/dist/prompts/programmers-hint-guide.d.ts +38 -0
- package/dist/prompts/programmers-hint-guide.d.ts.map +1 -0
- package/dist/prompts/programmers-hint-guide.js +134 -0
- package/dist/prompts/programmers-hint-guide.js.map +1 -0
- package/dist/services/code-analyzer.d.ts +46 -0
- package/dist/services/code-analyzer.d.ts.map +1 -0
- package/dist/services/code-analyzer.js +177 -0
- package/dist/services/code-analyzer.js.map +1 -0
- package/dist/services/hint-generator.d.ts +60 -0
- package/dist/services/hint-generator.d.ts.map +1 -0
- package/dist/services/hint-generator.js +222 -0
- package/dist/services/hint-generator.js.map +1 -0
- package/dist/services/problem-analyzer.d.ts +38 -0
- package/dist/services/problem-analyzer.d.ts.map +1 -0
- package/dist/services/problem-analyzer.js +114 -0
- package/dist/services/problem-analyzer.js.map +1 -0
- package/dist/services/programmers-problem-analyzer.d.ts +26 -0
- package/dist/services/programmers-problem-analyzer.d.ts.map +1 -0
- package/dist/services/programmers-problem-analyzer.js +64 -0
- package/dist/services/programmers-problem-analyzer.js.map +1 -0
- package/dist/services/programmers-review-template-generator.d.ts +27 -0
- package/dist/services/programmers-review-template-generator.d.ts.map +1 -0
- package/dist/services/programmers-review-template-generator.js +153 -0
- package/dist/services/programmers-review-template-generator.js.map +1 -0
- package/dist/services/review-generator.d.ts +51 -0
- package/dist/services/review-generator.d.ts.map +1 -0
- package/dist/services/review-generator.js +149 -0
- package/dist/services/review-generator.js.map +1 -0
- package/dist/services/review-template-generator.d.ts +27 -0
- package/dist/services/review-template-generator.d.ts.map +1 -0
- package/dist/services/review-template-generator.js +163 -0
- package/dist/services/review-template-generator.js.map +1 -0
- package/dist/templates/review-guideline.md +89 -0
- package/dist/tools/analyze-code-submission-boj.d.ts +67 -0
- package/dist/tools/analyze-code-submission-boj.d.ts.map +1 -0
- package/dist/tools/analyze-code-submission-boj.js +89 -0
- package/dist/tools/analyze-code-submission-boj.js.map +1 -0
- package/dist/tools/analyze-code-submission-programmers.d.ts +60 -0
- package/dist/tools/analyze-code-submission-programmers.d.ts.map +1 -0
- package/dist/tools/analyze-code-submission-programmers.js +83 -0
- package/dist/tools/analyze-code-submission-programmers.js.map +1 -0
- package/dist/tools/analyze-code-submission.d.ts +67 -0
- package/dist/tools/analyze-code-submission.d.ts.map +1 -0
- package/dist/tools/analyze-code-submission.js +89 -0
- package/dist/tools/analyze-code-submission.js.map +1 -0
- package/dist/tools/analyze-problem-boj.d.ts +48 -0
- package/dist/tools/analyze-problem-boj.d.ts.map +1 -0
- package/dist/tools/analyze-problem-boj.js +52 -0
- package/dist/tools/analyze-problem-boj.js.map +1 -0
- package/dist/tools/analyze-problem-programmers.d.ts +48 -0
- package/dist/tools/analyze-problem-programmers.d.ts.map +1 -0
- package/dist/tools/analyze-problem-programmers.js +53 -0
- package/dist/tools/analyze-problem-programmers.js.map +1 -0
- package/dist/tools/analyze-problem.d.ts +48 -0
- package/dist/tools/analyze-problem.d.ts.map +1 -0
- package/dist/tools/analyze-problem.js +52 -0
- package/dist/tools/analyze-problem.js.map +1 -0
- package/dist/tools/create-review.d.ts +47 -0
- package/dist/tools/create-review.d.ts.map +1 -0
- package/dist/tools/create-review.js +122 -0
- package/dist/tools/create-review.js.map +1 -0
- package/dist/tools/fetch-problem-content-boj.d.ts +49 -0
- package/dist/tools/fetch-problem-content-boj.d.ts.map +1 -0
- package/dist/tools/fetch-problem-content-boj.js +93 -0
- package/dist/tools/fetch-problem-content-boj.js.map +1 -0
- package/dist/tools/fetch-problem-content-programmers.d.ts +46 -0
- package/dist/tools/fetch-problem-content-programmers.d.ts.map +1 -0
- package/dist/tools/fetch-problem-content-programmers.js +74 -0
- package/dist/tools/fetch-problem-content-programmers.js.map +1 -0
- package/dist/tools/fetch-problem-content.d.ts +49 -0
- package/dist/tools/fetch-problem-content.d.ts.map +1 -0
- package/dist/tools/fetch-problem-content.js +93 -0
- package/dist/tools/fetch-problem-content.js.map +1 -0
- package/dist/tools/generate-hint-boj.d.ts +42 -0
- package/dist/tools/generate-hint-boj.d.ts.map +1 -0
- package/dist/tools/generate-hint-boj.js +80 -0
- package/dist/tools/generate-hint-boj.js.map +1 -0
- package/dist/tools/generate-hint-programmers.d.ts +42 -0
- package/dist/tools/generate-hint-programmers.d.ts.map +1 -0
- package/dist/tools/generate-hint-programmers.js +78 -0
- package/dist/tools/generate-hint-programmers.js.map +1 -0
- package/dist/tools/generate-hint.d.ts +42 -0
- package/dist/tools/generate-hint.d.ts.map +1 -0
- package/dist/tools/generate-hint.js +80 -0
- package/dist/tools/generate-hint.js.map +1 -0
- package/dist/tools/generate-review-template-boj.d.ts +48 -0
- package/dist/tools/generate-review-template-boj.d.ts.map +1 -0
- package/dist/tools/generate-review-template-boj.js +52 -0
- package/dist/tools/generate-review-template-boj.js.map +1 -0
- package/dist/tools/generate-review-template-programmers.d.ts +48 -0
- package/dist/tools/generate-review-template-programmers.d.ts.map +1 -0
- package/dist/tools/generate-review-template-programmers.js +53 -0
- package/dist/tools/generate-review-template-programmers.js.map +1 -0
- package/dist/tools/generate-review-template.d.ts +48 -0
- package/dist/tools/generate-review-template.d.ts.map +1 -0
- package/dist/tools/generate-review-template.js +52 -0
- package/dist/tools/generate-review-template.js.map +1 -0
- package/dist/tools/get-hint.d.ts +41 -0
- package/dist/tools/get-hint.d.ts.map +1 -0
- package/dist/tools/get-hint.js +108 -0
- package/dist/tools/get-hint.js.map +1 -0
- package/dist/tools/get-problem.d.ts +22 -0
- package/dist/tools/get-problem.d.ts.map +1 -0
- package/dist/tools/get-problem.js +89 -0
- package/dist/tools/get-problem.js.map +1 -0
- package/dist/tools/get-programmers-problem.d.ts +53 -0
- package/dist/tools/get-programmers-problem.d.ts.map +1 -0
- package/dist/tools/get-programmers-problem.js +161 -0
- package/dist/tools/get-programmers-problem.js.map +1 -0
- package/dist/tools/search-problems.d.ts +42 -0
- package/dist/tools/search-problems.d.ts.map +1 -0
- package/dist/tools/search-problems.js +123 -0
- package/dist/tools/search-problems.js.map +1 -0
- package/dist/tools/search-programmers-problems.d.ts +73 -0
- package/dist/tools/search-programmers-problems.d.ts.map +1 -0
- package/dist/tools/search-programmers-problems.js +171 -0
- package/dist/tools/search-programmers-problems.js.map +1 -0
- package/dist/tools/search-tags.d.ts +22 -0
- package/dist/tools/search-tags.d.ts.map +1 -0
- package/dist/tools/search-tags.js +70 -0
- package/dist/tools/search-tags.js.map +1 -0
- package/dist/types/analysis.d.ts +211 -0
- package/dist/types/analysis.d.ts.map +1 -0
- package/dist/types/analysis.js +11 -0
- package/dist/types/analysis.js.map +1 -0
- package/dist/types/problem-content.d.ts +110 -0
- package/dist/types/problem-content.d.ts.map +1 -0
- package/dist/types/problem-content.js +7 -0
- package/dist/types/problem-content.js.map +1 -0
- package/dist/types/programmers.d.ts +72 -0
- package/dist/types/programmers.d.ts.map +1 -0
- package/dist/types/programmers.js +5 -0
- package/dist/types/programmers.js.map +1 -0
- package/dist/utils/browser-pool.d.ts +93 -0
- package/dist/utils/browser-pool.d.ts.map +1 -0
- package/dist/utils/browser-pool.js +193 -0
- package/dist/utils/browser-pool.js.map +1 -0
- package/dist/utils/cache-stats.d.ts +60 -0
- package/dist/utils/cache-stats.d.ts.map +1 -0
- package/dist/utils/cache-stats.js +78 -0
- package/dist/utils/cache-stats.js.map +1 -0
- package/dist/utils/cache.d.ts +72 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +99 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/html-parser.d.ts +57 -0
- package/dist/utils/html-parser.d.ts.map +1 -0
- package/dist/utils/html-parser.js +383 -0
- package/dist/utils/html-parser.js.map +1 -0
- package/dist/utils/lru-cache.d.ts +124 -0
- package/dist/utils/lru-cache.d.ts.map +1 -0
- package/dist/utils/lru-cache.js +259 -0
- package/dist/utils/lru-cache.js.map +1 -0
- package/dist/utils/programmers-converter.d.ts +15 -0
- package/dist/utils/programmers-converter.d.ts.map +1 -0
- package/dist/utils/programmers-converter.js +41 -0
- package/dist/utils/programmers-converter.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +145 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +244 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/tier-converter.d.ts +108 -0
- package/dist/utils/tier-converter.d.ts.map +1 -0
- package/dist/utils/tier-converter.js +198 -0
- package/dist/utils/tier-converter.js.map +1 -0
- package/dist/utils/url-parser.d.ts +25 -0
- package/dist/utils/url-parser.d.ts.map +1 -0
- package/dist/utils/url-parser.js +45 -0
- package/dist/utils/url-parser.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 프로그래머스 관련 타입 정의
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 프로그래머스 문제 검색 옵션
|
|
6
|
+
*/
|
|
7
|
+
export interface ProgrammersSearchOptions {
|
|
8
|
+
/** 난이도 필터 (0-5) */
|
|
9
|
+
levels?: number[];
|
|
10
|
+
/** 카테고리 필터 */
|
|
11
|
+
categories?: string[];
|
|
12
|
+
/** 정렬 순서 */
|
|
13
|
+
order?: 'recent' | 'accuracy' | 'popular';
|
|
14
|
+
/** 페이지 번호 (1부터 시작) */
|
|
15
|
+
page?: number;
|
|
16
|
+
/** 반환할 최대 문제 수 */
|
|
17
|
+
limit?: number;
|
|
18
|
+
/** 검색어 */
|
|
19
|
+
query?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 프로그래머스 문제 요약 정보 (검색 결과)
|
|
23
|
+
*/
|
|
24
|
+
export interface ProgrammersProblemSummary {
|
|
25
|
+
/** 문제 ID */
|
|
26
|
+
problemId: string;
|
|
27
|
+
/** 문제 제목 */
|
|
28
|
+
title: string;
|
|
29
|
+
/** 난이도 (0-5) */
|
|
30
|
+
level: number;
|
|
31
|
+
/** 카테고리 */
|
|
32
|
+
category: string;
|
|
33
|
+
/** 문제 URL */
|
|
34
|
+
url: string;
|
|
35
|
+
/** 완료한 사람 수 (optional) */
|
|
36
|
+
finishedCount?: number;
|
|
37
|
+
/** 정답률 (0-100, optional) */
|
|
38
|
+
acceptanceRate?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 프로그래머스 문제 상세 정보 (상세 페이지)
|
|
42
|
+
*/
|
|
43
|
+
export interface ProgrammersProblemDetail {
|
|
44
|
+
/** 문제 ID */
|
|
45
|
+
problemId: string;
|
|
46
|
+
/** 문제 제목 */
|
|
47
|
+
title: string;
|
|
48
|
+
/** 난이도 (0-5) */
|
|
49
|
+
level: number;
|
|
50
|
+
/** 카테고리 */
|
|
51
|
+
category: string;
|
|
52
|
+
/** 문제 설명 (HTML) */
|
|
53
|
+
description: string;
|
|
54
|
+
/** 제한사항 */
|
|
55
|
+
constraints: string[];
|
|
56
|
+
/** 입출력 예시 */
|
|
57
|
+
examples: ProgrammersExample[];
|
|
58
|
+
/** 태그 */
|
|
59
|
+
tags: string[];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 입출력 예시
|
|
63
|
+
*/
|
|
64
|
+
export interface ProgrammersExample {
|
|
65
|
+
/** 입력 */
|
|
66
|
+
input: string;
|
|
67
|
+
/** 출력 */
|
|
68
|
+
output: string;
|
|
69
|
+
/** 설명 (optional) */
|
|
70
|
+
explanation?: string;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=programmers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"programmers.d.ts","sourceRoot":"","sources":["../../src/types/programmers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,mBAAmB;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc;IACd,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY;IACZ,KAAK,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAC1C,sBAAsB;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,YAAY;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4BAA4B;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,YAAY;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW;IACX,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa;IACb,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,SAAS;IACT,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS;IACT,KAAK,EAAE,MAAM,CAAC;IACd,SAAS;IACT,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"programmers.js","sourceRoot":"","sources":["../../src/types/programmers.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Puppeteer 브라우저 인스턴스 풀
|
|
3
|
+
*
|
|
4
|
+
* Phase 7 - Task 7.1: Puppeteer 설치 및 BrowserPool 구현
|
|
5
|
+
*
|
|
6
|
+
* 메모리 효율성을 위해 브라우저 인스턴스를 재사용합니다.
|
|
7
|
+
* - 최대 2개 인스턴스 유지
|
|
8
|
+
* - 100회 사용 후 자동 재시작 (메모리 누수 방지)
|
|
9
|
+
* - 타임아웃 및 에러 처리
|
|
10
|
+
*/
|
|
11
|
+
import { Browser } from 'puppeteer';
|
|
12
|
+
/**
|
|
13
|
+
* BrowserPool 설정 옵션
|
|
14
|
+
*/
|
|
15
|
+
export interface BrowserPoolOptions {
|
|
16
|
+
/** 최대 브라우저 인스턴스 수 (기본값: 2) */
|
|
17
|
+
maxSize?: number;
|
|
18
|
+
/** 브라우저 재시작 임계값 (사용 횟수, 기본값: 100) */
|
|
19
|
+
restartThreshold?: number;
|
|
20
|
+
/** 브라우저 인스턴스 타임아웃 (밀리초, 기본값: 60000) */
|
|
21
|
+
timeout?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Puppeteer 브라우저 풀
|
|
25
|
+
*
|
|
26
|
+
* 싱글톤 패턴으로 브라우저 인스턴스를 관리합니다.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const pool = BrowserPool.getInstance();
|
|
31
|
+
* const browser = await pool.acquire();
|
|
32
|
+
* try {
|
|
33
|
+
* const page = await browser.newPage();
|
|
34
|
+
* await page.goto('https://example.com');
|
|
35
|
+
* // ...
|
|
36
|
+
* } finally {
|
|
37
|
+
* await pool.release(browser);
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare class BrowserPool {
|
|
42
|
+
private static instance;
|
|
43
|
+
private instances;
|
|
44
|
+
private readonly maxSize;
|
|
45
|
+
private readonly restartThreshold;
|
|
46
|
+
private readonly timeout;
|
|
47
|
+
private acquireQueue;
|
|
48
|
+
private constructor();
|
|
49
|
+
/**
|
|
50
|
+
* BrowserPool 싱글톤 인스턴스 획득
|
|
51
|
+
*/
|
|
52
|
+
static getInstance(options?: BrowserPoolOptions): BrowserPool;
|
|
53
|
+
/**
|
|
54
|
+
* 싱글톤 인스턴스 초기화 (테스트용)
|
|
55
|
+
*/
|
|
56
|
+
static resetInstance(): void;
|
|
57
|
+
/**
|
|
58
|
+
* 브라우저 인스턴스 획득
|
|
59
|
+
*
|
|
60
|
+
* 사용 가능한 인스턴스가 없으면 대기하거나 새로 생성합니다.
|
|
61
|
+
*
|
|
62
|
+
* @returns Browser 인스턴스
|
|
63
|
+
* @throws {Error} 타임아웃 또는 브라우저 실행 실패 시
|
|
64
|
+
*/
|
|
65
|
+
acquire(): Promise<Browser>;
|
|
66
|
+
/**
|
|
67
|
+
* 브라우저 인스턴스 반환
|
|
68
|
+
*
|
|
69
|
+
* @param browser - 반환할 Browser 인스턴스
|
|
70
|
+
*/
|
|
71
|
+
release(browser: Browser): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* 모든 브라우저 인스턴스 종료
|
|
74
|
+
*/
|
|
75
|
+
closeAll(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* 풀 상태 조회
|
|
78
|
+
*/
|
|
79
|
+
getStatus(): {
|
|
80
|
+
total: number;
|
|
81
|
+
active: number;
|
|
82
|
+
waiting: number;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* 새 브라우저 인스턴스 생성
|
|
86
|
+
*/
|
|
87
|
+
private createBrowser;
|
|
88
|
+
/**
|
|
89
|
+
* 브라우저 인스턴스 재시작
|
|
90
|
+
*/
|
|
91
|
+
private restartBrowser;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=browser-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-pool.d.ts","sourceRoot":"","sources":["../../src/utils/browser-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAkB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,qCAAqC;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA4B;IAEnD,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,YAAY,CAGZ;IAER,OAAO;IAMP;;OAEG;WACW,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,WAAW;IAOpE;;OAEG;WACW,aAAa,IAAI,IAAI;IAOnC;;;;;;;OAOG;IACU,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAqDxC;;;;OAIG;IACU,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBrD;;OAEG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtC;;OAEG;IACI,SAAS,IAAI;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;KACjB;IAQD;;OAEG;YACW,aAAa;IAe3B;;OAEG;YACW,cAAc;CAW7B"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Puppeteer 브라우저 인스턴스 풀
|
|
3
|
+
*
|
|
4
|
+
* Phase 7 - Task 7.1: Puppeteer 설치 및 BrowserPool 구현
|
|
5
|
+
*
|
|
6
|
+
* 메모리 효율성을 위해 브라우저 인스턴스를 재사용합니다.
|
|
7
|
+
* - 최대 2개 인스턴스 유지
|
|
8
|
+
* - 100회 사용 후 자동 재시작 (메모리 누수 방지)
|
|
9
|
+
* - 타임아웃 및 에러 처리
|
|
10
|
+
*/
|
|
11
|
+
import puppeteer from 'puppeteer';
|
|
12
|
+
/**
|
|
13
|
+
* Puppeteer 브라우저 풀
|
|
14
|
+
*
|
|
15
|
+
* 싱글톤 패턴으로 브라우저 인스턴스를 관리합니다.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const pool = BrowserPool.getInstance();
|
|
20
|
+
* const browser = await pool.acquire();
|
|
21
|
+
* try {
|
|
22
|
+
* const page = await browser.newPage();
|
|
23
|
+
* await page.goto('https://example.com');
|
|
24
|
+
* // ...
|
|
25
|
+
* } finally {
|
|
26
|
+
* await pool.release(browser);
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export class BrowserPool {
|
|
31
|
+
static instance = null;
|
|
32
|
+
instances = [];
|
|
33
|
+
maxSize;
|
|
34
|
+
restartThreshold;
|
|
35
|
+
timeout;
|
|
36
|
+
acquireQueue = [];
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.maxSize = options.maxSize ?? 2;
|
|
39
|
+
this.restartThreshold = options.restartThreshold ?? 100;
|
|
40
|
+
this.timeout = options.timeout ?? 60000;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* BrowserPool 싱글톤 인스턴스 획득
|
|
44
|
+
*/
|
|
45
|
+
static getInstance(options) {
|
|
46
|
+
if (!BrowserPool.instance) {
|
|
47
|
+
BrowserPool.instance = new BrowserPool(options);
|
|
48
|
+
}
|
|
49
|
+
return BrowserPool.instance;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 싱글톤 인스턴스 초기화 (테스트용)
|
|
53
|
+
*/
|
|
54
|
+
static resetInstance() {
|
|
55
|
+
if (BrowserPool.instance) {
|
|
56
|
+
BrowserPool.instance.closeAll();
|
|
57
|
+
BrowserPool.instance = null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 브라우저 인스턴스 획득
|
|
62
|
+
*
|
|
63
|
+
* 사용 가능한 인스턴스가 없으면 대기하거나 새로 생성합니다.
|
|
64
|
+
*
|
|
65
|
+
* @returns Browser 인스턴스
|
|
66
|
+
* @throws {Error} 타임아웃 또는 브라우저 실행 실패 시
|
|
67
|
+
*/
|
|
68
|
+
async acquire() {
|
|
69
|
+
// 1. 사용 가능한 인스턴스 우선 확인 (재사용)
|
|
70
|
+
const available = this.instances.find(inst => inst.browser.isConnected() && !inst.inUse);
|
|
71
|
+
if (available) {
|
|
72
|
+
available.inUse = true;
|
|
73
|
+
available.usageCount++;
|
|
74
|
+
// 재시작 임계값 초과 시 교체
|
|
75
|
+
if (available.usageCount >= this.restartThreshold) {
|
|
76
|
+
await this.restartBrowser(available);
|
|
77
|
+
}
|
|
78
|
+
return available.browser;
|
|
79
|
+
}
|
|
80
|
+
// 2. 새 인스턴스 생성 가능 여부 확인
|
|
81
|
+
if (this.instances.length < this.maxSize) {
|
|
82
|
+
const browser = await this.createBrowser();
|
|
83
|
+
const instance = {
|
|
84
|
+
browser,
|
|
85
|
+
usageCount: 1,
|
|
86
|
+
createdAt: Date.now(),
|
|
87
|
+
inUse: true,
|
|
88
|
+
};
|
|
89
|
+
this.instances.push(instance);
|
|
90
|
+
return browser;
|
|
91
|
+
}
|
|
92
|
+
// 3. 대기 큐에 추가 (풀이 가득 차고 사용 가능한 인스턴스 없음)
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
const timeoutId = setTimeout(() => {
|
|
95
|
+
const index = this.acquireQueue.findIndex(item => item.resolve === resolve);
|
|
96
|
+
if (index !== -1) {
|
|
97
|
+
this.acquireQueue.splice(index, 1);
|
|
98
|
+
}
|
|
99
|
+
reject(new Error('Browser acquire timeout'));
|
|
100
|
+
}, this.timeout);
|
|
101
|
+
this.acquireQueue.push({
|
|
102
|
+
resolve: (browser) => {
|
|
103
|
+
clearTimeout(timeoutId);
|
|
104
|
+
resolve(browser);
|
|
105
|
+
},
|
|
106
|
+
reject: (error) => {
|
|
107
|
+
clearTimeout(timeoutId);
|
|
108
|
+
reject(error);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 브라우저 인스턴스 반환
|
|
115
|
+
*
|
|
116
|
+
* @param browser - 반환할 Browser 인스턴스
|
|
117
|
+
*/
|
|
118
|
+
async release(browser) {
|
|
119
|
+
const instance = this.instances.find(inst => inst.browser === browser);
|
|
120
|
+
if (!instance) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// 대기 중인 요청이 있으면 즉시 전달 (inUse 상태 유지)
|
|
124
|
+
if (this.acquireQueue.length > 0) {
|
|
125
|
+
const waiter = this.acquireQueue.shift();
|
|
126
|
+
if (waiter) {
|
|
127
|
+
instance.usageCount++;
|
|
128
|
+
waiter.resolve(browser);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// 아니면 사용 가능 상태로 전환
|
|
133
|
+
instance.inUse = false;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 모든 브라우저 인스턴스 종료
|
|
137
|
+
*/
|
|
138
|
+
async closeAll() {
|
|
139
|
+
// 대기 중인 요청 모두 거부
|
|
140
|
+
for (const waiter of this.acquireQueue) {
|
|
141
|
+
waiter.reject(new Error('BrowserPool is closing'));
|
|
142
|
+
}
|
|
143
|
+
this.acquireQueue = [];
|
|
144
|
+
// 모든 브라우저 종료
|
|
145
|
+
await Promise.all(this.instances.map(async (inst) => {
|
|
146
|
+
if (inst.browser.isConnected()) {
|
|
147
|
+
await inst.browser.close();
|
|
148
|
+
}
|
|
149
|
+
}));
|
|
150
|
+
this.instances = [];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 풀 상태 조회
|
|
154
|
+
*/
|
|
155
|
+
getStatus() {
|
|
156
|
+
return {
|
|
157
|
+
total: this.instances.length,
|
|
158
|
+
active: this.instances.filter(inst => inst.browser.isConnected()).length,
|
|
159
|
+
waiting: this.acquireQueue.length,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 새 브라우저 인스턴스 생성
|
|
164
|
+
*/
|
|
165
|
+
async createBrowser() {
|
|
166
|
+
return await puppeteer.launch({
|
|
167
|
+
headless: true,
|
|
168
|
+
args: [
|
|
169
|
+
'--no-sandbox',
|
|
170
|
+
'--disable-setuid-sandbox',
|
|
171
|
+
'--disable-dev-shm-usage', // 메모리 절약
|
|
172
|
+
'--disable-accelerated-2d-canvas',
|
|
173
|
+
'--no-first-run',
|
|
174
|
+
'--no-zygote',
|
|
175
|
+
'--disable-gpu',
|
|
176
|
+
],
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* 브라우저 인스턴스 재시작
|
|
181
|
+
*/
|
|
182
|
+
async restartBrowser(instance) {
|
|
183
|
+
if (instance.browser.isConnected()) {
|
|
184
|
+
await instance.browser.close();
|
|
185
|
+
}
|
|
186
|
+
const newBrowser = await this.createBrowser();
|
|
187
|
+
instance.browser = newBrowser;
|
|
188
|
+
instance.usageCount = 0;
|
|
189
|
+
instance.createdAt = Date.now();
|
|
190
|
+
instance.inUse = true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=browser-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-pool.js","sourceRoot":"","sources":["../../src/utils/browser-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 캐시 통계 수집기
|
|
3
|
+
*
|
|
4
|
+
* 여러 캐시의 통계를 중앙에서 관리하고 보고서 생성
|
|
5
|
+
*/
|
|
6
|
+
export interface CacheMetrics {
|
|
7
|
+
hits: number;
|
|
8
|
+
misses: number;
|
|
9
|
+
evictions: number;
|
|
10
|
+
size: number;
|
|
11
|
+
capacity: number;
|
|
12
|
+
}
|
|
13
|
+
export interface AggregatedCacheStats {
|
|
14
|
+
totalRequests: number;
|
|
15
|
+
hitRate: number;
|
|
16
|
+
hits: number;
|
|
17
|
+
misses: number;
|
|
18
|
+
evictions: number;
|
|
19
|
+
size: number;
|
|
20
|
+
capacity: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* CacheStatsCollector 클래스
|
|
24
|
+
*
|
|
25
|
+
* 여러 캐시의 통계를 수집하고 관리
|
|
26
|
+
*/
|
|
27
|
+
export declare class CacheStatsCollector {
|
|
28
|
+
private stats;
|
|
29
|
+
/**
|
|
30
|
+
* 캐시 통계 기록
|
|
31
|
+
*
|
|
32
|
+
* @param cacheName - 캐시 이름 (예: 'problems', 'tags')
|
|
33
|
+
* @param metrics - 캐시 메트릭
|
|
34
|
+
*/
|
|
35
|
+
record(cacheName: string, metrics: CacheMetrics): void;
|
|
36
|
+
/**
|
|
37
|
+
* 특정 캐시 통계 조회
|
|
38
|
+
*
|
|
39
|
+
* @param cacheName - 캐시 이름
|
|
40
|
+
* @returns 캐시 통계 또는 undefined
|
|
41
|
+
*/
|
|
42
|
+
get(cacheName: string): AggregatedCacheStats | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* 모든 캐시 통계 조회
|
|
45
|
+
*
|
|
46
|
+
* @returns 모든 캐시 통계 Map
|
|
47
|
+
*/
|
|
48
|
+
getAll(): Map<string, AggregatedCacheStats>;
|
|
49
|
+
/**
|
|
50
|
+
* 모든 캐시 통계 초기화
|
|
51
|
+
*/
|
|
52
|
+
reset(): void;
|
|
53
|
+
/**
|
|
54
|
+
* 보고서 생성
|
|
55
|
+
*
|
|
56
|
+
* @returns 텍스트 형식의 통계 보고서
|
|
57
|
+
*/
|
|
58
|
+
generateReport(): string;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=cache-stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-stats.d.ts","sourceRoot":"","sources":["../../src/utils/cache-stats.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAA2C;IAExD;;;;;OAKG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAetD;;;;;OAKG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS;IAIxD;;;;OAIG;IACH,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC;IAI3C;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;;OAIG;IACH,cAAc,IAAI,MAAM;CAsBzB"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 캐시 통계 수집기
|
|
3
|
+
*
|
|
4
|
+
* 여러 캐시의 통계를 중앙에서 관리하고 보고서 생성
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* CacheStatsCollector 클래스
|
|
8
|
+
*
|
|
9
|
+
* 여러 캐시의 통계를 수집하고 관리
|
|
10
|
+
*/
|
|
11
|
+
export class CacheStatsCollector {
|
|
12
|
+
stats = new Map();
|
|
13
|
+
/**
|
|
14
|
+
* 캐시 통계 기록
|
|
15
|
+
*
|
|
16
|
+
* @param cacheName - 캐시 이름 (예: 'problems', 'tags')
|
|
17
|
+
* @param metrics - 캐시 메트릭
|
|
18
|
+
*/
|
|
19
|
+
record(cacheName, metrics) {
|
|
20
|
+
const totalRequests = metrics.hits + metrics.misses;
|
|
21
|
+
const hitRate = totalRequests > 0 ? metrics.hits / totalRequests : 0;
|
|
22
|
+
this.stats.set(cacheName, {
|
|
23
|
+
totalRequests,
|
|
24
|
+
hitRate,
|
|
25
|
+
hits: metrics.hits,
|
|
26
|
+
misses: metrics.misses,
|
|
27
|
+
evictions: metrics.evictions,
|
|
28
|
+
size: metrics.size,
|
|
29
|
+
capacity: metrics.capacity,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 특정 캐시 통계 조회
|
|
34
|
+
*
|
|
35
|
+
* @param cacheName - 캐시 이름
|
|
36
|
+
* @returns 캐시 통계 또는 undefined
|
|
37
|
+
*/
|
|
38
|
+
get(cacheName) {
|
|
39
|
+
return this.stats.get(cacheName);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 모든 캐시 통계 조회
|
|
43
|
+
*
|
|
44
|
+
* @returns 모든 캐시 통계 Map
|
|
45
|
+
*/
|
|
46
|
+
getAll() {
|
|
47
|
+
return new Map(this.stats);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 모든 캐시 통계 초기화
|
|
51
|
+
*/
|
|
52
|
+
reset() {
|
|
53
|
+
this.stats.clear();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 보고서 생성
|
|
57
|
+
*
|
|
58
|
+
* @returns 텍스트 형식의 통계 보고서
|
|
59
|
+
*/
|
|
60
|
+
generateReport() {
|
|
61
|
+
if (this.stats.size === 0) {
|
|
62
|
+
return '캐시 통계가 없습니다.';
|
|
63
|
+
}
|
|
64
|
+
const lines = ['=== 캐시 통계 보고서 ==='];
|
|
65
|
+
for (const [cacheName, stats] of this.stats.entries()) {
|
|
66
|
+
lines.push('');
|
|
67
|
+
lines.push(`캐시: ${cacheName}`);
|
|
68
|
+
lines.push(`총 요청: ${stats.totalRequests}`);
|
|
69
|
+
lines.push(`히트: ${stats.hits} (${(stats.hitRate * 100).toFixed(2)}%)`);
|
|
70
|
+
lines.push(`미스: ${stats.misses}`);
|
|
71
|
+
lines.push(`제거: ${stats.evictions}`);
|
|
72
|
+
lines.push(`크기: ${stats.size}/${stats.capacity}`);
|
|
73
|
+
}
|
|
74
|
+
lines.push('');
|
|
75
|
+
return lines.join('\n');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=cache-stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-stats.js","sourceRoot":"","sources":["../../src/utils/cache-stats.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH;;;;GAIG;AACH,MAAM,OAAO,mBAAmB;IACtB,KAAK,GAAG,IAAI,GAAG,EAAgC,CAAC;IAExD;;;;;OAKG;IACH,MAAM,CAAC,SAAiB,EAAE,OAAqB;QAC7C,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;QACpD,MAAM,OAAO,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAErE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE;YACxB,aAAa;YACb,OAAO;YACP,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,SAAiB;QACnB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,MAAM;QACJ,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACH,cAAc;QACZ,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,MAAM,KAAK,GAAa,CAAC,mBAAmB,CAAC,CAAC;QAE9C,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YACtD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,OAAO,SAAS,EAAE,CAAC,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC;YAC3C,KAAK,CAAC,IAAI,CACR,OAAO,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAC3D,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 간단한 인메모리 캐시 구현
|
|
3
|
+
* TTL (Time To Live) 기반 캐싱
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 캐시 옵션
|
|
7
|
+
*/
|
|
8
|
+
export interface CacheOptions {
|
|
9
|
+
ttl?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 인메모리 캐시 클래스
|
|
13
|
+
*/
|
|
14
|
+
export declare class Cache<T> {
|
|
15
|
+
private store;
|
|
16
|
+
private defaultTtl;
|
|
17
|
+
constructor(options?: CacheOptions);
|
|
18
|
+
/**
|
|
19
|
+
* 캐시에 값 저장
|
|
20
|
+
* @param key - 캐시 키
|
|
21
|
+
* @param value - 저장할 값
|
|
22
|
+
* @param ttl - TTL (밀리초, 선택사항)
|
|
23
|
+
*/
|
|
24
|
+
set(key: string, value: T, ttl?: number): void;
|
|
25
|
+
/**
|
|
26
|
+
* 캐시에서 값 조회
|
|
27
|
+
* @param key - 캐시 키
|
|
28
|
+
* @returns 캐시된 값 또는 undefined
|
|
29
|
+
*/
|
|
30
|
+
get(key: string): T | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* 캐시에 키가 존재하는지 확인
|
|
33
|
+
* @param key - 캐시 키
|
|
34
|
+
* @returns 존재 여부
|
|
35
|
+
*/
|
|
36
|
+
has(key: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* 캐시에서 키 삭제
|
|
39
|
+
* @param key - 캐시 키
|
|
40
|
+
* @returns 삭제 성공 여부
|
|
41
|
+
*/
|
|
42
|
+
delete(key: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* 캐시 전체 삭제
|
|
45
|
+
*/
|
|
46
|
+
clear(): void;
|
|
47
|
+
/**
|
|
48
|
+
* 만료된 항목 정리
|
|
49
|
+
*/
|
|
50
|
+
cleanup(): void;
|
|
51
|
+
/**
|
|
52
|
+
* 캐시 크기 반환
|
|
53
|
+
*/
|
|
54
|
+
size(): number;
|
|
55
|
+
/**
|
|
56
|
+
* 캐시 히트율 측정용 통계 (간단한 구현)
|
|
57
|
+
*/
|
|
58
|
+
getStats(): {
|
|
59
|
+
size: number;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 문제 상세 정보 캐시 (싱글톤)
|
|
64
|
+
* TTL: 1시간 (문제 메타데이터는 자주 변경되지 않음)
|
|
65
|
+
*/
|
|
66
|
+
export declare const problemCache: Cache<unknown>;
|
|
67
|
+
/**
|
|
68
|
+
* 검색 결과 캐시 (싱글톤)
|
|
69
|
+
* TTL: 10분 (검색 결과는 상대적으로 자주 변경될 수 있음)
|
|
70
|
+
*/
|
|
71
|
+
export declare const searchCache: Cache<unknown>;
|
|
72
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,qBAAa,KAAK,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAyC;IACtD,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,GAAE,YAAiB;IAItC;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAK9C;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAgB/B;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,QAAQ,IAAI;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;CAK7B;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,gBAAqC,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,WAAW,gBAAqC,CAAC"}
|