@path58/n8n-mcp 0.1.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 (319) hide show
  1. package/AGENT_INSTALL.md +223 -0
  2. package/CHANGELOG.md +38 -0
  3. package/LICENSE +21 -0
  4. package/README.md +187 -0
  5. package/dist/autofix/suggestion-fixers/deprecated-node-fixer.js +465 -0
  6. package/dist/autofix/suggestion-fixers/deprecated-node-fixer.js.map +1 -0
  7. package/dist/autofix/suggestion-fixers/fixer-registry.js +495 -0
  8. package/dist/autofix/suggestion-fixers/fixer-registry.js.map +1 -0
  9. package/dist/autofix/suggestion-fixers/l1-structure-fixer.js +639 -0
  10. package/dist/autofix/suggestion-fixers/l1-structure-fixer.js.map +1 -0
  11. package/dist/autofix/suggestion-fixers/l4-connection-fixer.js +449 -0
  12. package/dist/autofix/suggestion-fixers/l4-connection-fixer.js.map +1 -0
  13. package/dist/autofix/suggestion-fixers/l5-parameter-fixer.js +575 -0
  14. package/dist/autofix/suggestion-fixers/l5-parameter-fixer.js.map +1 -0
  15. package/dist/autofix/suggestion-fixers/l5-typeversion-fixer.js +431 -0
  16. package/dist/autofix/suggestion-fixers/l5-typeversion-fixer.js.map +1 -0
  17. package/dist/autofix/suggestion-fixers/l5-webhook-path-fixer.js +356 -0
  18. package/dist/autofix/suggestion-fixers/l5-webhook-path-fixer.js.map +1 -0
  19. package/dist/autofix/suggestion-fixers/l6-ai-tool-variant-fixer.js +618 -0
  20. package/dist/autofix/suggestion-fixers/l6-ai-tool-variant-fixer.js.map +1 -0
  21. package/dist/autofix/suggestion-fixers/l6-pattern-fixer.js +1475 -0
  22. package/dist/autofix/suggestion-fixers/l6-pattern-fixer.js.map +1 -0
  23. package/dist/autofix/suggestion-fixers/llm-fixer.js +716 -0
  24. package/dist/autofix/suggestion-fixers/llm-fixer.js.map +1 -0
  25. package/dist/autofix/suggestion-fixers/missing-credential-fixer.js +336 -0
  26. package/dist/autofix/suggestion-fixers/missing-credential-fixer.js.map +1 -0
  27. package/dist/autofix/suggestion-fixers/types.js +29 -0
  28. package/dist/autofix/suggestion-fixers/types.js.map +1 -0
  29. package/dist/autofix/suggestion-fixers/typo-fixer.js +197 -0
  30. package/dist/autofix/suggestion-fixers/typo-fixer.js.map +1 -0
  31. package/dist/classification/certification-engine.js +208 -0
  32. package/dist/classification/certification-engine.js.map +1 -0
  33. package/dist/classification/feedback-collector.js +516 -0
  34. package/dist/classification/feedback-collector.js.map +1 -0
  35. package/dist/classification/l5-parameter-analyzer.js +670 -0
  36. package/dist/classification/l5-parameter-analyzer.js.map +1 -0
  37. package/dist/classification/l6-graph-analyzer.js +613 -0
  38. package/dist/classification/l6-graph-analyzer.js.map +1 -0
  39. package/dist/classification/severity-classifier.js +237 -0
  40. package/dist/classification/severity-classifier.js.map +1 -0
  41. package/dist/config/env.js +280 -0
  42. package/dist/config/env.js.map +1 -0
  43. package/dist/config/env.schema.js +234 -0
  44. package/dist/config/env.schema.js.map +1 -0
  45. package/dist/config/scraperEnv.js +55 -0
  46. package/dist/config/scraperEnv.js.map +1 -0
  47. package/dist/db/postgresClient.js +38 -0
  48. package/dist/db/postgresClient.js.map +1 -0
  49. package/dist/db/scraperDb.js +6 -0
  50. package/dist/db/scraperDb.js.map +1 -0
  51. package/dist/db/scraperPostgresClient.js +118 -0
  52. package/dist/db/scraperPostgresClient.js.map +1 -0
  53. package/dist/db/validationRepository.js +55 -0
  54. package/dist/db/validationRepository.js.map +1 -0
  55. package/dist/db/validatorPostgresClient.js +248 -0
  56. package/dist/db/validatorPostgresClient.js.map +1 -0
  57. package/dist/db/workflowInstanceMappingRepository.js +128 -0
  58. package/dist/db/workflowInstanceMappingRepository.js.map +1 -0
  59. package/dist/errors/AppError.js +156 -0
  60. package/dist/errors/AppError.js.map +1 -0
  61. package/dist/errors/index.js +7 -0
  62. package/dist/errors/index.js.map +1 -0
  63. package/dist/factory/error-to-problem-mappers.js +385 -0
  64. package/dist/factory/error-to-problem-mappers.js.map +1 -0
  65. package/dist/factory/gap-recorder.js +260 -0
  66. package/dist/factory/gap-recorder.js.map +1 -0
  67. package/dist/factory/problem-recorder.js +94 -0
  68. package/dist/factory/problem-recorder.js.map +1 -0
  69. package/dist/factory/warning-to-gap-mappers.js +493 -0
  70. package/dist/factory/warning-to-gap-mappers.js.map +1 -0
  71. package/dist/factory/workflow-normalizer.js +247 -0
  72. package/dist/factory/workflow-normalizer.js.map +1 -0
  73. package/dist/mcp/adapters/catalog.js +13 -0
  74. package/dist/mcp/adapters/catalog.js.map +1 -0
  75. package/dist/mcp/adapters/index.js +36 -0
  76. package/dist/mcp/adapters/index.js.map +1 -0
  77. package/dist/mcp/adapters/supabase-catalog.js +467 -0
  78. package/dist/mcp/adapters/supabase-catalog.js.map +1 -0
  79. package/dist/mcp/adapters/test-catalog-adapter.js +100 -0
  80. package/dist/mcp/adapters/test-catalog-adapter.js.map +1 -0
  81. package/dist/mcp/adapters/validation.js +258 -0
  82. package/dist/mcp/adapters/validation.js.map +1 -0
  83. package/dist/mcp/build-email-workflow.js +113 -0
  84. package/dist/mcp/build-email-workflow.js.map +1 -0
  85. package/dist/mcp/config.js +22 -0
  86. package/dist/mcp/config.js.map +1 -0
  87. package/dist/mcp/formatters/errors.js +217 -0
  88. package/dist/mcp/formatters/errors.js.map +1 -0
  89. package/dist/mcp/formatters/index.js +12 -0
  90. package/dist/mcp/formatters/index.js.map +1 -0
  91. package/dist/mcp/formatters/response.js +141 -0
  92. package/dist/mcp/formatters/response.js.map +1 -0
  93. package/dist/mcp/quick-test.js +33 -0
  94. package/dist/mcp/quick-test.js.map +1 -0
  95. package/dist/mcp/server.js +70 -0
  96. package/dist/mcp/server.js.map +1 -0
  97. package/dist/mcp/test-mcp-error.js +81 -0
  98. package/dist/mcp/test-mcp-error.js.map +1 -0
  99. package/dist/mcp/test-mcp.js +80 -0
  100. package/dist/mcp/test-mcp.js.map +1 -0
  101. package/dist/mcp/tools/fixes/expression-fixes.js +166 -0
  102. package/dist/mcp/tools/fixes/expression-fixes.js.map +1 -0
  103. package/dist/mcp/tools/fixes/flow-fixes.js +155 -0
  104. package/dist/mcp/tools/fixes/flow-fixes.js.map +1 -0
  105. package/dist/mcp/tools/fixes/index.js +91 -0
  106. package/dist/mcp/tools/fixes/index.js.map +1 -0
  107. package/dist/mcp/tools/fixes/node-fixes.js +233 -0
  108. package/dist/mcp/tools/fixes/node-fixes.js.map +1 -0
  109. package/dist/mcp/tools/fixes/parameter-fixes.js +277 -0
  110. package/dist/mcp/tools/fixes/parameter-fixes.js.map +1 -0
  111. package/dist/mcp/tools/fixes/types.js +10 -0
  112. package/dist/mcp/tools/fixes/types.js.map +1 -0
  113. package/dist/mcp/tools/handlers/check-parameter.js +300 -0
  114. package/dist/mcp/tools/handlers/check-parameter.js.map +1 -0
  115. package/dist/mcp/tools/handlers/find-similar-pattern.js +121 -0
  116. package/dist/mcp/tools/handlers/find-similar-pattern.js.map +1 -0
  117. package/dist/mcp/tools/handlers/get-node-info.js +131 -0
  118. package/dist/mcp/tools/handlers/get-node-info.js.map +1 -0
  119. package/dist/mcp/tools/handlers/get-operation-schema.js +141 -0
  120. package/dist/mcp/tools/handlers/get-operation-schema.js.map +1 -0
  121. package/dist/mcp/tools/handlers/list-nodes.js +126 -0
  122. package/dist/mcp/tools/handlers/list-nodes.js.map +1 -0
  123. package/dist/mcp/tools/handlers/list-operations.js +138 -0
  124. package/dist/mcp/tools/handlers/list-operations.js.map +1 -0
  125. package/dist/mcp/tools/handlers/suggest-fix.js +120 -0
  126. package/dist/mcp/tools/handlers/suggest-fix.js.map +1 -0
  127. package/dist/mcp/tools/handlers/validate-workflow.js +92 -0
  128. package/dist/mcp/tools/handlers/validate-workflow.js.map +1 -0
  129. package/dist/mcp/tools/index.js +190 -0
  130. package/dist/mcp/tools/index.js.map +1 -0
  131. package/dist/mcp/tools/schemas.js +195 -0
  132. package/dist/mcp/tools/schemas.js.map +1 -0
  133. package/dist/mcp/tools/validate.js +95 -0
  134. package/dist/mcp/tools/validate.js.map +1 -0
  135. package/dist/mcp/types/mcp.js +7 -0
  136. package/dist/mcp/types/mcp.js.map +1 -0
  137. package/dist/mcp/utils/timeout.js +78 -0
  138. package/dist/mcp/utils/timeout.js.map +1 -0
  139. package/dist/services/BatchProcessor.js +433 -0
  140. package/dist/services/BatchProcessor.js.map +1 -0
  141. package/dist/services/CheckpointManager.js +281 -0
  142. package/dist/services/CheckpointManager.js.map +1 -0
  143. package/dist/services/CostCalculator.js +211 -0
  144. package/dist/services/CostCalculator.js.map +1 -0
  145. package/dist/services/EmbeddingCache.js +68 -0
  146. package/dist/services/EmbeddingCache.js.map +1 -0
  147. package/dist/services/EmbeddingService.js +143 -0
  148. package/dist/services/EmbeddingService.js.map +1 -0
  149. package/dist/services/RankingService.js +81 -0
  150. package/dist/services/RankingService.js.map +1 -0
  151. package/dist/services/RedisCache.js +376 -0
  152. package/dist/services/RedisCache.js.map +1 -0
  153. package/dist/services/RedisCatalogCache.js +680 -0
  154. package/dist/services/RedisCatalogCache.js.map +1 -0
  155. package/dist/services/ResumeManager.js +252 -0
  156. package/dist/services/ResumeManager.js.map +1 -0
  157. package/dist/services/SearchService.js +282 -0
  158. package/dist/services/SearchService.js.map +1 -0
  159. package/dist/services/SemanticCatalogSearch.js +405 -0
  160. package/dist/services/SemanticCatalogSearch.js.map +1 -0
  161. package/dist/services/ValidationCache.js +157 -0
  162. package/dist/services/ValidationCache.js.map +1 -0
  163. package/dist/services/WorkflowPipelineService.js +1997 -0
  164. package/dist/services/WorkflowPipelineService.js.map +1 -0
  165. package/dist/services/catalog/index.js +34 -0
  166. package/dist/services/catalog/index.js.map +1 -0
  167. package/dist/services/catalog/interfaces.js +17 -0
  168. package/dist/services/catalog/interfaces.js.map +1 -0
  169. package/dist/services/catalog/loaders.js +169 -0
  170. package/dist/services/catalog/loaders.js.map +1 -0
  171. package/dist/services/catalog/types.js +138 -0
  172. package/dist/services/catalog/types.js.map +1 -0
  173. package/dist/services/documentation-normalization/docUrlUtils.js +88 -0
  174. package/dist/services/documentation-normalization/docUrlUtils.js.map +1 -0
  175. package/dist/services/error-quality/ErrorQualityService.js +262 -0
  176. package/dist/services/error-quality/ErrorQualityService.js.map +1 -0
  177. package/dist/services/error-quality/analyzers/CredentialAnalyzer.js +260 -0
  178. package/dist/services/error-quality/analyzers/CredentialAnalyzer.js.map +1 -0
  179. package/dist/services/error-quality/analyzers/IssuePredictor.js +380 -0
  180. package/dist/services/error-quality/analyzers/IssuePredictor.js.map +1 -0
  181. package/dist/services/error-quality/analyzers/MockCoverageAnalyzer.js +267 -0
  182. package/dist/services/error-quality/analyzers/MockCoverageAnalyzer.js.map +1 -0
  183. package/dist/services/error-quality/data/ErrorPatternSeeder.js +963 -0
  184. package/dist/services/error-quality/data/ErrorPatternSeeder.js.map +1 -0
  185. package/dist/services/error-quality/index.js +25 -0
  186. package/dist/services/error-quality/index.js.map +1 -0
  187. package/dist/services/error-quality/reports/ReportGenerator.js +343 -0
  188. package/dist/services/error-quality/reports/ReportGenerator.js.map +1 -0
  189. package/dist/services/error-quality/taxonomy/ErrorTaxonomy.js +698 -0
  190. package/dist/services/error-quality/taxonomy/ErrorTaxonomy.js.map +1 -0
  191. package/dist/services/error-quality/types.js +11 -0
  192. package/dist/services/error-quality/types.js.map +1 -0
  193. package/dist/services/progress/ProgressTracker.js +288 -0
  194. package/dist/services/progress/ProgressTracker.js.map +1 -0
  195. package/dist/services/progress/formatters.js +122 -0
  196. package/dist/services/progress/formatters.js.map +1 -0
  197. package/dist/services/progress/index.js +36 -0
  198. package/dist/services/progress/index.js.map +1 -0
  199. package/dist/services/progress/types.js +7 -0
  200. package/dist/services/progress/types.js.map +1 -0
  201. package/dist/services/search/embeddingGenerator.js +112 -0
  202. package/dist/services/search/embeddingGenerator.js.map +1 -0
  203. package/dist/types/aiCapabilities.js +7 -0
  204. package/dist/types/aiCapabilities.js.map +1 -0
  205. package/dist/types/aiConfigSchema.js +7 -0
  206. package/dist/types/aiConfigSchema.js.map +1 -0
  207. package/dist/utils/bannerLogger.js +186 -0
  208. package/dist/utils/bannerLogger.js.map +1 -0
  209. package/dist/utils/bannerService.js +23 -0
  210. package/dist/utils/bannerService.js.map +1 -0
  211. package/dist/utils/bannerServiceAdapter.js +54 -0
  212. package/dist/utils/bannerServiceAdapter.js.map +1 -0
  213. package/dist/utils/batchLogger.js +171 -0
  214. package/dist/utils/batchLogger.js.map +1 -0
  215. package/dist/utils/bottomStickyBanner.js +239 -0
  216. package/dist/utils/bottomStickyBanner.js.map +1 -0
  217. package/dist/utils/credentialMatcher.js +206 -0
  218. package/dist/utils/credentialMatcher.js.map +1 -0
  219. package/dist/utils/credentialNormalizer.js +442 -0
  220. package/dist/utils/credentialNormalizer.js.map +1 -0
  221. package/dist/utils/integratedBannerLogger.js +59 -0
  222. package/dist/utils/integratedBannerLogger.js.map +1 -0
  223. package/dist/utils/n8nSourceGit.js +195 -0
  224. package/dist/utils/n8nSourceGit.js.map +1 -0
  225. package/dist/utils/nodeTypeNormalizer.js +131 -0
  226. package/dist/utils/nodeTypeNormalizer.js.map +1 -0
  227. package/dist/utils/openaiClient.js +397 -0
  228. package/dist/utils/openaiClient.js.map +1 -0
  229. package/dist/utils/productionLogger.js +16 -0
  230. package/dist/utils/productionLogger.js.map +1 -0
  231. package/dist/utils/progressBarBanner.js +132 -0
  232. package/dist/utils/progressBarBanner.js.map +1 -0
  233. package/dist/utils/scriptHeartbeat.js +117 -0
  234. package/dist/utils/scriptHeartbeat.js.map +1 -0
  235. package/dist/utils/scriptLogger.js +125 -0
  236. package/dist/utils/scriptLogger.js.map +1 -0
  237. package/dist/utils/scriptRunner.js +95 -0
  238. package/dist/utils/scriptRunner.js.map +1 -0
  239. package/dist/utils/scriptTimeout.js +128 -0
  240. package/dist/utils/scriptTimeout.js.map +1 -0
  241. package/dist/utils/scriptWrapper.js +219 -0
  242. package/dist/utils/scriptWrapper.js.map +1 -0
  243. package/dist/utils/stickyBanner.js +226 -0
  244. package/dist/utils/stickyBanner.js.map +1 -0
  245. package/dist/utils/terminalSpinner.js +97 -0
  246. package/dist/utils/terminalSpinner.js.map +1 -0
  247. package/dist/utils/threeLineBanner.js +427 -0
  248. package/dist/utils/threeLineBanner.js.map +1 -0
  249. package/dist/utils/validatorCheckpointManager.js +170 -0
  250. package/dist/utils/validatorCheckpointManager.js.map +1 -0
  251. package/dist/utils/validatorConnectionManager.js +124 -0
  252. package/dist/utils/validatorConnectionManager.js.map +1 -0
  253. package/dist/validation/catalog.js +56 -0
  254. package/dist/validation/catalog.js.map +1 -0
  255. package/dist/validation/config/deprecated-nodes.js +234 -0
  256. package/dist/validation/config/deprecated-nodes.js.map +1 -0
  257. package/dist/validation/config/l6-severity.js +227 -0
  258. package/dist/validation/config/l6-severity.js.map +1 -0
  259. package/dist/validation/config/terminal-nodes.js +132 -0
  260. package/dist/validation/config/terminal-nodes.js.map +1 -0
  261. package/dist/validation/config/unreachable-nodes.js +67 -0
  262. package/dist/validation/config/unreachable-nodes.js.map +1 -0
  263. package/dist/validation/core.js +47 -0
  264. package/dist/validation/core.js.map +1 -0
  265. package/dist/validation/docExtraction.js +12 -0
  266. package/dist/validation/docExtraction.js.map +1 -0
  267. package/dist/validation/dryRunMockRunner.js +128 -0
  268. package/dist/validation/dryRunMockRunner.js.map +1 -0
  269. package/dist/validation/fixtureEngine.js +61 -0
  270. package/dist/validation/fixtureEngine.js.map +1 -0
  271. package/dist/validation/index.js +15 -0
  272. package/dist/validation/index.js.map +1 -0
  273. package/dist/validation/k-levels/k2-blockers.js +222 -0
  274. package/dist/validation/k-levels/k2-blockers.js.map +1 -0
  275. package/dist/validation/l1-structure.js +296 -0
  276. package/dist/validation/l1-structure.js.map +1 -0
  277. package/dist/validation/l2-nodes.js +282 -0
  278. package/dist/validation/l2-nodes.js.map +1 -0
  279. package/dist/validation/l3-credentials.js +322 -0
  280. package/dist/validation/l3-credentials.js.map +1 -0
  281. package/dist/validation/l4-connections.js +698 -0
  282. package/dist/validation/l4-connections.js.map +1 -0
  283. package/dist/validation/l5-parameters.js +803 -0
  284. package/dist/validation/l5-parameters.js.map +1 -0
  285. package/dist/validation/l6-checks/ai-tool-variants.js +407 -0
  286. package/dist/validation/l6-checks/ai-tool-variants.js.map +1 -0
  287. package/dist/validation/l6-checks/catalog-checks.js +260 -0
  288. package/dist/validation/l6-checks/catalog-checks.js.map +1 -0
  289. package/dist/validation/l6-checks/data-contracts.js +197 -0
  290. package/dist/validation/l6-checks/data-contracts.js.map +1 -0
  291. package/dist/validation/l6-checks/deprecation.js +133 -0
  292. package/dist/validation/l6-checks/deprecation.js.map +1 -0
  293. package/dist/validation/l6-checks/error-handling.js +193 -0
  294. package/dist/validation/l6-checks/error-handling.js.map +1 -0
  295. package/dist/validation/l6-checks/expression-syntax.js +387 -0
  296. package/dist/validation/l6-checks/expression-syntax.js.map +1 -0
  297. package/dist/validation/l6-checks/flow-integrity.js +504 -0
  298. package/dist/validation/l6-checks/flow-integrity.js.map +1 -0
  299. package/dist/validation/l6-checks/index.js +106 -0
  300. package/dist/validation/l6-checks/index.js.map +1 -0
  301. package/dist/validation/l6-checks/loops.js +370 -0
  302. package/dist/validation/l6-checks/loops.js.map +1 -0
  303. package/dist/validation/l6-checks/performance.js +182 -0
  304. package/dist/validation/l6-checks/performance.js.map +1 -0
  305. package/dist/validation/l6-checks/security.js +273 -0
  306. package/dist/validation/l6-checks/security.js.map +1 -0
  307. package/dist/validation/l6-patterns.js +472 -0
  308. package/dist/validation/l6-patterns.js.map +1 -0
  309. package/dist/validation/mockLevelResolver.js +95 -0
  310. package/dist/validation/mockLevelResolver.js.map +1 -0
  311. package/dist/validation/n8nApiClient.js +21 -0
  312. package/dist/validation/n8nApiClient.js.map +1 -0
  313. package/dist/validation/n8nCli.js +87 -0
  314. package/dist/validation/n8nCli.js.map +1 -0
  315. package/dist/validation/types.js +8 -0
  316. package/dist/validation/types.js.map +1 -0
  317. package/dist/validation/usageStats.js +82 -0
  318. package/dist/validation/usageStats.js.map +1 -0
  319. package/package.json +274 -0
