@fedify/fedify 2.4.0-pr.936.41 → 2.5.0-dev.2271

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 (244) hide show
  1. package/README.md +50 -39
  2. package/dist/{assert-CJ1KXcvv.mjs → assert-D1Eafmd_.mjs} +1 -1
  3. package/dist/{assert_equals-BV7oLMxm.mjs → assert_equals-Z6IcEbWU.mjs} +2 -28
  4. package/dist/assert_exists-cffSpJ7X.mjs +28 -0
  5. package/dist/assert_false-CPdRnc3E.mjs +23 -0
  6. package/dist/assert_greater_or_equal-BlafOF4-.mjs +31 -0
  7. package/dist/{assert_instance_of-Q9KTBnrf.mjs → assert_instance_of-mrXWWNY-.mjs} +1 -1
  8. package/dist/{assert_not_equals-EPJPoxuf.mjs → assert_not_equals-CpPK2t89.mjs} +2 -1
  9. package/dist/assert_rejects-CTptdYck.mjs +39 -0
  10. package/dist/{assert_strict_equals-Ec20AUwa.mjs → assert_strict_equals-CYvBmkpC.mjs} +2 -1
  11. package/dist/{assert_throws-NiFfqbnH.mjs → assert_throws-BYITOvPO.mjs} +2 -1
  12. package/dist/assertion_error-B-cx0fFA.mjs +31 -0
  13. package/dist/audience-CHQ-FlLD.mjs +95 -0
  14. package/dist/{builder-DonuxRl_.mjs → builder-Bda6LK7A.mjs} +169 -14
  15. package/dist/{circuit-breaker-CBGyz5F7.mjs → circuit-breaker-XJ53md4S.mjs} +224 -17
  16. package/dist/circuit-breaker-test-utils-DW6YC_Pe.mjs +14 -0
  17. package/dist/{client-CjF5IYQS.mjs → client-CEnNz8O7.mjs} +144 -8
  18. package/dist/{codec-BBga-FWI.mjs → codec-C6rTrpIp.mjs} +26 -3
  19. package/dist/{collection-BIhlldqK.mjs → collection-CnnP1UAv.mjs} +1 -1
  20. package/dist/compat/mod.cjs +1 -1
  21. package/dist/compat/mod.d.cts +1 -1
  22. package/dist/compat/mod.d.ts +1 -1
  23. package/dist/compat/mod.js +1 -1
  24. package/dist/compat/outgoing-jsonld.test.mjs +71 -3
  25. package/dist/compat/public-audience.test.mjs +14 -5
  26. package/dist/compat/secured-document.test.d.mts +2 -0
  27. package/dist/compat/secured-document.test.mjs +58 -0
  28. package/dist/compat/transformers.test.mjs +5 -5
  29. package/dist/compound-proof-B-9mXxFW.mjs +989 -0
  30. package/dist/{context-Zii1f5xS.d.ts → context-7NyiqIcg.d.ts} +1600 -25
  31. package/dist/{context-BJXxPElm.mjs → context-8Tu9kea0.mjs} +21 -63
  32. package/dist/{context-lxX6I7as.d.cts → context-tsYPJ2Ew.d.cts} +1600 -25
  33. package/dist/{deno-BHzKn9Ig.mjs → deno-oR5aJKpU.mjs} +1 -1
  34. package/dist/dist-DJQM4u7i.mjs +189 -0
  35. package/dist/docloader-DBoYbvYW.mjs +87 -0
  36. package/dist/{esm-yYQfPhIY.mjs → esm-BHXXx4Wx.mjs} +13 -6
  37. package/dist/federation/audience.test.d.mts +2 -0
  38. package/dist/federation/audience.test.mjs +130 -0
  39. package/dist/federation/builder.test.mjs +54 -5
  40. package/dist/federation/circuit-breaker.test.mjs +838 -7
  41. package/dist/federation/collection.test.mjs +3 -3
  42. package/dist/federation/compound-fanout.test.d.mts +2 -0
  43. package/dist/federation/compound-fanout.test.mjs +228 -0
  44. package/dist/federation/handler-compound-proof.test.d.mts +2 -0
  45. package/dist/federation/handler-compound-proof.test.mjs +384 -0
  46. package/dist/federation/handler.test.mjs +385 -15
  47. package/dist/federation/hashlink-media.test.d.mts +2 -0
  48. package/dist/federation/hashlink-media.test.mjs +422 -0
  49. package/dist/federation/idempotency.test.mjs +6 -6
  50. package/dist/federation/inbox-report.test.d.mts +2 -0
  51. package/dist/federation/inbox-report.test.mjs +475 -0
  52. package/dist/federation/inbox.test.mjs +3 -3
  53. package/dist/federation/keycache.test.mjs +215 -14
  54. package/dist/federation/kv.test.mjs +3 -3
  55. package/dist/federation/metrics.test.mjs +5 -5
  56. package/dist/federation/middleware.test.mjs +967 -35
  57. package/dist/federation/mod.cjs +18 -261
  58. package/dist/federation/mod.d.cts +5 -5
  59. package/dist/federation/mod.d.ts +5 -5
  60. package/dist/federation/mod.js +279 -1
  61. package/dist/federation/mq.test.mjs +123 -47
  62. package/dist/federation/negotiation.test.mjs +4 -4
  63. package/dist/federation/outgoing-proof.test.d.mts +2 -0
  64. package/dist/federation/outgoing-proof.test.mjs +931 -0
  65. package/dist/federation/portable-actor.test.d.mts +2 -0
  66. package/dist/federation/portable-actor.test.mjs +496 -0
  67. package/dist/federation/portable-chain.test.d.mts +2 -0
  68. package/dist/federation/portable-chain.test.mjs +370 -0
  69. package/dist/federation/portable-collection.test.d.mts +2 -0
  70. package/dist/federation/portable-collection.test.mjs +832 -0
  71. package/dist/federation/portable-delivery.test.d.mts +2 -0
  72. package/dist/federation/portable-delivery.test.mjs +746 -0
  73. package/dist/federation/portable-gateway-keys.test.d.mts +2 -0
  74. package/dist/federation/portable-gateway-keys.test.mjs +686 -0
  75. package/dist/federation/portable-inbox.test.d.mts +2 -0
  76. package/dist/federation/portable-inbox.test.mjs +1535 -0
  77. package/dist/federation/portable-parse-uri.test.d.mts +2 -0
  78. package/dist/federation/portable-parse-uri.test.mjs +348 -0
  79. package/dist/federation/portable-route-activity.test.d.mts +2 -0
  80. package/dist/federation/portable-route-activity.test.mjs +259 -0
  81. package/dist/federation/portable.test.d.mts +2 -0
  82. package/dist/federation/portable.test.mjs +1072 -0
  83. package/dist/federation/retry.test.mjs +4 -3
  84. package/dist/federation/router.test.mjs +9 -159
  85. package/dist/federation/send.test.mjs +245 -27
  86. package/dist/federation/tasks/codec.test.mjs +4 -4
  87. package/dist/federation/tasks/enqueue.test.mjs +42 -4
  88. package/dist/federation/tasks/tasks.test.mjs +7 -6
  89. package/dist/federation/temporal.test.mjs +4 -4
  90. package/dist/federation/webfinger.test.mjs +275 -12
  91. package/dist/{middleware-FrSMAYEx.cjs → federation-CkZiAcWY.cjs} +8640 -3722
  92. package/dist/http-B5JT115n.cjs +10630 -0
  93. package/dist/http-DydWCB7R.js +6527 -0
  94. package/dist/{http-CPVMUgsW.mjs → http-siciWkmx.mjs} +397 -168
  95. package/dist/key-BspPiXqn.mjs +951 -0
  96. package/dist/key-C1nv7_jD.d.ts +1125 -0
  97. package/dist/key-DYxuyd-s.d.cts +1125 -0
  98. package/dist/key-owner-evidence-APB6NpSk.mjs +108 -0
  99. package/dist/keycache-Da8A8mZa.mjs +200 -0
  100. package/dist/{kv-D6hNiMTK.d.ts → kv-B2mzK5tl.d.cts} +3 -2
  101. package/dist/{kv-gJ8LYbxX.d.cts → kv-B2mzK5tl.d.ts} +3 -2
  102. package/dist/kv-DBRWVx3Q.mjs +104 -0
  103. package/dist/{kv-cache-KyGqJqSp.mjs → kv-cache-BF1hnW65.mjs} +1 -1
  104. package/dist/{kv-cache-5bnX3-Jq.js → kv-cache-CTQr1tbn.js} +54 -16
  105. package/dist/{kv-cache-DQ29C4XL.cjs → kv-cache-DCac1nEU.cjs} +55 -19
  106. package/dist/{ld-Cj9F_5AP.mjs → ld-CzaP-hJl.mjs} +44 -12
  107. package/dist/map-local-context-conflict-DOYEEJ3u.mjs +204 -0
  108. package/dist/map-local-create-note-B0SeXJms.mjs +214 -0
  109. package/dist/{metrics-DMk-nTxI.mjs → metrics-CYg9yxBL.mjs} +3 -2
  110. package/dist/metrics-DVKYY6K1.d.cts +36 -0
  111. package/dist/metrics-DoRtI0qU.d.ts +36 -0
  112. package/dist/{middleware-Y-kpsp6S.js → middleware-CsDDXKuL.js} +5493 -1103
  113. package/dist/{middleware-CvwTUgnP.mjs → middleware-D7_LO-Vs.mjs} +3157 -272
  114. package/dist/{middleware-CEctxBN6.mjs → middleware-DWjrfpcz.mjs} +1 -1
  115. package/dist/{mod-gOlPDuT8.d.cts → mod-BojP2Bw3.d.cts} +1 -1
  116. package/dist/mod-CavhAgLw.d.cts +320 -0
  117. package/dist/mod-CtpF2BU5.d.ts +320 -0
  118. package/dist/{mod-BtEaIEcD.d.cts → mod-DEZXwV6J.d.ts} +10 -4
  119. package/dist/{mod-UMmveiO0.d.ts → mod-Dw-nPxQh.d.cts} +10 -4
  120. package/dist/{mod-DLc2Ot6f.d.ts → mod-Xj5P4s4d.d.ts} +1 -1
  121. package/dist/mod.cjs +40 -39
  122. package/dist/mod.d.cts +10 -11
  123. package/dist/mod.d.ts +10 -11
  124. package/dist/mod.js +9 -9
  125. package/dist/{mq-llHKivST.mjs → mq-Dm1Wmtm-.mjs} +6 -0
  126. package/dist/nodeinfo/client.test.mjs +139 -4
  127. package/dist/nodeinfo/handler.test.mjs +5 -5
  128. package/dist/nodeinfo/mod.cjs +1 -1
  129. package/dist/nodeinfo/mod.d.cts +1 -1
  130. package/dist/nodeinfo/mod.d.ts +1 -1
  131. package/dist/nodeinfo/mod.js +1 -1
  132. package/dist/nodeinfo/types.test.mjs +4 -4
  133. package/dist/otel/exporter.test.mjs +3 -3
  134. package/dist/otel/mod.cjs +0 -1
  135. package/dist/otel/mod.d.cts +1 -1
  136. package/dist/otel/mod.d.ts +1 -1
  137. package/dist/{outgoing-jsonld-URuqsICz.mjs → outgoing-jsonld-4IJqPYos.mjs} +12 -10
  138. package/dist/{owner-DEvZuyOE.d.cts → owner-BF0L9cMt.d.cts} +11 -0
  139. package/dist/{owner-CnngXDNJ.d.ts → owner-BSzr5-I8.d.ts} +11 -0
  140. package/dist/owner-DYgfTFHy.mjs +267 -0
  141. package/dist/portable-collection-BpsVsRov.js +670 -0
  142. package/dist/portable-collection-C74P1vtC.mjs +418 -0
  143. package/dist/portable-collection-DZd2bm7M.cjs +686 -0
  144. package/dist/portable-key-BIMLrAP4.mjs +549 -0
  145. package/dist/portable-key-id-Ca30-hOa.mjs +248 -0
  146. package/dist/proof-Dxy6ByqI.mjs +1299 -0
  147. package/dist/{public-audience-Cr5MsnMq.mjs → public-audience--klBIOk1.mjs} +15 -10
  148. package/dist/router-u5O5KCQr.mjs +156 -0
  149. package/dist/runtime/mod.cjs +1 -1
  150. package/dist/runtime/mod.js +1 -1
  151. package/dist/secured-document-CxzZZ9nL.mjs +35 -0
  152. package/dist/send-C4dDpAxm.mjs +495 -0
  153. package/dist/sig/accept.test.mjs +1 -1
  154. package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
  155. package/dist/sig/compound-proof-discovery.test.mjs +331 -0
  156. package/dist/sig/compound-proof-producer.test.d.mts +2 -0
  157. package/dist/sig/compound-proof-producer.test.mjs +107 -0
  158. package/dist/sig/compound-proof-verification.test.d.mts +2 -0
  159. package/dist/sig/compound-proof-verification.test.mjs +833 -0
  160. package/dist/sig/compound-proof.test.d.mts +2 -0
  161. package/dist/sig/compound-proof.test.mjs +411 -0
  162. package/dist/sig/http.test.mjs +702 -31
  163. package/dist/sig/key-owner-evidence.test.d.mts +2 -0
  164. package/dist/sig/key-owner-evidence.test.mjs +100 -0
  165. package/dist/sig/key.test.mjs +220 -8
  166. package/dist/sig/ld.test.mjs +65 -7
  167. package/dist/sig/mitra-receive-interop.test.d.mts +2 -0
  168. package/dist/sig/mitra-receive-interop.test.mjs +260 -0
  169. package/dist/sig/mitra-send-interop.test.d.mts +2 -0
  170. package/dist/sig/mitra-send-interop.test.mjs +461 -0
  171. package/dist/sig/mod.cjs +18 -16
  172. package/dist/sig/mod.d.cts +4 -4
  173. package/dist/sig/mod.d.ts +4 -4
  174. package/dist/sig/mod.js +3 -3
  175. package/dist/sig/owner.test.mjs +108 -9
  176. package/dist/sig/portable-collection.test.d.mts +2 -0
  177. package/dist/sig/portable-collection.test.mjs +697 -0
  178. package/dist/sig/portable-interop.test.d.mts +2 -0
  179. package/dist/sig/portable-interop.test.mjs +156 -0
  180. package/dist/sig/portable-key-id.test.d.mts +2 -0
  181. package/dist/sig/portable-key-id.test.mjs +67 -0
  182. package/dist/sig/portable-key.test.d.mts +2 -0
  183. package/dist/sig/portable-key.test.mjs +1439 -0
  184. package/dist/sig/proof.test.mjs +1753 -16
  185. package/dist/sig/tootik-request-interop.test.d.mts +2 -0
  186. package/dist/sig/tootik-request-interop.test.mjs +190 -0
  187. package/dist/sig/tootik-send-interop.test.d.mts +2 -0
  188. package/dist/sig/tootik-send-interop.test.mjs +331 -0
  189. package/dist/sig/verification.test.d.mts +2 -0
  190. package/dist/sig/verification.test.mjs +310 -0
  191. package/dist/std__assert-DvMDRPes.mjs +8 -0
  192. package/dist/{testing-CO7ftO8A.mjs → tasks-IG3pHfvZ.mjs} +2 -2
  193. package/dist/{temporal-fsXO5IvD.mjs → temporal-D0KJI4NF.mjs} +3 -3
  194. package/dist/testing/context.test.d.mts +2 -0
  195. package/dist/testing/context.test.mjs +19 -0
  196. package/dist/testing/kv.test.d.mts +2 -0
  197. package/dist/testing/kv.test.mjs +101 -0
  198. package/dist/testing/mod.d.mts +1617 -48
  199. package/dist/testing/mod.mjs +6 -3
  200. package/dist/testing-t8xDeJZ5.mjs +8 -0
  201. package/dist/{transformers-DGwl-hD1.cjs → transformers-BalCrSsr.cjs} +0 -1
  202. package/dist/{types-DC1pNgJA.js → types-_S2_MeLF.js} +144 -8
  203. package/dist/{types-CPym83zc.cjs → types-poIao40f.cjs} +160 -7
  204. package/dist/utils/docloader.test.mjs +530 -8
  205. package/dist/utils/kv-cache.test.mjs +2 -2
  206. package/dist/utils/mod.cjs +1 -1
  207. package/dist/utils/mod.d.cts +1 -1
  208. package/dist/utils/mod.d.ts +1 -1
  209. package/dist/utils/mod.js +1 -1
  210. package/dist/verification-C3954hQh.mjs +5 -0
  211. package/dist/verification-Dpfcw8ml.mjs +105 -0
  212. package/dist/vocab/cjs.test.mjs +1 -1
  213. package/package.json +8 -8
  214. package/dist/assert_rejects-EgstcQy5.mjs +0 -82
  215. package/dist/docloader-e1khNUKy.mjs +0 -49
  216. package/dist/http-CsmQ-BQ4.js +0 -2483
  217. package/dist/http-VyDTd4G3.d.cts +0 -553
  218. package/dist/http-hlIjmewS.cjs +0 -2694
  219. package/dist/http-lf8Hsd91.d.ts +0 -553
  220. package/dist/key-DfPsX8hv.mjs +0 -453
  221. package/dist/keycache-_DHqz5z_.mjs +0 -97
  222. package/dist/metrics-CoUJLQhZ.d.cts +0 -276
  223. package/dist/metrics-Dc4jR-IC.d.ts +0 -276
  224. package/dist/mod-B0hW12_O.d.cts +0 -307
  225. package/dist/mod-COIAjwRS.d.ts +0 -307
  226. package/dist/owner-Br9YYzn_.mjs +0 -120
  227. package/dist/proof-B4ngoaNQ.mjs +0 -316
  228. package/dist/proof-B6E0XUXJ.js +0 -1415
  229. package/dist/proof-NN4xCQGL.cjs +0 -1562
  230. package/dist/send-CxHKUNzv.mjs +0 -239
  231. package/dist/std__assert-B2NnY9bq.mjs +0 -79
  232. package/dist/temporal-polyfill-BCdTHexd.cjs +0 -3565
  233. /package/dist/{accept-8PiolDP7.mjs → accept-CPVqki78.mjs} +0 -0
  234. /package/dist/{activity-listener-BtTSxZWA.mjs → activity-listener-C-BSbKI7.mjs} +0 -0
  235. /package/dist/{client-CAM_bQXx.d.cts → client-D-XP_Ccb.d.cts} +0 -0
  236. /package/dist/{client-CSddvgWN.d.ts → client-D-XP_Ccb.d.ts} +0 -0
  237. /package/dist/{keys-Dbyd7bhl.mjs → keys-DIJNHW-Y.mjs} +0 -0
  238. /package/dist/{kv-CXBAok3k.mjs → kv-DCHkaJ9-.mjs} +0 -0
  239. /package/dist/{negotiation-RuwrPFqi.mjs → negotiation-CCocWT_N.mjs} +0 -0
  240. /package/dist/{retry-DgFqeS5k.mjs → retry-zX5xw5e0.mjs} +0 -0
  241. /package/dist/{chunk-D5IdezsZ.js → rolldown-runtime-BC-Eo5Mj.js} +0 -0
  242. /package/dist/{chunk-Czpeue4M.cjs → rolldown-runtime-Dmm3t92W.cjs} +0 -0
  243. /package/dist/{transformers-DXze6FUB.js → transformers-DAtXl_Kc.js} +0 -0
  244. /package/dist/{types-CrtdVuDP.mjs → types-DE_LV1JB.mjs} +0 -0
