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

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 (103) hide show
  1. package/dist/{builder-B2d_Pt0j.mjs → builder-CFF0YNTp.mjs} +3 -3
  2. package/dist/{circuit-breaker-C5NqoLBJ.mjs → circuit-breaker-XJ53md4S.mjs} +16 -11
  3. package/dist/compat/mod.d.cts +1 -1
  4. package/dist/compat/mod.d.ts +1 -1
  5. package/dist/compat/transformers.test.mjs +1 -1
  6. package/dist/{compound-proof-D28gMFqP.mjs → compound-proof-F2jjkrt0.mjs} +3 -3
  7. package/dist/{context-BykNUf04.d.ts → context-9T--NSo4.d.ts} +55 -1
  8. package/dist/{context-L0Fnib9j.d.cts → context-CDcAgm4l.d.cts} +55 -1
  9. package/dist/{deno-DU8dvnWk.mjs → deno-EopndaNb.mjs} +1 -1
  10. package/dist/{docloader-CghLH7Zi.mjs → docloader-u6zzOExF.mjs} +25 -17
  11. package/dist/federation/builder.test.mjs +1 -1
  12. package/dist/federation/circuit-breaker.test.mjs +50 -1
  13. package/dist/federation/compound-fanout.test.mjs +3 -3
  14. package/dist/federation/handler-compound-proof.test.mjs +3 -3
  15. package/dist/federation/handler.test.mjs +5 -5
  16. package/dist/federation/hashlink-media.test.mjs +2 -2
  17. package/dist/federation/idempotency.test.mjs +2 -2
  18. package/dist/federation/keycache.test.mjs +1 -1
  19. package/dist/federation/metrics.test.mjs +1 -1
  20. package/dist/federation/middleware.test.mjs +137 -13
  21. package/dist/federation/mod.cjs +1 -1
  22. package/dist/federation/mod.d.cts +2 -2
  23. package/dist/federation/mod.d.ts +2 -2
  24. package/dist/federation/mod.js +1 -1
  25. package/dist/federation/outgoing-proof.test.mjs +5 -5
  26. package/dist/federation/portable-actor.test.mjs +3 -3
  27. package/dist/federation/portable-chain.test.mjs +3 -3
  28. package/dist/federation/portable-collection.test.mjs +4 -4
  29. package/dist/federation/portable-gateway-keys.test.mjs +6 -6
  30. package/dist/federation/portable-inbox.test.mjs +35 -5
  31. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  32. package/dist/federation/portable-route-activity.test.d.mts +2 -0
  33. package/dist/federation/portable-route-activity.test.mjs +259 -0
  34. package/dist/federation/portable.test.mjs +3 -3
  35. package/dist/federation/send.test.mjs +3 -3
  36. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  37. package/dist/federation/tasks/tasks.test.mjs +2 -2
  38. package/dist/federation/temporal.test.mjs +1 -1
  39. package/dist/federation/webfinger.test.mjs +1 -1
  40. package/dist/{federation-DrNgkLfJ.cjs → federation-BSS2dUO7.cjs} +38 -21
  41. package/dist/{http-BGpexPO7.js → http-BqN5kyUf.js} +219 -87
  42. package/dist/{http-Cok5-vIC.d.ts → http-BrwKINQn.d.cts} +29 -1
  43. package/dist/{http-5CJBdU8n.cjs → http-CCr2_ipG.cjs} +236 -86
  44. package/dist/{http-DC1cqAQ2.d.cts → http-DGx0KOws.d.ts} +29 -1
  45. package/dist/{http-Bd6rZlJX.mjs → http-Y1ObT1A8.mjs} +180 -92
  46. package/dist/{key-gIhVZO3p.mjs → key-DyXf88bq.mjs} +4 -4
  47. package/dist/{key-owner-evidence-Bo3yaeL5.mjs → key-owner-evidence-APB6NpSk.mjs} +1 -1
  48. package/dist/{keycache-PiOM9pM0.mjs → keycache-Da8A8mZa.mjs} +1 -1
  49. package/dist/{kv-cache-iR55fqlk.js → kv-cache-C02XitwK.js} +24 -16
  50. package/dist/{kv-cache-D0qjSeWY.mjs → kv-cache-C8YjNAi_.mjs} +1 -1
  51. package/dist/{kv-cache-YRi_g8GB.cjs → kv-cache-DUXluAc0.cjs} +23 -15
  52. package/dist/{ld-BsTkRrwF.mjs → ld-oQj6j_hP.mjs} +3 -3
  53. package/dist/{metrics-jUDFfVgi.mjs → metrics-zMe834ID.mjs} +1 -1
  54. package/dist/{middleware-Coqgp-K0.mjs → middleware-Bdu2-OPD.mjs} +37 -25
  55. package/dist/{middleware-DlxMxVp5.js → middleware-CaR2MRWY.js} +39 -22
  56. package/dist/{middleware-Dq-OCmb6.mjs → middleware-Ck9yghxs.mjs} +1 -1
  57. package/dist/{mod-DK0y9fd-.d.ts → mod-B3OBLj5g.d.ts} +1 -1
  58. package/dist/{mod-B5z_q9TH.d.ts → mod-C5Mwx5ty.d.ts} +5 -1
  59. package/dist/{mod--jv6vyrP.d.ts → mod-Ck9_lSJB.d.ts} +1 -1
  60. package/dist/{mod-BLOXGs6m.d.cts → mod-D58KCqUg.d.cts} +1 -1
  61. package/dist/{mod-CPPqkyV_.d.cts → mod-DHTuu3l8.d.cts} +1 -1
  62. package/dist/{mod-BA_F2x53.d.cts → mod-Dp3Ij7sw.d.cts} +5 -1
  63. package/dist/mod.cjs +4 -4
  64. package/dist/mod.d.cts +5 -5
  65. package/dist/mod.d.ts +5 -5
  66. package/dist/mod.js +4 -4
  67. package/dist/nodeinfo/handler.test.mjs +1 -1
  68. package/dist/{owner-D3GoetXS.mjs → owner-Dem4fbwc.mjs} +5 -5
  69. package/dist/{portable-collection-Bkdh_WpL.js → portable-collection-BEqLrMW3.js} +1 -1
  70. package/dist/{portable-collection-C60_acmx.mjs → portable-collection-BL6aZlQ0.mjs} +2 -2
  71. package/dist/{portable-collection-CnlCamup.cjs → portable-collection-DJe_bk50.cjs} +1 -1
  72. package/dist/{portable-key-DyF5AnZo.mjs → portable-key-Duue9Y2Y.mjs} +2 -2
  73. package/dist/{portable-key-id-Bg259c4Z.mjs → portable-key-id-Ca30-hOa.mjs} +45 -1
  74. package/dist/{proof-CQAYqWdj.mjs → proof-C9115DX_.mjs} +5 -5
  75. package/dist/{send-DjkQrxt5.mjs → send-D0hxFFRB.mjs} +3 -3
  76. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  77. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  78. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  79. package/dist/sig/compound-proof.test.mjs +2 -2
  80. package/dist/sig/http.test.mjs +495 -23
  81. package/dist/sig/key-owner-evidence.test.mjs +2 -2
  82. package/dist/sig/key.test.mjs +1 -1
  83. package/dist/sig/ld.test.mjs +2 -2
  84. package/dist/sig/mod.cjs +2 -2
  85. package/dist/sig/mod.d.cts +2 -2
  86. package/dist/sig/mod.d.ts +2 -2
  87. package/dist/sig/mod.js +2 -2
  88. package/dist/sig/owner.test.mjs +1 -1
  89. package/dist/sig/portable-collection.test.mjs +1 -1
  90. package/dist/sig/portable-key-id.test.d.mts +2 -0
  91. package/dist/sig/portable-key-id.test.mjs +67 -0
  92. package/dist/sig/portable-key.test.mjs +7 -7
  93. package/dist/sig/proof.test.mjs +3 -3
  94. package/dist/{temporal-oRKP803M.mjs → temporal-DKchpKyp.mjs} +1 -1
  95. package/dist/testing/kv.test.mjs +1 -1
  96. package/dist/testing/mod.d.mts +52 -0
  97. package/dist/utils/docloader.test.mjs +93 -2
  98. package/dist/utils/kv-cache.test.mjs +1 -1
  99. package/dist/utils/mod.cjs +1 -1
  100. package/dist/utils/mod.d.cts +1 -1
  101. package/dist/utils/mod.d.ts +1 -1
  102. package/dist/utils/mod.js +1 -1
  103. package/package.json +7 -7
