@fedify/vocab-runtime 2.4.0-dev.2169 → 2.4.0-dev.2190

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 (32) hide show
  1. package/deno.json +1 -1
  2. package/dist/{docloader-ClQraSWr.d.cts → docloader-C63enuyr.d.cts} +53 -1
  3. package/dist/{docloader-ClQraSWr.d.ts → docloader-C63enuyr.d.ts} +53 -1
  4. package/dist/internal/jsonld-cache.d.cts +1 -1
  5. package/dist/internal/jsonld-cache.d.ts +1 -1
  6. package/dist/internal/portable-dereference.d.cts +2 -2
  7. package/dist/internal/portable-dereference.d.ts +2 -2
  8. package/dist/mod.cjs +205 -16
  9. package/dist/mod.d.cts +3 -3
  10. package/dist/mod.d.ts +3 -3
  11. package/dist/mod.js +204 -17
  12. package/dist/{portable-ilkFPcXa.d.cts → portable-Cux3IA20.d.cts} +1 -1
  13. package/dist/{portable-DRtvOxTb.d.ts → portable-DBA1FS_L.d.ts} +1 -1
  14. package/dist/tests/{body-DHAC8qhR.cjs → body-CmZdqiw3.cjs} +60 -1
  15. package/dist/tests/{body-CNwDKYQs.mjs → body-DMNbCBhz.mjs} +55 -2
  16. package/dist/tests/body.test.cjs +1 -1
  17. package/dist/tests/body.test.mjs +1 -1
  18. package/dist/tests/decimal.test.cjs +1 -1
  19. package/dist/tests/decimal.test.mjs +1 -1
  20. package/dist/tests/{docloader-DWkl3u7X.mjs → docloader-6iodlx7G.mjs} +152 -18
  21. package/dist/tests/{docloader-DLkb9qAS.cjs → docloader-B0omnjRS.cjs} +163 -17
  22. package/dist/tests/docloader.test.cjs +265 -2
  23. package/dist/tests/docloader.test.mjs +266 -3
  24. package/dist/tests/{request-Dm3ye46t.cjs → request-BU0mCgOL.cjs} +1 -1
  25. package/dist/tests/{request-Cg8MQByW.mjs → request-CGmX5n4v.mjs} +1 -1
  26. package/dist/tests/request.test.cjs +1 -1
  27. package/dist/tests/request.test.mjs +1 -1
  28. package/package.json +1 -1
  29. package/src/body.ts +57 -0
  30. package/src/docloader.test.ts +341 -3
  31. package/src/docloader.ts +205 -5
  32. package/src/mod.ts +2 -0
@@ -1,5 +1,5 @@
1
- import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-Cg8MQByW.mjs";
2
- import { n as MAX_BODY_SIZE, r as readBoundedText, t as BodyTooLargeError } from "./body-CNwDKYQs.mjs";
1
+ import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-CGmX5n4v.mjs";
2
+ import { i as readBoundedText, n as MAX_BODY_SIZE, r as readBoundedBytes, t as BodyTooLargeError } from "./body-DMNbCBhz.mjs";
3
3
  import { t as preloadedContexts } from "./contexts-CIKsin4e.mjs";
4
4
  import { t as HttpHeaderLink } from "./link-Cevmc87v.mjs";
5
5
  import { t as UrlError, v as validatePublicUrl } from "./url-D7qRF-dF.mjs";
@@ -13,6 +13,9 @@ const logger = getLogger([
13
13
  ]);
14
14
  const DEFAULT_MAX_REDIRECTION = 20;
15
15
  const MAX_HTML_SIZE = 1024 * 1024;
