@fedify/vocab-runtime 2.4.0-dev.2122 → 2.4.0-dev.2127

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 (46) hide show
  1. package/deno.json +1 -1
  2. package/dist/{docloader-Dr8wEkif.d.cts → docloader-oRpq1nQ8.d.cts} +8 -1
  3. package/dist/{docloader-Dr8wEkif.d.ts → docloader-oRpq1nQ8.d.ts} +8 -1
  4. package/dist/internal/jsonld-cache.cjs +50 -0
  5. package/dist/internal/jsonld-cache.d.cts +28 -2
  6. package/dist/internal/jsonld-cache.d.ts +28 -2
  7. package/dist/internal/jsonld-cache.js +48 -1
  8. package/dist/internal/portable-dereference.cjs +28 -12
  9. package/dist/internal/portable-dereference.d.cts +12 -4
  10. package/dist/internal/portable-dereference.d.ts +12 -4
  11. package/dist/internal/portable-dereference.js +28 -12
  12. package/dist/mod.cjs +15 -9
  13. package/dist/mod.d.cts +8 -2
  14. package/dist/mod.d.ts +8 -2
  15. package/dist/mod.js +15 -9
  16. package/dist/{portable-comBI05Y.d.cts → portable-Drfl02vZ.d.cts} +1 -1
  17. package/dist/{portable-DH3947GK.d.ts → portable-rwhiyMvY.d.ts} +1 -1
  18. package/dist/tests/{body-tLaZa-9t.cjs → body-BCEAkwBy.cjs} +1 -1
  19. package/dist/tests/{body-DkyJy_0c.mjs → body-BUO7KBud.mjs} +1 -1
  20. package/dist/tests/body.test.cjs +1 -1
  21. package/dist/tests/body.test.mjs +1 -1
  22. package/dist/tests/decimal.test.cjs +1 -1
  23. package/dist/tests/decimal.test.mjs +1 -1
  24. package/dist/tests/{docloader-CSfFzxWm.mjs → docloader-BBjIii4r.mjs} +16 -10
  25. package/dist/tests/{docloader-DFs6K8ol.cjs → docloader-DOtl16c7.cjs} +16 -10
  26. package/dist/tests/docloader.test.cjs +49 -2
  27. package/dist/tests/docloader.test.mjs +49 -2
  28. package/dist/tests/internal/portable-dereference.test.cjs +67 -6
  29. package/dist/tests/internal/portable-dereference.test.mjs +67 -6
  30. package/dist/tests/jsonld-cache-9jap4yM0.cjs +373 -0
  31. package/dist/tests/jsonld-cache-DnZS0z1G.mjs +324 -0
  32. package/dist/tests/jsonld-cache.test.cjs +20 -291
  33. package/dist/tests/jsonld-cache.test.mjs +2 -273
  34. package/dist/tests/{request-CmMy4YVK.mjs → request-C6bviL-E.mjs} +1 -1
  35. package/dist/tests/{request-BLe2W5ua.cjs → request-DzzSwifZ.cjs} +1 -1
  36. package/dist/tests/request.test.cjs +1 -1
  37. package/dist/tests/request.test.mjs +1 -1
  38. package/package.json +1 -1
  39. package/src/docloader.test.ts +73 -0
  40. package/src/docloader.ts +46 -17
  41. package/src/internal/jsonld-cache.ts +60 -0
  42. package/src/internal/portable-dereference.test.ts +71 -0
  43. package/src/internal/portable-dereference.ts +37 -24
  44. package/src/preprocessor.ts +7 -0
  45. package/dist/tests/jsonld-CmDhHNTx.cjs +0 -12
  46. package/dist/tests/jsonld-DweIJ07b.mjs +0 -5
package/dist/mod.cjs CHANGED
@@ -16,7 +16,7 @@ let _multiformats_base_x = require("@multiformats/base-x");
16
16
  _multiformats_base_x = require_rolldown_runtime.__toESM(_multiformats_base_x, 1);
17
17
  //#region deno.json
18
18
  var name = "@fedify/vocab-runtime";
19
- var version = "2.4.0-dev.2122+bdc0ce8d";
19
+ var version = "2.4.0-dev.2127+c41ce2eb";
20
20
  //#endregion
21
21
  //#region src/request.ts