@@ -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-D3GoetXS.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-Dem4fbwc.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-C60_acmx.mjs";
5
+ import { t as verifyPortableObject } from "../portable-collection-BL6aZlQ0.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";
@@ -0,0 +1,2 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";
@@ -0,0 +1,67 @@
1
+ import "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
5
+ import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
6
+ import "../std__assert-DvMDRPes.mjs";
7
+ import { t as assert } from "../assert-D1Eafmd_.mjs";
8
+ import { f as isSameObjectId, t as getAuthenticationOrigin } from "../portable-key-id-Ca30-hOa.mjs";
9
+ import { r as ed25519PublicKey } from "../keys-DIJNHW-Y.mjs";
10
+ import { test } from "@fedify/fixture";
11
+ import { exportDidKey, parseIri } from "@fedify/vocab-runtime";
12
+ //#region src/sig/portable-key-id.test.ts
13
+ const did = await exportDidKey(ed25519PublicKey.publicKey);
14
+ const otherDid = await exportDidKey((await crypto.subtle.generateKey("Ed25519", true, ["sign", "verify"])).publicKey);
15
+ test("getAuthenticationOrigin()", () => {
16
+ for (const id of [
17
+ parseIri(`ap://${did}/actor`),
18
+ parseIri(`ap+ef61://${did}/actor`),
19
+ parseIri(`ap+ef61://${encodeURIComponent(did)}/actor#main-key`),
20
+ parseIri(`ap://${did}/actor?@gateway=https%3A%2F%2Fgw.example`),
21
+ new URL(`https://gw.example/.well-known/apgateway/${did}/actor`),
22
+ new URL(`https://gw2.example/.well-known/apgateway/${did}/objects/1`),
23
+ new URL(`${did}#${did.slice(8)}`)
24
+ ]) assertEquals(getAuthenticationOrigin(id), did, id.href);
25
+ assertEquals(getAuthenticationOrigin(parseIri(`ap+ef61://${otherDid}/actor`)), otherDid);
26
+ assertEquals(getAuthenticationOrigin(new URL("https://example.com:443/users/alice")), "https://example.com");
27
+ assertEquals(getAuthenticationOrigin(new URL("http://example.com:8080/users/alice")), "http://example.com:8080");
28
+ for (const id of [
29
+ new URL(`https://gw.example/.well-known/apgateway/${did}/actor?@gateway=https%3A%2F%2Fgw.example`),
30
+ new URL("https://gw.example/.well-known/apgateway/did:key:invalid!/a"),
31
+ new URL(`https://gw.example/.well-known/apgateway/${did}`),
32
+ new URL(`https://gw.example/.well-known/apgateway/${did}/actor%ZZ`),
33
+ new URL("urn:uuid:3d6f4c1e-2f8b-4d1a-9c6e-7b8a9d0e1f2a"),
34
+ new URL("tag:example.com,2026:actor")
35
+ ]) assertEquals(getAuthenticationOrigin(id), null, id.href);
36
+ });
37
+ test("isSameObjectId()", () => {
38
+ const portable = parseIri(`ap+ef61://${did}/activities/1`);
39
+ for (const id of [
40
+ parseIri(`ap://${did}/activities/1`),
41
+ parseIri(`ap+ef61://${encodeURIComponent(did)}/activities/1`),
42
+ parseIri(`ap://${did}/activities/1?@gateway=https%3A%2F%2Fgw.example`),
43
+ new URL(`https://gw.example/.well-known/apgateway/${did}/activities/1`),
44
+ new URL(`https://gw2.example/.well-known/apgateway/${did}/activities/1`)
45
+ ]) {
46
+ assert(isSameObjectId(portable, id), id.href);
47
+ assert(isSameObjectId(id, portable), id.href);
48
+ }
49
+ for (const id of [
50
+ parseIri(`ap+ef61://${otherDid}/activities/1`),
51
+ parseIri(`ap+ef61://${did}/activities/2`),
52
+ parseIri(`ap+ef61://${did}/activities/1#fragment`),
53
+ new URL(`https://gw.example/.well-known/apgateway/${did}/activities/1%ZZ`),
54
+ new URL("https://gw.example/activities/1")
55
+ ]) {
56
+ assertFalse(isSameObjectId(portable, id), id.href);
57
+ assertFalse(isSameObjectId(id, portable), id.href);
58
+ }
59
+ const malformed = new URL(`https://gw.example/.well-known/apgateway/${did}/activities/1%ZZ`);
60
+ assertFalse(isSameObjectId(malformed, malformed));
61
+ const http = new URL("https://example.com/activities/1");
62
+ assert(isSameObjectId(http, new URL("https://example.com/activities/1")));
63
+ assertFalse(isSameObjectId(http, new URL("https://example.com/activities/1#a")));
64
+ assertFalse(isSameObjectId(http, new URL("https://example.com/activities/1?a")));
65
+ });
66
+ //#endregion
67
+ export {};
@@ -2,14 +2,14 @@ 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 { 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";
5
+ import { a as fetchKeyDetailed, i as fetchKey } from "../key-DyXf88bq.mjs";
6
+ import { h as verifyJsonLd, p as signJsonLd } from "../ld-oQj6j_hP.mjs";
7
+ import { d as verifyProof, r as createProof } from "../proof-C9115DX_.mjs";
8
+ import { n as resolvePortableActorKey } from "../portable-key-Duue9Y2Y.mjs";
9
+ import { f as verifyRequest, l as signRequest, p as verifyRequestDetailed } from "../http-Y1ObT1A8.mjs";
10
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";
11
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-D3GoetXS.mjs";
12
- import { t as KvKeyCache } from "../keycache-PiOM9pM0.mjs";
11
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-Dem4fbwc.mjs";
12
+ import { t as KvKeyCache } from "../keycache-Da8A8mZa.mjs";
13
13
  import { Create, CryptographicKey, Multikey, Note, Person } from "@fedify/vocab";
14
14
  import { test } from "@fedify/fixture";
15
15
  import { FetchError, encodeMultibase, exportDidKey, exportSpki, parseIri, preloadedContexts } from "@fedify/vocab-runtime";
@@ -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-CQAYqWdj.mjs";
14
- import { d as verifyRequest } from "../http-Bd6rZlJX.mjs";
13
+ import { a as signObject, c as verifyPortableObjectProof, d as verifyProof, i as hasProofLike, r as createProof, s as verifyObject } from "../proof-C9115DX_.mjs";
14
+ import { f as verifyRequest } from "../http-Y1ObT1A8.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-CghLH7Zi.mjs";
16
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-u6zzOExF.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-BsTkRrwF.mjs";
4
+ import { c as getNormalizationContextLoader } from "./ld-oQj6j_hP.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-Coqgp-K0.mjs";
9
+ import { o as createFederation } from "../middleware-Bdu2-OPD.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();
@@ -2275,6 +2275,35 @@ interface FederationOptions<TContextData> {
2275
2275
  * @since 1.3.0
2276
2276
  */
2277
2277
  userAgent?: GetUserAgentOptions | string;
2278
+ /**
2279
+ * The timeout for each call of the built-in document loader, context
2280
+ * loader, and authenticated document loader, e.g., when Fedify fetches
2281
+ * a key to verify a signature. The timeout is shared by all the steps of
2282
+ * a call, including every redirect it follows, retries, and reading the
2283
+ * response body. It does not cover the time spent reading from or
2284
+ * writing to the cache.
2285
+ *
2286
+ * A timed-out call throws a `FetchError` without a response, whose
2287
+ * `cause` is a `DOMException` named `"TimeoutError"`, so that, e.g.,
2288
+ * a key fetch that times out is reported as a `keyFetchError` and cached
2289
+ * like other failures to fetch a key.
2290
+ *
2291
+ * It does not affect loaders made by
2292
+ * {@link FederationOptions.documentLoaderFactory},
2293
+ * {@link FederationOptions.contextLoaderFactory}, or
2294
+ * {@link FederationOptions.authenticatedDocumentLoaderFactory}.
2295
+ * Note that if only {@link FederationOptions.documentLoaderFactory} is
2296
+ * set, it also makes context loaders.
2297
+ *
2298
+ * Set it to `null` to turn off the timeout.
2299
+ *
2300
+ * 10 seconds by default.
2301
+ * @throws {RangeError} If the duration is not positive, is longer than
2302
+ * about 24.8 days, or is given in calendar units
2303
+ * such as months.
2304
+ * @since 2.4.0
2305
+ */
2306
+ documentLoaderTimeout?: Temporal.Duration | Temporal.DurationLike | null;
2278
2307
  /**
2279
2308
  * A callback that handles errors during outbox processing. Note that this
2280
2309
  * callback can be called multiple times for the same activity, because
@@ -2303,6 +2332,29 @@ interface FederationOptions<TContextData> {
2303
2332
  * By default, the window is an hour.
2304
2333
  */
2305
2334
  signatureTimeWindow?: Temporal.Duration | Temporal.DurationLike | false;
2335
+ /**
2336
+ * The maximum number of [RFC 9421] signatures of an incoming request to
2337
+ * verify, e.g., in the inbox and in
2338
+ * {@link RequestContext.getSignedKey}. A request can carry several
2339
+ * signatures, each of which may make Fedify fetch the key that it names,
2340
+ * so only the first ones in the order of the `Signature-Input` header are
2341
+ * verified, and the rest are ignored as if they were absent. Every
2342
+ * signature among the first ones counts, even if it fails before its key
2343
+ * is fetched. See also the `maxSignatures` option of `verifyRequest()`.
2344
+ *
2345
+ * It has to be a positive integer, or `Infinity` to verify every
2346
+ * signature, which lets a single request make Fedify fetch any number of
2347
+ * keys. Draft-cavage HTTP Signatures carry a single signature, so this
2348
+ * option does not affect them.
2349
+ *
2350
+ * Three by default.
2351
+ *
2352
+ * [RFC 9421]: https://www.rfc-editor.org/rfc/rfc9421
2353
+ * @throws {RangeError} Thrown when the federation is created if the value
2354
+ * is not a positive integer or `Infinity`.
2355
+ * @since 2.4.0
2356
+ */
2357
+ maxHttpSignatures?: number;
2306
2358
  /**
2307
2359
  * Whether to skip HTTP Signatures verification for incoming activities.
2308
2360
  * This is useful for testing purposes, but should not be used in production.
@@ -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-Bd6rZlJX.mjs";
8
+ import { f as verifyRequest } from "../http-Y1ObT1A8.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-DIJNHW-Y.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-CghLH7Zi.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-u6zzOExF.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";
@@ -534,5 +534,96 @@ test("getAuthenticatedDocumentLoader() rejects cancellation before fetching", as
534
534
  esm_default.hardReset();
535
535
  }
536
536
  });
537
+ function assertTimeoutFetchError(error, url) {
538
+ ok(error instanceof FetchError, String(error));
539
+ deepStrictEqual(error.url.href, url);
540
+ deepStrictEqual(error.response, void 0);
541
+ ok(error.cause instanceof DOMException);
542
+ deepStrictEqual(error.cause.name, "TimeoutError");
543
+ return true;
544
+ }
545
+ test("getAuthenticatedDocumentLoader() times out", async (t) => {
546
+ const identity = {
547
+ keyId: new URL("https://example.com/key2"),
548
+ privateKey: rsaPrivateKey2
549
+ };
550
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
551
+ await t.step("a request without a response", async () => {
552
+ esm_default.mockGlobal();
553
+ const url = "https://example.com/hang";
554
+ esm_default.get(url, () => new Promise(() => {}));
555
+ try {
556
+ await rejects(getAuthenticatedDocumentLoader(identity, {
557
+ allowPrivateAddress: true,
558
+ timeout: 100
559
+ })(url), (e) => assertTimeoutFetchError(e, url));
560
+ } finally {
561
+ esm_default.hardReset();
562
+ }
563
+ });
564
+ await t.step("double-knocking shares the timeout", async () => {
565
+ esm_default.mockGlobal();
566
+ const url = "https://example.com/double-knock";
567
+ let requests = 0;
568
+ esm_default.get(url, async () => {
569
+ requests++;
570
+ await delay(80);
571
+ return new Response(null, { status: 401 });
572
+ });
573
+ try {
574
+ await rejects(getAuthenticatedDocumentLoader(identity, {
575
+ allowPrivateAddress: true,
576
+ timeout: 120
577
+ })(url), (e) => assertTimeoutFetchError(e, url));
578
+ deepStrictEqual(requests, 2);
579
+ await delay(100);
580
+ deepStrictEqual(requests, 2);
581
+ } finally {
582
+ esm_default.hardReset();
583
+ }
584
+ });
585
+ for (const step of ["determineSpec", "rememberSpec"]) await t.step(`a slow ${step}()`, async () => {
586
+ esm_default.mockGlobal();
587
+ const url = `https://example.com/slow-${step}`;
588
+ let requests = 0;
589
+ esm_default.get(url, () => {
590
+ requests++;
591
+ return Response.json({ parsed: true });
592
+ });
593
+ try {
594
+ await rejects(getAuthenticatedDocumentLoader(identity, {
595
+ allowPrivateAddress: true,
596
+ timeout: 50,
597
+ specDeterminer: {
598
+ async determineSpec() {
599
+ if (step === "determineSpec") await delay(150);
600
+ return "rfc9421";
601
+ },
602
+ async rememberSpec() {
603
+ if (step === "rememberSpec") await delay(150);
604
+ }
605
+ }
606
+ })(url), (e) => assertTimeoutFetchError(e, url));
607
+ await delay(200);
608
+ deepStrictEqual(requests, step === "determineSpec" ? 0 : 1);
609
+ } finally {
610
+ esm_default.hardReset();
611
+ }
612
+ });
613
+ await t.step("the caller's signal still aborts", async () => {
614
+ esm_default.mockGlobal();
615
+ const url = "https://example.com/hang";
616
+ esm_default.get(url, () => new Promise(() => {}));
617
+ try {
618
+ const loader = getAuthenticatedDocumentLoader(identity, { allowPrivateAddress: true });
619
+ const controller = new AbortController();
620
+ const reason = /* @__PURE__ */ new Error("Canceled by the caller");
621
+ setTimeout(() => controller.abort(reason), 50);
622
+ await rejects(loader(url, { signal: controller.signal }), (e) => e === reason);
623
+ } finally {
624
+ esm_default.hardReset();
625
+ }
626
+ });
627
+ });
537
628
  //#endregion
