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.
Files changed (195) hide show
  1. package/README.md +137 -0
  2. package/dist/api/boj-scraper.d.ts +68 -0
  3. package/dist/api/boj-scraper.d.ts.map +1 -0
  4. package/dist/api/boj-scraper.js +197 -0
  5. package/dist/api/boj-scraper.js.map +1 -0
  6. package/dist/api/programmers-scraper.d.ts +70 -0
  7. package/dist/api/programmers-scraper.d.ts.map +1 -0
  8. package/dist/api/programmers-scraper.js +303 -0
  9. package/dist/api/programmers-scraper.js.map +1 -0
  10. package/dist/api/solvedac-client.d.ts +67 -0
  11. package/dist/api/solvedac-client.d.ts.map +1 -0
  12. package/dist/api/solvedac-client.js +220 -0
  13. package/dist/api/solvedac-client.js.map +1 -0
  14. package/dist/api/types.d.ts +125 -0
  15. package/dist/api/types.d.ts.map +1 -0
  16. package/dist/api/types.js +110 -0
  17. package/dist/api/types.js.map +1 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +594 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/prompts/hint-guide.d.ts +73 -0
  23. package/dist/prompts/hint-guide.d.ts.map +1 -0
  24. package/dist/prompts/hint-guide.js +174 -0
  25. package/dist/prompts/hint-guide.js.map +1 -0
  26. package/dist/prompts/programmers-hint-guide.d.ts +38 -0
  27. package/dist/prompts/programmers-hint-guide.d.ts.map +1 -0
  28. package/dist/prompts/programmers-hint-guide.js +134 -0
  29. package/dist/prompts/programmers-hint-guide.js.map +1 -0
  30. package/dist/services/code-analyzer.d.ts +46 -0
  31. package/dist/services/code-analyzer.d.ts.map +1 -0
  32. package/dist/services/code-analyzer.js +177 -0
  33. package/dist/services/code-analyzer.js.map +1 -0
  34. package/dist/services/hint-generator.d.ts +60 -0
  35. package/dist/services/hint-generator.d.ts.map +1 -0
  36. package/dist/services/hint-generator.js +222 -0
  37. package/dist/services/hint-generator.js.map +1 -0
  38. package/dist/services/problem-analyzer.d.ts +38 -0
  39. package/dist/services/problem-analyzer.d.ts.map +1 -0
  40. package/dist/services/problem-analyzer.js +114 -0
  41. package/dist/services/problem-analyzer.js.map +1 -0
  42. package/dist/services/programmers-problem-analyzer.d.ts +26 -0
  43. package/dist/services/programmers-problem-analyzer.d.ts.map +1 -0
  44. package/dist/services/programmers-problem-analyzer.js +64 -0
  45. package/dist/services/programmers-problem-analyzer.js.map +1 -0
  46. package/dist/services/programmers-review-template-generator.d.ts +27 -0
  47. package/dist/services/programmers-review-template-generator.d.ts.map +1 -0
  48. package/dist/services/programmers-review-template-generator.js +153 -0
  49. package/dist/services/programmers-review-template-generator.js.map +1 -0
  50. package/dist/services/review-generator.d.ts +51 -0
  51. package/dist/services/review-generator.d.ts.map +1 -0
  52. package/dist/services/review-generator.js +149 -0
  53. package/dist/services/review-generator.js.map +1 -0
  54. package/dist/services/review-template-generator.d.ts +27 -0
  55. package/dist/services/review-template-generator.d.ts.map +1 -0
  56. package/dist/services/review-template-generator.js +163 -0
  57. package/dist/services/review-template-generator.js.map +1 -0
  58. package/dist/templates/review-guideline.md +89 -0
  59. package/dist/tools/analyze-code-submission-boj.d.ts +67 -0
  60. package/dist/tools/analyze-code-submission-boj.d.ts.map +1 -0
  61. package/dist/tools/analyze-code-submission-boj.js +89 -0
  62. package/dist/tools/analyze-code-submission-boj.js.map +1 -0
  63. package/dist/tools/analyze-code-submission-programmers.d.ts +60 -0
  64. package/dist/tools/analyze-code-submission-programmers.d.ts.map +1 -0
  65. package/dist/tools/analyze-code-submission-programmers.js +83 -0
  66. package/dist/tools/analyze-code-submission-programmers.js.map +1 -0
  67. package/dist/tools/analyze-code-submission.d.ts +67 -0
  68. package/dist/tools/analyze-code-submission.d.ts.map +1 -0
  69. package/dist/tools/analyze-code-submission.js +89 -0
  70. package/dist/tools/analyze-code-submission.js.map +1 -0
  71. package/dist/tools/analyze-problem-boj.d.ts +48 -0
  72. package/dist/tools/analyze-problem-boj.d.ts.map +1 -0
  73. package/dist/tools/analyze-problem-boj.js +52 -0
  74. package/dist/tools/analyze-problem-boj.js.map +1 -0
  75. package/dist/tools/analyze-problem-programmers.d.ts +48 -0
  76. package/dist/tools/analyze-problem-programmers.d.ts.map +1 -0
  77. package/dist/tools/analyze-problem-programmers.js +53 -0
  78. package/dist/tools/analyze-problem-programmers.js.map +1 -0
  79. package/dist/tools/analyze-problem.d.ts +48 -0
  80. package/dist/tools/analyze-problem.d.ts.map +1 -0
  81. package/dist/tools/analyze-problem.js +52 -0
  82. package/dist/tools/analyze-problem.js.map +1 -0
  83. package/dist/tools/create-review.d.ts +47 -0
  84. package/dist/tools/create-review.d.ts.map +1 -0
  85. package/dist/tools/create-review.js +122 -0
  86. package/dist/tools/create-review.js.map +1 -0
  87. package/dist/tools/fetch-problem-content-boj.d.ts +49 -0
  88. package/dist/tools/fetch-problem-content-boj.d.ts.map +1 -0
  89. package/dist/tools/fetch-problem-content-boj.js +93 -0
  90. package/dist/tools/fetch-problem-content-boj.js.map +1 -0
  91. package/dist/tools/fetch-problem-content-programmers.d.ts +46 -0
  92. package/dist/tools/fetch-problem-content-programmers.d.ts.map +1 -0
  93. package/dist/tools/fetch-problem-content-programmers.js +74 -0
  94. package/dist/tools/fetch-problem-content-programmers.js.map +1 -0
  95. package/dist/tools/fetch-problem-content.d.ts +49 -0
  96. package/dist/tools/fetch-problem-content.d.ts.map +1 -0
  97. package/dist/tools/fetch-problem-content.js +93 -0
  98. package/dist/tools/fetch-problem-content.js.map +1 -0
  99. package/dist/tools/generate-hint-boj.d.ts +42 -0
  100. package/dist/tools/generate-hint-boj.d.ts.map +1 -0
  101. package/dist/tools/generate-hint-boj.js +80 -0
  102. package/dist/tools/generate-hint-boj.js.map +1 -0
  103. package/dist/tools/generate-hint-programmers.d.ts +42 -0
  104. package/dist/tools/generate-hint-programmers.d.ts.map +1 -0
  105. package/dist/tools/generate-hint-programmers.js +78 -0
  106. package/dist/tools/generate-hint-programmers.js.map +1 -0
  107. package/dist/tools/generate-hint.d.ts +42 -0
  108. package/dist/tools/generate-hint.d.ts.map +1 -0
  109. package/dist/tools/generate-hint.js +80 -0
  110. package/dist/tools/generate-hint.js.map +1 -0
  111. package/dist/tools/generate-review-template-boj.d.ts +48 -0
  112. package/dist/tools/generate-review-template-boj.d.ts.map +1 -0
  113. package/dist/tools/generate-review-template-boj.js +52 -0
  114. package/dist/tools/generate-review-template-boj.js.map +1 -0
  115. package/dist/tools/generate-review-template-programmers.d.ts +48 -0
  116. package/dist/tools/generate-review-template-programmers.d.ts.map +1 -0
  117. package/dist/tools/generate-review-template-programmers.js +53 -0
  118. package/dist/tools/generate-review-template-programmers.js.map +1 -0
  119. package/dist/tools/generate-review-template.d.ts +48 -0
  120. package/dist/tools/generate-review-template.d.ts.map +1 -0
  121. package/dist/tools/generate-review-template.js +52 -0
  122. package/dist/tools/generate-review-template.js.map +1 -0
  123. package/dist/tools/get-hint.d.ts +41 -0
  124. package/dist/tools/get-hint.d.ts.map +1 -0
  125. package/dist/tools/get-hint.js +108 -0
  126. package/dist/tools/get-hint.js.map +1 -0
  127. package/dist/tools/get-problem.d.ts +22 -0
  128. package/dist/tools/get-problem.d.ts.map +1 -0
  129. package/dist/tools/get-problem.js +89 -0
  130. package/dist/tools/get-problem.js.map +1 -0
  131. package/dist/tools/get-programmers-problem.d.ts +53 -0
  132. package/dist/tools/get-programmers-problem.d.ts.map +1 -0
  133. package/dist/tools/get-programmers-problem.js +161 -0
  134. package/dist/tools/get-programmers-problem.js.map +1 -0
  135. package/dist/tools/search-problems.d.ts +42 -0
  136. package/dist/tools/search-problems.d.ts.map +1 -0
  137. package/dist/tools/search-problems.js +123 -0
  138. package/dist/tools/search-problems.js.map +1 -0
  139. package/dist/tools/search-programmers-problems.d.ts +73 -0
  140. package/dist/tools/search-programmers-problems.d.ts.map +1 -0
  141. package/dist/tools/search-programmers-problems.js +171 -0
  142. package/dist/tools/search-programmers-problems.js.map +1 -0
  143. package/dist/tools/search-tags.d.ts +22 -0
  144. package/dist/tools/search-tags.d.ts.map +1 -0
  145. package/dist/tools/search-tags.js +70 -0
  146. package/dist/tools/search-tags.js.map +1 -0
  147. package/dist/types/analysis.d.ts +211 -0
  148. package/dist/types/analysis.d.ts.map +1 -0
  149. package/dist/types/analysis.js +11 -0
  150. package/dist/types/analysis.js.map +1 -0
  151. package/dist/types/problem-content.d.ts +110 -0
  152. package/dist/types/problem-content.d.ts.map +1 -0
  153. package/dist/types/problem-content.js +7 -0
  154. package/dist/types/problem-content.js.map +1 -0
  155. package/dist/types/programmers.d.ts +72 -0
  156. package/dist/types/programmers.d.ts.map +1 -0
  157. package/dist/types/programmers.js +5 -0
  158. package/dist/types/programmers.js.map +1 -0
  159. package/dist/utils/browser-pool.d.ts +93 -0
  160. package/dist/utils/browser-pool.d.ts.map +1 -0
  161. package/dist/utils/browser-pool.js +193 -0
  162. package/dist/utils/browser-pool.js.map +1 -0
  163. package/dist/utils/cache-stats.d.ts +60 -0
  164. package/dist/utils/cache-stats.d.ts.map +1 -0
  165. package/dist/utils/cache-stats.js +78 -0
  166. package/dist/utils/cache-stats.js.map +1 -0
  167. package/dist/utils/cache.d.ts +72 -0
  168. package/dist/utils/cache.d.ts.map +1 -0
  169. package/dist/utils/cache.js +99 -0
  170. package/dist/utils/cache.js.map +1 -0
  171. package/dist/utils/html-parser.d.ts +57 -0
  172. package/dist/utils/html-parser.d.ts.map +1 -0
  173. package/dist/utils/html-parser.js +383 -0
  174. package/dist/utils/html-parser.js.map +1 -0
  175. package/dist/utils/lru-cache.d.ts +124 -0
  176. package/dist/utils/lru-cache.d.ts.map +1 -0
  177. package/dist/utils/lru-cache.js +259 -0
  178. package/dist/utils/lru-cache.js.map +1 -0
  179. package/dist/utils/programmers-converter.d.ts +15 -0
  180. package/dist/utils/programmers-converter.d.ts.map +1 -0
  181. package/dist/utils/programmers-converter.js +41 -0
  182. package/dist/utils/programmers-converter.js.map +1 -0
  183. package/dist/utils/rate-limiter.d.ts +145 -0
  184. package/dist/utils/rate-limiter.d.ts.map +1 -0
  185. package/dist/utils/rate-limiter.js +244 -0
  186. package/dist/utils/rate-limiter.js.map +1 -0
  187. package/dist/utils/tier-converter.d.ts +108 -0
  188. package/dist/utils/tier-converter.d.ts.map +1 -0
  189. package/dist/utils/tier-converter.js +198 -0
  190. package/dist/utils/tier-converter.js.map +1 -0
  191. package/dist/utils/url-parser.d.ts +25 -0
  192. package/dist/utils/url-parser.d.ts.map +1 -0
  193. package/dist/utils/url-parser.js +45 -0
  194. package/dist/utils/url-parser.js.map +1 -0
  195. 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,5 @@
1
+ /**
2
+ * 프로그래머스 관련 타입 정의
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=programmers.js.map
@@ -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"}