@fedify/fedify 2.4.0-dev.2164 → 2.4.0-dev.2169

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 (71) hide show
  1. package/dist/{builder-BqRmnx7p.mjs → builder-B2d_Pt0j.mjs} +2 -2
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{compound-proof-CxDBdtNz.mjs → compound-proof-D28gMFqP.mjs} +2 -2
  4. package/dist/{deno-CizGaYeG.mjs → deno-DU8dvnWk.mjs} +1 -1
  5. package/dist/{docloader-BBFAItNB.mjs → docloader-CghLH7Zi.mjs} +2 -2
  6. package/dist/federation/builder.test.mjs +1 -1
  7. package/dist/federation/compound-fanout.test.mjs +3 -3
  8. package/dist/federation/handler-compound-proof.test.mjs +3 -3
  9. package/dist/federation/handler.test.mjs +5 -5
  10. package/dist/federation/hashlink-media.test.mjs +2 -2
  11. package/dist/federation/idempotency.test.mjs +2 -2
  12. package/dist/federation/metrics.test.mjs +1 -1
  13. package/dist/federation/middleware.test.mjs +7 -7
  14. package/dist/federation/mod.cjs +1 -1
  15. package/dist/federation/mod.js +1 -1
  16. package/dist/federation/outgoing-proof.test.mjs +5 -5
  17. package/dist/federation/portable-actor.test.mjs +3 -3
  18. package/dist/federation/portable-chain.test.mjs +3 -3
  19. package/dist/federation/portable-collection.test.mjs +4 -4
  20. package/dist/federation/portable-gateway-keys.test.mjs +4 -4
  21. package/dist/federation/portable-inbox.test.mjs +4 -4
  22. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  23. package/dist/federation/portable.test.mjs +3 -3
  24. package/dist/federation/send.test.mjs +3 -3
  25. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  26. package/dist/federation/tasks/tasks.test.mjs +2 -2
  27. package/dist/federation/temporal.test.mjs +1 -1
  28. package/dist/federation/webfinger.test.mjs +1 -1
  29. package/dist/{federation-DFCnp94y.cjs → federation-DrNgkLfJ.cjs} +3 -3
  30. package/dist/{http-R4g1McwE.cjs → http-5CJBdU8n.cjs} +208 -55
  31. package/dist/{http-Baovr6xq.js → http-BGpexPO7.js} +208 -55
  32. package/dist/{http-DRH0n8TD.mjs → http-Bd6rZlJX.mjs} +4 -4
  33. package/dist/{key-D5awqp7u.mjs → key-gIhVZO3p.mjs} +2 -2
  34. package/dist/{kv-cache-C7RWL7hz.mjs → kv-cache-D0qjSeWY.mjs} +1 -1
  35. package/dist/{kv-cache-Ct-KWRta.cjs → kv-cache-YRi_g8GB.cjs} +1 -1
  36. package/dist/{kv-cache-CZiBDLPi.js → kv-cache-iR55fqlk.js} +1 -1
  37. package/dist/{ld-CyliEU48.mjs → ld-BsTkRrwF.mjs} +3 -3
  38. package/dist/{metrics-CFBEehTc.mjs → metrics-jUDFfVgi.mjs} +1 -1
  39. package/dist/{middleware-B99JjvFn.mjs → middleware-Coqgp-K0.mjs} +14 -14
  40. package/dist/{middleware-CdpTFsa2.js → middleware-DlxMxVp5.js} +3 -3
  41. package/dist/{middleware-BmqEWsWP.mjs → middleware-Dq-OCmb6.mjs} +1 -1
  42. package/dist/mod.cjs +4 -4
  43. package/dist/mod.js +4 -4
  44. package/dist/nodeinfo/handler.test.mjs +1 -1
  45. package/dist/{owner-DKdtsrEq.mjs → owner-D3GoetXS.mjs} +3 -3
  46. package/dist/{portable-collection-uv4CuQXm.js → portable-collection-Bkdh_WpL.js} +1 -1
  47. package/dist/{portable-collection-Cb5cdPIU.mjs → portable-collection-C60_acmx.mjs} +2 -2
  48. package/dist/{portable-collection-UajqDrSL.cjs → portable-collection-CnlCamup.cjs} +1 -1
  49. package/dist/{portable-key-Bv1RdQ0n.mjs → portable-key-DyF5AnZo.mjs} +208 -55
  50. package/dist/{proof-CRTPWbVh.mjs → proof-CQAYqWdj.mjs} +4 -4
  51. package/dist/{send-2dULlZc8.mjs → send-DjkQrxt5.mjs} +3 -3
  52. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  53. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  54. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  55. package/dist/sig/compound-proof.test.mjs +2 -2
  56. package/dist/sig/http.test.mjs +2 -2
  57. package/dist/sig/key.test.mjs +1 -1
  58. package/dist/sig/ld.test.mjs +2 -2
  59. package/dist/sig/mod.cjs +2 -2
  60. package/dist/sig/mod.js +2 -2
  61. package/dist/sig/owner.test.mjs +1 -1
  62. package/dist/sig/portable-collection.test.mjs +1 -1
  63. package/dist/sig/portable-key.test.mjs +252 -6
  64. package/dist/sig/proof.test.mjs +3 -3
  65. package/dist/{temporal-Dhsk6aUT.mjs → temporal-oRKP803M.mjs} +1 -1
  66. package/dist/testing/kv.test.mjs +1 -1
  67. package/dist/utils/docloader.test.mjs +2 -2
  68. package/dist/utils/kv-cache.test.mjs +1 -1
  69. package/dist/utils/mod.cjs +1 -1
  70. package/dist/utils/mod.js +1 -1
  71. package/package.json +7 -7
