te.js 2.1.0 → 2.1.2

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 (70) hide show
  1. package/README.md +197 -196
  2. package/auto-docs/analysis/handler-analyzer.js +58 -58
  3. package/auto-docs/analysis/source-resolver.js +101 -101
  4. package/auto-docs/constants.js +37 -37
  5. package/auto-docs/docs-llm/index.js +7 -7
  6. package/auto-docs/docs-llm/prompts.js +222 -222
  7. package/auto-docs/docs-llm/provider.js +132 -132
  8. package/auto-docs/index.js +146 -146
  9. package/auto-docs/openapi/endpoint-processor.js +277 -277
  10. package/auto-docs/openapi/generator.js +107 -107
  11. package/auto-docs/openapi/level3.js +131 -131
  12. package/auto-docs/openapi/spec-builders.js +244 -244
  13. package/auto-docs/ui/docs-ui.js +186 -186
  14. package/auto-docs/utils/logger.js +17 -17
  15. package/auto-docs/utils/strip-usage.js +10 -10
  16. package/cli/docs-command.js +315 -315
  17. package/cli/fly-command.js +71 -71
  18. package/cli/index.js +56 -56
  19. package/cors/index.js +71 -0
  20. package/database/index.js +165 -165
  21. package/database/mongodb.js +146 -146
  22. package/database/redis.js +201 -201
  23. package/docs/README.md +36 -36
  24. package/docs/ammo.md +362 -362
  25. package/docs/api-reference.md +490 -490
  26. package/docs/auto-docs.md +216 -216
  27. package/docs/cli.md +152 -152
  28. package/docs/configuration.md +275 -275
  29. package/docs/database.md +390 -390
  30. package/docs/error-handling.md +438 -438
  31. package/docs/file-uploads.md +333 -333
  32. package/docs/getting-started.md +214 -214
  33. package/docs/middleware.md +355 -355
  34. package/docs/rate-limiting.md +393 -393
  35. package/docs/routing.md +302 -302
  36. package/lib/llm/client.js +73 -0
  37. package/lib/llm/index.js +7 -0
  38. package/lib/llm/parse.js +89 -0
  39. package/package.json +64 -62
  40. package/rate-limit/algorithms/fixed-window.js +141 -141
  41. package/rate-limit/algorithms/sliding-window.js +147 -147
  42. package/rate-limit/algorithms/token-bucket.js +115 -115
  43. package/rate-limit/base.js +165 -165
  44. package/rate-limit/index.js +147 -147
  45. package/rate-limit/storage/base.js +104 -104
  46. package/rate-limit/storage/memory.js +101 -101
  47. package/rate-limit/storage/redis.js +88 -88
  48. package/server/ammo/body-parser.js +220 -220
  49. package/server/ammo/dispatch-helper.js +103 -103
  50. package/server/ammo/enhancer.js +57 -57
  51. package/server/ammo.js +454 -415
  52. package/server/endpoint.js +97 -74
  53. package/server/error.js +9 -9
  54. package/server/errors/code-context.js +125 -125
  55. package/server/errors/llm-error-service.js +140 -140
  56. package/server/files/helper.js +33 -33
  57. package/server/files/uploader.js +143 -143
  58. package/server/handler.js +158 -119
  59. package/server/target.js +185 -175
  60. package/server/targets/middleware-validator.js +22 -22
  61. package/server/targets/path-validator.js +21 -21
  62. package/server/targets/registry.js +160 -160
  63. package/server/targets/shoot-validator.js +21 -21
  64. package/te.js +428 -402
  65. package/utils/auto-register.js +17 -17
  66. package/utils/configuration.js +64 -64
  67. package/utils/errors-llm-config.js +84 -84
  68. package/utils/request-logger.js +43 -43
  69. package/utils/status-codes.js +82 -82
  70. package/utils/tejas-entrypoint-html.js +18 -18
