@dollhousemcp/mcp-server 1.5.2 → 1.6.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 (272) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +494 -111
  3. package/data/agents/code-reviewer.md +8 -1
  4. package/data/agents/research-assistant.md +8 -1
  5. package/data/agents/task-manager.md +8 -1
  6. package/data/ensembles/business-advisor.md +8 -1
  7. package/data/ensembles/creative-studio.md +8 -1
  8. package/data/ensembles/development-team.md +8 -1
  9. package/data/ensembles/security-analysis-team.md +8 -1
  10. package/data/memories/conversation-history.md +8 -1
  11. package/data/memories/learning-progress.md +8 -1
  12. package/data/memories/project-context.md +8 -1
  13. package/data/personas/business-consultant.md +8 -1
  14. package/data/personas/creative-writer.md +8 -1
  15. package/data/personas/debug-detective.md +8 -1
  16. package/data/personas/eli5-explainer.md +8 -1
  17. package/data/personas/security-analyst.md +8 -1
  18. package/data/personas/technical-analyst.md +8 -1
  19. package/data/skills/code-review.md +8 -1
  20. package/data/skills/creative-writing.md +8 -1
  21. package/data/skills/data-analysis.md +8 -1
  22. package/data/skills/penetration-testing.md +8 -1
  23. package/data/skills/research.md +8 -1
  24. package/data/skills/threat-modeling.md +8 -1
  25. package/data/skills/translation.md +8 -1
  26. package/data/templates/code-documentation.md +8 -1
  27. package/data/templates/email-professional.md +8 -1
  28. package/data/templates/meeting-notes.md +8 -1
  29. package/data/templates/penetration-test-report.md +8 -1
  30. package/data/templates/project-brief.md +8 -1
  31. package/data/templates/report-executive.md +8 -1
  32. package/data/templates/security-vulnerability-report.md +8 -1
  33. package/data/templates/threat-assessment-report.md +8 -1
  34. package/dist/auth/GitHubAuthManager.d.ts +6 -1
  35. package/dist/auth/GitHubAuthManager.d.ts.map +1 -1
  36. package/dist/auth/GitHubAuthManager.js +45 -18
  37. package/dist/benchmarks/IndexPerformanceBenchmark.d.ts +98 -0
  38. package/dist/benchmarks/IndexPerformanceBenchmark.d.ts.map +1 -0
  39. package/dist/benchmarks/IndexPerformanceBenchmark.js +531 -0
  40. package/dist/cache/CollectionCache.d.ts.map +1 -1
  41. package/dist/cache/CollectionCache.js +13 -3
  42. package/dist/cache/CollectionIndexCache.d.ts +77 -0
  43. package/dist/cache/CollectionIndexCache.d.ts.map +1 -0
  44. package/dist/cache/CollectionIndexCache.js +349 -0
  45. package/dist/cache/LRUCache.d.ts +93 -0
  46. package/dist/cache/LRUCache.d.ts.map +1 -0
  47. package/dist/cache/LRUCache.js +299 -0
  48. package/dist/cache/index.d.ts +1 -0
  49. package/dist/cache/index.d.ts.map +1 -1
  50. package/dist/cache/index.js +2 -1
  51. package/dist/collection/CollectionBrowser.d.ts +21 -1
  52. package/dist/collection/CollectionBrowser.d.ts.map +1 -1
  53. package/dist/collection/CollectionBrowser.js +130 -10
  54. package/dist/collection/CollectionIndexManager.d.ts +151 -0
  55. package/dist/collection/CollectionIndexManager.d.ts.map +1 -0
  56. package/dist/collection/CollectionIndexManager.js +499 -0
  57. package/dist/collection/CollectionSearch.d.ts +55 -0
  58. package/dist/collection/CollectionSearch.d.ts.map +1 -1
  59. package/dist/collection/CollectionSearch.js +338 -13
  60. package/dist/collection/CollectionSeeder.d.ts.map +1 -1
  61. package/dist/collection/CollectionSeeder.js +38 -1
  62. package/dist/collection/ElementInstaller.d.ts +31 -0
  63. package/dist/collection/ElementInstaller.d.ts.map +1 -1
  64. package/dist/collection/ElementInstaller.js +77 -15
  65. package/dist/collection/PersonaSubmitter.d.ts +1 -1
  66. package/dist/collection/PersonaSubmitter.d.ts.map +1 -1
  67. package/dist/collection/PersonaSubmitter.js +2 -2
  68. package/dist/collection/index.d.ts +1 -0
  69. package/dist/collection/index.d.ts.map +1 -1
  70. package/dist/collection/index.js +2 -1
  71. package/dist/config/ConfigManager.d.ts +78 -0
  72. package/dist/config/ConfigManager.d.ts.map +1 -0
  73. package/dist/config/ConfigManager.js +216 -0
  74. package/dist/config/element-types.d.ts +135 -0
  75. package/dist/config/element-types.d.ts.map +1 -0
  76. package/dist/config/element-types.js +108 -0
  77. package/dist/config/index.d.ts +2 -0
  78. package/dist/config/index.d.ts.map +1 -1
  79. package/dist/config/index.js +3 -1
  80. package/dist/config/portfolio-constants.d.ts +83 -0
  81. package/dist/config/portfolio-constants.d.ts.map +1 -0
  82. package/dist/config/portfolio-constants.js +99 -0
  83. package/dist/elements/BaseElement.d.ts +14 -2
  84. package/dist/elements/BaseElement.d.ts.map +1 -1
  85. package/dist/elements/BaseElement.js +88 -6
  86. package/dist/elements/agents/Agent.d.ts +10 -1
  87. package/dist/elements/agents/Agent.d.ts.map +1 -1
  88. package/dist/elements/agents/Agent.js +66 -19
  89. package/dist/elements/agents/AgentManager.d.ts +2 -0
  90. package/dist/elements/agents/AgentManager.d.ts.map +1 -1
  91. package/dist/elements/agents/AgentManager.js +12 -10
  92. package/dist/elements/skills/Skill.d.ts +10 -1
  93. package/dist/elements/skills/Skill.d.ts.map +1 -1
  94. package/dist/elements/skills/Skill.js +40 -3
  95. package/dist/elements/skills/SkillManager.d.ts +1 -0
  96. package/dist/elements/skills/SkillManager.d.ts.map +1 -1
  97. package/dist/elements/skills/SkillManager.js +10 -4
  98. package/dist/elements/templates/Template.d.ts +10 -1
  99. package/dist/elements/templates/Template.d.ts.map +1 -1
  100. package/dist/elements/templates/Template.js +35 -18
  101. package/dist/elements/templates/TemplateManager.d.ts +1 -1
  102. package/dist/elements/templates/TemplateManager.d.ts.map +1 -1
  103. package/dist/elements/templates/TemplateManager.js +6 -5
  104. package/dist/generated/version.d.ts +2 -2
  105. package/dist/generated/version.js +3 -3
  106. package/dist/index.barrel.d.ts +1 -2
  107. package/dist/index.barrel.d.ts.map +1 -1
  108. package/dist/index.barrel.js +2 -4
  109. package/dist/index.d.ts +143 -25
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +1883 -310
  112. package/dist/persona/PersonaElement.d.ts +10 -0
  113. package/dist/persona/PersonaElement.d.ts.map +1 -1
  114. package/dist/persona/PersonaElement.js +55 -32
  115. package/dist/persona/PersonaElementManager.d.ts.map +1 -1
  116. package/dist/persona/PersonaElementManager.js +13 -11
  117. package/dist/persona/PersonaLoader.d.ts.map +1 -1
  118. package/dist/persona/PersonaLoader.js +8 -2
  119. package/dist/persona/export-import/PersonaImporter.d.ts.map +1 -1
  120. package/dist/persona/export-import/PersonaImporter.js +24 -5
  121. package/dist/persona/export-import/PersonaSharer.d.ts +21 -0
  122. package/dist/persona/export-import/PersonaSharer.d.ts.map +1 -1
  123. package/dist/persona/export-import/PersonaSharer.js +198 -22
  124. package/dist/portfolio/DefaultElementProvider.d.ts +90 -0
  125. package/dist/portfolio/DefaultElementProvider.d.ts.map +1 -1
  126. package/dist/portfolio/DefaultElementProvider.js +499 -7
  127. package/dist/portfolio/GitHubPortfolioIndexer.d.ts +129 -0
  128. package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -0
  129. package/dist/portfolio/GitHubPortfolioIndexer.js +475 -0
  130. package/dist/portfolio/MigrationManager.d.ts.map +1 -1
  131. package/dist/portfolio/MigrationManager.js +136 -3
  132. package/dist/portfolio/PortfolioIndexManager.d.ts +130 -0
  133. package/dist/portfolio/PortfolioIndexManager.d.ts.map +1 -0
  134. package/dist/portfolio/PortfolioIndexManager.js +478 -0
  135. package/dist/portfolio/PortfolioManager.d.ts +5 -0
  136. package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
  137. package/dist/portfolio/PortfolioManager.js +61 -20
  138. package/dist/portfolio/PortfolioRepoManager.d.ts +75 -0
  139. package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -0
  140. package/dist/portfolio/PortfolioRepoManager.js +337 -0
  141. package/dist/portfolio/UnifiedIndexManager.d.ts +388 -0
  142. package/dist/portfolio/UnifiedIndexManager.d.ts.map +1 -0
  143. package/dist/portfolio/UnifiedIndexManager.js +1434 -0
  144. package/dist/portfolio/index.d.ts +15 -0
  145. package/dist/portfolio/index.d.ts.map +1 -0
  146. package/dist/portfolio/index.js +15 -0
  147. package/dist/portfolio/types.d.ts +7 -0
  148. package/dist/portfolio/types.d.ts.map +1 -1
  149. package/dist/portfolio/types.js +6 -1
  150. package/dist/security/InputValidator.d.ts.map +1 -1
  151. package/dist/security/InputValidator.js +50 -48
  152. package/dist/security/audit/SecurityAuditor.d.ts.map +1 -1
  153. package/dist/security/audit/SecurityAuditor.js +17 -9
  154. package/dist/security/audit/config/suppressions.d.ts.map +1 -1
  155. package/dist/security/audit/config/suppressions.js +19 -3
  156. package/dist/security/contentValidator.d.ts +2 -0
  157. package/dist/security/contentValidator.d.ts.map +1 -1
  158. package/dist/security/contentValidator.js +115 -4
  159. package/dist/security/secureYamlParser.d.ts +1 -0
  160. package/dist/security/secureYamlParser.d.ts.map +1 -1
  161. package/dist/security/secureYamlParser.js +29 -7
  162. package/dist/security/securityMonitor.d.ts +1 -1
  163. package/dist/security/securityMonitor.d.ts.map +1 -1
  164. package/dist/security/securityMonitor.js +1 -1
  165. package/dist/security/tokenManager.d.ts +1 -1
  166. package/dist/security/tokenManager.d.ts.map +1 -1
  167. package/dist/security/tokenManager.js +30 -10
  168. package/dist/server/ServerSetup.d.ts +22 -2
  169. package/dist/server/ServerSetup.d.ts.map +1 -1
  170. package/dist/server/ServerSetup.js +77 -12
  171. package/dist/server/tools/AuthTools.d.ts.map +1 -1
  172. package/dist/server/tools/AuthTools.js +33 -1
  173. package/dist/server/tools/BuildInfoTools.d.ts +25 -0
  174. package/dist/server/tools/BuildInfoTools.d.ts.map +1 -0
  175. package/dist/server/tools/BuildInfoTools.js +36 -0
  176. package/dist/server/tools/CollectionTools.d.ts.map +1 -1
  177. package/dist/server/tools/CollectionTools.js +55 -46
  178. package/dist/server/tools/ConfigTools.d.ts.map +1 -1
  179. package/dist/server/tools/ConfigTools.js +29 -1
  180. package/dist/server/tools/PersonaTools.d.ts +4 -2
  181. package/dist/server/tools/PersonaTools.d.ts.map +1 -1
  182. package/dist/server/tools/PersonaTools.js +5 -152
  183. package/dist/server/tools/PortfolioTools.d.ts +12 -0
  184. package/dist/server/tools/PortfolioTools.d.ts.map +1 -0
  185. package/dist/server/tools/PortfolioTools.js +221 -0
  186. package/dist/server/tools/index.d.ts +3 -1
  187. package/dist/server/tools/index.d.ts.map +1 -1
  188. package/dist/server/tools/index.js +4 -2
  189. package/dist/server/types.d.ts +40 -5
  190. package/dist/server/types.d.ts.map +1 -1
  191. package/dist/server/types.js +1 -1
  192. package/dist/services/BuildInfoService.d.ts +84 -0
  193. package/dist/services/BuildInfoService.d.ts.map +1 -0
  194. package/dist/services/BuildInfoService.js +271 -0
  195. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts +54 -0
  196. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts.map +1 -0
  197. package/dist/tools/portfolio/PortfolioElementAdapter.js +229 -0
  198. package/dist/tools/portfolio/submitToPortfolioTool.d.ts +164 -0
  199. package/dist/tools/portfolio/submitToPortfolioTool.d.ts.map +1 -0
  200. package/dist/tools/portfolio/submitToPortfolioTool.js +1523 -0
  201. package/dist/tools/portfolio/types.d.ts +41 -0
  202. package/dist/tools/portfolio/types.d.ts.map +1 -0
  203. package/dist/tools/portfolio/types.js +15 -0
  204. package/dist/types/collection.d.ts +51 -0
  205. package/dist/types/collection.d.ts.map +1 -1
  206. package/dist/types/collection.js +1 -1
  207. package/dist/utils/EarlyTerminationSearch.d.ts +41 -0
  208. package/dist/utils/EarlyTerminationSearch.d.ts.map +1 -0
  209. package/dist/utils/EarlyTerminationSearch.js +164 -0
  210. package/dist/utils/ErrorHandler.d.ts +86 -0
  211. package/dist/utils/ErrorHandler.d.ts.map +1 -0
  212. package/dist/utils/ErrorHandler.js +201 -0
  213. package/dist/utils/FileDiscoveryUtil.d.ts +53 -0
  214. package/dist/utils/FileDiscoveryUtil.d.ts.map +1 -0
  215. package/dist/utils/FileDiscoveryUtil.js +169 -0
  216. package/dist/utils/GitHubRateLimiter.d.ts +88 -0
  217. package/dist/utils/GitHubRateLimiter.d.ts.map +1 -0
  218. package/dist/utils/GitHubRateLimiter.js +315 -0
  219. package/dist/utils/PerformanceMonitor.d.ts +134 -0
  220. package/dist/utils/PerformanceMonitor.d.ts.map +1 -0
  221. package/dist/utils/PerformanceMonitor.js +347 -0
  222. package/dist/utils/RateLimiter.d.ts.map +1 -0
  223. package/dist/utils/RateLimiter.js +172 -0
  224. package/dist/utils/SecureDownloader.d.ts +241 -0
  225. package/dist/utils/SecureDownloader.d.ts.map +1 -0
  226. package/dist/utils/SecureDownloader.js +759 -0
  227. package/dist/utils/ToolCache.d.ts +82 -0
  228. package/dist/utils/ToolCache.d.ts.map +1 -0
  229. package/dist/utils/ToolCache.js +196 -0
  230. package/dist/utils/errorCodes.d.ts +136 -0
  231. package/dist/utils/errorCodes.d.ts.map +1 -0
  232. package/dist/utils/errorCodes.js +87 -0
  233. package/dist/utils/index.d.ts +3 -0
  234. package/dist/utils/index.d.ts.map +1 -1
  235. package/dist/utils/index.js +4 -1
  236. package/dist/utils/installation.d.ts +1 -1
  237. package/dist/utils/installation.d.ts.map +1 -1
  238. package/dist/utils/installation.js +9 -8
  239. package/dist/utils/searchUtils.d.ts +31 -0
  240. package/dist/utils/searchUtils.d.ts.map +1 -1
  241. package/dist/utils/searchUtils.js +62 -1
  242. package/package.json +17 -7
  243. package/dist/config/updateConfig.d.ts +0 -84
  244. package/dist/config/updateConfig.d.ts.map +0 -1
  245. package/dist/config/updateConfig.js +0 -148
  246. package/dist/server/tools/UpdateTools.d.ts +0 -10
  247. package/dist/server/tools/UpdateTools.d.ts.map +0 -1
  248. package/dist/server/tools/UpdateTools.js +0 -85
  249. package/dist/update/BackupManager.d.ts +0 -63
  250. package/dist/update/BackupManager.d.ts.map +0 -1
  251. package/dist/update/BackupManager.js +0 -370
  252. package/dist/update/DependencyChecker.d.ts +0 -41
  253. package/dist/update/DependencyChecker.d.ts.map +0 -1
  254. package/dist/update/DependencyChecker.js +0 -132
  255. package/dist/update/RateLimiter.d.ts.map +0 -1
  256. package/dist/update/RateLimiter.js +0 -172
  257. package/dist/update/SignatureVerifier.d.ts +0 -71
  258. package/dist/update/SignatureVerifier.d.ts.map +0 -1
  259. package/dist/update/SignatureVerifier.js +0 -214
  260. package/dist/update/UpdateChecker.d.ts +0 -132
  261. package/dist/update/UpdateChecker.d.ts.map +0 -1
  262. package/dist/update/UpdateChecker.js +0 -506
  263. package/dist/update/UpdateManager.d.ts +0 -60
  264. package/dist/update/UpdateManager.d.ts.map +0 -1
  265. package/dist/update/UpdateManager.js +0 -730
  266. package/dist/update/VersionManager.d.ts +0 -31
  267. package/dist/update/VersionManager.d.ts.map +0 -1
  268. package/dist/update/VersionManager.js +0 -181
  269. package/dist/update/index.d.ts +0 -9
  270. package/dist/update/index.d.ts.map +0 -1
  271. package/dist/update/index.js +0 -9
  272. /package/dist/{update → utils}/RateLimiter.d.ts +0 -0
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Centralized error handling utilities for consistent error processing
3
+ * Preserves stack traces and provides user-friendly messages
4
+ */
5
+ import { logger } from './logger.js';
6
+ /**
7
+ * Error categories for better error handling
8
+ */
9
+ export var ErrorCategory;
10
+ (function (ErrorCategory) {
11
+ ErrorCategory["USER_ERROR"] = "USER_ERROR";
12
+ ErrorCategory["SYSTEM_ERROR"] = "SYSTEM_ERROR";
13
+ ErrorCategory["NETWORK_ERROR"] = "NETWORK_ERROR";
14
+ ErrorCategory["AUTH_ERROR"] = "AUTH_ERROR";
15
+ ErrorCategory["VALIDATION_ERROR"] = "VALIDATION_ERROR"; // Validation failures
16
+ })(ErrorCategory || (ErrorCategory = {}));
17
+ /**
18
+ * Custom error class with additional context
19
+ */
20
+ export class ApplicationError extends Error {
21
+ category;
22
+ code;
23
+ details;
24
+ originalError;
25
+ constructor(message, category = ErrorCategory.SYSTEM_ERROR, code, details, originalError) {
26
+ super(message);
27
+ this.name = 'ApplicationError';
28
+ this.category = category;
29
+ this.code = code;
30
+ this.details = details;
31
+ this.originalError = originalError;
32
+ // Maintain proper stack trace with truncation to prevent memory issues
33
+ if (originalError?.stack) {
34
+ const truncatedOriginalStack = ErrorHandler.truncateStack(originalError.stack);
35
+ this.stack = `${this.stack}\nCaused by: ${truncatedOriginalStack}`;
36
+ }
37
+ }
38
+ }
39
+ /**
40
+ * Utility class for consistent error handling
41
+ */
42
+ export class ErrorHandler {
43
+ /**
44
+ * Maximum stack trace depth to prevent memory issues
45
+ */
46
+ static MAX_STACK_DEPTH = 10;
47
+ /**
48
+ * Maximum length for stack trace strings
49
+ */
50
+ static MAX_STACK_LENGTH = 5000;
51
+ /**
52
+ * Truncate stack trace to prevent memory issues
53
+ */
54
+ static truncateStack(stack) {
55
+ if (!stack)
56
+ return undefined;
57
+ // Limit total length
58
+ if (stack.length > this.MAX_STACK_LENGTH) {
59
+ stack = stack.substring(0, this.MAX_STACK_LENGTH) + '\n... (truncated)';
60
+ }
61
+ // Limit number of stack frames
62
+ const lines = stack.split('\n');
63
+ if (lines.length > this.MAX_STACK_DEPTH) {
64
+ return lines.slice(0, this.MAX_STACK_DEPTH).join('\n') + '\n... (truncated)';
65
+ }
66
+ return stack;
67
+ }
68
+ /**
69
+ * Extract error information while preserving context
70
+ */
71
+ static extractErrorInfo(error) {
72
+ // Handle ApplicationError
73
+ if (error instanceof ApplicationError) {
74
+ return {
75
+ message: error.message,
76
+ category: error.category,
77
+ code: error.code,
78
+ details: error.details,
79
+ stack: this.truncateStack(error.stack),
80
+ originalError: error.originalError
81
+ };
82
+ }
83
+ // Handle standard Error
84
+ if (error instanceof Error) {
85
+ return {
86
+ message: error.message,
87
+ category: ErrorCategory.SYSTEM_ERROR,
88
+ stack: this.truncateStack(error.stack),
89
+ originalError: error
90
+ };
91
+ }
92
+ // Handle string errors
93
+ if (typeof error === 'string') {
94
+ return {
95
+ message: error,
96
+ category: ErrorCategory.SYSTEM_ERROR
97
+ };
98
+ }
99
+ // Handle unknown errors
100
+ return {
101
+ message: 'An unknown error occurred',
102
+ category: ErrorCategory.SYSTEM_ERROR,
103
+ details: error
104
+ };
105
+ }
106
+ /**
107
+ * Get user-friendly error message
108
+ */
109
+ static getUserMessage(error) {
110
+ const errorInfo = this.extractErrorInfo(error);
111
+ // Provide user-friendly messages based on category
112
+ switch (errorInfo.category) {
113
+ case ErrorCategory.AUTH_ERROR:
114
+ return `Authentication error: ${errorInfo.message}`;
115
+ case ErrorCategory.VALIDATION_ERROR:
116
+ return `Validation error: ${errorInfo.message}`;
117
+ case ErrorCategory.NETWORK_ERROR:
118
+ return `Network error: ${errorInfo.message}. Please check your connection and try again.`;
119
+ case ErrorCategory.USER_ERROR:
120
+ return errorInfo.message; // User errors should already be user-friendly
121
+ default:
122
+ // For system errors, provide a generic message
123
+ return 'An unexpected error occurred. Please try again later.';
124
+ }
125
+ }
126
+ /**
127
+ * Log error with appropriate level and context
128
+ */
129
+ static logError(context, error, additionalInfo) {
130
+ const errorInfo = this.extractErrorInfo(error);
131
+ const logData = {
132
+ context,
133
+ category: errorInfo.category,
134
+ code: errorInfo.code,
135
+ message: errorInfo.message,
136
+ ...additionalInfo
137
+ };
138
+ // Log based on category
139
+ switch (errorInfo.category) {
140
+ case ErrorCategory.USER_ERROR:
141
+ case ErrorCategory.VALIDATION_ERROR:
142
+ logger.warn(`${context}: ${errorInfo.message}`, logData);
143
+ break;
144
+ case ErrorCategory.AUTH_ERROR:
145
+ logger.warn(`${context}: Authentication error`, logData);
146
+ break;
147
+ case ErrorCategory.NETWORK_ERROR:
148
+ logger.error(`${context}: Network error`, {
149
+ ...logData,
150
+ stack: errorInfo.stack
151
+ });
152
+ break;
153
+ default:
154
+ logger.error(`${context}: System error`, {
155
+ ...logData,
156
+ stack: errorInfo.stack,
157
+ details: errorInfo.details
158
+ });
159
+ }
160
+ // Log stack trace in debug mode for all errors (already truncated)
161
+ if (errorInfo.stack) {
162
+ logger.debug(`${context} - Stack trace:`, { stack: errorInfo.stack });
163
+ }
164
+ }
165
+ /**
166
+ * Create an error with context preservation
167
+ */
168
+ static createError(message, category = ErrorCategory.SYSTEM_ERROR, code, originalError) {
169
+ const original = originalError instanceof Error ? originalError : undefined;
170
+ return new ApplicationError(message, category, code, undefined, original);
171
+ }
172
+ /**
173
+ * Wrap an error with additional context
174
+ */
175
+ static wrapError(error, context, category) {
176
+ const errorInfo = this.extractErrorInfo(error);
177
+ return new ApplicationError(`${context}: ${errorInfo.message}`, category || errorInfo.category, errorInfo.code, errorInfo.details, errorInfo.originalError);
178
+ }
179
+ /**
180
+ * Check if error is of a specific category
181
+ */
182
+ static isErrorCategory(error, category) {
183
+ const errorInfo = this.extractErrorInfo(error);
184
+ return errorInfo.category === category;
185
+ }
186
+ /**
187
+ * Format error for API response
188
+ */
189
+ static formatForResponse(error) {
190
+ const errorInfo = this.extractErrorInfo(error);
191
+ const userMessage = this.getUserMessage(error);
192
+ return {
193
+ success: false,
194
+ message: userMessage,
195
+ error: errorInfo.code || errorInfo.category,
196
+ // Only include details in development
197
+ details: process.env.NODE_ENV === 'development' ? errorInfo.details : undefined
198
+ };
199
+ }
200
+ }
201
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXJyb3JIYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL0Vycm9ySGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRXJDOztHQUVHO0FBQ0gsTUFBTSxDQUFOLElBQVksYUFNWDtBQU5ELFdBQVksYUFBYTtJQUN2QiwwQ0FBeUIsQ0FBQTtJQUN6Qiw4Q0FBNkIsQ0FBQTtJQUM3QixnREFBK0IsQ0FBQTtJQUMvQiwwQ0FBeUIsQ0FBQTtJQUN6QixzREFBcUMsQ0FBQSxDQUFDLHNCQUFzQjtBQUM5RCxDQUFDLEVBTlcsYUFBYSxLQUFiLGFBQWEsUUFNeEI7QUFjRDs7R0FFRztBQUNILE1BQU0sT0FBTyxnQkFBaUIsU0FBUSxLQUFLO0lBQ3pCLFFBQVEsQ0FBZ0I7SUFDeEIsSUFBSSxDQUFVO0lBQ2QsT0FBTyxDQUEyQjtJQUNsQyxhQUFhLENBQVM7SUFFdEMsWUFDRSxPQUFlLEVBQ2YsV0FBMEIsYUFBYSxDQUFDLFlBQVksRUFDcEQsSUFBYSxFQUNiLE9BQWlDLEVBQ2pDLGFBQXFCO1FBRXJCLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNmLElBQUksQ0FBQyxJQUFJLEdBQUcsa0JBQWtCLENBQUM7UUFDL0IsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFDakIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFFbkMsdUVBQXVFO1FBQ3ZFLElBQUksYUFBYSxFQUFFLEtBQUssRUFBRSxDQUFDO1lBQ3pCLE1BQU0sc0JBQXNCLEdBQUcsWUFBWSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDL0UsSUFBSSxDQUFDLEtBQUss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LEVBQ2pCLFNBQVMsQ0FBQyxhQUFhLENBQ3hCLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsZUFBZSxDQUFDLEtBQWMsRUFBRSxRQUF1QjtRQUM1RCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDL0MsT0FBTyxTQUFTLENBQUMsUUFBUSxLQUFLLFFBQVEsQ0FBQztJQUN6QyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsaUJBQWlCLENBQUMsS0FBYztRQU1yQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDL0MsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUUvQyxPQUFPO1lBQ0wsT0FBTyxFQUFFLEtBQUs7WUFDZCxPQUFPLEVBQUUsV0FBVztZQUNwQixLQUFLLEVBQUUsU0FBUyxDQUFDLElBQUksSUFBSSxTQUFTLENBQUMsUUFBUTtZQUMzQyxzQ0FBc0M7WUFDdEMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLGFBQWEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUztTQUNoRixDQUFDO0lBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxpbmcgdXRpbGl0aWVzIGZvciBjb25zaXN0ZW50IGVycm9yIHByb2Nlc3NpbmdcbiAqIFByZXNlcnZlcyBzdGFjayB0cmFjZXMgYW5kIHByb3ZpZGVzIHVzZXItZnJpZW5kbHkgbWVzc2FnZXNcbiAqL1xuXG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5cbi8qKlxuICogRXJyb3IgY2F0ZWdvcmllcyBmb3IgYmV0dGVyIGVycm9yIGhhbmRsaW5nXG4gKi9cbmV4cG9ydCBlbnVtIEVycm9yQ2F0ZWdvcnkge1xuICBVU0VSX0VSUk9SID0gJ1VTRVJfRVJST1InLCAgICAgICAgLy8gVXNlciBpbnB1dCBpc3N1ZXNcbiAgU1lTVEVNX0VSUk9SID0gJ1NZU1RFTV9FUlJPUicsICAgIC8vIEludGVybmFsIHN5c3RlbSBmYWlsdXJlc1xuICBORVRXT1JLX0VSUk9SID0gJ05FVFdPUktfRVJST1InLCAgLy8gQVBJL25ldHdvcmsgaXNzdWVzXG4gIEFVVEhfRVJST1IgPSAnQVVUSF9FUlJPUicsICAgICAgICAvLyBBdXRoZW50aWNhdGlvbi9hdXRob3JpemF0aW9uXG4gIFZBTElEQVRJT05fRVJST1IgPSAnVkFMSURBVElPTl9FUlJPUicgLy8gVmFsaWRhdGlvbiBmYWlsdXJlc1xufVxuXG4vKipcbiAqIFN0cnVjdHVyZWQgZXJyb3IgaW5mb3JtYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFcnJvckluZm8ge1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIGNhdGVnb3J5OiBFcnJvckNhdGVnb3J5O1xuICBjb2RlPzogc3RyaW5nO1xuICBkZXRhaWxzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIHN0YWNrPzogc3RyaW5nO1xuICBvcmlnaW5hbEVycm9yPzogRXJyb3I7XG59XG5cbi8qKlxuICogQ3VzdG9tIGVycm9yIGNsYXNzIHdpdGggYWRkaXRpb25hbCBjb250ZXh0XG4gKi9cbmV4cG9ydCBjbGFzcyBBcHBsaWNhdGlvbkVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBwdWJsaWMgcmVhZG9ubHkgY2F0ZWdvcnk6IEVycm9yQ2F0ZWdvcnk7XG4gIHB1YmxpYyByZWFkb25seSBjb2RlPzogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgZGV0YWlscz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBwdWJsaWMgcmVhZG9ubHkgb3JpZ2luYWxFcnJvcj86IEVycm9yO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIG1lc3NhZ2U6IHN0cmluZyxcbiAgICBjYXRlZ29yeTogRXJyb3JDYXRlZ29yeSA9IEVycm9yQ2F0ZWdvcnkuU1lTVEVNX0VSUk9SLFxuICAgIGNvZGU/OiBzdHJpbmcsXG4gICAgZGV0YWlscz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgIG9yaWdpbmFsRXJyb3I/OiBFcnJvclxuICApIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnQXBwbGljYXRpb25FcnJvcic7XG4gICAgdGhpcy5jYXRlZ29yeSA9IGNhdGVnb3J5O1xuICAgIHRoaXMuY29kZSA9IGNvZGU7XG4gICAgdGhpcy5kZXRhaWxzID0gZGV0YWlscztcbiAgICB0aGlzLm9yaWdpbmFsRXJyb3IgPSBvcmlnaW5hbEVycm9yO1xuXG4gICAgLy8gTWFpbnRhaW4gcHJvcGVyIHN0YWNrIHRyYWNlIHdpdGggdHJ1bmNhdGlvbiB0byBwcmV2ZW50IG1lbW9yeSBpc3N1ZXNcbiAgICBpZiAob3JpZ2luYWxFcnJvcj8uc3RhY2spIHtcbiAgICAgIGNvbnN0IHRydW5jYXRlZE9yaWdpbmFsU3RhY2sgPSBFcnJvckhhbmRsZXIudHJ1bmNhdGVTdGFjayhvcmlnaW5hbEVycm9yLnN0YWNrKTtcbiAgICAgIHRoaXMuc3RhY2sgPSBgJHt0aGlzLnN0YWNrfVxcbkNhdXNlZCBieTogJHt0cnVuY2F0ZWRPcmlnaW5hbFN0YWNrfWA7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogVXRpbGl0eSBjbGFzcyBmb3IgY29uc2lzdGVudCBlcnJvciBoYW5kbGluZ1xuICovXG5leHBvcnQgY2xhc3MgRXJyb3JIYW5kbGVyIHtcbiAgLyoqXG4gICAqIE1heGltdW0gc3RhY2sgdHJhY2UgZGVwdGggdG8gcHJldmVudCBtZW1vcnkgaXNzdWVzXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBNQVhfU1RBQ0tfREVQVEggPSAxMDtcbiAgXG4gIC8qKlxuICAgKiBNYXhpbXVtIGxlbmd0aCBmb3Igc3RhY2sgdHJhY2Ugc3RyaW5nc1xuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgTUFYX1NUQUNLX0xFTkdUSCA9IDUwMDA7XG4gIFxuICAvKipcbiAgICogVHJ1bmNhdGUgc3RhY2sgdHJhY2UgdG8gcHJldmVudCBtZW1vcnkgaXNzdWVzXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHRydW5jYXRlU3RhY2soc3RhY2s/OiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICghc3RhY2spIHJldHVybiB1bmRlZmluZWQ7XG4gICAgXG4gICAgLy8gTGltaXQgdG90YWwgbGVuZ3RoXG4gICAgaWYgKHN0YWNrLmxlbmd0aCA+IHRoaXMuTUFYX1NUQUNLX0xFTkdUSCkge1xuICAgICAgc3RhY2sgPSBzdGFjay5zdWJzdHJpbmcoMCwgdGhpcy5NQVhfU1RBQ0tfTEVOR1RIKSArICdcXG4uLi4gKHRydW5jYXRlZCknO1xuICAgIH1cbiAgICBcbiAgICAvLyBMaW1pdCBudW1iZXIgb2Ygc3RhY2sgZnJhbWVzXG4gICAgY29uc3QgbGluZXMgPSBzdGFjay5zcGxpdCgnXFxuJyk7XG4gICAgaWYgKGxpbmVzLmxlbmd0aCA+IHRoaXMuTUFYX1NUQUNLX0RFUFRIKSB7XG4gICAgICByZXR1cm4gbGluZXMuc2xpY2UoMCwgdGhpcy5NQVhfU1RBQ0tfREVQVEgpLmpvaW4oJ1xcbicpICsgJ1xcbi4uLiAodHJ1bmNhdGVkKSc7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBzdGFjaztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEV4dHJhY3QgZXJyb3IgaW5mb3JtYXRpb24gd2hpbGUgcHJlc2VydmluZyBjb250ZXh0XG4gICAqL1xuICBzdGF0aWMgZXh0cmFjdEVycm9ySW5mbyhlcnJvcjogdW5rbm93bik6IEVycm9ySW5mbyB7XG4gICAgLy8gSGFuZGxlIEFwcGxpY2F0aW9uRXJyb3JcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBBcHBsaWNhdGlvbkVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBtZXNzYWdlOiBlcnJvci5tZXNzYWdlLFxuICAgICAgICBjYXRlZ29yeTogZXJyb3IuY2F0ZWdvcnksXG4gICAgICAgIGNvZGU6IGVycm9yLmNvZGUsXG4gICAgICAgIGRldGFpbHM6IGVycm9yLmRldGFpbHMsXG4gICAgICAgIHN0YWNrOiB0aGlzLnRydW5jYXRlU3RhY2soZXJyb3Iuc3RhY2spLFxuICAgICAgICBvcmlnaW5hbEVycm9yOiBlcnJvci5vcmlnaW5hbEVycm9yXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIEhhbmRsZSBzdGFuZGFyZCBFcnJvclxuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBtZXNzYWdlOiBlcnJvci5tZXNzYWdlLFxuICAgICAgICBjYXRlZ29yeTogRXJyb3JDYXRlZ29yeS5TWVNURU1fRVJST1IsXG4gICAgICAgIHN0YWNrOiB0aGlzLnRydW5jYXRlU3RhY2soZXJyb3Iuc3RhY2spLFxuICAgICAgICBvcmlnaW5hbEVycm9yOiBlcnJvclxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBIYW5kbGUgc3RyaW5nIGVycm9yc1xuICAgIGlmICh0eXBlb2YgZXJyb3IgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBtZXNzYWdlOiBlcnJvcixcbiAgICAgICAgY2F0ZWdvcnk6IEVycm9yQ2F0ZWdvcnkuU1lTVEVNX0VSUk9SXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIEhhbmRsZSB1bmtub3duIGVycm9yc1xuICAgIHJldHVybiB7XG4gICAgICBtZXNzYWdlOiAnQW4gdW5rbm93biBlcnJvciBvY2N1cnJlZCcsXG4gICAgICBjYXRlZ29yeTogRXJyb3JDYXRlZ29yeS5TWVNURU1fRVJST1IsXG4gICAgICBkZXRhaWxzOiBlcnJvciBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IHVzZXItZnJpZW5kbHkgZXJyb3IgbWVzc2FnZVxuICAgKi9cbiAgc3RhdGljIGdldFVzZXJNZXNzYWdlKGVycm9yOiB1bmtub3duKTogc3RyaW5nIHtcbiAgICBjb25zdCBlcnJvckluZm8gPSB0aGlzLmV4dHJhY3RFcnJvckluZm8oZXJyb3IpO1xuICAgIFxuICAgIC8vIFByb3ZpZGUgdXNlci1mcmllbmRseSBtZXNzYWdlcyBiYXNlZCBvbiBjYXRlZ29yeVxuICAgIHN3aXRjaCAoZXJyb3JJbmZvLmNhdGVnb3J5KSB7XG4gICAgICBjYXNlIEVycm9yQ2F0ZWdvcnkuQVVUSF9FUlJPUjpcbiAgICAgICAgcmV0dXJuIGBBdXRoZW50aWNhdGlvbiBlcnJvcjogJHtlcnJvckluZm8ubWVzc2FnZX1gO1xuICAgICAgY2FzZSBFcnJvckNhdGVnb3J5LlZBTElEQVRJT05fRVJST1I6XG4gICAgICAgIHJldHVybiBgVmFsaWRhdGlvbiBlcnJvcjogJHtlcnJvckluZm8ubWVzc2FnZX1gO1xuICAgICAgY2FzZSBFcnJvckNhdGVnb3J5Lk5FVFdPUktfRVJST1I6XG4gICAgICAgIHJldHVybiBgTmV0d29yayBlcnJvcjogJHtlcnJvckluZm8ubWVzc2FnZX0uIFBsZWFzZSBjaGVjayB5b3VyIGNvbm5lY3Rpb24gYW5kIHRyeSBhZ2Fpbi5gO1xuICAgICAgY2FzZSBFcnJvckNhdGVnb3J5LlVTRVJfRVJST1I6XG4gICAgICAgIHJldHVybiBlcnJvckluZm8ubWVzc2FnZTsgLy8gVXNlciBlcnJvcnMgc2hvdWxkIGFscmVhZHkgYmUgdXNlci1mcmllbmRseVxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgLy8gRm9yIHN5c3RlbSBlcnJvcnMsIHByb3ZpZGUgYSBnZW5lcmljIG1lc3NhZ2VcbiAgICAgICAgcmV0dXJuICdBbiB1bmV4cGVjdGVkIGVycm9yIG9jY3VycmVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIExvZyBlcnJvciB3aXRoIGFwcHJvcHJpYXRlIGxldmVsIGFuZCBjb250ZXh0XG4gICAqL1xuICBzdGF0aWMgbG9nRXJyb3IoXG4gICAgY29udGV4dDogc3RyaW5nLFxuICAgIGVycm9yOiB1bmtub3duLFxuICAgIGFkZGl0aW9uYWxJbmZvPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj5cbiAgKTogdm9pZCB7XG4gICAgY29uc3QgZXJyb3JJbmZvID0gdGhpcy5leHRyYWN0RXJyb3JJbmZvKGVycm9yKTtcbiAgICBcbiAgICBjb25zdCBsb2dEYXRhID0ge1xuICAgICAgY29udGV4dCxcbiAgICAgIGNhdGVnb3J5OiBlcnJvckluZm8uY2F0ZWdvcnksXG4gICAgICBjb2RlOiBlcnJvckluZm8uY29kZSxcbiAgICAgIG1lc3NhZ2U6IGVycm9ySW5mby5tZXNzYWdlLFxuICAgICAgLi4uYWRkaXRpb25hbEluZm9cbiAgICB9O1xuXG4gICAgLy8gTG9nIGJhc2VkIG9uIGNhdGVnb3J5XG4gICAgc3dpdGNoIChlcnJvckluZm8uY2F0ZWdvcnkpIHtcbiAgICAgIGNhc2UgRXJyb3JDYXRlZ29yeS5VU0VSX0VSUk9SOlxuICAgICAgY2FzZSBFcnJvckNhdGVnb3J5LlZBTElEQVRJT05fRVJST1I6XG4gICAgICAgIGxvZ2dlci53YXJuKGAke2NvbnRleHR9OiAke2Vycm9ySW5mby5tZXNzYWdlfWAsIGxvZ0RhdGEpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgRXJyb3JDYXRlZ29yeS5BVVRIX0VSUk9SOlxuICAgICAgICBsb2dnZXIud2FybihgJHtjb250ZXh0fTogQXV0aGVudGljYXRpb24gZXJyb3JgLCBsb2dEYXRhKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIEVycm9yQ2F0ZWdvcnkuTkVUV09SS19FUlJPUjpcbiAgICAgICAgbG9nZ2VyLmVycm9yKGAke2NvbnRleHR9OiBOZXR3b3JrIGVycm9yYCwge1xuICAgICAgICAgIC4uLmxvZ0RhdGEsXG4gICAgICAgICAgc3RhY2s6IGVycm9ySW5mby5zdGFja1xuICAgICAgICB9KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBsb2dnZXIuZXJyb3IoYCR7Y29udGV4dH06IFN5c3RlbSBlcnJvcmAsIHtcbiAgICAgICAgICAuLi5sb2dEYXRhLFxuICAgICAgICAgIHN0YWNrOiBlcnJvckluZm8uc3RhY2ssXG4gICAgICAgICAgZGV0YWlsczogZXJyb3JJbmZvLmRldGFpbHNcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gTG9nIHN0YWNrIHRyYWNlIGluIGRlYnVnIG1vZGUgZm9yIGFsbCBlcnJvcnMgKGFscmVhZHkgdHJ1bmNhdGVkKVxuICAgIGlmIChlcnJvckluZm8uc3RhY2spIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgJHtjb250ZXh0fSAtIFN0YWNrIHRyYWNlOmAsIHsgc3RhY2s6IGVycm9ySW5mby5zdGFjayB9KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGFuIGVycm9yIHdpdGggY29udGV4dCBwcmVzZXJ2YXRpb25cbiAgICovXG4gIHN0YXRpYyBjcmVhdGVFcnJvcihcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgY2F0ZWdvcnk6IEVycm9yQ2F0ZWdvcnkgPSBFcnJvckNhdGVnb3J5LlNZU1RFTV9FUlJPUixcbiAgICBjb2RlPzogc3RyaW5nLFxuICAgIG9yaWdpbmFsRXJyb3I/OiB1bmtub3duXG4gICk6IEFwcGxpY2F0aW9uRXJyb3Ige1xuICAgIGNvbnN0IG9yaWdpbmFsID0gb3JpZ2luYWxFcnJvciBpbnN0YW5jZW9mIEVycm9yID8gb3JpZ2luYWxFcnJvciA6IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gbmV3IEFwcGxpY2F0aW9uRXJyb3IobWVzc2FnZSwgY2F0ZWdvcnksIGNvZGUsIHVuZGVmaW5lZCwgb3JpZ2luYWwpO1xuICB9XG5cbiAgLyoqXG4gICAqIFdyYXAgYW4gZXJyb3Igd2l0aCBhZGRpdGlvbmFsIGNvbnRleHRcbiAgICovXG4gIHN0YXRpYyB3cmFwRXJyb3IoXG4gICAgZXJyb3I6IHVua25vd24sXG4gICAgY29udGV4dDogc3RyaW5nLFxuICAgIGNhdGVnb3J5PzogRXJyb3JDYXRlZ29yeVxuICApOiBBcHBsaWNhdGlvbkVycm9yIHtcbiAgICBjb25zdCBlcnJvckluZm8gPSB0aGlzLmV4dHJhY3RFcnJvckluZm8oZXJyb3IpO1xuICAgIHJldHVybiBuZXcgQXBwbGljYXRpb25FcnJvcihcbiAgICAgIGAke2NvbnRleHR9OiAke2Vycm9ySW5mby5tZXNzYWdlfWAsXG4gICAgICBjYXRlZ29yeSB8fCBlcnJvckluZm8uY2F0ZWdvcnksXG4gICAgICBlcnJvckluZm8uY29kZSxcbiAgICAgIGVycm9ySW5mby5kZXRhaWxzLFxuICAgICAgZXJyb3JJbmZvLm9yaWdpbmFsRXJyb3JcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGVycm9yIGlzIG9mIGEgc3BlY2lmaWMgY2F0ZWdvcnlcbiAgICovXG4gIHN0YXRpYyBpc0Vycm9yQ2F0ZWdvcnkoZXJyb3I6IHVua25vd24sIGNhdGVnb3J5OiBFcnJvckNhdGVnb3J5KTogYm9vbGVhbiB7XG4gICAgY29uc3QgZXJyb3JJbmZvID0gdGhpcy5leHRyYWN0RXJyb3JJbmZvKGVycm9yKTtcbiAgICByZXR1cm4gZXJyb3JJbmZvLmNhdGVnb3J5ID09PSBjYXRlZ29yeTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JtYXQgZXJyb3IgZm9yIEFQSSByZXNwb25zZVxuICAgKi9cbiAgc3RhdGljIGZvcm1hdEZvclJlc3BvbnNlKGVycm9yOiB1bmtub3duKToge1xuICAgIHN1Y2Nlc3M6IGZhbHNlO1xuICAgIG1lc3NhZ2U6IHN0cmluZztcbiAgICBlcnJvcjogc3RyaW5nO1xuICAgIGRldGFpbHM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgfSB7XG4gICAgY29uc3QgZXJyb3JJbmZvID0gdGhpcy5leHRyYWN0RXJyb3JJbmZvKGVycm9yKTtcbiAgICBjb25zdCB1c2VyTWVzc2FnZSA9IHRoaXMuZ2V0VXNlck1lc3NhZ2UoZXJyb3IpO1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgIG1lc3NhZ2U6IHVzZXJNZXNzYWdlLFxuICAgICAgZXJyb3I6IGVycm9ySW5mby5jb2RlIHx8IGVycm9ySW5mby5jYXRlZ29yeSxcbiAgICAgIC8vIE9ubHkgaW5jbHVkZSBkZXRhaWxzIGluIGRldmVsb3BtZW50XG4gICAgICBkZXRhaWxzOiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50JyA/IGVycm9ySW5mby5kZXRhaWxzIDogdW5kZWZpbmVkXG4gICAgfTtcbiAgfVxufSJdfQ==
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Utility class for efficient file discovery operations
3
+ * Provides optimized file search with caching and security
4
+ *
5
+ * IMPLEMENTATION (PR #503 - PR #496 Recommendation):
6
+ * 1. PERFORMANCE: Single readdir operation instead of multiple file checks
7
+ * 2. PERFORMANCE: 5-second cache TTL for repeated searches
8
+ * 3. SECURITY: Unicode normalization for all search inputs
9
+ * 4. MEMORY: Efficient cache management with 100 entry limit
10
+ *
11
+ * This addresses the PR #496 review recommendation to extract file discovery
12
+ * logic to a reusable utility class for better performance and maintainability.
13
+ */
14
+ export interface FileSearchOptions {
15
+ extensions?: string[];
16
+ partialMatch?: boolean;
17
+ maxResults?: number;
18
+ cacheResults?: boolean;
19
+ }
20
+ export declare class FileDiscoveryUtil {
21
+ private static readonly CACHE_TTL;
22
+ private static cache;
23
+ /**
24
+ * Find files in a directory with optimized search
25
+ * Uses single readdir operation and filters results
26
+ */
27
+ static findFiles(directory: string, searchName: string, options?: FileSearchOptions): Promise<string[]>;
28
+ /**
29
+ * Build search patterns for different file extensions
30
+ */
31
+ private static buildSearchPatterns;
32
+ /**
33
+ * Check if filename matches pattern
34
+ */
35
+ private static matchesPattern;
36
+ /**
37
+ * Get cached results if still valid
38
+ */
39
+ private static getCached;
40
+ /**
41
+ * Cache results with timestamp
42
+ */
43
+ private static setCached;
44
+ /**
45
+ * Clear the cache
46
+ */
47
+ static clearCache(): void;
48
+ /**
49
+ * Find a single file (convenience method)
50
+ */
51
+ static findFile(directory: string, searchName: string, options?: FileSearchOptions): Promise<string | null>;
52
+ }
53
+ //# sourceMappingURL=FileDiscoveryUtil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileDiscoveryUtil.d.ts","sourceRoot":"","sources":["../../src/utils/FileDiscoveryUtil.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAOD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAQ;IACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAiC;IAErD;;;OAGG;WACU,SAAS,CACpB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,MAAM,EAAE,CAAC;IAkFpB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAoBlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAO7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAaxB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAiBxB;;OAEG;IACH,MAAM,CAAC,UAAU,IAAI,IAAI;IAKzB;;OAEG;WACU,QAAQ,CACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAO1B"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Utility class for efficient file discovery operations
3
+ * Provides optimized file search with caching and security
4
+ *
5
+ * IMPLEMENTATION (PR #503 - PR #496 Recommendation):
6
+ * 1. PERFORMANCE: Single readdir operation instead of multiple file checks
7
+ * 2. PERFORMANCE: 5-second cache TTL for repeated searches
8
+ * 3. SECURITY: Unicode normalization for all search inputs
9
+ * 4. MEMORY: Efficient cache management with 100 entry limit
10
+ *
11
+ * This addresses the PR #496 review recommendation to extract file discovery
12
+ * logic to a reusable utility class for better performance and maintainability.
13
+ */
14
+ import * as fs from 'fs/promises';
15
+ import * as path from 'path';
16
+ import { logger } from './logger.js';
17
+ import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
18
+ export class FileDiscoveryUtil {
19
+ static CACHE_TTL = 5000; // 5 seconds cache TTL
20
+ static cache = new Map();
21
+ /**
22
+ * Find files in a directory with optimized search
23
+ * Uses single readdir operation and filters results
24
+ */
25
+ static async findFiles(directory, searchName, options = {}) {
26
+ const { extensions = ['.json', '.yaml', '.yml', '.md'], partialMatch = true, maxResults = 10, cacheResults = true } = options;
27
+ // Normalize search name for security
28
+ const normalizedSearch = UnicodeValidator.normalize(searchName);
29
+ if (!normalizedSearch.isValid) {
30
+ logger.warn('Invalid Unicode in search name', {
31
+ issues: normalizedSearch.detectedIssues
32
+ });
33
+ return [];
34
+ }
35
+ const safeName = normalizedSearch.normalizedContent.toLowerCase();
36
+ // Check cache if enabled
37
+ const cacheKey = `${directory}:${safeName}:${JSON.stringify(options)}`;
38
+ if (cacheResults) {
39
+ const cached = this.getCached(cacheKey);
40
+ if (cached) {
41
+ logger.debug('File search cache hit', { directory, searchName });
42
+ return cached;
43
+ }
44
+ }
45
+ try {
46
+ // Single readdir operation for efficiency
47
+ const files = await fs.readdir(directory);
48
+ // Build search patterns
49
+ const searchPatterns = this.buildSearchPatterns(safeName, extensions);
50
+ // Filter files efficiently
51
+ const matches = [];
52
+ for (const file of files) {
53
+ const fileLower = file.toLowerCase();
54
+ // Check each pattern
55
+ for (const pattern of searchPatterns) {
56
+ if (this.matchesPattern(fileLower, pattern, partialMatch)) {
57
+ const fullPath = path.join(directory, file);
58
+ matches.push(fullPath);
59
+ if (matches.length >= maxResults) {
60
+ break;
61
+ }
62
+ }
63
+ }
64
+ if (matches.length >= maxResults) {
65
+ break;
66
+ }
67
+ }
68
+ // Cache results if enabled
69
+ if (cacheResults && matches.length > 0) {
70
+ this.setCached(cacheKey, matches);
71
+ }
72
+ // Log file discovery for monitoring
73
+ if (matches.length > 0) {
74
+ logger.debug('Files discovered', {
75
+ directory,
76
+ searchName,
77
+ count: matches.length
78
+ });
79
+ }
80
+ return matches;
81
+ }
82
+ catch (error) {
83
+ logger.error('File discovery failed', {
84
+ directory,
85
+ searchName,
86
+ error: error instanceof Error ? error.message : String(error)
87
+ });
88
+ return [];
89
+ }
90
+ }
91
+ /**
92
+ * Build search patterns for different file extensions
93
+ */
94
+ static buildSearchPatterns(baseName, extensions) {
95
+ const patterns = [baseName];
96
+ // Add extension variations
97
+ for (const ext of extensions) {
98
+ patterns.push(`${baseName}${ext}`);
99
+ }
100
+ // Add common variations
101
+ const nameWithoutExtension = baseName.replace(/\.[^.]+$/, '');
102
+ if (nameWithoutExtension !== baseName) {
103
+ patterns.push(nameWithoutExtension);
104
+ for (const ext of extensions) {
105
+ patterns.push(`${nameWithoutExtension}${ext}`);
106
+ }
107
+ }
108
+ return patterns;
109
+ }
110
+ /**
111
+ * Check if filename matches pattern
112
+ */
113
+ static matchesPattern(filename, pattern, partialMatch) {
114
+ if (partialMatch) {
115
+ return filename.includes(pattern);
116
+ }
117
+ return filename === pattern;
118
+ }
119
+ /**
120
+ * Get cached results if still valid
121
+ */
122
+ static getCached(key) {
123
+ const entry = this.cache.get(key);
124
+ if (!entry)
125
+ return null;
126
+ const age = Date.now() - entry.timestamp;
127
+ if (age > this.CACHE_TTL) {
128
+ this.cache.delete(key);
129
+ return null;
130
+ }
131
+ return entry.files;
132
+ }
133
+ /**
134
+ * Cache results with timestamp
135
+ */
136
+ static setCached(key, files) {
137
+ // Limit cache size to prevent memory issues
138
+ if (this.cache.size > 100) {
139
+ // Remove oldest entries
140
+ const entries = Array.from(this.cache.entries());
141
+ entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
142
+ for (let i = 0; i < 50; i++) {
143
+ this.cache.delete(entries[i][0]);
144
+ }
145
+ }
146
+ this.cache.set(key, {
147
+ files,
148
+ timestamp: Date.now()
149
+ });
150
+ }
151
+ /**
152
+ * Clear the cache
153
+ */
154
+ static clearCache() {
155
+ this.cache.clear();
156
+ logger.debug('File discovery cache cleared');
157
+ }
158
+ /**
159
+ * Find a single file (convenience method)
160
+ */
161
+ static async findFile(directory, searchName, options) {
162
+ const files = await this.findFiles(directory, searchName, {
163
+ ...options,
164
+ maxResults: 1
165
+ });
166
+ return files.length > 0 ? files[0] : null;
167
+ }
168
+ }
169
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmlsZURpc2NvdmVyeVV0aWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvRmlsZURpc2NvdmVyeVV0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7OztHQVlHO0FBRUgsT0FBTyxLQUFLLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbEMsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNyQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQWU5RSxNQUFNLE9BQU8saUJBQWlCO0lBQ3BCLE1BQU0sQ0FBVSxTQUFTLEdBQUcsSUFBSSxDQUFDLENBQUMsc0JBQXNCO0lBQ3hELE1BQU0sQ0FBQyxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQXNCLENBQUM7SUFFckQ7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQ3BCLFNBQWlCLEVBQ2pCLFVBQWtCLEVBQ2xCLFVBQTZCLEVBQUU7UUFFL0IsTUFBTSxFQUNKLFVBQVUsR0FBRyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxFQUM5QyxZQUFZLEdBQUcsSUFBSSxFQUNuQixVQUFVLEdBQUcsRUFBRSxFQUNmLFlBQVksR0FBRyxJQUFJLEVBQ3BCLEdBQUcsT0FBTyxDQUFDO1FBRVoscUNBQXFDO1FBQ3JDLE1BQU0sZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2hFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUM5QixNQUFNLENBQUMsSUFBSSxDQUFDLGdDQUFnQyxFQUFFO2dCQUM1QyxNQUFNLEVBQUUsZ0JBQWdCLENBQUMsY0FBYzthQUN4QyxDQUFDLENBQUM7WUFDSCxPQUFPLEVBQUUsQ0FBQztRQUNaLENBQUM7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QixFQUNqQixVQUFrQixFQUNsQixPQUEyQjtRQUUzQixNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFLFVBQVUsRUFBRTtZQUN4RCxHQUFHLE9BQU87WUFDVixVQUFVLEVBQUUsQ0FBQztTQUNkLENBQUMsQ0FBQztRQUNILE9BQU8sS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQzVDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFV0aWxpdHkgY2xhc3MgZm9yIGVmZmljaWVudCBmaWxlIGRpc2NvdmVyeSBvcGVyYXRpb25zXG4gKiBQcm92aWRlcyBvcHRpbWl6ZWQgZmlsZSBzZWFyY2ggd2l0aCBjYWNoaW5nIGFuZCBzZWN1cml0eVxuICogXG4gKiBJTVBMRU1FTlRBVElPTiAoUFIgIzUwMyAtIFBSICM0OTYgUmVjb21tZW5kYXRpb24pOlxuICogMS4gUEVSRk9STUFOQ0U6IFNpbmdsZSByZWFkZGlyIG9wZXJhdGlvbiBpbnN0ZWFkIG9mIG11bHRpcGxlIGZpbGUgY2hlY2tzXG4gKiAyLiBQRVJGT1JNQU5DRTogNS1zZWNvbmQgY2FjaGUgVFRMIGZvciByZXBlYXRlZCBzZWFyY2hlc1xuICogMy4gU0VDVVJJVFk6IFVuaWNvZGUgbm9ybWFsaXphdGlvbiBmb3IgYWxsIHNlYXJjaCBpbnB1dHNcbiAqIDQuIE1FTU9SWTogRWZmaWNpZW50IGNhY2hlIG1hbmFnZW1lbnQgd2l0aCAxMDAgZW50cnkgbGltaXRcbiAqIFxuICogVGhpcyBhZGRyZXNzZXMgdGhlIFBSICM0OTYgcmV2aWV3IHJlY29tbWVuZGF0aW9uIHRvIGV4dHJhY3QgZmlsZSBkaXNjb3ZlcnlcbiAqIGxvZ2ljIHRvIGEgcmV1c2FibGUgdXRpbGl0eSBjbGFzcyBmb3IgYmV0dGVyIHBlcmZvcm1hbmNlIGFuZCBtYWludGFpbmFiaWxpdHkuXG4gKi9cblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBGaWxlU2VhcmNoT3B0aW9ucyB7XG4gIGV4dGVuc2lvbnM/OiBzdHJpbmdbXTtcbiAgcGFydGlhbE1hdGNoPzogYm9vbGVhbjtcbiAgbWF4UmVzdWx0cz86IG51bWJlcjtcbiAgY2FjaGVSZXN1bHRzPzogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIENhY2hlRW50cnkge1xuICBmaWxlczogc3RyaW5nW107XG4gIHRpbWVzdGFtcDogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgRmlsZURpc2NvdmVyeVV0aWwge1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBDQUNIRV9UVEwgPSA1MDAwOyAvLyA1IHNlY29uZHMgY2FjaGUgVFRMXG4gIHByaXZhdGUgc3RhdGljIGNhY2hlID0gbmV3IE1hcDxzdHJpbmcsIENhY2hlRW50cnk+KCk7XG4gIFxuICAvKipcbiAgICogRmluZCBmaWxlcyBpbiBhIGRpcmVjdG9yeSB3aXRoIG9wdGltaXplZCBzZWFyY2hcbiAgICogVXNlcyBzaW5nbGUgcmVhZGRpciBvcGVyYXRpb24gYW5kIGZpbHRlcnMgcmVzdWx0c1xuICAgKi9cbiAgc3RhdGljIGFzeW5jIGZpbmRGaWxlcyhcbiAgICBkaXJlY3Rvcnk6IHN0cmluZyxcbiAgICBzZWFyY2hOYW1lOiBzdHJpbmcsXG4gICAgb3B0aW9uczogRmlsZVNlYXJjaE9wdGlvbnMgPSB7fVxuICApOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgY29uc3Qge1xuICAgICAgZXh0ZW5zaW9ucyA9IFsnLmpzb24nLCAnLnlhbWwnLCAnLnltbCcsICcubWQnXSxcbiAgICAgIHBhcnRpYWxNYXRjaCA9IHRydWUsXG4gICAgICBtYXhSZXN1bHRzID0gMTAsXG4gICAgICBjYWNoZVJlc3VsdHMgPSB0cnVlXG4gICAgfSA9IG9wdGlvbnM7XG4gICAgXG4gICAgLy8gTm9ybWFsaXplIHNlYXJjaCBuYW1lIGZvciBzZWN1cml0eVxuICAgIGNvbnN0IG5vcm1hbGl6ZWRTZWFyY2ggPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShzZWFyY2hOYW1lKTtcbiAgICBpZiAoIW5vcm1hbGl6ZWRTZWFyY2guaXNWYWxpZCkge1xuICAgICAgbG9nZ2VyLndhcm4oJ0ludmFsaWQgVW5pY29kZSBpbiBzZWFyY2ggbmFtZScsIHtcbiAgICAgICAgaXNzdWVzOiBub3JtYWxpemVkU2VhcmNoLmRldGVjdGVkSXNzdWVzXG4gICAgICB9KTtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgY29uc3Qgc2FmZU5hbWUgPSBub3JtYWxpemVkU2VhcmNoLm5vcm1hbGl6ZWRDb250ZW50LnRvTG93ZXJDYXNlKCk7XG4gICAgXG4gICAgLy8gQ2hlY2sgY2FjaGUgaWYgZW5hYmxlZFxuICAgIGNvbnN0IGNhY2hlS2V5ID0gYCR7ZGlyZWN0b3J5fToke3NhZmVOYW1lfToke0pTT04uc3RyaW5naWZ5KG9wdGlvbnMpfWA7XG4gICAgaWYgKGNhY2hlUmVzdWx0cykge1xuICAgICAgY29uc3QgY2FjaGVkID0gdGhpcy5nZXRDYWNoZWQoY2FjaGVLZXkpO1xuICAgICAgaWYgKGNhY2hlZCkge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ0ZpbGUgc2VhcmNoIGNhY2hlIGhpdCcsIHsgZGlyZWN0b3J5LCBzZWFyY2hOYW1lIH0pO1xuICAgICAgICByZXR1cm4gY2FjaGVkO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICB0cnkge1xuICAgICAgLy8gU2luZ2xlIHJlYWRkaXIgb3BlcmF0aW9uIGZvciBlZmZpY2llbmN5XG4gICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IGZzLnJlYWRkaXIoZGlyZWN0b3J5KTtcbiAgICAgIFxuICAgICAgLy8gQnVpbGQgc2VhcmNoIHBhdHRlcm5zXG4gICAgICBjb25zdCBzZWFyY2hQYXR0ZXJucyA9IHRoaXMuYnVpbGRTZWFyY2hQYXR0ZXJucyhzYWZlTmFtZSwgZXh0ZW5zaW9ucyk7XG4gICAgICBcbiAgICAgIC8vIEZpbHRlciBmaWxlcyBlZmZpY2llbnRseVxuICAgICAgY29uc3QgbWF0Y2hlczogc3RyaW5nW10gPSBbXTtcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgICAgICBjb25zdCBmaWxlTG93ZXIgPSBmaWxlLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIFxuICAgICAgICAvLyBDaGVjayBlYWNoIHBhdHRlcm5cbiAgICAgICAgZm9yIChjb25zdCBwYXR0ZXJuIG9mIHNlYXJjaFBhdHRlcm5zKSB7XG4gICAgICAgICAgaWYgKHRoaXMubWF0Y2hlc1BhdHRlcm4oZmlsZUxvd2VyLCBwYXR0ZXJuLCBwYXJ0aWFsTWF0Y2gpKSB7XG4gICAgICAgICAgICBjb25zdCBmdWxsUGF0aCA9IHBhdGguam9pbihkaXJlY3RvcnksIGZpbGUpO1xuICAgICAgICAgICAgbWF0Y2hlcy5wdXNoKGZ1bGxQYXRoKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgaWYgKG1hdGNoZXMubGVuZ3RoID49IG1heFJlc3VsdHMpIHtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBpZiAobWF0Y2hlcy5sZW5ndGggPj0gbWF4UmVzdWx0cykge1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIENhY2hlIHJlc3VsdHMgaWYgZW5hYmxlZFxuICAgICAgaWYgKGNhY2hlUmVzdWx0cyAmJiBtYXRjaGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGhpcy5zZXRDYWNoZWQoY2FjaGVLZXksIG1hdGNoZXMpO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBMb2cgZmlsZSBkaXNjb3ZlcnkgZm9yIG1vbml0b3JpbmdcbiAgICAgIGlmIChtYXRjaGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdGaWxlcyBkaXNjb3ZlcmVkJywge1xuICAgICAgICAgIGRpcmVjdG9yeSxcbiAgICAgICAgICBzZWFyY2hOYW1lLFxuICAgICAgICAgIGNvdW50OiBtYXRjaGVzLmxlbmd0aFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIG1hdGNoZXM7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcignRmlsZSBkaXNjb3ZlcnkgZmFpbGVkJywge1xuICAgICAgICBkaXJlY3RvcnksXG4gICAgICAgIHNlYXJjaE5hbWUsXG4gICAgICAgIGVycm9yOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcilcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEJ1aWxkIHNlYXJjaCBwYXR0ZXJucyBmb3IgZGlmZmVyZW50IGZpbGUgZXh0ZW5zaW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgYnVpbGRTZWFyY2hQYXR0ZXJucyhiYXNlTmFtZTogc3RyaW5nLCBleHRlbnNpb25zOiBzdHJpbmdbXSk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBwYXR0ZXJuczogc3RyaW5nW10gPSBbYmFzZU5hbWVdO1xuICAgIFxuICAgIC8vIEFkZCBleHRlbnNpb24gdmFyaWF0aW9uc1xuICAgIGZvciAoY29uc3QgZXh0IG9mIGV4dGVuc2lvbnMpIHtcbiAgICAgIHBhdHRlcm5zLnB1c2goYCR7YmFzZU5hbWV9JHtleHR9YCk7XG4gICAgfVxuICAgIFxuICAgIC8vIEFkZCBjb21tb24gdmFyaWF0aW9uc1xuICAgIGNvbnN0IG5hbWVXaXRob3V0RXh0ZW5zaW9uID0gYmFzZU5hbWUucmVwbGFjZSgvXFwuW14uXSskLywgJycpO1xuICAgIGlmIChuYW1lV2l0aG91dEV4dGVuc2lvbiAhPT0gYmFzZU5hbWUpIHtcbiAgICAgIHBhdHRlcm5zLnB1c2gobmFtZVdpdGhvdXRFeHRlbnNpb24pO1xuICAgICAgZm9yIChjb25zdCBleHQgb2YgZXh0ZW5zaW9ucykge1xuICAgICAgICBwYXR0ZXJucy5wdXNoKGAke25hbWVXaXRob3V0RXh0ZW5zaW9ufSR7ZXh0fWApO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gcGF0dGVybnM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDaGVjayBpZiBmaWxlbmFtZSBtYXRjaGVzIHBhdHRlcm5cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIG1hdGNoZXNQYXR0ZXJuKGZpbGVuYW1lOiBzdHJpbmcsIHBhdHRlcm46IHN0cmluZywgcGFydGlhbE1hdGNoOiBib29sZWFuKTogYm9vbGVhbiB7XG4gICAgaWYgKHBhcnRpYWxNYXRjaCkge1xuICAgICAgcmV0dXJuIGZpbGVuYW1lLmluY2x1ZGVzKHBhdHRlcm4pO1xuICAgIH1cbiAgICByZXR1cm4gZmlsZW5hbWUgPT09IHBhdHRlcm47XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgY2FjaGVkIHJlc3VsdHMgaWYgc3RpbGwgdmFsaWRcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGdldENhY2hlZChrZXk6IHN0cmluZyk6IHN0cmluZ1tdIHwgbnVsbCB7XG4gICAgY29uc3QgZW50cnkgPSB0aGlzLmNhY2hlLmdldChrZXkpO1xuICAgIGlmICghZW50cnkpIHJldHVybiBudWxsO1xuICAgIFxuICAgIGNvbnN0IGFnZSA9IERhdGUubm93KCkgLSBlbnRyeS50aW1lc3RhbXA7XG4gICAgaWYgKGFnZSA+IHRoaXMuQ0FDSEVfVFRMKSB7XG4gICAgICB0aGlzLmNhY2hlLmRlbGV0ZShrZXkpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBlbnRyeS5maWxlcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIENhY2hlIHJlc3VsdHMgd2l0aCB0aW1lc3RhbXBcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIHNldENhY2hlZChrZXk6IHN0cmluZywgZmlsZXM6IHN0cmluZ1tdKTogdm9pZCB7XG4gICAgLy8gTGltaXQgY2FjaGUgc2l6ZSB0byBwcmV2ZW50IG1lbW9yeSBpc3N1ZXNcbiAgICBpZiAodGhpcy5jYWNoZS5zaXplID4gMTAwKSB7XG4gICAgICAvLyBSZW1vdmUgb2xkZXN0IGVudHJpZXNcbiAgICAgIGNvbnN0IGVudHJpZXMgPSBBcnJheS5mcm9tKHRoaXMuY2FjaGUuZW50cmllcygpKTtcbiAgICAgIGVudHJpZXMuc29ydCgoYSwgYikgPT4gYVsxXS50aW1lc3RhbXAgLSBiWzFdLnRpbWVzdGFtcCk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDUwOyBpKyspIHtcbiAgICAgICAgdGhpcy5jYWNoZS5kZWxldGUoZW50cmllc1tpXVswXSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHRoaXMuY2FjaGUuc2V0KGtleSwge1xuICAgICAgZmlsZXMsXG4gICAgICB0aW1lc3RhbXA6IERhdGUubm93KClcbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIENsZWFyIHRoZSBjYWNoZVxuICAgKi9cbiAgc3RhdGljIGNsZWFyQ2FjaGUoKTogdm9pZCB7XG4gICAgdGhpcy5jYWNoZS5jbGVhcigpO1xuICAgIGxvZ2dlci5kZWJ1ZygnRmlsZSBkaXNjb3ZlcnkgY2FjaGUgY2xlYXJlZCcpO1xuICB9XG4gIFxuICAvKipcbiAgICogRmluZCBhIHNpbmdsZSBmaWxlIChjb252ZW5pZW5jZSBtZXRob2QpXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZmluZEZpbGUoXG4gICAgZGlyZWN0b3J5OiBzdHJpbmcsXG4gICAgc2VhcmNoTmFtZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBGaWxlU2VhcmNoT3B0aW9uc1xuICApOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgICBjb25zdCBmaWxlcyA9IGF3YWl0IHRoaXMuZmluZEZpbGVzKGRpcmVjdG9yeSwgc2VhcmNoTmFtZSwge1xuICAgICAgLi4ub3B0aW9ucyxcbiAgICAgIG1heFJlc3VsdHM6IDFcbiAgICB9KTtcbiAgICByZXR1cm4gZmlsZXMubGVuZ3RoID4gMCA/IGZpbGVzWzBdIDogbnVsbDtcbiAgfVxufSJdfQ==
@@ -0,0 +1,88 @@
1
+ /**
2
+ * GitHubRateLimiter - Specialized rate limiter for GitHub API calls
3
+ *
4
+ * Features:
5
+ * - Respects GitHub's authenticated (5000/hour) and unauthenticated (60/hour) limits
6
+ * - Client-side queuing when approaching limits
7
+ * - Request prioritization for critical operations
8
+ * - Comprehensive logging for quota management
9
+ * - Early termination when exact matches are found
10
+ */
11
+ import { RateLimitStatus } from './RateLimiter.js';
12
+ export interface GitHubRateLimitInfo {
13
+ limit: number;
14
+ remaining: number;
15
+ reset: Date;
16
+ used: number;
17
+ }
18
+ export interface GitHubApiRequest {
19
+ id: string;
20
+ operation: string;
21
+ priority: 'high' | 'normal' | 'low';
22
+ timestamp: number;
23
+ resolve: (value: any) => void;
24
+ reject: (error: any) => void;
25
+ }
26
+ export interface GitHubRateStatus extends RateLimitStatus {
27
+ queueLength: number;
28
+ currentLimit: number;
29
+ rateLimitInfo?: GitHubRateLimitInfo;
30
+ }
31
+ export declare class GitHubRateLimiter {
32
+ private rateLimiter;
33
+ private requestQueue;
34
+ private processing;
35
+ private lastRateLimitInfo?;
36
+ private isAuthenticated;
37
+ constructor();
38
+ /**
39
+ * Update rate limits based on current authentication status
40
+ */
41
+ private updateLimitsForAuthStatus;
42
+ /**
43
+ * Setup periodic check for rate limit status
44
+ */
45
+ private setupPeriodicStatusCheck;
46
+ /**
47
+ * Queue a GitHub API request with rate limiting
48
+ * @param operation Description of the operation
49
+ * @param apiCall Function that makes the actual API call
50
+ * @param priority Request priority (high, normal, low)
51
+ * @returns Promise that resolves with the API response
52
+ */
53
+ queueRequest<T>(operation: string, apiCall: () => Promise<T>, priority?: 'high' | 'normal' | 'low'): Promise<T>;
54
+ /**
55
+ * Add request to queue with priority ordering
56
+ */
57
+ private addToQueue;
58
+ /**
59
+ * Process the request queue
60
+ */
61
+ private processQueue;
62
+ /**
63
+ * Get current rate limit status
64
+ */
65
+ getStatus(): GitHubRateStatus;
66
+ /**
67
+ * Check if an error is a GitHub rate limit error
68
+ */
69
+ private isGitHubRateLimitError;
70
+ /**
71
+ * Handle GitHub rate limit error response
72
+ */
73
+ private handleGitHubRateLimit;
74
+ /**
75
+ * Log API usage for monitoring and diagnostics
76
+ */
77
+ private logApiUsage;
78
+ /**
79
+ * Clear the request queue (for testing or emergency situations)
80
+ */
81
+ clearQueue(): void;
82
+ /**
83
+ * Reset the rate limiter (for testing)
84
+ */
85
+ reset(): void;
86
+ }
87
+ export declare const githubRateLimiter: GitHubRateLimiter;
88
+ //# sourceMappingURL=GitHubRateLimiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHubRateLimiter.d.ts","sourceRoot":"","sources":["../../src/utils/GitHubRateLimiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAkC,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAOnF,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9B,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACrC;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,iBAAiB,CAAC,CAAsB;IAChD,OAAO,CAAC,eAAe,CAAS;;IAQhC;;OAEG;YACW,yBAAyB;IA2CvC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAShC;;;;;;OAMG;IACG,YAAY,CAAC,CAAC,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,QAAQ,GAAE,MAAM,GAAG,QAAQ,GAAG,KAAgB,GAC7C,OAAO,CAAC,CAAC,CAAC;IAwDb;;OAEG;IACH,OAAO,CAAC,UAAU;IAuBlB;;OAEG;YACW,YAAY;IA0C1B;;OAEG;IACH,SAAS,IAAI,gBAAgB;IAa7B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAM9B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA6C7B;;OAEG;IACH,OAAO,CAAC,WAAW;IA8BnB;;OAEG;IACH,UAAU,IAAI,IAAI;IAalB;;OAEG;IACH,KAAK,IAAI,IAAI;CAMd;AAGD,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}