@@ -8,8 +8,8 @@ import { t as assertInstanceOf } from "../assert_instance_of-mrXWWNY-.mjs";
8
8
  import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
9
9
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
10
10
  import { t as assert } from "../assert-D1Eafmd_.mjs";
11
- import { o as generateCryptoKeyPair } from "../key-D5awqp7u.mjs";
12
- import { a as compactJsonLd, f as isInvalidUrlTypeError, g as verifySignature, h as verifyJsonLd, i as attachSignature, n as UnsafeJsonLdError, o as createSignature, p as signJsonLd, s as detachSignature, u as hasSignatureLike } from "../ld-CyliEU48.mjs";
11
+ import { o as generateCryptoKeyPair } from "../key-gIhVZO3p.mjs";
12
+ import { a as compactJsonLd, f as isInvalidUrlTypeError, g as verifySignature, h as verifyJsonLd, i as attachSignature, n as UnsafeJsonLdError, o as createSignature, p as signJsonLd, s as detachSignature, u as hasSignatureLike } from "../ld-BsTkRrwF.mjs";
13
13
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
14
14
  import { CryptographicKey } from "@fedify/vocab";
15
15
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
package/dist/sig/mod.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_http = require("../http-R4g1McwE.cjs");
4
- const require_portable_collection = require("../portable-collection-UajqDrSL.cjs");
3
+ const require_http = require("../http-5CJBdU8n.cjs");
4
+ const require_portable_collection = require("../portable-collection-CnlCamup.cjs");
5
5
  exports.attachSignature = require_http.attachSignature;
6
6
  exports.createProof = require_http.createProof;
7
7
  exports.createSignature = require_http.createSignature;
package/dist/sig/mod.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { A as hasSignatureLike, B as fetchKey, D as detachSignature, E as createSignature, F as verifyJsonLd, H as generateCryptoKeyPair, I as verifySignature, N as signJsonLd, R as exportJwk, U as importJwk, V as fetchKeyDetailed, _ as verifyPortableObjectProof, a as signRequest, b as verifyProof, f as createProof, g as verifyObject, gt as validateAcceptSignature, ht as parseAcceptSignature, m as signObject, mt as fulfillAcceptSignature, o as verifyRequest, p as hasProofLike, pt as formatAcceptSignature, s as verifyRequestDetailed, w as attachSignature } from "../http-Baovr6xq.js";
4
- import { n as doesActorOwnKey, r as getKeyOwner, t as verifyPortableObject } from "../portable-collection-uv4CuQXm.js";
3
+ import { A as hasSignatureLike, B as fetchKey, D as detachSignature, E as createSignature, F as verifyJsonLd, H as generateCryptoKeyPair, I as verifySignature, N as signJsonLd, R as exportJwk, U as importJwk, V as fetchKeyDetailed, _ as verifyPortableObjectProof, a as signRequest, b as verifyProof, f as createProof, g as verifyObject, gt as validateAcceptSignature, ht as parseAcceptSignature, m as signObject, mt as fulfillAcceptSignature, o as verifyRequest, p as hasProofLike, pt as formatAcceptSignature, s as verifyRequestDetailed, w as attachSignature } from "../http-BGpexPO7.js";
4
+ import { n as doesActorOwnKey, r as getKeyOwner, t as verifyPortableObject } from "../portable-collection-Bkdh_WpL.js";
5
5
  export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, hasProofLike, hasSignatureLike, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyPortableObject, verifyPortableObjectProof, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