@@ -0,0 +1,405 @@
1
+ /**
2
+ * Semantic Catalog Search Service
3
+ *
4
+ * Provides semantic similarity search across the bluelime catalog using
5
+ * pre-computed embeddings (77,958 vectors) and pgvector for similarity queries.
6
+ *
7
+ * Features:
8
+ * - Search nodes, operations, parameters, and credentials semantically
9
+ * - Redis caching for search results (1h TTL)
10
+ * - Graceful fallback when Redis unavailable
11
+ * - Uses existing bluelime.search_*_multi() database functions
12
+ *
13
+ * @module services/SemanticCatalogSearch
14
+ */
15
+ import OpenAI from 'openai';
16
+ import Redis from 'ioredis';
17
+ import { logger } from '@tsvika58/shared-utilities/logging';
18
+ import { validatorQuery } from '../db/validatorPostgresClient.js';
19
+ import { generateQueryEmbedding, hashQuery, normalizeQueryText, } from './search/embeddingGenerator.js';
20
+ /** Default TTL for search result cache (1 hour) */
21
+ const DEFAULT_CACHE_TTL_SECONDS = 3600;
22
+ /** Redis key prefix for semantic search results */
23
+ const CACHE_PREFIX = 'semantic:';
24
+ /**
25
+ * SemanticCatalogSearch provides semantic similarity search across the
26
+ * bluelime catalog using pre-computed embeddings.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const search = new SemanticCatalogSearch();
31
+ * await search.initialize();
32
+ *
33
+ * // Find nodes similar to "send email"
34
+ * const nodes = await search.searchNodes('send email', 5);
35
+ * console.log(nodes[0].nodeType); // e.g., 'n8n-nodes-base.gmail'
36
+ *
37
+ * // Get suggestions for typo correction
38
+ * const suggestions = await search.searchNodes('httpRequst');
39
+ * console.log(suggestions[0].nodeType); // 'n8n-nodes-base.httpRequest'
40
+ * ```
41
+ */
42
+ export class SemanticCatalogSearch {
43
+ openai;
44
+ redis = null;
45
+ dbQuery;
46
+ cacheTtl;
47
+ minSimilarity;
48
+ isRedisConnected = false;
49
+ stats = {
50
+ cacheHits: 0,
51
+ cacheMisses: 0,
52
+ totalSearches: 0,
53
+ totalLatencyMs: 0,
54
+ };
55
+ /**
56
+ * Create a new SemanticCatalogSearch instance.
57
+ *
58
+ * @param config - Configuration options
59
+ * @param deps - Optional dependencies for testing
60
+ */
61
+ constructor(config, deps) {
62
+ // Use injected dependencies or create defaults
63
+ if (deps) {
64
+ this.openai = deps.openai;
65
+ this.dbQuery = deps.dbQuery;
66
+ this.redis = deps.redis ?? null;
67
+ this.isRedisConnected = deps.redis !== null && deps.redis !== undefined;
68
+ }
69
+ else {
70
+ const apiKey = config?.openaiApiKey || process.env.OPENAI_API_KEY;
71
+ if (!apiKey) {
72
+ throw new Error('OpenAI API key required: set OPENAI_API_KEY or pass openaiApiKey in config');
73
+ }
74
+ this.openai = new OpenAI({ apiKey });
75
+ this.dbQuery = validatorQuery;
76
+ }
77
+ this.cacheTtl = config?.cacheTtlSeconds ?? DEFAULT_CACHE_TTL_SECONDS;
78
+ this.minSimilarity = config?.minSimilarity ?? 0.5;
79
+ }
80
+ /**
81
+ * Initialize the service and connect to Redis.
82
+ * Must be called before using search methods when not using injected dependencies.
83
+ */
84
+ async initialize() {
85
+ if (this.redis) {
86
+ return; // Already initialized via deps
87
+ }
88
+ const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379';
89
+ try {
90
+ this.redis = new Redis(redisUrl, {
91
+ maxRetriesPerRequest: 3,
92
+ connectTimeout: 5000,
93
+ retryStrategy: (times) => {
94
+ if (times > 3)
95
+ return null;
96
+ return Math.min(times * 100, 2000);
97
+ },
98
+ enableReadyCheck: true,
99
+ });
100
+ await new Promise((resolve, reject) => {
101
+ const timeout = setTimeout(() => {
102
+ reject(new Error('Redis connection timeout'));
103
+ }, 5000);
104
+ this.redis.on('ready', () => {
105
+ clearTimeout(timeout);
106
+ this.isRedisConnected = true;
107
+ resolve();
108
+ });
109
+ this.redis.on('error', (err) => {
110
+ clearTimeout(timeout);
111
+ reject(err);
112
+ });
113
+ });
114
+ await this.redis.ping();
115
+ this.isRedisConnected = true;
116
+ }
117
+ catch {
118
+ if (this.redis) {
119
+ await this.redis.quit().catch((err) => {
120
+ logger.debug('Redis quit failed during connection cleanup', { error: err.message });
121
+ });
122
+ }
123
+ this.redis = null;
124
+ this.isRedisConnected = false;
125
+ }
126
+ }
127
+ /**
128
+ * Search for nodes semantically similar to the query.
129
+ *
130
+ * @param query - Search query (e.g., "send email", "make http request")
131
+ * @param limit - Maximum results to return (default: 5)
132
+ * @returns Array of matching nodes with similarity scores
133
+ */
134
+ async searchNodes(query, limit = 5) {
135
+ const cacheKey = this.getCacheKey('nodes', query);
136
+ const cached = await this.getFromCache(cacheKey);
137
+ if (cached) {
138
+ return cached.slice(0, limit);
139
+ }
140
+ const startTime = performance.now();
141
+ const embedding = await this.getEmbedding(query);
142
+ const result = await this.dbQuery(`SELECT node_type, name, category, is_trigger,
143
+ 1 - (embedding <=> $1::vector) as similarity
144
+ FROM bluelime.nodes
145
+ WHERE embedding IS NOT NULL
146
+ ORDER BY embedding <=> $1::vector
147
+ LIMIT $2`, [`[${embedding.join(',')}]`, limit * 2]);
148
+ const matches = result.rows
149
+ .filter((row) => row.similarity >= this.minSimilarity)
150
+ .map((row) => ({
151
+ nodeType: row.node_type,
152
+ name: row.name,
153
+ category: row.category,
154
+ isTrigger: row.is_trigger,
155
+ similarity: row.similarity,
156
+ }));
157
+ await this.setCache(cacheKey, matches);
158
+ this.recordSearchLatency(startTime);
159
+ return matches.slice(0, limit);
160
+ }
161
+ /**
162
+ * Search for operations semantically similar to the query.
163
+ *
164
+ * @param query - Search query (e.g., "send message", "create record")
165
+ * @param nodeType - Optional node type to filter by
166
+ * @param limit - Maximum results to return (default: 5)
167
+ * @returns Array of matching operations with similarity scores
168
+ */
169
+ async searchOperations(query, nodeType, limit = 5) {
170
+ const cacheKey = this.getCacheKey('operations', query, nodeType);
171
+ const cached = await this.getFromCache(cacheKey);
172
+ if (cached) {
173
+ return cached.slice(0, limit);
174
+ }
175
+ const startTime = performance.now();
176
+ const embedding = await this.getEmbedding(query);
177
+ let sql = `
178
+ SELECT o.id, n.node_type, o.display_name as operation_name,
179
+ o.operation as operation_value, o.description,
180
+ 1 - (o.embedding <=> $1::vector) as similarity
181
+ FROM bluelime.operations o
182
+ JOIN bluelime.nodes n ON o.node_id = n.id
183
+ WHERE o.embedding IS NOT NULL
184
+ `;
185
+ const params = [`[${embedding.join(',')}]`];
186
+ if (nodeType) {
187
+ sql += ` AND LOWER(n.node_type) = LOWER($2)`;
188
+ params.push(nodeType);
189
+ }
190
+ sql += ` ORDER BY o.embedding <=> $1::vector LIMIT $${params.length + 1}`;
191
+ params.push(limit * 2);
192
+ const result = await this.dbQuery(sql, params);
193
+ const matches = result.rows
194
+ .filter((row) => row.similarity >= this.minSimilarity)
195
+ .map((row) => ({
196
+ id: row.id,
197
+ nodeType: row.node_type,
198
+ operationName: row.operation_name,
199
+ operationValue: row.operation_value,
200
+ description: row.description,
201
+ similarity: row.similarity,
202
+ }));
203
+ await this.setCache(cacheKey, matches);
204
+ this.recordSearchLatency(startTime);
205
+ return matches.slice(0, limit);
206
+ }
207
+ /**
208
+ * Search for parameters semantically similar to the query.
209
+ *
210
+ * @param query - Search query (e.g., "recipient email", "message body")
211
+ * @param operationId - Optional operation ID to filter by
212
+ * @param limit - Maximum results to return (default: 5)
213
+ * @returns Array of matching parameters with similarity scores
214
+ */
215
+ async searchParameters(query, operationId, limit = 5) {
216
+ const cacheKey = this.getCacheKey('parameters', query, operationId?.toString());
217
+ const cached = await this.getFromCache(cacheKey);
218
+ if (cached) {
219
+ return cached.slice(0, limit);
220
+ }
221
+ const startTime = performance.now();
222
+ const embedding = await this.getEmbedding(query);
223
+ let sql = `
224
+ SELECT id, operation_id, parameter_name, parameter_type, is_required,
225
+ 1 - (embedding <=> $1::vector) as similarity
226
+ FROM bluelime.parameters
227
+ WHERE embedding IS NOT NULL
228
+ `;
229
+ const params = [`[${embedding.join(',')}]`];
230
+ if (operationId !== undefined) {
231
+ sql += ` AND operation_id = $2`;
232
+ params.push(operationId);
233
+ }
234
+ sql += ` ORDER BY embedding <=> $1::vector LIMIT $${params.length + 1}`;
235
+ params.push(limit * 2);
236
+ const result = await this.dbQuery(sql, params);
237
+ const matches = result.rows
238
+ .filter((row) => row.similarity >= this.minSimilarity)
239
+ .map((row) => ({
240
+ id: row.id,
241
+ operationId: row.operation_id,
242
+ parameterName: row.parameter_name,
243
+ parameterType: row.parameter_type,
244
+ isRequired: row.is_required,
245
+ similarity: row.similarity,
246
+ }));
247
+ await this.setCache(cacheKey, matches);
248
+ this.recordSearchLatency(startTime);
249
+ return matches.slice(0, limit);
250
+ }
251
+ /**
252
+ * Search for credentials semantically similar to the query.
253
+ *
254
+ * @param query - Search query (e.g., "google oauth", "api key")
255
+ * @param limit - Maximum results to return (default: 5)
256
+ * @returns Array of matching credentials with similarity scores
257
+ */
258
+ async searchCredentials(query, limit = 5) {
259
+ const cacheKey = this.getCacheKey('credentials', query);
260
+ const cached = await this.getFromCache(cacheKey);
261
+ if (cached) {
262
+ return cached.slice(0, limit);
263
+ }
264
+ const startTime = performance.now();
265
+ const embedding = await this.getEmbedding(query);
266
+ const result = await this.dbQuery(`SELECT credential_type, name, auth_type, is_oauth,
267
+ 1 - (embedding <=> $1::vector) as similarity
268
+ FROM bluelime.credentials
269
+ WHERE embedding IS NOT NULL
270
+ ORDER BY embedding <=> $1::vector
271
+ LIMIT $2`, [`[${embedding.join(',')}]`, limit * 2]);
272
+ const matches = result.rows
273
+ .filter((row) => row.similarity >= this.minSimilarity)
274
+ .map((row) => ({
275
+ credentialType: row.credential_type,
276
+ name: row.name,
277
+ authType: row.auth_type,
278
+ isOauth: row.is_oauth,
279
+ similarity: row.similarity,
280
+ }));
281
+ await this.setCache(cacheKey, matches);
282
+ this.recordSearchLatency(startTime);
283
+ return matches.slice(0, limit);
284
+ }
285
+ /**
286
+ * Get search statistics.
287
+ */
288
+ getStats() {
289
+ return {
290
+ cacheHits: this.stats.cacheHits,
291
+ cacheMisses: this.stats.cacheMisses,
292
+ redisConnected: this.isRedisConnected,
293
+ avgSearchLatencyMs: this.stats.totalSearches > 0
294
+ ? Math.round(this.stats.totalLatencyMs / this.stats.totalSearches)
295
+ : 0,
296
+ };
297
+ }
298
+ /**
299
+ * Clear all search caches.
300
+ */
301
+ async clearCache() {
302
+ if (!this.redis || !this.isRedisConnected) {
303
+ return;
304
+ }
305
+ try {
306
+ const keys = await this.redis.keys(`${CACHE_PREFIX}*`);
307
+ if (keys.length > 0) {
308
+ await this.redis.del(...keys);
309
+ }
310
+ }
311
+ catch {
312
+ // Ignore cache clear errors
313
+ }
314
+ }
315
+ /**
316
+ * Dispose of resources (close Redis connection).
317
+ */
318
+ async dispose() {
319
+ if (this.redis) {
320
+ await this.redis.quit().catch((err) => {
321
+ logger.debug('Redis quit failed during dispose', { error: err.message });
322
+ });
323
+ this.redis = null;
324
+ this.isRedisConnected = false;
325
+ }
326
+ }
327
+ // ============================================================
328
+ // Private Methods
329
+ // ============================================================
330
+ async getEmbedding(query) {
331
+ const result = await generateQueryEmbedding(query, this.openai);
332
+ return result.embedding;
333
+ }
334
+ getCacheKey(type, query, filter) {
335
+ const normalizedQuery = normalizeQueryText(query);
336
+ const queryHash = hashQuery(normalizedQuery);
337
+ return filter
338
+ ? `${CACHE_PREFIX}${type}:${filter}:${queryHash}`
339
+ : `${CACHE_PREFIX}${type}:${queryHash}`;
340
+ }
341
+ async getFromCache(key) {
342
+ if (!this.redis || !this.isRedisConnected) {
343
+ this.stats.cacheMisses++;
344
+ return null;
345
+ }
346
+ try {
347
+ const cached = await this.redis.get(key);
348
+ if (cached) {
349
+ this.stats.cacheHits++;
350
+ return JSON.parse(cached);
351
+ }
352
+ }
353
+ catch {
354
+ // Fall through to miss
355
+ }
356
+ this.stats.cacheMisses++;
357
+ return null;
358
+ }
359
+ async setCache(key, value) {
360
+ if (!this.redis || !this.isRedisConnected) {
361
+ return;
362
+ }
363
+ try {
364
+ await this.redis.setex(key, this.cacheTtl, JSON.stringify(value));
365
+ }
366
+ catch {
367
+ // Ignore cache set errors
368
+ }
369
+ }
370
+ recordSearchLatency(startTime) {
371
+ this.stats.totalSearches++;
372
+ this.stats.totalLatencyMs += performance.now() - startTime;
373
+ }
374
+ }
375
+ /** Singleton instance for shared use */
376
+ let instance = null;
377
+ /**
378
+ * Get or create the singleton SemanticCatalogSearch instance.
379
+ */
380
+ export function getSemanticCatalogSearch(config) {
381
+ if (!instance) {
382
+ instance = new SemanticCatalogSearch(config);
383
+ }
384
+ return instance;
385
+ }
386
+ /**
387
+ * Initialize and return the singleton instance.
388
+ */
389
+ export async function initSemanticCatalogSearch(config) {
390
+ const search = getSemanticCatalogSearch(config);
391
+ await search.initialize();
392
+ return search;
393
+ }
394
+ /**
395
+ * Reset the singleton instance (for testing).
396
+ */
397
+ export function resetSemanticCatalogSearch() {
398
+ if (instance) {
399
+ instance.dispose().catch((err) => {
400
+ logger.debug('Dispose failed during reset', { error: err.message });
401
+ });
402
+ instance = null;
403
+ }
404
+ }
405
+ //# sourceMappingURL=SemanticCatalogSearch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SemanticCatalogSearch.js","sourceRoot":"","sources":["../../src/services/SemanticCatalogSearch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Validation Cache Service
3
+ * ------------------------
4
+ *
5
+ * Caches validation results to avoid redundant database queries.
6
+ * Uses Redis when available, falls back to in-memory cache.
7
+ *
8
+ * RAG-2.2.7: Unified Validation Service (Database + Redis)
9
+ * Created: January 1, 2026
10
+ * Based on: EmbeddingCache.ts pattern
11
+ */
12
+ import NodeCache from 'node-cache';
13
+ import { logger } from '@tsvika58/shared-utilities/logging';
14
+ import { RedisCache } from './RedisCache.js';
15
+ /**
16
+ * In-memory cache fallback
17
+ */
18
+ class MemoryValidationCache {
19
+ cache;
20
+ constructor() {
21
+ const ttl = process.env.VALIDATION_CACHE_TTL
22
+ ? Number(process.env.VALIDATION_CACHE_TTL)
23
+ : 3600; // Default: 1 hour
24
+ const maxKeys = process.env.VALIDATION_CACHE_MAX_SIZE
25
+ ? Number(process.env.VALIDATION_CACHE_MAX_SIZE)
26
+ : 10000; // Default: 10,000 entries
27
+ this.cache = new NodeCache({
28
+ stdTTL: ttl,
29
+ checkperiod: 600, // Check for expired keys every 10 minutes
30
+ useClones: true, // Clone values to prevent mutations
31
+ maxKeys: maxKeys,
32
+ });
33
+ }
34
+ async get(key) {
35
+ const value = this.cache.get(key);
36
+ return value !== undefined ? value : null;
37
+ }
38
+ async set(key, value, ttlSeconds) {
39
+ if (ttlSeconds) {
40
+ this.cache.set(key, value, ttlSeconds);
41
+ }
42
+ else {
43
+ this.cache.set(key, value);
44
+ }
45
+ }
46
+ async delete(key) {
47
+ this.cache.del(key);
48
+ }
49
+ async clear() {
50
+ this.cache.flushAll();
51
+ }
52
+ async has(key) {
53
+ return this.cache.has(key);
54
+ }
55
+ }
56
+ /**
57
+ * Validation Cache Service
58
+ *
59
+ * Uses Redis if available, otherwise falls back to in-memory cache.
60
+ */
61
+ class ValidationCacheService {
62
+ redisCache = null;
63
+ memoryCache;
64
+ useRedis;
65
+ constructor() {
66
+ this.memoryCache = new MemoryValidationCache();
67
+ // Try to use Redis if available
68
+ try {
69
+ this.redisCache = new RedisCache();
70
+ this.useRedis = true;
71
+ logger.debug('ValidationCache: Using Redis cache');
72
+ }
73
+ catch (error) {
74
+ this.useRedis = false;
75
+ logger.debug('ValidationCache: Redis not available, using in-memory cache');
76
+ }
77
+ }
78
+ async get(key) {
79
+ if (this.useRedis && this.redisCache) {
80
+ try {
81
+ const value = await this.redisCache.get(key);
82
+ return value;
83
+ }
84
+ catch (error) {
85
+ logger.warn('Redis cache get failed, falling back to memory', { key, error });
86
+ return await this.memoryCache.get(key);
87
+ }
88
+ }
89
+ return await this.memoryCache.get(key);
90
+ }
91
+ async set(key, value, ttlSeconds) {
92
+ if (this.useRedis && this.redisCache) {
93
+ try {
94
+ await this.redisCache.setGeneric(key, value, ttlSeconds);
95
+ }
96
+ catch (error) {
97
+ logger.warn('Redis cache set failed, falling back to memory', { key, error });
98
+ await this.memoryCache.set(key, value, ttlSeconds);
99
+ }
100
+ }
101
+ else {
102
+ await this.memoryCache.set(key, value, ttlSeconds);
103
+ }
104
+ }
105
+ async delete(key) {
106
+ if (this.useRedis && this.redisCache) {
107
+ try {
108
+ await this.redisCache.delete(key);
109
+ }
110
+ catch (error) {
111
+ logger.warn('Redis cache delete failed, falling back to memory', { key, error });
112
+ }
113
+ }
114
+ await this.memoryCache.delete(key);
115
+ }
116
+ async clear() {
117
+ if (this.useRedis && this.redisCache) {
118
+ try {
119
+ await this.redisCache.clear();
120
+ }
121
+ catch (error) {
122
+ logger.warn('Redis cache clear failed', { error });
123
+ }
124
+ }
125
+ await this.memoryCache.clear();
126
+ }
127
+ // Credential mock specific methods
128
+ async getMock(type) {
129
+ return await this.get(`credential_mock:${type}`);
130
+ }
131
+ async setMock(type, mock) {
132
+ await this.set(`credential_mock:${type}`, mock);
133
+ }
134
+ async getAllMocks() {
135
+ return await this.get('credential_mocks:all');
136
+ }
137
+ async setAllMocks(mocks) {
138
+ await this.set('credential_mocks:all', mocks);
139
+ }
140
+ async has(key) {
141
+ if (this.useRedis && this.redisCache) {
142
+ try {
143
+ return await this.redisCache.has(key);
144
+ }
145
+ catch (error) {
146
+ logger.warn('Redis cache has failed, falling back to memory', { key, error });
147
+ return await this.memoryCache.has(key);
148
+ }
149
+ }
150
+ return await this.memoryCache.has(key);
151
+ }
152
+ }
153
+ /**
154
+ * Singleton instance of validation cache
155
+ */
156
+ export const validationCache = new ValidationCacheService();
157
+ //# sourceMappingURL=ValidationCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidationCache.js","sourceRoot":"","sources":["../../src/services/ValidationCache.ts"],"names":[],"mappings":"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"}