@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.
- package/README.md +108 -40
- package/build/config.d.ts +9 -0
- package/build/config.d.ts.map +1 -0
- package/build/config.js +32 -0
- package/build/config.js.map +1 -0
- package/build/format.d.ts +6 -0
- package/build/format.d.ts.map +1 -0
- package/build/format.js +23 -0
- package/build/format.js.map +1 -0
- package/build/http-server.d.ts +15 -0
- package/build/http-server.d.ts.map +1 -0
- package/build/http-server.js +131 -0
- package/build/http-server.js.map +1 -0
- package/build/index.js +184 -69
- package/build/index.js.map +1 -1
- package/build/prompts.d.ts +23 -0
- package/build/prompts.d.ts.map +1 -0
- package/build/prompts.js +112 -0
- package/build/prompts.js.map +1 -0
- package/build/resources.d.ts +31 -0
- package/build/resources.d.ts.map +1 -0
- package/build/resources.js +66 -0
- package/build/resources.js.map +1 -0
- package/build/services/advanced-features.d.ts +19 -9
- package/build/services/advanced-features.d.ts.map +1 -1
- package/build/services/advanced-features.js +266 -191
- package/build/services/advanced-features.js.map +1 -1
- package/build/services/boot-wiki.d.ts +25 -0
- package/build/services/boot-wiki.d.ts.map +1 -0
- package/build/services/boot-wiki.js +103 -0
- package/build/services/boot-wiki.js.map +1 -0
- package/build/services/cache.d.ts +18 -3
- package/build/services/cache.d.ts.map +1 -1
- package/build/services/cache.js +84 -3
- package/build/services/cache.js.map +1 -1
- package/build/services/dependency-finder.d.ts +46 -0
- package/build/services/dependency-finder.d.ts.map +1 -0
- package/build/services/dependency-finder.js +181 -0
- package/build/services/dependency-finder.js.map +1 -0
- package/build/services/diagnosis.d.ts +46 -0
- package/build/services/diagnosis.d.ts.map +1 -0
- package/build/services/diagnosis.js +481 -0
- package/build/services/diagnosis.js.map +1 -0
- package/build/services/guides-list.d.ts +16 -0
- package/build/services/guides-list.d.ts.map +1 -0
- package/build/services/guides-list.js +45 -0
- package/build/services/guides-list.js.map +1 -0
- package/build/services/http.d.ts +21 -0
- package/build/services/http.d.ts.map +1 -0
- package/build/services/http.js +168 -0
- package/build/services/http.js.map +1 -0
- package/build/services/initializr.d.ts +41 -0
- package/build/services/initializr.d.ts.map +1 -0
- package/build/services/initializr.js +135 -0
- package/build/services/initializr.js.map +1 -0
- package/build/services/markdown.d.ts +56 -0
- package/build/services/markdown.d.ts.map +1 -0
- package/build/services/markdown.js +146 -0
- package/build/services/markdown.js.map +1 -0
- package/build/services/migration-sources.d.ts +13 -0
- package/build/services/migration-sources.d.ts.map +1 -0
- package/build/services/migration-sources.js +48 -0
- package/build/services/migration-sources.js.map +1 -0
- package/build/services/release-notes.d.ts +23 -0
- package/build/services/release-notes.d.ts.map +1 -0
- package/build/services/release-notes.js +94 -0
- package/build/services/release-notes.js.map +1 -0
- package/build/services/search-index.d.ts +33 -0
- package/build/services/search-index.d.ts.map +1 -0
- package/build/services/search-index.js +147 -0
- package/build/services/search-index.js.map +1 -0
- package/build/services/spring-projects-config.d.ts +98 -0
- package/build/services/spring-projects-config.d.ts.map +1 -0
- package/build/services/spring-projects-config.js +397 -0
- package/build/services/spring-projects-config.js.map +1 -0
- package/build/services/springboot-docs-optimized.d.ts +72 -21
- package/build/services/springboot-docs-optimized.d.ts.map +1 -1
- package/build/services/springboot-docs-optimized.js +354 -208
- package/build/services/springboot-docs-optimized.js.map +1 -1
- package/build/services/url.d.ts +15 -0
- package/build/services/url.d.ts.map +1 -0
- package/build/services/url.js +40 -0
- package/build/services/url.js.map +1 -0
- package/build/tools/index.d.ts +393 -2
- package/build/tools/index.d.ts.map +1 -1
- package/build/tools/index.js +188 -15
- package/build/tools/index.js.map +1 -1
- package/build/validation.d.ts +7 -0
- package/build/validation.d.ts.map +1 -0
- package/build/validation.js +50 -0
- package/build/validation.js.map +1 -0
- package/build/version.d.ts +3 -0
- package/build/version.d.ts.map +1 -0
- package/build/version.js +6 -0
- package/build/version.js.map +1 -0
- package/package.json +9 -7
- package/build/debug.d.ts +0 -3
- package/build/debug.d.ts.map +0 -1
- package/build/debug.js +0 -292
- package/build/debug.js.map +0 -1
- package/build/services/advanced-features-old.d.ts +0 -45
- package/build/services/advanced-features-old.d.ts.map +0 -1
- package/build/services/advanced-features-old.js +0 -792
- package/build/services/advanced-features-old.js.map +0 -1
- package/build/services/springboot-docs-optimized-old.d.ts +0 -55
- package/build/services/springboot-docs-optimized-old.d.ts.map +0 -1
- package/build/services/springboot-docs-optimized-old.js +0 -588
- package/build/services/springboot-docs-optimized-old.js.map +0 -1
- package/build/services/springboot-docs.d.ts +0 -65
- package/build/services/springboot-docs.d.ts.map +0 -1
- package/build/services/springboot-docs.js +0 -708
- package/build/services/springboot-docs.js.map +0 -1
|
@@ -0,0 +1,481 @@
|
|
|
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
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Caps
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
const MAX_TRACE_LINES = 400;
|
|
13
|
+
const MAX_TRACE_CHARS = 20000;
|
|
14
|
+
const MAX_LINE_CHARS = 500;
|
|
15
|
+
const MAX_ERROR_MESSAGE_CHARS = 2000;
|
|
16
|
+
const MAX_LINK_MESSAGE_CHARS = 300;
|
|
17
|
+
const IDENTIFIER = /^[A-Za-z0-9_.$]+$/;
|
|
18
|
+
const EXCEPTION_SUFFIXES = ['Exception', 'Error', 'Throwable'];
|
|
19
|
+
/** Qualified-name prefixes of framework / JDK frames, skipped when looking for application code */
|
|
20
|
+
const FRAMEWORK_FRAME_PREFIXES = [
|
|
21
|
+
'java.', 'javax.', 'jakarta.', 'jdk.', 'sun.', 'com.sun.', 'org.springframework.', 'org.apache.',
|
|
22
|
+
'org.hibernate.', 'com.fasterxml.', 'io.netty.', 'reactor.', 'org.aspectj.', 'net.bytebuddy.',
|
|
23
|
+
'org.junit.', 'org.eclipse.', 'org.jboss.', 'org.slf4j.', 'ch.qos.', 'com.zaxxer.',
|
|
24
|
+
];
|
|
25
|
+
/** Ordered (needle in frame name -> component) pairs for component inference */
|
|
26
|
+
const COMPONENT_HINTS = [
|
|
27
|
+
['org.springframework.security', 'security'],
|
|
28
|
+
['org.springframework.data', 'data'],
|
|
29
|
+
['org.hibernate', 'data'],
|
|
30
|
+
['jakarta.persistence', 'data'],
|
|
31
|
+
['javax.persistence', 'data'],
|
|
32
|
+
['org.springframework.jdbc', 'data'],
|
|
33
|
+
['org.springframework.orm', 'data'],
|
|
34
|
+
['org.springframework.boot.actuate', 'actuator'],
|
|
35
|
+
['org.springframework.web', 'web'],
|
|
36
|
+
['org.apache.catalina', 'web'],
|
|
37
|
+
['org.apache.tomcat', 'web'],
|
|
38
|
+
['com.fasterxml.jackson', 'web'],
|
|
39
|
+
['org.springframework.boot.context.properties', 'configuration'],
|
|
40
|
+
['org.springframework.boot.autoconfigure', 'configuration'],
|
|
41
|
+
['org.springframework.beans', 'startup'],
|
|
42
|
+
['org.springframework.context', 'startup'],
|
|
43
|
+
['org.springframework.boot.SpringApplication', 'startup'],
|
|
44
|
+
];
|
|
45
|
+
/** Applies the size caps and returns the bounded, NUL-free lines of a trace. */
|
|
46
|
+
function boundedLines(stackTrace) {
|
|
47
|
+
if (!stackTrace)
|
|
48
|
+
return [];
|
|
49
|
+
const text = stackTrace.slice(0, MAX_TRACE_CHARS).split('\0').join('');
|
|
50
|
+
const lines = [];
|
|
51
|
+
let start = 0;
|
|
52
|
+
while (lines.length < MAX_TRACE_LINES && start <= text.length) {
|
|
53
|
+
let end = text.indexOf('\n', start);
|
|
54
|
+
if (end === -1)
|
|
55
|
+
end = text.length;
|
|
56
|
+
let line = text.slice(start, Math.min(end, start + MAX_LINE_CHARS + 1)); // +1 room for a trailing \r
|
|
57
|
+
if (line.endsWith('\r'))
|
|
58
|
+
line = line.slice(0, -1);
|
|
59
|
+
lines.push(line.slice(0, MAX_LINE_CHARS).trim());
|
|
60
|
+
start = end + 1;
|
|
61
|
+
}
|
|
62
|
+
return lines;
|
|
63
|
+
}
|
|
64
|
+
/** Parses "at pkg.Class.method(File.java:12)"; undefined when the line is not a well-formed frame. */
|
|
65
|
+
function parseFrame(line) {
|
|
66
|
+
if (!line.startsWith('at '))
|
|
67
|
+
return undefined;
|
|
68
|
+
const open = line.indexOf('(');
|
|
69
|
+
if (open < 0 || line.indexOf(')', open) < 0)
|
|
70
|
+
return undefined;
|
|
71
|
+
let name = line.slice(3, open).trim();
|
|
72
|
+
// JDK 9+ frames may carry a module prefix: "java.base/java.util.List.get"
|
|
73
|
+
// Hidden/lambda classes ("Foo$$Lambda/0x...") keep the qualified name before the "/"
|
|
74
|
+
const slash = name.indexOf('/');
|
|
75
|
+
if (slash >= 0) {
|
|
76
|
+
const before = name.slice(0, slash);
|
|
77
|
+
const after = name.slice(name.lastIndexOf('/') + 1);
|
|
78
|
+
// Hidden classes ("com.acme.Foo/0x0000...method") also keep the part before the "/"
|
|
79
|
+
name = before.includes('$$Lambda') || after.startsWith('0x') || !after.includes('.') ? before : after;
|
|
80
|
+
}
|
|
81
|
+
if (name.length === 0 || !IDENTIFIER.test(name.replace(/<(init|clinit)>/, 'x')))
|
|
82
|
+
return undefined;
|
|
83
|
+
return { text: line, name };
|
|
84
|
+
}
|
|
85
|
+
/** Parses an exception header line ("Caused by: x.YException: msg"); undefined when it is not one. */
|
|
86
|
+
function parseHeader(line) {
|
|
87
|
+
if (line.length === 0 || line.startsWith('at ') || line.startsWith('...'))
|
|
88
|
+
return undefined;
|
|
89
|
+
let rest = line;
|
|
90
|
+
if (rest.startsWith('Caused by: ')) {
|
|
91
|
+
rest = rest.slice('Caused by: '.length);
|
|
92
|
+
}
|
|
93
|
+
else if (rest.startsWith('Exception in thread "')) {
|
|
94
|
+
const close = rest.indexOf('" ', 'Exception in thread "'.length);
|
|
95
|
+
if (close < 0)
|
|
96
|
+
return undefined;
|
|
97
|
+
rest = rest.slice(close + 2);
|
|
98
|
+
}
|
|
99
|
+
rest = rest.trimStart();
|
|
100
|
+
const colon = rest.indexOf(':');
|
|
101
|
+
const type = (colon < 0 ? rest : rest.slice(0, colon)).trim();
|
|
102
|
+
if (type.length === 0 || !IDENTIFIER.test(type))
|
|
103
|
+
return undefined;
|
|
104
|
+
const lastDot = type.lastIndexOf('.');
|
|
105
|
+
const simple = type.slice(lastDot + 1);
|
|
106
|
+
if (!EXCEPTION_SUFFIXES.some((s) => simple.endsWith(s)))
|
|
107
|
+
return undefined;
|
|
108
|
+
const message = colon < 0 ? '' : rest.slice(colon + 1).trim().slice(0, MAX_LINK_MESSAGE_CHARS);
|
|
109
|
+
return { type, message };
|
|
110
|
+
}
|
|
111
|
+
function parseTrace(stackTrace) {
|
|
112
|
+
const chain = [];
|
|
113
|
+
const frames = [];
|
|
114
|
+
for (const line of boundedLines(stackTrace)) {
|
|
115
|
+
const frame = parseFrame(line);
|
|
116
|
+
if (frame) {
|
|
117
|
+
frames.push(frame);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const header = parseHeader(line);
|
|
121
|
+
if (header)
|
|
122
|
+
chain.push(header);
|
|
123
|
+
}
|
|
124
|
+
return { chain, frames };
|
|
125
|
+
}
|
|
126
|
+
function isFrameworkFrame(name) {
|
|
127
|
+
return FRAMEWORK_FRAME_PREFIXES.some((p) => name.startsWith(p));
|
|
128
|
+
}
|
|
129
|
+
function inferComponent(frames) {
|
|
130
|
+
for (const frame of frames) {
|
|
131
|
+
for (const [needle, component] of COMPONENT_HINTS) {
|
|
132
|
+
if (frame.name.includes(needle))
|
|
133
|
+
return component;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
export function analyzeStackTrace(stackTrace) {
|
|
139
|
+
const { chain, frames } = parseTrace(stackTrace);
|
|
140
|
+
const analysis = { chain };
|
|
141
|
+
if (chain.length > 0) {
|
|
142
|
+
analysis.top = chain[0];
|
|
143
|
+
analysis.root = chain[chain.length - 1];
|
|
144
|
+
}
|
|
145
|
+
const appFrame = frames.find((f) => !isFrameworkFrame(f.name));
|
|
146
|
+
if (appFrame)
|
|
147
|
+
analysis.applicationFrame = appFrame.text;
|
|
148
|
+
const inferred = inferComponent(frames);
|
|
149
|
+
if (inferred)
|
|
150
|
+
analysis.inferredComponent = inferred;
|
|
151
|
+
return analysis;
|
|
152
|
+
}
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
// Rules
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
export const DIAGNOSIS_RULES = [
|
|
157
|
+
{
|
|
158
|
+
id: 'non-unique-bean',
|
|
159
|
+
needles: ['nouniquebeandefinitionexception', 'expected single matching bean but found'],
|
|
160
|
+
title: 'Several beans match the injection point',
|
|
161
|
+
checks: [
|
|
162
|
+
'mark one candidate `@Primary`',
|
|
163
|
+
'select explicitly with `@Qualifier` or a matching parameter name',
|
|
164
|
+
'inject `List<T>`/`Map<String, T>` to receive all candidates',
|
|
165
|
+
],
|
|
166
|
+
references: [{ project: 'framework', section: 'core', subsection: 'beans' }],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: 'missing-bean',
|
|
170
|
+
needles: ['nosuchbeandefinitionexception', 'no qualifying bean of type'],
|
|
171
|
+
title: 'A required bean is missing',
|
|
172
|
+
checks: [
|
|
173
|
+
'the class is outside the `@SpringBootApplication` package or lacks `@Component`/`@Service`/`@Repository`',
|
|
174
|
+
'the `@Bean` method or auto-configuration condition is not met (start with `--debug` to read the conditions report)',
|
|
175
|
+
'a profile or `@ConditionalOn…` excludes it',
|
|
176
|
+
'a starter dependency is missing',
|
|
177
|
+
],
|
|
178
|
+
references: [
|
|
179
|
+
{ project: 'framework', section: 'core', subsection: 'beans' },
|
|
180
|
+
{ project: 'boot', section: 'using' },
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: 'circular-dependency',
|
|
185
|
+
needles: ['beancurrentlyincreationexception', 'form a cycle', 'circular dependency', 'circular reference'],
|
|
186
|
+
title: 'Circular dependency between beans',
|
|
187
|
+
checks: [
|
|
188
|
+
'extract the shared logic into a third bean',
|
|
189
|
+
'break the cycle with `@Lazy` on one injection point or setter injection',
|
|
190
|
+
'Spring Boot 2.6+ forbids circular references by default — `spring.main.allow-circular-references=true` is a workaround, not a fix',
|
|
191
|
+
],
|
|
192
|
+
references: [
|
|
193
|
+
{ project: 'framework', section: 'core', subsection: 'beans' },
|
|
194
|
+
{ project: 'boot', section: 'application-properties' },
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
id: 'datasource',
|
|
199
|
+
needles: ['failed to configure a datasource', 'cannot determine embedded database driver class'],
|
|
200
|
+
title: 'No usable DataSource',
|
|
201
|
+
checks: [
|
|
202
|
+
'set `spring.datasource.url`, `username` and `password`',
|
|
203
|
+
'add the JDBC driver (or an embedded database such as H2) to the classpath',
|
|
204
|
+
'exclude `DataSourceAutoConfiguration` if the application needs no database',
|
|
205
|
+
],
|
|
206
|
+
references: [
|
|
207
|
+
{ project: 'boot', section: 'data' },
|
|
208
|
+
{ project: 'boot', section: 'application-properties' },
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: 'port-in-use',
|
|
213
|
+
needles: ['was already in use', 'port already in use', 'address already in use'],
|
|
214
|
+
title: 'The server port is already taken',
|
|
215
|
+
checks: [
|
|
216
|
+
'stop the process holding the port (for example `lsof -i :8080`)',
|
|
217
|
+
'change `server.port`, or use `server.port=0` for a random port',
|
|
218
|
+
],
|
|
219
|
+
references: [
|
|
220
|
+
{ project: 'boot', section: 'web' },
|
|
221
|
+
{ project: 'boot', section: 'application-properties' },
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
id: 'config-binding',
|
|
226
|
+
needles: ['configurationpropertiesbindexception', 'failed to bind properties', 'binding to target'],
|
|
227
|
+
title: 'Configuration properties cannot be bound',
|
|
228
|
+
checks: [
|
|
229
|
+
'check the property name and value type (kebab-case is the canonical form)',
|
|
230
|
+
'check `@Validated` constraints and required constructor-bound values',
|
|
231
|
+
'read the "Action" hint printed with the failure',
|
|
232
|
+
],
|
|
233
|
+
references: [
|
|
234
|
+
{ project: 'boot', section: 'features' },
|
|
235
|
+
{ project: 'boot', section: 'application-properties' },
|
|
236
|
+
],
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
id: 'http-message-not-readable',
|
|
240
|
+
needles: ['httpmessagenotreadableexception', 'json parse error', 'required request body is missing'],
|
|
241
|
+
title: 'The request body cannot be read',
|
|
242
|
+
checks: [
|
|
243
|
+
'the JSON does not match the target type (types, enums, unknown properties)',
|
|
244
|
+
'the `Content-Type` is not `application/json`',
|
|
245
|
+
'an empty body is sent to a `@RequestBody` that is required',
|
|
246
|
+
],
|
|
247
|
+
references: [
|
|
248
|
+
{ project: 'framework', section: 'web' },
|
|
249
|
+
{ project: 'boot', section: 'web' },
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: 'lazy-initialization',
|
|
254
|
+
needles: ['lazyinitializationexception', 'could not initialize proxy', 'no session'],
|
|
255
|
+
title: 'A lazy association is accessed outside a session',
|
|
256
|
+
checks: [
|
|
257
|
+
'access the association inside a `@Transactional` boundary',
|
|
258
|
+
'load it with a fetch join or `@EntityGraph`',
|
|
259
|
+
'return a DTO projection instead of entities',
|
|
260
|
+
'do not rely on open-in-view',
|
|
261
|
+
],
|
|
262
|
+
references: [
|
|
263
|
+
{ project: 'data-jpa', section: 'jpa' },
|
|
264
|
+
{ project: 'boot', section: 'data' },
|
|
265
|
+
],
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
id: 'no-transaction',
|
|
269
|
+
needles: ['no entitymanager with actual transaction available', 'transactionrequiredexception'],
|
|
270
|
+
title: 'A transaction is required',
|
|
271
|
+
checks: [
|
|
272
|
+
'annotate the service method with `@Transactional`',
|
|
273
|
+
'calls must go through the Spring proxy (no self-invocation, not a private method)',
|
|
274
|
+
'modifying queries need `@Modifying` and a transaction',
|
|
275
|
+
],
|
|
276
|
+
references: [
|
|
277
|
+
{ project: 'data-jpa', section: 'jpa', subsection: 'transactions' },
|
|
278
|
+
{ project: 'framework', section: 'data-access' },
|
|
279
|
+
],
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
id: 'classpath',
|
|
283
|
+
needles: ['classnotfoundexception', 'noclassdeffounderror', 'nosuchmethoderror', 'nosuchfielderror', 'abstractmethoderror'],
|
|
284
|
+
title: 'Missing class or incompatible library versions',
|
|
285
|
+
checks: [
|
|
286
|
+
'inspect the dependency tree (`mvn dependency:tree` or `gradle dependencies`)',
|
|
287
|
+
"let Spring Boot's dependency management choose versions instead of overriding them",
|
|
288
|
+
'do a clean build',
|
|
289
|
+
'if the text mentions `javax.`, it may be the Jakarta migration — see `get_migration_guide` with version `3.0` and section `jakarta`',
|
|
290
|
+
],
|
|
291
|
+
references: [{ project: 'boot', section: 'using' }],
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: 'access-denied',
|
|
295
|
+
needles: ['accessdeniedexception', 'invalid csrf token', 'could not verify the provided csrf token'],
|
|
296
|
+
title: 'Access denied by Spring Security',
|
|
297
|
+
checks: [
|
|
298
|
+
'state-changing requests need the CSRF token unless CSRF is deliberately disabled for a stateless API',
|
|
299
|
+
'check the order of the `requestMatchers` rules',
|
|
300
|
+
'roles need the `ROLE_` prefix as an authority and `hasRole` adds it for you',
|
|
301
|
+
],
|
|
302
|
+
references: [
|
|
303
|
+
{ project: 'security', section: 'authorization' },
|
|
304
|
+
{ project: 'security', section: 'exploits' },
|
|
305
|
+
],
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
id: 'unsatisfied-dependency',
|
|
309
|
+
needles: ['unsatisfieddependencyexception'],
|
|
310
|
+
title: 'Dependency injection failed',
|
|
311
|
+
checks: [
|
|
312
|
+
'this exception only wraps the real failure: read the root cause above',
|
|
313
|
+
'typical causes are a missing or ambiguous bean, or a failing `@Bean` method',
|
|
314
|
+
],
|
|
315
|
+
references: [{ project: 'framework', section: 'core', subsection: 'beans' }],
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
id: 'bean-creation',
|
|
319
|
+
needles: ['beancreationexception'],
|
|
320
|
+
title: 'A bean could not be created',
|
|
321
|
+
checks: [
|
|
322
|
+
'the exception wraps the cause: read the root cause above',
|
|
323
|
+
'check the constructor, `@PostConstruct` and the `@Bean` method for failures',
|
|
324
|
+
],
|
|
325
|
+
references: [{ project: 'framework', section: 'core', subsection: 'beans' }],
|
|
326
|
+
},
|
|
327
|
+
];
|
|
328
|
+
/** References appended per component, after those of the matched rules */
|
|
329
|
+
const COMPONENT_REFERENCES = {
|
|
330
|
+
startup: [{ project: 'boot', section: 'using' }],
|
|
331
|
+
web: [{ project: 'boot', section: 'web' }],
|
|
332
|
+
data: [{ project: 'boot', section: 'data' }],
|
|
333
|
+
security: [{ project: 'security', section: 'servlet' }],
|
|
334
|
+
actuator: [{ project: 'boot', section: 'actuator' }],
|
|
335
|
+
configuration: [
|
|
336
|
+
{ project: 'boot', section: 'features' },
|
|
337
|
+
{ project: 'boot', section: 'application-properties' },
|
|
338
|
+
],
|
|
339
|
+
};
|
|
340
|
+
/** Display titles of every reference the module can emit (keyed "project/section[/subsection]") */
|
|
341
|
+
const REFERENCE_TITLES = {
|
|
342
|
+
'boot/features': 'Spring Boot: Core Features',
|
|
343
|
+
'boot/using': 'Spring Boot: Using Spring Boot',
|
|
344
|
+
'boot/web': 'Spring Boot: Web',
|
|
345
|
+
'boot/data': 'Spring Boot: Data',
|
|
346
|
+
'boot/actuator': 'Spring Boot: Actuator',
|
|
347
|
+
'boot/application-properties': 'Spring Boot: Application Properties',
|
|
348
|
+
'boot/deployment': 'Spring Boot: Deployment',
|
|
349
|
+
'framework/core/beans': 'Spring Framework: Core — Beans',
|
|
350
|
+
'framework/web': 'Spring Framework: Web',
|
|
351
|
+
'framework/data-access': 'Spring Framework: Data Access',
|
|
352
|
+
'data-jpa/jpa': 'Spring Data JPA: Reference',
|
|
353
|
+
'data-jpa/jpa/transactions': 'Spring Data JPA: Transactionality',
|
|
354
|
+
'security/servlet': 'Spring Security: Servlet Applications',
|
|
355
|
+
'security/authentication': 'Spring Security: Authentication',
|
|
356
|
+
'security/authorization': 'Spring Security: Authorization',
|
|
357
|
+
'security/exploits': 'Spring Security: Protection Against Exploits',
|
|
358
|
+
};
|
|
359
|
+
/**
|
|
360
|
+
* "forbidden" alone is too broad (a 403 from an external API is not a Spring Security issue):
|
|
361
|
+
* it only counts when the exception header mentioning it is thrown from a Spring Security frame.
|
|
362
|
+
*/
|
|
363
|
+
function hasSecurityForbidden(stackTrace) {
|
|
364
|
+
let forbiddenHeader = false;
|
|
365
|
+
for (const line of boundedLines(stackTrace)) {
|
|
366
|
+
const frame = parseFrame(line);
|
|
367
|
+
if (frame) {
|
|
368
|
+
if (forbiddenHeader && frame.name.startsWith('org.springframework.security.'))
|
|
369
|
+
return true;
|
|
370
|
+
forbiddenHeader = false; // only the first frame of the exception counts
|
|
371
|
+
}
|
|
372
|
+
else if (parseHeader(line)) {
|
|
373
|
+
forbiddenHeader = line.toLowerCase().includes('forbidden');
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Returns the rules whose needles appear (lower-cased) in the analyzed text:
|
|
380
|
+
* the error message plus the exception header lines of the trace. Order = table order.
|
|
381
|
+
*/
|
|
382
|
+
export function matchRules(errorMessage, analysis, stackTrace) {
|
|
383
|
+
const parts = [(errorMessage ?? '').slice(0, MAX_ERROR_MESSAGE_CHARS)];
|
|
384
|
+
if (stackTrace) {
|
|
385
|
+
// Use the full (capped) header lines so legacy "; nested exception is X" text is searchable
|
|
386
|
+
for (const line of boundedLines(stackTrace)) {
|
|
387
|
+
if (parseHeader(line))
|
|
388
|
+
parts.push(line);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
for (const link of analysis.chain)
|
|
393
|
+
parts.push(`${link.type}: ${link.message}`);
|
|
394
|
+
}
|
|
395
|
+
const text = parts.join('\n').toLowerCase();
|
|
396
|
+
const securityForbidden = stackTrace !== undefined && hasSecurityForbidden(stackTrace);
|
|
397
|
+
const matched = DIAGNOSIS_RULES.filter((rule) => rule.needles.some((n) => text.includes(n)) || (rule.id === 'access-denied' && securityForbidden));
|
|
398
|
+
// NoUniqueBeanDefinitionException messages also read "No qualifying bean of type ...":
|
|
399
|
+
// that is not a missing bean.
|
|
400
|
+
if (matched.some((r) => r.id === 'non-unique-bean')) {
|
|
401
|
+
return matched.filter((r) => r.id !== 'missing-bean');
|
|
402
|
+
}
|
|
403
|
+
return matched;
|
|
404
|
+
}
|
|
405
|
+
// ---------------------------------------------------------------------------
|
|
406
|
+
// Rendering
|
|
407
|
+
// ---------------------------------------------------------------------------
|
|
408
|
+
const BOOT_DOCS_URL = 'https://docs.spring.io/spring-boot/index.html';
|
|
409
|
+
function referenceKey(ref) {
|
|
410
|
+
return `${ref.project}/${ref.section}${ref.subsection ? `/${ref.subsection}` : ''}`;
|
|
411
|
+
}
|
|
412
|
+
function renderReferences(refs, config) {
|
|
413
|
+
const seen = new Set();
|
|
414
|
+
const lines = [];
|
|
415
|
+
for (const ref of refs) {
|
|
416
|
+
if (!config.validateSection(ref.project, ref.section))
|
|
417
|
+
continue;
|
|
418
|
+
const url = config.buildReferenceUrl(ref.project, ref.section, ref.subsection);
|
|
419
|
+
if (seen.has(url))
|
|
420
|
+
continue;
|
|
421
|
+
seen.add(url);
|
|
422
|
+
const title = REFERENCE_TITLES[referenceKey(ref)] ?? `${ref.project}: ${ref.section}`;
|
|
423
|
+
const sub = ref.subsection ? `, subsection="${ref.subsection}"` : '';
|
|
424
|
+
lines.push(`- ${title} — ${url} (get_spring_reference: project="${ref.project}", section="${ref.section}"${sub})`);
|
|
425
|
+
}
|
|
426
|
+
return lines;
|
|
427
|
+
}
|
|
428
|
+
function formatLink(link) {
|
|
429
|
+
return link.message ? `${link.type}: ${link.message}` : link.type;
|
|
430
|
+
}
|
|
431
|
+
export function renderDiagnosis(input, config = springProjectsConfig) {
|
|
432
|
+
const errorMessage = (input.errorMessage ?? '').slice(0, MAX_ERROR_MESSAGE_CHARS);
|
|
433
|
+
const analysis = analyzeStackTrace(input.stackTrace);
|
|
434
|
+
const rules = matchRules(errorMessage, analysis, input.stackTrace);
|
|
435
|
+
let component = input.component?.trim() ? input.component.trim().slice(0, 100) : undefined;
|
|
436
|
+
let inferred = false;
|
|
437
|
+
if (!component && analysis.inferredComponent) {
|
|
438
|
+
component = analysis.inferredComponent;
|
|
439
|
+
inferred = true;
|
|
440
|
+
}
|
|
441
|
+
const out = ['# Spring Boot Issue Diagnosis', '', `**Error:** ${errorMessage}`];
|
|
442
|
+
if (component) {
|
|
443
|
+
out.push(`**Component:** ${component}${inferred ? ' (inferred from the stack trace)' : ''}`);
|
|
444
|
+
}
|
|
445
|
+
out.push('');
|
|
446
|
+
if (analysis.top && analysis.root) {
|
|
447
|
+
out.push('## Exception Summary', '', `**Exception:** ${formatLink(analysis.top)}`);
|
|
448
|
+
if (analysis.chain.length > 1)
|
|
449
|
+
out.push(`**Root cause:** ${formatLink(analysis.root)}`);
|
|
450
|
+
if (analysis.applicationFrame)
|
|
451
|
+
out.push(`**Your code:** \`${analysis.applicationFrame}\``);
|
|
452
|
+
out.push('');
|
|
453
|
+
}
|
|
454
|
+
out.push('## Likely Cause', '');
|
|
455
|
+
if (rules.length === 0) {
|
|
456
|
+
out.push('No known pattern matched this error. Read the root cause above (or the error message) and use the references below.', '');
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
for (const rule of rules) {
|
|
460
|
+
out.push(`### ${rule.title}`, '', 'The error text matches a known pattern for this problem.', '', 'What to check:');
|
|
461
|
+
for (const check of rule.checks)
|
|
462
|
+
out.push(`- ${check}`);
|
|
463
|
+
out.push('');
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
const refs = rules.flatMap((r) => r.references);
|
|
467
|
+
const componentRefs = component ? COMPONENT_REFERENCES[component.toLowerCase()] : undefined;
|
|
468
|
+
if (componentRefs && Object.prototype.hasOwnProperty.call(COMPONENT_REFERENCES, component.toLowerCase())) {
|
|
469
|
+
refs.push(...componentRefs);
|
|
470
|
+
}
|
|
471
|
+
const refLines = renderReferences(refs, config);
|
|
472
|
+
out.push('## Reference Documentation', '');
|
|
473
|
+
if (refLines.length > 0)
|
|
474
|
+
out.push(...refLines);
|
|
475
|
+
else
|
|
476
|
+
out.push(`- Spring Boot documentation — ${BOOT_DOCS_URL}`);
|
|
477
|
+
out.push('');
|
|
478
|
+
out.push('## General Troubleshooting Steps', '', `1. Check the Spring Boot documentation: ${BOOT_DOCS_URL}`, '2. Search Spring Boot issues: https://github.com/spring-projects/spring-boot/issues', '3. Enable debug logging: `logging.level.org.springframework=DEBUG`', '4. Check actuator health endpoint: `/actuator/health`', '');
|
|
479
|
+
return out.join('\n');
|
|
480
|
+
}
|
|
481
|
+
//# sourceMappingURL=diagnosis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnosis.js","sourceRoot":"","sources":["../../src/services/diagnosis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const SPRING_GUIDES_DATA_URL = "https://spring.io/page-data/guides/page-data.json";
|
|
2
|
+
export interface SpringGuideEntry {
|
|
3
|
+
type: 'spring-guide';
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
category: string;
|
|
7
|
+
url: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Lists the spring.io guides, optionally filtered on category (case-insensitive substring).
|
|
11
|
+
* The /guides page is rendered client-side (Gatsby): its HTML holds no guide links, the list
|
|
12
|
+
* lives in the page-data JSON that the page itself loads. Entries without title or path are
|
|
13
|
+
* skipped; an unexpected payload throws (callers must not cache it).
|
|
14
|
+
*/
|
|
15
|
+
export declare function fetchSpringGuidesList(category?: string): Promise<SpringGuideEntry[]>;
|
|
16
|
+
//# sourceMappingURL=guides-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides-list.d.ts","sourceRoot":"","sources":["../../src/services/guides-list.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB,sDAAsD,CAAC;AAE1F,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAoC1F"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { fetchWithRetry } from './http.js';
|
|
2
|
+
import { absoluteSpringUrl } from './url.js';
|
|
3
|
+
export const SPRING_GUIDES_DATA_URL = 'https://spring.io/page-data/guides/page-data.json';
|
|
4
|
+
/**
|
|
5
|
+
* Lists the spring.io guides, optionally filtered on category (case-insensitive substring).
|
|
6
|
+
* The /guides page is rendered client-side (Gatsby): its HTML holds no guide links, the list
|
|
7
|
+
* lives in the page-data JSON that the page itself loads. Entries without title or path are
|
|
8
|
+
* skipped; an unexpected payload throws (callers must not cache it).
|
|
9
|
+
*/
|
|
10
|
+
export async function fetchSpringGuidesList(category) {
|
|
11
|
+
const response = await fetchWithRetry(SPRING_GUIDES_DATA_URL);
|
|
12
|
+
if (!response.ok) {
|
|
13
|
+
throw new Error('Unable to access Spring guides page');
|
|
14
|
+
}
|
|
15
|
+
let nodes;
|
|
16
|
+
try {
|
|
17
|
+
nodes = JSON.parse(await response.text())?.result?.data?.guides?.nodes;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
nodes = undefined;
|
|
21
|
+
}
|
|
22
|
+
if (!Array.isArray(nodes)) {
|
|
23
|
+
throw new Error('Unexpected format of the Spring guides data (no guides list found)');
|
|
24
|
+
}
|
|
25
|
+
const guides = [];
|
|
26
|
+
for (const node of nodes) {
|
|
27
|
+
const title = typeof node?.title === 'string' ? node.title.trim() : '';
|
|
28
|
+
const url = absoluteSpringUrl(typeof node?.path === 'string' ? node.path : undefined);
|
|
29
|
+
if (!title || !url)
|
|
30
|
+
continue;
|
|
31
|
+
const categories = Array.isArray(node.category) ? node.category.map(String) : [];
|
|
32
|
+
const guideCategory = categories.join(', ');
|
|
33
|
+
if (category && !guideCategory.toLowerCase().includes(category.toLowerCase()))
|
|
34
|
+
continue;
|
|
35
|
+
guides.push({
|
|
36
|
+
type: 'spring-guide',
|
|
37
|
+
title,
|
|
38
|
+
description: (typeof node.description === 'string' && node.description.trim()) || 'Spring guide',
|
|
39
|
+
category: guideCategory || 'General',
|
|
40
|
+
url,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return guides;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=guides-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides-list.js","sourceRoot":"","sources":["../../src/services/guides-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,CAAC,MAAM,sBAAsB,GAAG,mDAAmD,CAAC;AAU1F;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,QAAiB;IAC3D,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAE9D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,SAAS,CAAC;IACpB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,KAAc,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,OAAO,IAAI,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACtF,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG;YAAE,SAAS;QAE7B,MAAM,UAAU,GAAa,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,MAAM,aAAa,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,QAAQ,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YAAE,SAAS;QAExF,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,cAAc;YACpB,KAAK;YACL,WAAW,EAAE,CAAC,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,IAAI,cAAc;YAChG,QAAQ,EAAE,aAAa,IAAI,SAAS;YACpC,GAAG;SACJ,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface FetchResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
status: number;
|
|
4
|
+
text(): Promise<string>;
|
|
5
|
+
json(): Promise<any>;
|
|
6
|
+
/** Set for an api.github.com response refused because of a rate limit (never retried). */
|
|
7
|
+
rateLimit?: GitHubRateLimit;
|
|
8
|
+
}
|
|
9
|
+
export interface GitHubRateLimit {
|
|
10
|
+
retryAfterSeconds?: number;
|
|
11
|
+
resetAt?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Clear message for a GitHub rate-limited response (no waiting, no secret in it). */
|
|
14
|
+
export declare function githubRateLimitMessage(rateLimit?: GitHubRateLimit): string;
|
|
15
|
+
export declare const REQUEST_TIMEOUT = 10000;
|
|
16
|
+
export declare const MAX_RETRIES = 3;
|
|
17
|
+
export declare const MAX_RESPONSE_BYTES: number;
|
|
18
|
+
export declare const MAX_REDIRECTS = 5;
|
|
19
|
+
export declare const ALLOWED_REDIRECT_HOSTS: ReadonlySet<string>;
|
|
20
|
+
export declare function fetchWithRetry(url: string, timeout?: number, retries?: number): Promise<FetchResult>;
|
|
21
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/services/http.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IACrB,0FAA0F;IAC1F,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAUD,sFAAsF;AACtF,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,eAAe,GAAG,MAAM,CAY1E;AAcD,eAAO,MAAM,eAAe,QAAQ,CAAC;AACrC,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,kBAAkB,QAAkB,CAAC;AAElD,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAMrD,CAAC;AAYH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,SAAkB,EAAE,OAAO,SAAc,GAAG,OAAO,CAAC,WAAW,CAAC,CAyGxH"}
|