@@ -1,222 +1,222 @@
1
- /**
2
- * Prompt builders for auto-documentation LLM calls.
3
- * Each function returns the prompt string; provider calls analyze(prompt).
4
- */
5
-
6
- import {
7
- PROMPT_HANDLER_SLICE,
8
- PROMPT_HANDLER_SLICE_WITH_DEPS,
9
- PROMPT_DEPENDENCY_SLICE,
10
- PROMPT_GROUP_CODE_LIMIT,
11
- PROMPT_GROUP_CODE_LIMIT_WITH_DEPS,
12
- PROMPT_GROUP_SNIPPET_CHARS,
13
- } from '../constants.js';
14
-
15
- /** Shared rule block for enhance prompts: required vs optional and format. */
16
- const ENHANCE_RULES = `CRITICAL - Required vs optional: Infer from the code which parameters are required and which are optional. Look for: validation that throws or returns error when missing; checks like !payload.field or !ammo.payload.x; required in schema or JSDoc; or optional/undefined/default handling. For every body property and every query parameter you list, you MUST set "required": true or "required": false explicitly. Do not omit "required".
17
-
18
- Respond with ONLY a single JSON object (no markdown, no explanation). Use this shape:`;
19
-
20
- /** JSON shape example for single-endpoint enhance. */
21
- const ENHANCE_RESPONSE_SHAPE = `{
22
- "summary": "Short one-line description",
23
- "description": "Optional longer description",
24
- "request": {
25
- "body": {
26
- "fieldName": { "type": "string", "description": "...", "required": true }
27
- },
28
- "query": {
29
- "paramName": { "type": "string", "description": "...", "required": false }
30
- }
31
- },
32
- "response": { "200": { "description": "Success" }, "201": { "description": "Created" } }
33
- }
34
- - For every field in request.body and request.query set "required": true or "required": false based on code context.
35
- - Include "format" when relevant (e.g. "email", "date-time", "binary").
36
- - Omit "request" or "response" if not applicable. Keep summary under 80 characters.`;
37
-
38
- /** JSON shape example for per-method enhance. */
39
- const PER_METHOD_RESPONSE_SHAPE = `{
40
- "get": { "summary": "...", "description": "...", "response": { "200": { "description": "..." } } },
41
- "put": { "summary": "...", "description": "...", "request": { "body": { "name": { "type": "string", "required": true }, "email": { "type": "string", "format": "email", "required": true } } }, "response": { "200": { "description": "..." } } },
42
- "delete": { "summary": "...", "description": "...", "response": { "204": { "description": "..." } } }
43
- }`;
44
-
45
- /**
46
- * Build handler snippet and related-files section for endpoint prompts. Single place for limits and formatting.
47
- * @param {object} endpointInfo - { handlerSource?, dependencySources? }
48
- * @returns {{ handlerSnippet: string, relatedSection: string }}
49
- */
50
- export function buildEndpointPromptContext(endpointInfo) {
51
- const { handlerSource = '', dependencySources = '' } = endpointInfo;
52
- const handlerLimit = dependencySources ? PROMPT_HANDLER_SLICE_WITH_DEPS : PROMPT_HANDLER_SLICE;
53
- const handlerSnippet = (handlerSource || '').slice(0, handlerLimit);
54
- const relatedSection = dependencySources
55
- ? `
56
-
57
- Related source files (target and dependencies):
58
- \`\`\`javascript
59
- ${dependencySources.slice(0, PROMPT_DEPENDENCY_SLICE)}
60
- \`\`\`
61
- `
62
- : '';
63
- return { handlerSnippet, relatedSection };
64
- }
65
-
66
- /**
67
- * Build prompt for summarizing a target group (tag name + description).
68
- * @param {string} groupId
69
- * @param {Array<object>} endpointsInfo - { path, methods, summary?, description?, handlerSource?, dependencySources? }
70
- * @param {string} [dependencySources]
71
- * @returns {string}
72
- */
73
- export function buildSummarizeGroupPrompt(groupId, endpointsInfo, dependencySources = '') {
74
- if (!endpointsInfo?.length) return '';
75
- const list = endpointsInfo
76
- .map((e) => `- ${e.path} [${(e.methods || []).join(', ')}]: ${e.summary || e.description || '—'}`)
77
- .join('\n');
78
- const codeSnippets = endpointsInfo
79
- .filter((e) => e.handlerSource)
80
- .map((e) => `Path ${e.path}:\n${(e.handlerSource || '').slice(0, PROMPT_GROUP_SNIPPET_CHARS)}`)
81
- .join('\n\n');
82
- const codeLimit = dependencySources ? PROMPT_GROUP_CODE_LIMIT_WITH_DEPS : PROMPT_GROUP_CODE_LIMIT;
83
- const { relatedSection } = buildEndpointPromptContext({ dependencySources });
84
- return `You are an API documentation assistant. A single source file (group) exposes these endpoints:
85
-
86
- Group id: ${groupId}
87
-
88
- Endpoints:
89
- ${list}
90
-
91
- Handler code (excerpts):
92
- \`\`\`javascript
93
- ${codeSnippets.slice(0, codeLimit)}
94
- \`\`\`
95
- ${relatedSection}
96
-
97
- Write a SHORT paragraph (2–4 sentences) describing what this group of endpoints does as a whole. Focus on the domain and purpose, not the HTTP details. Respond with ONLY a single JSON object:
98
- { "name": "Human-readable group name", "description": "Your paragraph here." }
99
- Use "name" as a short label (e.g. "Users", "Health & routes"); keep description under 300 characters.`;
100
- }
101
-
102
- /**
103
- * Build prompt for enhancing a single endpoint (OpenAPI-style metadata).
104
- * @param {object} endpointInfo - { path, methods, metadata?, handlerSource?, dependencySources? }
105
- * @returns {string}
106
- */
107
- export function buildEnhanceEndpointPrompt(endpointInfo) {
108
- const { path, methods = [], metadata = {} } = endpointInfo;
109
- const { handlerSnippet, relatedSection } = buildEndpointPromptContext(endpointInfo);
110
- const existing = Object.keys(metadata).length ? `Existing metadata: ${JSON.stringify(metadata)}\n` : '';
111
- return `You are an API documentation assistant. Given an HTTP endpoint and its source code, suggest OpenAPI-style metadata.
112
-
113
- Endpoint path: ${path}
114
- HTTP methods: ${methods.join(', ')}
115
- ${existing}Handler source (for context):
116
- \`\`\`javascript
117
- ${handlerSnippet}
118
- \`\`\`
119
- ${relatedSection}
120
-
121
- ${ENHANCE_RULES}
122
- ${ENHANCE_RESPONSE_SHAPE}`;
123
- }
124
-
125
- /**
126
- * Build prompt for method-specific endpoint metadata (per-method summary, request, response).
127
- * @param {object} endpointInfo - { path, methods, metadata?, handlerSource?, dependencySources? }
128
- * @returns {string}
129
- */
130
- export function buildEnhanceEndpointPerMethodPrompt(endpointInfo) {
131
- const { path, methods = [], metadata = {} } = endpointInfo;
132
- const { handlerSnippet, relatedSection } = buildEndpointPromptContext(endpointInfo);
133
- const methodsLower = methods.map((m) => m.toLowerCase());
134
- const existing = Object.keys(metadata).length ? `Existing metadata: ${JSON.stringify(metadata)}\n` : '';
135
- return `You are an API documentation assistant. This endpoint supports multiple HTTP methods. Provide METHOD-SPECIFIC metadata so each method is documented accurately.
136
-
137
- Endpoint path: ${path}
138
- HTTP methods: ${methods.join(', ')}
139
-
140
- ${existing}Handler source (for context):
141
- \`\`\`javascript
142
- ${handlerSnippet}
143
- \`\`\`
144
- ${relatedSection}
145
-
146
- RULES:
147
- - Return ONE JSON object keyed by lowercase method name: "get", "put", "post", "delete", "patch", "head", "options".
148
- - Include a key for EACH of: ${methodsLower.map((m) => `"${m}"`).join(', ')}.
149
- - For each method provide: "summary" (one line, method-specific, e.g. "Get user by id" for GET, "Update user" for PUT), optional "description", optional "request" (only for methods that accept a body: put, post, patch; omit for get, delete, head, options), and "response" (ONLY the status codes that THIS method returns — e.g. GET returns 200, DELETE returns 204; do not list 204 under PUT or 200 under DELETE unless the handler returns it for that branch).
150
- - For request.body, set "required": true or "required": false on each field based on code. Include "format" when relevant (e.g. "email").
151
- - Each method's response object must only list the HTTP status codes that that specific method returns.
152
-
153
- Respond with ONLY a single JSON object (no markdown, no explanation). Shape:
154
- ${PER_METHOD_RESPONSE_SHAPE}`;
155
- }
156
-
157
- /**
158
- * Build prompt for reordering tag groups by importance.
159
- * @param {object} spec - OpenAPI 3 spec with spec.tags
160
- * @returns {string}
161
- */
162
- export function buildReorderTagsPrompt(spec) {
163
- const tags = spec?.tags ?? [];
164
- if (!tags.length) return '';
165
- const list = tags
166
- .map((t) => `- "${t.name}"${t.description ? `: ${t.description.slice(0, 200)}` : ''}`)
167
- .join('\n');
168
- return `You are an API documentation assistant. This API has the following tag groups (categories):
169
-
170
- ${list}
171
-
172
- Reorder these groups by importance for a reader exploring the API. Put the most important or central groups first (e.g. main resources, auth), and utility or secondary groups last (e.g. health, admin).
173
-
174
- Respond with ONLY a JSON array of the tag names in the desired order. Example: ["Users", "Auth", "Health & routes"]
175
- Do not include any other text or markdown.`;
176
- }
177
-
178
- /**
179
- * Build prompt for generating the API overview Markdown page.
180
- * @param {object} spec - OpenAPI 3 spec with info, tags, paths
181
- * @param {object} [options] - { title?, version?, description? }
182
- * @returns {string}
183
- */
184
- export function buildOverviewPrompt(spec, options = {}) {
185
- const info = spec?.info ?? {};
186
- const title = options.title ?? info.title ?? 'API';
187
- const version = options.version ?? info.version ?? '1.0.0';
188
- const description = options.description ?? info.description ?? '';
189
- const tags = spec?.tags ?? [];
190
- const paths = spec?.paths ?? {};
191
- const tagList = tags.map((t) => `- **${t.name}**: ${t.description || '—'}`).join('\n');
192
- const pathList = Object.entries(paths)
193
- .slice(0, 50)
194
- .map(([p, ops]) => {
195
- const methods = Object.keys(ops)
196
- .filter((k) => ['get', 'post', 'put', 'delete', 'patch', 'head', 'options'].includes(k))
197
- .join(', ')
198
- .toUpperCase();
199
- return `- ${p} [${methods}]`;
200
- })
201
- .join('\n');
202
-
203
- return `You are an API documentation assistant. Generate a single comprehensive Markdown document for this API.
204
-
205
- API title: ${title}
206
- Version: ${version}
207
- ${description ? `Description: ${description.slice(0, 500)}\n` : ''}
208
-
209
- Tag groups (API areas):
210
- ${tagList}
211
-
212
- Sample of endpoints (path and methods):
213
- ${pathList}
214
-
215
- Write a Markdown document that includes:
216
- 1. A short **project summary** (what this API does).
217
- 2. **APIs available**: a high-level list of the tag groups and what they cover.
218
- 3. **Key endpoints** or "Getting started": suggest a few important paths (e.g. health check, main resources).
219
- 4. Any other brief sections that fit (e.g. Authentication, Rate limits) only if clearly inferable from the spec; otherwise omit.
220
-
221
- Use clear headings (##, ###). Keep the document concise (under 2 pages). Output ONLY the Markdown, no surrounding explanation or code fence.`;
222
- }
1
+ /**
2
+ * Prompt builders for auto-documentation LLM calls.
3
+ * Each function returns the prompt string; provider calls analyze(prompt).
4
+ */
5
+
6
+ import {
7
+ PROMPT_HANDLER_SLICE,
8
+ PROMPT_HANDLER_SLICE_WITH_DEPS,
9
+ PROMPT_DEPENDENCY_SLICE,
10
+ PROMPT_GROUP_CODE_LIMIT,
11
+ PROMPT_GROUP_CODE_LIMIT_WITH_DEPS,
12
+ PROMPT_GROUP_SNIPPET_CHARS,
13
+ } from '../constants.js';
14
+
15
+ /** Shared rule block for enhance prompts: required vs optional and format. */
16
+ const ENHANCE_RULES = `CRITICAL - Required vs optional: Infer from the code which parameters are required and which are optional. Look for: validation that throws or returns error when missing; checks like !payload.field or !ammo.payload.x; required in schema or JSDoc; or optional/undefined/default handling. For every body property and every query parameter you list, you MUST set "required": true or "required": false explicitly. Do not omit "required".
17
+
18
+ Respond with ONLY a single JSON object (no markdown, no explanation). Use this shape:`;
19
+
20
+ /** JSON shape example for single-endpoint enhance. */
21
+ const ENHANCE_RESPONSE_SHAPE = `{
22
+ "summary": "Short one-line description",
23
+ "description": "Optional longer description",
24
+ "request": {
25
+ "body": {
26
+ "fieldName": { "type": "string", "description": "...", "required": true }
27
+ },
28
+ "query": {
29
+ "paramName": { "type": "string", "description": "...", "required": false }
30
+ }
31
+ },
32
+ "response": { "200": { "description": "Success" }, "201": { "description": "Created" } }
33
+ }
34
+ - For every field in request.body and request.query set "required": true or "required": false based on code context.
35
+ - Include "format" when relevant (e.g. "email", "date-time", "binary").
36
+ - Omit "request" or "response" if not applicable. Keep summary under 80 characters.`;
37
+
38
+ /** JSON shape example for per-method enhance. */
39
+ const PER_METHOD_RESPONSE_SHAPE = `{
40
+ "get": { "summary": "...", "description": "...", "response": { "200": { "description": "..." } } },
41
+ "put": { "summary": "...", "description": "...", "request": { "body": { "name": { "type": "string", "required": true }, "email": { "type": "string", "format": "email", "required": true } } }, "response": { "200": { "description": "..." } } },
42
+ "delete": { "summary": "...", "description": "...", "response": { "204": { "description": "..." } } }
43
+ }`;
44
+
45
+ /**
46
+ * Build handler snippet and related-files section for endpoint prompts. Single place for limits and formatting.
47
+ * @param {object} endpointInfo - { handlerSource?, dependencySources? }
48
+ * @returns {{ handlerSnippet: string, relatedSection: string }}
49
+ */
50
+ export function buildEndpointPromptContext(endpointInfo) {
51
+ const { handlerSource = '', dependencySources = '' } = endpointInfo;
52
+ const handlerLimit = dependencySources ? PROMPT_HANDLER_SLICE_WITH_DEPS : PROMPT_HANDLER_SLICE;
53
+ const handlerSnippet = (handlerSource || '').slice(0, handlerLimit);
54
+ const relatedSection = dependencySources
55
+ ? `
56
+
57
+ Related source files (target and dependencies):
58
+ \`\`\`javascript
59
+ ${dependencySources.slice(0, PROMPT_DEPENDENCY_SLICE)}
60
+ \`\`\`
61
+ `
62
+ : '';
63
+ return { handlerSnippet, relatedSection };
64
+ }
65
+
66
+ /**
67
+ * Build prompt for summarizing a target group (tag name + description).
68
+ * @param {string} groupId
69
+ * @param {Array<object>} endpointsInfo - { path, methods, summary?, description?, handlerSource?, dependencySources? }
70
+ * @param {string} [dependencySources]
71
+ * @returns {string}
72
+ */
73
+ export function buildSummarizeGroupPrompt(groupId, endpointsInfo, dependencySources = '') {
74
+ if (!endpointsInfo?.length) return '';
75
+ const list = endpointsInfo
76
+ .map((e) => `- ${e.path} [${(e.methods || []).join(', ')}]: ${e.summary || e.description || '—'}`)
77
+ .join('\n');
78
+ const codeSnippets = endpointsInfo
79
+ .filter((e) => e.handlerSource)
80
+ .map((e) => `Path ${e.path}:\n${(e.handlerSource || '').slice(0, PROMPT_GROUP_SNIPPET_CHARS)}`)
81
+ .join('\n\n');
82
+ const codeLimit = dependencySources ? PROMPT_GROUP_CODE_LIMIT_WITH_DEPS : PROMPT_GROUP_CODE_LIMIT;
83
+ const { relatedSection } = buildEndpointPromptContext({ dependencySources });
84
+ return `You are an API documentation assistant. A single source file (group) exposes these endpoints:
85
+
86
+ Group id: ${groupId}
87
+
88
+ Endpoints:
89
+ ${list}
90
+
91
+ Handler code (excerpts):
92
+ \`\`\`javascript
93
+ ${codeSnippets.slice(0, codeLimit)}
94
+ \`\`\`
95
+ ${relatedSection}
96
+
97
+ Write a SHORT paragraph (2–4 sentences) describing what this group of endpoints does as a whole. Focus on the domain and purpose, not the HTTP details. Respond with ONLY a single JSON object:
98
+ { "name": "Human-readable group name", "description": "Your paragraph here." }
99
+ Use "name" as a short label (e.g. "Users", "Health & routes"); keep description under 300 characters.`;
100
+ }
101
+
102
+ /**
103
+ * Build prompt for enhancing a single endpoint (OpenAPI-style metadata).
104
+ * @param {object} endpointInfo - { path, methods, metadata?, handlerSource?, dependencySources? }
105
+ * @returns {string}
106
+ */
107
+ export function buildEnhanceEndpointPrompt(endpointInfo) {
108
+ const { path, methods = [], metadata = {} } = endpointInfo;
109
+ const { handlerSnippet, relatedSection } = buildEndpointPromptContext(endpointInfo);
110
+ const existing = Object.keys(metadata).length ? `Existing metadata: ${JSON.stringify(metadata)}\n` : '';
111
+ return `You are an API documentation assistant. Given an HTTP endpoint and its source code, suggest OpenAPI-style metadata.
112
+
113
+ Endpoint path: ${path}
114
+ HTTP methods: ${methods.join(', ')}
115
+ ${existing}Handler source (for context):
116
+ \`\`\`javascript
117
+ ${handlerSnippet}
118
+ \`\`\`
119
+ ${relatedSection}
120
+
121
+ ${ENHANCE_RULES}
122
+ ${ENHANCE_RESPONSE_SHAPE}`;
123
+ }
124
+
125
+ /**
126
+ * Build prompt for method-specific endpoint metadata (per-method summary, request, response).
127
+ * @param {object} endpointInfo - { path, methods, metadata?, handlerSource?, dependencySources? }
128
+ * @returns {string}
129
+ */
130
+ export function buildEnhanceEndpointPerMethodPrompt(endpointInfo) {
131
+ const { path, methods = [], metadata = {} } = endpointInfo;
132
+ const { handlerSnippet, relatedSection } = buildEndpointPromptContext(endpointInfo);
133
+ const methodsLower = methods.map((m) => m.toLowerCase());
134
+ const existing = Object.keys(metadata).length ? `Existing metadata: ${JSON.stringify(metadata)}\n` : '';
135
+ return `You are an API documentation assistant. This endpoint supports multiple HTTP methods. Provide METHOD-SPECIFIC metadata so each method is documented accurately.
136
+
137
+ Endpoint path: ${path}
138
+ HTTP methods: ${methods.join(', ')}
139
+
140
+ ${existing}Handler source (for context):
141
+ \`\`\`javascript
142
+ ${handlerSnippet}
143
+ \`\`\`
144
+ ${relatedSection}
145
+
146
+ RULES:
147
+ - Return ONE JSON object keyed by lowercase method name: "get", "put", "post", "delete", "patch", "head", "options".
148
+ - Include a key for EACH of: ${methodsLower.map((m) => `"${m}"`).join(', ')}.
149
+ - For each method provide: "summary" (one line, method-specific, e.g. "Get user by id" for GET, "Update user" for PUT), optional "description", optional "request" (only for methods that accept a body: put, post, patch; omit for get, delete, head, options), and "response" (ONLY the status codes that THIS method returns — e.g. GET returns 200, DELETE returns 204; do not list 204 under PUT or 200 under DELETE unless the handler returns it for that branch).
150
+ - For request.body, set "required": true or "required": false on each field based on code. Include "format" when relevant (e.g. "email").
151
+ - Each method's response object must only list the HTTP status codes that that specific method returns.
152
+
153
+ Respond with ONLY a single JSON object (no markdown, no explanation). Shape:
154
+ ${PER_METHOD_RESPONSE_SHAPE}`;
155
+ }
156
+
157
+ /**
158
+ * Build prompt for reordering tag groups by importance.
159
+ * @param {object} spec - OpenAPI 3 spec with spec.tags
160
+ * @returns {string}
161
+ */
162
+ export function buildReorderTagsPrompt(spec) {
163
+ const tags = spec?.tags ?? [];
164
+ if (!tags.length) return '';
165
+ const list = tags
166
+ .map((t) => `- "${t.name}"${t.description ? `: ${t.description.slice(0, 200)}` : ''}`)
167
+ .join('\n');
168
+ return `You are an API documentation assistant. This API has the following tag groups (categories):
169
+
170
+ ${list}
171
+
172
+ Reorder these groups by importance for a reader exploring the API. Put the most important or central groups first (e.g. main resources, auth), and utility or secondary groups last (e.g. health, admin).
173
+
174
+ Respond with ONLY a JSON array of the tag names in the desired order. Example: ["Users", "Auth", "Health & routes"]
175
+ Do not include any other text or markdown.`;
176
+ }
177
+
178
+ /**
179
+ * Build prompt for generating the API overview Markdown page.
180
+ * @param {object} spec - OpenAPI 3 spec with info, tags, paths
181
+ * @param {object} [options] - { title?, version?, description? }
182
+ * @returns {string}
183
+ */
184
+ export function buildOverviewPrompt(spec, options = {}) {
185
+ const info = spec?.info ?? {};
186
+ const title = options.title ?? info.title ?? 'API';
187
+ const version = options.version ?? info.version ?? '1.0.0';
188
+ const description = options.description ?? info.description ?? '';
189
+ const tags = spec?.tags ?? [];
190
+ const paths = spec?.paths ?? {};
191
+ const tagList = tags.map((t) => `- **${t.name}**: ${t.description || '—'}`).join('\n');
192
+ const pathList = Object.entries(paths)
193
+ .slice(0, 50)
194
+ .map(([p, ops]) => {
195
+ const methods = Object.keys(ops)
196
+ .filter((k) => ['get', 'post', 'put', 'delete', 'patch', 'head', 'options'].includes(k))
197
+ .join(', ')
198
+ .toUpperCase();
199
+ return `- ${p} [${methods}]`;
200
+ })
201
+ .join('\n');
202
+
203
+ return `You are an API documentation assistant. Generate a single comprehensive Markdown document for this API.
204
+
205
+ API title: ${title}
206
+ Version: ${version}
207
+ ${description ? `Description: ${description.slice(0, 500)}\n` : ''}
208
+
209
+ Tag groups (API areas):
210
+ ${tagList}
211
+
212
+ Sample of endpoints (path and methods):
213
+ ${pathList}
214
+
215
+ Write a Markdown document that includes:
216
+ 1. A short **project summary** (what this API does).
217
+ 2. **APIs available**: a high-level list of the tag groups and what they cover.
218
+ 3. **Key endpoints** or "Getting started": suggest a few important paths (e.g. health check, main resources).
219
+ 4. Any other brief sections that fit (e.g. Authentication, Rate limits) only if clearly inferable from the spec; otherwise omit.
220
+
221
+ Use clear headings (##, ###). Keep the document concise (under 2 pages). Output ONLY the Markdown, no surrounding explanation or code fence.`;
222
+ }