@fedify/vocab-runtime 2.0.29-dev.2020 → 2.0.29-dev.2053

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/vocab-runtime",
3
- "version": "2.0.29-dev.2020+b789935e",
3
+ "version": "2.0.29-dev.2053+58b638b4",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/mod.ts",
package/dist/mod.cjs CHANGED
@@ -128,6 +128,30 @@ var cid_v1_default = { "@context": {
128
128
  }
129
129
  } };
130
130
  //#endregion
131
+ //#region src/contexts/fep-7aa9.json
132
+ var fep_7aa9_default = { "@context": {
133
+ "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
134
+ "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
135
+ "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
136
+ "FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
137
+ "topic": {
138
+ "@id": "https://w3id.org/fep/7aa9#topic",
139
+ "@type": "@id"
140
+ },
141
+ "featuredObject": {
142
+ "@id": "https://w3id.org/fep/7aa9#featuredObject",
143
+ "@type": "@id"
144
+ },
145
+ "canFeature": {
146
+ "@id": "https://w3id.org/fep/7aa9#canFeature",
147
+ "@type": "@id"
148
+ },
149
+ "featureAuthorization": {
150
+ "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
151
+ "@type": "@id"
152
+ }
153
+ } };
154
+ //#endregion
131
155
  //#region src/contexts/fep-ef61.json
