@j0hanz/fetch-url-mcp 1.10.2 → 1.10.3

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 (55) hide show
  1. package/dist/http/native.d.ts.map +1 -1
  2. package/dist/http/native.js +20 -26
  3. package/dist/http/session-teardown.d.ts +17 -0
  4. package/dist/http/session-teardown.d.ts.map +1 -0
  5. package/dist/http/session-teardown.js +30 -0
  6. package/dist/lib/core.d.ts.map +1 -1
  7. package/dist/lib/core.js +2 -0
  8. package/dist/lib/dom-prep.d.ts.map +1 -1
  9. package/dist/lib/dom-prep.js +19 -14
  10. package/dist/lib/progress.d.ts.map +1 -1
  11. package/dist/lib/progress.js +59 -32
  12. package/dist/lib/sdk-interop.d.ts +8 -0
  13. package/dist/lib/sdk-interop.d.ts.map +1 -0
  14. package/dist/lib/sdk-interop.js +73 -0
  15. package/dist/lib/task-handlers.d.ts +0 -2
  16. package/dist/lib/task-handlers.d.ts.map +1 -1
  17. package/dist/lib/task-handlers.js +9 -94
  18. package/dist/resources/index.js +1 -1
  19. package/dist/server.d.ts.map +1 -1
  20. package/dist/server.js +10 -3
  21. package/dist/tasks/call-contract.d.ts +25 -0
  22. package/dist/tasks/call-contract.d.ts.map +1 -0
  23. package/dist/tasks/call-contract.js +58 -0
  24. package/dist/tasks/cursor-codec.d.ts +5 -0
  25. package/dist/tasks/cursor-codec.d.ts.map +1 -0
  26. package/dist/tasks/cursor-codec.js +41 -0
  27. package/dist/tasks/execution.d.ts +1 -20
  28. package/dist/tasks/execution.d.ts.map +1 -1
  29. package/dist/tasks/execution.js +7 -32
  30. package/dist/tasks/manager.d.ts +1 -5
  31. package/dist/tasks/manager.d.ts.map +1 -1
  32. package/dist/tasks/manager.js +16 -144
  33. package/dist/tasks/owner.d.ts +12 -2
  34. package/dist/tasks/owner.d.ts.map +1 -1
  35. package/dist/tasks/owner.js +52 -3
  36. package/dist/tasks/tool-registry.d.ts +1 -0
  37. package/dist/tasks/tool-registry.d.ts.map +1 -1
  38. package/dist/tasks/waiters.d.ts +27 -0
  39. package/dist/tasks/waiters.d.ts.map +1 -0
  40. package/dist/tasks/waiters.js +113 -0
  41. package/dist/tools/fetch-url-progress.d.ts +17 -0
  42. package/dist/tools/fetch-url-progress.d.ts.map +1 -0
  43. package/dist/tools/fetch-url-progress.js +78 -0
  44. package/dist/tools/fetch-url.d.ts +5 -9
  45. package/dist/tools/fetch-url.d.ts.map +1 -1
  46. package/dist/tools/fetch-url.js +43 -96
  47. package/dist/transform/next-flight.d.ts +2 -0
  48. package/dist/transform/next-flight.d.ts.map +1 -0
  49. package/dist/transform/next-flight.js +285 -0
  50. package/dist/transform/transform.d.ts.map +1 -1
  51. package/dist/transform/transform.js +21 -336
  52. package/package.json +4 -4
  53. package/dist/tools/index.d.ts +0 -3
  54. package/dist/tools/index.d.ts.map +0 -1
  55. package/dist/tools/index.js +0 -4
@@ -1,14 +1,15 @@
1
- import { randomUUID } from 'node:crypto';
2
1
  import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
3
2
  import { z } from 'zod';