22
22
  /**
@@ -369,15 +369,21 @@ function createResponseMetadata(response) {
369
369
  * @param url The URL of the document to load.
370
370
  * @param response The response to get the document from.
371
371
  * @param fetch The function to fetch the document.
372
+ * @param options The options for loading the document.
372
373
  * @returns The loaded remote document.
373
374
  * @throws {FetchError} If the response is not OK.
374
375
  * @internal
375
376
  */
376
- async function getRemoteDocument(url, response, fetch) {
377
+ async function getRemoteDocument(url, response, fetch, options) {
377
378
  const documentUrl = response.url === "" ? url : response.url;
378
379
  const docUrl = new URL(documentUrl);
379
380
  if (!response.ok) {
380
- logger.error("Failed to fetch document: {status} {url} {headers}", {
381
+ if (options?.suppressError) logger.warn("Failed to fetch document: {status} {url} {headers}", {
382
+ status: response.status,
383
+ url: documentUrl,
384
+ headers: Object.fromEntries(response.headers.entries())
385
+ });
386
+ else logger.error("Failed to fetch document: {status} {url} {headers}", {
381
387
  status: response.status,
382
388
  url: documentUrl,
383
389
  headers: Object.fromEntries(response.headers.entries())
@@ -411,7 +417,7 @@ async function getRemoteDocument(url, response, fetch) {
411
417
  alternateUrl: altUri.href,
412
418
  url: documentUrl
413
419
  });
414
- return await fetch(altUri.href);
420
+ return await fetch(altUri.href, options);
415
421
  }
416
422
  }
417
423
  }
@@ -447,7 +453,7 @@ async function getRemoteDocument(url, response, fetch) {
447
453
  alternateUrl: attribs.href,
448
454
  url: documentUrl
449
455
  });
450
- return await fetch(new URL(attribs.href, docUrl).href);
456
+ return await fetch(new URL(attribs.href, docUrl).href, options);
451
457
  }
452
458
  }
