@fedify/relay 2.0.28-dev.1974 → 2.0.28-dev.1982

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.
@@ -1,7 +1,7 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as exportSpki, r as getDocumentLoader, t as isRelayFollowerData } from "./types-BK-R7IEP.js";
4
+ import { n as exportSpki, r as getDocumentLoader, t as isRelayFollowerData } from "./types-DsXLSii6.js";
5
5
  import { MemoryKvStore, signRequest } from "@fedify/fedify";
6
6
  import { createRelay } from "@fedify/relay";
7
7
  import { Accept, Announce, Create, Delete, Follow, Move, Note, Person, Undo, Update } from "@fedify/vocab";
@@ -1,7 +1,7 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as exportSpki, r as getDocumentLoader, t as isRelayFollowerData } from "./types-BK-R7IEP.js";
4
+ import { n as exportSpki, r as getDocumentLoader, t as isRelayFollowerData } from "./types-DsXLSii6.js";
5
5
  import { MemoryKvStore, signRequest } from "@fedify/fedify";
6
6
  import { createRelay } from "@fedify/relay";
7
7
  import { Create, Delete, Follow, Move, Note, Person, Undo, Update } from "@fedify/vocab";
@@ -25647,7 +25647,141 @@ const preloadedContexts = {
25647
25647
  "https://purl.archive.org/miscellany": miscellany_default
25648
25648
  };
25649
25649
  var name = "@fedify/vocab-runtime";
25650
- var version = "2.0.28-dev.1974+d70e3148";
25650
+ var version = "2.0.28-dev.1982+a57dec3f";
25651
+ /**
25652
+ * Error thrown when fetching a JSON-LD document failed.
25653
+ */
25654
+ var FetchError = class extends Error {
25655
+ /**
25656
+ * The URL that failed to fetch.
25657
+ */
25658
+ url;
25659
+ /**
25660
+ * Constructs a new `FetchError`.
25661
+ *
25662
+ * @param url The URL that failed to fetch.
25663
+ * @param message Error message.
25664
+ */
25665
+ constructor(url, message) {
25666
+ super(message == null ? url.toString() : `${url}: ${message}`);
25667
+ this.name = "FetchError";
25668
+ this.url = typeof url === "string" ? new URL(url) : url;
25669
+ }
25670
+ };
25671
+ /**
25672
+ * Creates a request for the given URL.
25673
+ * @param url The URL to create the request for.
25674
+ * @param options The options for the request.
25675
+ * @returns The created request.
25676
+ * @internal
25677
+ */
25678
+ function createActivityPubRequest(url, options = {}) {
25679
+ return new Request(url, {
25680
+ headers: {
25681
+ Accept: "application/activity+json, application/ld+json",
25682
+ "User-Agent": typeof options.userAgent === "string" ? options.userAgent : getUserAgent(options.userAgent)
25683
+ },
25684
+ redirect: "manual"
25685
+ });
25686
+ }
25687
+ /**
25688
+ * Gets the user agent string for the given application and URL.
25689
+ * @param options The options for making the user agent string.
25690
+ * @returns The user agent string.
25691
+ * @since 1.3.0
25692
+ */
25693
+ function getUserAgent({ software, url } = {}) {
25694
+ const fedify = `Fedify/${version}`;
25695
+ const runtime = globalThis.Deno?.version?.deno != null ? `Deno/${Deno.version.deno}` : globalThis.process?.versions?.bun != null ? `Bun/${process$1.versions.bun}` : "navigator" in globalThis && navigator.userAgent === "Cloudflare-Workers" ? navigator.userAgent : globalThis.process?.versions?.node != null ? `Node.js/${process$1.versions.node}` : null;
25696
+ const userAgent = software == null ? [fedify] : [software, fedify];
25697
+ if (runtime != null) userAgent.push(runtime);
25698
+ if (url != null) userAgent.push(`+${url.toString()}`);
25699
+ return `${userAgent.shift()} (${userAgent.join("; ")})`;
25700
+ }
25701
+ /**
25702
+ * Logs the request.
25703
+ * @param request The request to log.
25704
+ * @internal
25705
+ */
25706
+ function logRequest(logger, request) {
25707
+ logger.debug("Fetching document: {method} {url} {headers}", {
25708
+ method: request.method,
25709
+ url: request.url,
25710
+ headers: Object.fromEntries(request.headers.entries())
25711
+ });
25712
+ }
25713
+ /** Decoded JSON body limit: 16 MiB. @internal */
25714
+ const MAX_BODY_SIZE = 16 * 1024 * 1024;
25715
+ /** A body exceeded the byte limit. @internal */
25716
+ var BodyTooLargeError = class extends FetchError {
25717
+ /** Creates an error for a body exceeding the given limit. */
25718
+ constructor(url, maxBytes) {
25719
+ super(url, `Body exceeds the limit of ${maxBytes} bytes`);
25720
+ this.name = "BodyTooLargeError";
25721
+ }
25722
+ };
25723
+ /** Validates a finite, positive byte limit. @internal */
25724
+ function validateBodySizeLimit(maxBytes) {
25725
+ if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) throw new RangeError("The body size limit must be a positive safe integer.");
25726
+ }
25727
+ /**
25728
+ * Reads UTF-8 text while limiting bytes received from the body stream.
25729
+ * Fetch responses are already decompressed, so the stream count is authoritative.
25730
+ * @param message The response or request to read.
25731
+ * @param maxBytes The maximum number of decoded bytes to read.
25732
+ * @param url The URL to include in errors and logs.
25733
+ * @returns The decoded body text.
25734
+ * @throws {BodyTooLargeError} If the body exceeds the limit.
25735
+ * @internal
25736
+ */
25737
+ async function readBoundedText(message, maxBytes, url) {
25738
+ validateBodySizeLimit(maxBytes);
25739
+ const reader = message.body?.getReader();
25740
+ const tooLarge = () => {
25741
+ getLogger([
25742
+ "fedify",
25743
+ "runtime",
25744
+ "body"
25745
+ ]).warn("Body from {url} exceeds the limit of {maxBytes} bytes.", {
25746
+ url: url.toString(),
25747
+ maxBytes
25748
+ });
25749
+ throw new BodyTooLargeError(url, maxBytes);
25750
+ };
25751
+ try {
25752
+ const length = message.headers.get("Content-Length");
25753
+ const encoding = message.headers.get("Content-Encoding");
25754
+ if ((encoding == null || encoding.toLowerCase() === "identity") && length != null && /^\d+$/.test(length) && Number(length) > maxBytes) tooLarge();
25755
+ if (reader == null) return "";
25756
+ let size = 0;
25757
+ const textReader = new ReadableStream({ async pull(controller) {
25758
+ const { done, value } = await reader.read();
25759
+ if (done) {
25760
+ controller.close();
25761
+ return;
25762
+ }
25763
+ size += value.byteLength;
25764
+ if (size > maxBytes) tooLarge();
25765
+ controller.enqueue(value);
25766
+ } }, { highWaterMark: 0 }).pipeThrough(new TextDecoderStream()).getReader();
25767
+ try {
25768
+ const chunks = [];
25769
+ while (true) {
25770
+ const { done, value } = await textReader.read();
25771
+ if (done) break;
25772
+ chunks.push(value);
25773
+ }
25774
+ return chunks.join("");
25775
+ } finally {
25776
+ textReader.releaseLock();
25777
+ }
25778
+ } catch (error) {
25779
+ if (reader != null) reader.cancel(error).catch(() => {});
25780
+ throw error;
25781
+ } finally {
25782
+ reader?.releaseLock();
25783
+ }
25784
+ }
25651
25785
  const parametersNeedLowerCase = ["rel", "type"];