16
+ const MAX_ERROR_BODY_SIZE = 1024 * 1024;
17
+ const DEFAULT_TIMEOUT = 1e4;
18
+ const MAX_TIMEOUT = 2147483647;
16
19
  function createResponseMetadata(response) {
17
20
  return new Response(null, {
18
21
  headers: response.headers,
@@ -20,6 +23,55 @@ function createResponseMetadata(response) {
20
23
  statusText: response.statusText
21
24
  });
22
25
  }
26
+ const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([
27
+ 204,
28
+ 205,
29
+ 304
30
+ ]);
31
+ /**
32
+ * Reads the body of an error response while the document loader is still
33
+ * running, so that its timeout and `AbortSignal` also bound the read, and
34
+ * nothing reading {@link FetchError.response} later waits on the network.
35
+ * The body is kept byte for byte, unless it is too large or cannot be read;
36
+ * then only the status and headers are kept. A response whose status
37
+ * the `Response` constructor does not accept (e.g., 999) is kept as a clone
38
+ * whose body has been read in full; if its body is too large or cannot be
39
+ * read, no response is kept at all.
40
+ */
41
+ async function bufferErrorResponse(response, url, signal) {
42
+ if (response.status < 200 || response.status > 599) {
43
+ const clone = response.clone();
44
+ try {
45
+ await readBoundedBytes(response, MAX_ERROR_BODY_SIZE, url);
46
+ } catch (error) {
47
+ await clone.body?.cancel().catch(() => {});
48
+ if (signal?.aborted) throw error;
49
+ logger.debug("Failed to read the error response body from {url}: {error}", {
50
+ url,
51
+ error
52
+ });
53
+ return;
54
+ }
55
+ return clone;
56
+ }
57
+ if (response.body == null || NULL_BODY_STATUSES.has(response.status)) return createResponseMetadata(response);
58
+ let body;
59
+ try {
60
+ body = await readBoundedBytes(response, MAX_ERROR_BODY_SIZE, url);
61
+ } catch (error) {
62
+ if (signal?.aborted) throw error;
63
+ logger.debug("Failed to read the error response body from {url}: {error}", {
64
+ url,
65
+ error
66
+ });
67
+ return createResponseMetadata(response);
68
+ }
69
+ return new Response(body, {
70
+ headers: response.headers,
71
+ status: response.status,
72
+ statusText: response.statusText
73
+ });
74
+ }
23
75
  /**
24
76
  * Gets a {@link RemoteDocument} from the given response.
25
77
  * @param url The URL of the document to load.
@@ -44,7 +96,7 @@ async function getRemoteDocument(url, response, fetch, options) {
44
96
  url: documentUrl,
45
97
  headers: Object.fromEntries(response.headers.entries())
46
98
  });
47
- throw new FetchError(documentUrl, `HTTP ${response.status}: ${documentUrl}`, response.clone());
99
+ throw new FetchError(documentUrl, `HTTP ${response.status}: ${documentUrl}`, await bufferErrorResponse(response, documentUrl, options?.signal));
48
100
  }
49
101
  const contentType = response.headers.get("Content-Type");
50
102
  const jsonLd = contentType == null || contentType === "application/activity+json" || contentType.startsWith("application/activity+json;") || contentType === "application/ld+json" || contentType.startsWith("application/ld+json;");
@@ -131,9 +183,87 @@ async function getRemoteDocument(url, response, fetch, options) {
131
183
  };
132
184
  }
133
185
  /**
186
+ * Resolves {@link DocumentLoaderFactoryOptions.timeout} into milliseconds.
187
+ * @param timeout The timeout option. `undefined` means the default timeout,
188
+ * and `null` means no timeout.
189
+ * @returns The timeout in milliseconds, or `null` if it is turned off.
190
+ * @throws {RangeError} If the timeout is invalid.
191
+ * @internal
192
+ */
193
+ function resolveDocumentLoaderTimeout(timeout) {
194
+ if (timeout === void 0) return DEFAULT_TIMEOUT;
195
+ if (timeout === null) return null;
196
+ if (typeof timeout !== "number" || !Number.isFinite(timeout) || timeout <= 0) throw new RangeError(`The document loader timeout must be a positive finite number of milliseconds, but got ${String(timeout)}.`);
197
+ const ms = Math.ceil(timeout);
198
+ if (ms > MAX_TIMEOUT) throw new RangeError(`The document loader timeout must not be greater than ${MAX_TIMEOUT} milliseconds, but got ${timeout}.`);
199
+ return ms;
200
+ }
201
+ /**
202
+ * Bounds each call of the given document loader by the given timeout.
203
+ * The timeout is combined with the caller's `signal`, and the combined
204
+ * signal is passed to the loader. The call settles no later than the
205
+ * timeout even if the loader is stuck in a step that cannot be aborted,
206
+ * e.g., a DNS lookup.
207
+ *
208
+ * A timed-out call throws a {@link FetchError} without a response, whose
209
+ * `cause` is a `DOMException` named `"TimeoutError"`. If the caller's
210
+ * signal is aborted, its reason is thrown instead.
211
+ * @param loader The document loader to bound.
212
+ * @param timeout The timeout in milliseconds, or `null` for no timeout.
213
+ * It is assumed to have been resolved by
214
+ * {@link resolveDocumentLoaderTimeout}.
215
+ * @returns The bounded document loader.
216
+ * @internal
217
+ */
218
+ function withDocumentLoaderTimeout(loader, timeout) {
219
+ if (timeout == null) return loader;
220
+ return async (url, options) => {
221
+ const callerSignal = options?.signal;
222
+ callerSignal?.throwIfAborted();
223
+ const controller = new AbortController();
224
+ const timeoutReason = new DOMException(`The document loader timed out after ${timeout} ms.`, "TimeoutError");
225
+ let timedOut = false;
226
+ const timer = setTimeout(() => {
227
+ timedOut = true;
228
+ controller.abort(timeoutReason);
229
+ }, timeout);
230
+ const onCallerAbort = () => controller.abort(callerSignal?.reason);
231
+ callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
232
+ let onAbort;
233
+ const aborted = new Promise((_, reject) => {
234
+ onAbort = () => reject(controller.signal.reason);
235
+ controller.signal.addEventListener("abort", onAbort, { once: true });
236
+ });
237
+ const loading = loader(url, {
238
+ ...options,
239
+ signal: controller.signal
240
+ });
241
+ loading.catch(() => {});
242
+ try {
243
+ return await Promise.race([loading, aborted]);
244
+ } catch (error) {
245
+ if (callerSignal?.aborted) throw callerSignal.reason;
246
+ if (!timedOut) throw error;
247
+ logger[options?.suppressError ? "warn" : "error"]("Timed out after {timeout} ms while fetching document: {url}", {
248
+ timeout,
249
+ url
250
+ });
251
+ const fetchError = new FetchError(url, `Timed out after ${timeout} ms`);
252
+ fetchError.cause = timeoutReason;
253
+ throw fetchError;
254
+ } finally {
255
+ clearTimeout(timer);
256
+ callerSignal?.removeEventListener("abort", onCallerAbort);
257
+ if (onAbort != null) controller.signal.removeEventListener("abort", onAbort);
258
+ }
259
+ };
260
+ }
261
+ /**
134
262
  * Creates a JSON-LD document loader that utilizes the browser's `fetch` API.
135
263
  * At most 20 HTTP redirects and alternate document links are followed in total
136
264
  * per call. Revisiting a URL within that chain throws a {@link FetchError}.
265
+ * Each call times out after 10 seconds by default; see
266
+ * {@link DocumentLoaderFactoryOptions.timeout}.
137
267
  *
138
268
  * The created loader preloads the below frequently used contexts by default
139
269
  * (unless `options.skipPreloadedContexts` is set to `true`):
@@ -153,7 +283,8 @@ async function getRemoteDocument(url, response, fetch, options) {
153
283
  * @returns The document loader.
154
284
  * @since 1.3.0
155
285
  */
156
- function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedContexts, userAgent } = {}) {
286
+ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedContexts, timeout, userAgent } = {}) {
287
+ const resolvedTimeout = resolveDocumentLoaderTimeout(timeout);
157
288
  const tracer = trace.getTracerProvider().getTracer(name, version);
158
289
  const maximumRedirection = maxRedirection ?? DEFAULT_MAX_REDIRECTION;
159
290
  async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
@@ -167,18 +298,21 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
167
298
  documentUrl: currentUrl
168
299
  };
