@fedify/fedify 2.0.0-pr.490.2 → 2.0.0-pr.559.4

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 (267) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +64 -37
  3. package/dist/{builder-4syLV1-z.js → builder-DTlQwmVF.js} +10 -3
  4. package/dist/{client-BsGzbnV-.d.ts → client-CUTUGgvJ.d.ts} +18 -18
  5. package/dist/{client-pY7-3icS.js → client-Dg7OfUDA.js} +28 -23
  6. package/dist/{client-94iWEfQa.d.cts → client-by-PEGAJ.d.cts} +18 -18
  7. package/dist/compat/mod.cjs +1 -1
  8. package/dist/compat/mod.d.cts +6 -10
  9. package/dist/compat/mod.d.ts +6 -10
  10. package/dist/compat/mod.js +1 -1
  11. package/dist/compat/transformers.test.js +22 -21
  12. package/dist/{context-PxGADCsD.d.cts → context-B6X-7loD.d.cts} +206 -74
  13. package/dist/{context-V-XS2_6O.d.ts → context-CJaICYPw.d.ts} +206 -74
  14. package/dist/context-CZ5llAss.js +109 -0
  15. package/dist/deno-DGx1JZHr.js +124 -0
  16. package/dist/{testing-BslrM_9E.js → dist-B5f6a8Tt.js} +90 -110
  17. package/dist/{docloader-DndkGj0O.js → docloader-D8UHsyqD.js} +3 -3
  18. package/dist/{esm-VlKMJQqV.js → esm-DGl7uK1r.js} +1 -1
  19. package/dist/federation/builder.test.js +7 -5
  20. package/dist/federation/collection.test.js +2 -3
  21. package/dist/federation/handler.test.js +24 -23
  22. package/dist/federation/idempotency.test.js +59 -22
  23. package/dist/federation/inbox.test.js +4 -3
  24. package/dist/federation/keycache.test.js +4 -4
  25. package/dist/federation/kv.test.js +56 -3
  26. package/dist/federation/middleware.test.js +307 -93
  27. package/dist/federation/mod.cjs +9 -10
  28. package/dist/federation/mod.d.cts +7 -11
  29. package/dist/federation/mod.d.ts +7 -11
  30. package/dist/federation/mod.js +8 -11
  31. package/dist/federation/mq.test.js +167 -16
  32. package/dist/federation/negotiation.test.js +2 -3
  33. package/dist/federation/retry.test.js +2 -3
  34. package/dist/federation/router.test.js +2 -2
  35. package/dist/federation/send.test.js +93 -11
  36. package/dist/{webfinger/handler.test.js → federation/webfinger.test.js} +24 -22
  37. package/dist/{federation-CRpdnOMS.cjs → federation-CE0CJ_0G.cjs} +116 -10
  38. package/dist/{federation-jcR8-ZxP.js → federation-D6FVaeAR.js} +122 -16
  39. package/dist/{http-YhR_TMMQ.js → http-CL3G0rnf.js} +126 -9
  40. package/dist/{http-M8k5mKc0.d.cts → http-ClB3pLcL.d.cts} +1 -1
  41. package/dist/{http-Dxpqz4hE.cjs → http-DKBUv5zZ.cjs} +139 -16
  42. package/dist/{http-BbO0ejuk.d.ts → http-DLBDPal9.d.ts} +1 -1
  43. package/dist/{http-DH47B-h3.js → http-LGtYlSfN.js} +3 -2
  44. package/dist/{inbox-CEyHvxOo.js → inbox-DbtWQY2D.js} +2 -1
  45. package/dist/{key-x7E5PYI0.js → key-BCtt1Ugy.js} +3 -3
  46. package/dist/{keycache-BRXuBDuy.js → keycache-DRxpZ5r9.js} +1 -1
  47. package/dist/{keys-DLk_8H-l.js → keys-ZbcByPg9.js} +1 -1
  48. package/dist/{kv-Bxr0Q87_.d.cts → kv-B4vFhIYL.d.cts} +30 -1
  49. package/dist/{kv-BKNZ-Tb-.d.ts → kv-CYySNrsn.d.ts} +30 -1
  50. package/dist/{kv-CRZrzyXm.js → kv-QzKcOQgP.js} +22 -0
  51. package/dist/{kv-cache-HFnFIjSD.js → kv-cache-0786BfqY.js} +3 -3
  52. package/dist/{kv-cache-DN9pfMBe.js → kv-cache-B__dHl7g.js} +15 -2
  53. package/dist/{kv-cache-BMpfJFTx.cjs → kv-cache-DCJojeTn.cjs} +3 -3
  54. package/dist/{ld-CRPaU6c8.js → ld-QlZPwGEH.js} +4 -3
  55. package/dist/middleware-B3jUPnDa.js +12 -0
  56. package/dist/middleware-BFiwWMA2.cjs +12 -0
  57. package/dist/middleware-DMx6DyIw.js +26 -0
  58. package/dist/{middleware-DfLpMu7C.js → middleware-Dm58nObp.js} +280 -166
  59. package/dist/{middleware-BIqFwRwI.js → middleware-WokE4qxc.js} +245 -178
  60. package/dist/{middleware-Ck7O6mb0.cjs → middleware-hWyKOO_6.cjs} +332 -206
  61. package/dist/{mod-DMpuiKXi.d.cts → mod-BHXq4Q3x.d.cts} +7 -7
  62. package/dist/{mod-DgxG-byT.d.cts → mod-BrS8tiad.d.cts} +2 -2
  63. package/dist/mod-CoMP50Rf.d.ts +64 -0
  64. package/dist/{mod-BoRKfJPE.d.cts → mod-DScazwCW.d.cts} +4 -4
  65. package/dist/mod-DTzN6Pv3.d.cts +62 -0
  66. package/dist/{mod-aAE2wOWV.d.ts → mod-DZmuPaKv.d.ts} +7 -7
  67. package/dist/{mod-D5Z2tISD.d.ts → mod-jOa7W503.d.ts} +2 -2
  68. package/dist/{mod-Cdo6SYlJ.d.ts → mod-xKJ57rwu.d.ts} +4 -4
  69. package/dist/mod.cjs +12 -93
  70. package/dist/mod.d.cts +11 -15
  71. package/dist/mod.d.ts +11 -15
  72. package/dist/mod.js +11 -15
  73. package/dist/nodeinfo/client.test.js +3 -4
  74. package/dist/nodeinfo/handler.test.js +22 -21
  75. package/dist/nodeinfo/mod.cjs +2 -2
  76. package/dist/nodeinfo/mod.d.cts +2 -2
  77. package/dist/nodeinfo/mod.d.ts +2 -2
  78. package/dist/nodeinfo/mod.js +2 -2
  79. package/dist/nodeinfo/types.test.js +2 -3
  80. package/dist/otel/exporter.test.js +893 -0
  81. package/dist/otel/mod.cjs +256 -0
  82. package/dist/otel/mod.d.cts +230 -0
  83. package/dist/otel/mod.d.ts +232 -0
  84. package/dist/otel/mod.js +255 -0
  85. package/dist/{owner-kQRGVXG1.d.ts → owner-BgI8C-VY.d.ts} +1 -2
  86. package/dist/{owner-B4HbyP8s.d.cts → owner-C-zfmVAD.d.cts} +1 -2
  87. package/dist/{owner-CIWnopkT.js → owner-Cejm-F7S.js} +2 -2
  88. package/dist/{proof-D-5ri6rf.js → proof-BOQBHd-i.js} +3 -2
  89. package/dist/{proof-fEwcA7LA.cjs → proof-Bmi8ZIcW.cjs} +24 -25
  90. package/dist/{proof-C8-2l0zH.js → proof-CnaEQ_Ev.js} +4 -5
  91. package/dist/router-D9eI0s4b.js +118 -0
  92. package/dist/{send-CPGk9QKZ.js → send-jFxXfsN8.js} +38 -4
  93. package/dist/sig/http.test.js +6 -7
  94. package/dist/sig/key.test.js +5 -5
  95. package/dist/sig/ld.test.js +6 -6
  96. package/dist/sig/mod.cjs +3 -5
  97. package/dist/sig/mod.d.cts +3 -5
  98. package/dist/sig/mod.d.ts +3 -5
  99. package/dist/sig/mod.js +3 -5
  100. package/dist/sig/owner.test.js +6 -7
  101. package/dist/sig/proof.test.js +6 -6
  102. package/dist/testing/mod.d.ts +173 -7006
  103. package/dist/testing/mod.js +4 -3
  104. package/dist/{transformers-CoBS-oFG.cjs → transformers-BjBg6Lag.cjs} +2 -2
  105. package/dist/{transformers-BFT6d7J5.js → transformers-N_ip_y4P.js} +2 -2
  106. package/dist/{types-BtUjyi5y.js → types-8l28uC8o.js} +30 -25
  107. package/dist/{types-CWgzGaqk.cjs → types-B6z6CqIz.cjs} +30 -25
  108. package/dist/{types-C2XVl6gj.js → types-CPz01LGH.js} +3 -3
  109. package/dist/utils/docloader.test.js +7 -8
  110. package/dist/utils/kv-cache.test.js +5 -3
  111. package/dist/utils/mod.cjs +3 -5
  112. package/dist/utils/mod.d.cts +3 -4
  113. package/dist/utils/mod.d.ts +3 -4
  114. package/dist/utils/mod.js +3 -5
  115. package/dist/vocab/mod.cjs +8 -81
  116. package/dist/vocab/mod.d.cts +1 -4
  117. package/dist/vocab/mod.d.ts +1 -4
  118. package/dist/vocab/mod.js +1 -5
  119. package/package.json +27 -27
  120. package/dist/actor-BT-e5fn9.js +0 -146
  121. package/dist/actor-B_gRMloq.js +0 -41647
  122. package/dist/actor-CBfPjuWj.cjs +0 -42079
  123. package/dist/actor-DqFajh9s.d.ts +0 -130
  124. package/dist/actor-f2NtjyCg.d.cts +0 -128
  125. package/dist/fixtures/activitypub.academy/users/brauca_darradiul.json +0 -83
  126. package/dist/fixtures/example.com/announce.json +0 -6
  127. package/dist/fixtures/example.com/collection.json +0 -19
  128. package/dist/fixtures/example.com/create.json +0 -6
  129. package/dist/fixtures/example.com/cross-origin-actor.json +0 -6
  130. package/dist/fixtures/example.com/hong-gildong.json +0 -11
  131. package/dist/fixtures/example.com/invite.json +0 -7
  132. package/dist/fixtures/example.com/key.json +0 -7
  133. package/dist/fixtures/example.com/key2.json +0 -6
  134. package/dist/fixtures/example.com/object.json +0 -6
  135. package/dist/fixtures/example.com/orderedcollectionpage.json +0 -24
  136. package/dist/fixtures/example.com/paged/a.json +0 -13
  137. package/dist/fixtures/example.com/paged/b.json +0 -16
  138. package/dist/fixtures/example.com/paged-collection.json +0 -6
  139. package/dist/fixtures/example.com/person.json +0 -22
  140. package/dist/fixtures/example.com/person2.json +0 -40
  141. package/dist/fixtures/example.com/test.json +0 -5
  142. package/dist/fixtures/example.com/users/handle.json +0 -16
  143. package/dist/fixtures/example.com/wrong-type.json +0 -3
  144. package/dist/fixtures/media.example.com/avatars/test-avatar.jpg.json +0 -6
  145. package/dist/fixtures/oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd.json +0 -24
  146. package/dist/fixtures/remote.domain/users/bob.json +0 -20
  147. package/dist/fixtures/server.example/users/alice.json +0 -20
  148. package/dist/fixtures/w3id.org/identity/v1.json +0 -152
  149. package/dist/fixtures/w3id.org/security/data-integrity/v1.json +0 -74
  150. package/dist/fixtures/w3id.org/security/multikey/v1.json +0 -35
  151. package/dist/fixtures/w3id.org/security/v1.json +0 -50
  152. package/dist/fixtures/wizard.casa/users/hongminhee.json +0 -69
  153. package/dist/fixtures/www.w3.org/ns/activitystreams.json +0 -379
  154. package/dist/fixtures/www.w3.org/ns/did/v1.json +0 -58
  155. package/dist/lookup-BTqtVATt.cjs +0 -266
  156. package/dist/lookup-DOSnR912.js +0 -254
  157. package/dist/lookup-Dj9-mgOn.js +0 -42184
  158. package/dist/middleware-CxswDtQn.js +0 -15
  159. package/dist/middleware-CyITsnX0.js +0 -26
  160. package/dist/middleware-Z8lc_drL.cjs +0 -15
  161. package/dist/mod-BlVovdcy.d.ts +0 -309
  162. package/dist/mod-BxRCHTz-.d.cts +0 -307
  163. package/dist/mod-C58MZ7Wx.d.cts +0 -113
  164. package/dist/mod-CcDPcLJW.d.cts +0 -1
  165. package/dist/mod-Ds0mpFZU.d.ts +0 -115
  166. package/dist/mod-bjzj5QIb.d.ts +0 -2
  167. package/dist/otel-1BmGPuZc.js +0 -64
  168. package/dist/src/vocab/accept.yaml +0 -15
  169. package/dist/src/vocab/activity.yaml +0 -98
  170. package/dist/src/vocab/add.yaml +0 -16
  171. package/dist/src/vocab/announce.yaml +0 -30
  172. package/dist/src/vocab/application.yaml +0 -324
  173. package/dist/src/vocab/arrive.yaml +0 -15
  174. package/dist/src/vocab/article.yaml +0 -46
  175. package/dist/src/vocab/audio.yaml +0 -11
  176. package/dist/src/vocab/block.yaml +0 -16
  177. package/dist/src/vocab/chatmessage.yaml +0 -50
  178. package/dist/src/vocab/collection.yaml +0 -154
  179. package/dist/src/vocab/collectionpage.yaml +0 -55
  180. package/dist/src/vocab/create.yaml +0 -28
  181. package/dist/src/vocab/dataintegrityproof.yaml +0 -56
  182. package/dist/src/vocab/delete.yaml +0 -27
  183. package/dist/src/vocab/didservice.yaml +0 -22
  184. package/dist/src/vocab/dislike.yaml +0 -14
  185. package/dist/src/vocab/document.yaml +0 -31
  186. package/dist/src/vocab/emoji.yaml +0 -12
  187. package/dist/src/vocab/emojireact.yaml +0 -17
  188. package/dist/src/vocab/endpoints.yaml +0 -85
  189. package/dist/src/vocab/event.yaml +0 -11
  190. package/dist/src/vocab/export.yaml +0 -9
  191. package/dist/src/vocab/flag.yaml +0 -15
  192. package/dist/src/vocab/follow.yaml +0 -19
  193. package/dist/src/vocab/group.yaml +0 -324
  194. package/dist/src/vocab/hashtag.yaml +0 -14
  195. package/dist/src/vocab/ignore.yaml +0 -14
  196. package/dist/src/vocab/image.yaml +0 -9
  197. package/dist/src/vocab/intransitiveactivity.yaml +0 -15
  198. package/dist/src/vocab/invite.yaml +0 -14
  199. package/dist/src/vocab/join.yaml +0 -14
  200. package/dist/src/vocab/key.yaml +0 -28
  201. package/dist/src/vocab/leave.yaml +0 -14
  202. package/dist/src/vocab/like.yaml +0 -16
  203. package/dist/src/vocab/link.yaml +0 -101
  204. package/dist/src/vocab/listen.yaml +0 -12
  205. package/dist/src/vocab/mention.yaml +0 -9
  206. package/dist/src/vocab/move.yaml +0 -15
  207. package/dist/src/vocab/multikey.yaml +0 -36
  208. package/dist/src/vocab/note.yaml +0 -48
  209. package/dist/src/vocab/object.yaml +0 -404
  210. package/dist/src/vocab/offer.yaml +0 -15
  211. package/dist/src/vocab/orderedcollection.yaml +0 -39
  212. package/dist/src/vocab/orderedcollectionpage.yaml +0 -50
  213. package/dist/src/vocab/organization.yaml +0 -324
  214. package/dist/src/vocab/page.yaml +0 -11
  215. package/dist/src/vocab/person.yaml +0 -324
  216. package/dist/src/vocab/place.yaml +0 -75
  217. package/dist/src/vocab/profile.yaml +0 -26
  218. package/dist/src/vocab/propertyvalue.yaml +0 -32
  219. package/dist/src/vocab/question.yaml +0 -103
  220. package/dist/src/vocab/read.yaml +0 -13
  221. package/dist/src/vocab/reject.yaml +0 -14
  222. package/dist/src/vocab/relationship.yaml +0 -52
  223. package/dist/src/vocab/remove.yaml +0 -14
  224. package/dist/src/vocab/service.yaml +0 -324
  225. package/dist/src/vocab/source.yaml +0 -26
  226. package/dist/src/vocab/tentativeaccept.yaml +0 -14
  227. package/dist/src/vocab/tentativereject.yaml +0 -14
  228. package/dist/src/vocab/tombstone.yaml +0 -24
  229. package/dist/src/vocab/travel.yaml +0 -16
  230. package/dist/src/vocab/undo.yaml +0 -26
  231. package/dist/src/vocab/update.yaml +0 -58
  232. package/dist/src/vocab/video.yaml +0 -11
  233. package/dist/src/vocab/view.yaml +0 -13
  234. package/dist/testing/docloader.test.js +0 -22
  235. package/dist/vocab/actor.test.js +0 -5963
  236. package/dist/vocab/lookup.test.d.ts +0 -3
  237. package/dist/vocab/lookup.test.js +0 -476
  238. package/dist/vocab/type.test.d.ts +0 -3
  239. package/dist/vocab/type.test.js +0 -24
  240. package/dist/vocab/vocab.test.d.ts +0 -3
  241. package/dist/vocab/vocab.test.js +0 -9397
  242. package/dist/vocab-BCWe1Ih5.d.ts +0 -14905
  243. package/dist/vocab-ByUp-A2_.js +0 -260
  244. package/dist/vocab-CeDBzu-f.d.cts +0 -14903
  245. package/dist/vocab-X_X5T8D3.cjs +0 -296
  246. package/dist/webfinger/handler.test.d.ts +0 -3
  247. package/dist/webfinger/lookup.test.d.ts +0 -3
  248. package/dist/webfinger/lookup.test.js +0 -193
  249. package/dist/webfinger/mod.cjs +0 -8
  250. package/dist/webfinger/mod.d.cts +0 -2
  251. package/dist/webfinger/mod.d.ts +0 -4
  252. package/dist/webfinger/mod.js +0 -8
  253. package/dist/webfinger-C72Y8lrh.js +0 -4
  254. package/dist/webfinger-vAtLmxOF.cjs +0 -4
  255. /package/dist/{collection-BzWsN9pB.js → collection-CcnIw1qY.js} +0 -0
  256. /package/dist/{testing/docloader.test.d.ts → federation/webfinger.test.d.ts} +0 -0
  257. /package/dist/{mod-CVgZgliM.d.ts → mod-1E3W847c.d.ts} +0 -0
  258. /package/dist/{mod-B-hUPT2N.d.cts → mod-C81L6_lQ.d.cts} +0 -0
  259. /package/dist/{negotiation-C4nFufNk.js → negotiation-5NPJL6zp.js} +0 -0
  260. /package/dist/{nodeinfo-BnthBobC.js → nodeinfo-BlLsRSiT.js} +0 -0
  261. /package/dist/{nodeinfo-CdN0rEnZ.cjs → nodeinfo-DuMYTpbZ.cjs} +0 -0
  262. /package/dist/{vocab/actor.test.d.ts → otel/exporter.test.d.ts} +0 -0
  263. /package/dist/{retry-CfF8Gn4d.js → retry-D4GJ670a.js} +0 -0
  264. /package/dist/{sig-C34-oHBl.js → sig-CwuONEzF.js} +0 -0
  265. /package/dist/{sig-YYj5tCnr.cjs → sig-DeXX2xnj.cjs} +0 -0
  266. /package/dist/{utils-DyRU1gdZ.cjs → utils-Db0ZmjcD.cjs} +0 -0
  267. /package/dist/{utils-D-Va7aXC.js → utils-Wranxuoe.js} +0 -0