@@ -6,7 +6,7 @@ import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
6
6
  import "../std__assert-DvMDRPes.mjs";
7
7
  import { t as assert } from "../assert-D1Eafmd_.mjs";
8
8
  import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
9
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-DKdtsrEq.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-D3GoetXS.mjs";
10
10
  import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
11
11
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
12
12
  //#region src/sig/owner.test.ts
@@ -2,7 +2,7 @@ import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as ed25519PrivateKey, r as ed25519PublicKey } from "../keys-DIJNHW-Y.mjs";
5
- import { t as verifyPortableObject } from "../portable-collection-Cb5cdPIU.mjs";
5
+ import { t as verifyPortableObject } from "../portable-collection-C60_acmx.mjs";
6
6
  import { Collection, CollectionPage, Note, OrderedCollection, Person, traverseCollection } from "@fedify/vocab";
7
7
  import { test } from "@fedify/fixture";
8
8
  import { FetchError, encodeMultibase, exportDidKey, preloadedContexts } from "@fedify/vocab-runtime";
@@ -2,12 +2,13 @@ import { Temporal } from "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
5
- import { i as fetchKey } from "../key-D5awqp7u.mjs";
6
- import { h as verifyJsonLd, p as signJsonLd } from "../ld-CyliEU48.mjs";
7
- import { d as verifyProof, r as createProof } from "../proof-CRTPWbVh.mjs";
8
- import { d as verifyRequest, f as verifyRequestDetailed, l as signRequest } from "../http-DRH0n8TD.mjs";
5
+ import { a as fetchKeyDetailed, i as fetchKey } from "../key-gIhVZO3p.mjs";
6
+ import { h as verifyJsonLd, p as signJsonLd } from "../ld-BsTkRrwF.mjs";
7
+ import { d as verifyProof, r as createProof } from "../proof-CQAYqWdj.mjs";
8
+ import { n as resolvePortableActorKey } from "../portable-key-DyF5AnZo.mjs";
9
+ import { d as verifyRequest, f as verifyRequestDetailed, l as signRequest } from "../http-Bd6rZlJX.mjs";
9
10
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
10
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-DKdtsrEq.mjs";
11
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-D3GoetXS.mjs";
11
12
  import { t as KvKeyCache } from "../keycache-PiOM9pM0.mjs";
12
13
  import { Create, CryptographicKey, Multikey, Note, Person } from "@fedify/vocab";
13
14
  import { test } from "@fedify/fixture";
@@ -965,7 +966,21 @@ test("verifyRequest() tries the gateways of ap: key IDs in order", async () => {
965
966
  documentLoader: many,
966
967
  contextLoader
967
968
  })).verified);
968
- deepStrictEqual(many.fetched, gateways.slice(0, 5).map((g) => compatibleId(g)));
969
+ deepStrictEqual(many.fetched, gateways.slice(0, 3).map((g) => compatibleId(g)));
970
+ for (const [index, expected] of [[2, true], [3, false]]) {
971
+ const documentLoader = createLoader({ [compatibleId(gateways[index])]: signed });
972
+ strictEqual(await verifyRequest(await signedRequest(void 0, hinted(...gateways)), {
973
+ documentLoader,
974
+ contextLoader
975
+ }) != null, expected, `gateway ${index + 1}`);
976
+ deepStrictEqual(documentLoader.fetched, gateways.slice(0, 3).map((g) => compatibleId(g)), `gateway ${index + 1}`);
977
+ }
978
+ const sparse = createLoader({ [compatibleId(gateways[2])]: signed });
979
+ ok(await verifyRequest(await signedRequest(void 0, hinted("not a gateway", gateways[0], gateways[0].toUpperCase(), "https://gw.example/path", gateways[1], gateways[2])), {
980
+ documentLoader: sparse,
981
+ contextLoader
982
+ }) != null);
983
+ deepStrictEqual(sparse.fetched, gateways.slice(0, 3).map((g) => compatibleId(g)));
969
984
  });