169
300
  }
170
- if (!allowPrivateAddress) try {
171
- await validatePublicUrl(currentUrl);
172
- } catch (error) {
173
- if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
174
- url: currentUrl,
175
- error
176
- });
177
- else logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
178
- url: currentUrl,
179
- error
180
- });
181
- throw error;
301
+ if (!allowPrivateAddress) {
302
+ try {
303
+ await validatePublicUrl(currentUrl);
304
+ } catch (error) {
305
+ if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
306
+ url: currentUrl,
307
+ error
308
+ });
309
+ else logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
310
+ url: currentUrl,
311
+ error
312
+ });
313
+ throw error;
314
+ }
315
+ options?.signal?.throwIfAborted();
182
316
  }
183
317
  visited.add(currentUrl);
184
318
  return await tracer.startActiveSpan("activitypub.fetch_document", {
@@ -233,7 +367,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
233
367
  }
234
368
  });
235
369
  }
236
- return (url, options) => load(url, options);
370
+ return withDocumentLoaderTimeout((url, options) => load(url, options), resolvedTimeout);
237
371
  }
238
372
  //#endregion
239
- export { getRemoteDocument as n, getDocumentLoader as t };
373
+ export { withDocumentLoaderTimeout as i, getRemoteDocument as n, resolveDocumentLoaderTimeout as r, getDocumentLoader as t };
@@ -1,5 +1,5 @@
1
- const require_request = require("./request-Dm3ye46t.cjs");
2
- const require_body = require("./body-DHAC8qhR.cjs");
1
+ const require_request = require("./request-BU0mCgOL.cjs");
2
+ const require_body = require("./body-CmZdqiw3.cjs");
3
3
  const require_contexts = require("./contexts-DizzBjz4.cjs");