25652
25786
  const regexpLinkWhitespace = /[\n\r\s\t]/;
25653
25787
  function validateURI(uri) {
@@ -25827,68 +25961,6 @@ var HttpHeaderLink = class HttpHeaderLink {
25827
25961
  return new this(...inputs).toString();
25828
25962
  }
25829
25963
  };
25830
- /**
25831
- * Error thrown when fetching a JSON-LD document failed.
25832
- */
25833
- var FetchError = class extends Error {
25834
- /**
25835
- * The URL that failed to fetch.
25836
- */
25837
- url;
25838
- /**
25839
- * Constructs a new `FetchError`.
25840
- *
25841
- * @param url The URL that failed to fetch.
25842
- * @param message Error message.
25843
- */
25844
- constructor(url, message) {
25845
- super(message == null ? url.toString() : `${url}: ${message}`);
25846
- this.name = "FetchError";
25847
- this.url = typeof url === "string" ? new URL(url) : url;
25848
- }
25849
- };
25850
- /**
25851
- * Creates a request for the given URL.
25852
- * @param url The URL to create the request for.
25853
- * @param options The options for the request.
25854
- * @returns The created request.
25855
- * @internal
25856
- */
25857
- function createActivityPubRequest(url, options = {}) {
25858
- return new Request(url, {
25859
- headers: {
25860
- Accept: "application/activity+json, application/ld+json",
25861
- "User-Agent": typeof options.userAgent === "string" ? options.userAgent : getUserAgent(options.userAgent)
25862
- },
25863
- redirect: "manual"
25864
- });
25865
- }
25866
- /**
25867
- * Gets the user agent string for the given application and URL.
25868
- * @param options The options for making the user agent string.
25869
- * @returns The user agent string.
25870
- * @since 1.3.0
25871
- */
25872
- function getUserAgent({ software, url } = {}) {
25873
- const fedify = `Fedify/${version}`;
25874
- const runtime = globalThis.Deno?.version?.deno != null ? `Deno/${Deno.version.deno}` : globalThis.process?.versions?.bun != null ? `Bun/${process$1.versions.bun}` : "navigator" in globalThis && navigator.userAgent === "Cloudflare-Workers" ? navigator.userAgent : globalThis.process?.versions?.node != null ? `Node.js/${process$1.versions.node}` : null;
25875
- const userAgent = software == null ? [fedify] : [software, fedify];
25876
- if (runtime != null) userAgent.push(runtime);
25877
- if (url != null) userAgent.push(`+${url.toString()}`);
25878
- return `${userAgent.shift()} (${userAgent.join("; ")})`;
25879
- }
25880
- /**
25881
- * Logs the request.
25882
- * @param request The request to log.
25883
- * @internal
25884
- */
25885
- function logRequest(logger, request) {
25886
- logger.debug("Fetching document: {method} {url} {headers}", {
25887
- method: request.method,
25888
- url: request.url,
25889
- headers: Object.fromEntries(request.headers.entries())
25890
- });
25891
- }
25892
25964
  var UrlError = class extends Error {
25893
25965
  constructor(message, options) {
25894
25966
  super(message, options);
@@ -26147,38 +26219,29 @@ async function getRemoteDocument(url, response, fetch) {
26147
26219
  }
26148
26220
  let document;
26149
26221
  if (!jsonLd && (contentType === "text/html" || contentType?.startsWith("text/html;") || contentType === "application/xhtml+xml" || contentType?.startsWith("application/xhtml+xml;"))) {
26150
- const MAX_HTML_SIZE = 1024 * 1024;
26151
- const html = await response.text();
26152
- if (html.length > MAX_HTML_SIZE) {
26153
- logger.warn("HTML response too large, skipping alternate link discovery: {url}", {
26154
- url: documentUrl,
26155
- size: html.length
26156
- });
26157
- document = JSON.parse(html);
26158
- } else {
26159
- const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
26160
- const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
26161
- let tagMatch;
26162
- while ((tagMatch = tagPattern.exec(html)) !== null) {
26163
- const tagContent = tagMatch[2];
26164
- let attrMatch;
26165
- const attribs = {};
26166
- attrPattern.lastIndex = 0;
26167
- while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
26168
- const key = attrMatch[1].toLowerCase();
26169
- attribs[key] = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
26170
- }
26171
- 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) {
26172
- logger.debug("Found alternate document: {alternateUrl} from {url}", {
26173
- alternateUrl: attribs.href,
26174
- url: documentUrl
26175
- });
26176
- return await fetch(new URL(attribs.href, docUrl).href);
26177
- }
26222
+ const html = await readBoundedText(response, 1024 * 1024, documentUrl);
26223
+ const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
26224
+ const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
26225
+ let tagMatch;
26226
+ while ((tagMatch = tagPattern.exec(html)) !== null) {
26227
+ const tagContent = tagMatch[2];
26228
+ let attrMatch;
26229
+ const attribs = {};
26230
+ attrPattern.lastIndex = 0;
26231
+ while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
26232
+ const key = attrMatch[1].toLowerCase();
26233
+ attribs[key] = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
26234
+ }
26235
+ 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) {
26236
+ logger.debug("Found alternate document: {alternateUrl} from {url}", {
26237
+ alternateUrl: attribs.href,
26238
+ url: documentUrl
26239
+ });
26240
+ return await fetch(new URL(attribs.href, docUrl).href);
26178
26241
  }
26179
- document = JSON.parse(html);
26180
26242
  }
26181
- } else document = await response.json();
26243
+ document = JSON.parse(html);
26244
+ } else document = JSON.parse(await readBoundedText(response, MAX_BODY_SIZE, documentUrl));
26182
26245
  logger.debug("Fetched document: {status} {url} {headers}", {
26183
26246
  status: response.status,
26184
26247
  url: documentUrl,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/relay",
3
- "version": "2.0.28-dev.1974+d70e3148",
3
+ "version": "2.0.28-dev.1982+a57dec3f",
4
4
  "description": "ActivityPub relay support for Fedify",
5
5
  "keywords": [
6
6
  "Fedify",
@@ -50,14 +50,14 @@
50
50
  "dependencies": {
51
51
  "@js-temporal/polyfill": "^0.5.1",
52
52
  "@logtape/logtape": "^2.0.0",
53
- "@fedify/vocab": "2.0.28-dev.1974+d70e3148",
54
- "@fedify/fedify": "^2.0.28-dev.1974+d70e3148"
53
+ "@fedify/fedify": "^2.0.28-dev.1982+a57dec3f",
54
+ "@fedify/vocab": "2.0.28-dev.1982+a57dec3f"
55
55
  },
56
56
  "devDependencies": {
57
57
  "tsdown": "^0.21.6",
58
58
  "typescript": "^6.0.0",
59
59
  "urlpattern-polyfill": "^10.1.0",
60
- "@fedify/vocab-runtime": "^2.0.28-dev.1974+d70e3148"
60
+ "@fedify/vocab-runtime": "^2.0.28-dev.1982+a57dec3f"
61
61
  },
62
62
  "scripts": {
63
63
  "build:self": "tsdown",