@zhixuan92/multi-model-agent-core 4.7.20 → 4.9.0
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/config/schema.d.ts +2 -20
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +9 -80
- package/dist/config/schema.js.map +1 -1
- package/dist/events/task-envelope.d.ts +8 -1
- package/dist/events/task-envelope.d.ts.map +1 -1
- package/dist/events/task-envelope.js +2 -1
- package/dist/events/task-envelope.js.map +1 -1
- package/dist/events/wire-schema.d.ts +4 -0
- package/dist/events/wire-schema.d.ts.map +1 -1
- package/dist/events/wire-schema.js +3 -3
- package/dist/events/wire-schema.js.map +1 -1
- package/dist/journal/default-schema.d.ts +2 -0
- package/dist/journal/default-schema.d.ts.map +1 -0
- package/dist/journal/default-schema.js +27 -0
- package/dist/journal/default-schema.js.map +1 -0
- package/dist/journal/types.d.ts +22 -0
- package/dist/journal/types.d.ts.map +1 -0
- package/dist/journal/types.js +5 -0
- package/dist/journal/types.js.map +1 -0
- package/dist/lifecycle/annotate-parser.js +1 -1
- package/dist/lifecycle/annotate-parser.js.map +1 -1
- package/dist/lifecycle/derive-completion.js +1 -1
- package/dist/lifecycle/derive-completion.js.map +1 -1
- package/dist/lifecycle/handlers/annotate-stage.d.ts.map +1 -1
- package/dist/lifecycle/handlers/annotate-stage.js +9 -3
- package/dist/lifecycle/handlers/annotate-stage.js.map +1 -1
- package/dist/lifecycle/handlers/baseline-handlers.d.ts.map +1 -1
- package/dist/lifecycle/handlers/baseline-handlers.js +10 -0
- package/dist/lifecycle/handlers/baseline-handlers.js.map +1 -1
- package/dist/lifecycle/handlers/compose-commit-message.d.ts +15 -0
- package/dist/lifecycle/handlers/compose-commit-message.d.ts.map +1 -0
- package/dist/lifecycle/handlers/compose-commit-message.js +227 -0
- package/dist/lifecycle/handlers/compose-commit-message.js.map +1 -0
- package/dist/lifecycle/handlers/enrich-runtime-result.d.ts.map +1 -1
- package/dist/lifecycle/handlers/enrich-runtime-result.js +31 -0
- package/dist/lifecycle/handlers/enrich-runtime-result.js.map +1 -1
- package/dist/lifecycle/handlers/git-commit-handler.d.ts.map +1 -1
- package/dist/lifecycle/handlers/git-commit-handler.js +2 -15
- package/dist/lifecycle/handlers/git-commit-handler.js.map +1 -1
- package/dist/lifecycle/handlers/implement-stage.d.ts.map +1 -1
- package/dist/lifecycle/handlers/implement-stage.js +4 -1
- package/dist/lifecycle/handlers/implement-stage.js.map +1 -1
- package/dist/lifecycle/handlers/journal-review-prompt.d.ts +7 -0
- package/dist/lifecycle/handlers/journal-review-prompt.d.ts.map +1 -0
- package/dist/lifecycle/handlers/journal-review-prompt.js +54 -0
- package/dist/lifecycle/handlers/journal-review-prompt.js.map +1 -0
- package/dist/lifecycle/handlers/quality-review-prompt.d.ts +1 -0
- package/dist/lifecycle/handlers/quality-review-prompt.d.ts.map +1 -1
- package/dist/lifecycle/handlers/quality-review-prompt.js +8 -0
- package/dist/lifecycle/handlers/quality-review-prompt.js.map +1 -1
- package/dist/lifecycle/handlers/review-stage.d.ts.map +1 -1
- package/dist/lifecycle/handlers/review-stage.js +57 -13
- package/dist/lifecycle/handlers/review-stage.js.map +1 -1
- package/dist/lifecycle/handlers/rework-stage.d.ts.map +1 -1
- package/dist/lifecycle/handlers/rework-stage.js +3 -0
- package/dist/lifecycle/handlers/rework-stage.js.map +1 -1
- package/dist/lifecycle/handlers/spec-review-prompt.d.ts +1 -0
- package/dist/lifecycle/handlers/spec-review-prompt.d.ts.map +1 -1
- package/dist/lifecycle/handlers/spec-review-prompt.js +8 -0
- package/dist/lifecycle/handlers/spec-review-prompt.js.map +1 -1
- package/dist/lifecycle/perform-implementation.d.ts.map +1 -1
- package/dist/lifecycle/perform-implementation.js +7 -4
- package/dist/lifecycle/perform-implementation.js.map +1 -1
- package/dist/lifecycle/read-route-criteria.d.ts +3 -2
- package/dist/lifecycle/read-route-criteria.d.ts.map +1 -1
- package/dist/lifecycle/read-route-criteria.js +2 -0
- package/dist/lifecycle/read-route-criteria.js.map +1 -1
- package/dist/lifecycle/research-pre-loop.d.ts +5 -4
- package/dist/lifecycle/research-pre-loop.d.ts.map +1 -1
- package/dist/lifecycle/research-pre-loop.js +7 -10
- package/dist/lifecycle/research-pre-loop.js.map +1 -1
- package/dist/lifecycle/stage-io.d.ts +7 -3
- package/dist/lifecycle/stage-io.d.ts.map +1 -1
- package/dist/lifecycle/stage-io.js +2 -2
- package/dist/lifecycle/stage-io.js.map +1 -1
- package/dist/lifecycle/stage-progression.d.ts.map +1 -1
- package/dist/lifecycle/stage-progression.js +2 -0
- package/dist/lifecycle/stage-progression.js.map +1 -1
- package/dist/lifecycle/task-runner.d.ts +14 -0
- package/dist/lifecycle/task-runner.d.ts.map +1 -1
- package/dist/lifecycle/task-runner.js +71 -2
- package/dist/lifecycle/task-runner.js.map +1 -1
- package/dist/lifecycle/worker-output-contract.d.ts +3 -1
- package/dist/lifecycle/worker-output-contract.d.ts.map +1 -1
- package/dist/lifecycle/worker-output-contract.js +4 -1
- package/dist/lifecycle/worker-output-contract.js.map +1 -1
- package/dist/providers/claude-session.d.ts +1 -0
- package/dist/providers/claude-session.d.ts.map +1 -1
- package/dist/providers/claude-session.js +9 -0
- package/dist/providers/claude-session.js.map +1 -1
- package/dist/providers/claude-skill-plugin.d.ts +12 -0
- package/dist/providers/claude-skill-plugin.d.ts.map +1 -0
- package/dist/providers/claude-skill-plugin.js +27 -0
- package/dist/providers/claude-skill-plugin.js.map +1 -0
- package/dist/providers/codex-cli-launch.d.ts +2 -0
- package/dist/providers/codex-cli-launch.d.ts.map +1 -1
- package/dist/providers/codex-cli-launch.js +3 -1
- package/dist/providers/codex-cli-launch.js.map +1 -1
- package/dist/providers/codex-cli-session.d.ts +2 -0
- package/dist/providers/codex-cli-session.d.ts.map +1 -1
- package/dist/providers/codex-cli-session.js +13 -0
- package/dist/providers/codex-cli-session.js.map +1 -1
- package/dist/providers/codex-skill-home.d.ts +15 -0
- package/dist/providers/codex-skill-home.d.ts.map +1 -0
- package/dist/providers/codex-skill-home.js +23 -0
- package/dist/providers/codex-skill-home.js.map +1 -0
- package/dist/providers/skill-resolver.d.ts +17 -0
- package/dist/providers/skill-resolver.d.ts.map +1 -0
- package/dist/providers/skill-resolver.js +123 -0
- package/dist/providers/skill-resolver.js.map +1 -0
- package/dist/reporting/headline-templates/journal-recall.d.ts +3 -0
- package/dist/reporting/headline-templates/journal-recall.d.ts.map +1 -0
- package/dist/reporting/headline-templates/journal-recall.js +9 -0
- package/dist/reporting/headline-templates/journal-recall.js.map +1 -0
- package/dist/reporting/headline-templates/journal.d.ts +3 -0
- package/dist/reporting/headline-templates/journal.d.ts.map +1 -0
- package/dist/reporting/headline-templates/journal.js +17 -0
- package/dist/reporting/headline-templates/journal.js.map +1 -0
- package/dist/reporting/report-parser-slots/journal-report.d.ts +8 -0
- package/dist/reporting/report-parser-slots/journal-report.d.ts.map +1 -0
- package/dist/reporting/report-parser-slots/journal-report.js +12 -0
- package/dist/reporting/report-parser-slots/journal-report.js.map +1 -0
- package/dist/research/adapters/index.d.ts +0 -1
- package/dist/research/adapters/index.d.ts.map +1 -1
- package/dist/research/adapters/index.js +0 -3
- package/dist/research/adapters/index.js.map +1 -1
- package/dist/research/adapters/types.d.ts +1 -1
- package/dist/research/adapters/types.d.ts.map +1 -1
- package/dist/research/evidence-pack.d.ts +19 -1
- package/dist/research/evidence-pack.d.ts.map +1 -1
- package/dist/research/evidence-pack.js +36 -1
- package/dist/research/evidence-pack.js.map +1 -1
- package/dist/research/orchestrator.d.ts +0 -4
- package/dist/research/orchestrator.d.ts.map +1 -1
- package/dist/research/orchestrator.js +4 -53
- package/dist/research/orchestrator.js.map +1 -1
- package/dist/research/query-plan.d.ts +0 -2
- package/dist/research/query-plan.d.ts.map +1 -1
- package/dist/research/query-plan.js +1 -8
- package/dist/research/query-plan.js.map +1 -1
- package/dist/research/user-agent.js +1 -1
- package/dist/research/user-agent.js.map +1 -1
- package/dist/research/web-search.d.ts +2 -1
- package/dist/research/web-search.d.ts.map +1 -1
- package/dist/research/web-search.js +31 -7
- package/dist/research/web-search.js.map +1 -1
- package/dist/tool-surface/register-all-tools.d.ts.map +1 -1
- package/dist/tool-surface/register-all-tools.js +4 -0
- package/dist/tool-surface/register-all-tools.js.map +1 -1
- package/dist/tools/delegate/brief-slot.d.ts +4 -0
- package/dist/tools/delegate/brief-slot.d.ts.map +1 -1
- package/dist/tools/delegate/brief-slot.js +2 -0
- package/dist/tools/delegate/brief-slot.js.map +1 -1
- package/dist/tools/delegate/schema.d.ts +1 -0
- package/dist/tools/delegate/schema.d.ts.map +1 -1
- package/dist/tools/delegate/schema.js +4 -0
- package/dist/tools/delegate/schema.js.map +1 -1
- package/dist/tools/delegate/tool-config.d.ts.map +1 -1
- package/dist/tools/delegate/tool-config.js +2 -0
- package/dist/tools/delegate/tool-config.js.map +1 -1
- package/dist/tools/execute-plan/tool-config.d.ts.map +1 -1
- package/dist/tools/execute-plan/tool-config.js +3 -0
- package/dist/tools/execute-plan/tool-config.js.map +1 -1
- package/dist/tools/journal/recall/brief-slot.d.ts +7 -0
- package/dist/tools/journal/recall/brief-slot.d.ts.map +1 -0
- package/dist/tools/journal/recall/brief-slot.js +5 -0
- package/dist/tools/journal/recall/brief-slot.js.map +1 -0
- package/dist/tools/journal/recall/implementer-criteria.d.ts +9 -0
- package/dist/tools/journal/recall/implementer-criteria.d.ts.map +1 -0
- package/dist/tools/journal/recall/implementer-criteria.js +23 -0
- package/dist/tools/journal/recall/implementer-criteria.js.map +1 -0
- package/dist/tools/journal/recall/schema.d.ts +54 -0
- package/dist/tools/journal/recall/schema.d.ts.map +1 -0
- package/dist/tools/journal/recall/schema.js +10 -0
- package/dist/tools/journal/recall/schema.js.map +1 -0
- package/dist/tools/journal/recall/subtypes.d.ts +4 -0
- package/dist/tools/journal/recall/subtypes.d.ts.map +1 -0
- package/dist/tools/journal/recall/subtypes.js +25 -0
- package/dist/tools/journal/recall/subtypes.js.map +1 -0
- package/dist/tools/journal/recall/tool-config.d.ts +8 -0
- package/dist/tools/journal/recall/tool-config.d.ts.map +1 -0
- package/dist/tools/journal/recall/tool-config.js +46 -0
- package/dist/tools/journal/recall/tool-config.js.map +1 -0
- package/dist/tools/journal/record/brief-slot.d.ts +14 -0
- package/dist/tools/journal/record/brief-slot.d.ts.map +1 -0
- package/dist/tools/journal/record/brief-slot.js +18 -0
- package/dist/tools/journal/record/brief-slot.js.map +1 -0
- package/dist/tools/journal/record/implementer-criteria.d.ts +6 -0
- package/dist/tools/journal/record/implementer-criteria.d.ts.map +1 -0
- package/dist/tools/journal/record/implementer-criteria.js +17 -0
- package/dist/tools/journal/record/implementer-criteria.js.map +1 -0
- package/dist/tools/journal/record/schema.d.ts +55 -0
- package/dist/tools/journal/record/schema.d.ts.map +1 -0
- package/dist/tools/journal/record/schema.js +13 -0
- package/dist/tools/journal/record/schema.js.map +1 -0
- package/dist/tools/journal/record/tool-config.d.ts +7 -0
- package/dist/tools/journal/record/tool-config.d.ts.map +1 -0
- package/dist/tools/journal/record/tool-config.js +40 -0
- package/dist/tools/journal/record/tool-config.js.map +1 -0
- package/dist/tools/research/brief-slot.d.ts +0 -2
- package/dist/tools/research/brief-slot.d.ts.map +1 -1
- package/dist/tools/research/brief-slot.js.map +1 -1
- package/dist/tools/research/implementer-criteria.d.ts +0 -1
- package/dist/tools/research/implementer-criteria.d.ts.map +1 -1
- package/dist/tools/research/implementer-criteria.js +3 -15
- package/dist/tools/research/implementer-criteria.js.map +1 -1
- package/dist/tools/research/tool-config.d.ts.map +1 -1
- package/dist/tools/research/tool-config.js +0 -1
- package/dist/tools/research/tool-config.js.map +1 -1
- package/dist/types/run-result.d.ts +9 -0
- package/dist/types/run-result.d.ts.map +1 -1
- package/dist/types/task-spec.d.ts +5 -1
- package/dist/types/task-spec.d.ts.map +1 -1
- package/package.json +17 -1
- package/dist/research/adapters/generic-rss.d.ts +0 -8
- package/dist/research/adapters/generic-rss.d.ts.map +0 -1
- package/dist/research/adapters/generic-rss.js +0 -26
- package/dist/research/adapters/generic-rss.js.map +0 -1
- package/dist/research/ssrf-guard.d.ts +0 -12
- package/dist/research/ssrf-guard.d.ts.map +0 -1
- package/dist/research/ssrf-guard.js +0 -209
- package/dist/research/ssrf-guard.js.map +0 -1
- package/dist/research/untrusted-content.d.ts +0 -13
- package/dist/research/untrusted-content.d.ts.map +0 -1
- package/dist/research/untrusted-content.js +0 -9
- package/dist/research/untrusted-content.js.map +0 -1
- package/dist/research/web-fetch-helpers.d.ts +0 -44
- package/dist/research/web-fetch-helpers.d.ts.map +0 -1
- package/dist/research/web-fetch-helpers.js +0 -209
- package/dist/research/web-fetch-helpers.js.map +0 -1
- package/dist/research/web-fetch.d.ts +0 -55
- package/dist/research/web-fetch.d.ts.map +0 -1
- package/dist/research/web-fetch.js +0 -236
- package/dist/research/web-fetch.js.map +0 -1
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { isIP } from 'node:net';
|
|
2
|
-
import { Readability } from '@mozilla/readability';
|
|
3
|
-
import { JSDOM } from 'jsdom';
|
|
4
|
-
import { resolveAndPin, SsrfBlocked } from './ssrf-guard.js';
|
|
5
|
-
/** Max bytes to drain from a redirect response body before giving up. */
|
|
6
|
-
export const REDIRECT_DRAIN_CAP = 64 * 1024;
|
|
7
|
-
export const REDIRECT_ERR_CODE_MAP = {
|
|
8
|
-
web_fetch_off_allowlist: 'web_fetch_redirect_off_allowlist',
|
|
9
|
-
web_fetch_invalid_url: 'web_fetch_redirect_invalid_url',
|
|
10
|
-
web_fetch_invalid_scheme: 'web_fetch_redirect_scheme_downgrade',
|
|
11
|
-
web_fetch_ip_literal_blocked: 'web_fetch_redirect_ip_literal_blocked',
|
|
12
|
-
web_fetch_private_ip_blocked: 'web_fetch_redirect_private_ip_blocked',
|
|
13
|
-
web_fetch_reserved_ip_blocked: 'web_fetch_redirect_reserved_ip_blocked',
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* Races a promise against an AbortSignal. If the signal fires first, throws
|
|
17
|
-
* a DOMException with name 'AbortError' so callers can map it to timeout.
|
|
18
|
-
*/
|
|
19
|
-
export async function withDeadline(promise, signal) {
|
|
20
|
-
if (signal.aborted)
|
|
21
|
-
throw new DOMException('Aborted', 'AbortError');
|
|
22
|
-
return new Promise((resolve, reject) => {
|
|
23
|
-
const onAbort = () => reject(new DOMException('Aborted', 'AbortError'));
|
|
24
|
-
signal.addEventListener('abort', onAbort, { once: true });
|
|
25
|
-
promise.then((result) => {
|
|
26
|
-
signal.removeEventListener('abort', onAbort);
|
|
27
|
-
resolve(result);
|
|
28
|
-
}, (err) => {
|
|
29
|
-
signal.removeEventListener('abort', onAbort);
|
|
30
|
-
reject(err);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
export async function validateAndPinURL(raw, hostAllowlist, privateNetworkHosts, resolveIP, signal) {
|
|
35
|
-
let url;
|
|
36
|
-
try {
|
|
37
|
-
url = new URL(raw);
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return { ok: false, reasonCode: 'web_fetch_invalid_url' };
|
|
41
|
-
}
|
|
42
|
-
if (url.protocol !== 'https:') {
|
|
43
|
-
return { ok: false, reasonCode: 'web_fetch_invalid_scheme' };
|
|
44
|
-
}
|
|
45
|
-
const stripped = url.hostname.replace(/^\[|\]$/g, '');
|
|
46
|
-
if (isIP(stripped) !== 0) {
|
|
47
|
-
return { ok: false, reasonCode: 'web_fetch_ip_literal_blocked' };
|
|
48
|
-
}
|
|
49
|
-
const host = url.hostname.toLowerCase();
|
|
50
|
-
if (!hostAllowlist.has(host)) {
|
|
51
|
-
return { ok: false, reasonCode: 'web_fetch_off_allowlist', host };
|
|
52
|
-
}
|
|
53
|
-
const allowPrivate = privateNetworkHosts.has(host);
|
|
54
|
-
let pinnedIP;
|
|
55
|
-
try {
|
|
56
|
-
pinnedIP = await withDeadline(resolveAndPin(host, {
|
|
57
|
-
resolve: resolveIP ? async (h) => [await resolveIP(h)] : undefined,
|
|
58
|
-
allowPrivateForHost: allowPrivate,
|
|
59
|
-
}), signal);
|
|
60
|
-
}
|
|
61
|
-
catch (e) {
|
|
62
|
-
if (e instanceof DOMException && e.name === 'AbortError') {
|
|
63
|
-
throw e;
|
|
64
|
-
}
|
|
65
|
-
if (e instanceof SsrfBlocked) {
|
|
66
|
-
return { ok: false, reasonCode: e.code, host };
|
|
67
|
-
}
|
|
68
|
-
return { ok: false, reasonCode: 'web_fetch_dns_resolution_failed', host };
|
|
69
|
-
}
|
|
70
|
-
return { ok: true, url, host, pinnedIP };
|
|
71
|
-
}
|
|
72
|
-
export function extractContentType(headers) {
|
|
73
|
-
const raw = headers['content-type'];
|
|
74
|
-
if (typeof raw === 'string') {
|
|
75
|
-
return raw.split(';')[0].trim().toLowerCase();
|
|
76
|
-
}
|
|
77
|
-
if (Array.isArray(raw) && raw.length > 0) {
|
|
78
|
-
return String(raw[0]).split(';')[0].trim().toLowerCase();
|
|
79
|
-
}
|
|
80
|
-
return '';
|
|
81
|
-
}
|
|
82
|
-
export function isRedirect(status) {
|
|
83
|
-
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
84
|
-
}
|
|
85
|
-
export function extractLocation(headers) {
|
|
86
|
-
const loc = headers['location'];
|
|
87
|
-
if (typeof loc === 'string')
|
|
88
|
-
return loc;
|
|
89
|
-
if (Array.isArray(loc) && loc.length > 0)
|
|
90
|
-
return String(loc[0]);
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
export function extractBodyFromHTML(html) {
|
|
94
|
-
let dom;
|
|
95
|
-
try {
|
|
96
|
-
dom = new JSDOM(html, { url: 'https://localhost/' });
|
|
97
|
-
const reader = new Readability(dom.window.document);
|
|
98
|
-
const article = reader.parse();
|
|
99
|
-
if (article?.textContent) {
|
|
100
|
-
return article.textContent;
|
|
101
|
-
}
|
|
102
|
-
return dom.window.document.body?.textContent?.trim() ?? html;
|
|
103
|
-
}
|
|
104
|
-
catch {
|
|
105
|
-
try {
|
|
106
|
-
return dom?.window.document.body?.textContent?.trim() || html;
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
return html;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
export function stripCredentialsFromURL(url) {
|
|
114
|
-
if (!url.username && !url.password)
|
|
115
|
-
return false;
|
|
116
|
-
url.username = '';
|
|
117
|
-
url.password = '';
|
|
118
|
-
return true;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Read a response body with a byte cap and abort-signal awareness.
|
|
122
|
-
* Stream errors (non-abort) are re-thrown so the caller can map them to
|
|
123
|
-
* web_fetch_body_read_failed rather than silently returning partial content.
|
|
124
|
-
*/
|
|
125
|
-
export async function readBody(body, maxBytes, signal) {
|
|
126
|
-
if (!body)
|
|
127
|
-
return { text: '', bytesReturned: 0, truncated: false };
|
|
128
|
-
const chunks = [];
|
|
129
|
-
let total = 0;
|
|
130
|
-
let truncated = false;
|
|
131
|
-
for await (const chunk of body) {
|
|
132
|
-
if (signal.aborted) {
|
|
133
|
-
throw new DOMException('Aborted', 'AbortError');
|
|
134
|
-
}
|
|
135
|
-
const remaining = maxBytes - total;
|
|
136
|
-
if (remaining <= 0) {
|
|
137
|
-
truncated = true;
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
const value = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
|
|
141
|
-
if (value.length > remaining) {
|
|
142
|
-
chunks.push(value.subarray(0, remaining));
|
|
143
|
-
total += remaining;
|
|
144
|
-
truncated = true;
|
|
145
|
-
break;
|
|
146
|
-
}
|
|
147
|
-
chunks.push(value);
|
|
148
|
-
total += value.length;
|
|
149
|
-
}
|
|
150
|
-
const decoder = new TextDecoder();
|
|
151
|
-
let text = '';
|
|
152
|
-
for (const chunk of chunks) {
|
|
153
|
-
text += decoder.decode(chunk, { stream: true });
|
|
154
|
-
}
|
|
155
|
-
text += decoder.decode();
|
|
156
|
-
return { text, bytesReturned: total, truncated };
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Drain a response body with a size cap and abort-signal awareness.
|
|
160
|
-
* Used for redirect responses and rejected content types.
|
|
161
|
-
*/
|
|
162
|
-
export async function drainBody(body, signal) {
|
|
163
|
-
if (!body)
|
|
164
|
-
return;
|
|
165
|
-
let drained = 0;
|
|
166
|
-
try {
|
|
167
|
-
for await (const chunk of body) {
|
|
168
|
-
if (signal.aborted)
|
|
169
|
-
break;
|
|
170
|
-
let len = 0;
|
|
171
|
-
if (typeof chunk === 'string') {
|
|
172
|
-
len = Buffer.byteLength(chunk);
|
|
173
|
-
}
|
|
174
|
-
else if (chunk instanceof Uint8Array) {
|
|
175
|
-
len = chunk.length;
|
|
176
|
-
}
|
|
177
|
-
else if (Buffer.isBuffer(chunk)) {
|
|
178
|
-
len = chunk.length;
|
|
179
|
-
}
|
|
180
|
-
drained += len;
|
|
181
|
-
if (drained > REDIRECT_DRAIN_CAP)
|
|
182
|
-
break;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch {
|
|
186
|
-
// drain errors are ignorable
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
export function isUndiciTimeout(err) {
|
|
190
|
-
if (!(err instanceof Error))
|
|
191
|
-
return false;
|
|
192
|
-
const code = err.code;
|
|
193
|
-
return code === 'UND_ERR_CONNECT_TIMEOUT'
|
|
194
|
-
|| code === 'UND_ERR_HEADERS_TIMEOUT'
|
|
195
|
-
|| code === 'UND_ERR_BODY_TIMEOUT';
|
|
196
|
-
}
|
|
197
|
-
export function mapRequestError(err, signal, host) {
|
|
198
|
-
if (signal.aborted) {
|
|
199
|
-
return { status: 'error', reasonCode: 'web_fetch_timeout', host, credentialsStripped: false };
|
|
200
|
-
}
|
|
201
|
-
if (err instanceof DOMException && err.name === 'AbortError') {
|
|
202
|
-
return { status: 'error', reasonCode: 'web_fetch_timeout', host, credentialsStripped: false };
|
|
203
|
-
}
|
|
204
|
-
if (isUndiciTimeout(err)) {
|
|
205
|
-
return { status: 'error', reasonCode: 'web_fetch_timeout', host, credentialsStripped: false };
|
|
206
|
-
}
|
|
207
|
-
return { status: 'error', reasonCode: 'web_fetch_request_failed', host, credentialsStripped: false };
|
|
208
|
-
}
|
|
209
|
-
//# sourceMappingURL=web-fetch-helpers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"web-fetch-helpers.js","sourceRoot":"","sources":["../../src/research/web-fetch-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { LookupFunction } from 'node:net';
|
|
2
|
-
import type { ResearchConfig } from '../config/schema.js';
|
|
3
|
-
export interface WebFetchInput {
|
|
4
|
-
url: string;
|
|
5
|
-
cfg: ResearchConfig['fetch'];
|
|
6
|
-
hostAllowlist: ReadonlySet<string>;
|
|
7
|
-
privateNetworkHosts?: ReadonlySet<string>;
|
|
8
|
-
resolveIP?: (host: string) => Promise<string>;
|
|
9
|
-
/** Test seam — when present, treated as the IP that the connect callback
|
|
10
|
-
* "resolved" at request time. Production must not pass this. */
|
|
11
|
-
_testConnectResolvedIp?: string;
|
|
12
|
-
/** Test-only injection seam. When set, webFetch uses the returned dispatcher
|
|
13
|
-
* (or, if it returns undefined, no dispatcher — so undici's global MockAgent
|
|
14
|
-
* can intercept). Production never sets this: it always uses the connect-guard
|
|
15
|
-
* agent built in webFetch(). */
|
|
16
|
-
createDispatcher?: (host: string, pinnedIP: string, cfg: ResearchConfig['fetch']) => import('undici').Dispatcher | undefined;
|
|
17
|
-
}
|
|
18
|
-
export type WebFetchOk = {
|
|
19
|
-
status: 'ok';
|
|
20
|
-
body: string;
|
|
21
|
-
rawText: string;
|
|
22
|
-
host: string;
|
|
23
|
-
bytesReturned: number;
|
|
24
|
-
truncated: boolean;
|
|
25
|
-
textTruncated: boolean;
|
|
26
|
-
credentialsStripped: boolean;
|
|
27
|
-
};
|
|
28
|
-
export type WebFetchErr = {
|
|
29
|
-
status: 'error';
|
|
30
|
-
reasonCode: string;
|
|
31
|
-
host?: string;
|
|
32
|
-
credentialsStripped: boolean;
|
|
33
|
-
};
|
|
34
|
-
export type WebFetchResult = WebFetchOk | WebFetchErr;
|
|
35
|
-
/**
|
|
36
|
-
* Build the SSRF-revalidating `connect.lookup` for the guard agent.
|
|
37
|
-
*
|
|
38
|
-
* undici invokes `connect.lookup` with `{ all: true }` and expects the callback
|
|
39
|
-
* to receive an ARRAY of `{ address, family }` entries — NOT the single-result
|
|
40
|
-
* `dns.lookup(host, (err, address, family) => ...)` form. Returning a bare
|
|
41
|
-
* address string makes undici read `addresses[0].address === undefined`, throw
|
|
42
|
-
* `ERR_INVALID_IP_ADDRESS`, and surface as `web_fetch_request_failed`. Every
|
|
43
|
-
* callback path here therefore returns the array form.
|
|
44
|
-
*
|
|
45
|
-
* Typed as `net.LookupFunction` — the exact type undici's `connect.lookup`
|
|
46
|
-
* field accepts. On error paths we pass an empty address array (undici reads
|
|
47
|
-
* `err` first and never consumes the addresses), which keeps the runtime
|
|
48
|
-
* contract while satisfying the callback's required address argument.
|
|
49
|
-
*
|
|
50
|
-
* Exported for unit testing — it locks the undici lookup contract without
|
|
51
|
-
* requiring real network (see tests/research/web-fetch.test.ts).
|
|
52
|
-
*/
|
|
53
|
-
export declare function makeConnectGuardLookup(allowPrivateNetwork: boolean, testResolvedIp: string | undefined): LookupFunction;
|
|
54
|
-
export declare function webFetch(input: WebFetchInput): Promise<WebFetchResult>;
|
|
55
|
-
//# sourceMappingURL=web-fetch.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../src/research/web-fetch.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAW1D,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAkB,MAAM,CAAC;IAC5B,GAAG,EAAkB,cAAc,CAAC,OAAO,CAAC,CAAC;IAC7C,aAAa,EAAQ,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,mBAAmB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C,SAAS,CAAC,EAAW,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD;qEACiE;IACjE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;qCAGiC;IACjC,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,CAAC,OAAO,CAAC,KAAK,OAAO,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAC;CAC9H;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAC1D,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAClE,mBAAmB,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAC;CAClF,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,WAAW,CAAC;AAStD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CACpC,mBAAmB,EAAE,OAAO,EAC5B,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,cAAc,CAkChB;AAeD,wBAAsB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAoJ5E"}
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
// packages/core/src/research/web-fetch.ts
|
|
2
|
-
//
|
|
3
|
-
// Replaces the previous IP-pinning dispatcher (which failed 100% of real
|
|
4
|
-
// requests on Node 25 / undici current) with a connect-callback re-validation
|
|
5
|
-
// SSRF guard: undici resolves the host normally; the connect callback compares
|
|
6
|
-
// the resolved IP against ssrf-guard's public-IP classification and aborts
|
|
7
|
-
// the connection if it's private/loopback/metadata. validateAndPinURL still
|
|
8
|
-
// runs first as the pre-request defense.
|
|
9
|
-
import { request, Agent } from 'undici';
|
|
10
|
-
import { USER_AGENT } from './user-agent.js';
|
|
11
|
-
import { wrapFetchedContent } from './untrusted-content.js';
|
|
12
|
-
import { classifyIP } from './ssrf-guard.js';
|
|
13
|
-
import { REDIRECT_ERR_CODE_MAP, validateAndPinURL, extractContentType, isRedirect, extractLocation, extractBodyFromHTML, stripCredentialsFromURL, readBody, drainBody, mapRequestError, } from './web-fetch-helpers.js';
|
|
14
|
-
const ALLOWED_CT = new Set([
|
|
15
|
-
'text/html', 'text/plain',
|
|
16
|
-
'application/xml', 'application/atom+xml', 'application/rss+xml',
|
|
17
|
-
'application/json',
|
|
18
|
-
]);
|
|
19
|
-
const RETURNED_TEXT_CAP = 64 * 1024;
|
|
20
|
-
/**
|
|
21
|
-
* Build the SSRF-revalidating `connect.lookup` for the guard agent.
|
|
22
|
-
*
|
|
23
|
-
* undici invokes `connect.lookup` with `{ all: true }` and expects the callback
|
|
24
|
-
* to receive an ARRAY of `{ address, family }` entries — NOT the single-result
|
|
25
|
-
* `dns.lookup(host, (err, address, family) => ...)` form. Returning a bare
|
|
26
|
-
* address string makes undici read `addresses[0].address === undefined`, throw
|
|
27
|
-
* `ERR_INVALID_IP_ADDRESS`, and surface as `web_fetch_request_failed`. Every
|
|
28
|
-
* callback path here therefore returns the array form.
|
|
29
|
-
*
|
|
30
|
-
* Typed as `net.LookupFunction` — the exact type undici's `connect.lookup`
|
|
31
|
-
* field accepts. On error paths we pass an empty address array (undici reads
|
|
32
|
-
* `err` first and never consumes the addresses), which keeps the runtime
|
|
33
|
-
* contract while satisfying the callback's required address argument.
|
|
34
|
-
*
|
|
35
|
-
* Exported for unit testing — it locks the undici lookup contract without
|
|
36
|
-
* requiring real network (see tests/research/web-fetch.test.ts).
|
|
37
|
-
*/
|
|
38
|
-
export function makeConnectGuardLookup(allowPrivateNetwork, testResolvedIp) {
|
|
39
|
-
return (host, opts, cb) => {
|
|
40
|
-
// If test seam present, return that IP; otherwise let Node resolve.
|
|
41
|
-
if (testResolvedIp) {
|
|
42
|
-
const fam = testResolvedIp.includes(':') ? 6 : 4;
|
|
43
|
-
// Re-validate test IP via ssrf-guard classification.
|
|
44
|
-
if (!allowPrivateNetwork) {
|
|
45
|
-
if (classifyIP(testResolvedIp) !== 'public') {
|
|
46
|
-
cb(new Error('web_fetch_ssrf_postresolve_block'), []);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
cb(null, [{ address: testResolvedIp, family: fam }]);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
// Production path: forward undici's options (which carry `all: true`) to
|
|
54
|
-
// Node's resolver, re-validate EVERY resolved address via the SSRF
|
|
55
|
-
// classifier, then return the array form undici expects.
|
|
56
|
-
import('node:dns').then(({ lookup }) => {
|
|
57
|
-
lookup(host, { ...opts, all: true }, (err, addresses) => {
|
|
58
|
-
if (err) {
|
|
59
|
-
cb(err, []);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const list = addresses;
|
|
63
|
-
if (!allowPrivateNetwork) {
|
|
64
|
-
for (const a of list) {
|
|
65
|
-
if (classifyIP(a.address) !== 'public') {
|
|
66
|
-
cb(new Error('web_fetch_ssrf_postresolve_block'), []);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
cb(null, list);
|
|
72
|
-
});
|
|
73
|
-
}).catch(e => cb(e, []));
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
/** Build a shared agent that re-validates the resolved IP at connect time. */
|
|
77
|
-
function makeConnectGuardAgent(allowPrivateNetwork, testResolvedIp, connectTimeoutMs) {
|
|
78
|
-
const lookup = makeConnectGuardLookup(allowPrivateNetwork, testResolvedIp);
|
|
79
|
-
return new Agent({
|
|
80
|
-
connect: { lookup },
|
|
81
|
-
connectTimeout: connectTimeoutMs,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
export async function webFetch(input) {
|
|
85
|
-
const { cfg, hostAllowlist } = input;
|
|
86
|
-
const privateNetworkHosts = input.privateNetworkHosts ?? new Set();
|
|
87
|
-
let credentialsStripped = false;
|
|
88
|
-
let initial;
|
|
89
|
-
try {
|
|
90
|
-
initial = new URL(input.url);
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
93
|
-
return { status: 'error', reasonCode: 'web_fetch_invalid_url', credentialsStripped };
|
|
94
|
-
}
|
|
95
|
-
credentialsStripped = stripCredentialsFromURL(initial);
|
|
96
|
-
const totalCtrl = new AbortController();
|
|
97
|
-
const totalTimer = setTimeout(() => totalCtrl.abort(), cfg.totalDeadlineMs);
|
|
98
|
-
try {
|
|
99
|
-
let currentURL = initial.toString();
|
|
100
|
-
let redirects = 0;
|
|
101
|
-
while (true) {
|
|
102
|
-
let v;
|
|
103
|
-
try {
|
|
104
|
-
v = await validateAndPinURL(currentURL, hostAllowlist, privateNetworkHosts, input.resolveIP, totalCtrl.signal);
|
|
105
|
-
}
|
|
106
|
-
catch (e) {
|
|
107
|
-
if (e instanceof DOMException && e.name === 'AbortError') {
|
|
108
|
-
return { status: 'error', reasonCode: 'web_fetch_timeout', credentialsStripped };
|
|
109
|
-
}
|
|
110
|
-
return { status: 'error', reasonCode: 'web_fetch_dns_resolution_failed', credentialsStripped };
|
|
111
|
-
}
|
|
112
|
-
if (!v.ok) {
|
|
113
|
-
if (redirects > 0) {
|
|
114
|
-
const mapped = REDIRECT_ERR_CODE_MAP[v.reasonCode] ?? v.reasonCode;
|
|
115
|
-
return { status: 'error', reasonCode: mapped, host: v.host, credentialsStripped };
|
|
116
|
-
}
|
|
117
|
-
return { status: 'error', reasonCode: v.reasonCode, host: v.host, credentialsStripped };
|
|
118
|
-
}
|
|
119
|
-
// Honor createDispatcher hook for tests: when present, use whatever it
|
|
120
|
-
// returns (or skip dispatcher entirely if undefined → MockAgent
|
|
121
|
-
// intercepts via global). In production, fall back to the connect-guard
|
|
122
|
-
// agent for post-resolve SSRF re-validation.
|
|
123
|
-
let agent;
|
|
124
|
-
if (input.createDispatcher !== undefined) {
|
|
125
|
-
agent = input.createDispatcher(v.host, v.pinnedIP, cfg);
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
agent = makeConnectGuardAgent(cfg.allowPrivateNetwork ?? false, input._testConnectResolvedIp, cfg.connectTimeoutMs);
|
|
129
|
-
}
|
|
130
|
-
const closeAgent = async () => {
|
|
131
|
-
if (agent && typeof agent.close === 'function') {
|
|
132
|
-
try {
|
|
133
|
-
await agent.close();
|
|
134
|
-
}
|
|
135
|
-
catch { /* ignore */ }
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
let res;
|
|
139
|
-
try {
|
|
140
|
-
res = await request(v.url.toString(), {
|
|
141
|
-
method: 'GET',
|
|
142
|
-
headersTimeout: cfg.connectTimeoutMs,
|
|
143
|
-
headers: { 'user-agent': USER_AGENT },
|
|
144
|
-
...(agent ? { dispatcher: agent } : {}),
|
|
145
|
-
signal: totalCtrl.signal,
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
catch (e) {
|
|
149
|
-
await closeAgent();
|
|
150
|
-
// Map our connect-callback abort to a stable reasonCode.
|
|
151
|
-
const msg = e?.message ?? '';
|
|
152
|
-
if (msg.includes('web_fetch_ssrf_postresolve_block')) {
|
|
153
|
-
return { status: 'error', reasonCode: 'web_fetch_ssrf_postresolve_block', host: v.host, credentialsStripped };
|
|
154
|
-
}
|
|
155
|
-
return { ...mapRequestError(e, totalCtrl.signal, v.host), credentialsStripped };
|
|
156
|
-
}
|
|
157
|
-
if (isRedirect(res.statusCode)) {
|
|
158
|
-
redirects++;
|
|
159
|
-
if (redirects > cfg.maxRedirects) {
|
|
160
|
-
await closeAgent();
|
|
161
|
-
return { status: 'error', reasonCode: 'web_fetch_too_many_redirects', host: v.host, credentialsStripped };
|
|
162
|
-
}
|
|
163
|
-
const location = extractLocation(res.headers);
|
|
164
|
-
if (!location) {
|
|
165
|
-
await closeAgent();
|
|
166
|
-
return { status: 'error', reasonCode: 'web_fetch_redirect_missing_location', host: v.host, credentialsStripped };
|
|
167
|
-
}
|
|
168
|
-
let nextURL;
|
|
169
|
-
try {
|
|
170
|
-
nextURL = new URL(location, v.url);
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
await closeAgent();
|
|
174
|
-
return { status: 'error', reasonCode: 'web_fetch_redirect_invalid_url', host: v.host, credentialsStripped };
|
|
175
|
-
}
|
|
176
|
-
credentialsStripped = stripCredentialsFromURL(nextURL) || credentialsStripped;
|
|
177
|
-
currentURL = nextURL.toString();
|
|
178
|
-
await drainBody(res.body, totalCtrl.signal);
|
|
179
|
-
await closeAgent();
|
|
180
|
-
if (totalCtrl.signal.aborted) {
|
|
181
|
-
return { status: 'error', reasonCode: 'web_fetch_timeout', host: v.host, credentialsStripped };
|
|
182
|
-
}
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
const contentType = extractContentType(res.headers);
|
|
186
|
-
if (contentType && !ALLOWED_CT.has(contentType)) {
|
|
187
|
-
await drainBody(res.body, totalCtrl.signal);
|
|
188
|
-
await closeAgent();
|
|
189
|
-
if (totalCtrl.signal.aborted) {
|
|
190
|
-
return { status: 'error', reasonCode: 'web_fetch_timeout', host: v.host, credentialsStripped };
|
|
191
|
-
}
|
|
192
|
-
return { status: 'error', reasonCode: 'web_fetch_unsupported_content_type', host: v.host, credentialsStripped };
|
|
193
|
-
}
|
|
194
|
-
let rawText;
|
|
195
|
-
let bytesReturned;
|
|
196
|
-
let truncated;
|
|
197
|
-
try {
|
|
198
|
-
const rawBody = res.body;
|
|
199
|
-
const result = await readBody(rawBody, cfg.maxBodyBytes, totalCtrl.signal);
|
|
200
|
-
rawText = result.text;
|
|
201
|
-
bytesReturned = result.bytesReturned;
|
|
202
|
-
truncated = result.truncated;
|
|
203
|
-
}
|
|
204
|
-
catch (e) {
|
|
205
|
-
await closeAgent();
|
|
206
|
-
if (e instanceof DOMException && e.name === 'AbortError') {
|
|
207
|
-
return { status: 'error', reasonCode: 'web_fetch_timeout', host: v.host, credentialsStripped };
|
|
208
|
-
}
|
|
209
|
-
if (totalCtrl.signal.aborted) {
|
|
210
|
-
return { status: 'error', reasonCode: 'web_fetch_timeout', host: v.host, credentialsStripped };
|
|
211
|
-
}
|
|
212
|
-
return { status: 'error', reasonCode: 'web_fetch_body_read_failed', host: v.host, credentialsStripped };
|
|
213
|
-
}
|
|
214
|
-
await closeAgent();
|
|
215
|
-
let extracted = rawText;
|
|
216
|
-
if (contentType === 'text/html')
|
|
217
|
-
extracted = extractBodyFromHTML(rawText);
|
|
218
|
-
let textTruncated = false;
|
|
219
|
-
if (extracted.length > RETURNED_TEXT_CAP) {
|
|
220
|
-
extracted = extracted.slice(0, RETURNED_TEXT_CAP);
|
|
221
|
-
textTruncated = true;
|
|
222
|
-
}
|
|
223
|
-
const wrapped = wrapFetchedContent({
|
|
224
|
-
url: v.url.toString(), host: v.host, content: extracted,
|
|
225
|
-
});
|
|
226
|
-
return {
|
|
227
|
-
status: 'ok', body: wrapped, rawText, host: v.host,
|
|
228
|
-
bytesReturned, truncated, textTruncated, credentialsStripped,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
finally {
|
|
233
|
-
clearTimeout(totalTimer);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
//# sourceMappingURL=web-fetch.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"web-fetch.js","sourceRoot":"","sources":["../../src/research/web-fetch.ts"],"names":[],"mappings":"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"}
|