@fedify/vocab-runtime 2.1.29 → 2.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deno.json +5 -2
- package/dist/internal.cjs +6 -0
- package/dist/internal.d.cts +3 -0
- package/dist/internal.d.ts +3 -0
- package/dist/internal.js +3 -0
- package/dist/mod.cjs +105 -252
- package/dist/mod.d.cts +5 -27
- package/dist/mod.d.ts +6 -27
- package/dist/mod.js +99 -245
- package/dist/public-fetch-BC-nWJNM.d.ts +143 -0
- package/dist/public-fetch-CFnW7XMn.cjs +821 -0
- package/dist/public-fetch-DBpt3xxf.d.cts +143 -0
- package/dist/public-fetch-Dfmc_Kfy.js +772 -0
- package/dist/tests/{body-C-p-RXaQ.mjs → body-B0Z2Vegb.mjs} +1 -1
- package/dist/tests/{body-BI7IK9DK.cjs → body-i_FdQE3f.cjs} +1 -1
- package/dist/tests/body.test.cjs +1 -1
- package/dist/tests/body.test.mjs +1 -1
- package/dist/tests/decimal.test.cjs +6 -6
- package/dist/tests/decimal.test.mjs +6 -6
- package/dist/tests/{docloader-DVamy9FW.mjs → docloader-dwostFF6.mjs} +103 -37
- package/dist/tests/{docloader-Okt4FgM8.cjs → docloader-oZrKg7F3.cjs} +107 -35
- package/dist/tests/docloader.test.cjs +568 -1272
- package/dist/tests/docloader.test.mjs +514 -1237
- package/dist/tests/esm-CnLt0wAF.mjs +1225 -0
- package/dist/tests/esm-CxbqfkLP.cjs +1208 -0
- package/dist/tests/internal/multicodec.test.cjs +1 -1
- package/dist/tests/internal/multicodec.test.mjs +1 -1
- package/dist/tests/{key-BDIsC6hV.mjs → key-GEdpxA4M.mjs} +2 -2
- package/dist/tests/{key-BarKGLQz.cjs → key-L6ReMuUb.cjs} +2 -2
- package/dist/tests/key.test.cjs +2 -2
- package/dist/tests/key.test.mjs +2 -2
- package/dist/tests/{langstr-BsqFJupv.cjs → langstr-CZpWmpo5.cjs} +1 -1
- package/dist/tests/{langstr-ABdAOKlF.mjs → langstr-DTB4sl0a.mjs} +1 -1
- package/dist/tests/langstr.test.cjs +1 -1
- package/dist/tests/langstr.test.mjs +1 -1
- package/dist/tests/langtag.test.cjs +1 -1
- package/dist/tests/langtag.test.mjs +1 -1
- package/dist/tests/link.test.mjs +1 -1
- package/dist/tests/multibase/multibase.test.cjs +1 -1
- package/dist/tests/multibase/multibase.test.mjs +1 -1
- package/dist/tests/node-C3bjFjL1.mjs +84 -0
- package/dist/tests/node-DWD76vPo.cjs +90 -0
- package/dist/tests/pin-grant-CU-o367k.cjs +70 -0
- package/dist/tests/pin-grant-HW3B6SKv.mjs +53 -0
- package/dist/tests/pin-grant.test.cjs +88 -0
- package/dist/tests/pin-grant.test.d.cts +1 -0
- package/dist/tests/pin-grant.test.d.mts +1 -0
- package/dist/tests/pin-grant.test.mjs +88 -0
- package/dist/tests/pinners/bun.test.cjs +167 -0
- package/dist/tests/pinners/bun.test.d.cts +1 -0
- package/dist/tests/pinners/bun.test.d.mts +1 -0
- package/dist/tests/pinners/bun.test.mjs +167 -0
- package/dist/tests/pinners/node.test.cjs +269 -0
- package/dist/tests/pinners/node.test.d.cts +1 -0
- package/dist/tests/pinners/node.test.d.mts +1 -0
- package/dist/tests/pinners/node.test.mjs +268 -0
- package/dist/tests/pinners/pinners.test.cjs +197 -0
- package/dist/tests/pinners/pinners.test.d.cts +1 -0
- package/dist/tests/pinners/pinners.test.d.mts +1 -0
- package/dist/tests/pinners/pinners.test.mjs +197 -0
- package/dist/tests/pinners/testdata/node-child.cjs +135 -0
- package/dist/tests/pinners/testdata/node-child.d.cts +1 -0
- package/dist/tests/pinners/testdata/node-child.d.mts +1 -0
- package/dist/tests/pinners/testdata/node-child.mjs +134 -0
- package/dist/tests/pinners-BjE-YJLL.cjs +221 -0
- package/dist/tests/pinners-ZgZDx9y6.mjs +203 -0
- package/dist/tests/public-fetch-Ddjfxbwc.cjs +187 -0
- package/dist/tests/public-fetch-Yi7Vks9s.mjs +170 -0
- package/dist/tests/public-fetch.test.cjs +1074 -0
- package/dist/tests/public-fetch.test.d.cts +1 -0
- package/dist/tests/public-fetch.test.d.mts +1 -0
- package/dist/tests/public-fetch.test.mjs +1074 -0
- package/dist/tests/{request-C_PrlGe_.cjs → request-CzYw8aEp.cjs} +1 -1
- package/dist/tests/{request-B9R4Y9qS.mjs → request-DY2AaRpH.mjs} +1 -1
- package/dist/tests/request.test.cjs +1 -1
- package/dist/tests/request.test.mjs +1 -1
- package/dist/tests/support-D5-KVjWZ.cjs +363 -0
- package/dist/tests/support-M5ClN-no.mjs +272 -0
- package/dist/tests/{url-vZTgkIZg.cjs → url-DLuSj57U.cjs} +88 -12
- package/dist/tests/{url-3fyJuqC0.mjs → url-DQWrMGhu.mjs} +65 -13
- package/dist/tests/url.test.cjs +4 -1
- package/dist/tests/url.test.mjs +4 -1
- package/package.json +14 -3
- package/src/docloader.test.ts +780 -31
- package/src/docloader.ts +179 -67
- package/src/internal.ts +13 -0
- package/src/pin-grant.test.ts +118 -0
- package/src/pin-grant.ts +99 -0
- package/src/pinners/bun.test.ts +278 -0
- package/src/pinners/bun.ts +223 -0
- package/src/pinners/mod.ts +59 -0
- package/src/pinners/node.test.ts +415 -0
- package/src/pinners/node.ts +144 -0
- package/src/pinners/pinners.test.ts +316 -0
- package/src/pinners/testdata/node-child.ts +147 -0
- package/src/pinners/testdata/proxy-child.ts +82 -0
- package/src/pinners/testdata/support.ts +343 -0
- package/src/pinners/testdata/tls-cert.pem +12 -0
- package/src/pinners/testdata/tls-child.ts +88 -0
- package/src/pinners/testdata/tls-key.pem +5 -0
- package/src/pinners/types.ts +48 -0
- package/src/public-fetch.test.ts +1286 -0
- package/src/public-fetch.ts +338 -0
- package/src/testdata/public-fetch-deno-worker.ts +74 -0
- package/src/url.test.ts +11 -0
- package/src/url.ts +113 -22
- package/tsdown.config.ts +12 -3
- /package/dist/tests/{langtag-LDBqlxHv.mjs → langtag-D8FWxjv8.mjs} +0 -0
- /package/dist/tests/{langtag-DgySESmk.cjs → langtag-a2-s9uyi.cjs} +0 -0
- /package/dist/tests/{link-CYszIegt.mjs → link-CHMtH2-k.mjs} +0 -0
- /package/dist/tests/{multibase-8zhYPa7o.cjs → multibase-BmWaK56H.cjs} +0 -0
- /package/dist/tests/{multibase-Ds75BvXs.mjs → multibase-D642Uv3S.mjs} +0 -0
- /package/dist/tests/{multicodec-ByS9XLsw.cjs → multicodec-B-_CSt1M.cjs} +0 -0
- /package/dist/tests/{multicodec-BBPZjRfg.mjs → multicodec-caWdG98t.mjs} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
2
|
+
const require_request = require("./request-CzYw8aEp.cjs");
|
|
3
3
|
let _logtape_logtape = require("@logtape/logtape");
|
|
4
4
|
//#region src/body.ts
|
|
5
5
|
/** Decoded JSON body limit: 16 MiB. @internal */
|
package/dist/tests/body.test.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
const require_body = require("./body-
|
|
2
|
+
const require_body = require("./body-i_FdQE3f.cjs");
|
|
3
3
|
let node_assert_strict = require("node:assert/strict");
|
|
4
4
|
let node_test = require("node:test");
|
|
5
5
|
let node_zlib = require("node:zlib");
|
package/dist/tests/body.test.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as readBoundedText, t as BodyTooLargeError } from "./body-
|
|
1
|
+
import { r as readBoundedText, t as BodyTooLargeError } from "./body-B0Z2Vegb.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,10 +1,10 @@
|
|
|
1
1
|
require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
require("./docloader-
|
|
3
|
-
require("./url-
|
|
4
|
-
require("./key-
|
|
5
|
-
require("./multibase-
|
|
6
|
-
require("./langtag-
|
|
7
|
-
require("./langstr-
|
|
2
|
+
require("./docloader-oZrKg7F3.cjs");
|
|
3
|
+
require("./url-DLuSj57U.cjs");
|
|
4
|
+
require("./key-L6ReMuUb.cjs");
|
|
5
|
+
require("./multibase-BmWaK56H.cjs");
|
|
6
|
+
require("./langtag-a2-s9uyi.cjs");
|
|
7
|
+
require("./langstr-CZpWmpo5.cjs");
|
|
8
8
|
let node_test = require("node:test");
|
|
9
9
|
let node_assert = require("node:assert");
|
|
10
10
|
//#region src/decimal.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import "./docloader-
|
|
2
|
-
import "./url-
|
|
3
|
-
import "./key-
|
|
4
|
-
import "./multibase-
|
|
5
|
-
import "./langtag-
|
|
6
|
-
import "./langstr-
|
|
1
|
+
import "./docloader-dwostFF6.mjs";
|
|
2
|
+
import "./url-DQWrMGhu.mjs";
|
|
3
|
+
import "./key-GEdpxA4M.mjs";
|
|
4
|
+
import "./multibase-D642Uv3S.mjs";
|
|
5
|
+
import "./langtag-D8FWxjv8.mjs";
|
|
6
|
+
import "./langstr-DTB4sl0a.mjs";
|
|
7
7
|
import { test } from "node:test";
|
|
8
8
|
import { deepStrictEqual, throws } from "node:assert";
|
|
9
9
|
//#region src/decimal.ts
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-
|
|
2
|
-
import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-
|
|
3
|
-
import { t as HttpHeaderLink } from "./link-
|
|
4
|
-
import {
|
|
1
|
+
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-DY2AaRpH.mjs";
|
|
2
|
+
import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-B0Z2Vegb.mjs";
|
|
3
|
+
import { t as HttpHeaderLink } from "./link-CHMtH2-k.mjs";
|
|
4
|
+
import { t as UrlError } from "./url-DQWrMGhu.mjs";
|
|
5
|
+
import { n as openDirectFetch, r as openPublicFetch } from "./public-fetch-Yi7Vks9s.mjs";
|
|
5
6
|
import { getLogger } from "@logtape/logtape";
|
|
6
7
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
7
8
|
//#region src/contexts/activitystreams.json
|
|
@@ -4591,13 +4592,47 @@ const DEFAULT_MAX_REDIRECTION = 20;
|
|
|
4591
4592
|
* Gets a {@link RemoteDocument} from the given response.
|
|
4592
4593
|
* @param url The URL of the document to load.
|
|
4593
4594
|
* @param response The response to get the document from.
|
|
4594
|
-
* @param fetch The function to fetch the document.
|
|
4595
|
+
* @param fetch The function to fetch the document. It is called with the URL
|
|
4596
|
+
* of an alternate document, if any, after the response body has
|
|
4597
|
+
* been either read or its cancellation has been started.
|
|
4595
4598
|
* @returns The loaded remote document.
|
|
4596
4599
|
* @throws {FetchError} If the response is not OK.
|
|
4597
4600
|
* @internal
|
|
4598
4601
|
*/
|
|
4599
4602
|
async function getRemoteDocument(url, response, fetch) {
|
|
4600
|
-
const
|
|
4603
|
+
const result = await parseRemoteDocument(url, response);
|
|
4604
|
+
if ("alternate" in result) return await fetch(result.alternate);
|
|
4605
|
+
return result.document;
|
|
4606
|
+
}
|
|
4607
|
+
/**
|
|
4608
|
+
* Starts cancelling the body of a response without waiting for it to settle.
|
|
4609
|
+
* The cancellation of a branch of a tee (e.g., a body cloned by a fetch mock)
|
|
4610
|
+
* settles only after the other branch is cancelled too, per the Streams
|
|
4611
|
+
* standard, so awaiting it could block forever. Failures are only logged.
|
|
4612
|
+
* @param response The response whose body is cancelled.
|
|
4613
|
+
* @param url The URL of the response, for logging.
|
|
4614
|
+
*/
|
|
4615
|
+
function cancelResponseBody(response, url) {
|
|
4616
|
+
response.body?.cancel().catch((error) => {
|
|
4617
|
+
logger.debug("Failed to cancel the response body from {url}: {error}", {
|
|
4618
|
+
url,
|
|
4619
|
+
error
|
|
4620
|
+
});
|
|
4621
|
+
});
|
|
4622
|
+
}
|
|
4623
|
+
/**
|
|
4624
|
+
* Gets a {@link RemoteDocument} from the given response, or the URL of an
|
|
4625
|
+
* alternate document to load instead. When an alternate document is found,
|
|
4626
|
+
* the response body has been either read or its cancellation has been started
|
|
4627
|
+
* (without waiting for it), so that the alternate document can be loaded after
|
|
4628
|
+
* the response's session is closed.
|
|
4629
|
+
* @param url The URL of the document to load.
|
|
4630
|
+
* @param response The response to get the document from.
|
|
4631
|
+
* @returns The loaded remote document, or the alternate document URL.
|
|
4632
|
+
* @throws {FetchError} If the response is not OK.
|
|
4633
|
+
*/
|
|
4634
|
+
async function parseRemoteDocument(url, response) {
|
|
4635
|
+
const documentUrl = url;
|
|
4601
4636
|
const docUrl = new URL(documentUrl);
|
|
4602
4637
|
if (!response.ok) {
|
|
4603
4638
|
logger.error("Failed to fetch document: {status} {url} {headers}", {
|
|
@@ -4634,7 +4669,8 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4634
4669
|
alternateUrl: altUri.href,
|
|
4635
4670
|
url: documentUrl
|
|
4636
4671
|
});
|
|
4637
|
-
|
|
4672
|
+
cancelResponseBody(response, documentUrl);
|
|
4673
|
+
return { alternate: altUri.href };
|
|
4638
4674
|
}
|
|
4639
4675
|
}
|
|
4640
4676
|
}
|
|
@@ -4659,7 +4695,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4659
4695
|
alternateUrl: attribs.href,
|
|
4660
4696
|
url: documentUrl
|
|
4661
4697
|
});
|
|
4662
|
-
return
|
|
4698
|
+
return { alternate: new URL(attribs.href, docUrl).href };
|
|
4663
4699
|
}
|
|
4664
4700
|
}
|
|
4665
4701
|
document = JSON.parse(html);
|
|
@@ -4669,11 +4705,11 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4669
4705
|
url: documentUrl,
|
|
4670
4706
|
headers: Object.fromEntries(response.headers.entries())
|
|
4671
4707
|
});
|
|
4672
|
-
return {
|
|
4708
|
+
return { document: {
|
|
4673
4709
|
contextUrl,
|
|
4674
4710
|
document,
|
|
4675
4711
|
documentUrl
|
|
4676
|
-
};
|
|
4712
|
+
} };
|
|
4677
4713
|
}
|
|
4678
4714
|
/**
|
|
4679
4715
|
* Creates a JSON-LD document loader that utilizes the browser's `fetch` API.
|
|
@@ -4699,12 +4735,58 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4699
4735
|
* @returns The document loader.
|
|
4700
4736
|
* @since 1.3.0
|
|
4701
4737
|
*/
|
|
4702
|
-
function getDocumentLoader(
|
|
4738
|
+
function getDocumentLoader(options = {}) {
|
|
4739
|
+
return createDocumentLoader(options);
|
|
4740
|
+
}
|
|
4741
|
+
/**
|
|
4742
|
+
* The implementation of {@link getDocumentLoader}, with injectable
|
|
4743
|
+
* dependencies. This is not exported from any entry point.
|
|
4744
|
+
* @param options Options for the document loader.
|
|
4745
|
+
* @param deps The dependencies.
|
|
4746
|
+
* @returns The document loader.
|
|
4747
|
+
*/
|
|
4748
|
+
function createDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAgent } = {}, deps = {}) {
|
|
4703
4749
|
const tracer = trace.getTracerProvider().getTracer(name, version);
|
|
4750
|
+
async function openHop(url, signal) {
|
|
4751
|
+
try {
|
|
4752
|
+
if (deps.openHop != null) return await deps.openHop(url);
|
|
4753
|
+
return allowPrivateAddress ? await openDirectFetch(url) : await openPublicFetch(url, { signal });
|
|
4754
|
+
} catch (error) {
|
|
4755
|
+
if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
|
|
4756
|
+
url,
|
|
4757
|
+
error
|
|
4758
|
+
});
|
|
4759
|
+
else logger.error("Disallowed private URL: {url}", {
|
|
4760
|
+
url,
|
|
4761
|
+
error
|
|
4762
|
+
});
|
|
4763
|
+
throw error;
|
|
4764
|
+
}
|
|
4765
|
+
}
|
|
4766
|
+
async function fetchHop(session, url, span, options) {
|
|
4767
|
+
try {
|
|
4768
|
+
const request = createActivityPubRequest(url, { userAgent });
|
|
4769
|
+
logRequest(logger, request);
|
|
4770
|
+
const response = await session.fetch(request, {
|
|
4771
|
+
redirect: "manual",
|
|
4772
|
+
signal: options?.signal
|
|
4773
|
+
});
|
|
4774
|
+
span.setAttribute("http.response.status_code", response.status);
|
|
4775
|
+
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
4776
|
+
const location = response.headers.get("Location");
|
|
4777
|
+
cancelResponseBody(response, url);
|
|
4778
|
+
return { location };
|
|
4779
|
+
}
|
|
4780
|
+
return await parseRemoteDocument(url, response);
|
|
4781
|
+
} finally {
|
|
4782
|
+
await session.close();
|
|
4783
|
+
}
|
|
4784
|
+
}
|
|
4704
4785
|
async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
|
|
4705
4786
|
options?.signal?.throwIfAborted();
|
|
4706
4787
|
const parsedUrl = new URL(url);
|
|
4707
4788
|
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new UrlError(`Unsupported protocol: ${parsedUrl.protocol}`);
|
|
4789
|
+
if (parsedUrl.username !== "" || parsedUrl.password !== "") throw new UrlError("URLs with credentials are not allowed");
|
|
4708
4790
|
const currentUrl = parsedUrl.href;
|
|
4709
4791
|
if (!skipPreloadedContexts && currentUrl in preloadedContexts) {
|
|
4710
4792
|
logger.debug("Using preloaded context: {url}.", { url: currentUrl });
|
|
@@ -4714,33 +4796,15 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4714
4796
|
documentUrl: currentUrl
|
|
4715
4797
|
};
|
|
4716
4798
|
}
|
|
4717
|
-
|
|
4718
|
-
await validatePublicUrl(currentUrl);
|
|
4719
|
-
} catch (error) {
|
|
4720
|
-
if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
|
|
4721
|
-
url: currentUrl,
|
|
4722
|
-
error
|
|
4723
|
-
});
|
|
4724
|
-
else logger.error("Disallowed private URL: {url}", {
|
|
4725
|
-
url: currentUrl,
|
|
4726
|
-
error
|
|
4727
|
-
});
|
|
4728
|
-
throw error;
|
|
4729
|
-
}
|
|
4799
|
+
const session = await openHop(currentUrl, options?.signal);
|
|
4730
4800
|
visited.add(currentUrl);
|
|
4731
4801
|
return await tracer.startActiveSpan("activitypub.fetch_document", {
|
|
4732
4802
|
kind: SpanKind.CLIENT,
|
|
4733
4803
|
attributes: { "url.full": currentUrl }
|
|
4734
4804
|
}, async (span) => {
|
|
4735
4805
|
try {
|
|
4736
|
-
const
|
|
4737
|
-
|
|
4738
|
-
const response = await fetch(request, {
|
|
4739
|
-
redirect: "manual",
|
|
4740
|
-
signal: options?.signal
|
|
4741
|
-
});
|
|
4742
|
-
span.setAttribute("http.response.status_code", response.status);
|
|
4743
|
-
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
4806
|
+
const outcome = await fetchHop(session, currentUrl, span, options);
|
|
4807
|
+
if ("location" in outcome) {
|
|
4744
4808
|
if (redirected >= DEFAULT_MAX_REDIRECTION) {
|
|
4745
4809
|
logger.error("Too many redirections ({redirections}) while fetching document.", {
|
|
4746
4810
|
redirections: redirected + 1,
|
|
@@ -4748,7 +4812,7 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4748
4812
|
});
|
|
4749
4813
|
throw new FetchError(currentUrl, `Too many redirections (${redirected + 1})`);
|
|
4750
4814
|
}
|
|
4751
|
-
const redirectUrl = new URL(
|
|
4815
|
+
const redirectUrl = new URL(outcome.location, currentUrl).href;
|
|
4752
4816
|
span.setAttribute("http.redirect.url", redirectUrl);
|
|
4753
4817
|
if (visited.has(redirectUrl)) {
|
|
4754
4818
|
logger.error("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
|
|
@@ -4759,12 +4823,14 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4759
4823
|
}
|
|
4760
4824
|
return await load(redirectUrl, options, redirected + 1, visited);
|
|
4761
4825
|
}
|
|
4762
|
-
|
|
4826
|
+
let result;
|
|
4827
|
+
if ("alternate" in outcome) {
|
|
4828
|
+
const alternateUrl = outcome.alternate;
|
|
4763
4829
|
options?.signal?.throwIfAborted();
|
|
4764
4830
|
if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(currentUrl, `Too many redirections (${redirected + 1})`);
|
|
4765
4831
|
if (visited.has(alternateUrl)) throw new FetchError(currentUrl, `Redirect loop detected: ${alternateUrl}`);
|
|
4766
|
-
|
|
4767
|
-
}
|
|
4832
|
+
result = await load(alternateUrl, options, redirected + 1, visited);
|
|
4833
|
+
} else result = outcome.document;
|
|
4768
4834
|
span.setAttribute("docloader.document_url", result.documentUrl);
|
|
4769
4835
|
if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
|
|
4770
4836
|
return result;
|
|
@@ -4783,4 +4849,4 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4783
4849
|
return (url, options) => load(url, options);
|
|
4784
4850
|
}
|
|
4785
4851
|
//#endregion
|
|
4786
|
-
export { cid_v1_default as i,
|
|
4852
|
+
export { cid_v1_default as a, preloadedContexts as i, getDocumentLoader as n, getRemoteDocument as r, createDocumentLoader as t };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
3
|
-
const require_body = require("./body-
|
|
2
|
+
const require_request = require("./request-CzYw8aEp.cjs");
|
|
3
|
+
const require_body = require("./body-i_FdQE3f.cjs");
|
|
4
4
|
const require_link = require("./link-qDTmjPw_.cjs");
|
|
5
|
-
const require_url = require("./url-
|
|
5
|
+
const require_url = require("./url-DLuSj57U.cjs");
|
|
6
|
+
const require_public_fetch = require("./public-fetch-Ddjfxbwc.cjs");
|
|
6
7
|
let _logtape_logtape = require("@logtape/logtape");
|
|
7
8
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
8
9
|
//#region src/contexts/activitystreams.json
|
|
@@ -4592,13 +4593,47 @@ const DEFAULT_MAX_REDIRECTION = 20;
|
|
|
4592
4593
|
* Gets a {@link RemoteDocument} from the given response.
|
|
4593
4594
|
* @param url The URL of the document to load.
|
|
4594
4595
|
* @param response The response to get the document from.
|
|
4595
|
-
* @param fetch The function to fetch the document.
|
|
4596
|
+
* @param fetch The function to fetch the document. It is called with the URL
|
|
4597
|
+
* of an alternate document, if any, after the response body has
|
|
4598
|
+
* been either read or its cancellation has been started.
|
|
4596
4599
|
* @returns The loaded remote document.
|
|
4597
4600
|
* @throws {FetchError} If the response is not OK.
|
|
4598
4601
|
* @internal
|
|
4599
4602
|
*/
|
|
4600
4603
|
async function getRemoteDocument(url, response, fetch) {
|
|
4601
|
-
const
|
|
4604
|
+
const result = await parseRemoteDocument(url, response);
|
|
4605
|
+
if ("alternate" in result) return await fetch(result.alternate);
|
|
4606
|
+
return result.document;
|
|
4607
|
+
}
|
|
4608
|
+
/**
|
|
4609
|
+
* Starts cancelling the body of a response without waiting for it to settle.
|
|
4610
|
+
* The cancellation of a branch of a tee (e.g., a body cloned by a fetch mock)
|
|
4611
|
+
* settles only after the other branch is cancelled too, per the Streams
|
|
4612
|
+
* standard, so awaiting it could block forever. Failures are only logged.
|
|
4613
|
+
* @param response The response whose body is cancelled.
|
|
4614
|
+
* @param url The URL of the response, for logging.
|
|
4615
|
+
*/
|
|
4616
|
+
function cancelResponseBody(response, url) {
|
|
4617
|
+
response.body?.cancel().catch((error) => {
|
|
4618
|
+
logger.debug("Failed to cancel the response body from {url}: {error}", {
|
|
4619
|
+
url,
|
|
4620
|
+
error
|
|
4621
|
+
});
|
|
4622
|
+
});
|
|
4623
|
+
}
|
|
4624
|
+
/**
|
|
4625
|
+
* Gets a {@link RemoteDocument} from the given response, or the URL of an
|
|
4626
|
+
* alternate document to load instead. When an alternate document is found,
|
|
4627
|
+
* the response body has been either read or its cancellation has been started
|
|
4628
|
+
* (without waiting for it), so that the alternate document can be loaded after
|
|
4629
|
+
* the response's session is closed.
|
|
4630
|
+
* @param url The URL of the document to load.
|
|
4631
|
+
* @param response The response to get the document from.
|
|
4632
|
+
* @returns The loaded remote document, or the alternate document URL.
|
|
4633
|
+
* @throws {FetchError} If the response is not OK.
|
|
4634
|
+
*/
|
|
4635
|
+
async function parseRemoteDocument(url, response) {
|
|
4636
|
+
const documentUrl = url;
|
|
4602
4637
|
const docUrl = new URL(documentUrl);
|
|
4603
4638
|
if (!response.ok) {
|
|
4604
4639
|
logger.error("Failed to fetch document: {status} {url} {headers}", {
|
|
@@ -4635,7 +4670,8 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4635
4670
|
alternateUrl: altUri.href,
|
|
4636
4671
|
url: documentUrl
|
|
4637
4672
|
});
|
|
4638
|
-
|
|
4673
|
+
cancelResponseBody(response, documentUrl);
|
|
4674
|
+
return { alternate: altUri.href };
|
|
4639
4675
|
}
|
|
4640
4676
|
}
|
|
4641
4677
|
}
|
|
@@ -4660,7 +4696,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4660
4696
|
alternateUrl: attribs.href,
|
|
4661
4697
|
url: documentUrl
|
|
4662
4698
|
});
|
|
4663
|
-
return
|
|
4699
|
+
return { alternate: new URL(attribs.href, docUrl).href };
|
|
4664
4700
|
}
|
|
4665
4701
|
}
|
|
4666
4702
|
document = JSON.parse(html);
|
|
@@ -4670,11 +4706,11 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4670
4706
|
url: documentUrl,
|
|
4671
4707
|
headers: Object.fromEntries(response.headers.entries())
|
|
4672
4708
|
});
|
|
4673
|
-
return {
|
|
4709
|
+
return { document: {
|
|
4674
4710
|
contextUrl,
|
|
4675
4711
|
document,
|
|
4676
4712
|
documentUrl
|
|
4677
|
-
};
|
|
4713
|
+
} };
|
|
4678
4714
|
}
|
|
4679
4715
|
/**
|
|
4680
4716
|
* Creates a JSON-LD document loader that utilizes the browser's `fetch` API.
|
|
@@ -4700,12 +4736,58 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4700
4736
|
* @returns The document loader.
|
|
4701
4737
|
* @since 1.3.0
|
|
4702
4738
|
*/
|
|
4703
|
-
function getDocumentLoader(
|
|
4739
|
+
function getDocumentLoader(options = {}) {
|
|
4740
|
+
return createDocumentLoader(options);
|
|
4741
|
+
}
|
|
4742
|
+
/**
|
|
4743
|
+
* The implementation of {@link getDocumentLoader}, with injectable
|
|
4744
|
+
* dependencies. This is not exported from any entry point.
|
|
4745
|
+
* @param options Options for the document loader.
|
|
4746
|
+
* @param deps The dependencies.
|
|
4747
|
+
* @returns The document loader.
|
|
4748
|
+
*/
|
|
4749
|
+
function createDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAgent } = {}, deps = {}) {
|
|
4704
4750
|
const tracer = _opentelemetry_api.trace.getTracerProvider().getTracer(require_request.name, require_request.version);
|
|
4751
|
+
async function openHop(url, signal) {
|
|
4752
|
+
try {
|
|
4753
|
+
if (deps.openHop != null) return await deps.openHop(url);
|
|
4754
|
+
return allowPrivateAddress ? await require_public_fetch.openDirectFetch(url) : await require_public_fetch.openPublicFetch(url, { signal });
|
|
4755
|
+
} catch (error) {
|
|
4756
|
+
if (error instanceof require_url.UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
|
|
4757
|
+
url,
|
|
4758
|
+
error
|
|
4759
|
+
});
|
|
4760
|
+
else logger.error("Disallowed private URL: {url}", {
|
|
4761
|
+
url,
|
|
4762
|
+
error
|
|
4763
|
+
});
|
|
4764
|
+
throw error;
|
|
4765
|
+
}
|
|
4766
|
+
}
|
|
4767
|
+
async function fetchHop(session, url, span, options) {
|
|
4768
|
+
try {
|
|
4769
|
+
const request = require_request.createActivityPubRequest(url, { userAgent });
|
|
4770
|
+
require_request.logRequest(logger, request);
|
|
4771
|
+
const response = await session.fetch(request, {
|
|
4772
|
+
redirect: "manual",
|
|
4773
|
+
signal: options?.signal
|
|
4774
|
+
});
|
|
4775
|
+
span.setAttribute("http.response.status_code", response.status);
|
|
4776
|
+
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
4777
|
+
const location = response.headers.get("Location");
|
|
4778
|
+
cancelResponseBody(response, url);
|
|
4779
|
+
return { location };
|
|
4780
|
+
}
|
|
4781
|
+
return await parseRemoteDocument(url, response);
|
|
4782
|
+
} finally {
|
|
4783
|
+
await session.close();
|
|
4784
|
+
}
|
|
4785
|
+
}
|
|
4705
4786
|
async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
|
|
4706
4787
|
options?.signal?.throwIfAborted();
|
|
4707
4788
|
const parsedUrl = new URL(url);
|
|
4708
4789
|
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new require_url.UrlError(`Unsupported protocol: ${parsedUrl.protocol}`);
|
|
4790
|
+
if (parsedUrl.username !== "" || parsedUrl.password !== "") throw new require_url.UrlError("URLs with credentials are not allowed");
|
|
4709
4791
|
const currentUrl = parsedUrl.href;
|
|
4710
4792
|
if (!skipPreloadedContexts && currentUrl in preloadedContexts) {
|
|
4711
4793
|
logger.debug("Using preloaded context: {url}.", { url: currentUrl });
|
|
@@ -4715,33 +4797,15 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4715
4797
|
documentUrl: currentUrl
|
|
4716
4798
|
};
|
|
4717
4799
|
}
|
|
4718
|
-
|
|
4719
|
-
await require_url.validatePublicUrl(currentUrl);
|
|
4720
|
-
} catch (error) {
|
|
4721
|
-
if (error instanceof require_url.UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
|
|
4722
|
-
url: currentUrl,
|
|
4723
|
-
error
|
|
4724
|
-
});
|
|
4725
|
-
else logger.error("Disallowed private URL: {url}", {
|
|
4726
|
-
url: currentUrl,
|
|
4727
|
-
error
|
|
4728
|
-
});
|
|
4729
|
-
throw error;
|
|
4730
|
-
}
|
|
4800
|
+
const session = await openHop(currentUrl, options?.signal);
|
|
4731
4801
|
visited.add(currentUrl);
|
|
4732
4802
|
return await tracer.startActiveSpan("activitypub.fetch_document", {
|
|
4733
4803
|
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
4734
4804
|
attributes: { "url.full": currentUrl }
|
|
4735
4805
|
}, async (span) => {
|
|
4736
4806
|
try {
|
|
4737
|
-
const
|
|
4738
|
-
|
|
4739
|
-
const response = await fetch(request, {
|
|
4740
|
-
redirect: "manual",
|
|
4741
|
-
signal: options?.signal
|
|
4742
|
-
});
|
|
4743
|
-
span.setAttribute("http.response.status_code", response.status);
|
|
4744
|
-
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
4807
|
+
const outcome = await fetchHop(session, currentUrl, span, options);
|
|
4808
|
+
if ("location" in outcome) {
|
|
4745
4809
|
if (redirected >= DEFAULT_MAX_REDIRECTION) {
|
|
4746
4810
|
logger.error("Too many redirections ({redirections}) while fetching document.", {
|
|
4747
4811
|
redirections: redirected + 1,
|
|
@@ -4749,7 +4813,7 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4749
4813
|
});
|
|
4750
4814
|
throw new require_request.FetchError(currentUrl, `Too many redirections (${redirected + 1})`);
|
|
4751
4815
|
}
|
|
4752
|
-
const redirectUrl = new URL(
|
|
4816
|
+
const redirectUrl = new URL(outcome.location, currentUrl).href;
|
|
4753
4817
|
span.setAttribute("http.redirect.url", redirectUrl);
|
|
4754
4818
|
if (visited.has(redirectUrl)) {
|
|
4755
4819
|
logger.error("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
|
|
@@ -4760,12 +4824,14 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4760
4824
|
}
|
|
4761
4825
|
return await load(redirectUrl, options, redirected + 1, visited);
|
|
4762
4826
|
}
|
|
4763
|
-
|
|
4827
|
+
let result;
|
|
4828
|
+
if ("alternate" in outcome) {
|
|
4829
|
+
const alternateUrl = outcome.alternate;
|
|
4764
4830
|
options?.signal?.throwIfAborted();
|
|
4765
4831
|
if (redirected >= DEFAULT_MAX_REDIRECTION) throw new require_request.FetchError(currentUrl, `Too many redirections (${redirected + 1})`);
|
|
4766
4832
|
if (visited.has(alternateUrl)) throw new require_request.FetchError(currentUrl, `Redirect loop detected: ${alternateUrl}`);
|
|
4767
|
-
|
|
4768
|
-
}
|
|
4833
|
+
result = await load(alternateUrl, options, redirected + 1, visited);
|
|
4834
|
+
} else result = outcome.document;
|
|
4769
4835
|
span.setAttribute("docloader.document_url", result.documentUrl);
|
|
4770
4836
|
if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
|
|
4771
4837
|
return result;
|
|
@@ -4790,6 +4856,12 @@ Object.defineProperty(exports, "cid_v1_default", {
|
|
|
4790
4856
|
return cid_v1_default;
|
|
4791
4857
|
}
|
|
4792
4858
|
});
|
|
4859
|
+
Object.defineProperty(exports, "createDocumentLoader", {
|
|
4860
|
+
enumerable: true,
|
|
4861
|
+
get: function() {
|
|
4862
|
+
return createDocumentLoader;
|
|
4863
|
+
}
|
|
4864
|
+
});
|
|
4793
4865
|
Object.defineProperty(exports, "getDocumentLoader", {
|
|
4794
4866
|
enumerable: true,
|
|
4795
4867
|
get: function() {
|