453
459
  try {
@@ -505,7 +511,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
505
511
  if (!allowPrivateAddress) try {
506
512
  await require_url.validatePublicUrl(currentUrl);
507
513
  } catch (error) {
508
- if (error instanceof require_url.UrlError) logger.error("Disallowed private URL: {url}", {
514
+ if (error instanceof require_url.UrlError) logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
509
515
  url: currentUrl,
510
516
  error
511
517
  });
@@ -526,7 +532,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
526
532
  span.setAttribute("http.response.status_code", response.status);
527
533
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
528
534
  if (redirected >= maximumRedirection) {
529
- logger.error("Too many redirections ({redirections}) while fetching document.", {
535
+ logger[options?.suppressError ? "warn" : "error"]("Too many redirections ({redirections}) while fetching document.", {
530
536
  redirections: redirected + 1,
531
537
  url: currentUrl
532
538
  });
@@ -535,7 +541,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
535
541
  const redirectUrl = new URL(response.headers.get("Location"), response.url === "" ? currentUrl : response.url).href;
536
542
  span.setAttribute("http.redirect.url", redirectUrl);
537
543
  if (visited.has(redirectUrl)) {
538
- logger.error("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
544
+ logger[options?.suppressError ? "warn" : "error"]("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
539
545
  url: currentUrl,
540
546
  redirectUrl
541
547
  });
@@ -543,7 +549,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
543
549
  }
544
550
  return await load(redirectUrl, options, redirected + 1, visited);
545
551
  }
546
- const result = await getRemoteDocument(currentUrl, response, load);
552
+ const result = await getRemoteDocument(currentUrl, response, load, options);
547
553
  span.setAttribute("docloader.document_url", result.documentUrl);
548
554
  if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
549
555
  return result;
package/dist/mod.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { a as DocumentLoaderOptions, c as getDocumentLoader, d as FetchError, f as GetUserAgentOptions, h as logRequest, i as DocumentLoaderFactoryOptions, l as getRemoteDocument, m as getUserAgent, n as DocumentLoader, o as GetDocumentLoaderOptions, p as createActivityPubRequest, r as DocumentLoaderFactory, s as RemoteDocument, t as AuthenticatedDocumentLoaderFactory, u as CreateRequestOptions } from "./docloader-Dr8wEkif.cjs";
3
- import { i as PortableObjectVerifierOptions, n as PortableObjectVerification, r as PortableObjectVerifier, t as PortableObjectReferrer } from "./portable-comBI05Y.cjs";
2
+ import { a as DocumentLoaderOptions, c as getDocumentLoader, d as FetchError, f as GetUserAgentOptions, h as logRequest, i as DocumentLoaderFactoryOptions, l as getRemoteDocument, m as getUserAgent, n as DocumentLoader, o as GetDocumentLoaderOptions, p as createActivityPubRequest, r as DocumentLoaderFactory, s as RemoteDocument, t as AuthenticatedDocumentLoaderFactory, u as CreateRequestOptions } from "./docloader-oRpq1nQ8.cjs";
3
+ import { i as PortableObjectVerifierOptions, n as PortableObjectVerification, r as PortableObjectVerifier, t as PortableObjectReferrer } from "./portable-Drfl02vZ.cjs";
4
4
  import { TracerProvider } from "@opentelemetry/api";
5
5
 
6
6
  //#region src/contexts.d.ts
@@ -384,6 +384,12 @@ interface PropertyPreprocessorContext {
384
384
  contextLoader?: DocumentLoader;
385
385
  /** OpenTelemetry tracer provider for instrumentation. */
386
386
  tracerProvider?: TracerProvider;
387
+ /**
388
+ * The default FEP-ef61 portable object verifier that objects returned by
389
+ * the preprocessor should use for their property accessors.
390
+ * @since 2.4.0
391
+ */
392
+ verifyPortableObject?: PortableObjectVerifier;
387
393
  /** Base URL for resolving relative references. */
388
394
  baseUrl?: URL;
389
395
  }
package/dist/mod.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { a as DocumentLoaderOptions, c as getDocumentLoader, d as FetchError, f as GetUserAgentOptions, h as logRequest, i as DocumentLoaderFactoryOptions, l as getRemoteDocument, m as getUserAgent, n as DocumentLoader, o as GetDocumentLoaderOptions, p as createActivityPubRequest, r as DocumentLoaderFactory, s as RemoteDocument, t as AuthenticatedDocumentLoaderFactory, u as CreateRequestOptions } from "./docloader-Dr8wEkif.js";
3
- import { i as PortableObjectVerifierOptions, n as PortableObjectVerification, r as PortableObjectVerifier, t as PortableObjectReferrer } from "./portable-DH3947GK.js";
2
+ import { a as DocumentLoaderOptions, c as getDocumentLoader, d as FetchError, f as GetUserAgentOptions, h as logRequest, i as DocumentLoaderFactoryOptions, l as getRemoteDocument, m as getUserAgent, n as DocumentLoader, o as GetDocumentLoaderOptions, p as createActivityPubRequest, r as DocumentLoaderFactory, s as RemoteDocument, t as AuthenticatedDocumentLoaderFactory, u as CreateRequestOptions } from "./docloader-oRpq1nQ8.js";
3
+ import { i as PortableObjectVerifierOptions, n as PortableObjectVerification, r as PortableObjectVerifier, t as PortableObjectReferrer } from "./portable-rwhiyMvY.js";
4
4
  import { TracerProvider } from "@opentelemetry/api";
5
5
  //#region src/contexts.d.ts
6
6
  declare const preloadedContexts: Record<string, unknown>;
@@ -383,6 +383,12 @@ interface PropertyPreprocessorContext {
383
383
  contextLoader?: DocumentLoader;
384
384
  /** OpenTelemetry tracer provider for instrumentation. */
385
385
  tracerProvider?: TracerProvider;
386
+ /**
387
+ * The default FEP-ef61 portable object verifier that objects returned by
388
+ * the preprocessor should use for their property accessors.
389
+ * @since 2.4.0
390
+ */
391
+ verifyPortableObject?: PortableObjectVerifier;
386
392
  /** Base URL for resolving relative references. */
387
393
  baseUrl?: URL;
388
394
  }
package/dist/mod.js CHANGED
@@ -12,7 +12,7 @@ import { PublicKeyInfo } from "pkijs";
12
12
  import baseX from "@multiformats/base-x";
13
13
  //#region deno.json
14
14
  var name = "@fedify/vocab-runtime";
15
- var version = "2.4.0-dev.2122+bdc0ce8d";
15
+ var version = "2.4.0-dev.2127+c41ce2eb";
16
16
  //#endregion
17
17
  //#region src/request.ts
18
18
  /**
@@ -365,15 +365,21 @@ function createResponseMetadata(response) {
365
365
  * @param url The URL of the document to load.
366
366
  * @param response The response to get the document from.
367
367
  * @param fetch The function to fetch the document.
368
+ * @param options The options for loading the document.
368
369
  * @returns The loaded remote document.
369
370
  * @throws {FetchError} If the response is not OK.
370
371
  * @internal
371
372
  */
372
- async function getRemoteDocument(url, response, fetch) {
373
+ async function getRemoteDocument(url, response, fetch, options) {
373
374
  const documentUrl = response.url === "" ? url : response.url;
374
375
  const docUrl = new URL(documentUrl);
375
376
  if (!response.ok) {
376
- logger.error("Failed to fetch document: {status} {url} {headers}", {
377
+ if (options?.suppressError) logger.warn("Failed to fetch document: {status} {url} {headers}", {
378
+ status: response.status,
379
+ url: documentUrl,
380
+ headers: Object.fromEntries(response.headers.entries())
381
+ });
382
+ else logger.error("Failed to fetch document: {status} {url} {headers}", {
377
383
  status: response.status,
378
384
  url: documentUrl,
379
385
  headers: Object.fromEntries(response.headers.entries())
@@ -407,7 +413,7 @@ async function getRemoteDocument(url, response, fetch) {
407
413
  alternateUrl: altUri.href,
408
414
  url: documentUrl
409
415
  });
410
- return await fetch(altUri.href);
416
+ return await fetch(altUri.href, options);
411
417
  }
412
418
  }
413
419
  }
@@ -443,7 +449,7 @@ async function getRemoteDocument(url, response, fetch) {
443
449
  alternateUrl: attribs.href,
444
450
  url: documentUrl
445
451
  });
446
- return await fetch(new URL(attribs.href, docUrl).href);
452
+ return await fetch(new URL(attribs.href, docUrl).href, options);
447
453
  }
448
454
  }
449
455
  try {
@@ -501,7 +507,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
501
507
  if (!allowPrivateAddress) try {
502
508
  await validatePublicUrl(currentUrl);
503
509
  } catch (error) {
504
- if (error instanceof UrlError) logger.error("Disallowed private URL: {url}", {
510
+ if (error instanceof UrlError) logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
505
511
  url: currentUrl,
506
512
  error
507
513
  });
@@ -522,7 +528,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
522
528
  span.setAttribute("http.response.status_code", response.status);
523
529
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
524
530
  if (redirected >= maximumRedirection) {
525
- logger.error("Too many redirections ({redirections}) while fetching document.", {
531
+ logger[options?.suppressError ? "warn" : "error"]("Too many redirections ({redirections}) while fetching document.", {
526
532
  redirections: redirected + 1,
527
533
  url: currentUrl
528
534
  });
@@ -531,7 +537,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
531
537
  const redirectUrl = new URL(response.headers.get("Location"), response.url === "" ? currentUrl : response.url).href;
532
538
  span.setAttribute("http.redirect.url", redirectUrl);
533
539
  if (visited.has(redirectUrl)) {
534
- logger.error("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
540
+ logger[options?.suppressError ? "warn" : "error"]("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
535
541
  url: currentUrl,
536
542
  redirectUrl
537
543
  });
@@ -539,7 +545,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
539
545
  }
540
546
  return await load(redirectUrl, options, redirected + 1, visited);
541
547
  }
542
- const result = await getRemoteDocument(currentUrl, response, load);
548
+ const result = await getRemoteDocument(currentUrl, response, load, options);
543
549
  span.setAttribute("docloader.document_url", result.documentUrl);
544
550
  if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
545
551
  return result;
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as DocumentLoader } from "./docloader-Dr8wEkif.cjs";
2
+ import { n as DocumentLoader } from "./docloader-oRpq1nQ8.cjs";
3
3
  import { TracerProvider } from "@opentelemetry/api";
4
4
 
5
5
  //#region src/portable.d.ts
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as DocumentLoader } from "./docloader-Dr8wEkif.js";
2
+ import { n as DocumentLoader } from "./docloader-oRpq1nQ8.js";
3
3
  import { TracerProvider } from "@opentelemetry/api";
4
4
 
5
5
  //#region src/portable.d.ts
@@ -1,4 +1,4 @@
1
- const require_request = require("./request-BLe2W5ua.cjs");
1
+ const require_request = require("./request-DzzSwifZ.cjs");
2
2
  let _logtape_logtape = require("@logtape/logtape");
3
3
  //#region src/body.ts
4
4
  /** Decoded JSON body limit: 16 MiB. @internal */
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "./request-CmMy4YVK.mjs";
1
+ import { t as FetchError } from "./request-C6bviL-E.mjs";
2
2
  import { getLogger } from "@logtape/logtape";
3
3
  //#region src/body.ts
4
4
  /** Decoded JSON body limit: 16 MiB. @internal */
@@ -1,4 +1,4 @@
1
- const require_body = require("./body-tLaZa-9t.cjs");
1
+ const require_body = require("./body-BCEAkwBy.cjs");
2
2
  let node_assert_strict = require("node:assert/strict");
3
3
  let node_test = require("node:test");
4
4
  let node_zlib = require("node:zlib");
@@ -1,4 +1,4 @@
1
- import { r as readBoundedText, t as BodyTooLargeError } from "./body-DkyJy_0c.mjs";
1
+ import { r as readBoundedText, t as BodyTooLargeError } from "./body-BUO7KBud.mjs";
2
2
  import { deepStrictEqual, ok, rejects } from "node:assert/strict";
3
3
  import { test } from "node:test";
4
4
  import { gunzipSync, gzipSync } from "node:zlib";
@@ -1,5 +1,5 @@
1
1
  require("./url-BqlldzT8.cjs");
2
- require("./docloader-DFs6K8ol.cjs");
2
+ require("./docloader-DOtl16c7.cjs");
3
3
  require("./key-C-AYkdJJ.cjs");
4
4
  require("./multibase-B5Mea7Ip.cjs");
5
5
  require("./digest-3FeH2Y-Q.cjs");
@@ -1,5 +1,5 @@
1
1
  import "./url-DgJM9WJn.mjs";
2
- import "./docloader-CSfFzxWm.mjs";
2
+ import "./docloader-BBjIii4r.mjs";
3
3
  import "./key-C2Db_TAJ.mjs";
4
4
  import "./multibase-BPnF_L4e.mjs";
5
5
  import "./digest-COC7xDiQ.mjs";
@@ -1,5 +1,5 @@
1
- import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-CmMy4YVK.mjs";
2
- import { n as MAX_BODY_SIZE, r as readBoundedText, t as BodyTooLargeError } from "./body-DkyJy_0c.mjs";
1
+ import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-C6bviL-E.mjs";
2
+ import { n as MAX_BODY_SIZE, r as readBoundedText, t as BodyTooLargeError } from "./body-BUO7KBud.mjs";
3
3
  import { t as preloadedContexts } from "./contexts-BBX_qhBL.mjs";
4
4
  import { t as HttpHeaderLink } from "./link-Cevmc87v.mjs";
5
5
  import { t as UrlError, v as validatePublicUrl } from "./url-DgJM9WJn.mjs";
@@ -25,15 +25,21 @@ function createResponseMetadata(response) {
25
25
  * @param url The URL of the document to load.
26
26
  * @param response The response to get the document from.
27
27
  * @param fetch The function to fetch the document.
28
+ * @param options The options for loading the document.
28
29
  * @returns The loaded remote document.
29
30
  * @throws {FetchError} If the response is not OK.
30
31
  * @internal
31
32
  */
32
- async function getRemoteDocument(url, response, fetch) {
33
+ async function getRemoteDocument(url, response, fetch, options) {
33
34
  const documentUrl = response.url === "" ? url : response.url;
34
35
  const docUrl = new URL(documentUrl);
35
36
  if (!response.ok) {
36
- logger.error("Failed to fetch document: {status} {url} {headers}", {
37
+ if (options?.suppressError) logger.warn("Failed to fetch document: {status} {url} {headers}", {
38
+ status: response.status,
39
+ url: documentUrl,
40
+ headers: Object.fromEntries(response.headers.entries())
41
+ });
42
+ else logger.error("Failed to fetch document: {status} {url} {headers}", {
37
43
  status: response.status,
38
44
  url: documentUrl,
39
45
  headers: Object.fromEntries(response.headers.entries())
@@ -67,7 +73,7 @@ async function getRemoteDocument(url, response, fetch) {
67
73
  alternateUrl: altUri.href,
68
74
  url: documentUrl
69
75
  });
70
- return await fetch(altUri.href);
76
+ return await fetch(altUri.href, options);
71
77
  }
72
78
  }
73
79
  }
@@ -103,7 +109,7 @@ async function getRemoteDocument(url, response, fetch) {
103
109
  alternateUrl: attribs.href,
104
110
  url: documentUrl
105
111
  });
106
- return await fetch(new URL(attribs.href, docUrl).href);
112
+ return await fetch(new URL(attribs.href, docUrl).href, options);
107
113
  }
108
114
  }
109
115
  try {
@@ -161,7 +167,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
161
167
  if (!allowPrivateAddress) try {
162
168
  await validatePublicUrl(currentUrl);
163
169
  } catch (error) {
164
- if (error instanceof UrlError) logger.error("Disallowed private URL: {url}", {
170
+ if (error instanceof UrlError) logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
165
171
  url: currentUrl,
166
172
  error
167
173
  });
@@ -182,7 +188,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
182
188
  span.setAttribute("http.response.status_code", response.status);
183
189
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
184
190
  if (redirected >= maximumRedirection) {
185
- logger.error("Too many redirections ({redirections}) while fetching document.", {
191
+ logger[options?.suppressError ? "warn" : "error"]("Too many redirections ({redirections}) while fetching document.", {
186
192
  redirections: redirected + 1,
187
193
  url: currentUrl
188
194
  });
@@ -191,7 +197,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
191
197
  const redirectUrl = new URL(response.headers.get("Location"), response.url === "" ? currentUrl : response.url).href;
192
198
  span.setAttribute("http.redirect.url", redirectUrl);
193
199
  if (visited.has(redirectUrl)) {
194
- logger.error("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
200
+ logger[options?.suppressError ? "warn" : "error"]("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
195
201
  url: currentUrl,
196
202
  redirectUrl
197
203
  });
@@ -199,7 +205,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
199
205
  }
200
206
  return await load(redirectUrl, options, redirected + 1, visited);
201
207
  }
202
- const result = await getRemoteDocument(currentUrl, response, load);
208
+ const result = await getRemoteDocument(currentUrl, response, load, options);
203
209
  span.setAttribute("docloader.document_url", result.documentUrl);
204
210
  if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
205
211
  return result;
@@ -1,5 +1,5 @@
1
- const require_request = require("./request-BLe2W5ua.cjs");
2
- const require_body = require("./body-tLaZa-9t.cjs");
1
+ const require_request = require("./request-DzzSwifZ.cjs");
2
+ const require_body = require("./body-BCEAkwBy.cjs");
3
3
  const require_contexts = require("./contexts-Ch3v2Cgu.cjs");
4
4
  const require_link = require("./link-DlKm8bEr.cjs");
5
5
  const require_url = require("./url-BqlldzT8.cjs");
@@ -25,15 +25,21 @@ function createResponseMetadata(response) {
25
25
  * @param url The URL of the document to load.
26
26
  * @param response The response to get the document from.
27
27
  * @param fetch The function to fetch the document.
28
+ * @param options The options for loading the document.
28
29
  * @returns The loaded remote document.
29
30
  * @throws {FetchError} If the response is not OK.
30
31
  * @internal
31
32
  */
32
- async function getRemoteDocument(url, response, fetch) {
33
+ async function getRemoteDocument(url, response, fetch, options) {
33
34
  const documentUrl = response.url === "" ? url : response.url;
34
35
  const docUrl = new URL(documentUrl);
35
36
  if (!response.ok) {
36
- logger.error("Failed to fetch document: {status} {url} {headers}", {
37
+ if (options?.suppressError) logger.warn("Failed to fetch document: {status} {url} {headers}", {
38
+ status: response.status,
39
+ url: documentUrl,
40
+ headers: Object.fromEntries(response.headers.entries())
41
+ });
42
+ else logger.error("Failed to fetch document: {status} {url} {headers}", {
37
43
  status: response.status,
38
44
  url: documentUrl,
39
45
  headers: Object.fromEntries(response.headers.entries())
@@ -67,7 +73,7 @@ async function getRemoteDocument(url, response, fetch) {
67
73
  alternateUrl: altUri.href,
68
74
  url: documentUrl
69
75
  });
70
- return await fetch(altUri.href);
76
+ return await fetch(altUri.href, options);
71
77
  }
72
78
  }
73
79
  }
@@ -103,7 +109,7 @@ async function getRemoteDocument(url, response, fetch) {
103
109
  alternateUrl: attribs.href,
104
110
  url: documentUrl
105
111
  });
106
- return await fetch(new URL(attribs.href, docUrl).href);
112
+ return await fetch(new URL(attribs.href, docUrl).href, options);
107
113
  }
108
114
  }
109
115
  try {
@@ -161,7 +167,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
161
167
  if (!allowPrivateAddress) try {
162
168
  await require_url.validatePublicUrl(currentUrl);
163
169
  } catch (error) {
164
- if (error instanceof require_url.UrlError) logger.error("Disallowed private URL: {url}", {
170
+ if (error instanceof require_url.UrlError) logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
165
171
  url: currentUrl,
166
172
  error
167
173
  });
@@ -182,7 +188,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
182
188
  span.setAttribute("http.response.status_code", response.status);
183
189
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
184
190
  if (redirected >= maximumRedirection) {
185
- logger.error("Too many redirections ({redirections}) while fetching document.", {
191
+ logger[options?.suppressError ? "warn" : "error"]("Too many redirections ({redirections}) while fetching document.", {
186
192
  redirections: redirected + 1,
187
193
  url: currentUrl
188
194
  });
@@ -191,7 +197,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
191
197
  const redirectUrl = new URL(response.headers.get("Location"), response.url === "" ? currentUrl : response.url).href;
192
198
  span.setAttribute("http.redirect.url", redirectUrl);
193
199
  if (visited.has(redirectUrl)) {
194
- logger.error("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
200
+ logger[options?.suppressError ? "warn" : "error"]("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
195
201
  url: currentUrl,
196
202
  redirectUrl
197
203
  });
@@ -199,7 +205,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
199
205
  }
200
206
  return await load(redirectUrl, options, redirected + 1, visited);
201
207
  }
202
- const result = await getRemoteDocument(currentUrl, response, load);
208
+ const result = await getRemoteDocument(currentUrl, response, load, options);
203
209
  span.setAttribute("docloader.document_url", result.documentUrl);
204
210
  if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
205
211
  return result;
@@ -1,10 +1,11 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
2
- const require_request = require("./request-BLe2W5ua.cjs");
2
+ const require_request = require("./request-DzzSwifZ.cjs");
3
3
  const require_contexts = require("./contexts-Ch3v2Cgu.cjs");
4
4
  const require_url = require("./url-BqlldzT8.cjs");
5
- const require_docloader = require("./docloader-DFs6K8ol.cjs");
5
+ const require_docloader = require("./docloader-DOtl16c7.cjs");
6
6
  let node_test = require("node:test");
7
7
  let node_zlib = require("node:zlib");
8
+ let _logtape_logtape = require("@logtape/logtape");
8
9
  let node_assert = require("node:assert");
9
10
  let node_http = require("node:http");
10
11
  //#region ../../node_modules/.pnpm/glob-to-regexp@0.4.1/node_modules/glob-to-regexp/index.js
@@ -1216,6 +1217,52 @@ var esm_default = new class FetchMock {
1216
1217
  }({ ...defaultFetchMockConfig });
1217
1218
  //#endregion
1218
1219
  //#region src/docloader.test.ts
1220
+ (0, node_test.test)("getRemoteDocument() forwards options to alternate documents", async () => {
1221
+ const records = [];
1222
+ await (0, _logtape_logtape.reset)();
1223
+ await (0, _logtape_logtape.configure)({
1224
+ sinks: { capture: (record) => records.push(record) },
1225
+ loggers: [{
1226
+ category: ["fedify"],
1227
+ lowestLevel: "debug",
1228
+ sinks: ["capture"]
1229
+ }]
1230
+ });
1231
+ try {
1232
+ for (const linkHeader of [true, false]) for (const suppressError of [
1233
+ true,
1234
+ false,
1235
+ void 0
1236
+ ]) {
1237
+ records.length = 0;
1238
+ const url = "https://example.com/alternate-source";
1239
+ const alternateUrl = "https://example.com/missing-alternate";
1240
+ const options = {
1241
+ suppressError,
1242
+ signal: new AbortController().signal
1243
+ };
1244
+ const response = new Response(`<link rel="alternate" type="application/activity+json" href="${alternateUrl}">`, { headers: {
1245
+ "Content-Type": "text/html",
1246
+ ...linkHeader ? { Link: `<${alternateUrl}>; rel="alternate"; type="application/activity+json"` } : {}
1247
+ } });
1248
+ let alternateRequests = 0;
1249
+ await (0, node_assert.rejects)(() => require_docloader.getRemoteDocument(url, response, async (requestedUrl, forwarded) => {
1250
+ alternateRequests++;
1251
+ (0, node_assert.deepStrictEqual)(requestedUrl, alternateUrl);
1252
+ (0, node_assert.deepStrictEqual)(forwarded, options);
1253
+ return await require_docloader.getRemoteDocument(requestedUrl, new Response(null, { status: 404 }), () => {
1254
+ throw new Error("Unexpected additional alternate");
1255
+ }, forwarded);
1256
+ }, options), require_request.FetchError);
1257
+ (0, node_assert.deepStrictEqual)(alternateRequests, 1);
1258
+ const failures = records.filter((record) => record.rawMessage === "Failed to fetch document: {status} {url} {headers}");
1259
+ (0, node_assert.deepStrictEqual)(failures.length, 1);
1260
+ (0, node_assert.deepStrictEqual)(failures[0].level, suppressError ? "warning" : "error");
1261
+ }
1262
+ } finally {
1263
+ await (0, _logtape_logtape.reset)();
1264
+ }
1265
+ });
1219
1266
  (0, node_test.test)("new FetchError()", () => {
1220
1267
  const e = new require_request.FetchError("https://example.com/", "An error message.");
1221
1268
  (0, node_assert.deepStrictEqual)(e.name, "FetchError");
@@ -1,9 +1,10 @@
1
- import { t as FetchError } from "./request-CmMy4YVK.mjs";
1
+ import { t as FetchError } from "./request-C6bviL-E.mjs";
2
2
  import { n as cid_v1_default, t as preloadedContexts } from "./contexts-BBX_qhBL.mjs";
3
3
  import { t as UrlError } from "./url-DgJM9WJn.mjs";
4
- import { n as getRemoteDocument, t as getDocumentLoader } from "./docloader-CSfFzxWm.mjs";
4
+ import { n as getRemoteDocument, t as getDocumentLoader } from "./docloader-BBjIii4r.mjs";
5
5
  import { test } from "node:test";
6
6
  import { gzipSync } from "node:zlib";
7
+ import { configure, reset } from "@logtape/logtape";
7
8
  import { deepStrictEqual, ok, rejects } from "node:assert";
8
9
  import { createServer } from "node:http";
9
10
  //#region \0rolldown/runtime.js
@@ -1235,6 +1236,52 @@ var esm_default = new class FetchMock {
1235
1236
  }({ ...defaultFetchMockConfig });
1236
1237
  //#endregion
1237
1238
  //#region src/docloader.test.ts
1239
+ test("getRemoteDocument() forwards options to alternate documents", async () => {
1240
+ const records = [];
1241
+ await reset();
1242
+ await configure({
1243
+ sinks: { capture: (record) => records.push(record) },
1244
+ loggers: [{
1245
+ category: ["fedify"],
1246
+ lowestLevel: "debug",
1247
+ sinks: ["capture"]
1248
+ }]
1249
+ });
1250
+ try {
1251
+ for (const linkHeader of [true, false]) for (const suppressError of [
1252
+ true,
1253
+ false,
1254
+ void 0
1255
+ ]) {
1256
+ records.length = 0;
1257
+ const url = "https://example.com/alternate-source";
1258
+ const alternateUrl = "https://example.com/missing-alternate";
1259
+ const options = {
1260
+ suppressError,
1261
+ signal: new AbortController().signal
1262
+ };
1263
+ const response = new Response(`<link rel="alternate" type="application/activity+json" href="${alternateUrl}">`, { headers: {
1264
+ "Content-Type": "text/html",
1265
+ ...linkHeader ? { Link: `<${alternateUrl}>; rel="alternate"; type="application/activity+json"` } : {}
1266
+ } });
1267
+ let alternateRequests = 0;
1268
+ await rejects(() => getRemoteDocument(url, response, async (requestedUrl, forwarded) => {
1269
+ alternateRequests++;
1270
+ deepStrictEqual(requestedUrl, alternateUrl);
1271
+ deepStrictEqual(forwarded, options);
1272
+ return await getRemoteDocument(requestedUrl, new Response(null, { status: 404 }), () => {
1273
+ throw new Error("Unexpected additional alternate");
1274
+ }, forwarded);
1275
+ }, options), FetchError);
1276
+ deepStrictEqual(alternateRequests, 1);
1277
+ const failures = records.filter((record) => record.rawMessage === "Failed to fetch document: {status} {url} {headers}");
1278
+ deepStrictEqual(failures.length, 1);
1279
+ deepStrictEqual(failures[0].level, suppressError ? "warning" : "error");
1280
+ }
1281
+ } finally {
1282
+ await reset();
1283
+ }
1284
+ });
1238
1285
  test("new FetchError()", () => {
1239
1286
  const e = new FetchError("https://example.com/", "An error message.");
1240
1287
  deepStrictEqual(e.name, "FetchError");