4
4
  const require_link = require("./link-DlKm8bEr.cjs");
5
5
  const require_url = require("./url-gLKqAO1H.cjs");
@@ -13,6 +13,9 @@ const logger = (0, _logtape_logtape.getLogger)([
13
13
  ]);
14
14
  const DEFAULT_MAX_REDIRECTION = 20;
15
15
  const MAX_HTML_SIZE = 1024 * 1024;
16
+ const MAX_ERROR_BODY_SIZE = 1024 * 1024;
17
+ const DEFAULT_TIMEOUT = 1e4;
18
+ const MAX_TIMEOUT = 2147483647;
16
19
  function createResponseMetadata(response) {
17
20
  return new Response(null, {
18
21
  headers: response.headers,
@@ -20,6 +23,55 @@ function createResponseMetadata(response) {
20
23
  statusText: response.statusText
21
24
  });
22
25
  }
26
+ const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([
27
+ 204,
28
+ 205,
29
+ 304
30
+ ]);
31
+ /**
32
+ * Reads the body of an error response while the document loader is still
33
+ * running, so that its timeout and `AbortSignal` also bound the read, and
34
+ * nothing reading {@link FetchError.response} later waits on the network.
35
+ * The body is kept byte for byte, unless it is too large or cannot be read;
36
+ * then only the status and headers are kept. A response whose status
37
+ * the `Response` constructor does not accept (e.g., 999) is kept as a clone
38
+ * whose body has been read in full; if its body is too large or cannot be
39
+ * read, no response is kept at all.
40
+ */
41
+ async function bufferErrorResponse(response, url, signal) {
42
+ if (response.status < 200 || response.status > 599) {
43
+ const clone = response.clone();
44
+ try {
45
+ await require_body.readBoundedBytes(response, MAX_ERROR_BODY_SIZE, url);
46
+ } catch (error) {
47
+ await clone.body?.cancel().catch(() => {});
48
+ if (signal?.aborted) throw error;
49
+ logger.debug("Failed to read the error response body from {url}: {error}", {
50
+ url,
51
+ error
52
+ });
53
+ return;
54
+ }
55
+ return clone;
56
+ }
57
+ if (response.body == null || NULL_BODY_STATUSES.has(response.status)) return createResponseMetadata(response);
58
+ let body;
59
+ try {
60
+ body = await require_body.readBoundedBytes(response, MAX_ERROR_BODY_SIZE, url);
61
+ } catch (error) {
62
+ if (signal?.aborted) throw error;
63
+ logger.debug("Failed to read the error response body from {url}: {error}", {
64
+ url,
65
+ error
66
+ });
67
+ return createResponseMetadata(response);
68
+ }
69
+ return new Response(body, {
70
+ headers: response.headers,
71
+ status: response.status,
72
+ statusText: response.statusText
73
+ });
74
+ }
23
75
  /**
24
76
  * Gets a {@link RemoteDocument} from the given response.
25
77
  * @param url The URL of the document to load.
@@ -44,7 +96,7 @@ async function getRemoteDocument(url, response, fetch, options) {
44
96
  url: documentUrl,
45
97
  headers: Object.fromEntries(response.headers.entries())
46
98
  });
47
- throw new require_request.FetchError(documentUrl, `HTTP ${response.status}: ${documentUrl}`, response.clone());
99
+ throw new require_request.FetchError(documentUrl, `HTTP ${response.status}: ${documentUrl}`, await bufferErrorResponse(response, documentUrl, options?.signal));
48
100
  }
49
101
  const contentType = response.headers.get("Content-Type");
50
102
  const jsonLd = contentType == null || contentType === "application/activity+json" || contentType.startsWith("application/activity+json;") || contentType === "application/ld+json" || contentType.startsWith("application/ld+json;");
@@ -131,9 +183,87 @@ async function getRemoteDocument(url, response, fetch, options) {
131
183
  };
132
184
  }
133
185
  /**
186
+ * Resolves {@link DocumentLoaderFactoryOptions.timeout} into milliseconds.
187
+ * @param timeout The timeout option. `undefined` means the default timeout,
188
+ * and `null` means no timeout.
189
+ * @returns The timeout in milliseconds, or `null` if it is turned off.
190
+ * @throws {RangeError} If the timeout is invalid.
191
+ * @internal
192
+ */
193
+ function resolveDocumentLoaderTimeout(timeout) {
194
+ if (timeout === void 0) return DEFAULT_TIMEOUT;
195
+ if (timeout === null) return null;
196
+ if (typeof timeout !== "number" || !Number.isFinite(timeout) || timeout <= 0) throw new RangeError(`The document loader timeout must be a positive finite number of milliseconds, but got ${String(timeout)}.`);
197
+ const ms = Math.ceil(timeout);
198
+ if (ms > MAX_TIMEOUT) throw new RangeError(`The document loader timeout must not be greater than ${MAX_TIMEOUT} milliseconds, but got ${timeout}.`);
199
+ return ms;
200
+ }
201
+ /**
202
+ * Bounds each call of the given document loader by the given timeout.
203
+ * The timeout is combined with the caller's `signal`, and the combined
204
+ * signal is passed to the loader. The call settles no later than the
205
+ * timeout even if the loader is stuck in a step that cannot be aborted,
206
+ * e.g., a DNS lookup.
207
+ *
208
+ * A timed-out call throws a {@link FetchError} without a response, whose
209
+ * `cause` is a `DOMException` named `"TimeoutError"`. If the caller's
210
+ * signal is aborted, its reason is thrown instead.
211
+ * @param loader The document loader to bound.
212
+ * @param timeout The timeout in milliseconds, or `null` for no timeout.
213
+ * It is assumed to have been resolved by
214
+ * {@link resolveDocumentLoaderTimeout}.
215
+ * @returns The bounded document loader.
216
+ * @internal
217
+ */
218
+ function withDocumentLoaderTimeout(loader, timeout) {
219
+ if (timeout == null) return loader;
220
+ return async (url, options) => {
221
+ const callerSignal = options?.signal;
222
+ callerSignal?.throwIfAborted();
223
+ const controller = new AbortController();
224
+ const timeoutReason = new DOMException(`The document loader timed out after ${timeout} ms.`, "TimeoutError");
225
+ let timedOut = false;
226
+ const timer = setTimeout(() => {
227
+ timedOut = true;
228
+ controller.abort(timeoutReason);
229
+ }, timeout);
230
+ const onCallerAbort = () => controller.abort(callerSignal?.reason);
231
+ callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
232
+ let onAbort;
233
+ const aborted = new Promise((_, reject) => {
234
+ onAbort = () => reject(controller.signal.reason);
235
+ controller.signal.addEventListener("abort", onAbort, { once: true });
236
+ });
237
+ const loading = loader(url, {
238
+ ...options,
239
+ signal: controller.signal
240
+ });
241
+ loading.catch(() => {});
242
+ try {
243
+ return await Promise.race([loading, aborted]);
244
+ } catch (error) {
245
+ if (callerSignal?.aborted) throw callerSignal.reason;
246
+ if (!timedOut) throw error;
247
+ logger[options?.suppressError ? "warn" : "error"]("Timed out after {timeout} ms while fetching document: {url}", {
248
+ timeout,
249
+ url
250
+ });
251
+ const fetchError = new require_request.FetchError(url, `Timed out after ${timeout} ms`);
252
+ fetchError.cause = timeoutReason;
253
+ throw fetchError;
254
+ } finally {
255
+ clearTimeout(timer);
256
+ callerSignal?.removeEventListener("abort", onCallerAbort);
257
+ if (onAbort != null) controller.signal.removeEventListener("abort", onAbort);
258
+ }
259
+ };
260
+ }
261
+ /**
134
262
  * Creates a JSON-LD document loader that utilizes the browser's `fetch` API.
135
263
  * At most 20 HTTP redirects and alternate document links are followed in total
136
264
  * per call. Revisiting a URL within that chain throws a {@link FetchError}.
265
+ * Each call times out after 10 seconds by default; see
266
+ * {@link DocumentLoaderFactoryOptions.timeout}.
137
267
  *
138
268
  * The created loader preloads the below frequently used contexts by default
139
269
  * (unless `options.skipPreloadedContexts` is set to `true`):
@@ -153,7 +283,8 @@ async function getRemoteDocument(url, response, fetch, options) {
153
283
  * @returns The document loader.
154
284
  * @since 1.3.0
155
285
  */
156
- function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedContexts, userAgent } = {}) {
286
+ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedContexts, timeout, userAgent } = {}) {
287
+ const resolvedTimeout = resolveDocumentLoaderTimeout(timeout);
157
288
  const tracer = _opentelemetry_api.trace.getTracerProvider().getTracer(require_request.name, require_request.version);
158
289
  const maximumRedirection = maxRedirection ?? DEFAULT_MAX_REDIRECTION;
159
290
  async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
@@ -167,18 +298,21 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
167
298
  documentUrl: currentUrl
168
299
  };