970
985
  function failingLoader(responses) {
971
986
  const fetched = [];
@@ -1189,5 +1204,236 @@ test("verifyRequest() does not cache keys at ap: key IDs it could not process",
1189
1204
  strictEqual((await verifyRequest(await signedRequest(void 0, hintedKeyId), options))?.ownerId?.href, parseIri(actorId).href);
1190
1205
  strictEqual(documentLoader.fetched.length, 2);
1191
1206
  });
1207
+ /**
1208
+ * A loader that serves the given responses, and never responds for the URLs
1209
+ * in `hanging`. A hanging response is given up when its signal aborts,
1210
+ * unless `ignoreSignal` is set.
1211
+ */
1212
+ function controlledLoader(responses, hanging, { ignoreSignal = false, delays = {} } = {}) {
1213
+ const fetched = [];
1214
+ const signals = [];
1215
+ const respond = failingLoader(responses);
1216
+ const loader = async (url, options) => {
1217
+ fetched.push(url);
1218
+ signals.push(options?.signal);
1219
+ const signal = ignoreSignal ? void 0 : options?.signal;
1220
+ const delay = delays[url];
1221
+ if (delay != null) await new Promise((resolve) => setTimeout(resolve, delay));
1222
+ if (hanging.includes(url)) return await new Promise((_, reject) => {
1223
+ signal?.addEventListener("abort", () => reject(signal.reason));
1224
+ });
1225
+ return await respond(url);
1226
+ };
1227
+ return Object.assign(loader, {
1228
+ fetched,
1229
+ signals
1230
+ });
1231
+ }
1232
+ function isTimeoutError(error) {
1233
+ return error instanceof DOMException && error.name === "TimeoutError";
1234
+ }
1235
+ test("resolvePortableActorKey() gives up gateways that do not respond in time", async () => {
1236
+ const signed = await sign(await apActorJson());
1237
+ for (const ignoreSignal of [false, true]) {
1238
+ const documentLoader = controlledLoader({ [compatibleId(gw2)]: signed }, [compatibleId(gw1)], { ignoreSignal });
1239
+ const resolution = await resolvePortableActorKey(hinted(gw1, gw2), {
1240
+ documentLoader,
1241
+ contextLoader,
1242
+ lookupTimeout: 50
1243
+ });
1244
+ strictEqual(resolution.type, "unavailable", `ignoreSignal: ${ignoreSignal}`);
1245
+ if (resolution.type === "unavailable") strictEqual(resolution.cacheable, false);
1246
+ deepStrictEqual(documentLoader.fetched, [compatibleId(gw1)]);
1247
+ const [signal] = documentLoader.signals;
1248
+ ok(signal?.aborted);
1249
+ ok(isTimeoutError(signal.reason));
1250
+ }
1251
+ });
1252
+ test("resolvePortableActorKey() caches timeouts only as failures to fetch", async () => {
1253
+ const invalid = await apActorJson();
1254
+ const cases = [
1255
+ {
1256
+ name: "the only gateway times out",
1257
+ responses: {},
1258
+ hanging: [compatibleId(gw1)],
1259
+ hints: [gw1],
1260
+ cacheable: true
1261
+ },
1262
+ {
1263
+ name: "a gateway responds with 404, and the last one times out",
1264
+ responses: { [compatibleId(gw1)]: 404 },
1265
+ hanging: [compatibleId(gw2)],
1266
+ hints: [gw1, gw2],
1267
+ cacheable: true
1268
+ },
1269
+ {
1270
+ name: "a gateway serves an invalid document, and the last one times out",
1271
+ responses: { [compatibleId(gw1)]: invalid },
1272
+ hanging: [compatibleId(gw2)],
1273
+ hints: [gw1, gw2],
1274
+ cacheable: false
1275
+ },
1276
+ {
1277
+ name: "the document loader cannot resolve the ap: URI in time",
1278
+ responses: {},
1279
+ hanging: [actorId],
1280
+ hints: [],
1281
+ cacheable: true
1282
+ }
1283
+ ];
1284
+ for (const { name, responses, hanging, hints, cacheable } of cases) {
1285
+ const documentLoader = controlledLoader(responses, hanging);
1286
+ const resolution = await resolvePortableActorKey(hinted(...hints), {
1287
+ documentLoader,
1288
+ contextLoader,
1289
+ lookupTimeout: 50
1290
+ });
1291
+ strictEqual(resolution.type, "unavailable", name);
1292
+ if (resolution.type !== "unavailable") continue;
1293
+ strictEqual(resolution.cacheable, cacheable, name);
1294
+ ok(!(resolution.error instanceof FetchError), name);
1295
+ if (hanging.length === 1 && hints.length < 2) ok(isTimeoutError(resolution.error), name);
1296
+ }
1297
+ });
1298
+ test("resolvePortableActorKey() shares one timeout among all gateways", async () => {
1299
+ const documentLoader = controlledLoader({ [compatibleId(gw1)]: 404 }, [compatibleId(gw2)], { delays: { [compatibleId(gw1)]: 250 } });
1300
+ const started = Date.now();
1301
+ const resolution = await resolvePortableActorKey(hinted(gw1, gw2), {
1302
+ documentLoader,
1303
+ contextLoader,
1304
+ lookupTimeout: 300
1305
+ });
1306
+ const elapsed = Date.now() - started;
1307
+ ok(elapsed < 500, `took ${elapsed} ms`);
1308
+ strictEqual(resolution.type, "unavailable");
1309
+ deepStrictEqual(documentLoader.fetched, [compatibleId(gw1), compatibleId(gw2)]);
1310
+ ok(documentLoader.signals[1]?.aborted);
1311
+ });
1312
+ test("resolvePortableActorKey() bounds loading the contexts of actor documents", async () => {
1313
+ const documentLoader = controlledLoader({ [compatibleId(gw1)]: await sign(await apActorJson()) }, []);
1314
+ const hangingContextLoader = (_url, options) => new Promise((_, reject) => {
1315
+ options?.signal?.addEventListener("abort", () => reject(options.signal.reason));
1316
+ });
1317
+ const resolution = await resolvePortableActorKey(hinted(gw1, gw2), {
1318
+ documentLoader,
1319
+ contextLoader: hangingContextLoader,
1320
+ lookupTimeout: 50
1321
+ });
1322
+ strictEqual(resolution.type, "unavailable");
1323
+ if (resolution.type === "unavailable") strictEqual(resolution.cacheable, false);
1324
+ deepStrictEqual(documentLoader.fetched, [compatibleId(gw1)]);
1325
+ });
1326
+ test("resolvePortableActorKey() ignores what is resolved after the timeout", async () => {
1327
+ let verifiedLate = () => {};
1328
+ const late = new Promise((resolve) => verifiedLate = resolve);
1329
+ let lookupDone = () => {};
1330
+ const done = new Promise((resolve) => lookupDone = resolve);
1331
+ const slowKeyCache = {
1332
+ async get() {
1333
+ await done;
1334
+ },
1335
+ set() {
1336
+ verifiedLate();
1337
+ return Promise.resolve();
1338
+ }
1339
+ };
1340
+ const documentLoader = controlledLoader({ [compatibleId(gw1)]: await sign(await apActorJson()) }, []);
1341
+ const resolution = await resolvePortableActorKey(hinted(gw1), {
1342
+ documentLoader,
1343
+ contextLoader,
1344
+ keyCache: slowKeyCache,
1345
+ lookupTimeout: 300
1346
+ });
1347
+ lookupDone();
1348
+ strictEqual(resolution.type, "unavailable");
1349
+ if (resolution.type === "unavailable") strictEqual(resolution.cacheable, false);
1350
+ await late;
1351
+ const lateRejection = controlledLoader({}, [], { delays: { [compatibleId(gw1)]: 60 } });
1352
+ strictEqual((await resolvePortableActorKey(hinted(gw1), {
1353
+ documentLoader: lateRejection,
1354
+ contextLoader,
1355
+ lookupTimeout: 20
1356
+ })).type, "unavailable");
1357
+ await new Promise((resolve) => setTimeout(resolve, 80));
1358
+ });
1359
+ test("resolvePortableActorKey() validates the lookup timeout", async () => {
1360
+ const documentLoader = controlledLoader({}, []);
1361
+ for (const lookupTimeout of [
1362
+ -1,
1363
+ NaN,
1364
+ Infinity,
1365
+ 2 ** 31
1366
+ ]) {
1367
+ let error;
1368
+ try {
1369
+ await resolvePortableActorKey(hinted(gw1), {
1370
+ documentLoader,
1371
+ contextLoader,
1372
+ lookupTimeout
1373
+ });
1374
+ } catch (e) {
1375
+ error = e;
1376
+ }
1377
+ ok(error instanceof RangeError, String(lookupTimeout));
1378
+ }
1379
+ const resolution = await resolvePortableActorKey(hinted(gw1), {
1380
+ documentLoader,
1381
+ contextLoader,
1382
+ lookupTimeout: 0
1383
+ });
1384
+ strictEqual(resolution.type, "unavailable");
1385
+ if (resolution.type === "unavailable") strictEqual(resolution.cacheable, false);
1386
+ deepStrictEqual(documentLoader.fetched, []);
1387
+ });
1388
+ test("fetchKeyDetailed() caches keys at ap: key IDs that time out as fetch failures", async () => {
1389
+ const cases = [{
1390
+ responses: { [compatibleId(gw1)]: 404 },
1391
+ hanging: [compatibleId(gw2)],
1392
+ cached: true
1393
+ }, {
1394
+ responses: {},
1395
+ hanging: [compatibleId(gw1)],
1396
+ cached: false
1397
+ }];
1398
+ for (const { responses, hanging, cached } of cases) {
1399
+ const documentLoader = controlledLoader(responses, hanging);
1400
+ const keyCache = new KvKeyCache(new MemoryKvStore(), ["pk"]);
1401
+ const options = {
1402
+ documentLoader,
1403
+ contextLoader,
1404
+ keyCache,
1405
+ portableKeyResolvers: {
1406
+ gatewayKey: () => Promise.resolve({ type: "legacy" }),
1407
+ actorKey: (keyId) => resolvePortableActorKey(keyId, {
1408
+ documentLoader,
1409
+ contextLoader,
1410
+ lookupTimeout: 50
1411
+ })
1412
+ }
1413
+ };
1414
+ const hintedKeyId = hinted(gw1, gw2);
1415
+ for (let i = 0; i < 2; i++) {
1416
+ const result = await fetchKeyDetailed(hintedKeyId, CryptographicKey, options);
1417
+ strictEqual(result.key, null);
1418
+ strictEqual(result.cached, cached && i > 0, `${cached}, ${i}`);
1419
+ ok(result.fetchError == null || !("status" in result.fetchError), "a timeout has no HTTP status");
1420
+ }
1421
+ strictEqual(documentLoader.fetched.filter((url) => url === compatibleId(gw1)).length, cached ? 1 : 2);
1422
+ }
1423
+ });
1424
+ test("verifyRequestDetailed() reports keys at ap: key IDs that time out as fetch errors", async () => {
1425
+ const timeout = new DOMException("Timed out", "TimeoutError");
1426
+ const documentLoader = () => Promise.reject(timeout);
1427
+ for (const spec of specs) {
1428
+ const result = await verifyRequestDetailed(await signedRequest(spec, hinted(gw1)), {
1429
+ documentLoader,
1430
+ contextLoader,
1431
+ spec
1432
+ });
1433
+ ok(!result.verified, spec);
1434
+ strictEqual(result.reason.type, "keyFetchError", spec);
1435
+ if (result.reason.type === "keyFetchError") ok(!("status" in result.reason.result), spec);
1436
+ }
1437
+ });
1192
1438
  //#endregion