@@ -0,0 +1,255 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+ import { URLPattern } from "urlpattern-polyfill";
4
+
5
+ import { getLogger } from "@logtape/logtape";
6
+ import { ExportResultCode } from "@opentelemetry/core";
7
+
8
+ //#region src/otel/exporter.ts
9
+ /**
10
+ * A SpanExporter that persists ActivityPub activity traces to a
11
+ * {@link KvStore}. This enables distributed tracing across multiple
12
+ * nodes in a Fedify deployment.
13
+ *
14
+ * The exporter captures activity data from OpenTelemetry span events
15
+ * (`activitypub.activity.received` and `activitypub.activity.sent`)
16
+ * and stores them in the KvStore with trace context preserved.
17
+ *
18
+ * @example Basic usage with MemoryKvStore
19
+ * ```typescript ignore
20
+ * import { MemoryKvStore } from "@fedify/fedify";
21
+ * import { FedifySpanExporter } from "@fedify/fedify/otel";
22
+ * import {
23
+ * BasicTracerProvider,
24
+ * SimpleSpanProcessor,
25
+ * } from "@opentelemetry/sdk-trace-base";
26
+ *
27
+ * const kv = new MemoryKvStore();
28
+ * const exporter = new FedifySpanExporter(kv, {
29
+ * ttl: Temporal.Duration.from({ hours: 1 }),
30
+ * });
31
+ *
32
+ * const provider = new BasicTracerProvider({
33
+ * spanProcessors: [new SimpleSpanProcessor(exporter)],
34
+ * });
35
+ * ```
36
+ *
37
+ * @example Querying stored traces
38
+ * ```typescript ignore
39
+ * import { MemoryKvStore } from "@fedify/fedify";
40
+ * import { FedifySpanExporter } from "@fedify/fedify/otel";
41
+ *
42
+ * const kv = new MemoryKvStore();
43
+ * const exporter = new FedifySpanExporter(kv);
44
+ * const traceId = "abc123";
45
+ *
46
+ * // Get all activities for a specific trace
47
+ * const activities = await exporter.getActivitiesByTraceId(traceId);
48
+ *
49
+ * // Get recent traces
50
+ * const recentTraces = await exporter.getRecentTraces({ limit: 100 });
51
+ * ```
52
+ *
53
+ * @since 1.10.0
54
+ */
55
+ var FedifySpanExporter = class {
56
+ #kv;
57
+ #ttl;
58
+ #keyPrefix;
59
+ /**
60
+ * Creates a new FedifySpanExporter.
61
+ *
62
+ * @param kv The KvStore to persist trace data to.
63
+ * @param options Configuration options.
64
+ */
65
+ constructor(kv, options) {
66
+ this.#kv = kv;
67
+ this.#ttl = options?.ttl;
68
+ this.#keyPrefix = options?.keyPrefix ?? ["fedify", "traces"];
69
+ }
70
+ /**
71
+ * Exports spans to the KvStore.
72
+ *
73
+ * @param spans The spans to export.
74
+ * @param resultCallback Callback to invoke with the export result.
75
+ */
76
+ export(spans, resultCallback) {
77
+ this.#exportAsync(spans).then(() => resultCallback({ code: ExportResultCode.SUCCESS })).catch((error) => {
78
+ getLogger([
79
+ "fedify",
80
+ "otel",
81
+ "exporter"
82
+ ]).error("Failed to export spans to KvStore: {error}", { error });
83
+ resultCallback({ code: ExportResultCode.FAILED });
84
+ });
85
+ }
86
+ async #exportAsync(spans) {
87
+ const storeOperations = [];
88
+ for (const span of spans) {
89
+ const records = this.#extractRecords(span);
90
+ for (const record of records) storeOperations.push(this.#storeRecord(record));
91
+ }
92
+ const results = await Promise.allSettled(storeOperations);
93
+ const rejected = results.filter((r) => r.status === "rejected");
94
+ if (rejected.length > 0) throw new AggregateError(rejected.map((r) => r.reason), "Failed to store one or more trace activity records.");
95
+ }
96
+ #extractRecords(span) {
97
+ const records = [];
98
+ const spanContext = span.spanContext();
99
+ const traceId = spanContext.traceId;
100
+ const spanId = spanContext.spanId;
101
+ const parentSpanId = span.parentSpanContext?.spanId;
102
+ for (const event of span.events) if (event.name === "activitypub.activity.received") {
103
+ const record = this.#extractInboundRecord(event, traceId, spanId, parentSpanId);
104
+ if (record != null) records.push(record);
105
+ } else if (event.name === "activitypub.activity.sent") {
106
+ const record = this.#extractOutboundRecord(event, traceId, spanId, parentSpanId);
107
+ if (record != null) records.push(record);
108
+ }
109
+ return records;
110
+ }
111
+ #extractInboundRecord(event, traceId, spanId, parentSpanId) {
112
+ const attrs = event.attributes;
113
+ if (attrs == null) return null;
114
+ const activityJson = attrs["activitypub.activity.json"];
115
+ if (typeof activityJson !== "string") return null;
116
+ let activityType = "Unknown";
117
+ let activityId;
118
+ let actorId;
119
+ try {
120
+ const activity = JSON.parse(activityJson);
121
+ activityType = activity.type ?? "Unknown";
122
+ activityId = activity.id;
123
+ if (typeof activity.actor === "string") actorId = activity.actor;
124
+ else if (activity.actor != null && typeof activity.actor.id === "string") actorId = activity.actor.id;
125
+ } catch {}
126
+ const verified = attrs["activitypub.activity.verified"];
127
+ const httpSigVerified = attrs["http_signatures.verified"];
128
+ const httpSigKeyId = attrs["http_signatures.key_id"];
129
+ const ldSigVerified = attrs["ld_signatures.verified"];
130
+ let signatureDetails;
131
+ if (typeof httpSigVerified === "boolean" || typeof ldSigVerified === "boolean") signatureDetails = {
132
+ httpSignaturesVerified: httpSigVerified === true,
133
+ httpSignaturesKeyId: typeof httpSigKeyId === "string" && httpSigKeyId !== "" ? httpSigKeyId : void 0,
134
+ ldSignaturesVerified: ldSigVerified === true
135
+ };
136
+ return {
137
+ traceId,
138
+ spanId,
139
+ parentSpanId,
140
+ direction: "inbound",
141
+ activityType,
142
+ activityId,
143
+ actorId,
144
+ activityJson,
145
+ verified: typeof verified === "boolean" ? verified : void 0,
146
+ signatureDetails,
147
+ timestamp: (/* @__PURE__ */ new Date(event.time[0] * 1e3 + event.time[1] / 1e6)).toISOString()
148
+ };
149
+ }
150
+ #extractOutboundRecord(event, traceId, spanId, parentSpanId) {
151
+ const attrs = event.attributes;
152
+ if (attrs == null) return null;
153
+ const activityJson = attrs["activitypub.activity.json"];
154
+ if (typeof activityJson !== "string") return null;
155
+ let activityType = "Unknown";
156
+ let activityId;
157
+ let actorId;
158
+ try {
159
+ const activity = JSON.parse(activityJson);
160
+ activityType = activity.type ?? "Unknown";
161
+ activityId = activity.id;
162
+ if (typeof activity.actor === "string") actorId = activity.actor;
163
+ else if (activity.actor != null && typeof activity.actor.id === "string") actorId = activity.actor.id;
164
+ } catch {}
165
+ const inboxUrl = attrs["activitypub.inbox.url"];
166
+ const explicitActivityId = attrs["activitypub.activity.id"];
167
+ return {
168
+ traceId,
169
+ spanId,
170
+ parentSpanId,
171
+ direction: "outbound",
172
+ activityType,
173
+ activityId: activityId ?? (typeof explicitActivityId === "string" && explicitActivityId !== "" ? explicitActivityId : void 0),
174
+ actorId,
175
+ activityJson,
176
+ timestamp: (/* @__PURE__ */ new Date(event.time[0] * 1e3 + event.time[1] / 1e6)).toISOString(),
177
+ inboxUrl: typeof inboxUrl === "string" ? inboxUrl : void 0
178
+ };
179
+ }
180
+ async #storeRecord(record) {
181
+ const options = this.#ttl != null ? { ttl: this.#ttl } : void 0;
182
+ const key = [
183
+ ...this.#keyPrefix,
184
+ record.traceId,
185
+ record.spanId
186
+ ];
187
+ await this.#kv.set(key, record, options);
188
+ await this.#updateTraceSummary(record, options);
189
+ }
190
+ async #setWithCasRetry(key, transform, options) {
191
+ if (this.#kv.cas != null) for (let attempt = 0; attempt < 3; attempt++) {
192
+ const existing$1 = await this.#kv.get(key);
193
+ const newValue$1 = transform(existing$1);
194
+ if (await this.#kv.cas(key, existing$1, newValue$1, options)) return;
195
+ }
196
+ const existing = await this.#kv.get(key);
197
+ const newValue = transform(existing);
198
+ await this.#kv.set(key, newValue, options);
199
+ }
200
+ async #updateTraceSummary(record, options) {
201
+ const summaryKey = [
202
+ ...this.#keyPrefix,
203
+ "_summaries",
204
+ record.traceId
205
+ ];
206
+ await this.#setWithCasRetry(summaryKey, (existing) => {
207
+ const activityCount = existing != null ? existing.activityCount + 1 : 1;
208
+ const activityTypes = existing != null ? existing.activityTypes.includes(record.activityType) ? existing.activityTypes : [...existing.activityTypes, record.activityType] : [record.activityType];
209
+ return {
210
+ traceId: existing?.traceId ?? record.traceId,
211
+ timestamp: existing?.timestamp ?? record.timestamp,
212
+ activityCount,
213
+ activityTypes
214
+ };
215
+ }, options);
216
+ }
217
+ /**
218
+ * Gets all activity records for a specific trace ID.
219
+ *
220
+ * @param traceId The trace ID to query.
221
+ * @returns An array of activity records belonging to the trace.
222
+ */
223
+ async getActivitiesByTraceId(traceId) {
224
+ const prefix = [...this.#keyPrefix, traceId];
225
+ const records = [];
226
+ for await (const entry of this.#kv.list(prefix)) records.push(entry.value);
227
+ return records;
228
+ }
229
+ /**
230
+ * Gets recent traces with summary information.
231
+ *
232
+ * @param options Options for the query.
233
+ * @returns An array of trace summaries.
234
+ */
235
+ async getRecentTraces(options) {
236
+ const summaryPrefix = [...this.#keyPrefix, "_summaries"];
237
+ const summaries = [];
238
+ for await (const entry of this.#kv.list(summaryPrefix)) summaries.push(entry.value);
239
+ summaries.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
240
+ if (options?.limit != null) return summaries.slice(0, options.limit);
241
+ return summaries;
242
+ }
243
+ /**
244
+ * Forces the exporter to flush any buffered data.
245
+ * This is a no-op because we write directly to the KvStore without buffering.
246
+ */
247
+ async forceFlush() {}
248
+ /**
249
+ * Shuts down the exporter.
250
+ */
251
+ async shutdown() {}
252
+ };
253
+
254
+ //#endregion
255
+ export { FedifySpanExporter };
@@ -1,7 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { Activity, CryptographicKey } from "./vocab-BCWe1Ih5.js";
4
- import { Actor } from "./actor-DqFajh9s.js";
3
+ import { Activity, Actor, CryptographicKey } from "@fedify/vocab";
5
4
  import { TracerProvider } from "@opentelemetry/api";
6
5
  import { DocumentLoader } from "@fedify/vocab-runtime";
7
6
 
@@ -1,5 +1,4 @@
1
- import { Activity, CryptographicKey } from "./vocab-CeDBzu-f.cjs";
2
- import { Actor } from "./actor-f2NtjyCg.cjs";
1
+ import { Activity, Actor, CryptographicKey } from "@fedify/vocab";
3
2
  import { DocumentLoader } from "@fedify/vocab-runtime";
4
3
  import { TracerProvider } from "@opentelemetry/api";
5
4
 
@@ -3,8 +3,8 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { CryptographicKey, Object as Object$1, deno_default } from "./lookup-Dj9-mgOn.js";
7
- import { isActor } from "./actor-BT-e5fn9.js";
6
+ import { deno_default } from "./deno-DGx1JZHr.js";
7
+ import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
8
8
  import { getDocumentLoader } from "@fedify/vocab-runtime";
9
9
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
10
10
 
@@ -3,9 +3,10 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { Activity, DataIntegrityProof, Multikey, deno_default, getTypeId } from "./lookup-Dj9-mgOn.js";
7
- import { fetchKey, validateCryptoKey } from "./key-x7E5PYI0.js";
6
+ import { deno_default } from "./deno-DGx1JZHr.js";
7
+ import { fetchKey, validateCryptoKey } from "./key-BCtt1Ugy.js";
8
8
  import { getLogger } from "@logtape/logtape";
9
+ import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
9
10
  import { SpanStatusCode, trace } from "@opentelemetry/api";
10
11
  import { encodeHex } from "byte-encodings/hex";
11
12
  import serialize from "json-canon";
@@ -3,15 +3,14 @@
3
3
  const { URLPattern } = require("urlpattern-polyfill");
4
4
 
5
5
  const require_chunk = require('./chunk-DqRYRqnO.cjs');
6
- const require_lookup = require('./lookup-BTqtVATt.cjs');
7
- const require_actor = require('./actor-CBfPjuWj.cjs');
8
- const require_http = require('./http-Dxpqz4hE.cjs');
6
+ const require_http = require('./http-DKBUv5zZ.cjs');
9
7
  const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
8
+ const __fedify_vocab = require_chunk.__toESM(require("@fedify/vocab"));
10
9
  const __opentelemetry_api = require_chunk.__toESM(require("@opentelemetry/api"));
11
- const jsonld = require_chunk.__toESM(require("jsonld"));
12
- const __fedify_vocab_runtime = require_chunk.__toESM(require("@fedify/vocab-runtime"));
13
10
  const byte_encodings_hex = require_chunk.__toESM(require("byte-encodings/hex"));
14
11
  const byte_encodings_base64 = require_chunk.__toESM(require("byte-encodings/base64"));
12
+ const __fedify_vocab_runtime = require_chunk.__toESM(require("@fedify/vocab-runtime"));
13
+ const jsonld = require_chunk.__toESM(require("jsonld"));
15
14
  const json_canon = require_chunk.__toESM(require("json-canon"));
16
15
 
17
16
  //#region src/sig/ld.ts
@@ -82,7 +81,7 @@ async function createSignature(jsonLd, privateKey, keyId, { contextLoader, creat
82
81
  */
83
82
  async function signJsonLd(jsonLd, privateKey, keyId, options) {
84
83
  const tracerProvider = options.tracerProvider ?? __opentelemetry_api.trace.getTracerProvider();
85
- const tracer = tracerProvider.getTracer(require_lookup.deno_default.name, require_lookup.deno_default.version);
84
+ const tracer = tracerProvider.getTracer(require_http.deno_default.name, require_http.deno_default.version);
86
85
  return await tracer.startActiveSpan("ld_signatures.sign", { attributes: { "ld_signatures.key_id": keyId.href } }, async (span) => {
87
86
  try {
88
87
  const signature = await createSignature(jsonLd, privateKey, keyId, options);
@@ -151,7 +150,7 @@ async function verifySignature(jsonLd, options = {}) {
151
150
  });
152
151
  return null;
153
152
  }
154
- const { key, cached } = await require_http.fetchKey(new URL(sig.creator), require_actor.CryptographicKey, options);
153
+ const { key, cached } = await require_http.fetchKey(new URL(sig.creator), __fedify_vocab.CryptographicKey, options);
155
154
  if (key == null) return null;
156
155
  const sigOpts = {
157
156
  ...sig,
@@ -192,7 +191,7 @@ async function verifySignature(jsonLd, options = {}) {
192
191
  keyId: sig.creator,
193
192
  ...sig
194
193
  });
195
- const { key: key$1 } = await require_http.fetchKey(new URL(sig.creator), require_actor.CryptographicKey, {
194
+ const { key: key$1 } = await require_http.fetchKey(new URL(sig.creator), __fedify_vocab.CryptographicKey, {
196
195
  ...options,
197
196
  keyCache: {
198
197
  get: () => Promise.resolve(void 0),
@@ -221,19 +220,19 @@ async function verifySignature(jsonLd, options = {}) {
221
220
  */
222
221
  async function verifyJsonLd(jsonLd, options = {}) {
223
222
  const tracerProvider = options.tracerProvider ?? __opentelemetry_api.trace.getTracerProvider();
224
- const tracer = tracerProvider.getTracer(require_lookup.deno_default.name, require_lookup.deno_default.version);
223
+ const tracer = tracerProvider.getTracer(require_http.deno_default.name, require_http.deno_default.version);
225
224
  return await tracer.startActiveSpan("ld_signatures.verify", async (span) => {
226
225
  try {
227
- const object = await require_actor.Object.fromJsonLd(jsonLd, options);
226
+ const object = await __fedify_vocab.Object.fromJsonLd(jsonLd, options);
228
227
  if (object.id != null) span.setAttribute("activitypub.object.id", object.id.href);
229
- span.setAttribute("activitypub.object.type", require_actor.getTypeId(object).href);
228
+ span.setAttribute("activitypub.object.type", (0, __fedify_vocab.getTypeId)(object).href);
230
229
  if (typeof jsonLd === "object" && jsonLd != null && "signature" in jsonLd && typeof jsonLd.signature === "object" && jsonLd.signature != null) {
231
230
  if ("creator" in jsonLd.signature && typeof jsonLd.signature.creator === "string") span.setAttribute("ld_signatures.key_id", jsonLd.signature.creator);
232
231
  if ("signatureValue" in jsonLd.signature && typeof jsonLd.signature.signatureValue === "string") span.setAttribute("ld_signatures.signature", jsonLd.signature.signatureValue);
233
232
  if ("type" in jsonLd.signature && typeof jsonLd.signature.type === "string") span.setAttribute("ld_signatures.type", jsonLd.signature.type);
234
233
  }
235
234
  const attributions = new Set(object.attributionIds.map((uri) => uri.href));
236
- if (object instanceof require_actor.Activity) for (const uri of object.actorIds) attributions.add(uri.href);
235
+ if (object instanceof __fedify_vocab.Activity) for (const uri of object.actorIds) attributions.add(uri.href);
237
236
  const key = await verifySignature(jsonLd, options);
238
237
  if (key == null) return false;
239
238
  if (key.ownerId == null) {
@@ -278,7 +277,7 @@ async function hashJsonLd(jsonLd, contextLoader) {
278
277
  */
279
278
  async function doesActorOwnKey(activity, key, options) {
280
279
  const tracerProvider = options.tracerProvider ?? __opentelemetry_api.trace.getTracerProvider();
281
- const tracer = tracerProvider.getTracer(require_lookup.deno_default.name, require_lookup.deno_default.version);
280
+ const tracer = tracerProvider.getTracer(require_http.deno_default.name, require_http.deno_default.version);
282
281
  return await tracer.startActiveSpan("activitypub.verify_key_ownership", {
283
282
  kind: __opentelemetry_api.SpanKind.INTERNAL,
284
283
  attributes: {
@@ -294,7 +293,7 @@ async function doesActorOwnKey(activity, key, options) {
294
293
  return owns;
295
294
  }
296
295
  const actor = await activity.getActor(options);
297
- if (actor == null || !require_actor.isActor(actor)) {
296
+ if (actor == null || !(0, __fedify_vocab.isActor)(actor)) {
298
297
  span.setAttribute("activitypub.key_ownership.verified", false);
299
298
  span.setAttribute("activitypub.key_ownership.method", "actor_fetch");
300
299
  return false;
@@ -334,7 +333,7 @@ async function getKeyOwner(keyId, options) {
334
333
  const documentLoader = options.documentLoader ?? (0, __fedify_vocab_runtime.getDocumentLoader)();
335
334
  const contextLoader = options.contextLoader ?? (0, __fedify_vocab_runtime.getDocumentLoader)();
336
335
  let object;
337
- if (keyId instanceof require_actor.CryptographicKey) {
336
+ if (keyId instanceof __fedify_vocab.CryptographicKey) {
338
337
  object = keyId;
339
338
  if (object.id == null) return null;
340
339
  keyId = object.id;
@@ -347,7 +346,7 @@ async function getKeyOwner(keyId, options) {
347
346
  return null;
348
347
  }
349
348
  try {
350
- object = await require_actor.Object.fromJsonLd(keyDoc, {
349
+ object = await __fedify_vocab.Object.fromJsonLd(keyDoc, {
351
350
  documentLoader,
352
351
  contextLoader,
353
352
  tracerProvider
@@ -355,7 +354,7 @@ async function getKeyOwner(keyId, options) {
355
354
  } catch (e) {
356
355
  if (!(e instanceof TypeError)) throw e;
357
356
  try {
358
- object = await require_actor.CryptographicKey.fromJsonLd(keyDoc, {
357
+ object = await __fedify_vocab.CryptographicKey.fromJsonLd(keyDoc, {
359
358
  documentLoader,
360
359
  contextLoader,
361
360
  tracerProvider
@@ -367,14 +366,14 @@ async function getKeyOwner(keyId, options) {
367
366
  }
368
367
  }
369
368
  let owner = null;
370
- if (object instanceof require_actor.CryptographicKey) {
369
+ if (object instanceof __fedify_vocab.CryptographicKey) {
371
370
  if (object.ownerId == null) return null;
372
371
  owner = await object.getOwner({
373
372
  documentLoader,
374
373
  contextLoader,
375
374
  tracerProvider
376
375
  });
377
- } else if (require_actor.isActor(object)) owner = object;
376
+ } else if ((0, __fedify_vocab.isActor)(object)) owner = object;
378
377
  else return null;
379
378
  if (owner == null) return null;
380
379
  for (const kid of owner.publicKeyIds) if (kid.href === keyId.href) return owner;
@@ -427,7 +426,7 @@ async function createProof(object, privateKey, keyId, { contextLoader, context,
427
426
  digest.set(new Uint8Array(proofDigest), 0);
428
427
  digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
429
428
  const sig = await crypto.subtle.sign("Ed25519", privateKey, digest);
430
- return new require_actor.DataIntegrityProof({
429
+ return new __fedify_vocab.DataIntegrityProof({
431
430
  cryptosuite: "eddsa-jcs-2022",
432
431
  verificationMethod: keyId,
433
432
  proofPurpose: "assertionMethod",
@@ -447,8 +446,8 @@ async function createProof(object, privateKey, keyId, { contextLoader, context,
447
446
  */
448
447
  async function signObject(object, privateKey, keyId, options = {}) {
449
448
  const tracerProvider = options.tracerProvider ?? __opentelemetry_api.trace.getTracerProvider();
450
- const tracer = tracerProvider.getTracer(require_lookup.deno_default.name, require_lookup.deno_default.version);
451
- return await tracer.startActiveSpan("object_integrity_proofs.sign", { attributes: { "activitypub.object.type": require_actor.getTypeId(object).href } }, async (span) => {
449
+ const tracer = tracerProvider.getTracer(require_http.deno_default.name, require_http.deno_default.version);
450
+ return await tracer.startActiveSpan("object_integrity_proofs.sign", { attributes: { "activitypub.object.type": (0, __fedify_vocab.getTypeId)(object).href } }, async (span) => {
452
451
  try {
453
452
  if (object.id != null) span.setAttribute("activitypub.object.id", object.id.href);
454
453
  const existingProofs = [];
@@ -483,7 +482,7 @@ async function signObject(object, privateKey, keyId, options = {}) {
483
482
  */
484
483
  async function verifyProof(jsonLd, proof, options = {}) {
485
484
  const tracerProvider = options.tracerProvider ?? __opentelemetry_api.trace.getTracerProvider();
486
- const tracer = tracerProvider.getTracer(require_lookup.deno_default.name, require_lookup.deno_default.version);
485
+ const tracer = tracerProvider.getTracer(require_http.deno_default.name, require_http.deno_default.version);
487
486
  return await tracer.startActiveSpan("object_integrity_proofs.verify", async (span) => {
488
487
  if (span.isRecording()) {
489
488
  if (proof.cryptosuite != null) span.setAttribute("object_integrity_proofs.cryptosuite", proof.cryptosuite);
@@ -507,7 +506,7 @@ async function verifyProof(jsonLd, proof, options = {}) {
507
506
  }
508
507
  async function verifyProofInternal(jsonLd, proof, options) {
509
508
  if (typeof jsonLd !== "object" || proof.cryptosuite !== "eddsa-jcs-2022" || proof.verificationMethodId == null || proof.proofPurpose !== "assertionMethod" || proof.proofValue == null || proof.created == null) return null;
510
- const publicKeyPromise = require_http.fetchKey(proof.verificationMethodId, require_actor.Multikey, options);
509
+ const publicKeyPromise = require_http.fetchKey(proof.verificationMethodId, __fedify_vocab.Multikey, options);
511
510
  const proofConfig = {
512
511
  "@context": jsonLd["@context"],
513
512
  type: "DataIntegrityProof",
@@ -612,7 +611,7 @@ async function verifyObject(cls, jsonLd, options = {}) {
612
611
  ]);
613
612
  const object = await cls.fromJsonLd(jsonLd, options);
614
613
  const attributions = new Set(object.attributionIds.map((uri) => uri.href));
615
- if (object instanceof require_actor.Activity) for (const uri of object.actorIds) attributions.add(uri.href);
614
+ if (object instanceof __fedify_vocab.Activity) for (const uri of object.actorIds) attributions.add(uri.href);
616
615
  for await (const proof of object.getProofs(options)) {
617
616
  const key = await verifyProof(jsonLd, proof, options);
618
617
  if (key === null) return null;
@@ -2,15 +2,14 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
- import { deno_default } from "./lookup-DOSnR912.js";
6
- import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, getTypeId, isActor } from "./actor-B_gRMloq.js";
7
- import { fetchKey, validateCryptoKey } from "./http-YhR_TMMQ.js";
5
+ import { deno_default, fetchKey, validateCryptoKey } from "./http-CL3G0rnf.js";
8
6
  import { getLogger } from "@logtape/logtape";
7
+ import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, getTypeId, isActor } from "@fedify/vocab";
9
8
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
10
- import jsonld from "jsonld";
11
- import { getDocumentLoader } from "@fedify/vocab-runtime";
12
9
  import { encodeHex } from "byte-encodings/hex";
13
10
  import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
11
+ import { getDocumentLoader } from "@fedify/vocab-runtime";
12
+ import jsonld from "jsonld";
14
13
  import serialize from "json-canon";
15
14
 
16
15
  //#region src/sig/ld.ts
@@ -0,0 +1,118 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+ import { URLPattern } from "urlpattern-polyfill";
4
+ globalThis.addEventListener = () => {};
5
+
6
+ import { cloneDeep } from "es-toolkit";
7
+ import { Router } from "uri-template-router";
8
+ import { parseTemplate } from "url-template";
9
+
10
+ //#region src/federation/router.ts
11
+ function cloneInnerRouter(router) {
12
+ const clone = new Router();
13
+ clone.nid = router.nid;
14
+ clone.fsm = cloneDeep(router.fsm);
15
+ clone.routeSet = new Set(router.routeSet);
16
+ clone.templateRouteMap = new Map(router.templateRouteMap);
17
+ clone.valueRouteMap = new Map(router.valueRouteMap);
18
+ clone.hierarchy = cloneDeep(router.hierarchy);
19
+ return clone;
20
+ }
21
+ /**
22
+ * URL router and constructor based on URI Template
23
+ * ([RFC 6570](https://tools.ietf.org/html/rfc6570)).
24
+ */
25
+ var Router$1 = class Router$1 {
26
+ #router;
27
+ #templates;
28
+ #templateStrings;
29
+ /**
30
+ * Whether to ignore trailing slashes when matching paths.
31
+ * @since 1.6.0
32
+ */
33
+ trailingSlashInsensitive;
34
+ /**
35
+ * Create a new {@link Router}.
36
+ * @param options Options for the router.
37
+ */
38
+ constructor(options = {}) {
39
+ this.#router = new Router();
40
+ this.#templates = {};
41
+ this.#templateStrings = {};
42
+ this.trailingSlashInsensitive = options.trailingSlashInsensitive ?? false;
43
+ }
44
+ clone() {
45
+ const clone = new Router$1({ trailingSlashInsensitive: this.trailingSlashInsensitive });
46
+ clone.#router = cloneInnerRouter(this.#router);
47
+ clone.#templates = { ...this.#templates };
48
+ clone.#templateStrings = { ...this.#templateStrings };
49
+ return clone;
50
+ }
51
+ /**
52
+ * Checks if a path name exists in the router.
53
+ * @param name The name of the path.
54
+ * @returns `true` if the path name exists, otherwise `false`.
55
+ */
56
+ has(name) {
57
+ return name in this.#templates;
58
+ }
59
+ /**
60
+ * Adds a new path rule to the router.
61
+ * @param template The path pattern.
62
+ * @param name The name of the path.
63
+ * @returns The names of the variables in the path pattern.
64
+ */
65
+ add(template, name) {
66
+ if (!template.startsWith("/")) throw new RouterError("Path must start with a slash.");
67
+ const rule = this.#router.addTemplate(template, {}, name);
68
+ this.#templates[name] = parseTemplate(template);
69
+ this.#templateStrings[name] = template;
70
+ return new Set(rule.variables.map((v) => v.varname));
71
+ }
72
+ /**
73
+ * Resolves a path name and values from a URL, if any match.
74
+ * @param url The URL to resolve.
75
+ * @returns The name of the path and its values, if any match. Otherwise,
76
+ * `null`.
77
+ */
78
+ route(url) {
79
+ let match = this.#router.resolveURI(url);
80
+ if (match == null) {
81
+ if (!this.trailingSlashInsensitive) return null;
82
+ url = url.endsWith("/") ? url.replace(/\/+$/, "") : `${url}/`;
83
+ match = this.#router.resolveURI(url);
84
+ if (match == null) return null;
85
+ }
86
+ return {
87
+ name: match.matchValue,
88
+ template: this.#templateStrings[match.matchValue],
89
+ values: match.params
90
+ };
91
+ }
92
+ /**
93
+ * Constructs a URL/path from a path name and values.
94
+ * @param name The name of the path.
95
+ * @param values The values to expand the path with.
96
+ * @returns The URL/path, if the name exists. Otherwise, `null`.
97
+ */
98
+ build(name, values) {
99
+ if (name in this.#templates) return this.#templates[name].expand(values);
100
+ return null;
101
+ }
102
+ };
103
+ /**
104
+ * An error thrown by the {@link Router}.
105
+ */
106
+ var RouterError = class extends Error {
107
+ /**
108
+ * Create a new {@link RouterError}.
109
+ * @param message The error message.
110
+ */
111
+ constructor(message) {
112
+ super(message);
113
+ this.name = "RouterError";
114
+ }
115
+ };
116
+
117
+ //#endregion
118
+ export { Router$1 as Router, RouterError };
@@ -3,8 +3,8 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { deno_default } from "./lookup-Dj9-mgOn.js";
7
- import { doubleKnock } from "./http-DH47B-h3.js";
6
+ import { deno_default } from "./deno-DGx1JZHr.js";
7
+ import { doubleKnock } from "./http-LGtYlSfN.js";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
10
10
 
@@ -120,7 +120,7 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
120
120
  statusText: response.statusText,
121
121
  error
122
122
  });
123
- throw new Error(`Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`);
123
+ throw new SendActivityError(inbox, response.status, `Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`, error);
124
124
  }
125
125
  span.addEvent("activitypub.activity.sent", {
126
126
  "activitypub.activity.json": JSON.stringify(activity),
@@ -128,6 +128,40 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
128
128
  "activitypub.activity.id": activityId ?? ""
129
129
  });
130
130
  }
131
+ /**
132
+ * An error that is thrown when an activity fails to send to a remote inbox.
133
+ * It contains structured information about the failure, including the HTTP
134
+ * status code, the inbox URL, and the response body.
135
+ * @since 2.0.0
136
+ */
137
+ var SendActivityError = class extends Error {
138
+ /**
139
+ * The inbox URL that the activity was being sent to.
140
+ */
141
+ inbox;
142
+ /**
143
+ * The HTTP status code returned by the inbox.
144
+ */
145
+ statusCode;
146
+ /**
147
+ * The response body from the inbox, if any.
148
+ */
149
+ responseBody;
150
+ /**
151
+ * Creates a new {@link SendActivityError}.
152
+ * @param inbox The inbox URL.
153
+ * @param statusCode The HTTP status code.
154
+ * @param message The error message.
155
+ * @param responseBody The response body.
156
+ */
157
+ constructor(inbox, statusCode, message, responseBody) {
158
+ super(message);
159
+ this.name = "SendActivityError";
160
+ this.inbox = inbox;
161
+ this.statusCode = statusCode;
162
+ this.responseBody = responseBody;
163
+ }
164
+ };
131
165
 
132
166
  //#endregion
133
- export { extractInboxes, sendActivity };
167
+ export { SendActivityError, extractInboxes, sendActivity };