@fedify/vocab-runtime 2.4.0-dev.1567 → 2.4.0-dev.1570

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 (48) hide show
  1. package/deno.json +1 -2
  2. package/dist/mod.cjs +190 -178
  3. package/dist/mod.d.cts +190 -59
  4. package/dist/mod.d.ts +190 -59
  5. package/dist/mod.js +184 -165
  6. package/dist/tests/decimal.test.cjs +3 -3
  7. package/dist/tests/decimal.test.mjs +3 -3
  8. package/dist/tests/{docloader-D61oV0K1.mjs → docloader-C76ldE5C.mjs} +10 -97
  9. package/dist/tests/{docloader-BcaQHb0Q.cjs → docloader-mvgIWKI7.cjs} +9 -102
  10. package/dist/tests/docloader.test.cjs +6 -58
  11. package/dist/tests/docloader.test.mjs +6 -58
  12. package/dist/tests/{key-CDGDH_vC.mjs → key-CrrK9mYh.mjs} +1 -69
  13. package/dist/tests/{key-_wXwomh_.cjs → key-pMmqUKuo.cjs} +0 -86
  14. package/dist/tests/key.test.cjs +1 -48
  15. package/dist/tests/key.test.mjs +1 -48
  16. package/dist/tests/{request-Cn0vP7Hj.mjs → request-BEXkv1ul.mjs} +1 -1
  17. package/dist/tests/{request-DnNWah97.cjs → request-SworbvLc.cjs} +1 -1
  18. package/dist/tests/request.test.cjs +1 -1
  19. package/dist/tests/request.test.mjs +1 -1
  20. package/dist/tests/{url-2XwVbUS_.cjs → url-C20FhC7p.cjs} +0 -108
  21. package/dist/tests/{url-YWJbnRlf.mjs → url-m9Qzxy-Y.mjs} +1 -85
  22. package/dist/tests/url.test.cjs +1 -104
  23. package/dist/tests/url.test.mjs +2 -105
  24. package/package.json +1 -11
  25. package/src/contexts.ts +0 -2
  26. package/src/docloader.test.ts +6 -102
  27. package/src/docloader.ts +8 -76
  28. package/src/key.test.ts +0 -86
  29. package/src/key.ts +0 -125
  30. package/src/mod.ts +0 -8
  31. package/src/url.test.ts +1 -252
  32. package/src/url.ts +0 -141
  33. package/tsdown.config.ts +1 -6
  34. package/dist/docloader-DnUMWHaJ.d.cts +0 -202
  35. package/dist/docloader-xRGn1azD.d.ts +0 -202
  36. package/dist/internal/jsonld-cache.cjs +0 -279
  37. package/dist/internal/jsonld-cache.d.cts +0 -48
  38. package/dist/internal/jsonld-cache.d.ts +0 -48
  39. package/dist/internal/jsonld-cache.js +0 -275
  40. package/dist/tests/jsonld-cache.test.cjs +0 -652
  41. package/dist/tests/jsonld-cache.test.d.cts +0 -1
  42. package/dist/tests/jsonld-cache.test.d.mts +0 -1
  43. package/dist/tests/jsonld-cache.test.mjs +0 -651
  44. package/dist/url-BAdyyqAa.cjs +0 -315
  45. package/dist/url-BuxPHxK2.js +0 -261
  46. package/src/contexts/fep-7aa9.json +0 -24
  47. package/src/internal/jsonld-cache.ts +0 -538
  48. package/src/jsonld-cache.test.ts +0 -554
package/dist/mod.js CHANGED
@@ -1,8 +1,9 @@
1
1
 
2
- import { a as isValidPublicIPv4Address, c as parseJsonLdId, i as haveSameIriOrigin, l as validatePublicUrl, n as expandIPv6Address, o as isValidPublicIPv6Address, r as formatIri, s as parseIri, t as UrlError } from "./url-BuxPHxK2.js";
3
2
  import { getLogger } from "@logtape/logtape";
4
3
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
5
4
  import process from "node:process";
5
+ import { lookup } from "node:dns/promises";
6
+ import { isIP } from "node:net";
6
7
  import { Integer, Sequence } from "asn1js";
7
8
  import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