1193
1439
  export {};
@@ -10,10 +10,10 @@ import "../std__assert-DvMDRPes.mjs";
10
10
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
11
11
  import { t as assert } from "../assert-D1Eafmd_.mjs";
12
12
  import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-4IJqPYos.mjs";
13
- import { a as signObject, c as verifyPortableObjectProof, d as verifyProof, i as hasProofLike, r as createProof, s as verifyObject } from "../proof-CRTPWbVh.mjs";
14
- import { d as verifyRequest } from "../http-DRH0n8TD.mjs";
13
+ import { a as signObject, c as verifyPortableObjectProof, d as verifyProof, i as hasProofLike, r as createProof, s as verifyObject } from "../proof-CQAYqWdj.mjs";
14
+ import { d as verifyRequest } from "../http-Bd6rZlJX.mjs";
15
15
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
16
- import { t as getAuthenticatedDocumentLoader } from "../docloader-BBFAItNB.mjs";
16
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-CghLH7Zi.mjs";
17
17
  import { Create, DataIntegrityProof, Document, Multikey, Note, PUBLIC_COLLECTION, Place, Translation } from "@fedify/vocab";
18
18
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
19
19
  import { decodeMultibase, encodeMultibase, exportDidKey, exportMultibaseKey, formatIri, importMultibaseKey, parseIri } from "@fedify/vocab-runtime";
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { c as getNormalizationContextLoader } from "./ld-CyliEU48.mjs";
4
+ import { c as getNormalizationContextLoader } from "./ld-BsTkRrwF.mjs";
5
5
  import jsonld from "@fedify/vocab-runtime/jsonld";
