@shuji-bonji/rfcxml-mcp 0.5.0 → 0.5.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.
- package/dist/cli/prefetch.d.ts +28 -0
- package/dist/cli/prefetch.d.ts.map +1 -0
- package/dist/cli/prefetch.js +200 -0
- package/dist/cli/prefetch.js.map +1 -0
- package/dist/config.d.ts +26 -10
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +26 -10
- package/dist/config.js.map +1 -1
- package/dist/services/rfc-fetcher.d.ts +101 -9
- package/dist/services/rfc-fetcher.d.ts.map +1 -1
- package/dist/services/rfc-fetcher.js +295 -61
- package/dist/services/rfc-fetcher.js.map +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +6 -1
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/handlers.d.ts +44 -7
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +105 -18
- package/dist/tools/handlers.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/disk-cache.d.ts +56 -0
- package/dist/utils/disk-cache.d.ts.map +1 -0
- package/dist/utils/disk-cache.js +95 -0
- package/dist/utils/disk-cache.js.map +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* rfcxml-prefetch — pre-populate the on-disk RFCXML cache.
|
|
4
|
+
*
|
|
5
|
+
* Phase 3 component. Bridges the gap between the MCP runtime (which fetches
|
|
6
|
+
* one RFC at a time on demand) and operators who need offline / CI-pinned
|
|
7
|
+
* access to a known set of RFCs. The CLI walks a list of RFC numbers, fetches
|
|
8
|
+
* each via the same pipeline as the MCP server (so source-priority and
|
|
9
|
+
* validation are identical), and writes them to the same disk cache layout.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* rfcxml-prefetch --range 9000-9120
|
|
13
|
+
* rfcxml-prefetch --rfc 9110 --rfc 9112 --rfc 9000
|
|
14
|
+
* rfcxml-prefetch --range 9000-9010 --cache-dir ./my-cache
|
|
15
|
+
* rfcxml-prefetch --range 9000-9050 --concurrency 4 --force
|
|
16
|
+
*
|
|
17
|
+
* Defaults:
|
|
18
|
+
* --cache-dir = $RFCXML_CACHE_DIR (or ~/.cache/rfcxml-mcp if unset)
|
|
19
|
+
* --concurrency = 3 (RFC Editor is shared infrastructure — be polite)
|
|
20
|
+
* --force = false (skip RFCs already on disk)
|
|
21
|
+
*
|
|
22
|
+
* Why not just `curl` in a loop?
|
|
23
|
+
* - Single source-priority list (rfc-editor first, datatracker fallback)
|
|
24
|
+
* - XML validation matches the MCP runtime expectations
|
|
25
|
+
* - Disk layout matches what the MCP runtime reads, no schema drift
|
|
26
|
+
*/
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=prefetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefetch.d.ts","sourceRoot":"","sources":["../../src/cli/prefetch.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* rfcxml-prefetch — pre-populate the on-disk RFCXML cache.
|
|
4
|
+
*
|
|
5
|
+
* Phase 3 component. Bridges the gap between the MCP runtime (which fetches
|
|
6
|
+
* one RFC at a time on demand) and operators who need offline / CI-pinned
|
|
7
|
+
* access to a known set of RFCs. The CLI walks a list of RFC numbers, fetches
|
|
8
|
+
* each via the same pipeline as the MCP server (so source-priority and
|
|
9
|
+
* validation are identical), and writes them to the same disk cache layout.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* rfcxml-prefetch --range 9000-9120
|
|
13
|
+
* rfcxml-prefetch --rfc 9110 --rfc 9112 --rfc 9000
|
|
14
|
+
* rfcxml-prefetch --range 9000-9010 --cache-dir ./my-cache
|
|
15
|
+
* rfcxml-prefetch --range 9000-9050 --concurrency 4 --force
|
|
16
|
+
*
|
|
17
|
+
* Defaults:
|
|
18
|
+
* --cache-dir = $RFCXML_CACHE_DIR (or ~/.cache/rfcxml-mcp if unset)
|
|
19
|
+
* --concurrency = 3 (RFC Editor is shared infrastructure — be polite)
|
|
20
|
+
* --force = false (skip RFCs already on disk)
|
|
21
|
+
*
|
|
22
|
+
* Why not just `curl` in a loop?
|
|
23
|
+
* - Single source-priority list (rfc-editor first, datatracker fallback)
|
|
24
|
+
* - XML validation matches the MCP runtime expectations
|
|
25
|
+
* - Disk layout matches what the MCP runtime reads, no schema drift
|
|
26
|
+
*/
|
|
27
|
+
import os from 'node:os';
|
|
28
|
+
import path from 'node:path';
|
|
29
|
+
import { promises as fs } from 'node:fs';
|
|
30
|
+
import { fetchRFCXML, resetDiskCacheForTesting } from '../services/rfc-fetcher.js';
|
|
31
|
+
import { DiskCache } from '../utils/disk-cache.js';
|
|
32
|
+
import { PACKAGE_INFO } from '../config.js';
|
|
33
|
+
const USAGE = `\
|
|
34
|
+
rfcxml-prefetch v${PACKAGE_INFO.version}
|
|
35
|
+
|
|
36
|
+
Pre-populate the RFCXML disk cache so the MCP server can serve cached RFCs
|
|
37
|
+
without hitting the network at runtime.
|
|
38
|
+
|
|
39
|
+
Usage:
|
|
40
|
+
rfcxml-prefetch --range A-B [--cache-dir DIR] [--concurrency N] [--force]
|
|
41
|
+
rfcxml-prefetch --rfc N [--rfc N ...]
|
|
42
|
+
rfcxml-prefetch --help
|
|
43
|
+
|
|
44
|
+
Options:
|
|
45
|
+
--range A-B Inclusive RFC number range (e.g. --range 9000-9120)
|
|
46
|
+
--rfc N Single RFC number; can be repeated
|
|
47
|
+
--cache-dir DIR Disk cache root (default: $RFCXML_CACHE_DIR or
|
|
48
|
+
~/.cache/rfcxml-mcp)
|
|
49
|
+
--concurrency N Parallel fetches (default: 3)
|
|
50
|
+
--force Re-download even if the file is already on disk
|
|
51
|
+
--help, -h Show this help
|
|
52
|
+
|
|
53
|
+
Notes:
|
|
54
|
+
- Old RFCs (< 8650) generally have no XML; those will fail and are skipped.
|
|
55
|
+
- The MCP server picks up the cache automatically when started with
|
|
56
|
+
RFCXML_CACHE_DIR pointing at the same directory.
|
|
57
|
+
`;
|
|
58
|
+
function parseArgs(argv) {
|
|
59
|
+
const opts = {
|
|
60
|
+
rfcs: [],
|
|
61
|
+
cacheDir: process.env.RFCXML_CACHE_DIR?.trim() || path.join(os.homedir(), '.cache', 'rfcxml-mcp'),
|
|
62
|
+
concurrency: 3,
|
|
63
|
+
force: false,
|
|
64
|
+
};
|
|
65
|
+
for (let i = 0; i < argv.length; i++) {
|
|
66
|
+
const a = argv[i];
|
|
67
|
+
switch (a) {
|
|
68
|
+
case '--help':
|
|
69
|
+
case '-h':
|
|
70
|
+
process.stdout.write(USAGE);
|
|
71
|
+
process.exit(0);
|
|
72
|
+
break;
|
|
73
|
+
case '--range': {
|
|
74
|
+
const v = argv[++i];
|
|
75
|
+
const m = v?.match(/^(\d+)-(\d+)$/);
|
|
76
|
+
if (!m)
|
|
77
|
+
throw new Error(`--range expects N-M, got "${v}"`);
|
|
78
|
+
const from = parseInt(m[1], 10);
|
|
79
|
+
const to = parseInt(m[2], 10);
|
|
80
|
+
if (from > to)
|
|
81
|
+
throw new Error(`--range: from (${from}) > to (${to})`);
|
|
82
|
+
for (let n = from; n <= to; n++)
|
|
83
|
+
opts.rfcs.push(n);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case '--rfc': {
|
|
87
|
+
const v = argv[++i];
|
|
88
|
+
const n = parseInt(v ?? '', 10);
|
|
89
|
+
if (!Number.isInteger(n) || n <= 0)
|
|
90
|
+
throw new Error(`--rfc expects positive integer`);
|
|
91
|
+
opts.rfcs.push(n);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case '--cache-dir':
|
|
95
|
+
opts.cacheDir = argv[++i];
|
|
96
|
+
if (!opts.cacheDir)
|
|
97
|
+
throw new Error(`--cache-dir requires a path`);
|
|
98
|
+
break;
|
|
99
|
+
case '--concurrency': {
|
|
100
|
+
const v = argv[++i];
|
|
101
|
+
const n = parseInt(v ?? '', 10);
|
|
102
|
+
if (!Number.isInteger(n) || n <= 0)
|
|
103
|
+
throw new Error(`--concurrency expects positive int`);
|
|
104
|
+
opts.concurrency = n;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case '--force':
|
|
108
|
+
opts.force = true;
|
|
109
|
+
break;
|
|
110
|
+
default:
|
|
111
|
+
throw new Error(`Unknown argument: ${a}\n\n${USAGE}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (opts.rfcs.length === 0) {
|
|
115
|
+
throw new Error(`No RFCs specified. Use --range or --rfc.\n\n${USAGE}`);
|
|
116
|
+
}
|
|
117
|
+
// Dedup + sort for stable output ordering.
|
|
118
|
+
opts.rfcs = Array.from(new Set(opts.rfcs)).sort((a, b) => a - b);
|
|
119
|
+
return opts;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Process one RFC. Returns a result row instead of throwing so the runner can
|
|
123
|
+
* tally totals across the whole batch.
|
|
124
|
+
*/
|
|
125
|
+
async function processOne(rfc, cache, force) {
|
|
126
|
+
if (!force && (await cache.has(rfc))) {
|
|
127
|
+
return { rfc, status: 'skipped' };
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const xml = await fetchRFCXML(rfc, { forceFresh: force });
|
|
131
|
+
// fetchRFCXML already writes to the disk cache when RFCXML_CACHE_DIR is
|
|
132
|
+
// set, so this is usually redundant. But we set it explicitly to handle
|
|
133
|
+
// the `--force` case where we want a guaranteed write even if the
|
|
134
|
+
// in-memory cache returned a stale entry on a previous loop iteration.
|
|
135
|
+
await cache.set(rfc, xml);
|
|
136
|
+
return { rfc, status: 'ok' };
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return {
|
|
140
|
+
rfc,
|
|
141
|
+
status: 'failed',
|
|
142
|
+
error: error instanceof Error ? error.message : String(error),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Bounded-concurrency runner. Plain Promise.all would saturate RFC Editor on
|
|
148
|
+
* a 1000-RFC range — keep it polite.
|
|
149
|
+
*/
|
|
150
|
+
async function runWithConcurrency(items, concurrency, worker) {
|
|
151
|
+
const results = [];
|
|
152
|
+
let cursor = 0;
|
|
153
|
+
async function next() {
|
|
154
|
+
while (cursor < items.length) {
|
|
155
|
+
const idx = cursor++;
|
|
156
|
+
results[idx] = await worker(items[idx]);
|
|
157
|
+
// Progress line — write to stderr so stdout stays clean for piping.
|
|
158
|
+
process.stderr.write(`[${idx + 1}/${items.length}] rfc${results[idx].rfc}: ${results[idx].status}` +
|
|
159
|
+
(results[idx].error ? ` (${results[idx].error.split('\n')[0]})` : '') +
|
|
160
|
+
'\n');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => next()));
|
|
164
|
+
return results;
|
|
165
|
+
}
|
|
166
|
+
async function main() {
|
|
167
|
+
let opts;
|
|
168
|
+
try {
|
|
169
|
+
opts = parseArgs(process.argv.slice(2));
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
173
|
+
process.exit(2);
|
|
174
|
+
}
|
|
175
|
+
// Plumb the cache dir into the env so fetchRFCXML's lazy init picks it up.
|
|
176
|
+
process.env.RFCXML_CACHE_DIR = opts.cacheDir;
|
|
177
|
+
resetDiskCacheForTesting();
|
|
178
|
+
const cache = new DiskCache(path.join(opts.cacheDir, 'xml'));
|
|
179
|
+
await fs.mkdir(cache.dir, { recursive: true });
|
|
180
|
+
process.stderr.write(`rfcxml-prefetch: ${opts.rfcs.length} RFCs -> ${cache.dir} ` +
|
|
181
|
+
`(concurrency=${opts.concurrency}, force=${opts.force})\n`);
|
|
182
|
+
const results = await runWithConcurrency(opts.rfcs, opts.concurrency, (rfc) => processOne(rfc, cache, opts.force));
|
|
183
|
+
const summary = results.reduce((acc, r) => {
|
|
184
|
+
acc[r.status]++;
|
|
185
|
+
return acc;
|
|
186
|
+
}, { ok: 0, skipped: 0, failed: 0 });
|
|
187
|
+
process.stderr.write(`\nDone: ${summary.ok} fetched, ${summary.skipped} skipped, ${summary.failed} failed\n`);
|
|
188
|
+
if (summary.failed > 0) {
|
|
189
|
+
process.stderr.write('\nFailures:\n');
|
|
190
|
+
for (const r of results.filter((r) => r.status === 'failed')) {
|
|
191
|
+
process.stderr.write(` rfc${r.rfc}: ${r.error}\n`);
|
|
192
|
+
}
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
main().catch((error) => {
|
|
197
|
+
process.stderr.write(`Fatal: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
});
|
|
200
|
+
//# sourceMappingURL=prefetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefetch.js","sourceRoot":"","sources":["../../src/cli/prefetch.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -57,34 +57,50 @@ export declare const RFC_CONFIG: {
|
|
|
57
57
|
};
|
|
58
58
|
/**
|
|
59
59
|
* RFC XML source URLs
|
|
60
|
-
* Defined in priority order
|
|
60
|
+
* Defined in priority order.
|
|
61
|
+
*
|
|
62
|
+
* NOTE: `xml2rfc.ietf.org` and `datatracker.ietf.org/doc/rfcN/xml/` both
|
|
63
|
+
* effectively redirect to / share the same backing storage as `rfc-editor.org`,
|
|
64
|
+
* so adding them as parallel race candidates does not improve latency in any
|
|
65
|
+
* meaningful way. They are kept here only as a defensive fallback (e.g., when
|
|
66
|
+
* the primary CDN is having transient issues). `tools.ietf.org` was retired in
|
|
67
|
+
* 2021 and is no longer included.
|
|
61
68
|
*/
|
|
62
69
|
export declare const RFC_XML_SOURCES: {
|
|
63
|
-
/** RFC Editor official */
|
|
70
|
+
/** RFC Editor official (primary) */
|
|
64
71
|
readonly rfcEditor: (num: number) => string;
|
|
65
|
-
/**
|
|
66
|
-
readonly ietfTools: (num: number) => string;
|
|
67
|
-
/** Datatracker */
|
|
72
|
+
/** Datatracker (redirects to rfc-editor.org) — defensive fallback only */
|
|
68
73
|
readonly datatracker: (num: number) => string;
|
|
69
74
|
};
|
|
70
75
|
/**
|
|
71
76
|
* RFC text source URLs
|
|
72
|
-
* Defined in priority order
|
|
77
|
+
* Defined in priority order.
|
|
78
|
+
*
|
|
79
|
+
* NOTE: `tools.ietf.org/rfc/rfcN.txt` was retired in February 2021 and now only
|
|
80
|
+
* 301-redirects to `rfc-editor.org`. We removed it because including it as a
|
|
81
|
+
* parallel race candidate just sends an extra request to the same backend.
|
|
73
82
|
*/
|
|
74
83
|
export declare const RFC_TEXT_SOURCES: {
|
|
75
|
-
/** RFC Editor official (
|
|
84
|
+
/** RFC Editor official (primary) */
|
|
76
85
|
readonly rfcEditor: (num: number) => string;
|
|
77
|
-
/** IETF Tools */
|
|
78
|
-
readonly ietfTools: (num: number) => string;
|
|
79
86
|
};
|
|
80
87
|
/**
|
|
81
88
|
* IETF Datatracker API
|
|
89
|
+
*
|
|
90
|
+
* Tastypie-based REST API. All endpoints are read-only / unauthenticated.
|
|
91
|
+
* See https://datatracker.ietf.org/api/ for the self-describing index.
|
|
82
92
|
*/
|
|
83
93
|
export declare const DATATRACKER_API: {
|
|
84
|
-
/** RFC document information */
|
|
94
|
+
/** RFC document core information (title, abstract, std_level, stream, group, time) */
|
|
85
95
|
readonly document: (num: number) => string;
|
|
96
|
+
/** Authors of an RFC (joined to /api/v1/person/person/...) */
|
|
97
|
+
readonly documentAuthor: (num: number, limit?: number) => string;
|
|
98
|
+
/** Recent document events (publication, changes, errata, etc.) */
|
|
99
|
+
readonly docEvent: (num: number, limit?: number) => string;
|
|
86
100
|
/** Documents that reference a given RFC (normative/informative, RFC sources only) */
|
|
87
101
|
readonly referencedBy: (num: number, limit?: number) => string;
|
|
102
|
+
/** Documents that this RFC references (normative/informative, RFC targets only) */
|
|
103
|
+
readonly references: (num: number, limit?: number) => string;
|
|
88
104
|
};
|
|
89
105
|
/**
|
|
90
106
|
* Check if RFC is likely available in XML format
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;GAEG;AACH,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,WAAW;IACtB,wBAAwB;;IAExB,8BAA8B;;IAE9B,6BAA6B;;CAErB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY;IACvB,iEAAiE;;;;;IAKjE,0BAA0B;;;;;IAK1B,8CAA8C;;;;;IAK9C,oCAAoC;;;;;CAK5B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,UAAU;IACrB;;;OAGG;;CAEK,CAAC;AAEX
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;GAEG;AACH,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,WAAW;IACtB,wBAAwB;;IAExB,8BAA8B;;IAE9B,6BAA6B;;CAErB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY;IACvB,iEAAiE;;;;;IAKjE,0BAA0B;;;;;IAK1B,8CAA8C;;;;;IAK9C,oCAAoC;;;;;CAK5B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,UAAU;IACrB;;;OAGG;;CAEK,CAAC;AAEX;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe;IAC1B,oCAAoC;8BACnB,MAAM;IACvB,0EAA0E;gCACvD,MAAM;CACjB,CAAC;AAEX;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;IAC3B,oCAAoC;8BACnB,MAAM;CACf,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,eAAe;IAC1B,sFAAsF;6BACtE,MAAM;IACtB,8DAA8D;mCACxC,MAAM;IAE5B,kEAAkE;6BAClD,MAAM;IAEtB,qFAAqF;iCACjE,MAAM;IAE1B,mFAAmF;+BACjE,MAAM;CAEhB,CAAC;AAEX;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAElE"}
|
package/dist/config.js
CHANGED
|
@@ -60,34 +60,50 @@ export const RFC_CONFIG = {
|
|
|
60
60
|
};
|
|
61
61
|
/**
|
|
62
62
|
* RFC XML source URLs
|
|
63
|
-
* Defined in priority order
|
|
63
|
+
* Defined in priority order.
|
|
64
|
+
*
|
|
65
|
+
* NOTE: `xml2rfc.ietf.org` and `datatracker.ietf.org/doc/rfcN/xml/` both
|
|
66
|
+
* effectively redirect to / share the same backing storage as `rfc-editor.org`,
|
|
67
|
+
* so adding them as parallel race candidates does not improve latency in any
|
|
68
|
+
* meaningful way. They are kept here only as a defensive fallback (e.g., when
|
|
69
|
+
* the primary CDN is having transient issues). `tools.ietf.org` was retired in
|
|
70
|
+
* 2021 and is no longer included.
|
|
64
71
|
*/
|
|
65
72
|
export const RFC_XML_SOURCES = {
|
|
66
|
-
/** RFC Editor official */
|
|
73
|
+
/** RFC Editor official (primary) */
|
|
67
74
|
rfcEditor: (num) => `https://www.rfc-editor.org/rfc/rfc${num}.xml`,
|
|
68
|
-
/**
|
|
69
|
-
ietfTools: (num) => `https://xml2rfc.ietf.org/public/rfc/rfc${num}.xml`,
|
|
70
|
-
/** Datatracker */
|
|
75
|
+
/** Datatracker (redirects to rfc-editor.org) — defensive fallback only */
|
|
71
76
|
datatracker: (num) => `https://datatracker.ietf.org/doc/rfc${num}/xml/`,
|
|
72
77
|
};
|
|
73
78
|
/**
|
|
74
79
|
* RFC text source URLs
|
|
75
|
-
* Defined in priority order
|
|
80
|
+
* Defined in priority order.
|
|
81
|
+
*
|
|
82
|
+
* NOTE: `tools.ietf.org/rfc/rfcN.txt` was retired in February 2021 and now only
|
|
83
|
+
* 301-redirects to `rfc-editor.org`. We removed it because including it as a
|
|
84
|
+
* parallel race candidate just sends an extra request to the same backend.
|
|
76
85
|
*/
|
|
77
86
|
export const RFC_TEXT_SOURCES = {
|
|
78
|
-
/** RFC Editor official (
|
|
87
|
+
/** RFC Editor official (primary) */
|
|
79
88
|
rfcEditor: (num) => `https://www.rfc-editor.org/rfc/rfc${num}.txt`,
|
|
80
|
-
/** IETF Tools */
|
|
81
|
-
ietfTools: (num) => `https://tools.ietf.org/rfc/rfc${num}.txt`,
|
|
82
89
|
};
|
|
83
90
|
/**
|
|
84
91
|
* IETF Datatracker API
|
|
92
|
+
*
|
|
93
|
+
* Tastypie-based REST API. All endpoints are read-only / unauthenticated.
|
|
94
|
+
* See https://datatracker.ietf.org/api/ for the self-describing index.
|
|
85
95
|
*/
|
|
86
96
|
export const DATATRACKER_API = {
|
|
87
|
-
/** RFC document information */
|
|
97
|
+
/** RFC document core information (title, abstract, std_level, stream, group, time) */
|
|
88
98
|
document: (num) => `https://datatracker.ietf.org/api/v1/doc/document/rfc${num}/`,
|
|
99
|
+
/** Authors of an RFC (joined to /api/v1/person/person/...) */
|
|
100
|
+
documentAuthor: (num, limit = 50) => `https://datatracker.ietf.org/api/v1/doc/documentauthor/?document__name=rfc${num}&limit=${limit}`,
|
|
101
|
+
/** Recent document events (publication, changes, errata, etc.) */
|
|
102
|
+
docEvent: (num, limit = 20) => `https://datatracker.ietf.org/api/v1/doc/docevent/?doc__name=rfc${num}&order_by=-time&limit=${limit}`,
|
|
89
103
|
/** Documents that reference a given RFC (normative/informative, RFC sources only) */
|
|
90
104
|
referencedBy: (num, limit = 100) => `https://datatracker.ietf.org/api/v1/doc/relateddocument/?target__name=rfc${num}&relationship__slug__in=refnorm,refinfo&source__type__slug=rfc&limit=${limit}`,
|
|
105
|
+
/** Documents that this RFC references (normative/informative, RFC targets only) */
|
|
106
|
+
references: (num, limit = 200) => `https://datatracker.ietf.org/api/v1/doc/relateddocument/?source__name=rfc${num}&relationship__slug__in=refnorm,refinfo&limit=${limit}`,
|
|
91
107
|
};
|
|
92
108
|
/**
|
|
93
109
|
* Check if RFC is likely available in XML format
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAsC,CAAC;AAEpF;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,WAAW,CAAC,IAAI;IACtB,OAAO,EAAE,WAAW,CAAC,OAAO;CACpB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,wBAAwB;IACxB,SAAS,EAAE,GAAG,YAAY,CAAC,IAAI,IAAI,YAAY,CAAC,OAAO,EAAE;IACzD,8BAA8B;IAC9B,OAAO,EAAE,KAAK;IACd,6BAA6B;IAC7B,UAAU,EAAE,CAAC;CACL,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,iEAAiE;IACjE,GAAG,EAAE;QACH,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,UAAU;KACjB;IACD,0BAA0B;IAC1B,IAAI,EAAE;QACJ,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,WAAW;KAClB;IACD,8CAA8C;IAC9C,QAAQ,EAAE;QACR,OAAO,EAAE,GAAG;QACZ,IAAI,EAAE,eAAe;KACtB;IACD,oCAAoC;IACpC,MAAM,EAAE;QACN,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,YAAY;KACnB;CACO,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB;;;OAGG;IACH,gBAAgB,EAAE,IAAI;CACd,CAAC;AAEX
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAsC,CAAC;AAEpF;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,WAAW,CAAC,IAAI;IACtB,OAAO,EAAE,WAAW,CAAC,OAAO;CACpB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,wBAAwB;IACxB,SAAS,EAAE,GAAG,YAAY,CAAC,IAAI,IAAI,YAAY,CAAC,OAAO,EAAE;IACzD,8BAA8B;IAC9B,OAAO,EAAE,KAAK;IACd,6BAA6B;IAC7B,UAAU,EAAE,CAAC;CACL,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,iEAAiE;IACjE,GAAG,EAAE;QACH,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,UAAU;KACjB;IACD,0BAA0B;IAC1B,IAAI,EAAE;QACJ,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,WAAW;KAClB;IACD,8CAA8C;IAC9C,QAAQ,EAAE;QACR,OAAO,EAAE,GAAG;QACZ,IAAI,EAAE,eAAe;KACtB;IACD,oCAAoC;IACpC,MAAM,EAAE;QACN,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,YAAY;KACnB;CACO,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB;;;OAGG;IACH,gBAAgB,EAAE,IAAI;CACd,CAAC;AAEX;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,oCAAoC;IACpC,SAAS,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,qCAAqC,GAAG,MAAM;IAC1E,0EAA0E;IAC1E,WAAW,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,uCAAuC,GAAG,OAAO;CACvE,CAAC;AAEX;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,oCAAoC;IACpC,SAAS,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,qCAAqC,GAAG,MAAM;CAClE,CAAC;AAEX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,sFAAsF;IACtF,QAAQ,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,uDAAuD,GAAG,GAAG;IACxF,8DAA8D;IAC9D,cAAc,EAAE,CAAC,GAAW,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,CAC1C,6EAA6E,GAAG,UAAU,KAAK,EAAE;IACnG,kEAAkE;IAClE,QAAQ,EAAE,CAAC,GAAW,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,CACpC,kEAAkE,GAAG,yBAAyB,KAAK,EAAE;IACvG,qFAAqF;IACrF,YAAY,EAAE,CAAC,GAAW,EAAE,KAAK,GAAG,GAAG,EAAE,EAAE,CACzC,4EAA4E,GAAG,wEAAwE,KAAK,EAAE;IAChK,mFAAmF;IACnF,UAAU,EAAE,CAAC,GAAW,EAAE,KAAK,GAAG,GAAG,EAAE,EAAE,CACvC,4EAA4E,GAAG,iDAAiD,KAAK,EAAE;CACjI,CAAC;AAEX;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAiB;IACvD,OAAO,SAAS,IAAI,UAAU,CAAC,gBAAgB,CAAC;AAClD,CAAC"}
|
|
@@ -2,26 +2,117 @@
|
|
|
2
2
|
* RFC Fetcher Service
|
|
3
3
|
* RFCXML source fetching and cache management
|
|
4
4
|
*/
|
|
5
|
-
import type { RFCMetadata, ReferencedByEntry } from '../types/index.js';
|
|
5
|
+
import type { Author, RFCMetadata, ReferencedByEntry } from '../types/index.js';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Reset the lazily-initialized disk cache. Tests use this to re-read the
|
|
8
|
+
* `RFCXML_CACHE_DIR` env var after mutating it. Not exposed in the MCP tool
|
|
9
|
+
* surface.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resetDiskCacheForTesting(): void;
|
|
12
|
+
/**
|
|
13
|
+
* Options for {@link fetchRFCXML}.
|
|
9
14
|
*/
|
|
10
|
-
export
|
|
15
|
+
export interface FetchRFCXMLOptions {
|
|
16
|
+
/**
|
|
17
|
+
* When true, bypass the in-memory LRU cache and the disk cache and force a
|
|
18
|
+
* fresh network fetch. Used by the prefetch CLI to refresh stale entries.
|
|
19
|
+
* The fresh result still gets written to both caches.
|
|
20
|
+
*/
|
|
21
|
+
forceFresh?: boolean;
|
|
22
|
+
}
|
|
11
23
|
/**
|
|
12
|
-
* Fetch
|
|
24
|
+
* Fetch RFCXML.
|
|
25
|
+
*
|
|
26
|
+
* Cache hierarchy (Phase 3):
|
|
27
|
+
* 1. in-memory LRU cache (`xmlCache`)
|
|
28
|
+
* 2. on-disk cache (`DiskCache`, opt-in via `RFCXML_CACHE_DIR`)
|
|
29
|
+
* 3. parallel network fetch from `RFC_XML_SOURCES`
|
|
30
|
+
*
|
|
31
|
+
* On a network fetch, the result is written back to both layers so the next
|
|
32
|
+
* call short-circuits at the in-memory layer.
|
|
13
33
|
*/
|
|
14
|
-
export declare function
|
|
34
|
+
export declare function fetchRFCXML(rfcNumber: number, options?: FetchRFCXMLOptions): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Options for fetchRFCMetadata.
|
|
37
|
+
*
|
|
38
|
+
* `includeAuthors` adds an extra parallel fetch to the documentauthor API and
|
|
39
|
+
* resolves person fullnames. Defaults to false to keep the base call cheap.
|
|
40
|
+
*/
|
|
41
|
+
export interface FetchRFCMetadataOptions {
|
|
42
|
+
includeAuthors?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Fetch RFC metadata (IETF Datatracker API).
|
|
46
|
+
*
|
|
47
|
+
* The base call hits a single endpoint (`/api/v1/doc/document/rfcN/`) and
|
|
48
|
+
* returns the core fields. Pass `includeAuthors: true` to also resolve the
|
|
49
|
+
* author list in parallel; it costs `1 + N` extra requests (1 for the
|
|
50
|
+
* documentauthor list, N for each person), but those are cached aggressively.
|
|
51
|
+
*/
|
|
52
|
+
export declare function fetchRFCMetadata(rfcNumber: number, options?: FetchRFCMetadataOptions): Promise<RFCMetadata>;
|
|
15
53
|
/**
|
|
16
54
|
* Fetch RFC text (parallel fetch)
|
|
17
55
|
* Sends concurrent requests to multiple sources and returns the first successful response
|
|
18
56
|
*/
|
|
19
57
|
export declare function fetchRFCText(rfcNumber: number): Promise<string>;
|
|
20
58
|
/**
|
|
21
|
-
*
|
|
22
|
-
|
|
59
|
+
* Doc event entry exposed to handlers.
|
|
60
|
+
*/
|
|
61
|
+
export interface DocEventEntry {
|
|
62
|
+
type: string;
|
|
63
|
+
desc: string;
|
|
64
|
+
time: string;
|
|
65
|
+
rev: string | null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Fetch authors of an RFC via Datatracker `documentauthor` API.
|
|
69
|
+
* Resolves each author's fullname in parallel against the person endpoint.
|
|
70
|
+
* Returns an empty array on failure (graceful degradation).
|
|
71
|
+
*/
|
|
72
|
+
export declare function fetchAuthors(rfcNumber: number): Promise<Author[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Fetch recent document events (publication, sync, errata-tagging, etc.).
|
|
75
|
+
*
|
|
76
|
+
* Note: Datatracker's tastypie API does not allow ordering by `time` directly,
|
|
77
|
+
* so we rely on the natural id-descending order returned by the endpoint
|
|
78
|
+
* (events are inserted monotonically) and limit on the server side.
|
|
79
|
+
* Returns an empty array on failure.
|
|
80
|
+
*/
|
|
81
|
+
export declare function fetchDocEvents(rfcNumber: number, limit?: number): Promise<DocEventEntry[]>;
|
|
82
|
+
/**
|
|
83
|
+
* Fetch RFCs that reference this RFC (via IETF Datatracker API).
|
|
84
|
+
* Returns only published RFCs (not drafts) with normative/informative relationships.
|
|
23
85
|
*/
|
|
24
86
|
export declare function fetchReferencedBy(rfcNumber: number): Promise<ReferencedByEntry[]>;
|
|
87
|
+
/**
|
|
88
|
+
* A reference entry as returned by `fetchReferences` — i.e., RFCs that the
|
|
89
|
+
* given RFC points to via normative or informative reference.
|
|
90
|
+
*
|
|
91
|
+
* Distinct from `RFCReference` (which is parsed out of the XML/text body and
|
|
92
|
+
* carries anchor/title information). This API-based variant only carries the
|
|
93
|
+
* RFC number and relationship slug, but works even when the XML is unavailable
|
|
94
|
+
* (RFCs published before 8650 / RFCXML v3).
|
|
95
|
+
*/
|
|
96
|
+
export interface ReferenceEntry {
|
|
97
|
+
rfcNumber: number;
|
|
98
|
+
name: string;
|
|
99
|
+
relationship: 'refnorm' | 'refinfo';
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Fetch RFCs that this RFC references (normative + informative) via the
|
|
103
|
+
* Datatracker `relateddocument` API.
|
|
104
|
+
*
|
|
105
|
+
* Why this exists: `getParsedRFC` extracts references from XML/text body, but
|
|
106
|
+
* for old RFCs (< 8650) we lose the references entirely when XML is not
|
|
107
|
+
* available. Hitting the Datatracker API gives us a structured fallback that
|
|
108
|
+
* is independent of the body format.
|
|
109
|
+
*
|
|
110
|
+
* The API target field can point to BCP/STD aliases (`bcp35`, `std97`) as well
|
|
111
|
+
* as actual RFCs (`rfc9000`). Aliases are filtered out here — only real RFC
|
|
112
|
+
* targets are returned. Callers wanting alias resolution can call the
|
|
113
|
+
* documentauthor / docalias endpoints separately.
|
|
114
|
+
*/
|
|
115
|
+
export declare function fetchReferences(rfcNumber: number): Promise<ReferenceEntry[]>;
|
|
25
116
|
/**
|
|
26
117
|
* Check if RFC is available in XML format
|
|
27
118
|
* Note: RFC 8650 (December 2019) and later use official RFCXML v3
|
|
@@ -37,7 +128,8 @@ export declare class RFCXMLNotAvailableError extends Error {
|
|
|
37
128
|
constructor(rfcNumber: number, originalErrors?: string[]);
|
|
38
129
|
}
|
|
39
130
|
/**
|
|
40
|
-
* Clear all caches
|
|
131
|
+
* Clear all caches.
|
|
132
|
+
* Includes the secondary caches added for Phase 1 API enrichment.
|
|
41
133
|
*/
|
|
42
134
|
export declare function clearCache(): void;
|
|
43
135
|
//# sourceMappingURL=rfc-fetcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rfc-fetcher.d.ts","sourceRoot":"","sources":["../../src/services/rfc-fetcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"rfc-fetcher.d.ts","sourceRoot":"","sources":["../../src/services/rfc-fetcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAoChF;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AASD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,MAAM,CAAC,CA8CjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,WAAW,CAAC,CA+CtB;AAuBD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BrE;AA2ED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AA4BD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmCvE;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAkB5F;AAuBD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAiCvF;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,SAAS,GAAG,SAAS,CAAC;CACrC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAiClF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,QAAQ,EAAE,OAAO,CAAC;IAClC,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,SAAS,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,EAAO;CAoB7D;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAMjC"}
|