@enokdev/springdocs-mcp 1.2.8 → 1.4.1

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 (112) hide show
  1. package/README.md +83 -40
  2. package/build/config.d.ts +9 -0
  3. package/build/config.d.ts.map +1 -0
  4. package/build/config.js +32 -0
  5. package/build/config.js.map +1 -0
  6. package/build/format.d.ts +6 -0
  7. package/build/format.d.ts.map +1 -0
  8. package/build/format.js +23 -0
  9. package/build/format.js.map +1 -0
  10. package/build/http-server.d.ts +15 -0
  11. package/build/http-server.d.ts.map +1 -0
  12. package/build/http-server.js +131 -0
  13. package/build/http-server.js.map +1 -0
  14. package/build/index.js +182 -68
  15. package/build/index.js.map +1 -1
  16. package/build/prompts.d.ts +23 -0
  17. package/build/prompts.d.ts.map +1 -0
  18. package/build/prompts.js +112 -0
  19. package/build/prompts.js.map +1 -0
  20. package/build/resources.d.ts +31 -0
  21. package/build/resources.d.ts.map +1 -0
  22. package/build/resources.js +66 -0
  23. package/build/resources.js.map +1 -0
  24. package/build/services/advanced-features.d.ts +14 -9
  25. package/build/services/advanced-features.d.ts.map +1 -1
  26. package/build/services/advanced-features.js +205 -195
  27. package/build/services/advanced-features.js.map +1 -1
  28. package/build/services/boot-wiki.d.ts +25 -0
  29. package/build/services/boot-wiki.d.ts.map +1 -0
  30. package/build/services/boot-wiki.js +103 -0
  31. package/build/services/boot-wiki.js.map +1 -0
  32. package/build/services/cache.d.ts +18 -3
  33. package/build/services/cache.d.ts.map +1 -1
  34. package/build/services/cache.js +84 -3
  35. package/build/services/cache.js.map +1 -1
  36. package/build/services/dependency-finder.d.ts +46 -0
  37. package/build/services/dependency-finder.d.ts.map +1 -0
  38. package/build/services/dependency-finder.js +181 -0
  39. package/build/services/dependency-finder.js.map +1 -0
  40. package/build/services/diagnosis.d.ts +46 -0
  41. package/build/services/diagnosis.d.ts.map +1 -0
  42. package/build/services/diagnosis.js +481 -0
  43. package/build/services/diagnosis.js.map +1 -0
  44. package/build/services/guides-list.d.ts +16 -0
  45. package/build/services/guides-list.d.ts.map +1 -0
  46. package/build/services/guides-list.js +45 -0
  47. package/build/services/guides-list.js.map +1 -0
  48. package/build/services/http.d.ts +21 -0
  49. package/build/services/http.d.ts.map +1 -0
  50. package/build/services/http.js +168 -0
  51. package/build/services/http.js.map +1 -0
  52. package/build/services/initializr.d.ts +41 -0
  53. package/build/services/initializr.d.ts.map +1 -0
  54. package/build/services/initializr.js +135 -0
  55. package/build/services/initializr.js.map +1 -0
  56. package/build/services/markdown.d.ts +56 -0
  57. package/build/services/markdown.d.ts.map +1 -0
  58. package/build/services/markdown.js +146 -0
  59. package/build/services/markdown.js.map +1 -0
  60. package/build/services/migration-sources.d.ts +13 -0
  61. package/build/services/migration-sources.d.ts.map +1 -0
  62. package/build/services/migration-sources.js +48 -0
  63. package/build/services/migration-sources.js.map +1 -0
  64. package/build/services/release-notes.d.ts +23 -0
  65. package/build/services/release-notes.d.ts.map +1 -0
  66. package/build/services/release-notes.js +94 -0
  67. package/build/services/release-notes.js.map +1 -0
  68. package/build/services/search-index.d.ts +33 -0
  69. package/build/services/search-index.d.ts.map +1 -0
  70. package/build/services/search-index.js +147 -0
  71. package/build/services/search-index.js.map +1 -0
  72. package/build/services/spring-projects-config.d.ts +26 -33
  73. package/build/services/spring-projects-config.d.ts.map +1 -1
  74. package/build/services/spring-projects-config.js +248 -79
  75. package/build/services/spring-projects-config.js.map +1 -1
  76. package/build/services/springboot-docs-optimized.d.ts +57 -16
  77. package/build/services/springboot-docs-optimized.d.ts.map +1 -1
  78. package/build/services/springboot-docs-optimized.js +315 -197
  79. package/build/services/springboot-docs-optimized.js.map +1 -1
  80. package/build/services/url.d.ts +15 -0
  81. package/build/services/url.d.ts.map +1 -0
  82. package/build/services/url.js +40 -0
  83. package/build/services/url.js.map +1 -0
  84. package/build/tools/index.d.ts +376 -2
  85. package/build/tools/index.d.ts.map +1 -1
  86. package/build/tools/index.js +178 -11
  87. package/build/tools/index.js.map +1 -1
  88. package/build/validation.d.ts +7 -0
  89. package/build/validation.d.ts.map +1 -0
  90. package/build/validation.js +50 -0
  91. package/build/validation.js.map +1 -0
  92. package/build/version.d.ts +3 -0
  93. package/build/version.d.ts.map +1 -0
  94. package/build/version.js +6 -0
  95. package/build/version.js.map +1 -0
  96. package/package.json +6 -6
  97. package/build/debug.d.ts +0 -3
  98. package/build/debug.d.ts.map +0 -1
  99. package/build/debug.js +0 -292
  100. package/build/debug.js.map +0 -1
  101. package/build/services/advanced-features-old.d.ts +0 -45
  102. package/build/services/advanced-features-old.d.ts.map +0 -1
  103. package/build/services/advanced-features-old.js +0 -792
  104. package/build/services/advanced-features-old.js.map +0 -1
  105. package/build/services/springboot-docs-optimized-old.d.ts +0 -55
  106. package/build/services/springboot-docs-optimized-old.d.ts.map +0 -1
  107. package/build/services/springboot-docs-optimized-old.js +0 -588
  108. package/build/services/springboot-docs-optimized-old.js.map +0 -1
  109. package/build/services/springboot-docs.d.ts +0 -65
  110. package/build/services/springboot-docs.d.ts.map +0 -1
  111. package/build/services/springboot-docs.js +0 -708
  112. package/build/services/springboot-docs.js.map +0 -1
