@enokdev/springdocs-mcp 1.2.7 → 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 +108 -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 +184 -69
  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 +19 -9
  25. package/build/services/advanced-features.d.ts.map +1 -1
  26. package/build/services/advanced-features.js +266 -191
  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 +98 -0
  73. package/build/services/spring-projects-config.d.ts.map +1 -0
  74. package/build/services/spring-projects-config.js +397 -0
  75. package/build/services/spring-projects-config.js.map +1 -0
  76. package/build/services/springboot-docs-optimized.d.ts +72 -21
  77. package/build/services/springboot-docs-optimized.d.ts.map +1 -1
  78. package/build/services/springboot-docs-optimized.js +354 -208
  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 +393 -2
  85. package/build/tools/index.d.ts.map +1 -1
  86. package/build/tools/index.js +188 -15
  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 +9 -7
  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,168 @@
1
+ import fetch from 'node-fetch';
2
+ import { USER_AGENT } from '../version.js';
3
+ const GITHUB_API_HOST = 'api.github.com';
4
+ /** Optional GITHUB_TOKEN, trimmed; undefined when unset or blank. Never log it. */
5
+ function githubToken() {
6
+ const token = process.env.GITHUB_TOKEN?.trim();
7
+ return token ? token : undefined;
8
+ }
9
+ /** Clear message for a GitHub rate-limited response (no waiting, no secret in it). */
10
+ export function githubRateLimitMessage(rateLimit) {
11
+ let message = githubToken()
12
+ ? 'GitHub API rate limit reached (authenticated with GITHUB_TOKEN).'
13
+ : 'GitHub API rate limit reached (60 requests/hour without authentication; set GITHUB_TOKEN to raise it to 5000).';
14
+ if (rateLimit?.retryAfterSeconds !== undefined) {
15
+ message += ` Retry in ${rateLimit.retryAfterSeconds} seconds.`;
16
+ }
17
+ else if (rateLimit?.resetAt) {
18
+ message += ` The limit resets at ${rateLimit.resetAt}.`;
19
+ }
20
+ else {
21
+ message += ' Try again later.';
22
+ }
23
+ return message;
24
+ }
25
+ function parseRateLimit(headers) {
26
+ const retryAfter = Number(headers.get('retry-after') ?? NaN);
27
+ const remaining = headers.get('x-ratelimit-remaining');
28
+ const reset = Number(headers.get('x-ratelimit-reset') ?? NaN);
29
+ const hasRetryAfter = headers.get('retry-after') !== null && Number.isFinite(retryAfter) && retryAfter >= 0;
30
+ if (!hasRetryAfter && remaining !== '0')
31
+ return undefined;
32
+ const info = {};
33
+ if (hasRetryAfter)
34
+ info.retryAfterSeconds = retryAfter;
35
+ if (Number.isFinite(reset) && reset > 0)
36
+ info.resetAt = new Date(reset * 1000).toISOString();
37
+ return info;
38
+ }
39
+ export const REQUEST_TIMEOUT = 10000;
40
+ export const MAX_RETRIES = 3;
41
+ export const MAX_RESPONSE_BYTES = 5 * 1024 * 1024; // 5 MiB
42
+ export const MAX_REDIRECTS = 5;
43
+ export const ALLOWED_REDIRECT_HOSTS = new Set([
44
+ 'docs.spring.io',
45
+ 'spring.io',
46
+ 'github.com',
47
+ 'api.github.com',
48
+ 'raw.githubusercontent.com'
49
+ ]);
50
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
51
+ class ResponseTooLargeError extends Error {
52
+ constructor(url) {
53
+ super(`Response from ${url} exceeds the 5 MiB limit`);
54
+ }
55
+ }
56
+ /** A refused redirect (host, protocol, loop, too many hops): never retried. */
57
+ class RedirectError extends Error {
58
+ }
59
+ export async function fetchWithRetry(url, timeout = REQUEST_TIMEOUT, retries = MAX_RETRIES) {
60
+ for (let attempt = 1; attempt <= retries; attempt++) {
61
+ const controller = new AbortController();
62
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
63
+ let delayMs = 1000 * 2 ** (attempt - 1); // Exponential backoff
64
+ try {
65
+ // Redirects are followed manually (always GET) so every hop can be checked
66
+ let currentUrl = url;
67
+ const visited = new Set([url]);
68
+ let redirects = 0;
69
+ let response;
70
+ for (;;) {
71
+ const headers = {
72
+ 'User-Agent': USER_AGENT,
73
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
74
+ 'Accept-Language': 'en-US,en;q=0.9'
75
+ };
76
+ // The token goes to api.github.com only, checked on every hop (never after a redirect elsewhere)
77
+ const token = githubToken();
78
+ if (token && new URL(currentUrl).hostname === GITHUB_API_HOST) {
79
+ headers['Authorization'] = `Bearer ${token}`;
80
+ }
81
+ response = await fetch(currentUrl, {
82
+ signal: controller.signal,
83
+ size: MAX_RESPONSE_BYTES,
84
+ redirect: 'manual',
85
+ headers
86
+ });
87
+ // Reject early when the server announces a body above the limit
88
+ const declaredLength = Number(response.headers.get('content-length'));
89
+ if (Number.isFinite(declaredLength) && declaredLength > MAX_RESPONSE_BYTES) {
90
+ throw new ResponseTooLargeError(currentUrl);
91
+ }
92
+ const location = REDIRECT_STATUSES.has(response.status) ? response.headers.get('location') : null;
93
+ if (!location)
94
+ break; // not a followable redirect: returned as is
95
+ // The body of a redirect is useless: discard it without reading
96
+ response.body?.resume?.();
97
+ let next;
98
+ try {
99
+ next = new URL(location, currentUrl);
100
+ }
101
+ catch {
102
+ throw new RedirectError(`Invalid redirect Location from ${currentUrl}: ${location}`);
103
+ }
104
+ if (next.protocol !== 'https:') {
105
+ throw new RedirectError(`Redirect to disallowed protocol ${next.protocol} from ${currentUrl}`);
106
+ }
107
+ if (!ALLOWED_REDIRECT_HOSTS.has(next.hostname)) {
108
+ throw new RedirectError(`Redirect to disallowed host ${next.hostname} from ${currentUrl}`);
109
+ }
110
+ if (visited.has(next.href)) {
111
+ throw new RedirectError(`Redirect loop detected at ${next.href}`);
112
+ }
113
+ if (++redirects > MAX_REDIRECTS) {
114
+ throw new RedirectError(`Too many redirects (more than ${MAX_REDIRECTS}) starting from ${url}`);
115
+ }
116
+ visited.add(next.href);
117
+ currentUrl = next.href;
118
+ }
119
+ // Read the body before clearing the timeout so the timeout also covers it
120
+ let body;
121
+ try {
122
+ body = await response.text();
123
+ }
124
+ catch (error) {
125
+ // node-fetch aborts the read once `size` is exceeded
126
+ if (error.type === 'max-size')
127
+ throw new ResponseTooLargeError(url);
128
+ throw error;
129
+ }
130
+ const result = {
131
+ ok: response.ok,
132
+ status: response.status,
133
+ text: async () => body,
134
+ json: async () => JSON.parse(body)
135
+ };
136
+ // A GitHub rate limit lasts minutes to an hour: waiting 10 s is pointless, report it at once
137
+ if ((response.status === 403 || response.status === 429) && new URL(currentUrl).hostname === GITHUB_API_HOST) {
138
+ const rateLimit = parseRateLimit(response.headers);
139
+ if (rateLimit) {
140
+ result.rateLimit = rateLimit;
141
+ return result;
142
+ }
143
+ }
144
+ const retryable = response.status === 429 || response.status >= 500;
145
+ if (!retryable || attempt === retries)
146
+ return result;
147
+ const retryAfterHeader = response.headers.get('retry-after');
148
+ const retryAfter = retryAfterHeader === null ? NaN : Number(retryAfterHeader);
149
+ if (Number.isFinite(retryAfter) && retryAfter >= 0) {
150
+ delayMs = Math.min(retryAfter * 1000, 10000);
151
+ }
152
+ console.error(`Retry ${attempt}/${retries} for ${url}: HTTP ${response.status}`);
153
+ }
154
+ catch (error) {
155
+ if (error instanceof ResponseTooLargeError || error instanceof RedirectError)
156
+ throw error; // never retried
157
+ if (attempt === retries)
158
+ throw error;
159
+ console.error(`Retry ${attempt}/${retries} for ${url}:`, error instanceof Error ? error.message : 'Unknown error');
160
+ }
161
+ finally {
162
+ clearTimeout(timeoutId);
163
+ }
164
+ await new Promise(resolve => setTimeout(resolve, delayMs));
165
+ }
166
+ throw new Error('All retry attempts failed');
167
+ }
168
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/services/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { CacheService } from './cache.js';
2
+ import { BuildChoice } from './dependency-finder.js';
3
+ interface OptionValue {
4
+ id: string;
5
+ name?: string;
6
+ }
7
+ interface OptionGroup {
8
+ default?: string;
9
+ values: OptionValue[];
10
+ }
11
+ interface Dependency {
12
+ id: string;
13
+ name: string;
14
+ description?: string;
15
+ }
16
+ interface DependencyGroup {
17
+ name: string;
18
+ values: Dependency[];
19
+ }
20
+ export interface InitializrMetadata {
21
+ type?: OptionGroup;
22
+ javaVersion?: OptionGroup;
23
+ language?: OptionGroup;
24
+ packaging?: OptionGroup;
25
+ bootVersion?: OptionGroup;
26
+ dependencies?: {
27
+ values: DependencyGroup[];
28
+ };
29
+ }
30
+ export declare function formatOptions(meta: InitializrMetadata): string;
31
+ export declare function formatDependencies(meta: InitializrMetadata, query?: string): string;
32
+ export declare class InitializrService {
33
+ private cache;
34
+ constructor(cache?: CacheService);
35
+ getInitializr(section?: 'options' | 'dependencies', query?: string): Promise<string>;
36
+ findDependency(need: string, build?: BuildChoice, bootVersion?: string): Promise<string>;
37
+ private loadCoordinates;
38
+ private loadMetadata;
39
+ }
40
+ export {};
41
+ //# sourceMappingURL=initializr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initializr.d.ts","sourceRoot":"","sources":["../../src/services/initializr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAwG,MAAM,wBAAwB,CAAC;AAY3J,UAAU,WAAW;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE;AACnD,UAAU,WAAW;IAAG,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,EAAE,CAAA;CAAE;AACjE,UAAU,UAAU;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE;AACvE,UAAU,eAAe;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,EAAE,CAAA;CAAE;AAEhE,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC;CAC9C;AAkBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAY9D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CA+BnF;AAED,qBAAa,iBAAiB;IAChB,OAAO,CAAC,KAAK;gBAAL,KAAK,GAAE,YAAiC;IAEtD,aAAa,CAAC,OAAO,GAAE,SAAS,GAAG,cAA0B,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/F,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,WAAoB,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAcxF,eAAe;YAiBf,YAAY;CAmB3B"}
@@ -0,0 +1,135 @@
1
+ import { CacheService } from './cache.js';
2
+ import { fetchWithRetry } from './http.js';
3
+ import { escapeInline, flattenCatalog, formatDependencyMatches, rankDependencies, searchWords } from './dependency-finder.js';
4
+ // Reads the Spring Initializr metadata (https://start.spring.io/metadata/client):
5
+ // build options and the list of available dependencies. Real API only, no mock data.
6
+ const METADATA_URL = 'https://start.spring.io/metadata/client';
7
+ const CACHE_KEY = 'initializr:metadata';
8
+ const COORDINATES_URL = 'https://start.spring.io/dependencies';
9
+ const COORDINATES_CACHE_KEY = 'initializr:dependencies';
10
+ const MAX_MATCHES = 30;
11
+ const BOOT_VERSION = /^\d{1,3}\.\d{1,3}\.\d{1,3}$/;
12
+ function unexpected(what) {
13
+ throw new Error(`Spring Initializr returned an unexpected response (missing ${what})`);
14
+ }
15
+ function optionLine(label, group) {
16
+ if (!group || !Array.isArray(group.values))
17
+ unexpected(label);
18
+ const items = group.values.map(v => {
19
+ const tags = [];
20
+ if (v.id === group.default)
21
+ tags.push('default');
22
+ if (/SNAPSHOT/i.test(v.id))
23
+ tags.push('snapshot');
24
+ else if (/[.-](M|RC)\d+/i.test(v.id))
25
+ tags.push('milestone');
26
+ return `\`${v.id}\`${tags.length ? ` (${tags.join(', ')})` : ''}`;
27
+ });
28
+ return `- **${label}**: ${items.join(', ')}`;
29
+ }
30
+ export function formatOptions(meta) {
31
+ return [
32
+ '# Spring Initializr options',
33
+ '',
34
+ optionLine('Build type', meta.type),
35
+ optionLine('Java version', meta.javaVersion),
36
+ optionLine('Language', meta.language),
37
+ optionLine('Packaging', meta.packaging),
38
+ optionLine('Spring Boot version', meta.bootVersion),
39
+ '',
40
+ 'Source: https://start.spring.io — use `section: "dependencies"` to list the dependency ids.',
41
+ ].join('\n');
42
+ }
43
+ export function formatDependencies(meta, query) {
44
+ const groups = meta.dependencies?.values;
45
+ if (!Array.isArray(groups))
46
+ unexpected('dependencies');
47
+ const needle = query?.trim().toLowerCase();
48
+ if (!needle) {
49
+ const lines = ['# Spring Initializr dependencies', ''];
50
+ for (const group of groups) {
51
+ lines.push(`## ${group.name}`, '');
52
+ for (const dep of group.values)
53
+ lines.push(`- \`${dep.id}\` — ${dep.name}`);
54
+ lines.push('');
55
+ }
56
+ return lines.join('\n').trimEnd();
57
+ }
58
+ const matches = [];
59
+ for (const group of groups) {
60
+ for (const dep of group.values) {
61
+ const haystack = `${dep.id} ${dep.name} ${dep.description ?? ''}`.toLowerCase();
62
+ if (haystack.includes(needle))
63
+ matches.push(dep);
64
+ }
65
+ }
66
+ if (matches.length === 0)
67
+ return `No dependency matches "${escapeInline(query)}".`;
68
+ const shown = matches.slice(0, MAX_MATCHES);
69
+ const lines = [`# Spring Initializr dependencies matching "${escapeInline(query)}"`, ''];
70
+ for (const dep of shown)
71
+ lines.push(`- \`${dep.id}\` — ${dep.name}${dep.description ? `: ${dep.description}` : ''}`);
72
+ if (matches.length > shown.length) {
73
+ lines.push('', `${matches.length - shown.length} more matches, refine the query.`);
74
+ }
75
+ return lines.join('\n');
76
+ }
77
+ export class InitializrService {
78
+ cache;
79
+ constructor(cache = new CacheService()) {
80
+ this.cache = cache;
81
+ }
82
+ async getInitializr(section = 'options', query) {
83
+ const meta = await this.loadMetadata();
84
+ return section === 'dependencies' ? formatDependencies(meta, query) : formatOptions(meta);
85
+ }
86
+ async findDependency(need, build = 'both', bootVersion) {
87
+ const words = searchWords(need);
88
+ if (words.length === 0) {
89
+ throw new Error('The need must contain at least one searchable word (English keywords such as "jpa" or "oauth2")');
90
+ }
91
+ if (bootVersion !== undefined && !BOOT_VERSION.test(bootVersion)) {
92
+ throw new Error('The bootVersion must use the X.Y.Z format (for example "4.0.8")');
93
+ }
94
+ const meta = await this.loadMetadata();
95
+ const data = await this.loadCoordinates(bootVersion);
96
+ const ranked = rankDependencies(flattenCatalog(meta), words);
97
+ return formatDependencyMatches(need, ranked, data, build);
98
+ }
99
+ async loadCoordinates(bootVersion) {
100
+ const cacheKey = bootVersion ? `${COORDINATES_CACHE_KEY}:${bootVersion}` : COORDINATES_CACHE_KEY;
101
+ const cached = this.cache.get(cacheKey);
102
+ if (cached)
103
+ return cached;
104
+ const response = await fetchWithRetry(bootVersion ? `${COORDINATES_URL}?bootVersion=${bootVersion}` : COORDINATES_URL);
105
+ if (!response.ok) {
106
+ throw new Error(`Spring Initializr is unavailable (HTTP ${response.status})`);
107
+ }
108
+ const data = (await response.json());
109
+ if (!data || typeof data.dependencies !== 'object' || data.dependencies === null || Array.isArray(data.dependencies)) {
110
+ unexpected('dependencies');
111
+ }
112
+ this.cache.setLongTerm(cacheKey, data);
113
+ return data;
114
+ }
115
+ async loadMetadata() {
116
+ const cached = this.cache.get(CACHE_KEY);
117
+ if (cached)
118
+ return cached;
119
+ const response = await fetchWithRetry(METADATA_URL);
120
+ if (!response.ok) {
121
+ throw new Error(`Spring Initializr is unavailable (HTTP ${response.status})`);
122
+ }
123
+ const meta = (await response.json());
124
+ const optionsOk = meta && [meta.type, meta.javaVersion, meta.language, meta.packaging, meta.bootVersion]
125
+ .every(group => Array.isArray(group?.values));
126
+ const dependenciesOk = meta && Array.isArray(meta.dependencies?.values)
127
+ && meta.dependencies.values.every(group => Array.isArray(group?.values));
128
+ if (!optionsOk || !dependenciesOk) {
129
+ unexpected('options or dependencies');
130
+ }
131
+ this.cache.setLongTerm(CACHE_KEY, meta);
132
+ return meta;
133
+ }
134
+ }
135
+ //# sourceMappingURL=initializr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initializr.js","sourceRoot":"","sources":["../../src/services/initializr.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import TurndownService from 'turndown';
2
+ export declare const turndownService: TurndownService;
3
+ /** An open fenced code block: its fence character and the length of the opening fence. */
4
+ export interface Fence {
5
+ char: '`' | '~';
6
+ length: number;
7
+ }
8
+ /**
9
+ * Fence state after `line`, given the state before it (null = outside a code block).
10
+ * An opening fence is 3+ backticks or tildes (a backtick fence cannot carry
11
+ * backticks in its info string); a closing fence uses the same character, is at
12
+ * least as long as the opening one and carries nothing but whitespace.
13
+ */
14
+ export declare function advanceFence(state: Fence | null, line: string): Fence | null;
15
+ /** The fence line that closes (or reopens) a block opened with `fence`. */
16
+ export declare function fenceMarker(fence: Fence): string;
17
+ export interface FenceLine {
18
+ /** Whether the line begins inside a fenced code block. */
19
+ inCode: boolean;
20
+ /** The open fence at the start of the line (null when outside a block). */
21
+ fence: Fence | null;
22
+ /** Whether the line is itself an opening or closing fence. */
23
+ isFence: boolean;
24
+ /** The open fence after this line (null when outside a block). */
25
+ after: Fence | null;
26
+ }
27
+ /** Code-fence state of every line, in one pass. Single source of truth for all fence tracking. */
28
+ export declare function scanFences(lines: readonly string[]): FenceLine[];
29
+ export declare const DETAIL_LIMITS: Record<string, number>;
30
+ /**
31
+ * Keep the beginning of a markdown document within the detail level's budget.
32
+ * The cut happens on a line boundary; a code block cut in the middle is closed
33
+ * so the result stays valid markdown.
34
+ */
35
+ export declare function extractContent(markdown: string, detailLevel?: string): {
36
+ content: string;
37
+ truncated: boolean;
38
+ };
39
+ export declare const PAGE_SIZE = 4000;
40
+ /**
41
+ * Return one page of a markdown document starting at `offset`.
42
+ * The page ends at a clean boundary: before a heading, else after a blank line
43
+ * (both only outside code blocks and past the middle of the window), else on a
44
+ * line boundary, else a hard cut for a single huge line. A code block cut by the
45
+ * page boundary is closed here and reopened at the start of the next page.
46
+ * `start`/`end` are positions in the original markdown (`end` exclusive);
47
+ * `nextOffset` is `end` when content remains, else null.
48
+ */
49
+ export declare function pageMarkdown(markdown: string, offset?: number, pageSize?: number): {
50
+ content: string;
51
+ start: number;
52
+ end: number;
53
+ nextOffset: number | null;
54
+ total: number;
55
+ };
56
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/services/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,UAAU,CAAC;AAEvC,eAAO,MAAM,eAAe,iBAG1B,CAAC;AAEH,0FAA0F;AAC1F,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAKD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAW5E;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEhD;AAED,MAAM,WAAW,SAAS;IACxB,0DAA0D;IAC1D,MAAM,EAAE,OAAO,CAAC;IAChB,2EAA2E;IAC3E,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,8DAA8D;IAC9D,OAAO,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,kGAAkG;AAClG,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAAE,CAOhE;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIhD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,GAAE,MAAiB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAyBxH;AAED,eAAO,MAAM,SAAS,OAAO,CAAC;AAsB9B;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAU,EAClB,QAAQ,GAAE,MAAkB,GAC3B;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAuC3F"}
@@ -0,0 +1,146 @@
1
+ import TurndownService from 'turndown';
2
+ export const turndownService = new TurndownService({
3
+ headingStyle: 'atx',
4
+ codeBlockStyle: 'fenced',
5
+ });
6
+ const OPENING_FENCE = /^\s*(`{3,}|~{3,})(.*)$/;
7
+ const CLOSING_FENCE = /^\s*(`{3,}|~{3,})\s*$/;
8
+ /**
9
+ * Fence state after `line`, given the state before it (null = outside a code block).
10
+ * An opening fence is 3+ backticks or tildes (a backtick fence cannot carry
11
+ * backticks in its info string); a closing fence uses the same character, is at
12
+ * least as long as the opening one and carries nothing but whitespace.
13
+ */
14
+ export function advanceFence(state, line) {
15
+ if (state) {
16
+ const close = CLOSING_FENCE.exec(line);
17
+ if (close && close[1][0] === state.char && close[1].length >= state.length)
18
+ return null;
19
+ return state;
20
+ }
21
+ const open = OPENING_FENCE.exec(line);
22
+ if (!open)
23
+ return null;
24
+ const char = open[1][0];
25
+ if (char === '`' && open[2].includes('`'))
26
+ return null;
27
+ return { char, length: open[1].length };
28
+ }
29
+ /** The fence line that closes (or reopens) a block opened with `fence`. */
30
+ export function fenceMarker(fence) {
31
+ return fence.char.repeat(fence.length);
32
+ }
33
+ /** Code-fence state of every line, in one pass. Single source of truth for all fence tracking. */
34
+ export function scanFences(lines) {
35
+ let state = null;
36
+ return lines.map((line) => {
37
+ const before = state;
38
+ state = advanceFence(before, line);
39
+ return { inCode: before !== null, fence: before, isFence: (before === null) !== (state === null), after: state };
40
+ });
41
+ }
42
+ export const DETAIL_LIMITS = {
43
+ summary: 1500,
44
+ medium: 4000,
45
+ full: 50000,
46
+ };
47
+ /**
48
+ * Keep the beginning of a markdown document within the detail level's budget.
49
+ * The cut happens on a line boundary; a code block cut in the middle is closed
50
+ * so the result stays valid markdown.
51
+ */
52
+ export function extractContent(markdown, detailLevel = 'medium') {
53
+ const maxLength = DETAIL_LIMITS[detailLevel] ?? DETAIL_LIMITS.medium;
54
+ if (markdown.length <= maxLength)
55
+ return { content: markdown, truncated: false };
56
+ const kept = [];
57
+ let length = 0;
58
+ let fence = null;
59
+ for (const line of markdown.split('\n')) {
60
+ if (length + line.length + 1 > maxLength)
61
+ break;
62
+ kept.push(line);
63
+ length += line.length + 1;
64
+ fence = advanceFence(fence, line);
65
+ }
66
+ // A first line longer than the budget leaves nothing: hard-cut it instead
67
+ if (kept.length === 0) {
68
+ const firstLine = markdown.split('\n', 1)[0];
69
+ const open = advanceFence(null, firstLine);
70
+ const first = markdown.slice(0, maxLength);
71
+ return { content: open ? `${first}\n${fenceMarker(open)}` : first, truncated: true };
72
+ }
73
+ let content = kept.join('\n').trimEnd();
74
+ if (fence)
75
+ content += `\n${fenceMarker(fence)}`;
76
+ return { content, truncated: true };
77
+ }
78
+ export const PAGE_SIZE = 4000;
79
+ /** Split into lines with their start position and code-fence state, in one pass. */
80
+ function scanLines(markdown) {
81
+ const texts = [];
82
+ const starts = [];
83
+ let start = 0;
84
+ while (start < markdown.length) {
85
+ const newline = markdown.indexOf('\n', start);
86
+ const end = newline === -1 ? markdown.length : newline;
87
+ texts.push(markdown.slice(start, end));
88
+ starts.push(start);
89
+ start = end + 1;
90
+ }
91
+ return scanFences(texts).map((fence, i) => ({ ...fence, start: starts[i], text: texts[i] }));
92
+ }
93
+ /**
94
+ * Return one page of a markdown document starting at `offset`.
95
+ * The page ends at a clean boundary: before a heading, else after a blank line
96
+ * (both only outside code blocks and past the middle of the window), else on a
97
+ * line boundary, else a hard cut for a single huge line. A code block cut by the
98
+ * page boundary is closed here and reopened at the start of the next page.
99
+ * `start`/`end` are positions in the original markdown (`end` exclusive);
100
+ * `nextOffset` is `end` when content remains, else null.
101
+ */
102
+ export function pageMarkdown(markdown, offset = 0, pageSize = PAGE_SIZE) {
103
+ const total = markdown.length;
104
+ if (offset >= total)
105
+ return { content: '', start: offset, end: offset, nextOffset: null, total };
106
+ const lines = scanLines(markdown);
107
+ // Fence state at a position = state at the start of the line containing it
108
+ const stateAt = (position) => {
109
+ let found = lines[0];
110
+ for (const line of lines) {
111
+ if (line.start > position)
112
+ break;
113
+ found = line;
114
+ }
115
+ return found.fence;
116
+ };
117
+ const startFence = stateAt(offset);
118
+ const windowEnd = Math.min(total, offset + pageSize);
119
+ let end = windowEnd;
120
+ if (windowEnd < total) {
121
+ let heading = -1;
122
+ let blank = -1;
123
+ let anyLine = -1;
124
+ lines.forEach((line, index) => {
125
+ // Candidate boundaries are line starts strictly after `offset`, within the window
126
+ if (line.start <= offset || line.start > windowEnd)
127
+ return;
128
+ anyLine = line.start;
129
+ if (line.inCode || line.start < offset + pageSize / 2)
130
+ return;
131
+ if (/^#{1,6}\s/.test(line.text))
132
+ heading = line.start;
133
+ else if (lines[index - 1].text === '')
134
+ blank = line.start;
135
+ });
136
+ end = heading !== -1 ? heading : blank !== -1 ? blank : anyLine !== -1 ? anyLine : windowEnd;
137
+ }
138
+ let content = markdown.slice(offset, end);
139
+ if (startFence)
140
+ content = `${fenceMarker(startFence)}\n${content}`;
141
+ const endFence = end < total ? stateAt(end) : null;
142
+ if (endFence)
143
+ content = content.replace(/\n?$/, `\n${fenceMarker(endFence)}`);
144
+ return { content, start: offset, end, nextOffset: end < total ? end : null, total };
145
+ }
146
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/services/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export type MigrationProject = 'spring-boot' | 'spring-framework' | 'spring-batch';
2
+ export type RawMigrationDocument = 'migration-guide' | 'release-notes';
3
+ export type RawMigrationProject = Exclude<MigrationProject, 'spring-boot'>;
4
+ export declare const MIGRATION_PROJECTS: readonly MigrationProject[];
5
+ export declare function isMigrationProject(value: string): value is MigrationProject;
6
+ export declare function projectDisplayName(project: MigrationProject): string;
7
+ export declare function rawWikiTitle(project: RawMigrationProject, version: string): string;
8
+ export declare function rawWikiUrl(project: RawMigrationProject, version: string): string;
9
+ /** `auto` and the project's only document resolve to it; the other one is rejected before any request. */
10
+ export declare function resolveRawDocument(project: RawMigrationProject, document: 'auto' | RawMigrationDocument): RawMigrationDocument;
11
+ /** A real page is markdown, never an HTML document (home page or error page). */
12
+ export declare function assertRawMarkdown(body: string, title: string, url: string): string;
13
+ //# sourceMappingURL=migration-sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-sources.d.ts","sourceRoot":"","sources":["../../src/services/migration-sources.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,kBAAkB,GAAG,cAAc,CAAC;AACnF,MAAM,MAAM,oBAAoB,GAAG,iBAAiB,GAAG,eAAe,CAAC;AACvE,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;AAE3E,eAAO,MAAM,kBAAkB,EAAE,SAAS,gBAAgB,EAAwD,CAAC;AAanH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,gBAAgB,CAE3E;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAEpE;AAID,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGlF;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAIhF;AAED,0GAA0G;AAC1G,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,MAAM,GAAG,oBAAoB,GACtC,oBAAoB,CAMtB;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMlF"}