@fedify/vocab-runtime 2.1.23 → 2.1.25
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 +1 -1
- package/dist/mod.cjs +220 -107
- package/dist/mod.d.cts +10 -0
- package/dist/mod.d.ts +10 -0
- package/dist/mod.js +220 -108
- package/dist/tests/body-D-gC5vdl.cjs +95 -0
- package/dist/tests/body-DBqFojnW.mjs +77 -0
- package/dist/tests/body.test.cjs +90 -0
- package/dist/tests/body.test.d.cts +1 -0
- package/dist/tests/body.test.d.mts +1 -0
- package/dist/tests/body.test.mjs +90 -0
- package/dist/tests/decimal.test.cjs +6 -6
- package/dist/tests/decimal.test.mjs +6 -6
- package/dist/tests/{docloader-D-CBVlrJ.mjs → docloader-Beoc8qTH.mjs} +66 -37
- package/dist/tests/{docloader-BcWmxXdo.cjs → docloader-fn4ICzFS.cjs} +71 -36
- package/dist/tests/docloader.test.cjs +321 -4
- package/dist/tests/docloader.test.mjs +320 -4
- package/dist/tests/internal/multicodec.test.cjs +2 -2
- package/dist/tests/internal/multicodec.test.mjs +2 -2
- package/dist/tests/{key-BeTHFQJK.mjs → key-BDIsC6hV.mjs} +2 -2
- package/dist/tests/{key-DTTIntwb.cjs → key-BarKGLQz.cjs} +2 -2
- package/dist/tests/key.test.cjs +3 -3
- package/dist/tests/key.test.mjs +3 -3
- package/dist/tests/langstr.test.cjs +2 -2
- package/dist/tests/langstr.test.mjs +2 -2
- package/dist/tests/link.test.cjs +2 -2
- package/dist/tests/link.test.mjs +2 -2
- package/dist/tests/multibase/multibase.test.cjs +2 -2
- package/dist/tests/multibase/multibase.test.mjs +2 -2
- package/dist/tests/{request-CdMLb0ba.cjs → request-DrO5xzev.cjs} +1 -1
- package/dist/tests/{request-DqsgdBUH.mjs → request-DxeGyJVh.mjs} +1 -1
- package/dist/tests/request.test.cjs +2 -2
- package/dist/tests/request.test.mjs +2 -2
- package/dist/tests/temporal.test.cjs +1 -1
- package/dist/tests/temporal.test.mjs +1 -1
- package/dist/tests/{url-o0e-aXQY.mjs → url-3fyJuqC0.mjs} +14 -4
- package/dist/tests/{url-CWU5HT3Y.cjs → url-vZTgkIZg.cjs} +15 -4
- package/dist/tests/url.test.cjs +37 -4
- package/dist/tests/url.test.mjs +37 -4
- package/package.json +1 -1
- package/src/body.test.ts +125 -0
- package/src/body.ts +95 -0
- package/src/contexts/fep-7aa9.json +24 -0
- package/src/contexts.ts +8 -0
- package/src/docloader.test.ts +431 -1
- package/src/docloader.ts +76 -49
- package/src/url.test.ts +29 -3
- package/src/url.ts +21 -5
- /package/dist/tests/{langstr-CbAxaeEZ.cjs → langstr-BOQHfJDr.cjs} +0 -0
- /package/dist/tests/{langstr-Di5AvKpB.mjs → langstr-DDLc4833.mjs} +0 -0
- /package/dist/tests/{link-NUUWCdnK.mjs → link-CYszIegt.mjs} +0 -0
- /package/dist/tests/{link-FguCydMA.cjs → link-qDTmjPw_.cjs} +0 -0
- /package/dist/tests/{multibase-F7LtMMsK.cjs → multibase-8zhYPa7o.cjs} +0 -0
- /package/dist/tests/{multibase-BgU9XRf7.mjs → multibase-Ds75BvXs.mjs} +0 -0
- /package/dist/tests/{multicodec-CyFp54fI.mjs → multicodec-BBPZjRfg.mjs} +0 -0
- /package/dist/tests/{multicodec-CxGVGa91.cjs → multicodec-ByS9XLsw.cjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { r as readBoundedText, t as BodyTooLargeError } from "./body-DBqFojnW.mjs";
|
|
2
|
+
import { deepStrictEqual, ok, rejects } from "node:assert/strict";
|
|
3
|
+
import { test } from "node:test";
|
|
4
|
+
import { gunzipSync, gzipSync } from "node:zlib";
|
|
5
|
+
//#region src/body.test.ts
|
|
6
|
+
const url = "https://example.com/document";
|
|
7
|
+
test("readBoundedText handles empty bodies and flushes incomplete UTF-8", async () => {
|
|
8
|
+
deepStrictEqual(await readBoundedText(new Response(null), 1, url), "");
|
|
9
|
+
deepStrictEqual(await readBoundedText(new Response(""), 1, url), "");
|
|
10
|
+
deepStrictEqual(await readBoundedText(new Response(new Uint8Array([226, 130])), 2, url), "�");
|
|
11
|
+
});
|
|
12
|
+
test("readBoundedText counts bytes and preserves split UTF-8", async () => {
|
|
13
|
+
const bytes = new TextEncoder().encode("\"안녕\"");
|
|
14
|
+
const stream = new ReadableStream({ start(controller) {
|
|
15
|
+
for (const byte of bytes) controller.enqueue(new Uint8Array([byte]));
|
|
16
|
+
controller.close();
|
|
17
|
+
} });
|
|
18
|
+
deepStrictEqual(await readBoundedText(new Response(stream), bytes.length, url), "\"안녕\"");
|
|
19
|
+
await rejects(readBoundedText(new Response(bytes), bytes.length - 1, url), BodyTooLargeError);
|
|
20
|
+
});
|
|
21
|
+
test("readBoundedText rejects a declared oversized body without pulling", async () => {
|
|
22
|
+
let pulled = false;
|
|
23
|
+
let canceled = false;
|
|
24
|
+
const response = new Response(new ReadableStream({
|
|
25
|
+
pull() {
|
|
26
|
+
pulled = true;
|
|
27
|
+
},
|
|
28
|
+
cancel() {
|
|
29
|
+
canceled = true;
|
|
30
|
+
}
|
|
31
|
+
}, { highWaterMark: 0 }), { headers: { "Content-Length": "100" } });
|
|
32
|
+
await rejects(readBoundedText(response, 10, url), BodyTooLargeError);
|
|
33
|
+
deepStrictEqual(pulled, false);
|
|
34
|
+
deepStrictEqual(canceled, true);
|
|
35
|
+
deepStrictEqual(response.body?.locked, false);
|
|
36
|
+
});
|
|
37
|
+
test("readBoundedText cancels chunked bodies despite absent or false lengths", async () => {
|
|
38
|
+
for (const length of [
|
|
39
|
+
void 0,
|
|
40
|
+
"1",
|
|
41
|
+
"invalid"
|
|
42
|
+
]) {
|
|
43
|
+
let pulls = 0;
|
|
44
|
+
let canceled = false;
|
|
45
|
+
const stream = new ReadableStream({
|
|
46
|
+
pull(controller) {
|
|
47
|
+
pulls++;
|
|
48
|
+
controller.enqueue(new Uint8Array(4));
|
|
49
|
+
},
|
|
50
|
+
cancel() {
|
|
51
|
+
canceled = true;
|
|
52
|
+
}
|
|
53
|
+
}, { highWaterMark: 0 });
|
|
54
|
+
const response = new Response(stream, { headers: length == null ? {} : { "Content-Length": length } });
|
|
55
|
+
await rejects(readBoundedText(response, 8, url), BodyTooLargeError);
|
|
56
|
+
deepStrictEqual(pulls, 3);
|
|
57
|
+
deepStrictEqual(canceled, true);
|
|
58
|
+
deepStrictEqual(response.body?.locked, false);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
test("readBoundedText limits decoded gzip bytes, not the compressed length", async () => {
|
|
62
|
+
const compressed = gzipSync("\"" + "a".repeat(4096) + "\"");
|
|
63
|
+
ok(compressed.length < 128);
|
|
64
|
+
const decoded = gunzipSync(compressed);
|
|
65
|
+
await rejects(readBoundedText(new Response(decoded, { headers: {
|
|
66
|
+
"Content-Encoding": "gzip",
|
|
67
|
+
"Content-Length": String(compressed.length)
|
|
68
|
+
} }), 128, url), BodyTooLargeError);
|
|
69
|
+
deepStrictEqual(await readBoundedText(new Response("{}", { headers: {
|
|
70
|
+
"Content-Encoding": "gzip",
|
|
71
|
+
"Content-Length": "22"
|
|
72
|
+
} }), 2, url), "{}");
|
|
73
|
+
});
|
|
74
|
+
test("readBoundedText rejects invalid limits and releases failed streams", async () => {
|
|
75
|
+
for (const limit of [
|
|
76
|
+
0,
|
|
77
|
+
-1,
|
|
78
|
+
NaN,
|
|
79
|
+
Infinity,
|
|
80
|
+
1.5
|
|
81
|
+
]) await rejects(readBoundedText(new Response("{}"), limit, url), RangeError);
|
|
82
|
+
const failure = /* @__PURE__ */ new Error("broken stream");
|
|
83
|
+
const response = new Response(new ReadableStream({ pull(controller) {
|
|
84
|
+
controller.error(failure);
|
|
85
|
+
} }));
|
|
86
|
+
await rejects(readBoundedText(response, 10, url), (error) => error === failure);
|
|
87
|
+
deepStrictEqual(response.body?.locked, false);
|
|
88
|
+
});
|
|
89
|
+
//#endregion
|
|
90
|
+
export {};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
require("./docloader-
|
|
3
|
-
require("./url-
|
|
4
|
-
require("./key-
|
|
5
|
-
require("./multibase-
|
|
6
|
-
require("./langstr-
|
|
7
|
-
let node_assert = require("node:assert");
|
|
2
|
+
require("./docloader-fn4ICzFS.cjs");
|
|
3
|
+
require("./url-vZTgkIZg.cjs");
|
|
4
|
+
require("./key-BarKGLQz.cjs");
|
|
5
|
+
require("./multibase-8zhYPa7o.cjs");
|
|
6
|
+
require("./langstr-BOQHfJDr.cjs");
|
|
8
7
|
let node_test = require("node:test");
|
|
8
|
+
let node_assert = require("node:assert");
|
|
9
9
|
//#region src/decimal.ts
|
|
10
10
|
const DECIMAL_PATTERN = /^(\+|-)?([0-9]+(\.[0-9]*)?|\.[0-9]+)$/;
|
|
11
11
|
const XML_SCHEMA_WHITESPACE_PATTERN = /[\t\n\r ]+/g;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import "./docloader-
|
|
2
|
-
import "./url-
|
|
3
|
-
import "./key-
|
|
4
|
-
import "./multibase-
|
|
5
|
-
import "./langstr-
|
|
6
|
-
import { deepStrictEqual, throws } from "node:assert";
|
|
1
|
+
import "./docloader-Beoc8qTH.mjs";
|
|
2
|
+
import "./url-3fyJuqC0.mjs";
|
|
3
|
+
import "./key-BDIsC6hV.mjs";
|
|
4
|
+
import "./multibase-Ds75BvXs.mjs";
|
|
5
|
+
import "./langstr-DDLc4833.mjs";
|
|
7
6
|
import { test } from "node:test";
|
|
7
|
+
import { deepStrictEqual, throws } from "node:assert";
|
|
8
8
|
//#region src/decimal.ts
|
|
9
9
|
const DECIMAL_PATTERN = /^(\+|-)?([0-9]+(\.[0-9]*)?|\.[0-9]+)$/;
|
|
10
10
|
const XML_SCHEMA_WHITESPACE_PATTERN = /[\t\n\r ]+/g;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-DxeGyJVh.mjs";
|
|
2
|
+
import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-DBqFojnW.mjs";
|
|
3
|
+
import { t as HttpHeaderLink } from "./link-CYszIegt.mjs";
|
|
4
|
+
import { o as validatePublicUrl, t as UrlError } from "./url-3fyJuqC0.mjs";
|
|
4
5
|
import { getLogger } from "@logtape/logtape";
|
|
5
6
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
6
7
|
//#region src/contexts/activitystreams.json
|
|
@@ -588,6 +589,30 @@ var fep_5711_default = { "@context": {
|
|
|
588
589
|
}
|
|
589
590
|
} };
|
|
590
591
|
//#endregion
|
|
592
|
+
//#region src/contexts/fep-7aa9.json
|
|
593
|
+
var fep_7aa9_default = { "@context": {
|
|
594
|
+
"FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
|
|
595
|
+
"FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
|
|
596
|
+
"FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
|
|
597
|
+
"FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
|
|
598
|
+
"topic": {
|
|
599
|
+
"@id": "https://w3id.org/fep/7aa9#topic",
|
|
600
|
+
"@type": "@id"
|
|
601
|
+
},
|
|
602
|
+
"featuredObject": {
|
|
603
|
+
"@id": "https://w3id.org/fep/7aa9#featuredObject",
|
|
604
|
+
"@type": "@id"
|
|
605
|
+
},
|
|
606
|
+
"canFeature": {
|
|
607
|
+
"@id": "https://w3id.org/fep/7aa9#canFeature",
|
|
608
|
+
"@type": "@id"
|
|
609
|
+
},
|
|
610
|
+
"featureAuthorization": {
|
|
611
|
+
"@id": "https://w3id.org/fep/7aa9#featureAuthorization",
|
|
612
|
+
"@type": "@id"
|
|
613
|
+
}
|
|
614
|
+
} };
|
|
615
|
+
//#endregion
|
|
591
616
|
//#region src/contexts/fep-ef61.json
|
|
592
617
|
var fep_ef61_default = { "@context": {
|
|
593
618
|
"gateways": {
|
|
@@ -4505,6 +4530,7 @@ const preloadedContexts = {
|
|
|
4505
4530
|
"https://w3id.org/fep/5711": fep_5711_default,
|
|
4506
4531
|
"https://www.w3.org/ns/cid/v1": cid_v1_default,
|
|
4507
4532
|
"https://w3id.org/fep/ef61": fep_ef61_default,
|
|
4533
|
+
"https://w3id.org/fep/7aa9": fep_7aa9_default,
|
|
4508
4534
|
"https://join-lemmy.org/context.json": join_lemmy_default,
|
|
4509
4535
|
"http://joinmastodon.org/ns": joinmastodon_default,
|
|
4510
4536
|
"https://purl.archive.org/miscellany": miscellany_default
|
|
@@ -4571,38 +4597,29 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4571
4597
|
}
|
|
4572
4598
|
let document;
|
|
4573
4599
|
if (!jsonLd && (contentType === "text/html" || contentType?.startsWith("text/html;") || contentType === "application/xhtml+xml" || contentType?.startsWith("application/xhtml+xml;"))) {
|
|
4574
|
-
const
|
|
4575
|
-
const
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
attribs[key] = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
|
|
4594
|
-
}
|
|
4595
|
-
if (attribs.rel === "alternate" && "type" in attribs && (attribs.type === "application/activity+json" || attribs.type === "application/ld+json" || attribs.type.startsWith("application/ld+json;")) && "href" in attribs && new URL(attribs.href, docUrl).href !== docUrl.href) {
|
|
4596
|
-
logger.debug("Found alternate document: {alternateUrl} from {url}", {
|
|
4597
|
-
alternateUrl: attribs.href,
|
|
4598
|
-
url: documentUrl
|
|
4599
|
-
});
|
|
4600
|
-
return await fetch(new URL(attribs.href, docUrl).href);
|
|
4601
|
-
}
|
|
4600
|
+
const html = await readBoundedText(response, 1024 * 1024, documentUrl);
|
|
4601
|
+
const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
|
|
4602
|
+
const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
|
|
4603
|
+
let tagMatch;
|
|
4604
|
+
while ((tagMatch = tagPattern.exec(html)) !== null) {
|
|
4605
|
+
const tagContent = tagMatch[2];
|
|
4606
|
+
let attrMatch;
|
|
4607
|
+
const attribs = {};
|
|
4608
|
+
attrPattern.lastIndex = 0;
|
|
4609
|
+
while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
|
|
4610
|
+
const key = attrMatch[1].toLowerCase();
|
|
4611
|
+
attribs[key] = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
|
|
4612
|
+
}
|
|
4613
|
+
if (attribs.rel === "alternate" && "type" in attribs && (attribs.type === "application/activity+json" || attribs.type === "application/ld+json" || attribs.type.startsWith("application/ld+json;")) && "href" in attribs && new URL(attribs.href, docUrl).href !== docUrl.href) {
|
|
4614
|
+
logger.debug("Found alternate document: {alternateUrl} from {url}", {
|
|
4615
|
+
alternateUrl: attribs.href,
|
|
4616
|
+
url: documentUrl
|
|
4617
|
+
});
|
|
4618
|
+
return await fetch(new URL(attribs.href, docUrl).href);
|
|
4602
4619
|
}
|
|
4603
|
-
document = JSON.parse(html);
|
|
4604
4620
|
}
|
|
4605
|
-
|
|
4621
|
+
document = JSON.parse(html);
|
|
4622
|
+
} else document = JSON.parse(await readBoundedText(response, MAX_BODY_SIZE, documentUrl));
|
|
4606
4623
|
logger.debug("Fetched document: {status} {url} {headers}", {
|
|
4607
4624
|
status: response.status,
|
|
4608
4625
|
url: documentUrl,
|
|
@@ -4616,6 +4633,8 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4616
4633
|
}
|
|
4617
4634
|
/**
|
|
4618
4635
|
* Creates a JSON-LD document loader that utilizes the browser's `fetch` API.
|
|
4636
|
+
* At most 20 HTTP redirects and alternate document links are followed in total
|
|
4637
|
+
* per call. Revisiting a URL within that chain throws a {@link FetchError}.
|
|
4619
4638
|
*
|
|
4620
4639
|
* The created loader preloads the below frequently used contexts by default
|
|
4621
4640
|
* (unless `options.skipPreloadedContexts` is set to `true`):
|
|
@@ -4627,6 +4646,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4627
4646
|
* - <https://www.w3.org/ns/cid/v1>
|
|
4628
4647
|
* - <https://w3id.org/security/multikey/v1>
|
|
4629
4648
|
* - <https://w3id.org/fep/ef61>
|
|
4649
|
+
* - <https://w3id.org/fep/7aa9>
|
|
4630
4650
|
* - <https://purl.archive.org/socialweb/webfinger>
|
|
4631
4651
|
* - <http://schema.org/>
|
|
4632
4652
|
* @param options Options for the document loader.
|
|
@@ -4649,7 +4669,11 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4649
4669
|
if (!allowPrivateAddress) try {
|
|
4650
4670
|
await validatePublicUrl(currentUrl);
|
|
4651
4671
|
} catch (error) {
|
|
4652
|
-
if (error instanceof UrlError) logger.
|
|
4672
|
+
if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
|
|
4673
|
+
url: currentUrl,
|
|
4674
|
+
error
|
|
4675
|
+
});
|
|
4676
|
+
else logger.error("Disallowed private URL: {url}", {
|
|
4653
4677
|
url: currentUrl,
|
|
4654
4678
|
error
|
|
4655
4679
|
});
|
|
@@ -4687,7 +4711,12 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4687
4711
|
}
|
|
4688
4712
|
return await load(redirectUrl, options, redirected + 1, visited);
|
|
4689
4713
|
}
|
|
4690
|
-
const result = await getRemoteDocument(currentUrl, response,
|
|
4714
|
+
const result = await getRemoteDocument(currentUrl, response, async (alternateUrl) => {
|
|
4715
|
+
options?.signal?.throwIfAborted();
|
|
4716
|
+
if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(currentUrl, `Too many redirections (${redirected + 1})`);
|
|
4717
|
+
if (visited.has(alternateUrl)) throw new FetchError(currentUrl, `Redirect loop detected: ${alternateUrl}`);
|
|
4718
|
+
return await load(alternateUrl, options, redirected + 1, visited);
|
|
4719
|
+
});
|
|
4691
4720
|
span.setAttribute("docloader.document_url", result.documentUrl);
|
|
4692
4721
|
if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
|
|
4693
4722
|
return result;
|
|
@@ -4703,7 +4732,7 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4703
4732
|
}
|
|
4704
4733
|
});
|
|
4705
4734
|
}
|
|
4706
|
-
return load;
|
|
4735
|
+
return (url, options) => load(url, options);
|
|
4707
4736
|
}
|
|
4708
4737
|
//#endregion
|
|
4709
|
-
export {
|
|
4738
|
+
export { cid_v1_default as i, getRemoteDocument as n, preloadedContexts as r, getDocumentLoader as t };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
2
|
+
const require_request = require("./request-DrO5xzev.cjs");
|
|
3
|
+
const require_body = require("./body-D-gC5vdl.cjs");
|
|
4
|
+
const require_link = require("./link-qDTmjPw_.cjs");
|
|
5
|
+
const require_url = require("./url-vZTgkIZg.cjs");
|
|
5
6
|
let _logtape_logtape = require("@logtape/logtape");
|
|
6
7
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
7
8
|
//#region src/contexts/activitystreams.json
|
|
@@ -589,6 +590,30 @@ var fep_5711_default = { "@context": {
|
|
|
589
590
|
}
|
|
590
591
|
} };
|
|
591
592
|
//#endregion
|
|
593
|
+
//#region src/contexts/fep-7aa9.json
|
|
594
|
+
var fep_7aa9_default = { "@context": {
|
|
595
|
+
"FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
|
|
596
|
+
"FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
|
|
597
|
+
"FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
|
|
598
|
+
"FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
|
|
599
|
+
"topic": {
|
|
600
|
+
"@id": "https://w3id.org/fep/7aa9#topic",
|
|
601
|
+
"@type": "@id"
|
|
602
|
+
},
|
|
603
|
+
"featuredObject": {
|
|
604
|
+
"@id": "https://w3id.org/fep/7aa9#featuredObject",
|
|
605
|
+
"@type": "@id"
|
|
606
|
+
},
|
|
607
|
+
"canFeature": {
|
|
608
|
+
"@id": "https://w3id.org/fep/7aa9#canFeature",
|
|
609
|
+
"@type": "@id"
|
|
610
|
+
},
|
|
611
|
+
"featureAuthorization": {
|
|
612
|
+
"@id": "https://w3id.org/fep/7aa9#featureAuthorization",
|
|
613
|
+
"@type": "@id"
|
|
614
|
+
}
|
|
615
|
+
} };
|
|
616
|
+
//#endregion
|
|
592
617
|
//#region src/contexts/fep-ef61.json
|
|
593
618
|
var fep_ef61_default = { "@context": {
|
|
594
619
|
"gateways": {
|
|
@@ -4506,6 +4531,7 @@ const preloadedContexts = {
|
|
|
4506
4531
|
"https://w3id.org/fep/5711": fep_5711_default,
|
|
4507
4532
|
"https://www.w3.org/ns/cid/v1": cid_v1_default,
|
|
4508
4533
|
"https://w3id.org/fep/ef61": fep_ef61_default,
|
|
4534
|
+
"https://w3id.org/fep/7aa9": fep_7aa9_default,
|
|
4509
4535
|
"https://join-lemmy.org/context.json": join_lemmy_default,
|
|
4510
4536
|
"http://joinmastodon.org/ns": joinmastodon_default,
|
|
4511
4537
|
"https://purl.archive.org/miscellany": miscellany_default
|
|
@@ -4572,38 +4598,29 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4572
4598
|
}
|
|
4573
4599
|
let document;
|
|
4574
4600
|
if (!jsonLd && (contentType === "text/html" || contentType?.startsWith("text/html;") || contentType === "application/xhtml+xml" || contentType?.startsWith("application/xhtml+xml;"))) {
|
|
4575
|
-
const
|
|
4576
|
-
const
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
attribs[key] = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
|
|
4595
|
-
}
|
|
4596
|
-
if (attribs.rel === "alternate" && "type" in attribs && (attribs.type === "application/activity+json" || attribs.type === "application/ld+json" || attribs.type.startsWith("application/ld+json;")) && "href" in attribs && new URL(attribs.href, docUrl).href !== docUrl.href) {
|
|
4597
|
-
logger.debug("Found alternate document: {alternateUrl} from {url}", {
|
|
4598
|
-
alternateUrl: attribs.href,
|
|
4599
|
-
url: documentUrl
|
|
4600
|
-
});
|
|
4601
|
-
return await fetch(new URL(attribs.href, docUrl).href);
|
|
4602
|
-
}
|
|
4601
|
+
const html = await require_body.readBoundedText(response, 1024 * 1024, documentUrl);
|
|
4602
|
+
const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
|
|
4603
|
+
const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
|
|
4604
|
+
let tagMatch;
|
|
4605
|
+
while ((tagMatch = tagPattern.exec(html)) !== null) {
|
|
4606
|
+
const tagContent = tagMatch[2];
|
|
4607
|
+
let attrMatch;
|
|
4608
|
+
const attribs = {};
|
|
4609
|
+
attrPattern.lastIndex = 0;
|
|
4610
|
+
while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
|
|
4611
|
+
const key = attrMatch[1].toLowerCase();
|
|
4612
|
+
attribs[key] = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
|
|
4613
|
+
}
|
|
4614
|
+
if (attribs.rel === "alternate" && "type" in attribs && (attribs.type === "application/activity+json" || attribs.type === "application/ld+json" || attribs.type.startsWith("application/ld+json;")) && "href" in attribs && new URL(attribs.href, docUrl).href !== docUrl.href) {
|
|
4615
|
+
logger.debug("Found alternate document: {alternateUrl} from {url}", {
|
|
4616
|
+
alternateUrl: attribs.href,
|
|
4617
|
+
url: documentUrl
|
|
4618
|
+
});
|
|
4619
|
+
return await fetch(new URL(attribs.href, docUrl).href);
|
|
4603
4620
|
}
|
|
4604
|
-
document = JSON.parse(html);
|
|
4605
4621
|
}
|
|
4606
|
-
|
|
4622
|
+
document = JSON.parse(html);
|
|
4623
|
+
} else document = JSON.parse(await require_body.readBoundedText(response, require_body.MAX_BODY_SIZE, documentUrl));
|
|
4607
4624
|
logger.debug("Fetched document: {status} {url} {headers}", {
|
|
4608
4625
|
status: response.status,
|
|
4609
4626
|
url: documentUrl,
|
|
@@ -4617,6 +4634,8 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4617
4634
|
}
|
|
4618
4635
|
/**
|
|
4619
4636
|
* Creates a JSON-LD document loader that utilizes the browser's `fetch` API.
|
|
4637
|
+
* At most 20 HTTP redirects and alternate document links are followed in total
|
|
4638
|
+
* per call. Revisiting a URL within that chain throws a {@link FetchError}.
|
|
4620
4639
|
*
|
|
4621
4640
|
* The created loader preloads the below frequently used contexts by default
|
|
4622
4641
|
* (unless `options.skipPreloadedContexts` is set to `true`):
|
|
@@ -4628,6 +4647,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
4628
4647
|
* - <https://www.w3.org/ns/cid/v1>
|
|
4629
4648
|
* - <https://w3id.org/security/multikey/v1>
|
|
4630
4649
|
* - <https://w3id.org/fep/ef61>
|
|
4650
|
+
* - <https://w3id.org/fep/7aa9>
|
|
4631
4651
|
* - <https://purl.archive.org/socialweb/webfinger>
|
|
4632
4652
|
* - <http://schema.org/>
|
|
4633
4653
|
* @param options Options for the document loader.
|
|
@@ -4650,7 +4670,11 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4650
4670
|
if (!allowPrivateAddress) try {
|
|
4651
4671
|
await require_url.validatePublicUrl(currentUrl);
|
|
4652
4672
|
} catch (error) {
|
|
4653
|
-
if (error instanceof require_url.UrlError) logger.
|
|
4673
|
+
if (error instanceof require_url.UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
|
|
4674
|
+
url: currentUrl,
|
|
4675
|
+
error
|
|
4676
|
+
});
|
|
4677
|
+
else logger.error("Disallowed private URL: {url}", {
|
|
4654
4678
|
url: currentUrl,
|
|
4655
4679
|
error
|
|
4656
4680
|
});
|
|
@@ -4688,7 +4712,12 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4688
4712
|
}
|
|
4689
4713
|
return await load(redirectUrl, options, redirected + 1, visited);
|
|
4690
4714
|
}
|
|
4691
|
-
const result = await getRemoteDocument(currentUrl, response,
|
|
4715
|
+
const result = await getRemoteDocument(currentUrl, response, async (alternateUrl) => {
|
|
4716
|
+
options?.signal?.throwIfAborted();
|
|
4717
|
+
if (redirected >= DEFAULT_MAX_REDIRECTION) throw new require_request.FetchError(currentUrl, `Too many redirections (${redirected + 1})`);
|
|
4718
|
+
if (visited.has(alternateUrl)) throw new require_request.FetchError(currentUrl, `Redirect loop detected: ${alternateUrl}`);
|
|
4719
|
+
return await load(alternateUrl, options, redirected + 1, visited);
|
|
4720
|
+
});
|
|
4692
4721
|
span.setAttribute("docloader.document_url", result.documentUrl);
|
|
4693
4722
|
if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
|
|
4694
4723
|
return result;
|
|
@@ -4704,7 +4733,7 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
|
|
|
4704
4733
|
}
|
|
4705
4734
|
});
|
|
4706
4735
|
}
|
|
4707
|
-
return load;
|
|
4736
|
+
return (url, options) => load(url, options);
|
|
4708
4737
|
}
|
|
4709
4738
|
//#endregion
|
|
4710
4739
|
Object.defineProperty(exports, "cid_v1_default", {
|
|
@@ -4719,6 +4748,12 @@ Object.defineProperty(exports, "getDocumentLoader", {
|
|
|
4719
4748
|
return getDocumentLoader;
|
|
4720
4749
|
}
|
|
4721
4750
|
});
|
|
4751
|
+
Object.defineProperty(exports, "getRemoteDocument", {
|
|
4752
|
+
enumerable: true,
|
|
4753
|
+
get: function() {
|
|
4754
|
+
return getRemoteDocument;
|
|
4755
|
+
}
|
|
4756
|
+
});
|
|
4722
4757
|
Object.defineProperty(exports, "preloadedContexts", {
|
|
4723
4758
|
enumerable: true,
|
|
4724
4759
|
get: function() {
|