4
- import { config, getRequestId, logDebug, logError, logWarn, runWithRequestContext, } from '../lib/core.js';
5
- import { appendTruncationMarker, markdownTransform, parseCachedMarkdownResult, performSharedFetch, readNestedRecord, serializeMarkdownResult, TRUNCATION_MARKER, withSignal, } from '../lib/fetch-pipeline.js';
3
+ import { config, logDebug, logError, logWarn } from '../lib/core.js';
4
+ import { appendTruncationMarker, markdownTransform, parseCachedMarkdownResult, performSharedFetch, serializeMarkdownResult, TRUNCATION_MARKER, withSignal, } from '../lib/fetch-pipeline.js';
6
5
  import { handleToolError } from '../lib/mcp-tools.js';
7
6
  import { createProgressReporter, } from '../lib/progress.js';
8
- import { isAbortError, isObject, toError } from '../lib/utils.js';
7
+ import { isAbortError, toError } from '../lib/utils.js';
9
8
  import { formatZodError } from '../lib/zod.js';
10
9
  import { fetchUrlInputSchema, fetchUrlOutputSchema, normalizeExtractedMetadata, normalizePageTitle, } from '../schemas.js';
10
+ import { withRequestContextIfMissing } from '../tasks/owner.js';
11
11
  import { registerTaskCapableTool, unregisterTaskCapableTool, } from '../tasks/tool-registry.js';
12
+ import { FetchUrlProgressPlan, getFetchCompletionStatusMessage, } from './fetch-url-progress.js';
12
13
  export const FETCH_URL_TOOL_NAME = 'fetch-url';