132
156
  var fep_ef61_default = { "@context": {
133
157
  "gateways": {
@@ -4403,6 +4427,7 @@ const preloadedContexts = {
4403
4427
  } },
4404
4428
  "https://www.w3.org/ns/cid/v1": cid_v1_default,
4405
4429
  "https://w3id.org/fep/ef61": fep_ef61_default,
4430
+ "https://w3id.org/fep/7aa9": fep_7aa9_default,
4406
4431
  "https://join-lemmy.org/context.json": join_lemmy_default,
4407
4432
  "http://joinmastodon.org/ns": { "@context": {
4408
4433
  "toot": "http://joinmastodon.org/ns#",
@@ -4435,7 +4460,7 @@ const preloadedContexts = {
4435
4460
  //#endregion
4436
4461
  //#region deno.json
4437
4462
  var name = "@fedify/vocab-runtime";
4438
- var version = "2.0.29-dev.2020+b789935e";
4463
+ var version = "2.0.29-dev.2053+58b638b4";
4439
4464
  //#endregion
4440
4465
  //#region src/request.ts
4441
4466
  /**
@@ -5074,6 +5099,7 @@ async function getRemoteDocument(url, response, fetch) {
5074
5099
  * - <https://www.w3.org/ns/cid/v1>
5075
5100
  * - <https://w3id.org/security/multikey/v1>
5076
5101
  * - <https://w3id.org/fep/ef61>
5102
+ * - <https://w3id.org/fep/7aa9>
5077
5103
  * - <https://purl.archive.org/socialweb/webfinger>
5078
5104
  * - <http://schema.org/>
5079
5105
  * @param options Options for the document loader.
@@ -5096,7 +5122,11 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
5096
5122
  if (!allowPrivateAddress) try {
5097
5123
  await validatePublicUrl(currentUrl);
5098
5124
  } catch (error) {
5099
- if (error instanceof UrlError) logger.error("Disallowed private URL: {url}", {
5125
+ if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
5126
+ url: currentUrl,
5127
+ error
5128
+ });
5129
+ else logger.error("Disallowed private URL: {url}", {
5100
5130
  url: currentUrl,
5101
5131
  error
5102
5132
  });
package/dist/mod.d.cts CHANGED
@@ -180,6 +180,7 @@ interface GetDocumentLoaderOptions extends DocumentLoaderFactoryOptions {
180
180
  * - <https://www.w3.org/ns/cid/v1>
181
181
  * - <https://w3id.org/security/multikey/v1>
182
182
  * - <https://w3id.org/fep/ef61>
183
+ * - <https://w3id.org/fep/7aa9>
183
184
  * - <https://purl.archive.org/socialweb/webfinger>
184
185
  * - <http://schema.org/>
185
186
  * @param options Options for the document loader.
package/dist/mod.d.ts CHANGED
@@ -179,6 +179,7 @@ interface GetDocumentLoaderOptions extends DocumentLoaderFactoryOptions {
179
179
  * - <https://www.w3.org/ns/cid/v1>
180
180
  * - <https://w3id.org/security/multikey/v1>
181
181
  * - <https://w3id.org/fep/ef61>
182
+ * - <https://w3id.org/fep/7aa9>
182
183
  * - <https://purl.archive.org/socialweb/webfinger>
183
184
  * - <http://schema.org/>
184
185
  * @param options Options for the document loader.
package/dist/mod.js CHANGED
@@ -123,6 +123,30 @@ var cid_v1_default = { "@context": {
123
123
  }
124
124
  } };
125
125
  //#endregion
126
+ //#region src/contexts/fep-7aa9.json
127
+ var fep_7aa9_default = { "@context": {
128
+ "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
129
+ "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
130
+ "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
131
+ "FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
132
+ "topic": {
133
+ "@id": "https://w3id.org/fep/7aa9#topic",
134
+ "@type": "@id"
135
+ },
136
+ "featuredObject": {
137
+ "@id": "https://w3id.org/fep/7aa9#featuredObject",
138
+ "@type": "@id"
139
+ },
140
+ "canFeature": {
141
+ "@id": "https://w3id.org/fep/7aa9#canFeature",
142
+ "@type": "@id"
143
+ },
144
+ "featureAuthorization": {
145
+ "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
146
+ "@type": "@id"
147
+ }
148
+ } };
149
+ //#endregion
126
150
  //#region src/contexts/fep-ef61.json
127
151
  var fep_ef61_default = { "@context": {
128
152
  "gateways": {
@@ -4398,6 +4422,7 @@ const preloadedContexts = {
4398
4422
  } },
4399
4423
  "https://www.w3.org/ns/cid/v1": cid_v1_default,
4400
4424
  "https://w3id.org/fep/ef61": fep_ef61_default,
4425
+ "https://w3id.org/fep/7aa9": fep_7aa9_default,
4401
4426
  "https://join-lemmy.org/context.json": join_lemmy_default,
4402
4427
  "http://joinmastodon.org/ns": { "@context": {
4403
4428
  "toot": "http://joinmastodon.org/ns#",
@@ -4430,7 +4455,7 @@ const preloadedContexts = {
4430
4455
  //#endregion
4431
4456
  //#region deno.json
4432
4457
  var name = "@fedify/vocab-runtime";
4433
- var version = "2.0.29-dev.2020+b789935e";
4458
+ var version = "2.0.29-dev.2053+58b638b4";
4434
4459
  //#endregion
4435
4460
  //#region src/request.ts
4436
4461
  /**
@@ -5069,6 +5094,7 @@ async function getRemoteDocument(url, response, fetch) {
5069
5094
  * - <https://www.w3.org/ns/cid/v1>
5070
5095
  * - <https://w3id.org/security/multikey/v1>
5071
5096
  * - <https://w3id.org/fep/ef61>
5097
+ * - <https://w3id.org/fep/7aa9>
5072
5098
  * - <https://purl.archive.org/socialweb/webfinger>
5073
5099
  * - <http://schema.org/>
5074
5100
  * @param options Options for the document loader.
@@ -5091,7 +5117,11 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
5091
5117
  if (!allowPrivateAddress) try {
5092
5118
  await validatePublicUrl(currentUrl);
5093
5119
  } catch (error) {
5094
- if (error instanceof UrlError) logger.error("Disallowed private URL: {url}", {
5120
+ if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
5121
+ url: currentUrl,
5122
+ error
5123
+ });
5124
+ else logger.error("Disallowed private URL: {url}", {
5095
5125
  url: currentUrl,
5096
5126
  error
5097
5127
  });
@@ -1,5 +1,5 @@
1
1
  require("./chunk-Do9eywBl.cjs");
2
- const require_request = require("./request-BGn7Xf1v.cjs");
2
+ const require_request = require("./request-CJBG7aUH.cjs");
3
3
  let _logtape_logtape = require("@logtape/logtape");
4
4
  //#region src/body.ts
5
5
  /** Decoded JSON body limit: 16 MiB. @internal */
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "./request-CDO-jqNj.mjs";
1
+ import { t as FetchError } from "./request-CJ_k5ecc.mjs";
2
2
  import { getLogger } from "@logtape/logtape";
3
3
  //#region src/body.ts
4
4
  /** Decoded JSON body limit: 16 MiB. @internal */
@@ -1,5 +1,5 @@
1
1
  require("./chunk-Do9eywBl.cjs");
2
- const require_body = require("./body-DlOEQngJ.cjs");
2
+ const require_body = require("./body-CXea4PBM.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");
@@ -1,4 +1,4 @@
1
- import { r as readBoundedText, t as BodyTooLargeError } from "./body-BXnCq6ed.mjs";
1
+ import { r as readBoundedText, t as BodyTooLargeError } from "./body-DzsCW7DB.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,12 +1,14 @@
1
1
  const require_chunk = require("./chunk-Do9eywBl.cjs");
2
- const require_request = require("./request-BGn7Xf1v.cjs");
3
- const require_body = require("./body-DlOEQngJ.cjs");
2
+ const require_request = require("./request-CJBG7aUH.cjs");
3
+ const require_body = require("./body-CXea4PBM.cjs");
4
4
  const require_link = require("./link-FguCydMA.cjs");
5
5
  const require_url = require("./url-Qk1svKZU.cjs");
6
6
  let node_test = require("node:test");
7
7
  let node_zlib = require("node:zlib");
8
8
  let _logtape_logtape = require("@logtape/logtape");
9
9
  let node_assert = require("node:assert");
10
+ let node_dns_promises = require("node:dns/promises");
11
+ node_dns_promises = require_chunk.__toESM(node_dns_promises);
10
12
  let node_http = require("node:http");
11
13
  let _opentelemetry_api = require("@opentelemetry/api");
12
14
  //#region ../../node_modules/.pnpm/glob-to-regexp@0.4.1/node_modules/glob-to-regexp/index.js
@@ -1323,6 +1325,30 @@ var cid_v1_default = { "@context": {
1323
1325
  }
1324
1326
  } };
1325
1327
  //#endregion
1328
+ //#region src/contexts/fep-7aa9.json
1329
+ var fep_7aa9_default = { "@context": {
1330
+ "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
1331
+ "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
1332
+ "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
1333
+ "FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
1334
+ "topic": {
1335
+ "@id": "https://w3id.org/fep/7aa9#topic",
1336
+ "@type": "@id"
1337
+ },
1338
+ "featuredObject": {
1339
+ "@id": "https://w3id.org/fep/7aa9#featuredObject",
1340
+ "@type": "@id"
1341
+ },
1342
+ "canFeature": {
1343
+ "@id": "https://w3id.org/fep/7aa9#canFeature",
1344
+ "@type": "@id"
1345
+ },
1346
+ "featureAuthorization": {
1347
+ "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
1348
+ "@type": "@id"
1349
+ }
1350
+ } };
1351
+ //#endregion
1326
1352
  //#region src/contexts/fep-ef61.json
1327
1353
  var fep_ef61_default = { "@context": {
1328
1354
  "gateways": {
@@ -5598,6 +5624,7 @@ const preloadedContexts = {
5598
5624
  } },
5599
5625
  "https://www.w3.org/ns/cid/v1": cid_v1_default,
5600
5626
  "https://w3id.org/fep/ef61": fep_ef61_default,
5627
+ "https://w3id.org/fep/7aa9": fep_7aa9_default,
5601
5628
  "https://join-lemmy.org/context.json": join_lemmy_default,
5602
5629
  "http://joinmastodon.org/ns": { "@context": {
5603
5630
  "toot": "http://joinmastodon.org/ns#",
@@ -5736,6 +5763,7 @@ async function getRemoteDocument(url, response, fetch) {
5736
5763
  * - <https://www.w3.org/ns/cid/v1>
5737
5764
  * - <https://w3id.org/security/multikey/v1>
5738
5765
  * - <https://w3id.org/fep/ef61>
5766
+ * - <https://w3id.org/fep/7aa9>
5739
5767
  * - <https://purl.archive.org/socialweb/webfinger>
5740
5768
  * - <http://schema.org/>
5741
5769
  * @param options Options for the document loader.
@@ -5758,7 +5786,11 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
5758
5786
  if (!allowPrivateAddress) try {
5759
5787
  await require_url.validatePublicUrl(currentUrl);
5760
5788
  } catch (error) {
5761
- if (error instanceof require_url.UrlError) logger.error("Disallowed private URL: {url}", {
5789
+ if (error instanceof require_url.UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
5790
+ url: currentUrl,
5791
+ error
5792
+ });
5793
+ else logger.error("Disallowed private URL: {url}", {
5762
5794
  url: currentUrl,
5763
5795
  error
5764
5796
  });
@@ -6062,6 +6094,37 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
6062
6094
  } }
6063
6095
  });
6064
6096
  });
6097
+ esm_default.get("https://w3id.org/fep/7aa9", { status: 502 });
6098
+ await t.test("preloaded FEP-7aa9 context", async () => {
6099
+ const url = "https://w3id.org/fep/7aa9";
6100
+ (0, node_assert.deepStrictEqual)(await fetchDocumentLoader(url), {
6101
+ contextUrl: null,
6102
+ documentUrl: url,
6103
+ document: { "@context": {
6104
+ "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
6105
+ "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
6106
+ "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
6107
+ "FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
6108
+ "topic": {
6109
+ "@id": "https://w3id.org/fep/7aa9#topic",
6110
+ "@type": "@id"
6111
+ },
6112
+ "featuredObject": {
6113
+ "@id": "https://w3id.org/fep/7aa9#featuredObject",
6114
+ "@type": "@id"
6115
+ },
6116
+ "canFeature": {
6117
+ "@id": "https://w3id.org/fep/7aa9#canFeature",
6118
+ "@type": "@id"
6119
+ },
6120
+ "featureAuthorization": {
6121
+ "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
6122
+ "@type": "@id"
6123
+ }
6124
+ } }
6125
+ });
6126
+ (0, node_assert.deepStrictEqual)(esm_default.callHistory.calls(url).length, 0);
6127
+ });
6065
6128
  await t.test("deny non-HTTP/HTTPS", async () => {
6066
6129
  await (0, node_assert.rejects)(() => fetchDocumentLoader("ftp://localhost"), require_url.UrlError);
6067
6130
  });
@@ -6244,4 +6307,62 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
6244
6307
  (0, node_assert.deepStrictEqual)(canceled, true);
6245
6308
  (0, node_assert.deepStrictEqual)(pulls, 257);
6246
6309
  });
6310
+ (0, node_test.test)("getDocumentLoader() logs DNS failures as such", async (t) => {
6311
+ if ("Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted") {
6312
+ t.skip("requires the net permission");
6313
+ return;
6314
+ }
6315
+ const loader = getDocumentLoader();
6316
+ for (const result of [
6317
+ "throws",
6318
+ "empty",
6319
+ "private"
6320
+ ]) await t.test(result, async () => {
6321
+ const originalLookup = node_dns_promises.default.lookup;
6322
+ node_dns_promises.default.lookup = (() => result === "throws" ? Promise.reject(/* @__PURE__ */ new Error("Resolver unavailable")) : Promise.resolve(result === "empty" ? [] : [{
6323
+ address: "127.0.0.1",
6324
+ family: 4
6325
+ }]));
6326
+ const records = [];
6327
+ await (0, _logtape_logtape.configure)({
6328
+ sinks: { buffer: (record) => records.push(record) },
6329
+ loggers: [{
6330
+ category: "fedify",
6331
+ sinks: ["buffer"],
6332
+ lowestLevel: "debug"
6333
+ }, {
6334
+ category: ["logtape", "meta"],
6335
+ sinks: []
6336
+ }],
6337
+ reset: true
6338
+ });
6339
+ try {
6340
+ const url = "https://dns-failure.invalid/object";
6341
+ let error;
6342
+ await (0, node_assert.rejects)(() => loader(url), (e) => {
6343
+ error = e;
6344
+ return true;
6345
+ });
6346
+ (0, node_assert.ok)(error instanceof require_url.UrlError);
6347
+ (0, node_assert.deepStrictEqual)(error.reason, result === "private" ? "disallowed" : "dns");
6348
+ (0, node_assert.deepStrictEqual)(records.map((r) => [
6349
+ r.level,
6350
+ r.rawMessage,
6351
+ r.properties.url
6352
+ ]), [result === "private" ? [
6353
+ "error",
6354
+ "Disallowed private URL: {url}",
6355
+ url
6356
+ ] : [
6357
+ "debug",
6358
+ "DNS lookup failed for {url}",
6359
+ url
6360
+ ]]);
6361
+ (0, node_assert.ok)(records[0].properties.error === error);
6362
+ } finally {
6363
+ await (0, _logtape_logtape.reset)();
6364
+ node_dns_promises.default.lookup = originalLookup;
6365
+ }
6366
+ });
6367
+ });
6247
6368
  //#endregion
@@ -1,11 +1,12 @@
1
- import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-CDO-jqNj.mjs";
2
- import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-BXnCq6ed.mjs";
1
+ import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-CJ_k5ecc.mjs";
2
+ import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-DzsCW7DB.mjs";
3
3
  import { t as HttpHeaderLink } from "./link-NUUWCdnK.mjs";
4
4
  import { o as validatePublicUrl, t as UrlError } from "./url-DzlMS01z.mjs";
5
5
  import { test } from "node:test";
6
6
  import { gzipSync } from "node:zlib";
7
- import { getLogger } from "@logtape/logtape";
7
+ import { configure, getLogger, reset } from "@logtape/logtape";
8
8
  import { deepStrictEqual, ok, rejects } from "node:assert";
9
+ import dns from "node:dns/promises";
9
10
  import { createServer } from "node:http";
10
11
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
11
12
  //#region \0rolldown/runtime.js
@@ -1342,6 +1343,30 @@ var cid_v1_default = { "@context": {
1342
1343
  }
1343
1344
  } };
1344
1345
  //#endregion
1346
+ //#region src/contexts/fep-7aa9.json
1347
+ var fep_7aa9_default = { "@context": {
1348
+ "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
1349
+ "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
1350
+ "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
1351
+ "FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
1352
+ "topic": {
1353
+ "@id": "https://w3id.org/fep/7aa9#topic",
1354
+ "@type": "@id"
1355
+ },
1356
+ "featuredObject": {
1357
+ "@id": "https://w3id.org/fep/7aa9#featuredObject",
1358
+ "@type": "@id"
1359
+ },
1360
+ "canFeature": {
1361
+ "@id": "https://w3id.org/fep/7aa9#canFeature",
1362
+ "@type": "@id"
1363
+ },
1364
+ "featureAuthorization": {
1365
+ "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
1366
+ "@type": "@id"
1367
+ }
1368
+ } };
1369
+ //#endregion
1345
1370
  //#region src/contexts/fep-ef61.json
1346
1371
  var fep_ef61_default = { "@context": {
1347
1372
  "gateways": {
@@ -5617,6 +5642,7 @@ const preloadedContexts = {
5617
5642
  } },
5618
5643
  "https://www.w3.org/ns/cid/v1": cid_v1_default,
5619
5644
  "https://w3id.org/fep/ef61": fep_ef61_default,
5645
+ "https://w3id.org/fep/7aa9": fep_7aa9_default,
5620
5646
  "https://join-lemmy.org/context.json": join_lemmy_default,
5621
5647
  "http://joinmastodon.org/ns": { "@context": {
5622
5648
  "toot": "http://joinmastodon.org/ns#",
@@ -5755,6 +5781,7 @@ async function getRemoteDocument(url, response, fetch) {
5755
5781
  * - <https://www.w3.org/ns/cid/v1>
5756
5782
  * - <https://w3id.org/security/multikey/v1>
5757
5783
  * - <https://w3id.org/fep/ef61>
5784
+ * - <https://w3id.org/fep/7aa9>
5758
5785
  * - <https://purl.archive.org/socialweb/webfinger>
5759
5786
  * - <http://schema.org/>
5760
5787
  * @param options Options for the document loader.
@@ -5777,7 +5804,11 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
5777
5804
  if (!allowPrivateAddress) try {
5778
5805
  await validatePublicUrl(currentUrl);
5779
5806
  } catch (error) {
5780
- if (error instanceof UrlError) logger.error("Disallowed private URL: {url}", {
5807
+ if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
5808
+ url: currentUrl,
5809
+ error
5810
+ });
5811
+ else logger.error("Disallowed private URL: {url}", {
5781
5812
  url: currentUrl,
5782
5813
  error
5783
5814
  });
@@ -6081,6 +6112,37 @@ test("getDocumentLoader()", async (t) => {
6081
6112
  } }
6082
6113
  });
6083
6114
  });
6115
+ esm_default.get("https://w3id.org/fep/7aa9", { status: 502 });
6116
+ await t.test("preloaded FEP-7aa9 context", async () => {
6117
+ const url = "https://w3id.org/fep/7aa9";
6118
+ deepStrictEqual(await fetchDocumentLoader(url), {
6119
+ contextUrl: null,
6120
+ documentUrl: url,
6121
+ document: { "@context": {
6122
+ "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
6123
+ "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
6124
+ "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
6125
+ "FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
6126
+ "topic": {
6127
+ "@id": "https://w3id.org/fep/7aa9#topic",
6128
+ "@type": "@id"
6129
+ },
6130
+ "featuredObject": {
6131
+ "@id": "https://w3id.org/fep/7aa9#featuredObject",
6132
+ "@type": "@id"
6133
+ },
6134
+ "canFeature": {
6135
+ "@id": "https://w3id.org/fep/7aa9#canFeature",
6136
+ "@type": "@id"
6137
+ },
6138
+ "featureAuthorization": {
6139
+ "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
6140
+ "@type": "@id"
6141
+ }
6142
+ } }
6143
+ });
6144
+ deepStrictEqual(esm_default.callHistory.calls(url).length, 0);
6145
+ });
6084
6146
  await t.test("deny non-HTTP/HTTPS", async () => {
6085
6147
  await rejects(() => fetchDocumentLoader("ftp://localhost"), UrlError);
6086
6148
  });
@@ -6263,5 +6325,63 @@ test("getRemoteDocument() bounds JSON by default", async () => {
6263
6325
  deepStrictEqual(canceled, true);
6264
6326
  deepStrictEqual(pulls, 257);
6265
6327
  });
6328
+ test("getDocumentLoader() logs DNS failures as such", async (t) => {
6329
+ if ("Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted") {
6330
+ t.skip("requires the net permission");
6331
+ return;
6332
+ }
6333
+ const loader = getDocumentLoader();
6334
+ for (const result of [
6335
+ "throws",
6336
+ "empty",
6337
+ "private"
6338
+ ]) await t.test(result, async () => {
6339
+ const originalLookup = dns.lookup;
6340
+ dns.lookup = (() => result === "throws" ? Promise.reject(/* @__PURE__ */ new Error("Resolver unavailable")) : Promise.resolve(result === "empty" ? [] : [{
6341
+ address: "127.0.0.1",
6342
+ family: 4
6343
+ }]));
6344
+ const records = [];
6345
+ await configure({
6346
+ sinks: { buffer: (record) => records.push(record) },
6347
+ loggers: [{
6348
+ category: "fedify",
6349
+ sinks: ["buffer"],
6350
+ lowestLevel: "debug"
6351
+ }, {
6352
+ category: ["logtape", "meta"],
6353
+ sinks: []
6354
+ }],
6355
+ reset: true
6356
+ });
6357
+ try {
6358
+ const url = "https://dns-failure.invalid/object";
6359
+ let error;
6360
+ await rejects(() => loader(url), (e) => {
6361
+ error = e;
6362
+ return true;
6363
+ });
6364
+ ok(error instanceof UrlError);
6365
+ deepStrictEqual(error.reason, result === "private" ? "disallowed" : "dns");
6366
+ deepStrictEqual(records.map((r) => [
6367
+ r.level,
6368
+ r.rawMessage,
6369
+ r.properties.url
6370
+ ]), [result === "private" ? [
6371
+ "error",
6372
+ "Disallowed private URL: {url}",
6373
+ url
6374
+ ] : [
6375
+ "debug",
6376
+ "DNS lookup failed for {url}",
6377
+ url
6378
+ ]]);
6379
+ ok(records[0].properties.error === error);
6380
+ } finally {
6381
+ await reset();
6382
+ dns.lookup = originalLookup;
6383
+ }
6384
+ });
6385
+ });
6266
6386
  //#endregion
6267
6387
  export {};
@@ -3,7 +3,7 @@ let node_process = require("node:process");
3
3
  node_process = require_chunk.__toESM(node_process);
4
4
  //#region deno.json
5
5
  var name = "@fedify/vocab-runtime";
6
- var version = "2.0.29-dev.2020+b789935e";
6
+ var version = "2.0.29-dev.2053+58b638b4";
7
7
  //#endregion
8
8
  //#region src/request.ts
9
9
  /**
@@ -1,7 +1,7 @@
1
1
  import process from "node:process";
2
2
  //#region deno.json
3
3
  var name = "@fedify/vocab-runtime";
4
- var version = "2.0.29-dev.2020+b789935e";
4
+ var version = "2.0.29-dev.2053+58b638b4";
5
5
  //#endregion
6
6
  //#region src/request.ts
7
7
  /**
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Do9eywBl.cjs");
2
- const require_request = require("./request-BGn7Xf1v.cjs");
2
+ const require_request = require("./request-CJBG7aUH.cjs");
3
3
  let node_test = require("node:test");
4
4
  let node_process = require("node:process");
5
5
  node_process = require_chunk.__toESM(node_process);
@@ -1,4 +1,4 @@
1
- import { o as version, r as getUserAgent } from "./request-CDO-jqNj.mjs";
1
+ import { o as version, r as getUserAgent } from "./request-CJ_k5ecc.mjs";
2
2
  import { test } from "node:test";
3
3
  import process from "node:process";
4
4
  import { deepStrictEqual } from "node:assert";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/vocab-runtime",
3
- "version": "2.0.29-dev.2020+b789935e",
3
+ "version": "2.0.29-dev.2053+58b638b4",
4
4
  "homepage": "https://fedify.dev/",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,24 @@
1
+ {
2
+ "@context": {
3
+ "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
4
+ "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
5
+ "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
6
+ "FeatureAuthorization": "https://w3id.org/fep/7aa9#FeatureAuthorization",
7
+ "topic": {
8
+ "@id": "https://w3id.org/fep/7aa9#topic",
9
+ "@type": "@id"
10
+ },
11
+ "featuredObject": {
12
+ "@id": "https://w3id.org/fep/7aa9#featuredObject",
13
+ "@type": "@id"
14
+ },
15
+ "canFeature": {
16
+ "@id": "https://w3id.org/fep/7aa9#canFeature",
17
+ "@type": "@id"
18
+ },
19
+ "featureAuthorization": {
20
+ "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
21
+ "@type": "@id"
22
+ }
23
+ }
24
+ }
package/src/contexts.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  // cSpell: disable
4
4
 
5
5
  import cidV1Context from "./contexts/cid-v1.json" with { type: "json" };
6
+ import fep7aa9 from "./contexts/fep-7aa9.json" with { type: "json" };
6
7
  import fepEf61 from "./contexts/fep-ef61.json" with { type: "json" };
7
8
  import joinLemmyContext from "./contexts/join-lemmy.json" with { type: "json" };
8
9
  import miscellany from "./contexts/miscellany.json" with { type: "json" };
@@ -4337,6 +4338,13 @@ const preloadedContexts: Record<string, unknown> = {
4337
4338
  // https://github.com/fedify-dev/fedify/issues/982
4338
4339
  "https://w3id.org/fep/ef61": fepEf61,
4339
4340
 
4341
+ // The FEP-7aa9 context is hosted on Codeberg Pages, whose outages can
4342
+ // prevent actor documents from being parsed. Resolve it locally so that
4343
+ // parsing does not depend on the remote context server's availability.
4344
+ // See: https://w3id.org/fep/7aa9
4345
+ // https://github.com/fedify-dev/fedify/issues/1078
4346
+ "https://w3id.org/fep/7aa9": fep7aa9,
4347
+
4340
4348
  // Lemmy's context document is served as application/json without the JSON-LD
4341
4349
  // context Link header. The default document loader treats that as a regular
4342
4350
  // JSON response instead of a JSON-LD context, so every Lemmy activity that
@@ -1,5 +1,7 @@
1
+ import { configure, type LogRecord, reset } from "@logtape/logtape";
1
2
  import fetchMock from "fetch-mock";
2
3
  import { deepStrictEqual, ok, rejects } from "node:assert";
4
+ import dns from "node:dns/promises";
3
5
  import { test } from "node:test";
4
6
  import { createServer } from "node:http";
5
7
  import { gzipSync } from "node:zlib";
@@ -328,6 +330,43 @@ test("getDocumentLoader()", async (t) => {
328
330
  });
329
331
  });
330
332
 
333
+ // A Codeberg Pages outage must not prevent loading the FEP-7aa9 context.
334
+ // See: https://github.com/fedify-dev/fedify/issues/1078
335
+ fetchMock.get("https://w3id.org/fep/7aa9", { status: 502 });
336
+ await t.test("preloaded FEP-7aa9 context", async () => {
337
+ const url = "https://w3id.org/fep/7aa9";
338
+ deepStrictEqual(await fetchDocumentLoader(url), {
339
+ contextUrl: null,
340
+ documentUrl: url,
341
+ document: {
342
+ "@context": {
343
+ "FeaturedCollection": "https://w3id.org/fep/7aa9#FeaturedCollection",
344
+ "FeaturedItem": "https://w3id.org/fep/7aa9#FeaturedItem",
345
+ "FeatureRequest": "https://w3id.org/fep/7aa9#FeatureRequest",
346
+ "FeatureAuthorization":
347
+ "https://w3id.org/fep/7aa9#FeatureAuthorization",
348
+ "topic": {
349
+ "@id": "https://w3id.org/fep/7aa9#topic",
350
+ "@type": "@id",
351
+ },
352
+ "featuredObject": {
353
+ "@id": "https://w3id.org/fep/7aa9#featuredObject",
354
+ "@type": "@id",
355
+ },
356
+ "canFeature": {
357
+ "@id": "https://w3id.org/fep/7aa9#canFeature",
358
+ "@type": "@id",
359
+ },
360
+ "featureAuthorization": {
361
+ "@id": "https://w3id.org/fep/7aa9#featureAuthorization",
362
+ "@type": "@id",
363
+ },
364
+ },
365
+ },
366
+ });
367
+ deepStrictEqual(fetchMock.callHistory.calls(url).length, 0);
368
+ });
369
+
331
370
  await t.test("deny non-HTTP/HTTPS", async () => {
332
371
  await rejects(
333
372
  () => fetchDocumentLoader("ftp://localhost"),
@@ -622,3 +661,66 @@ test("getRemoteDocument() bounds JSON by default", async () => {
622
661
  deepStrictEqual(canceled, true);
623
662
  deepStrictEqual(pulls, 257);
624
663
  });
664
+
665
+ test("getDocumentLoader() logs DNS failures as such", async (t) => {
666
+ // The validator skips DNS when Deno has no network permission. Checked
667
+ // here rather than with top-level await, which the CommonJS build rejects.
668
+ if (
669
+ "Deno" in globalThis &&
670
+ (await Deno.permissions.query({ name: "net" })).state !== "granted"
671
+ ) {
672
+ t.skip("requires the net permission");
673
+ return;
674
+ }
675
+ const loader = getDocumentLoader();
676
+ for (const result of ["throws", "empty", "private"] as const) {
677
+ await t.test(result, async () => {
678
+ // Stubbing works only because url.ts uses the default node:dns/promises
679
+ // import; see the FIXME there.
680
+ const originalLookup = dns.lookup;
681
+ dns.lookup = (() =>
682
+ result === "throws"
683
+ ? Promise.reject(new Error("Resolver unavailable"))
684
+ : Promise.resolve(
685
+ result === "empty" ? [] : [{ address: "127.0.0.1", family: 4 }],
686
+ )) as typeof dns.lookup;
687
+ const records: LogRecord[] = [];
688
+ await configure({
689
+ sinks: {
690
+ buffer: (record) =>
691
+ records.push(record),
692
+ },
693
+ loggers: [
694
+ { category: "fedify", sinks: ["buffer"], lowestLevel: "debug" },
695
+ { category: ["logtape", "meta"], sinks: [] },
696
+ ],
697
+ reset: true,
698
+ });
699
+ try {
700
+ const url = "https://dns-failure.invalid/object";
701
+ let error: unknown;
702
+ await rejects(() => loader(url), (e) => {
703
+ error = e;
704
+ return true;
705
+ });
706
+ ok(error instanceof UrlError);
707
+ deepStrictEqual(
708
+ error.reason,
709
+ result === "private" ? "disallowed" : "dns",
710
+ );
711
+ deepStrictEqual(
712
+ records.map((r) => [r.level, r.rawMessage, r.properties.url]),
713
+ [
714
+ result === "private"
715
+ ? ["error", "Disallowed private URL: {url}", url]
716
+ : ["debug", "DNS lookup failed for {url}", url],
717
+ ],
718
+ );
719
+ ok(records[0].properties.error === error);
720
+ } finally {
721
+ await reset();
722
+ dns.lookup = originalLookup;
723
+ }
724
+ });
725
+ }
726
+ });
package/src/docloader.ts CHANGED
@@ -277,6 +277,7 @@ export interface GetDocumentLoaderOptions extends DocumentLoaderFactoryOptions {
277
277
  * - <https://www.w3.org/ns/cid/v1>
278
278
  * - <https://w3id.org/security/multikey/v1>
279
279
  * - <https://w3id.org/fep/ef61>
280
+ * - <https://w3id.org/fep/7aa9>
280
281
  * - <https://purl.archive.org/socialweb/webfinger>
281
282
  * - <http://schema.org/>
282
283
  * @param options Options for the document loader.
@@ -311,10 +312,17 @@ export function getDocumentLoader(
311
312
  await validatePublicUrl(currentUrl);
312
313
  } catch (error) {
313
314
  if (error instanceof UrlError) {
314
- logger.error("Disallowed private URL: {url}", {
315
- url: currentUrl,
316
- error,
317
- });
315
+ if (error.reason === "dns") {
316
+ logger.debug("DNS lookup failed for {url}", {
317
+ url: currentUrl,
318
+ error,
319
+ });
320
+ } else {
321
+ logger.error("Disallowed private URL: {url}", {
322
+ url: currentUrl,
323
+ error,
324
+ });
325
+ }
318
326
  }
319
327
  throw error;
320
328
  }