@@ -0,0 +1,25 @@
1
+ export type WikiDocument = 'migration-guide' | 'release-notes';
2
+ /** `auto` picks the migration guide for x.0 versions and the release notes otherwise. */
3
+ export declare function resolveWikiDocument(version: string, document: 'auto' | WikiDocument): WikiDocument;
4
+ export declare function wikiPageName(version: string, document: WikiDocument): string;
5
+ export declare function wikiPageUrl(pageName: string): string;
6
+ export declare function expectedWikiTitle(version: string, document: WikiDocument): string;
7
+ /**
8
+ * Convert the wiki page HTML to markdown.
9
+ *
10
+ * GitHub answers a missing wiki page with a redirect to the wiki home page,
11
+ * which is followed transparently and returns 200. The page <title> must
12
+ * therefore match the expected title EXACTLY, otherwise the page is considered
13
+ * absent and the home page content is never returned as a guide.
14
+ */
15
+ export declare function extractWikiMarkdown(html: string, expectedTitle: string, url: string): {
16
+ markdown: string;
17
+ title: string;
18
+ };
19
+ /**
20
+ * Keep the sections whose heading contains the keyword (case-insensitive),
21
+ * each with its sub-sections. Matches nested in an already selected range are
22
+ * skipped; ranges are joined by a blank line.
23
+ */
24
+ export declare function selectSections(markdown: string, keyword: string, title: string): string;
25
+ //# sourceMappingURL=boot-wiki.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot-wiki.d.ts","sourceRoot":"","sources":["../../src/services/boot-wiki.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,eAAe,CAAC;AAK/D,yFAAyF;AACzF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,YAAY,CAGlG;AAMD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,MAAM,CAE5E;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,MAAM,CAEjF;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,GACV;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAmCrC;AAmBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAsBvF"}
@@ -0,0 +1,103 @@
1
+ import * as cheerio from 'cheerio';
2
+ import { scanFences, turndownService } from './markdown.js';
3
+ const WIKI_BASE_URL = 'https://github.com/spring-projects/spring-boot/wiki/';
4
+ const MAX_LISTED_SECTIONS = 80;
5
+ /** `auto` picks the migration guide for x.0 versions and the release notes otherwise. */
6
+ export function resolveWikiDocument(version, document) {
7
+ if (document !== 'auto')
8
+ return document;
9
+ return version.endsWith('.0') ? 'migration-guide' : 'release-notes';
10
+ }
11
+ function documentLabel(document) {
12
+ return document === 'migration-guide' ? 'Migration Guide' : 'Release Notes';
13
+ }
14
+ export function wikiPageName(version, document) {
15
+ return `Spring-Boot-${version}-${documentLabel(document).replace(' ', '-')}`;
16
+ }
17
+ export function wikiPageUrl(pageName) {
18
+ return `${WIKI_BASE_URL}${pageName}`;
19
+ }
20
+ export function expectedWikiTitle(version, document) {
21
+ return `Spring Boot ${version} ${documentLabel(document)}`;
22
+ }
23
+ /**
24
+ * Convert the wiki page HTML to markdown.
25
+ *
26
+ * GitHub answers a missing wiki page with a redirect to the wiki home page,
27
+ * which is followed transparently and returns 200. The page <title> must
28
+ * therefore match the expected title EXACTLY, otherwise the page is considered
29
+ * absent and the home page content is never returned as a guide.
30
+ */
31
+ export function extractWikiMarkdown(html, expectedTitle, url) {
32
+ const $ = cheerio.load(html);
33
+ const title = $('title').first().text().split(' · spring-projects')[0].trim();
34
+ if (title !== expectedTitle) {
35
+ const pageName = decodeURIComponent(url.split('/').pop() ?? url);
36
+ throw new Error(`Spring Boot wiki page not found: ${pageName} (${url})`);
37
+ }
38
+ const body = $('#wiki-body .markdown-body').first();
39
+ if (body.length === 0) {
40
+ throw new Error(`Unable to extract content from ${url}`);
41
+ }
42
+ // Heading permalinks and icons would otherwise leak as "[](#...)" links.
43
+ body.find('a.anchor, svg, .octicon').remove();
44
+ body.find('a[href^="#"]').each((_, el) => {
45
+ if ($(el).text().trim() === '')
46
+ $(el).remove();
47
+ });
48
+ // GitHub renders highlighted blocks as <pre> without <code>, which turndown
49
+ // would not fence: normalise them to <pre><code>.
50
+ body.find('pre').each((_, el) => {
51
+ const pre = $(el);
52
+ if (pre.children('code').length === 0) {
53
+ const code = $('<code></code>').text(pre.text());
54
+ pre.empty().append(code);
55
+ }
56
+ });
57
+ const markdown = turndownService.turndown(body.html() ?? '').trim();
58
+ if (!markdown) {
59
+ throw new Error(`Unable to extract content from ${url}`);
60
+ }
61
+ return { markdown, title };
62
+ }
63
+ function findHeadings(lines) {
64
+ const headings = [];
65
+ const scan = scanFences(lines);
66
+ lines.forEach((line, index) => {
67
+ if (scan[index].inCode || scan[index].isFence)
68
+ return;
69
+ const match = /^(#{1,6})\s+(.+?)\s*$/.exec(line);
70
+ if (match)
71
+ headings.push({ line: index, level: match[1].length, text: match[2] });
72
+ });
73
+ return headings;
74
+ }
75
+ /**
76
+ * Keep the sections whose heading contains the keyword (case-insensitive),
77
+ * each with its sub-sections. Matches nested in an already selected range are
78
+ * skipped; ranges are joined by a blank line.
79
+ */
80
+ export function selectSections(markdown, keyword, title) {
81
+ const lines = markdown.split(/\r?\n/);
82
+ const headings = findHeadings(lines);
83
+ const needle = keyword.toLowerCase();
84
+ const ranges = [];
85
+ let coveredUntil = 0;
86
+ headings.forEach((heading, i) => {
87
+ if (heading.line < coveredUntil)
88
+ return;
89
+ if (!heading.text.toLowerCase().includes(needle))
90
+ return;
91
+ const next = headings.slice(i + 1).find((h) => h.level <= heading.level);
92
+ const end = next ? next.line : lines.length;
93
+ ranges.push(lines.slice(heading.line, end).join('\n').trimEnd());
94
+ coveredUntil = end;
95
+ });
96
+ if (ranges.length === 0) {
97
+ const titles = headings.slice(0, MAX_LISTED_SECTIONS).map((h) => h.text).join(', ');
98
+ const more = headings.length > MAX_LISTED_SECTIONS ? '…' : '';
99
+ throw new Error(`No section matching "${keyword}" in ${title}. Available sections: ${titles}${more}`);
100
+ }
101
+ return ranges.join('\n\n');
102
+ }
103
+ //# sourceMappingURL=boot-wiki.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot-wiki.js","sourceRoot":"","sources":["../../src/services/boot-wiki.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAO5D,MAAM,aAAa,GAAG,sDAAsD,CAAC;AAC7E,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B,yFAAyF;AACzF,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,QAA+B;IAClF,IAAI,QAAQ,KAAK,MAAM;QAAE,OAAO,QAAQ,CAAC;IACzC,OAAO,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,eAAe,CAAC;AACtE,CAAC;AAED,SAAS,aAAa,CAAC,QAAsB;IAC3C,OAAO,QAAQ,KAAK,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,eAAe,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,QAAsB;IAClE,OAAO,eAAe,OAAO,IAAI,aAAa,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,GAAG,aAAa,GAAG,QAAQ,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,QAAsB;IACvE,OAAO,eAAe,OAAO,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,aAAqB,EACrB,GAAW;IAEX,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9E,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,KAAK,GAAG,GAAG,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,CAAC,2BAA2B,CAAC,CAAC,KAAK,EAAE,CAAC;IACpD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,yEAAyE;IACzE,IAAI,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9C,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;QACvC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,4EAA4E;IAC5E,kDAAkD;IAClD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;QAC9B,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;QAClB,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACjD,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAQD,SAAS,YAAY,CAAC,KAAe;IACnC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/B,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO;YAAE,OAAO;QACtD,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,KAAK;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,OAAe,EAAE,KAAa;IAC7E,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAErC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE;QAC9B,IAAI,OAAO,CAAC,IAAI,GAAG,YAAY;YAAE,OAAO;QACxC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO;QACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;QACzE,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACjE,YAAY,GAAG,GAAG,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpF,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,QAAQ,KAAK,yBAAyB,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC;IACxG,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC"}
@@ -1,10 +1,14 @@
1
- /**
2
- * Intelligent caching service for Spring documentation
3
- */
1
+ export interface CacheOptions {
2
+ /** Memory budget in bytes (estimated size of keys and values); default 64 MiB or MCP_CACHE_MAX_MB */
3
+ maxBytes?: number;
4
+ }
4
5
  export declare class CacheService {
5
6
  private cache;
7
+ private totalBytes;
8
+ private readonly maxBytes;
6
9
  private readonly DEFAULT_TTL;
7
10
  private readonly LONG_TTL;
11
+ constructor(options?: CacheOptions);
8
12
  /**
9
13
  * Get cached data if available and not expired
10
14
  */
@@ -13,6 +17,7 @@ export declare class CacheService {
13
17
  * Store data in cache with optional custom TTL
14
18
  */
15
19
  set<T>(key: string, data: T, ttl?: number): void;
20
+ private remove;
16
21
  /**
17
22
  * Store data with long TTL for stable content
18
23
  */
@@ -27,10 +32,20 @@ export declare class CacheService {
27
32
  getStats(): {
28
33
  size: number;
29
34
  expired: number;
35
+ bytes: number;
36
+ maxBytes: number;
30
37
  };
31
38
  /**
32
39
  * Clear all cache
33
40
  */
34
41
  clear(): void;
42
+ /**
43
+ * Remove expired entries or everything; returns how many entries were removed
44
+ */
45
+ purge(mode: "expired" | "all"): number;
46
+ /**
47
+ * Markdown report of the cache state, optionally purging first
48
+ */
49
+ statsReport(purge?: "none" | "expired" | "all"): string;
35
50
  }
36
51
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAoE;IACjF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAEhD;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAY7B;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAQhD;;OAEG;IACH,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAI1C;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,QAAQ,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAa7C;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IAC3B,qGAAqG;IACrG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAmBD,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAmF;IAChG,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;gBAEpC,OAAO,GAAE,YAAiB;IAMtC;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAgB7B;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAkBhD,OAAO,CAAC,MAAM;IAOd;;OAEG;IACH,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAI1C;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,QAAQ,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAa9E;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM;IAUtC;;OAEG;IACH,WAAW,CAAC,KAAK,GAAE,MAAM,GAAG,SAAS,GAAG,KAAc,GAAG,MAAM;CAgBhE"}
@@ -1,10 +1,36 @@
1
1
  /**
2
2
  * Intelligent caching service for Spring documentation
3
3
  */
4
+ const MIB = 1024 * 1024;
5
+ const DEFAULT_MAX_MB = 64;
6
+ function defaultMaxBytes() {
7
+ const mb = Number(process.env.MCP_CACHE_MAX_MB);
8
+ return Number.isFinite(mb) && mb > 0 ? Math.floor(mb * MIB) : DEFAULT_MAX_MB * MIB;
9
+ }
10
+ /** Estimated size in bytes: UTF-8 length for strings, of the JSON form otherwise */
11
+ function estimateBytes(key, data) {
12
+ let size = Buffer.byteLength(key);
13
+ if (typeof data === "string")
14
+ return size + Buffer.byteLength(data);
15
+ try {
16
+ size += Buffer.byteLength(JSON.stringify(data) ?? "");
17
+ }
18
+ catch {
19
+ size += 1024; // not serialisable (cycles, BigInt): flat estimate
20
+ }
21
+ return size;
22
+ }
4
23
  export class CacheService {
5
24
  cache = new Map();
25
+ totalBytes = 0;
26
+ maxBytes;
6
27
  DEFAULT_TTL = 30 * 60 * 1000; // 30 minutes
7
28
  LONG_TTL = 24 * 60 * 60 * 1000; // 24 hours for stable content
29
+ constructor(options = {}) {
30
+ this.maxBytes = options.maxBytes && options.maxBytes > 0 ? options.maxBytes : defaultMaxBytes();
31
+ // Drop expired entries every hour; unref so the timer never keeps the process alive
32
+ setInterval(() => this.cleanup(), 60 * 60 * 1000).unref();
33
+ }
8
34
  /**
9
35
  * Get cached data if available and not expired
10
36
  */
@@ -13,20 +39,42 @@ export class CacheService {
13
39
  if (!entry)
14
40
  return null;
15
41
  if (Date.now() - entry.timestamp > entry.ttl) {
16
- this.cache.delete(key);
42
+ this.remove(key);
17
43
  return null;
18
44
  }
45
+ // Refresh recency: Map iterates in insertion order, so re-insert at the end
46
+ this.cache.delete(key);
47
+ this.cache.set(key, entry);
19
48
  return entry.data;
20
49
  }
21
50
  /**
22
51
  * Store data in cache with optional custom TTL
23
52
  */
24
53
  set(key, data, ttl) {
54
+ this.remove(key);
55
+ const bytes = estimateBytes(key, data);
56
+ if (bytes > this.maxBytes)
57
+ return; // larger than the whole budget: never cached
58
+ while (this.totalBytes + bytes > this.maxBytes) {
59
+ const oldest = this.cache.keys().next().value;
60
+ if (oldest === undefined)
61
+ break;
62
+ this.remove(oldest);
63
+ }
25
64
  this.cache.set(key, {
26
65
  data,
27
66
  timestamp: Date.now(),
28
67
  ttl: ttl || this.DEFAULT_TTL,
68
+ bytes,
29
69
  });
70
+ this.totalBytes += bytes;
71
+ }
72
+ remove(key) {
73
+ const entry = this.cache.get(key);
74
+ if (!entry)
75
+ return;
76
+ this.totalBytes -= entry.bytes;
77
+ this.cache.delete(key);
30
78
  }
31
79
  /**
32
80
  * Store data with long TTL for stable content
@@ -41,7 +89,7 @@ export class CacheService {
41
89
  const now = Date.now();
42
90
  for (const [key, entry] of this.cache.entries()) {
43
91
  if (now - entry.timestamp > entry.ttl) {
44
- this.cache.delete(key);
92
+ this.remove(key);
45
93
  }
46
94
  }
47
95
  }
@@ -56,13 +104,46 @@ export class CacheService {
56
104
  expired++;
57
105
  }
58
106
  }
59
- return { size: this.cache.size, expired };
107
+ return { size: this.cache.size, expired, bytes: this.totalBytes, maxBytes: this.maxBytes };
60
108
  }
61
109
  /**
62
110
  * Clear all cache
63
111
  */
64
112
  clear() {
65
113
  this.cache.clear();
114
+ this.totalBytes = 0;
115
+ }
116
+ /**
117
+ * Remove expired entries or everything; returns how many entries were removed
118
+ */
119
+ purge(mode) {
120
+ const before = this.cache.size;
121
+ if (mode === "all") {
122
+ this.clear();
123
+ }
124
+ else {
125
+ this.cleanup();
126
+ }
127
+ return before - this.cache.size;
128
+ }
129
+ /**
130
+ * Markdown report of the cache state, optionally purging first
131
+ */
132
+ statsReport(purge = "none") {
133
+ const removed = purge === "none" ? null : this.purge(purge);
134
+ const { size, expired, bytes, maxBytes } = this.getStats();
135
+ const mib = (n) => (n / MIB).toFixed(1);
136
+ const lines = [
137
+ "# Cache statistics",
138
+ "",
139
+ `- Entries: ${size}`,
140
+ `- Memory (estimated): ${mib(bytes)} MiB / ${mib(maxBytes)} MiB`,
141
+ `- Expired (awaiting cleanup): ${expired}`,
142
+ ];
143
+ if (removed !== null) {
144
+ lines.push(`- Removed by purge (${purge}): ${removed}`);
145
+ }
146
+ return lines.join("\n");
66
147
  }
67
148
  }
68
149
  //# sourceMappingURL=cache.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,YAAY;IACf,KAAK,GAAG,IAAI,GAAG,EAAyD,CAAC;IAChE,WAAW,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,aAAa;IAC3C,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,8BAA8B;IAE/E;;OAEG;IACH,GAAG,CAAI,GAAW;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;YAC7C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC,IAAS,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,GAAW,EAAE,IAAO,EAAE,GAAY;QACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,WAAW;SAC7B,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,WAAW,CAAI,GAAW,EAAE,IAAO;QACjC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,OAAO;QACL,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBACtC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxC,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBACtC,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AACxB,MAAM,cAAc,GAAG,EAAE,CAAC;AAO1B,SAAS,eAAe;IACtB,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,GAAG,GAAG,CAAC;AACrF,CAAC;AAED,oFAAoF;AACpF,SAAS,aAAa,CAAC,GAAW,EAAE,IAAa;IAC/C,IAAI,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC;QACH,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,IAAI,IAAI,CAAC,CAAC,mDAAmD;IACnE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,OAAO,YAAY;IACf,KAAK,GAAG,IAAI,GAAG,EAAwE,CAAC;IACxF,UAAU,GAAG,CAAC,CAAC;IACN,QAAQ,CAAS;IACjB,WAAW,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,aAAa;IAC3C,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,8BAA8B;IAE/E,YAAY,UAAwB,EAAE;QACpC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;QAChG,oFAAoF;QACpF,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,GAAW;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;YAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,4EAA4E;QAC5E,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE3B,OAAO,KAAK,CAAC,IAAS,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,GAAW,EAAE,IAAO,EAAE,GAAY;QACvC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjB,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACvC,IAAI,KAAK,GAAG,IAAI,CAAC,QAAQ;YAAE,OAAO,CAAC,6CAA6C;QAChF,OAAO,IAAI,CAAC,UAAU,GAAG,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAC9C,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM;YAChC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,WAAW;YAC5B,KAAK;SACN,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC;IAC3B,CAAC;IAEO,MAAM,CAAC,GAAW;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,KAAK,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,WAAW,CAAI,GAAW,EAAE,IAAO;QACjC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,OAAO;QACL,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBACtC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxC,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBACtC,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC7F,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAuB;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAC/B,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;QACD,OAAO,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,QAAoC,MAAM;QACpD,MAAM,OAAO,GAAG,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5D,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC3D,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG;YACZ,oBAAoB;YACpB,EAAE;YACF,cAAc,IAAI,EAAE;YACpB,yBAAyB,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,QAAQ,CAAC,MAAM;YAChE,iCAAiC,OAAO,EAAE;SAC3C,CAAC;QACF,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,uBAAuB,KAAK,MAAM,OAAO,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,46 @@
1
+ import type { InitializrMetadata } from './initializr.js';
2
+ export type BuildChoice = 'maven' | 'gradle' | 'both';
3
+ export interface CatalogEntry {
4
+ id: string;
5
+ name: string;
6
+ description: string;
7
+ }
8
+ export interface Coordinates {
9
+ groupId: string;
10
+ artifactId: string;
11
+ scope: string;
12
+ bom?: string;
13
+ version?: string;
14
+ repository?: string;
15
+ }
16
+ export interface DependencyData {
17
+ bootVersion?: string;
18
+ dependencies: Record<string, Coordinates>;
19
+ boms?: Record<string, {
20
+ groupId: string;
21
+ artifactId: string;
22
+ version: string;
23
+ }>;
24
+ repositories?: Record<string, {
25
+ name: string;
26
+ url: string;
27
+ }>;
28
+ }
29
+ export interface Snippets {
30
+ kind: 'dependency' | 'plugin' | 'unavailable';
31
+ coordinates?: string;
32
+ scope?: string;
33
+ notes: string[];
34
+ maven?: string;
35
+ gradle?: string;
36
+ }
37
+ /** Lowercase alphanumeric words of the need, without stop words or duplicates. */
38
+ export declare function searchWords(need: string): string[];
39
+ export declare function flattenCatalog(meta: InitializrMetadata): CatalogEntry[];
40
+ /** One line of plain text, with the markdown specials neutralised (for titles built from user input). */
41
+ export declare function escapeInline(text: string): string;
42
+ /** Entries matching at least one word, best first (score, then shortest id, then alphabetical). */
43
+ export declare function rankDependencies(catalog: CatalogEntry[], words: string[]): CatalogEntry[];
44
+ export declare function buildSnippets(id: string, data: DependencyData, build: BuildChoice): Snippets;
45
+ export declare function formatDependencyMatches(need: string, ranked: CatalogEntry[], data: DependencyData, build: BuildChoice): string;
46
+ //# sourceMappingURL=dependency-finder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-finder.d.ts","sourceRoot":"","sources":["../../src/services/dependency-finder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAK1D,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,YAAY;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE;AAE/E,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9D;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,aAAa,CAAC;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAUD,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAIlD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,YAAY,EAAE,CAUvE;AAED,yGAAyG;AACzG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAwBD,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAUzF;AAOD,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,GAAG,QAAQ,CAyF5F;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,YAAY,EAAE,EACtB,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,WAAW,GACjB,MAAM,CAoBR"}
@@ -0,0 +1,181 @@
1
+ const MAX_RESULTS = 5;
2
+ const MIN_WORD_LENGTH = 2;
3
+ const DEVELOPMENT_ONLY = new Set(['spring-boot-devtools', 'spring-boot-docker-compose']);
4
+ const SAFE_VALUE = /^[A-Za-z0-9_.-]+$/;
5
+ const STOP_WORDS = new Set([
6
+ 'a', 'an', 'the', 'for', 'with', 'to', 'and', 'of', 'in', 'on', 'my', 'i', 'want', 'need', 'use', 'using', 'spring',
7
+ ]);
8
+ /** Lowercase alphanumeric words of the need, without stop words or duplicates. */
9
+ export function searchWords(need) {
10
+ const words = need.toLowerCase().split(/[^a-z0-9]+/)
11
+ .filter(word => word.length >= MIN_WORD_LENGTH && !STOP_WORDS.has(word));
12
+ return [...new Set(words)];
13
+ }
14
+ export function flattenCatalog(meta) {
15
+ const groups = meta.dependencies?.values;
16
+ if (!Array.isArray(groups)) {
17
+ throw new Error('Spring Initializr returned an unexpected response (missing dependencies)');
18
+ }
19
+ return groups.flatMap(group => group.values.map(dep => ({
20
+ id: dep.id,
21
+ name: dep.name,
22
+ description: dep.description ?? '',
23
+ })));
24
+ }
25
+ /** One line of plain text, with the markdown specials neutralised (for titles built from user input). */
26
+ export function escapeInline(text) {
27
+ return text.replace(/\s+/g, ' ').trim().replace(/[\\`*_[\]<>#|~]/g, '\\$&');
28
+ }
29
+ const SHORT_WORD_LENGTH = 3;
30
+ /** Substring match, except that short words (2-3 characters) must be whole words ("ai" is not in "mail"). */
31
+ function contains(text, word) {
32
+ if (word.length > SHORT_WORD_LENGTH)
33
+ return text.includes(word);
34
+ return new RegExp(`(?<![a-z0-9])${word}(?![a-z0-9])`).test(text);
35
+ }
36
+ function score(entry, words) {
37
+ const id = entry.id.toLowerCase();
38
+ const name = entry.name.toLowerCase();
39
+ const description = entry.description.toLowerCase();
40
+ let total = 0;
41
+ for (const word of words) {
42
+ if (id === word)
43
+ total += 10;
44
+ else if (contains(id, word))
45
+ total += 5;
46
+ if (contains(name, word))
47
+ total += 4;
48
+ if (contains(description, word))
49
+ total += 1;
50
+ }
51
+ return total;
52
+ }
53
+ /** Entries matching at least one word, best first (score, then shortest id, then alphabetical). */
54
+ export function rankDependencies(catalog, words) {
55
+ if (words.length === 0)
56
+ return [];
57
+ return catalog
58
+ .map(entry => ({ entry, score: score(entry, words) }))
59
+ .filter(item => item.score > 0)
60
+ .sort((a, b) => b.score - a.score ||
61
+ a.entry.id.length - b.entry.id.length ||
62
+ a.entry.id.localeCompare(b.entry.id))
63
+ .map(item => item.entry);
64
+ }
65
+ function mavenBlock(groupId, artifactId, extra) {
66
+ return ['<dependency>', ` <groupId>${groupId}</groupId>`, ` <artifactId>${artifactId}</artifactId>`,
67
+ ...extra.map(line => ` ${line}`), '</dependency>'].join('\n');
68
+ }
69
+ export function buildSnippets(id, data, build) {
70
+ const c = data.dependencies[id];
71
+ if (!c) {
72
+ return { kind: 'unavailable', notes: ['No Maven coordinates published by Initializr for this id.'] };
73
+ }
74
+ const bom = c.bom ? data.boms?.[c.bom] : undefined;
75
+ const values = [c.groupId, c.artifactId, c.scope, c.version, bom?.groupId, bom?.artifactId, bom?.version]
76
+ .filter((value) => value !== undefined);
77
+ if (!values.every(value => SAFE_VALUE.test(value))) {
78
+ return { kind: 'unavailable', notes: ['The coordinates published by Initializr contain unexpected characters: no snippet generated.'] };
79
+ }
80
+ const coordinates = `${c.groupId}:${c.artifactId}`;
81
+ if (c.groupId === 'org.springframework.boot' && c.artifactId === 'spring-boot') {
82
+ // Initializr publishes the "native" entry with the spring-boot coordinates, but it generates the GraalVM plugin.
83
+ return {
84
+ kind: 'plugin',
85
+ coordinates: id === 'native' ? undefined : coordinates,
86
+ notes: [
87
+ 'Build plugin, not a dependency: enable it in the build configuration.',
88
+ ...(id === 'native'
89
+ ? ['GraalVM Native Build Tools: Gradle plugin `org.graalvm.buildtools.native`, Maven plugin `org.graalvm.buildtools:native-maven-plugin`.']
90
+ : []),
91
+ ],
92
+ };
93
+ }
94
+ const notes = [];
95
+ if (c.bom && !bom) {
96
+ notes.push(`Needs the BOM "${c.bom}", which Initializr does not describe: add its version manually.`);
97
+ }
98
+ if (c.repository) {
99
+ const repo = data.repositories?.[c.repository];
100
+ notes.push(`Requires the Maven repository ${repo ? `${repo.name} (${repo.url})` : c.repository}.`);
101
+ }
102
+ let scope = c.scope;
103
+ if (!['compile', 'runtime', 'test', 'provided', 'annotationProcessor'].includes(scope)) {
104
+ notes.push(`Unknown scope "${scope}": shown as a regular (compile) dependency.`);
105
+ scope = 'compile';
106
+ }
107
+ // Initializr publishes these as "runtime" but generates optional (Maven) / developmentOnly (Gradle).
108
+ const developmentOnly = scope === 'runtime' && c.groupId === 'org.springframework.boot' && DEVELOPMENT_ONLY.has(c.artifactId);
109
+ if (developmentOnly)
110
+ notes.push('Development-only: not packaged in the production artifact.');
111
+ const gav = c.version ? `${coordinates}:${c.version}` : coordinates;
112
+ const mavenExtra = [
113
+ ...(c.version ? [`<version>${c.version}</version>`] : []),
114
+ ...(scope === 'runtime' || scope === 'test' || scope === 'provided' ? [`<scope>${scope}</scope>`] : []),
115
+ ...(scope === 'annotationProcessor' || developmentOnly ? ['<optional>true</optional>'] : []),
116
+ ];
117
+ const mavenParts = [];
118
+ if (bom) {
119
+ mavenParts.push([
120
+ '<dependencyManagement>',
121
+ ' <dependencies>',
122
+ ' <dependency>',
123
+ ` <groupId>${bom.groupId}</groupId>`,
124
+ ` <artifactId>${bom.artifactId}</artifactId>`,
125
+ ` <version>${bom.version}</version>`,
126
+ ' <type>pom</type>',
127
+ ' <scope>import</scope>',
128
+ ' </dependency>',
129
+ ' </dependencies>',
130
+ '</dependencyManagement>',
131
+ ].join('\n'));
132
+ }
133
+ mavenParts.push(mavenBlock(c.groupId, c.artifactId, mavenExtra));
134
+ const gradleConfig = {
135
+ compile: ['implementation'],
136
+ runtime: ['runtimeOnly'],
137
+ test: ['testImplementation'],
138
+ provided: ['compileOnly'],
139
+ annotationProcessor: ['compileOnly', 'annotationProcessor'],
140
+ };
141
+ const gradleLines = [
142
+ ...(bom ? [`implementation(platform("${bom.groupId}:${bom.artifactId}:${bom.version}"))`] : []),
143
+ ...(developmentOnly ? ['developmentOnly'] : gradleConfig[scope]).map(config => `${config}("${gav}")`),
144
+ ];
145
+ return {
146
+ kind: 'dependency',
147
+ coordinates,
148
+ scope: c.scope,
149
+ notes,
150
+ maven: build === 'gradle' ? undefined : mavenParts.join('\n\n'),
151
+ gradle: build === 'maven' ? undefined : gradleLines.join('\n'),
152
+ };
153
+ }
154
+ export function formatDependencyMatches(need, ranked, data, build) {
155
+ if (ranked.length === 0) {
156
+ return `No dependency matches "${escapeInline(need)}". Try other English keywords, or list everything with get_spring_initializr (section "dependencies").`;
157
+ }
158
+ const lines = [`# Dependencies for "${escapeInline(need)}"${data.bootVersion ? ` (Spring Boot ${data.bootVersion})` : ''}`];
159
+ for (const entry of ranked.slice(0, MAX_RESULTS)) {
160
+ const snippets = buildSnippets(entry.id, data, build);
161
+ lines.push('', `## \`${entry.id}\` — ${entry.name}`);
162
+ if (entry.description)
163
+ lines.push('', entry.description);
164
+ lines.push('');
165
+ if (snippets.coordinates)
166
+ lines.push(`- Coordinates: \`${snippets.coordinates}\``);
167
+ if (snippets.scope)
168
+ lines.push(`- Scope: ${snippets.scope}`);
169
+ for (const note of snippets.notes)
170
+ lines.push(`- ${note}`);
171
+ if (snippets.maven)
172
+ lines.push('', '**Maven**', '', '```xml', snippets.maven, '```');
173
+ if (snippets.gradle)
174
+ lines.push('', '**Gradle** (Groovy and Kotlin DSL)', '', '```gradle', snippets.gradle, '```');
175
+ }
176
+ if (ranked.length > MAX_RESULTS) {
177
+ lines.push('', `${ranked.length - MAX_RESULTS} more matches, refine the query.`);
178
+ }
179
+ return lines.join('\n');
180
+ }
181
+ //# sourceMappingURL=dependency-finder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-finder.js","sourceRoot":"","sources":["../../src/services/dependency-finder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Local, deterministic and bounded analysis of Spring error messages and stack traces.
3
+ *
4
+ * The input is untrusted user text: every cap is applied BEFORE any processing, and the
5
+ * parsing is line based (startsWith / indexOf / slice). No backtracking regex is used;
6
+ * the only regexes are anchored, linear and without nested quantifiers.
7
+ */
8
+ import { SpringProjectsConfig } from './spring-projects-config.js';
9
+ export interface ExceptionLink {
10
+ type: string;
11
+ message: string;
12
+ }
13
+ export interface TraceAnalysis {
14
+ chain: ExceptionLink[];
15
+ top?: ExceptionLink;
16
+ root?: ExceptionLink;
17
+ /** Trimmed first application frame, e.g. "at com.acme.Foo.bar(Foo.java:42)" */
18
+ applicationFrame?: string;
19
+ /** One of startup | web | data | security | actuator | configuration */
20
+ inferredComponent?: string;
21
+ }
22
+ export interface DiagnosisReference {
23
+ project: string;
24
+ section: string;
25
+ subsection?: string;
26
+ }
27
+ export interface DiagnosisRule {
28
+ id: string;
29
+ needles: string[];
30
+ title: string;
31
+ checks: string[];
32
+ references: DiagnosisReference[];
33
+ }
34
+ export declare function analyzeStackTrace(stackTrace?: string): TraceAnalysis;
35
+ export declare const DIAGNOSIS_RULES: DiagnosisRule[];
36
+ /**
37
+ * Returns the rules whose needles appear (lower-cased) in the analyzed text:
38
+ * the error message plus the exception header lines of the trace. Order = table order.
39
+ */
40
+ export declare function matchRules(errorMessage: string, analysis: TraceAnalysis, stackTrace?: string): DiagnosisRule[];
41
+ export declare function renderDiagnosis(input: {
42
+ errorMessage: string;
43
+ component?: string;
44
+ stackTrace?: string;
45
+ }, config?: SpringProjectsConfig): string;
46
+ //# sourceMappingURL=diagnosis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnosis.d.ts","sourceRoot":"","sources":["../../src/services/diagnosis.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAwB,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAEzF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wEAAwE;IACxE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,kBAAkB,EAAE,CAAC;CAClC;AAiJD,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CAYpE;AAMD,eAAO,MAAM,eAAe,EAAE,aAAa,EA2K1C,CAAC;AAqDF;;;GAGG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAqB9G;AA+BD,wBAAgB,eAAe,CAC7B,KAAK,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EACxE,MAAM,GAAE,oBAA2C,GAClD,MAAM,CA4DR"}