@@ -0,0 +1,310 @@
1
+ import "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { a as verificationObservation } from "../verification-Dpfcw8ml.mjs";
5
+ import { h as verifyJsonLd, p as signJsonLd } from "../ld-CzaP-hJl.mjs";
6
+ import { a as signObject, s as verifyObject } from "../proof-Dxy6ByqI.mjs";
7
+ import { l as signRequest, p as verifyRequestDetailed } from "../http-siciWkmx.mjs";
8
+ import { i as rsaPrivateKey2, n as ed25519PrivateKey, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
9
+ import { Activity, Create, CryptographicKey, Multikey } from "@fedify/vocab";
10
+ import { FetchError } from "@fedify/vocab-runtime";
11
+ import { mockDocumentLoader, test } from "@fedify/fixture";
12
+ import { deepStrictEqual, ok, strictEqual } from "node:assert/strict";
13
+ //#region src/sig/verification.test.ts
14
+ const loaders = {
15
+ documentLoader: mockDocumentLoader,
16
+ contextLoader: mockDocumentLoader
17
+ };
18
+ function observation() {
19
+ return { attempts: [] };
20
+ }
21
+ test("LDS evidence has no checks for absent or malformed signatures", async () => {
22
+ const json = await new Create({ actor: rsaPublicKey2.ownerId }).toJsonLd(loaders);
23
+ for (const signature of [
24
+ void 0,
25
+ null,
26
+ "invalid",
27
+ [],
28
+ {}
29
+ ]) {
30
+ const evidence = observation();
31
+ strictEqual(await verifyJsonLd(signature === void 0 ? json : {
32
+ ...json,
33
+ signature
34
+ }, {
35
+ ...loaders,
36
+ [verificationObservation]: evidence
37
+ }), false);
38
+ const attempt = evidence.attempts[0];
39
+ ok(attempt.status === "rejected");
40
+ strictEqual(attempt.reason.type, signature === void 0 ? "noSignature" : "signatureVerificationFailed");
41
+ deepStrictEqual(attempt.checks, []);
42
+ }
43
+ });
44
+ test("signature evidence preserves stale and fresh HTTP keys for both specs", async () => {
45
+ for (const spec of ["draft-cavage-http-signatures-12", "rfc9421"]) {
46
+ const evidence = observation();
47
+ const signed = await signRequest(new Request("https://example.com/inbox", {
48
+ method: "POST",
49
+ body: "{}"
50
+ }), rsaPrivateKey2, rsaPublicKey2.id, { spec });
51
+ const stale = rsaPublicKey1.clone({ id: rsaPublicKey2.id });
52
+ strictEqual((await verifyRequestDetailed(signed, {
53
+ ...loaders,
54
+ [verificationObservation]: evidence,
55
+ keyCache: {
56
+ get: () => Promise.resolve(stale),
57
+ set: () => Promise.resolve()
58
+ }
59
+ })).verified, true);
60
+ const attempt = evidence.attempts[0];
61
+ ok(attempt.status === "verified");
62
+ strictEqual(attempt.checks.length, 1);
63
+ const check = attempt.checks[0];
64
+ ok(check.status === "verified");
65
+ strictEqual(check.triedKeys.length, 2);
66
+ strictEqual(check.triedKeys[0].publicKey, rsaPublicKey1.publicKey);
67
+ deepStrictEqual(await crypto.subtle.exportKey("jwk", check.triedKeys[1].publicKey), await crypto.subtle.exportKey("jwk", rsaPublicKey2.publicKey));
68
+ strictEqual(check.key, check.triedKeys[1]);
69
+ strictEqual(attempt.signatures[0], check);
70
+ }
71
+ });
72
+ test("signature evidence retains the failed key when HTTP refresh cannot load", async () => {
73
+ for (const spec of ["draft-cavage-http-signatures-12", "rfc9421"]) {
74
+ const evidence = observation();
75
+ const signed = await signRequest(new Request("https://example.com/inbox", {
76
+ method: "POST",
77
+ body: "{}"
78
+ }), rsaPrivateKey2, rsaPublicKey2.id, { spec });
79
+ const response = new Response(null, { status: 410 });
80
+ strictEqual((await verifyRequestDetailed(signed, {
81
+ ...loaders,
82
+ [verificationObservation]: evidence,
83
+ documentLoader: () => Promise.reject(new FetchError(rsaPublicKey2.id, "gone", response)),
84
+ keyCache: {
85
+ get: () => Promise.resolve(rsaPublicKey1.clone({ id: rsaPublicKey2.id })),
86
+ set: () => Promise.resolve()
87
+ }
88
+ })).verified, false);
89
+ const check = evidence.attempts[0].checks[0];
90
+ ok(check.status === "rejected");
91
+ strictEqual(check.reason.type, "keyFetchError");
92
+ strictEqual(check.triedKeys[0].publicKey, rsaPublicKey1.publicKey);
93
+ }
94
+ });
95
+ test("signature evidence preserves failed LDS keys and successful stale-key refresh", async () => {
96
+ const signed = await signJsonLd(await new Create({ actor: new URL("https://example.com/person") }).toJsonLd(loaders), rsaPrivateKey2, rsaPublicKey2.id, loaders);
97
+ const evidence = observation();
98
+ strictEqual(await verifyJsonLd(signed, {
99
+ ...loaders,
100
+ [verificationObservation]: evidence,
101
+ keyCache: {
102
+ get: () => Promise.resolve(rsaPublicKey1.clone({ id: rsaPublicKey2.id })),
103
+ set: () => Promise.resolve()
104
+ }
105
+ }), false);
106
+ const attempt = evidence.attempts[0];
107
+ ok(attempt.status === "rejected");
108
+ strictEqual(attempt.reason.type, "missingOwner");
109
+ strictEqual(attempt.checks[0].status, "verified");
110
+ strictEqual(attempt.checks[0].triedKeys.length, 2);
111
+ const bad = observation();
112
+ strictEqual(await verifyJsonLd(signed, {
113
+ ...loaders,
114
+ [verificationObservation]: bad,
115
+ documentLoader: async () => ({
116
+ contextUrl: null,
117
+ documentUrl: rsaPublicKey2.id.href,
118
+ document: await new CryptographicKey({
119
+ id: rsaPublicKey2.id,
120
+ publicKey: rsaPublicKey1.publicKey
121
+ }).toJsonLd(loaders)
122
+ })
123
+ }), false);
124
+ strictEqual(bad.attempts[0].checks[0].status, "rejected");
125
+ strictEqual(bad.attempts[0].checks[0].triedKeys.length, 1);
126
+ });
127
+ test("signature evidence preserves multiple valid proofs despite uncovered attribution", async () => {
128
+ const second = await signObject(await signObject(new Create({ actor: new URL("https://example.com/person") }), ed25519PrivateKey, ed25519Multikey.id, loaders), ed25519PrivateKey, ed25519Multikey.id, loaders);
129
+ const evidence = observation();
130
+ strictEqual(await verifyObject(Activity, await second.toJsonLd(loaders), {
131
+ ...loaders,
132
+ [verificationObservation]: evidence
133
+ }), null);
134
+ const attempt = evidence.attempts[0];
135
+ ok(attempt.status === "rejected");
136
+ strictEqual(attempt.reason.type, "uncoveredAttribution");
137
+ strictEqual(attempt.checks.length, 2);
138
+ ok(attempt.checks.every((check) => check.status === "verified"));
139
+ });
140
+ test("signature evidence preserves OIP stale keys when fresh verification fails", async () => {
141
+ const signed = await signObject(new Create({ actor: ed25519Multikey.controllerId }), ed25519PrivateKey, ed25519Multikey.id, loaders);
142
+ const pair = await crypto.subtle.generateKey("Ed25519", true, ["sign", "verify"]);
143
+ const stale = new Multikey({
144
+ id: ed25519Multikey.id,
145
+ controller: null,
146
+ publicKey: pair.publicKey
147
+ });
148
+ const evidence = observation();
149
+ strictEqual(await verifyObject(Activity, await signed.toJsonLd(loaders), {
150
+ ...loaders,
151
+ [verificationObservation]: evidence,
152
+ keyCache: {
153
+ get: () => Promise.resolve(stale),
154
+ set: () => Promise.resolve()
155
+ },
156
+ documentLoader: async () => ({
157
+ contextUrl: null,
158
+ documentUrl: ed25519Multikey.id.href,
159
+ document: await stale.toJsonLd(loaders)
160
+ })
161
+ }), null);
162
+ const check = evidence.attempts[0].checks[0];
163
+ strictEqual(check.status, "rejected");
164
+ strictEqual(check.triedKeys.length, 2);
165
+ strictEqual(check.triedKeys[0].publicKey, pair.publicKey);
166
+ });
167
+ test("OIP check preserves the literal declared key ID", async () => {
168
+ const json = await (await signObject(new Create({ actor: ed25519Multikey.controllerId }), ed25519PrivateKey, ed25519Multikey.id, loaders)).toJsonLd(loaders);
169
+ const proof = json.proof;
170
+ const declaredKeyId = "https://EXAMPLE.com/person2#key4";
171
+ proof.verificationMethod = declaredKeyId;
172
+ const evidence = observation();
173
+ await verifyObject(Activity, json, {
174
+ ...loaders,
175
+ [verificationObservation]: evidence
176
+ });
177
+ strictEqual(evidence.attempts[0].checks[0].declaredKeyId, declaredKeyId);
178
+ });
179
+ test("signature observation cannot turn a cached miss into a metadata exception", async () => {
180
+ const json = await signJsonLd(await new Create({ actor: new URL("https://example.com/person") }).toJsonLd(loaders), rsaPrivateKey2, rsaPublicKey2.id, loaders);
181
+ const evidence = observation();
182
+ const cache = {
183
+ get: () => Promise.resolve(null),
184
+ set: () => Promise.resolve(),
185
+ getFetchError: () => Promise.reject(/* @__PURE__ */ new Error("diagnostic unavailable"))
186
+ };
187
+ strictEqual(await verifyJsonLd(json, {
188
+ ...loaders,
189
+ keyCache: cache,
190
+ [verificationObservation]: evidence
191
+ }), false);
192
+ strictEqual(evidence.attempts[0].checks[0].status, "rejected");
193
+ });
194
+ test("signature observation preserves rejection for consumed fetch-error responses", async () => {
195
+ const json = await signJsonLd(await new Create({ actor: new URL("https://example.com/person") }).toJsonLd(loaders), rsaPrivateKey2, rsaPublicKey2.id, loaders);
196
+ const response = new Response("gone", { status: 410 });
197
+ await response.text();
198
+ const error = new FetchError(rsaPublicKey2.id, "gone", response);
199
+ const options = {
200
+ ...loaders,
201
+ documentLoader: () => Promise.reject(error)
202
+ };
203
+ strictEqual(await verifyJsonLd(json, options), false);
204
+ const evidence = observation();
205
+ strictEqual(await verifyJsonLd(json, {
206
+ ...options,
207
+ [verificationObservation]: evidence
208
+ }), false);
209
+ const check = evidence.attempts[0].checks[0];
210
+ ok(check.status === "rejected" && check.reason.type === "keyFetchError");
211
+ let cloneThrows = false;
212
+ try {
213
+ response.clone();
214
+ } catch {
215
+ cloneThrows = true;
216
+ }
217
+ if (cloneThrows) {
218
+ ok("error" in check.reason.result);
219
+ strictEqual(check.reason.result.error, error);
220
+ } else {
221
+ ok("status" in check.reason.result);
222
+ strictEqual(check.reason.result.status, 410);
223
+ }
224
+ });
225
+ test("OIP check retains aliased declarations without extra context fetches", async () => {
226
+ const json = await (await signObject(new Create({ actor: ed25519Multikey.controllerId }), ed25519PrivateKey, ed25519Multikey.id, loaders)).toJsonLd(loaders);
227
+ const proof = json.proof;
228
+ const context = { vm: {
229
+ "@id": "https://w3id.org/security#verificationMethod",
230
+ "@type": "@id"
231
+ } };
232
+ const contextUrl = "https://example.com/custom-proof-context";
233
+ json["@context"] = [...json["@context"], contextUrl];
234
+ proof["@context"] = [...proof["@context"], contextUrl];
235
+ const declaredKeyId = "https://EXAMPLE.com/person2#key4";
236
+ proof.vm = declaredKeyId;
237
+ delete proof.verificationMethod;
238
+ const run = async (evidence) => {
239
+ let fetches = 0;
240
+ await verifyObject(Activity, structuredClone(json), {
241
+ ...loaders,
242
+ contextLoader: async (url, options) => {
243
+ fetches++;
244
+ if (url === contextUrl) return {
245
+ contextUrl: null,
246
+ documentUrl: url,
247
+ document: { "@context": context }
248
+ };
249
+ return await mockDocumentLoader(url, options);
250
+ },
251
+ ...evidence == null ? {} : { [verificationObservation]: evidence }
252
+ });
253
+ return fetches;
254
+ };
255
+ const baselineFetches = await run();
256
+ const evidence = observation();
257
+ strictEqual(await run(evidence), baselineFetches);
258
+ strictEqual(evidence.attempts[0].checks[0].declaredKeyId, declaredKeyId);
259
+ });
260
+ test("OIP check preserves compact node identifiers and their aliases", async () => {
261
+ for (const idProperty of [
262
+ "id",
263
+ "rawId",
264
+ "scopedId"
265
+ ]) {
266
+ const json = await (await signObject(new Create({ actor: ed25519Multikey.controllerId }), ed25519PrivateKey, ed25519Multikey.id, loaders)).toJsonLd(loaders);
267
+ const proof = json.proof;
268
+ const context = {
269
+ rawId: "@id",
270
+ vm: {
271
+ "@id": "https://w3id.org/security#verificationMethod",
272
+ "@type": "@id",
273
+ "@context": { scopedId: "@id" }
274
+ }
275
+ };
276
+ json["@context"] = [...json["@context"], context];
277
+ proof["@context"] = [...proof["@context"], context];
278
+ const declaredKeyId = "https://EXAMPLE.com/person2#key4";
279
+ if (idProperty === "scopedId") {
280
+ proof.vm = { [idProperty]: declaredKeyId };
281
+ delete proof.verificationMethod;
282
+ } else proof.verificationMethod = { [idProperty]: declaredKeyId };
283
+ const evidence = observation();
284
+ await verifyObject(Activity, json, {
285
+ ...loaders,
286
+ [verificationObservation]: evidence
287
+ });
288
+ strictEqual(evidence.attempts[0].checks[0].declaredKeyId, declaredKeyId);
289
+ }
290
+ });
291
+ test("signature evidence excludes keys loaded before canonicalization errors", async () => {
292
+ const json = await (await signObject(new Create({ actor: ed25519Multikey.controllerId }), ed25519PrivateKey, ed25519Multikey.id, loaders)).toJsonLd(loaders);
293
+ json.extra = JSON.parse("1e400");
294
+ const evidence = observation();
295
+ let thrown = false;
296
+ try {
297
+ await verifyObject(Activity, json, {
298
+ ...loaders,
299
+ [verificationObservation]: evidence
300
+ });
301
+ } catch {
302
+ thrown = true;
303
+ }
304
+ strictEqual(thrown, true);
305
+ const check = evidence.attempts[0].checks[0];
306
+ strictEqual(check.status, "error");
307
+ deepStrictEqual(check.triedKeys, []);
308
+ });
309
+ //#endregion
310
+ export {};
@@ -0,0 +1,8 @@
1
+ import "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import "./assert_equals-Z6IcEbWU.mjs";
5
+ import "./assert_throws-BYITOvPO.mjs";
6
+ import "./assert_rejects-CTptdYck.mjs";
7
+ import "./assert_strict_equals-CYvBmkpC.mjs";
8
+ export {};
@@ -1,8 +1,8 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { i as mockDocumentLoader } from "./context-BJXxPElm.mjs";
5
- import { t as MemoryKvStore } from "./kv-CXBAok3k.mjs";
4
+ import { t as mockDocumentLoader } from "./dist-DJQM4u7i.mjs";
5
+ import { t as MemoryKvStore } from "./kv-DCHkaJ9-.mjs";
6
6
  import { Note } from "@fedify/vocab";
7
7
  //#region src/testing/tasks.ts
8
8
  /**
@@ -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-Cj9F_5AP.mjs";
4
+ import { c as getNormalizationContextLoader } from "./ld-CzaP-hJl.mjs";
5
5
  import jsonld from "@fedify/vocab-runtime/jsonld";
6
6
  //#region src/federation/temporal.ts
7
7
  function isPlainObject(value) {
@@ -28,7 +28,7 @@ function isMalformedDurationLiteral(value) {
28
28
  return true;
29
29
  }
30
30
  }
31
- const TEMPORAL_DATE_TIME_IRIS = new Set([
31
+ const TEMPORAL_DATE_TIME_IRIS = /* @__PURE__ */ new Set([
32
32
  "https://www.w3.org/ns/activitystreams#deleted",
33
33
  "https://www.w3.org/ns/activitystreams#endTime",
34
34
  "https://www.w3.org/ns/activitystreams#published",
@@ -37,7 +37,7 @@ const TEMPORAL_DATE_TIME_IRIS = new Set([
37
37
  "http://purl.org/dc/terms/created",
38
38
  "https://w3id.org/security#created"
39
39
  ]);
40
- const TEMPORAL_DURATION_IRIS = new Set(["https://www.w3.org/ns/activitystreams#duration"]);
40
+ const TEMPORAL_DURATION_IRIS = /* @__PURE__ */ new Set(["https://www.w3.org/ns/activitystreams#duration"]);
41
41
  const QUESTION_CLOSED_IRI = "https://www.w3.org/ns/activitystreams#closed";
42
42
  const XSD_DATE_TIME_IRI = "http://www.w3.org/2001/XMLSchema#dateTime";
43
43
  function hasMalformedExpandedDateTimeLiteral(value) {
@@ -0,0 +1,2 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";
@@ -0,0 +1,19 @@
1
+ import "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { n as test } from "../dist-DJQM4u7i.mjs";
5
+ import { strictEqual } from "node:assert/strict";
6
+ //#region src/testing/context.test.ts
7
+ test("ignored nested test steps return false", async (t) => {
8
+ let executed = false;
9
+ strictEqual(await t.step({
10
+ name: "ignored nested test step",
11
+ ignore: true,
12
+ fn() {
13
+ executed = true;
14
+ }
15
+ }), false);
16
+ strictEqual(executed, false);
17
+ });
18
+ //#endregion
19
+ export {};
@@ -0,0 +1,2 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";
@@ -0,0 +1,101 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { n as test } from "../dist-DJQM4u7i.mjs";
5
+ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
6
+ import { t as ManualClockKvStore } from "../kv-DBRWVx3Q.mjs";
7
+ import { n as baseOptions, o as stringSchema, t as MockQueue } from "../tasks-IG3pHfvZ.mjs";
8
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
9
+ import { o as createFederation } from "../middleware-D7_LO-Vs.mjs";
10
+ //#region src/testing/kv.test.ts
11
+ test("ManualClockKvStore keeps an entry at its exact expiration instant", async () => {
12
+ const kv = new ManualClockKvStore();
13
+ const ttl = Temporal.Duration.from({ minutes: 10 });
14
+ await kv.set(["k"], "v", { ttl });
15
+ kv.advance(ttl);
16
+ assertEquals(kv.now, Temporal.Instant.fromEpochMilliseconds(6e5));
17
+ assertEquals(await kv.get(["k"]), "v");
18
+ kv.advance({ nanoseconds: 1 });
19
+ assertEquals(await kv.get(["k"]), void 0);
20
+ });
21
+ test("ManualClockKvStore.list() applies the same boundary", async () => {
22
+ const kv = new ManualClockKvStore();
23
+ const ttl = Temporal.Duration.from({ minutes: 10 });
24
+ await kv.set(["k"], "v", { ttl });
25
+ kv.advance(ttl);
26
+ assertEquals(await Array.fromAsync(kv.list()), [{
27
+ key: ["k"],
28
+ value: "v"
29
+ }]);
30
+ kv.advance({ nanoseconds: 1 });
31
+ assertEquals(await Array.fromAsync(kv.list()), []);
32
+ });
33
+ test("ManualClockKvStore.cas() applies the same boundary", async () => {
34
+ const ttl = Temporal.Duration.from({ minutes: 10 });
35
+ const atBoundary = new ManualClockKvStore();
36
+ await atBoundary.set(["k"], "v", { ttl });
37
+ atBoundary.advance(ttl);
38
+ assertEquals(await atBoundary.cas?.(["k"], "v", "w"), true);
39
+ const pastBoundary = new ManualClockKvStore();
40
+ await pastBoundary.set(["k"], "v", { ttl });
41
+ pastBoundary.advance(ttl);
42
+ pastBoundary.advance({ nanoseconds: 1 });
43
+ assertEquals(await pastBoundary.cas?.(["k"], "v", "w"), false);
44
+ assertEquals(await pastBoundary.get(["k"]), void 0);
45
+ });
46
+ test("ManualClockKvStore.cas() without a TTL clears the expiration", async () => {
47
+ const kv = new ManualClockKvStore();
48
+ const ttl = Temporal.Duration.from({ minutes: 10 });
49
+ await kv.set(["k"], "v", { ttl });
50
+ assertEquals(await kv.cas?.(["k"], "v", "w"), true);
51
+ kv.advance({ hours: 1 });
52
+ assertEquals(await kv.get(["k"]), "w");
53
+ });
54
+ test("ManualClockKvStore withholds the TTL from the wrapped store", async () => {
55
+ const inner = new MemoryKvStore();
56
+ const kv = new ManualClockKvStore(inner);
57
+ await kv.set(["k"], "v", { ttl: Temporal.Duration.from({ nanoseconds: 1 }) });
58
+ assertEquals(await inner.get(["k"]), "v");
59
+ assertEquals(await kv.get(["k"]), "v");
60
+ });
61
+ /**
62
+ * A {@link KvStore} without `cas()`, standing in for backends that offer no
63
+ * conditional write.
64
+ */
65
+ var CaslessKvStore = class {
66
+ #inner = new MemoryKvStore();
67
+ get(key) {
68
+ return this.#inner.get(key);
69
+ }
70
+ set(key, value, options) {
71
+ return this.#inner.set(key, value, options);
72
+ }
73
+ delete(key) {
74
+ return this.#inner.delete(key);
75
+ }
76
+ list(prefix) {
77
+ return this.#inner.list(prefix);
78
+ }
79
+ };
80
+ test("ManualClockKvStore exposes cas() only when the wrapped store does", () => {
81
+ assertEquals(new ManualClockKvStore(new CaslessKvStore()).cas, void 0);
82
+ assertEquals(typeof new ManualClockKvStore(new MemoryKvStore()).cas, "function");
83
+ });
84
+ test("ManualClockKvStore over a store without cas() keeps the open deduplication fallback", async () => {
85
+ const queue = new MockQueue();
86
+ const federation = createFederation({
87
+ ...baseOptions,
88
+ kv: new ManualClockKvStore(new CaslessKvStore()),
89
+ queue: { task: queue },
90
+ taskDeduplicationFallback: "open"
91
+ });
92
+ const task = federation.defineTask("casless-open-fallback", {
93
+ schema: stringSchema,
94
+ handler: () => {}
95
+ });
96
+ await federation.createContext(new URL("https://example.com/"), void 0).enqueueTask(task, "payload", { deduplicationKey: "k" });
97
+ assertEquals(queue.enqueued.length, 1);
98
+ assertEquals(queue.enqueued[0].options?.deduplicationKey, void 0);
99
+ });
100
+ //#endregion
101
+ export {};