538
629
  export {};
@@ -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-D0qjSeWY.mjs";
4
+ import { n as kvCache, t as MockKvStore } from "../kv-cache-C8YjNAi_.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-YRi_g8GB.cjs");
3
+ const require_kv_cache = require("../kv-cache-DUXluAc0.cjs");
4
4
  exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
5
5
  exports.kvCache = require_kv_cache.kvCache;
@@ -1,3 +1,3 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../mod-BA_F2x53.cjs";
2
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../mod-Dp3Ij7sw.cjs";
3
3
  export { getAuthenticatedDocumentLoader, kvCache };
@@ -1,3 +1,3 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../mod-B5z_q9TH.js";
2
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../mod-C5Mwx5ty.js";
3
3
  export { getAuthenticatedDocumentLoader, 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-iR55fqlk.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-C02XitwK.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.2169+0a45df07",
3
+ "version": "2.4.0-dev.2190+be3a8be0",
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/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"
154
+ "@fedify/uri-template": "2.4.0-dev.2190+be3a8be0",
155
+ "@fedify/vocab-runtime": "2.4.0-dev.2190+be3a8be0",
156
+ "@fedify/vocab": "2.4.0-dev.2190+be3a8be0",
157
+ "@fedify/webfinger": "2.4.0-dev.2190+be3a8be0"
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/vocab-tools": "^2.4.0-dev.2169+0a45df07",
170
- "@fedify/fixture": "2.0.0"
169
+ "@fedify/fixture": "2.0.0",
170
+ "@fedify/vocab-tools": "^2.4.0-dev.2190+be3a8be0"
171
171
  },
172
172
  "scripts": {
173
173
  "build:self": "tsdown",