13
14
  const FETCH_URL_TOOL_DESCRIPTION = `
14
15
  <role>Web Content Extractor</role>
@@ -27,9 +28,6 @@ const TOOL_ICON = {
27
28
  };
28
29
  const HARD_TOOL_TIMEOUT_MS = 300_000;
29
30
  const CODE_HOSTS = new Set(['github.com', 'gitlab.com', 'bitbucket.org']);
30
- /* -------------------------------------------------------------------------------------------------
31
- * URL context & progress
32
- * ------------------------------------------------------------------------------------------------- */
33
31
  function getUrlContext(urlStr) {
34
32
  try {
35
33
  const u = new URL(urlStr);
@@ -55,28 +53,6 @@ function getUrlContext(urlStr) {
55
53
  return 'unknown';
56
54
  }
57
55
  }
58
- function mapFetchStageToProgress(stage, context) {
59
- switch (stage) {
60
- case 'resolve_url':
61
- return { step: 2, message: 'Resolving URL' };
62
- case 'check_cache':
63
- return { step: 3, message: 'Checking cache' };
64
- case 'cache_hit':
65
- return { step: 4, message: 'Loaded from cache' };
66
- case 'cache_restore':
67
- return { step: 5, message: 'Restoring cached content' };
68
- case 'fetch_remote':
69
- return { step: 4, message: `Fetching ${context}` };
70
- case 'response_ready':
71
- return { step: 5, message: 'Received response' };
72
- case 'transform_start':
73
- return { step: 6, message: 'Parsing HTML → Markdown' };
74
- case 'prepare_output':
75
- return { step: 6, message: 'Preparing output' };
76
- case 'finalize_output':
77
- return { step: 7, message: 'Finalizing output' };
78
- }
79
- }
80
56
  /* -------------------------------------------------------------------------------------------------
81
57
  * Response assembly
82
58
  * ------------------------------------------------------------------------------------------------- */
@@ -132,14 +108,13 @@ function buildToolAbortSignal(extraSignal) {
132
108
  ? AbortSignal.any([extraSignal, timeoutSignal])
133
109
  : timeoutSignal;
134
110
  }
135
- function buildFetchOptions(url, context, signal, progress, forceRefresh) {
111
+ function buildFetchOptions(url, signal, progressPlan, forceRefresh) {
136
112
  return {
137
113
  url,
138
114
  ...withSignal(signal),
139
115
  ...(forceRefresh ? { forceRefresh: true } : {}),
140
116
  onStage: (stage) => {
141
- const { step, message } = mapFetchStageToProgress(stage, context);
142
- progress?.report(step, message);
117
+ progressPlan.reportStage(stage);
143
118
  },
144
119
  transform: async ({ buffer, encoding, truncated }, normalizedUrl) => {
145
120
  return markdownTransform({ buffer, encoding, ...(truncated ? { truncated } : {}) }, normalizedUrl, signal);
@@ -153,21 +128,16 @@ async function executeFetch(input, extra) {
153
128
  const signal = buildToolAbortSignal(extra?.signal);
154
129
  const progress = createProgressReporter(extra);
155
130
  const context = getUrlContext(url);
131
+ const progressPlan = new FetchUrlProgressPlan(progress, context);
156
132
  logDebug('Fetching URL', { url });
157
133
  try {
158
- progress.report(1, 'Preparing request');
159
- const { pipeline, inlineResult } = await performSharedFetch(buildFetchOptions(url, context, signal, progress, input.forceRefresh));
160
- const chars = inlineResult.contentSize;
161
- const size = chars < 1000
162
- ? `${chars} chars`
163
- : chars < 1_000_000
164
- ? `${(chars / 1024).toFixed(1)} KB`
165
- : `${(chars / (1024 * 1024)).toFixed(1)} MB`;
166
- progress.report(8, `Done — ${size}`);
134
+ progressPlan.reportStart();
135
+ const { pipeline, inlineResult } = await performSharedFetch(buildFetchOptions(url, signal, progressPlan, input.forceRefresh));
136
+ progressPlan.reportSuccess(inlineResult.contentSize);
167
137
  return buildResponse(pipeline, inlineResult, url);
168
138
  }
169
139
  catch (error) {
170
- progress.report(8, isAbortError(error) ? 'Cancelled' : 'Failed');
140
+ progressPlan.reportFailure(isAbortError(error));
171
141
  throw error;
172
142
  }
173
143
  }
@@ -190,7 +160,6 @@ const TOOL_DEFINITION = {
190
160
  inputSchema: fetchUrlInputSchema,
191
161
  outputSchema: z.toJSONSchema(fetchUrlOutputSchema),
192
162
  handler: fetchUrlToolHandler,
193
- execution: { taskSupport: 'optional' },
194
163
  annotations: {
195
164
  readOnlyHint: true,
196
165
  destructiveHint: false,
@@ -198,54 +167,8 @@ const TOOL_DEFINITION = {
198
167
  openWorldHint: true,
199
168
  },
200
169
  };
201
- /**
202
- * Stdio-path guard: ensures a request context (requestId, sessionId) is set
203
- * in AsyncLocalStorage before invoking the handler. On the HTTP path the SDK
204
- * populates `extra.requestId`/`extra.requestInfo`, so this is a no-op there.
205
- * On the stdio path there is no SDK-provided context, so we derive one from
206
- * the extra fields or generate a fresh UUID.
207
- */
208
- export function withRequestContextIfMissing(handler) {
209
- return async (params, extra) => {
210
- const existingRequestId = getRequestId();
211
- if (existingRequestId) {
212
- return handler(params, extra);
213
- }
214
- const derivedRequestId = resolveRequestIdFromExtra(extra) ?? randomUUID();
215
- const derivedSessionId = resolveSessionIdFromExtra(extra);
216
- return runWithRequestContext({
217
- requestId: derivedRequestId,
218
- operationId: derivedRequestId,
219
- ...(derivedSessionId ? { sessionId: derivedSessionId } : {}),
220
- }, () => handler(params, extra));
221
- };
222
- }
223
- function resolveRequestIdFromExtra(extra) {
224
- if (!isObject(extra))
225
- return undefined;
226
- const { requestId } = extra;
227
- if (typeof requestId === 'string')
228
- return requestId;
229
- if (typeof requestId === 'number')
230
- return String(requestId);
231
- return undefined;
232
- }
233
- function resolveSessionIdFromExtra(extra) {
234
- if (!isObject(extra))
235
- return undefined;
236
- const { sessionId } = extra;
237
- if (typeof sessionId === 'string')
238
- return sessionId;
239
- const headers = readNestedRecord(extra, ['requestInfo', 'headers']);
240
- const headerValue = headers ? headers['mcp-session-id'] : undefined;
241
- return typeof headerValue === 'string' ? headerValue : undefined;
242
- }
243
- export function registerTools(server) {
244
- if (!config.tools.enabled.includes(FETCH_URL_TOOL_NAME)) {
245
- unregisterTaskCapableTool(FETCH_URL_TOOL_NAME);
246
- return;
247
- }
248
- registerTaskCapableTool({
170
+ function createTaskCapableDescriptor() {
171
+ return {
249
172
  name: FETCH_URL_TOOL_NAME,
250
173
  parseArguments: (args) => {
251
174
  const parsed = fetchUrlInputSchema.safeParse(args);
@@ -255,17 +178,41 @@ export function registerTools(server) {
255
178
  return parsed.data;
256
179
  },
257
180
  execute: fetchUrlToolHandler,
258
- });
181
+ getCompletionStatusMessage: getFetchCompletionStatusMessage,
182
+ };
183
+ }
184
+ function setRegisteredToolTaskSupport(registeredTool, support) {
185
+ registeredTool.execution = { taskSupport: support };
186
+ }
187
+ export function registerTools(server) {
188
+ if (!config.tools.enabled.includes(FETCH_URL_TOOL_NAME)) {
189
+ unregisterTaskCapableTool(FETCH_URL_TOOL_NAME);
190
+ return {
191
+ setTaskSupport: () => { },
192
+ };
193
+ }
194
+ const descriptor = createTaskCapableDescriptor();
195
+ registerTaskCapableTool(descriptor);
259
196
  const registeredTool = server.registerTool(TOOL_DEFINITION.name, {
260
197
  title: TOOL_DEFINITION.title,
261
198
  description: TOOL_DEFINITION.description,
262
199
  inputSchema: TOOL_DEFINITION.inputSchema,
263
200
  outputSchema: TOOL_DEFINITION.outputSchema,
264
201
  annotations: TOOL_DEFINITION.annotations,
265
- execution: TOOL_DEFINITION.execution,
202
+ execution: { taskSupport: 'optional' },
266
203
  icons: [TOOL_ICON],
267
204
  }, withRequestContextIfMissing(TOOL_DEFINITION.handler));
268
- // SDK workaround: RegisteredTool type omits `execution`
269
- registeredTool.execution =
270
- TOOL_DEFINITION.execution;
205
+ const registeredToolRecord = registeredTool;
206
+ setRegisteredToolTaskSupport(registeredToolRecord, 'optional');
207
+ return {
208
+ setTaskSupport: (support) => {
209
+ if (support === 'optional') {
210
+ registerTaskCapableTool(descriptor);
211
+ }
212
+ else {
213
+ unregisterTaskCapableTool(FETCH_URL_TOOL_NAME);
214
+ }
215
+ setRegisteredToolTaskSupport(registeredToolRecord, support);
216
+ },
217
+ };
271
218
  }
@@ -0,0 +1,2 @@
1
+ export declare function supplementMarkdownFromNextFlight(markdown: string, originalHtml: string): string;
2
+ //# sourceMappingURL=next-flight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-flight.d.ts","sourceRoot":"","sources":["../../src/transform/next-flight.ts"],"names":[],"mappings":"AA0UA,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,MAAM,CAwDR"}
@@ -0,0 +1,285 @@
1
+ import { detectLanguageFromCode } from '../lib/code-lang.js';
2
+ const NEXT_FLIGHT_PAYLOAD_RE = /self\.__next_f\.push\(\[1,"((?:\\.|[^"\\])*)"\]\)<\/script>/gs;
3
+ const TEMPLATE_ASSIGNMENT_RE = /([A-Za-z_$][\w$]*)=`([\s\S]*?)`;/g;
4
+ const OBJECT_ASSIGNMENT_RE = /([A-Za-z_$][\w$]*)=\{([^{}]+)\}/g;
5
+ const FLIGHT_INSTALL_RE = /commands:\{cli:"([^"]+)",npm:"([^"]+)",yarn:"([^"]+)",pnpm:"([^"]+)",bun:"([^"]+)"\}/;
6
+ const FLIGHT_IMPORT_RE = /commands:\{main:'([^']+)',individual:'([^']+)'\}/;
7
+ const FLIGHT_DEMO_RE = /title:"([^"]+)",files:([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)/g;
8
+ const FLIGHT_API_RE = /children:"([^"]+)"\}\),`\\n`,\(0,e\.jsx\)\(o,\{data:\[([\s\S]*?)\]\}\)/g;
9
+ const FLIGHT_API_ROW_RE = /attribute:"([^"]+)",type:"([^"]+)",description:"([^"]*)",default:"([^"]*)"/g;
10
+ const FLIGHT_MERMAID_SECTION_RE = /_jsx\(Heading,\{\s*level:"[1-6]",\s*id:"[^"]+",\s*children:"((?:\\.|[^"\\])*)"\s*\}\)(?:(?!_jsx\(Heading,\{)[\s\S]){0,12000}?_jsx\(Mermaid,\{\s*chart:"((?:\\.|[^"\\])*)"\s*\}\)/g;
11
+ function decodeHtmlEntities(value) {
12
+ return value
13
+ .replace(/&#39;|&#x27;/g, "'")
14
+ .replace(/&quot;/g, '"')
15
+ .replace(/&amp;/g, '&')
16
+ .replace(/&lt;/g, '<')
17
+ .replace(/&gt;/g, '>');
18
+ }
19
+ function decodeFlightStringValue(value) {
20
+ try {
21
+ return JSON.parse(`"${value}"`);
22
+ }
23
+ catch {
24
+ return decodeHtmlEntities(value);
25
+ }
26
+ }
27
+ function decodeNextFlightPayloads(html) {
28
+ const payloads = [];
29
+ for (const match of html.matchAll(NEXT_FLIGHT_PAYLOAD_RE)) {
30
+ const rawPayload = match[1];
31
+ if (!rawPayload)
32
+ continue;
33
+ try {
34
+ payloads.push(JSON.parse(`"${rawPayload}"`));
35
+ }
36
+ catch {
37
+ // Ignore malformed payload fragments and continue with the rest.
38
+ }
39
+ }
40
+ return payloads;
41
+ }
42
+ function parseFlightObjectRefs(text) {
43
+ const templateMap = new Map();
44
+ const aliasMap = new Map();
45
+ const objectMaps = new Map();
46
+ for (const match of text.matchAll(TEMPLATE_ASSIGNMENT_RE)) {
47
+ const name = match[1];
48
+ const code = match[2];
49
+ if (name && code)
50
+ templateMap.set(name, decodeHtmlEntities(code));
51
+ }
52
+ for (const match of text.matchAll(OBJECT_ASSIGNMENT_RE)) {
53
+ const objectName = match[1];
54
+ const body = match[2]?.trim() ?? '';
55
+ if (!objectName || !body)
56
+ continue;
57
+ const spreadMatch = /^\.\.\.([A-Za-z_$][\w$]*)$/.exec(body);
58
+ if (spreadMatch?.[1]) {
59
+ aliasMap.set(objectName, spreadMatch[1]);
60
+ continue;
61
+ }
62
+ const entries = new Map();
63
+ for (const part of body.split(',')) {
64
+ const entryMatch = /(?:"([^"]+)"|([A-Za-z_$][\w$]*)):([A-Za-z_$][\w$]*)$/.exec(part.trim());
65
+ const key = entryMatch?.[1] ?? entryMatch?.[2];
66
+ const value = entryMatch?.[3];
67
+ if (key && value)
68
+ entries.set(key, value);
69
+ }
70
+ if (entries.size > 0)
71
+ objectMaps.set(objectName, entries);
72
+ }
73
+ return { templateMap, aliasMap, objectMaps };
74
+ }
75
+ function resolveFlightCodeRef(name, refs, seen = new Set()) {
76
+ if (!name || seen.has(name))
77
+ return undefined;
78
+ seen.add(name);
79
+ const direct = refs.templateMap.get(name);
80
+ if (direct)
81
+ return direct;
82
+ const alias = refs.aliasMap.get(name);
83
+ if (alias)
84
+ return resolveFlightCodeRef(alias, refs, seen);
85
+ const objectMap = refs.objectMaps.get(name);
86
+ if (!objectMap)
87
+ return undefined;
88
+ for (const ref of objectMap.values()) {
89
+ const resolved = resolveFlightCodeRef(ref, refs, seen);
90
+ if (resolved)
91
+ return resolved;
92
+ }
93
+ return undefined;
94
+ }
95
+ function escapeMarkdownTableCell(value) {
96
+ const normalized = decodeHtmlEntities(value).replace(/\s+/g, ' ').trim();
97
+ return (normalized || '-').replace(/\|/g, '\\|');
98
+ }
99
+ function buildMarkdownTable(rows) {
100
+ if (rows.length === 0)
101
+ return '';
102
+ const lines = [
103
+ '| Prop | Type | Description | Default |',
104
+ '| ---- | ---- | ----------- | ------- |',
105
+ ];
106
+ for (const row of rows) {
107
+ lines.push(`| ${escapeMarkdownTableCell(row.attribute)} | ${escapeMarkdownTableCell(row.type)} | ${escapeMarkdownTableCell(row.description)} | ${escapeMarkdownTableCell(row.defaultValue)} |`);
108
+ }
109
+ return lines.join('\n');
110
+ }
111
+ function buildCodeBlock(code) {
112
+ const trimmed = code.trim();
113
+ if (!trimmed)
114
+ return '';
115
+ const language = detectLanguageFromCode(trimmed) ?? 'tsx';
116
+ return `\`\`\`${language}\n${trimmed}\n\`\`\``;
117
+ }
118
+ function buildMermaidBlock(chart) {
119
+ const normalized = decodeFlightStringValue(chart).trim();
120
+ if (!normalized)
121
+ return '';
122
+ return `\`\`\`mermaid\n${normalized}\n\`\`\``;
123
+ }
124
+ function normalizeSupplementHeadingText(value) {
125
+ return value
126
+ .replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
127
+ .replace(/\s+/g, ' ')
128
+ .trim()
129
+ .toLowerCase();
130
+ }
131
+ function getMarkdownHeadingInfo(line) {
132
+ const match = /^(#{1,6})\s+(.+?)\s*$/.exec(line.trim());
133
+ if (!match)
134
+ return null;
135
+ return {
136
+ level: match[1]?.length ?? 0,
137
+ title: normalizeSupplementHeadingText(match[2] ?? ''),
138
+ };
139
+ }
140
+ function findMarkdownSection(lines, title) {
141
+ const target = normalizeSupplementHeadingText(title);
142
+ for (let i = 0; i < lines.length; i += 1) {
143
+ const heading = getMarkdownHeadingInfo(lines[i] ?? '');
144
+ if (heading?.title !== target)
145
+ continue;
146
+ let end = lines.length;
147
+ for (let j = i + 1; j < lines.length; j += 1) {
148
+ const nextLine = lines[j];
149
+ const nextHeading = nextLine !== undefined ? getMarkdownHeadingInfo(nextLine) : null;
150
+ if (nextHeading && nextHeading.level <= heading.level) {
151
+ end = j;
152
+ break;
153
+ }
154
+ }
155
+ return { start: i, end };
156
+ }
157
+ return null;
158
+ }
159
+ function getSectionBody(lines, section) {
160
+ return lines
161
+ .slice(section.start + 1, section.end)
162
+ .join('\n')
163
+ .trim();
164
+ }
165
+ function replaceMarkdownSection(lines, title, body) {
166
+ const section = findMarkdownSection(lines, title);
167
+ if (!section)
168
+ return false;
169
+ const replacement = body.trim().length > 0 ? ['', ...body.trim().split('\n'), ''] : [''];
170
+ lines.splice(section.start + 1, section.end - section.start - 1, ...replacement);
171
+ return true;
172
+ }
173
+ function appendMarkdownSection(lines, title, body) {
174
+ const section = findMarkdownSection(lines, title);
175
+ if (!section)
176
+ return false;
177
+ const bodyText = getSectionBody(lines, section);
178
+ if (bodyText.includes('```'))
179
+ return false;
180
+ const nextBody = bodyText ? `${bodyText}\n\n${body.trim()}` : body.trim();
181
+ return replaceMarkdownSection(lines, title, nextBody);
182
+ }
183
+ function extractNextFlightSupplement(originalHtml) {
184
+ const payloads = decodeNextFlightPayloads(originalHtml);
185
+ if (payloads.length === 0)
186
+ return null;
187
+ const text = payloads.join('\n');
188
+ const refs = parseFlightObjectRefs(text);
189
+ const installMatch = FLIGHT_INSTALL_RE.exec(text);
190
+ const importMatch = FLIGHT_IMPORT_RE.exec(text);
191
+ const apiTables = new Map();
192
+ for (const match of text.matchAll(FLIGHT_API_RE)) {
193
+ const title = match[1];
194
+ const rawRows = match[2] ?? '';
195
+ if (!title)
196
+ continue;
197
+ const rows = [];
198
+ for (const rowMatch of rawRows.matchAll(FLIGHT_API_ROW_RE)) {
199
+ const attribute = rowMatch[1];
200
+ const type = rowMatch[2];
201
+ const description = rowMatch[3];
202
+ const defaultValue = rowMatch[4];
203
+ if (!attribute ||
204
+ !type ||
205
+ description === undefined ||
206
+ defaultValue === undefined) {
207
+ continue;
208
+ }
209
+ rows.push({ attribute, type, description, defaultValue });
210
+ }
211
+ const table = buildMarkdownTable(rows);
212
+ if (table)
213
+ apiTables.set(title, table);
214
+ }
215
+ const mermaidDiagrams = new Map();
216
+ for (const match of text.matchAll(FLIGHT_MERMAID_SECTION_RE)) {
217
+ const title = match[1] ? decodeFlightStringValue(match[1]).trim() : '';
218
+ const chart = match[2] ? buildMermaidBlock(match[2]) : '';
219
+ if (title && chart)
220
+ mermaidDiagrams.set(title, chart);
221
+ }
222
+ const demoCodeBlocks = new Map();
223
+ for (const match of text.matchAll(FLIGHT_DEMO_RE)) {
224
+ const title = match[1];
225
+ const objectName = match[2];
226
+ const key = match[3];
227
+ const ref = objectName
228
+ ? refs.objectMaps.get(objectName)?.get(key ?? '')
229
+ : undefined;
230
+ const code = resolveFlightCodeRef(ref, refs);
231
+ const codeBlock = code ? buildCodeBlock(code) : '';
232
+ if (title && codeBlock)
233
+ demoCodeBlocks.set(title, codeBlock);
234
+ }
235
+ return {
236
+ ...(installMatch ? { installationCommands: installMatch.slice(1) } : {}),
237
+ ...(importMatch ? { importCommands: importMatch.slice(1) } : {}),
238
+ apiTables,
239
+ demoCodeBlocks,
240
+ mermaidDiagrams,
241
+ };
242
+ }
243
+ export function supplementMarkdownFromNextFlight(markdown, originalHtml) {
244
+ const supplement = extractNextFlightSupplement(originalHtml);
245
+ if (!supplement)
246
+ return markdown;
247
+ const lines = markdown.split('\n');
248
+ if (supplement.installationCommands?.length) {
249
+ const installationSection = findMarkdownSection(lines, 'Installation');
250
+ if (installationSection) {
251
+ const installBody = getSectionBody(lines, installationSection);
252
+ if (!/(npm|pnpm|yarn|bun|npx)\s+(install|add)/.test(installBody)) {
253
+ appendMarkdownSection(lines, 'Installation', buildCodeBlock(supplement.installationCommands.join('\n')));
254
+ }
255
+ }
256
+ }
257
+ if (supplement.importCommands?.length) {
258
+ const importSection = findMarkdownSection(lines, 'Import');
259
+ if (importSection) {
260
+ const importBody = getSectionBody(lines, importSection);
261
+ if (!/import\s+\{/.test(importBody)) {
262
+ appendMarkdownSection(lines, 'Import', buildCodeBlock(supplement.importCommands.join('\n\n')));
263
+ }
264
+ }
265
+ }
266
+ for (const [title, table] of supplement.apiTables) {
267
+ replaceMarkdownSection(lines, title, table);
268
+ }
269
+ for (const [title, mermaidBlock] of supplement.mermaidDiagrams) {
270
+ const section = findMarkdownSection(lines, title);
271
+ if (!section)
272
+ continue;
273
+ const sectionBody = getSectionBody(lines, section);
274
+ if (sectionBody.includes('```mermaid'))
275
+ continue;
276
+ const nextBody = sectionBody
277
+ ? `${sectionBody}\n\n${mermaidBlock}`
278
+ : mermaidBlock;
279
+ replaceMarkdownSection(lines, title, nextBody);
280
+ }
281
+ for (const [title, codeBlock] of supplement.demoCodeBlocks) {
282
+ appendMarkdownSection(lines, title, codeBlock);
283
+ }
284
+ return lines.join('\n');
285
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/transform/transform.ts"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EAEtB,MAAM,YAAY,CAAC;AAqCpB,UAAU,WAAW;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAqJD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,WAAW,GACnB,qBAAqB,GAAG,IAAI,CAE9B;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,qBAAqB,GAAG,IAAI,EACrC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAChC,MAAM,CAER;AAwYD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAExD,GACA,gBAAgB,CAGlB;AAgLD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE;IACR,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,GACA,MAAM,CAsBR;AAuJD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,sBAAsB,EAAE,MAAM,GAAG,QAAQ,GACxC,OAAO,CAQT;AAiED,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAC/B,OAAO,IAAI,gBAAgB,CAE7B;AAED,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,aAAa,EAAE,iBAAiB,EAChC,wBAAwB,EAAE,OAAO,EACjC,eAAe,EAAE,OAAO,GACvB,aAAa,GAAG,SAAS,CAuB3B;AAo8BD,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,gBAAgB,GACxB,uBAAuB,CAqCzB;AAaD,UAAU,kBAAkB;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,GAAG,IAAI,CAEjE;AAED,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjE;AAED,KAAK,yBAAyB,GAAG,gBAAgB,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAkH1E,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,uBAAuB,CAAC,CAElC;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,uBAAuB,CAAC,CAElC"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/transform/transform.ts"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EAEtB,MAAM,YAAY,CAAC;AAqCpB,UAAU,WAAW;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAqJD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,WAAW,GACnB,qBAAqB,GAAG,IAAI,CAE9B;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,qBAAqB,GAAG,IAAI,EACrC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAChC,MAAM,CAER;AAwYD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAExD,GACA,gBAAgB,CAGlB;AAgLD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE;IACR,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,GACA,MAAM,CAsBR;AAkKD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,sBAAsB,EAAE,MAAM,GAAG,QAAQ,GACxC,OAAO,CAQT;AAiED,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAC/B,OAAO,IAAI,gBAAgB,CAE7B;AAED,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,aAAa,EAAE,iBAAiB,EAChC,wBAAwB,EAAE,OAAO,EACjC,eAAe,EAAE,OAAO,GACvB,aAAa,GAAG,SAAS,CAuB3B;AA+fD,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,gBAAgB,GACxB,uBAAuB,CAqCzB;AAaD,UAAU,kBAAkB;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,GAAG,IAAI,CAEjE;AAED,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjE;AAED,KAAK,yBAAyB,GAAG,gBAAgB,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAkH1E,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,uBAAuB,CAAC,CAElC;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,uBAAuB,CAAC,CAElC"}