6
6
  //#region src/federation/temporal.ts
7
7
  function isPlainObject(value) {
@@ -6,7 +6,7 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
6
6
  import { t as ManualClockKvStore } from "../kv-DBRWVx3Q.mjs";
7
7
  import { n as baseOptions, o as stringSchema, t as MockQueue } from "../tasks-IG3pHfvZ.mjs";
8
8
  import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
9
- import { o as createFederation } from "../middleware-B99JjvFn.mjs";
9
+ import { o as createFederation } from "../middleware-Coqgp-K0.mjs";
10
10
  //#region src/testing/kv.test.ts
11
11
  test("ManualClockKvStore keeps an entry at its exact expiration instant", async () => {
12
12
  const kv = new ManualClockKvStore();
@@ -5,9 +5,9 @@ import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
6
6
  import "../std__assert-DvMDRPes.mjs";
7
7
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
8
- import { d as verifyRequest } from "../http-DRH0n8TD.mjs";
8
+ import { d as verifyRequest } from "../http-Bd6rZlJX.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-DIJNHW-Y.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-BBFAItNB.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-CghLH7Zi.mjs";
11
11
  import { configure, reset } from "@logtape/logtape";
12
12
  import { mockDocumentLoader, test } from "@fedify/fixture";
13
13
  import { FetchError, UrlError } from "@fedify/vocab-runtime";
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as kvCache, t as MockKvStore } from "../kv-cache-C7RWL7hz.mjs";
4
+ import { n as kvCache, t as MockKvStore } from "../kv-cache-D0qjSeWY.mjs";
5
5
  import { deepStrictEqual, throws } from "node:assert";
6
6
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
7
7
  import { preloadedContexts } from "@fedify/vocab-runtime";
@@ -1,5 +1,5 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_kv_cache = require("../kv-cache-Ct-KWRta.cjs");
3
+ const require_kv_cache = require("../kv-cache-YRi_g8GB.cjs");
4
4
  exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
5
5
  exports.kvCache = require_kv_cache.kvCache;
package/dist/utils/mod.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-CZiBDLPi.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-iR55fqlk.js";
4
4
  export { getAuthenticatedDocumentLoader, kvCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "2.4.0-dev.2164+db2b8571",
3
+ "version": "2.4.0-dev.2169+0a45df07",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -151,10 +151,10 @@
151
151
  "structured-field-values": "^2.0.4",
152
152
  "temporal-polyfill": "^1.0.1",
153
153
  "urlpattern-polyfill": "^10.1.0",
154
- "@fedify/webfinger": "2.4.0-dev.2164+db2b8571",
155
- "@fedify/uri-template": "2.4.0-dev.2164+db2b8571",
156
- "@fedify/vocab": "2.4.0-dev.2164+db2b8571",
157
- "@fedify/vocab-runtime": "2.4.0-dev.2164+db2b8571"
154
+ "@fedify/vocab": "2.4.0-dev.2169+0a45df07",
155
+ "@fedify/uri-template": "2.4.0-dev.2169+0a45df07",
156
+ "@fedify/vocab-runtime": "2.4.0-dev.2169+0a45df07",
157
+ "@fedify/webfinger": "2.4.0-dev.2169+0a45df07"
158
158
  },
159
159
  "devDependencies": {
160
160
  "@std/assert": "npm:@jsr/std__assert@^0.226.0",
@@ -166,8 +166,8 @@
166
166
  "tsx": "^4.21.0",
167
167
  "typescript": "^6.0.0",
168
168
  "wrangler": "^4.17.0",
169
- "@fedify/fixture": "2.0.0",
170
- "@fedify/vocab-tools": "^2.4.0-dev.2164+db2b8571"
169
+ "@fedify/vocab-tools": "^2.4.0-dev.2169+0a45df07",
170
+ "@fedify/fixture": "2.0.0"
171
171
  },
172
172
  "scripts": {
173
173
  "build:self": "tsdown",