8
9
  import { decodeBase64Url } from "byte-encodings/base64url";
@@ -4283,28 +4284,6 @@ const preloadedContexts = {
4283
4284
  "@type": "@id"
4284
4285
  }
4285
4286
  } },
4286
- "https://w3id.org/fep/7aa9": { "@context": {
4287
- "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
4288
- "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
4289
- "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
4290
- "FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
4291
- "topic": {
4292
- "@id": "https://w3id.org/fep/7aa9#topic",
4293
- "@type": "@id"
4294
- },
4295
- "featuredObject": {
4296
- "@id": "https://w3id.org/fep/7aa9#featuredObject",
4297
- "@type": "@id"
4298
- },
4299
- "canFeature": {
4300
- "@id": "https://w3id.org/fep/7aa9#canFeature",
4301
- "@type": "@id"
4302
- },
4303
- "featureAuthorization": {
4304
- "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
4305
- "@type": "@id"
4306
- }
4307
- } },
4308
4287
  "https://join-lemmy.org/context.json": { "@context": ["https://w3id.org/security/v1", {
4309
4288
  "as": "https://www.w3.org/ns/activitystreams#",
4310
4289
  "lemmy": "https://join-lemmy.org/ns#",
@@ -4363,7 +4342,7 @@ const preloadedContexts = {
4363
4342
  //#endregion
4364
4343
  //#region deno.json
4365
4344
  var name = "@fedify/vocab-runtime";
4366
- var version = "2.4.0-dev.1567+12e6a3c0";
4345
+ var version = "2.4.0-dev.1570+f1b6aaa3";
4367
4346
  //#endregion
4368
4347
  //#region src/link.ts
4369
4348
  const parametersNeedLowerCase = ["rel", "type"];
@@ -4616,6 +4595,179 @@ function logRequest(logger, request) {
4616
4595
  });
4617
4596
  }
4618
4597
  //#endregion
4598
+ //#region src/url.ts
4599
+ var UrlError = class extends Error {
4600
+ constructor(message) {
4601
+ super(message);
4602
+ this.name = "UrlError";
4603
+ }
4604
+ };
4605
+ /**
4606
+ * Validates a URL to prevent SSRF attacks.
4607
+ */
4608
+ async function validatePublicUrl(url) {
4609
+ const parsed = new URL(url);
4610
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new UrlError(`Unsupported protocol: ${parsed.protocol}`);
4611
+ let hostname = parsed.hostname;
4612
+ if (hostname.startsWith("[") && hostname.endsWith("]")) hostname = hostname.slice(1, -1);
4613
+ if (hostname === "localhost") throw new UrlError("Localhost is not allowed");
4614
+ const hostnameFamily = isIP(hostname);
4615
+ if (hostnameFamily !== 0) {
4616
+ validatePublicIpAddress(hostname, hostnameFamily);
4617
+ return;
4618
+ }
4619
+ if ("Deno" in globalThis && !isIP(hostname)) {
4620
+ if ((await Deno.permissions.query({ name: "net" })).state !== "granted") return;
4621
+ }
4622
+ if ("Bun" in globalThis) {
4623
+ if (hostname === "example.com" || hostname.endsWith(".example.com")) return;
4624
+ else if (hostname === "fedify-test.internal") throw new UrlError("Invalid or private address: fedify-test.internal");
4625
+ }
4626
+ let addresses;
4627
+ try {
4628
+ addresses = await lookup(hostname, { all: true });
4629
+ } catch {
4630
+ addresses = [];
4631
+ }
4632
+ for (const { address, family } of addresses) validatePublicIpAddress(address, family);
4633
+ }
4634
+ function validatePublicIpAddress(address, family) {
4635
+ if (family === 4 && isValidPublicIPv4Address(address) || family === 6 && isValidPublicIPv6Address(address)) return;
4636
+ throw new UrlError(`Invalid or private address: ${address}`);
4637
+ }
4638
+ function isValidPublicIPv4Address(address) {
4639
+ const parts = parseIPv4Address(address);
4640
+ if (parts == null) return false;
4641
+ const value = ipv4PartsToNumber(parts);
4642
+ return !nonPublicIPv4Prefixes.some(({ base, prefix }) => matchesIPv4Prefix(value, base, prefix));
4643
+ }
4644
+ function isValidPublicIPv6Address(address) {
4645
+ const words = parseIPv6Address(address);
4646
+ if (words == null) return false;
4647
+ if (nonPublicIPv6Prefixes.some(({ words: prefixWords, prefix }) => matchesIPv6Prefix(words, prefixWords, prefix))) return false;
4648
+ for (const { extractIPv4, prefix, words: prefixWords } of ipv6WithIPv4Prefixes) {
4649
+ if (!matchesIPv6Prefix(words, prefixWords, prefix)) continue;
4650
+ const ipv4Address = extractIPv4(words);
4651
+ if (ipv4Address != null && !isValidPublicIPv4Address(ipv4Address)) return false;
4652
+ }
4653
+ return true;
4654
+ }
4655
+ function expandIPv6Address(address) {
4656
+ address = address.toLowerCase();
4657
+ const ipv4Delimiter = address.lastIndexOf(":");
4658
+ if (address.includes(".") && ipv4Delimiter >= 0) {
4659
+ const ipv4Parts = parseIPv4Address(address.substring(ipv4Delimiter + 1));
4660
+ if (ipv4Parts == null) return address;
4661
+ const high = (ipv4Parts[0] << 8) + ipv4Parts[1];
4662
+ const low = (ipv4Parts[2] << 8) + ipv4Parts[3];
4663
+ address = address.substring(0, ipv4Delimiter + 1) + high.toString(16) + ":" + low.toString(16);
4664
+ }
4665
+ if (address === "::") return "0000:0000:0000:0000:0000:0000:0000:0000";
4666
+ if (address.startsWith("::")) address = "0000" + address;
4667
+ if (address.endsWith("::")) address = address + "0000";
4668
+ address = address.replace("::", ":0000".repeat(8 - (address.match(/:/g) || []).length) + ":");
4669
+ return address.split(":").map((part) => part.padStart(4, "0")).join(":");
4670
+ }
4671
+ const nonPublicIPv4Prefixes = [
4672
+ ipv4Prefix("0.0.0.0/8", "RFC 6890"),
4673
+ ipv4Prefix("10.0.0.0/8", "RFC 1918"),
4674
+ ipv4Prefix("100.64.0.0/10", "RFC 6598"),
4675
+ ipv4Prefix("127.0.0.0/8", "RFC 1122"),
4676
+ ipv4Prefix("169.254.0.0/16", "RFC 3927"),
4677
+ ipv4Prefix("172.16.0.0/12", "RFC 1918"),
4678
+ ipv4Prefix("192.0.0.0/24", "RFC 6890"),
4679
+ ipv4Prefix("192.0.2.0/24", "RFC 5737"),
4680
+ ipv4Prefix("192.88.99.0/24", "RFC 7526"),
4681
+ ipv4Prefix("192.168.0.0/16", "RFC 1918"),
4682
+ ipv4Prefix("198.18.0.0/15", "RFC 2544"),
4683
+ ipv4Prefix("198.51.100.0/24", "RFC 5737"),
4684
+ ipv4Prefix("203.0.113.0/24", "RFC 5737"),
4685
+ ipv4Prefix("224.0.0.0/4", "RFC 5771"),
4686
+ ipv4Prefix("240.0.0.0/4", "RFC 1112")
4687
+ ];
4688
+ const nonPublicIPv6Prefixes = [
4689
+ ipv6Prefix("::/16", "RFC 4291"),
4690
+ ipv6Prefix("2001::/32", "RFC 4380"),
4691
+ ipv6Prefix("2002::/16", "RFC 3056"),
4692
+ ipv6Prefix("64:ff9b:1::/48", "RFC 8215"),
4693
+ ipv6Prefix("fc00::/7", "RFC 4193"),
4694
+ ipv6Prefix("fe80::/10", "RFC 4291"),
4695
+ ipv6Prefix("ff00::/8", "RFC 4291")
4696
+ ];
4697
+ const ipv6WithIPv4Prefixes = [{
4698
+ ...ipv6Prefix("64:ff9b::/96", "RFC 6052"),
4699
+ extractIPv4: (words) => ipv4FromWords(words[6], words[7])
4700
+ }];
4701
+ function ipv4Prefix(cidr, rfc) {
4702
+ const [address, prefixText] = cidr.split("/");
4703
+ const prefix = parseInt(prefixText, 10);
4704
+ const parts = parseIPv4Address(address);
4705
+ if (parts == null || !Number.isInteger(prefix) || prefix < 0 || prefix > 32) throw new Error(`Invalid IPv4 prefix: ${cidr}`);
4706
+ return {
4707
+ cidr,
4708
+ base: ipv4PartsToNumber(parts),
4709
+ prefix,
4710
+ rfc
4711
+ };
4712
+ }
4713
+ function ipv6Prefix(cidr, rfc) {
4714
+ const [address, prefixText] = cidr.split("/");
4715
+ const prefix = parseInt(prefixText, 10);
4716
+ const words = parseIPv6Address(address);
4717
+ if (words == null || !Number.isInteger(prefix) || prefix < 0 || prefix > 128) throw new Error(`Invalid IPv6 prefix: ${cidr}`);
4718
+ return {
4719
+ cidr,
4720
+ words,
4721
+ prefix,
4722
+ rfc
4723
+ };
4724
+ }
4725
+ function parseIPv4Address(address) {
4726
+ const parts = address.split(".").map((part) => {
4727
+ if (!/^\d+$/.test(part)) return NaN;
4728
+ return parseInt(part, 10);
4729
+ });
4730
+ if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) return null;
4731
+ return parts;
4732
+ }
4733
+ function parseIPv6Address(address) {
4734
+ const parts = expandIPv6Address(address).split(":");
4735
+ if (parts.length !== 8) return null;
4736
+ const words = parts.map((part) => {
4737
+ if (!/^[0-9a-f]{1,4}$/i.test(part)) return NaN;
4738
+ return parseInt(part, 16);
4739
+ });
4740
+ if (words.some((word) => !Number.isInteger(word) || word < 0 || word > 65535)) return null;
4741
+ return words;
4742
+ }
4743
+ function ipv4PartsToNumber(parts) {
4744
+ return parts[0] * 2 ** 24 + parts[1] * 2 ** 16 + parts[2] * 2 ** 8 + parts[3];
4745
+ }
4746
+ function ipv4FromWords(highWord, lowWord) {
4747
+ return [
4748
+ highWord >> 8,
4749
+ highWord & 255,
4750
+ lowWord >> 8,
4751
+ lowWord & 255
4752
+ ].join(".");
4753
+ }
4754
+ function matchesIPv4Prefix(address, prefixBase, prefixLength) {
4755
+ const blockSize = 2 ** (32 - prefixLength);
4756
+ return Math.floor(address / blockSize) === Math.floor(prefixBase / blockSize);
4757
+ }
4758
+ function matchesIPv6Prefix(address, prefixWords, prefixLength) {
4759
+ let remaining = prefixLength;
4760
+ for (let i = 0; i < 8 && remaining > 0; i++) if (remaining >= 16) {
4761
+ if (address[i] !== prefixWords[i]) return false;
4762
+ remaining -= 16;
4763
+ } else {
4764
+ const mask = 65535 << 16 - remaining & 65535;
4765
+ if ((address[i] & mask) !== (prefixWords[i] & mask)) return false;
4766
+ remaining = 0;
4767
+ }
4768
+ return true;
4769
+ }
4770
+ //#endregion
4619
4771
  //#region src/docloader.ts
4620
4772
  const logger = getLogger([
4621
4773
  "fedify",
@@ -4623,66 +4775,6 @@ const logger = getLogger([
4623
4775
  "docloader"
4624
4776
  ]);
4625
4777
  const DEFAULT_MAX_REDIRECTION = 20;
4626
- const MAX_HTML_SIZE = 1024 * 1024;
4627
- function createResponseMetadata(response) {
4628
- return new Response(null, {
4629
- headers: response.headers,
4630
- status: response.status,
4631
- statusText: response.statusText
4632
- });
4633
- }
4634
- async function cancelResponseBody(response) {
4635
- if (response.body != null) await response.body.cancel();
4636
- }
4637
- async function readBoundedText(response, maxBytes) {
4638
- const contentLength = response.headers.get("Content-Length");
4639
- if (contentLength != null) {
4640
- const size = Number(contentLength);
4641
- if (size > maxBytes) {
4642
- await cancelResponseBody(response);
4643
- return {
4644
- text: "",
4645
- size,
4646
- tooLarge: true
4647
- };
4648
- }
4649
- }
4650
- if (response.body == null) return {
4651
- text: "",
4652
- size: 0,
4653
- tooLarge: false
4654
- };
4655
- const reader = response.body.getReader();
4656
- const decoder = new TextDecoder();
4657
- let text = "";
4658
- let size = 0;
4659
- try {
4660
- while (true) {
4661
- const result = await reader.read();
4662
- if (result.done) break;
4663
- const chunkSize = result.value.byteLength;
4664
- if (size + chunkSize > maxBytes) {
4665
- size += chunkSize;
4666
- await reader.cancel();
4667
- return {
4668
- text: "",
4669
- size,
4670
- tooLarge: true
4671
- };
4672
- }
4673
- size += chunkSize;
4674
- text += decoder.decode(result.value, { stream: true });
4675
- }
4676
- text += decoder.decode();
4677
- return {
4678
- text,
4679
- size,
4680
- tooLarge: false
4681
- };
4682
- } finally {
4683
- reader.releaseLock();
4684
- }
4685
- }
4686
4778
  /**
4687
4779
  * Gets a {@link RemoteDocument} from the given response.
4688
4780
  * @param url The URL of the document to load.
@@ -4737,19 +4829,19 @@ async function getRemoteDocument(url, response, fetch) {
4737
4829
  }
4738
4830
  let document;
4739
4831
  if (!jsonLd && (contentType === "text/html" || contentType?.startsWith("text/html;") || contentType === "application/xhtml+xml" || contentType?.startsWith("application/xhtml+xml;"))) {
4740
- const errorResponse = createResponseMetadata(response);
4741
- const html = await readBoundedText(response, MAX_HTML_SIZE);
4742
- if (html.tooLarge) {
4832
+ const MAX_HTML_SIZE = 1024 * 1024;
4833
+ const html = await response.text();
4834
+ if (html.length > MAX_HTML_SIZE) {
4743
4835
  logger.warn("HTML response too large, skipping alternate link discovery: {url}", {
4744
4836
  url: documentUrl,
4745
- size: html.size
4837
+ size: html.length
4746
4838
  });
4747
- throw new FetchError(documentUrl, `HTML document is too large to scan for an ActivityPub alternate link (Content-Type: ${contentType})`, errorResponse);
4839
+ document = JSON.parse(html);
4748
4840
  } else {
4749
4841
  const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
4750
4842
  const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
4751
4843
  let tagMatch;
4752
- while ((tagMatch = tagPattern.exec(html.text)) !== null) {
4844
+ while ((tagMatch = tagPattern.exec(html)) !== null) {
4753
4845
  const tagContent = tagMatch[2];
4754
4846
  let attrMatch;
4755
4847
  const attribs = {};
@@ -4766,12 +4858,7 @@ async function getRemoteDocument(url, response, fetch) {
4766
4858
  return await fetch(new URL(attribs.href, docUrl).href);
4767
4859
  }
4768
4860
  }
4769
- try {
4770
- document = JSON.parse(html.text);
4771
- } catch (error) {
4772
- if (!(error instanceof SyntaxError)) throw error;
4773
- throw new FetchError(documentUrl, `HTML document has no ActivityPub alternate link (Content-Type: ${contentType})`, errorResponse);
4774
- }
4861
+ document = JSON.parse(html);
4775
4862
  }
4776
4863
  } else document = await response.json();
4777
4864
  logger.debug("Fetched document: {status} {url} {headers}", {
@@ -5249,11 +5336,6 @@ const algorithms = {
5249
5336
  },
5250
5337
  "1.3.101.112": "Ed25519"
5251
5338
  };
5252
- const DID_KEY_PREFIX = "did:key:";
5253
- const ED25519_PUBLIC_KEY_MULTICODEC = 237;
5254
- const ED25519_PUBLIC_KEY_LENGTH = 32;
5255
- const DID_KEY_PATTERN = /^did:key:([^/?#]+)$/;
5256
- const DID_KEY_VERIFICATION_METHOD_PATTERN = /^did:key:([^/?#]+)#([^/?#]+)$/;
5257
5339
  /**
5258
5340
  * Imports a PEM-SPKI formatted public key.
5259
5341
  * @param pem The PEM-SPKI formatted public key.
@@ -5315,69 +5397,6 @@ const PKCS1_HEADER = /^\s*-----BEGIN\s+RSA\s+PUBLIC\s+KEY-----\s*\n/;
5315
5397
  function importPem(pem) {
5316
5398
  return PKCS1_HEADER.test(pem) ? importPkcs1(pem) : importSpki(pem);
5317
5399
  }
5318
- function decodeEd25519DidKeyMultibase(multibaseKey) {
5319
- if (!multibaseKey.startsWith("z")) throw new TypeError("did:key must use base58-btc Multibase encoding.");
5320
- let decoded;
5321
- try {
5322
- decoded = decodeMultibase(multibaseKey);
5323
- } catch (error) {
5324
- throw new TypeError("Invalid did:key Multibase encoding.", { cause: error });
5325
- }
5326
- const { code } = getMulticodecPrefix(decoded);
5327
- if (code !== ED25519_PUBLIC_KEY_MULTICODEC) throw new TypeError("Unsupported did:key type: 0x" + code.toString(16));
5328
- const content = removeMulticodecPrefix(decoded);
5329
- if (content.length !== ED25519_PUBLIC_KEY_LENGTH) throw new TypeError("Invalid Ed25519 did:key length.");
5330
- return content;
5331
- }
5332
- /**
5333
- * Imports an Ed25519 `did:key` DID.
5334
- *
5335
- * @param did The `did:key` DID.
5336
- * @returns The imported Ed25519 public key.
5337
- * @throws {TypeError} If the DID is malformed or uses an unsupported key type.
5338
- * @since 2.4.0
5339
- */
5340
- async function importDidKey(did) {
5341
- const match = (did instanceof URL ? did.href : did).match(DID_KEY_PATTERN);
5342
- if (match == null) throw new TypeError("Invalid did:key DID.");
5343
- const content = decodeEd25519DidKeyMultibase(match[1]);
5344
- return await crypto.subtle.importKey("raw", content.slice(), "Ed25519", true, ["verify"]);
5345
- }
5346
- /**
5347
- * Exports an Ed25519 public key as a `did:key` DID.
5348
- *
5349
- * @param key The Ed25519 public key.
5350
- * @returns The `did:key` DID.
5351
- * @throws {TypeError} If the key is invalid or unsupported.
5352
- * @since 2.4.0
5353
- */
5354
- async function exportDidKey(key) {
5355
- if (key.algorithm.name !== "Ed25519") throw new TypeError("Unsupported key type: " + JSON.stringify(key.algorithm));
5356
- return DID_KEY_PREFIX + await exportMultibaseKey(key);
5357
- }
5358
- /**
5359
- * Parses an Ed25519 `did:key` verification method DID URL.
5360
- *
5361
- * @param didUrl The `did:key` DID URL.
5362
- * @returns The parsed verification method.
5363
- * @throws {TypeError} If the DID URL is malformed, unsupported, or its
5364
- * fragment does not identify the same key as the DID.
5365
- * @since 2.4.0
5366
- */
5367
- async function parseDidKeyVerificationMethod(didUrl) {
5368
- const didUrlString = didUrl instanceof URL ? didUrl.href : didUrl;
5369
- const match = didUrlString.match(DID_KEY_VERIFICATION_METHOD_PATTERN);
5370
- if (match == null) throw new TypeError("Invalid did:key verification method.");
5371
- const [, publicKeyMultibase, fragment] = match;
5372
- if (publicKeyMultibase !== fragment) throw new TypeError("Invalid did:key verification method fragment.");
5373
- const publicKey = await importDidKey(DID_KEY_PREFIX + publicKeyMultibase);
5374
- return {
5375
- id: new URL(didUrlString),
5376
- controller: new URL(DID_KEY_PREFIX + publicKeyMultibase),
5377
- publicKeyMultibase,
5378
- publicKey
5379
- };
5380
- }
5381
5400
  /**
5382
5401
  * Imports a [Multibase]-encoded public key.
5383
5402
  *
@@ -5544,4 +5563,4 @@ LanguageString.prototype[Symbol.for("nodejs.util.inspect.custom")] = function(_d
5544
5563
  return `<${this.locale.baseName}> ${inspect(this.toString(), options)}`;
5545
5564
  };
5546
5565
  //#endregion
5547
- export { FetchError, LanguageString, UrlError, canParseDecimal, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getRemoteDocument, getUserAgent, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
5566
+ export { FetchError, LanguageString, UrlError, canParseDecimal, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportMultibaseKey, exportSpki, getDocumentLoader, getRemoteDocument, getUserAgent, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, preloadedContexts, validatePublicUrl };
@@ -1,7 +1,7 @@
1
1
  require("./chunk-C2EiDwsr.cjs");
2
- require("./docloader-BcaQHb0Q.cjs");
3
- require("./url-2XwVbUS_.cjs");
4
- require("./key-_wXwomh_.cjs");
2
+ require("./docloader-mvgIWKI7.cjs");
3
+ require("./url-C20FhC7p.cjs");
4
+ require("./key-pMmqUKuo.cjs");
5
5
  require("./multibase-Bz_UUDtL.cjs");
6
6
  require("./langstr-CbAxaeEZ.cjs");
7
7
  let node_assert = require("node:assert");
@@ -1,6 +1,6 @@
1
- import "./docloader-D61oV0K1.mjs";
2
- import "./url-YWJbnRlf.mjs";
3
- import "./key-CDGDH_vC.mjs";
1
+ import "./docloader-C76ldE5C.mjs";
2
+ import "./url-m9Qzxy-Y.mjs";
3
+ import "./key-CrrK9mYh.mjs";
4
4
  import "./multibase-B4bvakyA.mjs";
5
5
  import "./langstr-Di5AvKpB.mjs";
6
6
  import { deepStrictEqual, throws } from "node:assert";
@@ -1,6 +1,6 @@
1
- import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-Cn0vP7Hj.mjs";
1
+ import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-BEXkv1ul.mjs";
2
2
  import { t as HttpHeaderLink } from "./link-NUUWCdnK.mjs";
3
- import { l as validatePublicUrl, t as UrlError } from "./url-YWJbnRlf.mjs";
3
+ import { a as validatePublicUrl, t as UrlError } from "./url-m9Qzxy-Y.mjs";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
6
6
  //#endregion
@@ -4277,28 +4277,6 @@ const preloadedContexts = {
4277
4277
  "@type": "@id"
4278
4278
  }
4279
4279
  } },
4280
- "https://w3id.org/fep/7aa9": { "@context": {
4281
- "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
4282
- "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
4283
- "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
4284
- "FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
4285
- "topic": {
4286
- "@id": "https://w3id.org/fep/7aa9#topic",
4287
- "@type": "@id"
4288
- },
4289
- "featuredObject": {
4290
- "@id": "https://w3id.org/fep/7aa9#featuredObject",
4291
- "@type": "@id"
4292
- },
4293
- "canFeature": {
4294
- "@id": "https://w3id.org/fep/7aa9#canFeature",
4295
- "@type": "@id"
4296
- },
4297
- "featureAuthorization": {
4298
- "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
4299
- "@type": "@id"
4300
- }
4301
- } },
4302
4280
  "https://join-lemmy.org/context.json": { "@context": ["https://w3id.org/security/v1", {
4303
4281
  "as": "https://www.w3.org/ns/activitystreams#",
4304
4282
  "lemmy": "https://join-lemmy.org/ns#",
@@ -4362,66 +4340,6 @@ const logger = getLogger([
4362
4340
  "docloader"
4363
4341
  ]);
4364
4342
  const DEFAULT_MAX_REDIRECTION = 20;
4365
- const MAX_HTML_SIZE = 1024 * 1024;
4366
- function createResponseMetadata(response) {
4367
- return new Response(null, {
4368
- headers: response.headers,
4369
- status: response.status,
4370
- statusText: response.statusText
4371
- });
4372
- }
4373
- async function cancelResponseBody(response) {
4374
- if (response.body != null) await response.body.cancel();
4375
- }
4376
- async function readBoundedText(response, maxBytes) {
4377
- const contentLength = response.headers.get("Content-Length");
4378
- if (contentLength != null) {
4379
- const size = Number(contentLength);
4380
- if (size > maxBytes) {
4381
- await cancelResponseBody(response);
4382
- return {
4383
- text: "",
4384
- size,
4385
- tooLarge: true
4386
- };
4387
- }
4388
- }
4389
- if (response.body == null) return {
4390
- text: "",
4391
- size: 0,
4392
- tooLarge: false
4393
- };
4394
- const reader = response.body.getReader();
4395
- const decoder = new TextDecoder();
4396
- let text = "";
4397
- let size = 0;
4398
- try {
4399
- while (true) {
4400
- const result = await reader.read();
4401
- if (result.done) break;
4402
- const chunkSize = result.value.byteLength;
4403
- if (size + chunkSize > maxBytes) {
4404
- size += chunkSize;
4405
- await reader.cancel();
4406
- return {
4407
- text: "",
4408
- size,
4409
- tooLarge: true
4410
- };
4411
- }
4412
- size += chunkSize;
4413
- text += decoder.decode(result.value, { stream: true });
4414
- }
4415
- text += decoder.decode();
4416
- return {
4417
- text,
4418
- size,
4419
- tooLarge: false
4420
- };
4421
- } finally {
4422
- reader.releaseLock();
4423
- }
4424
- }
4425
4343
  /**
4426
4344
  * Gets a {@link RemoteDocument} from the given response.
4427
4345
  * @param url The URL of the document to load.
@@ -4476,19 +4394,19 @@ async function getRemoteDocument(url, response, fetch) {
4476
4394
  }
4477
4395
  let document;
4478
4396
  if (!jsonLd && (contentType === "text/html" || contentType?.startsWith("text/html;") || contentType === "application/xhtml+xml" || contentType?.startsWith("application/xhtml+xml;"))) {
4479
- const errorResponse = createResponseMetadata(response);
4480
- const html = await readBoundedText(response, MAX_HTML_SIZE);
4481
- if (html.tooLarge) {
4397
+ const MAX_HTML_SIZE = 1024 * 1024;
4398
+ const html = await response.text();
4399
+ if (html.length > MAX_HTML_SIZE) {
4482
4400
  logger.warn("HTML response too large, skipping alternate link discovery: {url}", {
4483
4401
  url: documentUrl,
4484
- size: html.size
4402
+ size: html.length
4485
4403
  });
4486
- throw new FetchError(documentUrl, `HTML document is too large to scan for an ActivityPub alternate link (Content-Type: ${contentType})`, errorResponse);
4404
+ document = JSON.parse(html);
4487
4405
  } else {
4488
4406
  const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
4489
4407
  const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
4490
4408
  let tagMatch;
4491
- while ((tagMatch = tagPattern.exec(html.text)) !== null) {
4409
+ while ((tagMatch = tagPattern.exec(html)) !== null) {
4492
4410
  const tagContent = tagMatch[2];
4493
4411
  let attrMatch;
4494
4412
  const attribs = {};
@@ -4505,12 +4423,7 @@ async function getRemoteDocument(url, response, fetch) {
4505
4423
  return await fetch(new URL(attribs.href, docUrl).href);
4506
4424
  }
4507
4425
  }
4508
- try {
4509
- document = JSON.parse(html.text);
4510
- } catch (error) {
4511
- if (!(error instanceof SyntaxError)) throw error;
4512
- throw new FetchError(documentUrl, `HTML document has no ActivityPub alternate link (Content-Type: ${contentType})`, errorResponse);
4513
- }
4426
+ document = JSON.parse(html);
4514
4427
  }
4515
4428
  } else document = await response.json();
4516
4429
  logger.debug("Fetched document: {status} {url} {headers}", {
@@ -4615,4 +4528,4 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
4615
4528
  return load;
4616
4529
  }
4617
4530
  //#endregion
4618
- export { getRemoteDocument as n, preloadedContexts as r, getDocumentLoader as t };
4531
+ export { preloadedContexts as n, getDocumentLoader as t };