@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.
Files changed (235) hide show
  1. package/dist/config/schema.d.ts +2 -20
  2. package/dist/config/schema.d.ts.map +1 -1
  3. package/dist/config/schema.js +9 -80
  4. package/dist/config/schema.js.map +1 -1
  5. package/dist/events/task-envelope.d.ts +8 -1
  6. package/dist/events/task-envelope.d.ts.map +1 -1
  7. package/dist/events/task-envelope.js +2 -1
  8. package/dist/events/task-envelope.js.map +1 -1
  9. package/dist/events/wire-schema.d.ts +4 -0
  10. package/dist/events/wire-schema.d.ts.map +1 -1
  11. package/dist/events/wire-schema.js +3 -3
  12. package/dist/events/wire-schema.js.map +1 -1
  13. package/dist/journal/default-schema.d.ts +2 -0
  14. package/dist/journal/default-schema.d.ts.map +1 -0
  15. package/dist/journal/default-schema.js +27 -0
  16. package/dist/journal/default-schema.js.map +1 -0
  17. package/dist/journal/types.d.ts +22 -0
  18. package/dist/journal/types.d.ts.map +1 -0
  19. package/dist/journal/types.js +5 -0
  20. package/dist/journal/types.js.map +1 -0
  21. package/dist/lifecycle/annotate-parser.js +1 -1
  22. package/dist/lifecycle/annotate-parser.js.map +1 -1
  23. package/dist/lifecycle/derive-completion.js +1 -1
  24. package/dist/lifecycle/derive-completion.js.map +1 -1
  25. package/dist/lifecycle/handlers/annotate-stage.d.ts.map +1 -1
  26. package/dist/lifecycle/handlers/annotate-stage.js +9 -3
  27. package/dist/lifecycle/handlers/annotate-stage.js.map +1 -1
  28. package/dist/lifecycle/handlers/baseline-handlers.d.ts.map +1 -1
  29. package/dist/lifecycle/handlers/baseline-handlers.js +10 -0
  30. package/dist/lifecycle/handlers/baseline-handlers.js.map +1 -1
  31. package/dist/lifecycle/handlers/compose-commit-message.d.ts +15 -0
  32. package/dist/lifecycle/handlers/compose-commit-message.d.ts.map +1 -0
  33. package/dist/lifecycle/handlers/compose-commit-message.js +227 -0
  34. package/dist/lifecycle/handlers/compose-commit-message.js.map +1 -0
  35. package/dist/lifecycle/handlers/enrich-runtime-result.d.ts.map +1 -1
  36. package/dist/lifecycle/handlers/enrich-runtime-result.js +31 -0
  37. package/dist/lifecycle/handlers/enrich-runtime-result.js.map +1 -1
  38. package/dist/lifecycle/handlers/git-commit-handler.d.ts.map +1 -1
  39. package/dist/lifecycle/handlers/git-commit-handler.js +2 -15
  40. package/dist/lifecycle/handlers/git-commit-handler.js.map +1 -1
  41. package/dist/lifecycle/handlers/implement-stage.d.ts.map +1 -1
  42. package/dist/lifecycle/handlers/implement-stage.js +4 -1
  43. package/dist/lifecycle/handlers/implement-stage.js.map +1 -1
  44. package/dist/lifecycle/handlers/journal-review-prompt.d.ts +7 -0
  45. package/dist/lifecycle/handlers/journal-review-prompt.d.ts.map +1 -0
  46. package/dist/lifecycle/handlers/journal-review-prompt.js +54 -0
  47. package/dist/lifecycle/handlers/journal-review-prompt.js.map +1 -0
  48. package/dist/lifecycle/handlers/quality-review-prompt.d.ts +1 -0
  49. package/dist/lifecycle/handlers/quality-review-prompt.d.ts.map +1 -1
  50. package/dist/lifecycle/handlers/quality-review-prompt.js +8 -0
  51. package/dist/lifecycle/handlers/quality-review-prompt.js.map +1 -1
  52. package/dist/lifecycle/handlers/review-stage.d.ts.map +1 -1
  53. package/dist/lifecycle/handlers/review-stage.js +57 -13
  54. package/dist/lifecycle/handlers/review-stage.js.map +1 -1
  55. package/dist/lifecycle/handlers/rework-stage.d.ts.map +1 -1
  56. package/dist/lifecycle/handlers/rework-stage.js +3 -0
  57. package/dist/lifecycle/handlers/rework-stage.js.map +1 -1
  58. package/dist/lifecycle/handlers/spec-review-prompt.d.ts +1 -0
  59. package/dist/lifecycle/handlers/spec-review-prompt.d.ts.map +1 -1
  60. package/dist/lifecycle/handlers/spec-review-prompt.js +8 -0
  61. package/dist/lifecycle/handlers/spec-review-prompt.js.map +1 -1
  62. package/dist/lifecycle/perform-implementation.d.ts.map +1 -1
  63. package/dist/lifecycle/perform-implementation.js +7 -4
  64. package/dist/lifecycle/perform-implementation.js.map +1 -1
  65. package/dist/lifecycle/read-route-criteria.d.ts +3 -2
  66. package/dist/lifecycle/read-route-criteria.d.ts.map +1 -1
  67. package/dist/lifecycle/read-route-criteria.js +2 -0
  68. package/dist/lifecycle/read-route-criteria.js.map +1 -1
  69. package/dist/lifecycle/research-pre-loop.d.ts +5 -4
  70. package/dist/lifecycle/research-pre-loop.d.ts.map +1 -1
  71. package/dist/lifecycle/research-pre-loop.js +7 -10
  72. package/dist/lifecycle/research-pre-loop.js.map +1 -1
  73. package/dist/lifecycle/stage-io.d.ts +7 -3
  74. package/dist/lifecycle/stage-io.d.ts.map +1 -1
  75. package/dist/lifecycle/stage-io.js +2 -2
  76. package/dist/lifecycle/stage-io.js.map +1 -1
  77. package/dist/lifecycle/stage-progression.d.ts.map +1 -1
  78. package/dist/lifecycle/stage-progression.js +2 -0
  79. package/dist/lifecycle/stage-progression.js.map +1 -1
  80. package/dist/lifecycle/task-runner.d.ts +14 -0
  81. package/dist/lifecycle/task-runner.d.ts.map +1 -1
  82. package/dist/lifecycle/task-runner.js +71 -2
  83. package/dist/lifecycle/task-runner.js.map +1 -1
  84. package/dist/lifecycle/worker-output-contract.d.ts +3 -1
  85. package/dist/lifecycle/worker-output-contract.d.ts.map +1 -1
  86. package/dist/lifecycle/worker-output-contract.js +4 -1
  87. package/dist/lifecycle/worker-output-contract.js.map +1 -1
  88. package/dist/providers/claude-session.d.ts +1 -0
  89. package/dist/providers/claude-session.d.ts.map +1 -1
  90. package/dist/providers/claude-session.js +9 -0
  91. package/dist/providers/claude-session.js.map +1 -1
  92. package/dist/providers/claude-skill-plugin.d.ts +12 -0
  93. package/dist/providers/claude-skill-plugin.d.ts.map +1 -0
  94. package/dist/providers/claude-skill-plugin.js +27 -0
  95. package/dist/providers/claude-skill-plugin.js.map +1 -0
  96. package/dist/providers/codex-cli-launch.d.ts +2 -0
  97. package/dist/providers/codex-cli-launch.d.ts.map +1 -1
  98. package/dist/providers/codex-cli-launch.js +3 -1
  99. package/dist/providers/codex-cli-launch.js.map +1 -1
  100. package/dist/providers/codex-cli-session.d.ts +2 -0
  101. package/dist/providers/codex-cli-session.d.ts.map +1 -1
  102. package/dist/providers/codex-cli-session.js +13 -0
  103. package/dist/providers/codex-cli-session.js.map +1 -1
  104. package/dist/providers/codex-skill-home.d.ts +15 -0
  105. package/dist/providers/codex-skill-home.d.ts.map +1 -0
  106. package/dist/providers/codex-skill-home.js +23 -0
  107. package/dist/providers/codex-skill-home.js.map +1 -0
  108. package/dist/providers/skill-resolver.d.ts +17 -0
  109. package/dist/providers/skill-resolver.d.ts.map +1 -0
  110. package/dist/providers/skill-resolver.js +123 -0
  111. package/dist/providers/skill-resolver.js.map +1 -0
  112. package/dist/reporting/headline-templates/journal-recall.d.ts +3 -0
  113. package/dist/reporting/headline-templates/journal-recall.d.ts.map +1 -0
  114. package/dist/reporting/headline-templates/journal-recall.js +9 -0
  115. package/dist/reporting/headline-templates/journal-recall.js.map +1 -0
  116. package/dist/reporting/headline-templates/journal.d.ts +3 -0
  117. package/dist/reporting/headline-templates/journal.d.ts.map +1 -0
  118. package/dist/reporting/headline-templates/journal.js +17 -0
  119. package/dist/reporting/headline-templates/journal.js.map +1 -0
  120. package/dist/reporting/report-parser-slots/journal-report.d.ts +8 -0
  121. package/dist/reporting/report-parser-slots/journal-report.d.ts.map +1 -0
  122. package/dist/reporting/report-parser-slots/journal-report.js +12 -0
  123. package/dist/reporting/report-parser-slots/journal-report.js.map +1 -0
  124. package/dist/research/adapters/index.d.ts +0 -1
  125. package/dist/research/adapters/index.d.ts.map +1 -1
  126. package/dist/research/adapters/index.js +0 -3
  127. package/dist/research/adapters/index.js.map +1 -1
  128. package/dist/research/adapters/types.d.ts +1 -1
  129. package/dist/research/adapters/types.d.ts.map +1 -1
  130. package/dist/research/evidence-pack.d.ts +19 -1
  131. package/dist/research/evidence-pack.d.ts.map +1 -1
  132. package/dist/research/evidence-pack.js +36 -1
  133. package/dist/research/evidence-pack.js.map +1 -1
  134. package/dist/research/orchestrator.d.ts +0 -4
  135. package/dist/research/orchestrator.d.ts.map +1 -1
  136. package/dist/research/orchestrator.js +4 -53
  137. package/dist/research/orchestrator.js.map +1 -1
  138. package/dist/research/query-plan.d.ts +0 -2
  139. package/dist/research/query-plan.d.ts.map +1 -1
  140. package/dist/research/query-plan.js +1 -8
  141. package/dist/research/query-plan.js.map +1 -1
  142. package/dist/research/user-agent.js +1 -1
  143. package/dist/research/user-agent.js.map +1 -1
  144. package/dist/research/web-search.d.ts +2 -1
  145. package/dist/research/web-search.d.ts.map +1 -1
  146. package/dist/research/web-search.js +31 -7
  147. package/dist/research/web-search.js.map +1 -1
  148. package/dist/tool-surface/register-all-tools.d.ts.map +1 -1
  149. package/dist/tool-surface/register-all-tools.js +4 -0
  150. package/dist/tool-surface/register-all-tools.js.map +1 -1
  151. package/dist/tools/delegate/brief-slot.d.ts +4 -0
  152. package/dist/tools/delegate/brief-slot.d.ts.map +1 -1
  153. package/dist/tools/delegate/brief-slot.js +2 -0
  154. package/dist/tools/delegate/brief-slot.js.map +1 -1
  155. package/dist/tools/delegate/schema.d.ts +1 -0
  156. package/dist/tools/delegate/schema.d.ts.map +1 -1
  157. package/dist/tools/delegate/schema.js +4 -0
  158. package/dist/tools/delegate/schema.js.map +1 -1
  159. package/dist/tools/delegate/tool-config.d.ts.map +1 -1
  160. package/dist/tools/delegate/tool-config.js +2 -0
  161. package/dist/tools/delegate/tool-config.js.map +1 -1
  162. package/dist/tools/execute-plan/tool-config.d.ts.map +1 -1
  163. package/dist/tools/execute-plan/tool-config.js +3 -0
  164. package/dist/tools/execute-plan/tool-config.js.map +1 -1
  165. package/dist/tools/journal/recall/brief-slot.d.ts +7 -0
  166. package/dist/tools/journal/recall/brief-slot.d.ts.map +1 -0
  167. package/dist/tools/journal/recall/brief-slot.js +5 -0
  168. package/dist/tools/journal/recall/brief-slot.js.map +1 -0
  169. package/dist/tools/journal/recall/implementer-criteria.d.ts +9 -0
  170. package/dist/tools/journal/recall/implementer-criteria.d.ts.map +1 -0
  171. package/dist/tools/journal/recall/implementer-criteria.js +23 -0
  172. package/dist/tools/journal/recall/implementer-criteria.js.map +1 -0
  173. package/dist/tools/journal/recall/schema.d.ts +54 -0
  174. package/dist/tools/journal/recall/schema.d.ts.map +1 -0
  175. package/dist/tools/journal/recall/schema.js +10 -0
  176. package/dist/tools/journal/recall/schema.js.map +1 -0
  177. package/dist/tools/journal/recall/subtypes.d.ts +4 -0
  178. package/dist/tools/journal/recall/subtypes.d.ts.map +1 -0
  179. package/dist/tools/journal/recall/subtypes.js +25 -0
  180. package/dist/tools/journal/recall/subtypes.js.map +1 -0
  181. package/dist/tools/journal/recall/tool-config.d.ts +8 -0
  182. package/dist/tools/journal/recall/tool-config.d.ts.map +1 -0
  183. package/dist/tools/journal/recall/tool-config.js +46 -0
  184. package/dist/tools/journal/recall/tool-config.js.map +1 -0
  185. package/dist/tools/journal/record/brief-slot.d.ts +14 -0
  186. package/dist/tools/journal/record/brief-slot.d.ts.map +1 -0
  187. package/dist/tools/journal/record/brief-slot.js +18 -0
  188. package/dist/tools/journal/record/brief-slot.js.map +1 -0
  189. package/dist/tools/journal/record/implementer-criteria.d.ts +6 -0
  190. package/dist/tools/journal/record/implementer-criteria.d.ts.map +1 -0
  191. package/dist/tools/journal/record/implementer-criteria.js +17 -0
  192. package/dist/tools/journal/record/implementer-criteria.js.map +1 -0
  193. package/dist/tools/journal/record/schema.d.ts +55 -0
  194. package/dist/tools/journal/record/schema.d.ts.map +1 -0
  195. package/dist/tools/journal/record/schema.js +13 -0
  196. package/dist/tools/journal/record/schema.js.map +1 -0
  197. package/dist/tools/journal/record/tool-config.d.ts +7 -0
  198. package/dist/tools/journal/record/tool-config.d.ts.map +1 -0
  199. package/dist/tools/journal/record/tool-config.js +40 -0
  200. package/dist/tools/journal/record/tool-config.js.map +1 -0
  201. package/dist/tools/research/brief-slot.d.ts +0 -2
  202. package/dist/tools/research/brief-slot.d.ts.map +1 -1
  203. package/dist/tools/research/brief-slot.js.map +1 -1
  204. package/dist/tools/research/implementer-criteria.d.ts +0 -1
  205. package/dist/tools/research/implementer-criteria.d.ts.map +1 -1
  206. package/dist/tools/research/implementer-criteria.js +3 -15
  207. package/dist/tools/research/implementer-criteria.js.map +1 -1
  208. package/dist/tools/research/tool-config.d.ts.map +1 -1
  209. package/dist/tools/research/tool-config.js +0 -1
  210. package/dist/tools/research/tool-config.js.map +1 -1
  211. package/dist/types/run-result.d.ts +9 -0
  212. package/dist/types/run-result.d.ts.map +1 -1
  213. package/dist/types/task-spec.d.ts +5 -1
  214. package/dist/types/task-spec.d.ts.map +1 -1
  215. package/package.json +17 -1
  216. package/dist/research/adapters/generic-rss.d.ts +0 -8
  217. package/dist/research/adapters/generic-rss.d.ts.map +0 -1
  218. package/dist/research/adapters/generic-rss.js +0 -26
  219. package/dist/research/adapters/generic-rss.js.map +0 -1
  220. package/dist/research/ssrf-guard.d.ts +0 -12
  221. package/dist/research/ssrf-guard.d.ts.map +0 -1
  222. package/dist/research/ssrf-guard.js +0 -209
  223. package/dist/research/ssrf-guard.js.map +0 -1
  224. package/dist/research/untrusted-content.d.ts +0 -13
  225. package/dist/research/untrusted-content.d.ts.map +0 -1
  226. package/dist/research/untrusted-content.js +0 -9
  227. package/dist/research/untrusted-content.js.map +0 -1
  228. package/dist/research/web-fetch-helpers.d.ts +0 -44
  229. package/dist/research/web-fetch-helpers.d.ts.map +0 -1
  230. package/dist/research/web-fetch-helpers.js +0 -209
  231. package/dist/research/web-fetch-helpers.js.map +0 -1
  232. package/dist/research/web-fetch.d.ts +0 -55
  233. package/dist/research/web-fetch.d.ts.map +0 -1
  234. package/dist/research/web-fetch.js +0 -236
  235. 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":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG7D,yEAAyE;AACzE,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,CAAC;AAE5C,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC3D,uBAAuB,EAAE,kCAAkC;IAC3D,qBAAqB,EAAE,gCAAgC;IACvD,wBAAwB,EAAE,qCAAqC;IAC/D,4BAA4B,EAAE,uCAAuC;IACrE,4BAA4B,EAAE,uCAAuC;IACrE,6BAA6B,EAAE,wCAAwC;CACxE,CAAC;AAeF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,OAAmB,EAAE,MAAmB;IAC5E,IAAI,MAAM,CAAC,OAAO;QAAE,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACpE,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;QACxE,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CACV,CAAC,MAAM,EAAE,EAAE;YACT,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,EACD,CAAC,GAAG,EAAE,EAAE;YACN,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAW,EACX,aAAkC,EAClC,mBAAwC,EACxC,SAAqC,EACrC,MAAmB;IAEnB,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,0BAA0B,EAAE,CAAC;IAC/D,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,8BAA8B,EAAE,CAAC;IACnE,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,yBAAyB,EAAE,IAAI,EAAE,CAAC;IACpE,CAAC;IACD,MAAM,YAAY,GAAG,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,YAAY,CAC3B,aAAa,CAAC,IAAI,EAAE;YAClB,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;YAClE,mBAAmB,EAAE,YAAY;SAClC,CAAC,EACF,MAAM,CACP,CAAC;IACJ,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,YAAY,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACzD,MAAM,CAAC,CAAC;QACV,CAAC;QACD,IAAI,CAAC,YAAY,WAAW,EAAE,CAAC;YAC7B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;QACjD,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,iCAAiC,EAAE,IAAI,EAAE,CAAC;IAC5E,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAsD;IACvF,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACpC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjD,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5D,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,OAAO,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,CAAC;AAChG,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAsD;IACpF,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,IAAI,GAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,OAAO,EAAE,WAAW,EAAE,CAAC;YACzB,OAAO,OAAO,CAAC,WAAW,CAAC;QAC7B,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,OAAO,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,GAAQ;IAC9C,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IACjD,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAA+C,EAC/C,QAAgB,EAChB,MAAmB;IAEnB,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAEnE,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QAC/B,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;QACnC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,SAAS,GAAG,IAAI,CAAC;YACjB,MAAM;QACR,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACrE,IAAI,KAAK,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;YAC1C,KAAK,IAAI,SAAS,CAAC;YACnB,SAAS,GAAG,IAAI,CAAC;YACjB,MAAM;QACR,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC;IACxB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,IAAmC,EACnC,MAAmB;IAEnB,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;YAC/B,IAAI,MAAM,CAAC,OAAO;gBAAE,MAAM;YAC1B,IAAI,GAAG,GAAG,CAAC,CAAC;YACZ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACjC,CAAC;iBAAM,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;gBACvC,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;YACrB,CAAC;iBAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClC,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;YACrB,CAAC;YACD,OAAO,IAAI,GAAG,CAAC;YACf,IAAI,OAAO,GAAG,kBAAkB;gBAAE,MAAM;QAC1C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,IAAI,CAAC,CAAC,GAAG,YAAY,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,IAAI,GAAI,GAAyB,CAAC,IAAI,CAAC;IAC7C,OAAO,IAAI,KAAK,yBAAyB;WAClC,IAAI,KAAK,yBAAyB;WAClC,IAAI,KAAK,sBAAsB,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,MAAmB,EAAE,IAAY;IAC7E,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC;IAChG,CAAC;IACD,IAAI,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC7D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC;IAChG,CAAC;IACD,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC;IAChG,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,0BAA0B,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC;AACvG,CAAC"}
@@ -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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"}