@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.
- package/dist/http/native.d.ts.map +1 -1
- package/dist/http/native.js +20 -26
- package/dist/http/session-teardown.d.ts +17 -0
- package/dist/http/session-teardown.d.ts.map +1 -0
- package/dist/http/session-teardown.js +30 -0
- package/dist/lib/core.d.ts.map +1 -1
- package/dist/lib/core.js +2 -0
- package/dist/lib/dom-prep.d.ts.map +1 -1
- package/dist/lib/dom-prep.js +19 -14
- package/dist/lib/progress.d.ts.map +1 -1
- package/dist/lib/progress.js +59 -32
- package/dist/lib/sdk-interop.d.ts +8 -0
- package/dist/lib/sdk-interop.d.ts.map +1 -0
- package/dist/lib/sdk-interop.js +73 -0
- package/dist/lib/task-handlers.d.ts +0 -2
- package/dist/lib/task-handlers.d.ts.map +1 -1
- package/dist/lib/task-handlers.js +9 -94
- package/dist/resources/index.js +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -3
- package/dist/tasks/call-contract.d.ts +25 -0
- package/dist/tasks/call-contract.d.ts.map +1 -0
- package/dist/tasks/call-contract.js +58 -0
- package/dist/tasks/cursor-codec.d.ts +5 -0
- package/dist/tasks/cursor-codec.d.ts.map +1 -0
- package/dist/tasks/cursor-codec.js +41 -0
- package/dist/tasks/execution.d.ts +1 -20
- package/dist/tasks/execution.d.ts.map +1 -1
- package/dist/tasks/execution.js +7 -32
- package/dist/tasks/manager.d.ts +1 -5
- package/dist/tasks/manager.d.ts.map +1 -1
- package/dist/tasks/manager.js +16 -144
- package/dist/tasks/owner.d.ts +12 -2
- package/dist/tasks/owner.d.ts.map +1 -1
- package/dist/tasks/owner.js +52 -3
- package/dist/tasks/tool-registry.d.ts +1 -0
- package/dist/tasks/tool-registry.d.ts.map +1 -1
- package/dist/tasks/waiters.d.ts +27 -0
- package/dist/tasks/waiters.d.ts.map +1 -0
- package/dist/tasks/waiters.js +113 -0
- package/dist/tools/fetch-url-progress.d.ts +17 -0
- package/dist/tools/fetch-url-progress.d.ts.map +1 -0
- package/dist/tools/fetch-url-progress.js +78 -0
- package/dist/tools/fetch-url.d.ts +5 -9
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +43 -96
- package/dist/transform/next-flight.d.ts +2 -0
- package/dist/transform/next-flight.d.ts.map +1 -0
- package/dist/transform/next-flight.js +285 -0
- package/dist/transform/transform.d.ts.map +1 -1
- package/dist/transform/transform.js +21 -336
- package/package.json +4 -4
- package/dist/tools/index.d.ts +0 -3
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js +0 -4
|
@@ -3,7 +3,7 @@ import diagnosticsChannel from 'node:diagnostics_channel';
|
|
|
3
3
|
import { performance } from 'node:perf_hooks';
|
|
4
4
|
import { isProbablyReaderable, Readability } from '@mozilla/readability';
|
|
5
5
|
import { parseHTML } from 'linkedom';
|
|
6
|
-
import {
|
|
6
|
+
import { extractLanguageFromClassName } from '../lib/code-lang.js';
|
|
7
7
|
import { config } from '../lib/core.js';
|
|
8
8
|
import { getOperationId, getRequestId, logDebug, logError, logInfo, logWarn, redactUrl, } from '../lib/core.js';
|
|
9
9
|
import { prepareDocumentForMarkdown, removeNoiseFromHtml, serializeDocumentForMarkdown, } from '../lib/dom-prep.js';
|
|
@@ -15,6 +15,7 @@ import { FetchError, getErrorMessage, toError } from '../lib/utils.js';
|
|
|
15
15
|
import { isObject } from '../lib/utils.js';
|
|
16
16
|
import { translateHtmlFragmentToMarkdown } from './html-translators.js';
|
|
17
17
|
import { extractMetadata, extractMetadataFromHead, mergeMetadata, normalizeDocumentTitle, } from './metadata.js';
|
|
18
|
+
import { supplementMarkdownFromNextFlight } from './next-flight.js';
|
|
18
19
|
import { getOrCreateWorkerPool, getWorkerPoolStats, shutdownWorkerPool, } from './worker-pool.js';
|
|
19
20
|
function decodeInput(input, encoding) {
|
|
20
21
|
if (typeof input === 'string')
|
|
@@ -628,13 +629,17 @@ function tryTransformRawContent(params) {
|
|
|
628
629
|
}
|
|
629
630
|
const MIN_CONTENT_RATIO = 0.15;
|
|
630
631
|
const MIN_HTML_LENGTH_FOR_GATE = 100;
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
632
|
+
const RETENTION_RULES = [
|
|
633
|
+
{ selector: 'h1,h2,h3,h4,h5,h6', minOriginal: 1, ratio: 0.3 },
|
|
634
|
+
{ selector: 'pre', minOriginal: 1, ratio: 0.15 },
|
|
635
|
+
{ selector: 'table', minOriginal: 1, ratio: 0.5 },
|
|
636
|
+
{ selector: 'img', minOriginal: 4, ratio: 0.2 },
|
|
637
|
+
{
|
|
638
|
+
selector: 'button,[role="tab"],[role="tabpanel"],[aria-controls]',
|
|
639
|
+
minOriginal: 6,
|
|
640
|
+
ratio: 0.1,
|
|
641
|
+
},
|
|
642
|
+
];
|
|
638
643
|
const MIN_HEADINGS_FOR_EMPTY_SECTION_GATE = 5;
|
|
639
644
|
const MAX_EMPTY_SECTION_RATIO = 0.05;
|
|
640
645
|
const MIN_LINE_LENGTH_FOR_TRUNCATION_CHECK = 20;
|
|
@@ -930,7 +935,6 @@ const TransformHeuristics = {
|
|
|
930
935
|
findPrimaryHeading,
|
|
931
936
|
isGithubRepositoryRootUrl,
|
|
932
937
|
};
|
|
933
|
-
const ARTICLE_INTERACTIVE_SELECTOR = 'button,[role="tab"],[role="tabpanel"],[aria-controls]';
|
|
934
938
|
function buildArticleDocument(article) {
|
|
935
939
|
return parseHTML(`<!DOCTYPE html><html><body>${article.content}</body></html>`).document;
|
|
936
940
|
}
|
|
@@ -940,40 +944,13 @@ function hasSufficientArticleContentRatio(article, document) {
|
|
|
940
944
|
return true;
|
|
941
945
|
return article.textContent.length / originalLength >= MIN_CONTENT_RATIO;
|
|
942
946
|
}
|
|
943
|
-
function
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
}
|
|
950
|
-
function retainsEnoughCodeBlocks(articleDoc, document) {
|
|
951
|
-
const originalCodeBlocks = countMatchingElements(document, 'pre');
|
|
952
|
-
if (originalCodeBlocks === 0)
|
|
953
|
-
return true;
|
|
954
|
-
const articleCodeBlocks = countMatchingElements(articleDoc, 'pre');
|
|
955
|
-
return (articleCodeBlocks / originalCodeBlocks >= MIN_CODE_BLOCK_RETENTION_RATIO);
|
|
956
|
-
}
|
|
957
|
-
function retainsEnoughTables(articleDoc, document) {
|
|
958
|
-
const originalTables = countMatchingElements(document, 'table');
|
|
959
|
-
if (originalTables === 0)
|
|
960
|
-
return true;
|
|
961
|
-
const articleTables = countMatchingElements(articleDoc, 'table');
|
|
962
|
-
return articleTables / originalTables >= MIN_TABLE_RETENTION_RATIO;
|
|
963
|
-
}
|
|
964
|
-
function retainsEnoughImages(articleDoc, document) {
|
|
965
|
-
const originalImages = countMatchingElements(document, 'img');
|
|
966
|
-
if (originalImages < MIN_IMAGE_ELEMENTS_FOR_GATE)
|
|
967
|
-
return true;
|
|
968
|
-
const articleImages = countMatchingElements(articleDoc, 'img');
|
|
969
|
-
return articleImages / originalImages >= MIN_IMAGE_RETENTION_RATIO;
|
|
970
|
-
}
|
|
971
|
-
function retainsEnoughInteractiveElements(articleDoc, document) {
|
|
972
|
-
const originalInteractive = countMatchingElements(document, ARTICLE_INTERACTIVE_SELECTOR);
|
|
973
|
-
if (originalInteractive < MIN_INTERACTIVE_ELEMENTS_FOR_GATE)
|
|
974
|
-
return true;
|
|
975
|
-
const articleInteractive = countMatchingElements(articleDoc, ARTICLE_INTERACTIVE_SELECTOR);
|
|
976
|
-
return (articleInteractive / originalInteractive >= MIN_INTERACTIVE_RETENTION_RATIO);
|
|
947
|
+
function passesRetentionChecks(articleDoc, document) {
|
|
948
|
+
return RETENTION_RULES.every(({ selector, minOriginal, ratio }) => {
|
|
949
|
+
const original = countMatchingElements(document, selector);
|
|
950
|
+
if (original < minOriginal)
|
|
951
|
+
return true;
|
|
952
|
+
return countMatchingElements(articleDoc, selector) / original >= ratio;
|
|
953
|
+
});
|
|
977
954
|
}
|
|
978
955
|
function hasAcceptableEmptySectionRatio(articleDoc) {
|
|
979
956
|
const articleHeadings = countMatchingElements(articleDoc, 'h1,h2,h3,h4,h5,h6');
|
|
@@ -986,15 +963,7 @@ function shouldUseArticleContent(article, document) {
|
|
|
986
963
|
if (!hasSufficientArticleContentRatio(article, document))
|
|
987
964
|
return false;
|
|
988
965
|
const articleDoc = buildArticleDocument(article);
|
|
989
|
-
if (!
|
|
990
|
-
return false;
|
|
991
|
-
if (!retainsEnoughCodeBlocks(articleDoc, document))
|
|
992
|
-
return false;
|
|
993
|
-
if (!retainsEnoughTables(articleDoc, document))
|
|
994
|
-
return false;
|
|
995
|
-
if (!retainsEnoughImages(articleDoc, document))
|
|
996
|
-
return false;
|
|
997
|
-
if (!retainsEnoughInteractiveElements(articleDoc, document))
|
|
966
|
+
if (!passesRetentionChecks(articleDoc, document))
|
|
998
967
|
return false;
|
|
999
968
|
if (!hasAcceptableEmptySectionRatio(articleDoc))
|
|
1000
969
|
return false;
|
|
@@ -1061,290 +1030,6 @@ function buildContentSource(params) {
|
|
|
1061
1030
|
title: extractedMeta.title,
|
|
1062
1031
|
};
|
|
1063
1032
|
}
|
|
1064
|
-
const NEXT_FLIGHT_PAYLOAD_RE = /self\.__next_f\.push\(\[1,"((?:\\.|[^"\\])*)"\]\)<\/script>/gs;
|
|
1065
|
-
const TEMPLATE_ASSIGNMENT_RE = /([A-Za-z_$][\w$]*)=`([\s\S]*?)`;/g;
|
|
1066
|
-
const OBJECT_ASSIGNMENT_RE = /([A-Za-z_$][\w$]*)=\{([^{}]+)\}/g;
|
|
1067
|
-
const FLIGHT_INSTALL_RE = /commands:\{cli:"([^"]+)",npm:"([^"]+)",yarn:"([^"]+)",pnpm:"([^"]+)",bun:"([^"]+)"\}/;
|
|
1068
|
-
const FLIGHT_IMPORT_RE = /commands:\{main:'([^']+)',individual:'([^']+)'\}/;
|
|
1069
|
-
const FLIGHT_DEMO_RE = /title:"([^"]+)",files:([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)/g;
|
|
1070
|
-
const FLIGHT_API_RE = /children:"([^"]+)"\}\),`\\n`,\(0,e\.jsx\)\(o,\{data:\[([\s\S]*?)\]\}\)/g;
|
|
1071
|
-
const FLIGHT_API_ROW_RE = /attribute:"([^"]+)",type:"([^"]+)",description:"([^"]*)",default:"([^"]*)"/g;
|
|
1072
|
-
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;
|
|
1073
|
-
function decodeHtmlEntities(value) {
|
|
1074
|
-
return value
|
|
1075
|
-
.replace(/'|'/g, "'")
|
|
1076
|
-
.replace(/"/g, '"')
|
|
1077
|
-
.replace(/&/g, '&')
|
|
1078
|
-
.replace(/</g, '<')
|
|
1079
|
-
.replace(/>/g, '>');
|
|
1080
|
-
}
|
|
1081
|
-
function decodeFlightStringValue(value) {
|
|
1082
|
-
try {
|
|
1083
|
-
return JSON.parse(`"${value}"`);
|
|
1084
|
-
}
|
|
1085
|
-
catch {
|
|
1086
|
-
return decodeHtmlEntities(value);
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
function decodeNextFlightPayloads(html) {
|
|
1090
|
-
const payloads = [];
|
|
1091
|
-
for (const match of html.matchAll(NEXT_FLIGHT_PAYLOAD_RE)) {
|
|
1092
|
-
const rawPayload = match[1];
|
|
1093
|
-
if (!rawPayload)
|
|
1094
|
-
continue;
|
|
1095
|
-
try {
|
|
1096
|
-
payloads.push(JSON.parse(`"${rawPayload}"`));
|
|
1097
|
-
}
|
|
1098
|
-
catch {
|
|
1099
|
-
// Ignore malformed payload fragments and continue with the rest.
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
return payloads;
|
|
1103
|
-
}
|
|
1104
|
-
function parseFlightObjectRefs(text) {
|
|
1105
|
-
const templateMap = new Map();
|
|
1106
|
-
const aliasMap = new Map();
|
|
1107
|
-
const objectMaps = new Map();
|
|
1108
|
-
for (const match of text.matchAll(TEMPLATE_ASSIGNMENT_RE)) {
|
|
1109
|
-
const name = match[1];
|
|
1110
|
-
const code = match[2];
|
|
1111
|
-
if (name && code)
|
|
1112
|
-
templateMap.set(name, decodeHtmlEntities(code));
|
|
1113
|
-
}
|
|
1114
|
-
for (const match of text.matchAll(OBJECT_ASSIGNMENT_RE)) {
|
|
1115
|
-
const objectName = match[1];
|
|
1116
|
-
const body = match[2]?.trim() ?? '';
|
|
1117
|
-
if (!objectName || !body)
|
|
1118
|
-
continue;
|
|
1119
|
-
const spreadMatch = /^\.\.\.([A-Za-z_$][\w$]*)$/.exec(body);
|
|
1120
|
-
if (spreadMatch?.[1]) {
|
|
1121
|
-
aliasMap.set(objectName, spreadMatch[1]);
|
|
1122
|
-
continue;
|
|
1123
|
-
}
|
|
1124
|
-
const entries = new Map();
|
|
1125
|
-
for (const part of body.split(',')) {
|
|
1126
|
-
const entryMatch = /(?:"([^"]+)"|([A-Za-z_$][\w$]*)):([A-Za-z_$][\w$]*)$/.exec(part.trim());
|
|
1127
|
-
const key = entryMatch?.[1] ?? entryMatch?.[2];
|
|
1128
|
-
const value = entryMatch?.[3];
|
|
1129
|
-
if (key && value)
|
|
1130
|
-
entries.set(key, value);
|
|
1131
|
-
}
|
|
1132
|
-
if (entries.size > 0)
|
|
1133
|
-
objectMaps.set(objectName, entries);
|
|
1134
|
-
}
|
|
1135
|
-
return { templateMap, aliasMap, objectMaps };
|
|
1136
|
-
}
|
|
1137
|
-
function resolveFlightCodeRef(name, refs, seen = new Set()) {
|
|
1138
|
-
if (!name || seen.has(name))
|
|
1139
|
-
return undefined;
|
|
1140
|
-
seen.add(name);
|
|
1141
|
-
const direct = refs.templateMap.get(name);
|
|
1142
|
-
if (direct)
|
|
1143
|
-
return direct;
|
|
1144
|
-
const alias = refs.aliasMap.get(name);
|
|
1145
|
-
if (alias)
|
|
1146
|
-
return resolveFlightCodeRef(alias, refs, seen);
|
|
1147
|
-
const objectMap = refs.objectMaps.get(name);
|
|
1148
|
-
if (!objectMap)
|
|
1149
|
-
return undefined;
|
|
1150
|
-
for (const ref of objectMap.values()) {
|
|
1151
|
-
const resolved = resolveFlightCodeRef(ref, refs, seen);
|
|
1152
|
-
if (resolved)
|
|
1153
|
-
return resolved;
|
|
1154
|
-
}
|
|
1155
|
-
return undefined;
|
|
1156
|
-
}
|
|
1157
|
-
function escapeMarkdownTableCell(value) {
|
|
1158
|
-
const normalized = decodeHtmlEntities(value).replace(/\s+/g, ' ').trim();
|
|
1159
|
-
return (normalized || '-').replace(/\|/g, '\\|');
|
|
1160
|
-
}
|
|
1161
|
-
function buildMarkdownTable(rows) {
|
|
1162
|
-
if (rows.length === 0)
|
|
1163
|
-
return '';
|
|
1164
|
-
const lines = [
|
|
1165
|
-
'| Prop | Type | Description | Default |',
|
|
1166
|
-
'| ---- | ---- | ----------- | ------- |',
|
|
1167
|
-
];
|
|
1168
|
-
for (const row of rows) {
|
|
1169
|
-
lines.push(`| ${escapeMarkdownTableCell(row.attribute)} | ${escapeMarkdownTableCell(row.type)} | ${escapeMarkdownTableCell(row.description)} | ${escapeMarkdownTableCell(row.defaultValue)} |`);
|
|
1170
|
-
}
|
|
1171
|
-
return lines.join('\n');
|
|
1172
|
-
}
|
|
1173
|
-
function buildCodeBlock(code) {
|
|
1174
|
-
const trimmed = code.trim();
|
|
1175
|
-
if (!trimmed)
|
|
1176
|
-
return '';
|
|
1177
|
-
const language = detectLanguageFromCode(trimmed) ?? 'tsx';
|
|
1178
|
-
return `\`\`\`${language}\n${trimmed}\n\`\`\``;
|
|
1179
|
-
}
|
|
1180
|
-
function buildMermaidBlock(chart) {
|
|
1181
|
-
const normalized = decodeFlightStringValue(chart).trim();
|
|
1182
|
-
if (!normalized)
|
|
1183
|
-
return '';
|
|
1184
|
-
return `\`\`\`mermaid\n${normalized}\n\`\`\``;
|
|
1185
|
-
}
|
|
1186
|
-
function normalizeSupplementHeadingText(value) {
|
|
1187
|
-
return value
|
|
1188
|
-
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
|
|
1189
|
-
.replace(/\s+/g, ' ')
|
|
1190
|
-
.trim()
|
|
1191
|
-
.toLowerCase();
|
|
1192
|
-
}
|
|
1193
|
-
function getMarkdownHeadingInfo(line) {
|
|
1194
|
-
const match = /^(#{1,6})\s+(.+?)\s*$/.exec(line.trim());
|
|
1195
|
-
if (!match)
|
|
1196
|
-
return null;
|
|
1197
|
-
return {
|
|
1198
|
-
level: match[1]?.length ?? 0,
|
|
1199
|
-
title: normalizeSupplementHeadingText(match[2] ?? ''),
|
|
1200
|
-
};
|
|
1201
|
-
}
|
|
1202
|
-
function findMarkdownSection(lines, title) {
|
|
1203
|
-
const target = normalizeSupplementHeadingText(title);
|
|
1204
|
-
for (let i = 0; i < lines.length; i += 1) {
|
|
1205
|
-
const heading = getMarkdownHeadingInfo(lines[i] ?? '');
|
|
1206
|
-
if (heading?.title !== target)
|
|
1207
|
-
continue;
|
|
1208
|
-
let end = lines.length;
|
|
1209
|
-
for (let j = i + 1; j < lines.length; j += 1) {
|
|
1210
|
-
const nextLine = lines[j];
|
|
1211
|
-
const nextHeading = nextLine !== undefined ? getMarkdownHeadingInfo(nextLine) : null;
|
|
1212
|
-
if (nextHeading && nextHeading.level <= heading.level) {
|
|
1213
|
-
end = j;
|
|
1214
|
-
break;
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
return { start: i, end };
|
|
1218
|
-
}
|
|
1219
|
-
return null;
|
|
1220
|
-
}
|
|
1221
|
-
function getSectionBody(lines, section) {
|
|
1222
|
-
return lines
|
|
1223
|
-
.slice(section.start + 1, section.end)
|
|
1224
|
-
.join('\n')
|
|
1225
|
-
.trim();
|
|
1226
|
-
}
|
|
1227
|
-
function replaceMarkdownSection(lines, title, body) {
|
|
1228
|
-
const section = findMarkdownSection(lines, title);
|
|
1229
|
-
if (!section)
|
|
1230
|
-
return false;
|
|
1231
|
-
const replacement = body.trim().length > 0 ? ['', ...body.trim().split('\n'), ''] : [''];
|
|
1232
|
-
lines.splice(section.start + 1, section.end - section.start - 1, ...replacement);
|
|
1233
|
-
return true;
|
|
1234
|
-
}
|
|
1235
|
-
function appendMarkdownSection(lines, title, body) {
|
|
1236
|
-
const section = findMarkdownSection(lines, title);
|
|
1237
|
-
if (!section)
|
|
1238
|
-
return false;
|
|
1239
|
-
const bodyText = getSectionBody(lines, section);
|
|
1240
|
-
if (bodyText.includes('```'))
|
|
1241
|
-
return false;
|
|
1242
|
-
const nextBody = bodyText ? `${bodyText}\n\n${body.trim()}` : body.trim();
|
|
1243
|
-
return replaceMarkdownSection(lines, title, nextBody);
|
|
1244
|
-
}
|
|
1245
|
-
function extractNextFlightSupplement(originalHtml) {
|
|
1246
|
-
const payloads = decodeNextFlightPayloads(originalHtml);
|
|
1247
|
-
if (payloads.length === 0)
|
|
1248
|
-
return null;
|
|
1249
|
-
const text = payloads.join('\n');
|
|
1250
|
-
const refs = parseFlightObjectRefs(text);
|
|
1251
|
-
const installMatch = FLIGHT_INSTALL_RE.exec(text);
|
|
1252
|
-
const importMatch = FLIGHT_IMPORT_RE.exec(text);
|
|
1253
|
-
const apiTables = new Map();
|
|
1254
|
-
for (const match of text.matchAll(FLIGHT_API_RE)) {
|
|
1255
|
-
const title = match[1];
|
|
1256
|
-
const rawRows = match[2] ?? '';
|
|
1257
|
-
if (!title)
|
|
1258
|
-
continue;
|
|
1259
|
-
const rows = [];
|
|
1260
|
-
for (const rowMatch of rawRows.matchAll(FLIGHT_API_ROW_RE)) {
|
|
1261
|
-
const attribute = rowMatch[1];
|
|
1262
|
-
const type = rowMatch[2];
|
|
1263
|
-
const description = rowMatch[3];
|
|
1264
|
-
const defaultValue = rowMatch[4];
|
|
1265
|
-
if (!attribute ||
|
|
1266
|
-
!type ||
|
|
1267
|
-
description === undefined ||
|
|
1268
|
-
defaultValue === undefined) {
|
|
1269
|
-
continue;
|
|
1270
|
-
}
|
|
1271
|
-
rows.push({ attribute, type, description, defaultValue });
|
|
1272
|
-
}
|
|
1273
|
-
const table = buildMarkdownTable(rows);
|
|
1274
|
-
if (table)
|
|
1275
|
-
apiTables.set(title, table);
|
|
1276
|
-
}
|
|
1277
|
-
const mermaidDiagrams = new Map();
|
|
1278
|
-
for (const match of text.matchAll(FLIGHT_MERMAID_SECTION_RE)) {
|
|
1279
|
-
const title = match[1] ? decodeFlightStringValue(match[1]).trim() : '';
|
|
1280
|
-
const chart = match[2] ? buildMermaidBlock(match[2]) : '';
|
|
1281
|
-
if (title && chart)
|
|
1282
|
-
mermaidDiagrams.set(title, chart);
|
|
1283
|
-
}
|
|
1284
|
-
const demoCodeBlocks = new Map();
|
|
1285
|
-
for (const match of text.matchAll(FLIGHT_DEMO_RE)) {
|
|
1286
|
-
const title = match[1];
|
|
1287
|
-
const objectName = match[2];
|
|
1288
|
-
const key = match[3];
|
|
1289
|
-
const ref = objectName
|
|
1290
|
-
? refs.objectMaps.get(objectName)?.get(key ?? '')
|
|
1291
|
-
: undefined;
|
|
1292
|
-
const code = resolveFlightCodeRef(ref, refs);
|
|
1293
|
-
const codeBlock = code ? buildCodeBlock(code) : '';
|
|
1294
|
-
if (title && codeBlock)
|
|
1295
|
-
demoCodeBlocks.set(title, codeBlock);
|
|
1296
|
-
}
|
|
1297
|
-
return {
|
|
1298
|
-
...(installMatch ? { installationCommands: installMatch.slice(1) } : {}),
|
|
1299
|
-
...(importMatch ? { importCommands: importMatch.slice(1) } : {}),
|
|
1300
|
-
apiTables,
|
|
1301
|
-
demoCodeBlocks,
|
|
1302
|
-
mermaidDiagrams,
|
|
1303
|
-
};
|
|
1304
|
-
}
|
|
1305
|
-
function supplementMarkdownFromNextFlight(markdown, originalHtml) {
|
|
1306
|
-
const supplement = extractNextFlightSupplement(originalHtml);
|
|
1307
|
-
if (!supplement)
|
|
1308
|
-
return markdown;
|
|
1309
|
-
const lines = markdown.split('\n');
|
|
1310
|
-
if (supplement.installationCommands?.length) {
|
|
1311
|
-
const installationSection = findMarkdownSection(lines, 'Installation');
|
|
1312
|
-
if (installationSection) {
|
|
1313
|
-
const installBody = getSectionBody(lines, installationSection);
|
|
1314
|
-
if (!/(npm|pnpm|yarn|bun|npx)\s+(install|add)/.test(installBody)) {
|
|
1315
|
-
appendMarkdownSection(lines, 'Installation', buildCodeBlock(supplement.installationCommands.join('\n')));
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
if (supplement.importCommands?.length) {
|
|
1320
|
-
const importSection = findMarkdownSection(lines, 'Import');
|
|
1321
|
-
if (importSection) {
|
|
1322
|
-
const importBody = getSectionBody(lines, importSection);
|
|
1323
|
-
if (!/import\s+\{/.test(importBody)) {
|
|
1324
|
-
appendMarkdownSection(lines, 'Import', buildCodeBlock(supplement.importCommands.join('\n\n')));
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
for (const [title, table] of supplement.apiTables) {
|
|
1329
|
-
replaceMarkdownSection(lines, title, table);
|
|
1330
|
-
}
|
|
1331
|
-
for (const [title, mermaidBlock] of supplement.mermaidDiagrams) {
|
|
1332
|
-
const section = findMarkdownSection(lines, title);
|
|
1333
|
-
if (!section)
|
|
1334
|
-
continue;
|
|
1335
|
-
const sectionBody = getSectionBody(lines, section);
|
|
1336
|
-
if (sectionBody.includes('```mermaid'))
|
|
1337
|
-
continue;
|
|
1338
|
-
const nextBody = sectionBody
|
|
1339
|
-
? `${sectionBody}\n\n${mermaidBlock}`
|
|
1340
|
-
: mermaidBlock;
|
|
1341
|
-
replaceMarkdownSection(lines, title, nextBody);
|
|
1342
|
-
}
|
|
1343
|
-
for (const [title, codeBlock] of supplement.demoCodeBlocks) {
|
|
1344
|
-
appendMarkdownSection(lines, title, codeBlock);
|
|
1345
|
-
}
|
|
1346
|
-
return lines.join('\n');
|
|
1347
|
-
}
|
|
1348
1033
|
function resolveContentSource(params) {
|
|
1349
1034
|
const { article, metadata: extractedMeta, document, truncated, } = extractContentContext(params.html, params.url, {
|
|
1350
1035
|
extractArticle: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@j0hanz/fetch-url-mcp",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.3",
|
|
4
4
|
"mcpName": "io.github.j0hanz/fetch-url-mcp",
|
|
5
5
|
"description": "A web content fetcher MCP server that converts HTML to clean, AI and human readable markdown.",
|
|
6
6
|
"type": "module",
|
|
@@ -74,19 +74,19 @@
|
|
|
74
74
|
"@mozilla/readability": "^0.6.0",
|
|
75
75
|
"linkedom": "^0.18.12",
|
|
76
76
|
"node-html-markdown": "^2.0.0",
|
|
77
|
-
"undici": "^7.24.
|
|
77
|
+
"undici": "^7.24.5",
|
|
78
78
|
"zod": "^4.3.6"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@eslint/js": "^10.0.1",
|
|
82
82
|
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
|
83
83
|
"@types/node": "^24",
|
|
84
|
-
"eslint": "^10.0
|
|
84
|
+
"eslint": "^10.1.0",
|
|
85
85
|
"eslint-config-prettier": "^10.1.8",
|
|
86
86
|
"eslint-plugin-de-morgan": "^2.1.1",
|
|
87
87
|
"eslint-plugin-depend": "^1.5.0",
|
|
88
88
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
89
|
-
"knip": "^
|
|
89
|
+
"knip": "^6.0.1",
|
|
90
90
|
"prettier": "^3.8.1",
|
|
91
91
|
"tsx": "^4.21.0",
|
|
92
92
|
"typescript": "^5.9.3",
|
package/dist/tools/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAExD"}
|
package/dist/tools/index.js
DELETED