169
300
  }
170
- if (!allowPrivateAddress) try {
171
- await require_url.validatePublicUrl(currentUrl);
172
- } catch (error) {
173
- if (error instanceof require_url.UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
174
- url: currentUrl,
175
- error
176
- });
177
- else logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
178
- url: currentUrl,
179
- error
180
- });
181
- throw error;
301
+ if (!allowPrivateAddress) {
302
+ try {
303
+ await require_url.validatePublicUrl(currentUrl);
304
+ } catch (error) {
305
+ if (error instanceof require_url.UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
306
+ url: currentUrl,
307
+ error
308
+ });
309
+ else logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
310
+ url: currentUrl,
311
+ error
312
+ });
313
+ throw error;
314
+ }
315
+ options?.signal?.throwIfAborted();
182
316
  }
183
317
  visited.add(currentUrl);
184
318
  return await tracer.startActiveSpan("activitypub.fetch_document", {
@@ -233,7 +367,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
233
367
  }
234
368
  });
235
369
  }
236
- return (url, options) => load(url, options);
370
+ return withDocumentLoaderTimeout((url, options) => load(url, options), resolvedTimeout);
237
371
  }
238
372
  //#endregion
239
373
  Object.defineProperty(exports, "getDocumentLoader", {
@@ -248,3 +382,15 @@ Object.defineProperty(exports, "getRemoteDocument", {
248
382
  return getRemoteDocument;
249
383
  }
250
384
  });
385
+ Object.defineProperty(exports, "resolveDocumentLoaderTimeout", {
386
+ enumerable: true,
387
+ get: function() {
388
+ return resolveDocumentLoaderTimeout;
389
+ }
390
+ });
391
+ Object.defineProperty(exports, "withDocumentLoaderTimeout", {
392
+ enumerable: true,
393
+ get: function() {
394
+ return withDocumentLoaderTimeout;
395
+ }
396
+ });