@fedify/fedify 2.3.0-dev.994 → 2.3.0-pr.809.36

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 (138) hide show
  1. package/README.md +16 -7
  2. package/dist/{assert-DikXweDx.mjs → assert-OguE97r2.mjs} +1 -1
  3. package/dist/{assert_instance_of-C4Ri6VuN.mjs → assert_instance_of-DBC5X09g.mjs} +1 -1
  4. package/dist/{assert_not_equals--wG9hV7u.mjs → assert_not_equals-DkVK8oqV.mjs} +1 -1
  5. package/dist/{assert_rejects-B-qJtC9Z.mjs → assert_rejects-DN60FHPX.mjs} +28 -3
  6. package/dist/{assert_strict_equals-Dmjbg-bA.mjs → assert_strict_equals-XEgZAlrj.mjs} +1 -1
  7. package/dist/{assert_throws-4NwKEy2q.mjs → assert_throws-BOkhLGYc.mjs} +1 -1
  8. package/dist/{builder-yAlpiIqP.mjs → builder-DSZ7FZmg.mjs} +96 -42
  9. package/dist/{chunk-nlSIicah.js → chunk-CRNNMoPX.js} +2 -2
  10. package/dist/circuit-breaker-CSWsyoef.mjs +337 -0
  11. package/dist/{client-z-8dc-e1.d.cts → client-CAM_bQXx.d.cts} +1 -0
  12. package/dist/{client-AtlibPOU.d.ts → client-CSddvgWN.d.ts} +1 -2
  13. package/dist/compat/mod.d.cts +2 -1
  14. package/dist/compat/mod.d.ts +2 -3
  15. package/dist/compat/mod.js +3 -3
  16. package/dist/compat/outgoing-jsonld.test.mjs +4 -4
  17. package/dist/compat/public-audience.test.mjs +4 -4
  18. package/dist/compat/transformers.test.mjs +5 -5
  19. package/dist/{context-BzH2-ajs.d.ts → context-BBVLF7lx.d.cts} +342 -269
  20. package/dist/{context-DJGagtNd.d.cts → context-BU6jSQdo.d.ts} +344 -266
  21. package/dist/{context-Dk_tacqz.mjs → context-DVoTs_wM.mjs} +64 -5
  22. package/dist/{deno-XBVlKnOX.mjs → deno-DCdM7d93.mjs} +1 -1
  23. package/dist/{docloader-DPp-X6gk.mjs → docloader-B7mVwA5_.mjs} +4 -4
  24. package/dist/{esm-DVILvP5e.mjs → esm-vrlUxr60.mjs} +4 -7
  25. package/dist/federation/builder.test.mjs +163 -11
  26. package/dist/federation/circuit-breaker.test.d.mts +2 -0
  27. package/dist/federation/circuit-breaker.test.mjs +446 -0
  28. package/dist/federation/collection.test.mjs +3 -3
  29. package/dist/federation/handler.test.mjs +1770 -29
  30. package/dist/federation/idempotency.test.mjs +5 -5
  31. package/dist/federation/inbox.test.mjs +4 -4
  32. package/dist/federation/keycache.test.mjs +5 -5
  33. package/dist/federation/kv.test.mjs +2 -2
  34. package/dist/federation/metrics.test.d.mts +2 -0
  35. package/dist/federation/metrics.test.mjs +634 -0
  36. package/dist/federation/middleware.test.mjs +4036 -146
  37. package/dist/federation/mod.cjs +195 -14
  38. package/dist/federation/mod.d.cts +6 -4
  39. package/dist/federation/mod.d.ts +6 -6
  40. package/dist/federation/mod.js +192 -14
  41. package/dist/federation/mq.test.mjs +176 -15
  42. package/dist/federation/negotiation.test.mjs +4 -4
  43. package/dist/federation/retry.test.mjs +3 -3
  44. package/dist/federation/router.test.mjs +190 -9
  45. package/dist/federation/send.test.mjs +153 -15
  46. package/dist/federation/temporal.test.d.mts +2 -0
  47. package/dist/federation/temporal.test.mjs +71 -0
  48. package/dist/federation/webfinger.test.mjs +150 -5
  49. package/dist/{http-CSlLA54v.mjs → http-BufbkLuW.mjs} +146 -47
  50. package/dist/{http-B4rrzxtg.js → http-Dh18nwJg.js} +994 -64
  51. package/dist/{http-aQzN9Ayi.d.ts → http-VyDTd4G3.d.cts} +15 -3
  52. package/dist/{http-BrGqJDXL.cjs → http-gOiudB3g.cjs} +1099 -61
  53. package/dist/{http-CrGuipxe.d.cts → http-lf8Hsd91.d.ts} +15 -1
  54. package/dist/{key-Bzx--sHD.mjs → key-DZdKLJXT.mjs} +43 -18
  55. package/dist/{kv-CbLNp3zQ.d.cts → kv-D6hNiMTK.d.ts} +1 -0
  56. package/dist/{kv-cache-DI-Sk7-I.cjs → kv-cache-BuK_nlpY.cjs} +20 -3
  57. package/dist/{kv-cache-U__xU4qR.mjs → kv-cache-C7SQnkGI.mjs} +21 -3
  58. package/dist/{kv-cache-EMIqoIuB.js → kv-cache-DNDSb6Po.js} +20 -3
  59. package/dist/{kv-GFYnFoOl.d.ts → kv-gJ8LYbxX.d.cts} +1 -3
  60. package/dist/ld-0Lsznacf.mjs +626 -0
  61. package/dist/metrics-BHeWd24f.mjs +815 -0
  62. package/dist/{middleware-zjZ6AFCW.mjs → middleware-BNANvDh2.mjs} +1 -1
  63. package/dist/{middleware-nidH7VZH.js → middleware-BgzRkDcm.js} +2260 -556
  64. package/dist/{middleware-An4DjES4.cjs → middleware-D-iES1nQ.cjs} +2318 -623
  65. package/dist/{middleware-K1g6bEkV.mjs → middleware-EV6J_eAc.mjs} +1639 -373
  66. package/dist/{mod-CR8soWa9.d.ts → mod-B0hW12_O.d.cts} +26 -4
  67. package/dist/mod-C0F6kvgS.d.cts +182 -0
  68. package/dist/{mod-Cr3f-ACa.d.cts → mod-COIAjwRS.d.ts} +26 -2
  69. package/dist/{mod-CMEbIaNh.d.cts → mod-DFvNJcNb.d.ts} +56 -4
  70. package/dist/mod-vPYVoa5n.d.ts +182 -0
  71. package/dist/{mod-CLgIXe9w.d.ts → mod-yvIXFAEi.d.cts} +56 -6
  72. package/dist/mod.cjs +9 -6
  73. package/dist/mod.d.cts +12 -10
  74. package/dist/mod.d.ts +12 -12
  75. package/dist/mod.js +11 -11
  76. package/dist/mq-D-nlpY04.d.ts +208 -0
  77. package/dist/mq-D8uSFzxe.d.cts +208 -0
  78. package/dist/{negotiation-SQvQgUqe.mjs → negotiation-DDstyBvc.mjs} +29 -0
  79. package/dist/nodeinfo/client.test.mjs +4 -4
  80. package/dist/nodeinfo/handler.test.mjs +4 -4
  81. package/dist/nodeinfo/mod.d.cts +2 -1
  82. package/dist/nodeinfo/mod.d.ts +2 -3
  83. package/dist/nodeinfo/mod.js +3 -3
  84. package/dist/nodeinfo/types.test.mjs +3 -3
  85. package/dist/otel/exporter.test.mjs +28 -25
  86. package/dist/otel/mod.cjs +6 -5
  87. package/dist/otel/mod.d.cts +5 -3
  88. package/dist/otel/mod.d.ts +5 -5
  89. package/dist/otel/mod.js +8 -7
  90. package/dist/{outgoing-jsonld-CNmZLixq.mjs → outgoing-jsonld-L_DbOaFe.mjs} +2 -2
  91. package/dist/{owner-C-tqfvxn.mjs → owner-Cl-1cAR8.mjs} +2 -2
  92. package/dist/{owner-CptqhsOy.d.cts → owner-CnngXDNJ.d.ts} +2 -1
  93. package/dist/{owner-74ARJ5TL.d.ts → owner-DEvZuyOE.d.cts} +2 -3
  94. package/dist/{proof-Bbbwf8_x.js → proof-CyXndf6-.js} +378 -15
  95. package/dist/{proof-BlmRPzrK.mjs → proof-Dnz8jtiQ.mjs} +26 -8
  96. package/dist/{proof-BW89QMVB.cjs → proof-tz35unOj.cjs} +432 -15
  97. package/dist/runtime/mod.d.cts +1 -0
  98. package/dist/runtime/mod.d.ts +1 -2
  99. package/dist/runtime/mod.js +3 -3
  100. package/dist/{send-05pJLcb6.mjs → send-DIbBYN5P.mjs} +72 -26
  101. package/dist/sig/http.test.mjs +356 -33
  102. package/dist/sig/key.test.mjs +103 -6
  103. package/dist/sig/ld.test.mjs +696 -7
  104. package/dist/sig/mod.cjs +2 -2
  105. package/dist/sig/mod.d.cts +4 -3
  106. package/dist/sig/mod.d.ts +4 -5
  107. package/dist/sig/mod.js +4 -4
  108. package/dist/sig/owner.test.mjs +6 -6
  109. package/dist/sig/proof.test.mjs +169 -8
  110. package/dist/{std__assert-CRDpx_HF.mjs → std__assert-BBjXFNOb.mjs} +5 -30
  111. package/dist/temporal-BEwob1Vg.mjs +95 -0
  112. package/dist/testing/mod.d.mts +110 -10
  113. package/dist/testing/mod.mjs +1 -2
  114. package/dist/{transformers-ve6e2xcg.js → transformers-BGMIq1cs.js} +2 -2
  115. package/dist/{types-hvL8ElAs.js → types-CAY3OdLq.js} +2 -2
  116. package/dist/utils/docloader.test.mjs +6 -6
  117. package/dist/utils/kv-cache.test.mjs +67 -2
  118. package/dist/utils/mod.cjs +1 -1
  119. package/dist/utils/mod.d.cts +2 -1
  120. package/dist/utils/mod.d.ts +2 -3
  121. package/dist/utils/mod.js +3 -3
  122. package/dist/vocab/cjs.test.mjs +1 -1
  123. package/dist/vocab/mod.d.cts +1 -0
  124. package/dist/vocab/mod.d.ts +1 -2
  125. package/dist/vocab/mod.js +2 -2
  126. package/package.json +16 -16
  127. package/dist/ld-DR78beiv.mjs +0 -279
  128. package/dist/middleware-BFBaR0mF.cjs +0 -4
  129. package/dist/mod-2d12ffz3.d.ts +0 -64
  130. package/dist/mod-D35TRn09.d.cts +0 -62
  131. package/dist/router-CrMLXoOr.mjs +0 -114
  132. package/dist/{activity-listener-ell7W1s9.mjs → activity-listener-tztVvlNb.mjs} +0 -0
  133. package/dist/{assert_equals-Ew3jOFa3.mjs → assert_equals-C-ZRDbaf.mjs} +0 -0
  134. package/dist/{client-D_1QpnWt.mjs → client-ByXmQhYD.mjs} +1 -1
  135. package/dist/{collection-D-HqUuA2.mjs → collection-Cc3DVAhE.mjs} +0 -0
  136. package/dist/{keycache-EGATflN-.mjs → keycache-BeU0LCII.mjs} +0 -0
  137. package/dist/{public-audience-DYFHzm_c.mjs → public-audience-Cvbr2Gzt.mjs} +1 -1
  138. /package/dist/{retry-bMXBL97A.mjs → retry-CXg_MBI-.mjs} +0 -0
@@ -11,7 +11,7 @@ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conve
11
11
  let byte_encodings_base64 = require("byte-encodings/base64");
12
12
  //#region deno.json
13
13
  var name = "@fedify/fedify";
14
- var version = "2.3.0-dev.994+9071ca0a";
14
+ var version = "2.3.0-pr.809.36+c592d116";
15
15
  //#endregion
16
16
  //#region src/sig/accept.ts
17
17
  /**
@@ -152,6 +152,814 @@ function fulfillAcceptSignature(entry, localKeyId, localAlg) {
152
152
  };
153
153
  }
154
154
  //#endregion
155
+ //#region src/federation/metrics.ts
156
+ var FederationMetrics = class {
157
+ deliverySent;
158
+ deliveryPermanentFailure;
159
+ signatureVerificationFailure;
160
+ signatureVerificationDuration;
161
+ signatureKeyFetchDuration;
162
+ deliveryDuration;
163
+ inboxProcessingDuration;
164
+ httpServerRequestCount;
165
+ httpServerRequestDuration;
166
+ queueTaskEnqueued;
167
+ queueTaskStarted;
168
+ queueTaskCompleted;
169
+ queueTaskFailed;
170
+ queueTaskDuration;
171
+ queueTaskInFlight;
172
+ queueDepth;
173
+ fanoutRecipients;
174
+ inboxActivity;
175
+ outboxActivity;
176
+ circuitBreakerStateChange;
177
+ keyLookup;
178
+ keyLookupDuration;
179
+ documentFetch;
180
+ documentFetchDuration;
181
+ documentCache;
182
+ webFingerHandle;
183
+ webFingerHandleDuration;
184
+ collectionRequest;
185
+ collectionDispatchDuration;
186
+ collectionPageItems;
187
+ collectionTotalItems;
188
+ constructor(meterProvider) {
189
+ const meter = meterProvider.getMeter(name, version);
190
+ this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
191
+ description: "ActivityPub delivery attempts.",
192
+ unit: "{attempt}"
193
+ });
194
+ this.deliveryPermanentFailure = meter.createCounter("activitypub.delivery.permanent_failure", {
195
+ description: "ActivityPub deliveries abandoned as permanent failures.",
196
+ unit: "{failure}"
197
+ });
198
+ this.signatureVerificationFailure = meter.createCounter("activitypub.signature.verification_failure", {
199
+ description: "ActivityPub signature verification failures.",
200
+ unit: "{failure}"
201
+ });
202
+ this.signatureVerificationDuration = meter.createHistogram("activitypub.signature.verification.duration", {
203
+ description: "Duration of ActivityPub signature verification, including local key lookup and remote key fetches.",
204
+ unit: "ms",
205
+ advice: { explicitBucketBoundaries: [
206
+ .1,
207
+ .25,
208
+ .5,
209
+ 1,
210
+ 2.5,
211
+ 5,
212
+ 10,
213
+ 25,
214
+ 50,
215
+ 100,
216
+ 250,
217
+ 500,
218
+ 1e3
219
+ ] }
220
+ });
221
+ this.signatureKeyFetchDuration = meter.createHistogram("activitypub.signature.key_fetch.duration", {
222
+ description: "Duration of public key lookup performed during ActivityPub signature verification.",
223
+ unit: "ms"
224
+ });
225
+ this.deliveryDuration = meter.createHistogram("activitypub.delivery.duration", {
226
+ description: "Duration of ActivityPub delivery attempts.",
227
+ unit: "ms"
228
+ });
229
+ this.inboxProcessingDuration = meter.createHistogram("activitypub.inbox.processing_duration", {
230
+ description: "Duration of ActivityPub inbox listener processing.",
231
+ unit: "ms"
232
+ });
233
+ this.httpServerRequestCount = meter.createCounter("fedify.http.server.request.count", {
234
+ description: "HTTP requests handled by Federation.fetch().",
235
+ unit: "{request}"
236
+ });
237
+ this.httpServerRequestDuration = meter.createHistogram("fedify.http.server.request.duration", {
238
+ description: "Duration of HTTP requests handled by Federation.fetch().",
239
+ unit: "ms",
240
+ advice: { explicitBucketBoundaries: [
241
+ 5,
242
+ 10,
243
+ 25,
244
+ 50,
245
+ 75,
246
+ 100,
247
+ 250,
248
+ 500,
249
+ 750,
250
+ 1e3,
251
+ 2500,
252
+ 5e3,
253
+ 7500,
254
+ 1e4
255
+ ] }
256
+ });
257
+ this.queueTaskEnqueued = meter.createCounter("fedify.queue.task.enqueued", {
258
+ description: "Tasks Fedify enqueued for inbox, outbox, or fanout work.",
259
+ unit: "{task}"
260
+ });
261
+ this.queueTaskStarted = meter.createCounter("fedify.queue.task.started", {
262
+ description: "Tasks Fedify began processing as a queue worker.",
263
+ unit: "{task}"
264
+ });
265
+ this.queueTaskCompleted = meter.createCounter("fedify.queue.task.completed", {
266
+ description: "Queue tasks Fedify finished processing without throwing.",
267
+ unit: "{task}"
268
+ });
269
+ this.queueTaskFailed = meter.createCounter("fedify.queue.task.failed", {
270
+ description: "Queue tasks Fedify abandoned because processing threw.",
271
+ unit: "{task}"
272
+ });
273
+ this.queueTaskDuration = meter.createHistogram("fedify.queue.task.duration", {
274
+ description: "Duration of queue task processing in Fedify workers.",
275
+ unit: "ms",
276
+ advice: { explicitBucketBoundaries: [
277
+ 5,
278
+ 10,
279
+ 25,
280
+ 50,
281
+ 75,
282
+ 100,
283
+ 250,
284
+ 500,
285
+ 750,
286
+ 1e3,
287
+ 2500,
288
+ 5e3,
289
+ 7500,
290
+ 1e4
291
+ ] }
292
+ });
293
+ this.queueTaskInFlight = meter.createUpDownCounter("fedify.queue.task.in_flight", {
294
+ description: "Queue tasks currently being processed in this Fedify process.",
295
+ unit: "{task}"
296
+ });
297
+ this.queueDepth = meter.createObservableGauge("fedify.queue.depth", {
298
+ description: "Messages waiting in configured Fedify queues, as reported by the queue backend.",
299
+ unit: "{message}"
300
+ });
301
+ this.fanoutRecipients = meter.createHistogram("activitypub.fanout.recipients", {
302
+ description: "Number of recipient inboxes produced by an ActivityPub fanout task.",
303
+ unit: "{recipient}"
304
+ });
305
+ this.inboxActivity = meter.createCounter("activitypub.inbox.activity", {
306
+ description: "ActivityPub activities observed at the inbox lifecycle level: queued, processed, retried, rejected, or abandoned.",
307
+ unit: "{activity}"
308
+ });
309
+ this.outboxActivity = meter.createCounter("activitypub.outbox.activity", {
310
+ description: "ActivityPub activities observed at the outbox lifecycle level: queued, retried, or abandoned. Per-recipient delivery counters live on `activitypub.delivery.*`.",
311
+ unit: "{activity}"
312
+ });
313
+ this.circuitBreakerStateChange = meter.createCounter("activitypub.circuit_breaker.state_change", {
314
+ description: "Outbound ActivityPub delivery circuit breaker changes.",
315
+ unit: "{change}"
316
+ });
317
+ this.keyLookup = meter.createCounter("activitypub.key.lookup", {
318
+ description: "Public-key lookup attempts performed by Fedify, including both cache hits and remote fetches.",
319
+ unit: "{lookup}"
320
+ });
321
+ this.keyLookupDuration = meter.createHistogram("activitypub.key.lookup.duration", {
322
+ description: "Duration of public-key lookups performed by Fedify, including any remote fetch.",
323
+ unit: "ms",
324
+ advice: { explicitBucketBoundaries: [
325
+ 5,
326
+ 10,
327
+ 25,
328
+ 50,
329
+ 75,
330
+ 100,
331
+ 250,
332
+ 500,
333
+ 750,
334
+ 1e3,
335
+ 2500,
336
+ 5e3,
337
+ 7500,
338
+ 1e4
339
+ ] }
340
+ });
341
+ this.documentFetch = meter.createCounter("activitypub.document.fetch", {
342
+ description: "Remote JSON-LD document loader invocations made by Fedify-wrapped loaders.",
343
+ unit: "{fetch}"
344
+ });
345
+ this.documentFetchDuration = meter.createHistogram("activitypub.document.fetch.duration", {
346
+ description: "Duration of remote JSON-LD document loader invocations made by Fedify-wrapped loaders.",
347
+ unit: "ms",
348
+ advice: { explicitBucketBoundaries: [
349
+ 5,
350
+ 10,
351
+ 25,
352
+ 50,
353
+ 75,
354
+ 100,
355
+ 250,
356
+ 500,
357
+ 750,
358
+ 1e3,
359
+ 2500,
360
+ 5e3,
361
+ 7500,
362
+ 1e4
363
+ ] }
364
+ });
365
+ this.documentCache = meter.createCounter("activitypub.document.cache", {
366
+ description: "KV-backed document loader cache lookups, with `hit` or `miss` classification.",
367
+ unit: "{lookup}"
368
+ });
369
+ this.webFingerHandle = meter.createCounter("webfinger.handle", {
370
+ description: "Incoming WebFinger requests handled by Fedify, classified by terminal outcome.",
371
+ unit: "{request}"
372
+ });
373
+ this.webFingerHandleDuration = meter.createHistogram("webfinger.handle.duration", {
374
+ description: "Duration of incoming WebFinger request handling in Fedify.",
375
+ unit: "ms",
376
+ advice: { explicitBucketBoundaries: [
377
+ 5,
378
+ 10,
379
+ 25,
380
+ 50,
381
+ 75,
382
+ 100,
383
+ 250,
384
+ 500,
385
+ 750,
386
+ 1e3,
387
+ 2500,
388
+ 5e3,
389
+ 7500,
390
+ 1e4
391
+ ] }
392
+ });
393
+ this.collectionRequest = meter.createCounter("activitypub.collection.request", {
394
+ description: "ActivityPub collection and collection-page requests handled by Fedify.",
395
+ unit: "{request}"
396
+ });
397
+ this.collectionDispatchDuration = meter.createHistogram("activitypub.collection.dispatch.duration", {
398
+ description: "Duration of ActivityPub collection dispatcher callbacks.",
399
+ unit: "ms",
400
+ advice: { explicitBucketBoundaries: [
401
+ 5,
402
+ 10,
403
+ 25,
404
+ 50,
405
+ 75,
406
+ 100,
407
+ 250,
408
+ 500,
409
+ 750,
410
+ 1e3,
411
+ 2500,
412
+ 5e3,
413
+ 7500,
414
+ 1e4
415
+ ] }
416
+ });
417
+ this.collectionPageItems = meter.createHistogram("activitypub.collection.page.items", {
418
+ description: "Number of items Fedify materialized for an ActivityPub collection response.",
419
+ unit: "{item}"
420
+ });
421
+ this.collectionTotalItems = meter.createHistogram("activitypub.collection.total_items", {
422
+ description: "Total item count reported by ActivityPub collection counters.",
423
+ unit: "{item}"
424
+ });
425
+ }
426
+ recordDelivery(inbox, durationMs, success, activityType) {
427
+ const deliveryAttributes = {
428
+ "activitypub.remote.host": getRemoteHost(inbox),
429
+ "activitypub.delivery.success": success
430
+ };
431
+ if (activityType != null) deliveryAttributes["activitypub.activity.type"] = activityType;
432
+ this.deliverySent.add(1, deliveryAttributes);
433
+ this.deliveryDuration.record(durationMs, deliveryAttributes);
434
+ }
435
+ recordPermanentFailure(inbox, statusCode) {
436
+ this.deliveryPermanentFailure.add(1, {
437
+ "activitypub.remote.host": getRemoteHost(inbox),
438
+ "http.response.status_code": statusCode
439
+ });
440
+ }
441
+ recordSignatureVerificationFailure(reason, remoteHost) {
442
+ const attributes = { "activitypub.verification.failure_reason": reason };
443
+ if (remoteHost != null) attributes["activitypub.remote.host"] = remoteHost;
444
+ this.signatureVerificationFailure.add(1, attributes);
445
+ }
446
+ recordSignatureVerificationDuration(durationMs, kind, result, extra = {}) {
447
+ const attributes = {
448
+ "activitypub.signature.kind": kind,
449
+ "activitypub.signature.result": result
450
+ };
451
+ if (extra.algorithm != null) attributes["http_signatures.algorithm"] = extra.algorithm;
452
+ if (extra.failureReason != null) attributes["http_signatures.failure_reason"] = extra.failureReason;
453
+ if (extra.ldType != null) attributes["ld_signatures.type"] = extra.ldType;
454
+ if (extra.cryptosuite != null) attributes["object_integrity_proofs.cryptosuite"] = extra.cryptosuite;
455
+ this.signatureVerificationDuration.record(durationMs, attributes);
456
+ }
457
+ recordSignatureKeyFetchDuration(durationMs, kind, result) {
458
+ this.signatureKeyFetchDuration.record(durationMs, {
459
+ "activitypub.signature.kind": kind,
460
+ "activitypub.signature.key_fetch.result": result
461
+ });
462
+ }
463
+ recordInboxProcessingDuration(activityType, durationMs) {
464
+ this.inboxProcessingDuration.record(durationMs, { "activitypub.activity.type": activityType });
465
+ }
466
+ recordHttpServerRequest(method, endpoint, durationMs, options = {}) {
467
+ const attributes = {
468
+ "http.request.method": normalizeHttpMethod(method),
469
+ "fedify.endpoint": endpoint
470
+ };
471
+ if (options.statusCode != null) attributes["http.response.status_code"] = options.statusCode;
472
+ if (options.routeTemplate != null) attributes["fedify.route.template"] = options.routeTemplate;
473
+ this.httpServerRequestCount.add(1, attributes);
474
+ this.httpServerRequestDuration.record(durationMs, attributes);
475
+ }
476
+ recordQueueTaskEnqueued(common, attempt) {
477
+ const attributes = buildQueueTaskAttributes(common);
478
+ attributes["fedify.queue.task.attempt"] = attempt;
479
+ this.queueTaskEnqueued.add(1, attributes);
480
+ }
481
+ recordQueueTaskStarted(common) {
482
+ this.queueTaskStarted.add(1, buildQueueTaskAttributes(common));
483
+ }
484
+ incrementQueueTaskInFlight(common) {
485
+ this.queueTaskInFlight.add(1, buildQueueTaskInFlightAttributes(common));
486
+ }
487
+ decrementQueueTaskInFlight(common) {
488
+ this.queueTaskInFlight.add(-1, buildQueueTaskInFlightAttributes(common));
489
+ }
490
+ recordQueueTaskOutcome(common, result, durationMs) {
491
+ const attributes = buildQueueTaskAttributes(common);
492
+ attributes["fedify.queue.task.result"] = result;
493
+ if (result === "completed") this.queueTaskCompleted.add(1, attributes);
494
+ else if (result === "failed") this.queueTaskFailed.add(1, attributes);
495
+ this.queueTaskDuration.record(durationMs, attributes);
496
+ }
497
+ recordFanoutRecipients(recipientCount, activityType) {
498
+ const attributes = {};
499
+ if (activityType != null) attributes["activitypub.activity.type"] = activityType;
500
+ this.fanoutRecipients.record(recipientCount, attributes);
501
+ }
502
+ recordInboxActivity(result, activityType) {
503
+ this.inboxActivity.add(1, buildActivityLifecycleAttributes(result, activityType));
504
+ }
505
+ recordOutboxActivity(result, activityType) {
506
+ this.outboxActivity.add(1, buildActivityLifecycleAttributes(result, activityType));
507
+ }
508
+ recordCircuitBreakerStateChange(remoteHost, state) {
509
+ this.circuitBreakerStateChange.add(1, {
510
+ "activitypub.remote.host": remoteHost,
511
+ "activitypub.circuit_breaker.state": state
512
+ });
513
+ }
514
+ recordKeyLookup(attrs) {
515
+ const attributes = {
516
+ "activitypub.lookup.kind": "public_key",
517
+ "activitypub.lookup.result": attrs.result,
518
+ "activitypub.cache.enabled": attrs.cacheEnabled
519
+ };
520
+ if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
521
+ if (attrs.statusCode != null) attributes["http.response.status_code"] = attrs.statusCode;
522
+ this.keyLookup.add(1, attributes);
523
+ this.keyLookupDuration.record(attrs.durationMs, attributes);
524
+ }
525
+ recordDocumentFetch(attrs) {
526
+ const attributes = {
527
+ "activitypub.lookup.kind": attrs.kind,
528
+ "activitypub.lookup.result": attrs.result
529
+ };
530
+ if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
531
+ if (attrs.cacheEnabled != null) attributes["activitypub.cache.enabled"] = attrs.cacheEnabled;
532
+ if (attrs.statusCode != null) attributes["http.response.status_code"] = attrs.statusCode;
533
+ this.documentFetch.add(1, attributes);
534
+ this.documentFetchDuration.record(attrs.durationMs, attributes);
535
+ }
536
+ recordDocumentCache(attrs) {
537
+ const attributes = {
538
+ "activitypub.lookup.kind": attrs.kind,
539
+ "activitypub.lookup.result": attrs.result
540
+ };
541
+ if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
542
+ this.documentCache.add(1, attributes);
543
+ }
544
+ recordWebFingerHandle(attrs) {
545
+ const attributes = { "webfinger.handle.result": attrs.result };
546
+ if (attrs.scheme != null) attributes["webfinger.resource.scheme"] = attrs.scheme;
547
+ if (attrs.statusCode != null) attributes["http.response.status_code"] = attrs.statusCode;
548
+ this.webFingerHandle.add(1, attributes);
549
+ this.webFingerHandleDuration.record(attrs.durationMs, attributes);
550
+ }
551
+ recordCollectionRequest(attrs) {
552
+ this.collectionRequest.add(1, buildCollectionAttributes(attrs));
553
+ }
554
+ recordCollectionDispatchDuration(durationMs, attrs) {
555
+ this.collectionDispatchDuration.record(durationMs, buildCollectionAttributes(attrs));
556
+ }
557
+ recordCollectionPageItems(itemCount, attrs) {
558
+ this.collectionPageItems.record(itemCount, buildCollectionAttributes(attrs));
559
+ }
560
+ recordCollectionTotalItems(totalItems, attrs) {
561
+ this.collectionTotalItems.record(totalItems, buildCollectionAttributes(attrs));
562
+ }
563
+ };
564
+ function buildCollectionAttributes(attrs) {
565
+ const attributes = {
566
+ "activitypub.collection.kind": attrs.kind,
567
+ "activitypub.collection.page": attrs.page,
568
+ "activitypub.collection.result": attrs.result,
569
+ "fedify.collection.dispatcher": attrs.dispatcher
570
+ };
571
+ if (attrs.statusCode != null) attributes["http.response.status_code"] = attrs.statusCode;
572
+ return attributes;
573
+ }
574
+ function buildActivityLifecycleAttributes(result, activityType) {
575
+ const attributes = { "activitypub.processing.result": result };
576
+ if (activityType != null) attributes["activitypub.activity.type"] = activityType;
577
+ return attributes;
578
+ }
579
+ function buildQueueTaskAttributes(common) {
580
+ const attributes = { "fedify.queue.role": common.role };
581
+ const backend = getQueueBackend(common.queue);
582
+ if (backend != null) attributes["fedify.queue.backend"] = backend;
583
+ const nativeRetrial = common.queue?.nativeRetrial;
584
+ if (typeof nativeRetrial === "boolean") attributes["fedify.queue.native_retrial"] = nativeRetrial;
585
+ if (common.activityType != null) attributes["activitypub.activity.type"] = common.activityType;
586
+ return attributes;
587
+ }
588
+ function buildQueueTaskInFlightAttributes(common) {
589
+ return buildQueueTaskAttributes({
590
+ role: common.role,
591
+ queue: common.queue
592
+ });
593
+ }
594
+ /**
595
+ * Returns the constructor name of the given message queue, when it is a
596
+ * meaningful identifier. Used as a best-effort `fedify.queue.backend`
597
+ * attribute on queue task metrics; returns `undefined` for plain object
598
+ * literals (whose constructor is `Object`) so the attribute does not appear
599
+ * with a non-informative value.
600
+ * @since 2.3.0
601
+ */
602
+ function getQueueBackend(queue) {
603
+ const name = queue?.constructor?.name;
604
+ if (name == null || name === "" || name === "Object") return void 0;
605
+ return name;
606
+ }
607
+ /**
608
+ * Registers a callback for observing queue backend depth.
609
+ * @since 2.3.0
610
+ */
611
+ function registerQueueDepthGauge(meterProvider, entries, options = {}) {
612
+ const uniqueQueues = /* @__PURE__ */ new Map();
613
+ for (const { role, queue } of entries) {
614
+ if (queue?.getDepth == null) continue;
615
+ const roles = uniqueQueues.get(queue);
616
+ if (roles == null) uniqueQueues.set(queue, [role]);
617
+ else if (!roles.includes(role)) roles.push(role);
618
+ }
619
+ if (uniqueQueues.size < 1) return;
620
+ const queueEntries = Array.from(uniqueQueues.entries());
621
+ getFederationMetrics(meterProvider).queueDepth.addCallback(async (observableResult) => {
622
+ await Promise.all(queueEntries.map(async ([queue, roles]) => {
623
+ let depth;
624
+ try {
625
+ depth = await queue.getDepth();
626
+ } catch {
627
+ return;
628
+ }
629
+ if (depth == null) return;
630
+ const attributes = buildQueueDepthAttributes(queue, roles, options);
631
+ observableResult.observe(depth.queued, {
632
+ ...attributes,
633
+ "fedify.queue.depth.state": "queued"
634
+ });
635
+ if (depth.ready != null) observableResult.observe(depth.ready, {
636
+ ...attributes,
637
+ "fedify.queue.depth.state": "ready"
638
+ });
639
+ if (depth.delayed != null) observableResult.observe(depth.delayed, {
640
+ ...attributes,
641
+ "fedify.queue.depth.state": "delayed"
642
+ });
643
+ }));
644
+ });
645
+ }
646
+ function buildQueueDepthAttributes(queue, roles, options) {
647
+ const sortedRoles = roles.toSorted();
648
+ const role = sortedRoles.length === 1 ? sortedRoles[0] : "shared";
649
+ const attributes = { "fedify.queue.role": role };
650
+ if (options.sourceId != null) attributes["fedify.federation.instance_id"] = options.sourceId;
651
+ if (role === "shared") attributes["fedify.queue.roles"] = sortedRoles.join(",");
652
+ const backend = getQueueBackend(queue);
653
+ if (backend != null) attributes["fedify.queue.backend"] = backend;
654
+ const nativeRetrial = queue.nativeRetrial;
655
+ if (typeof nativeRetrial === "boolean") attributes["fedify.queue.native_retrial"] = nativeRetrial;
656
+ return attributes;
657
+ }
658
+ /**
659
+ * Records `fedify.queue.task.enqueued` for an outgoing outbox enqueue and,
660
+ * for the initial attempt, also records
661
+ * `activitypub.outbox.activity{queued}`.
662
+ *
663
+ * Both `Context.sendActivity()` and `OutboxContext.forwardActivity()` enqueue
664
+ * outbox messages with the same metric attributes (role, queue, activity
665
+ * type, attempt), so they share this helper rather than each defining a local
666
+ * closure. Retry enqueues (attempt > 0) intentionally do not record a
667
+ * second `activitypub.outbox.activity{queued}`; retries are reported as
668
+ * `result=retried` from the retry-scheduling site, which has the failure
669
+ * context.
670
+ * @since 2.3.0
671
+ */
672
+ function recordOutboxEnqueue(meterProvider, outboxQueue, message) {
673
+ const metrics = getFederationMetrics(meterProvider);
674
+ metrics.recordQueueTaskEnqueued({
675
+ role: "outbox",
676
+ queue: outboxQueue,
677
+ activityType: message.activityType
678
+ }, message.attempt);
679
+ if (message.attempt === 0) metrics.recordOutboxActivity("queued", message.activityType);
680
+ }
681
+ /**
682
+ * Records `activitypub.fanout.recipients` with the number of recipient
683
+ * inboxes a single fanout produced. The histogram is unitless count
684
+ * (one measurement per fanout enqueue). Recipient URLs are deliberately
685
+ * not recorded; only the activity type, when known.
686
+ * @since 2.3.0
687
+ */
688
+ function recordFanoutRecipients(meterProvider, recipientCount, activityType) {
689
+ getFederationMetrics(meterProvider).recordFanoutRecipients(recipientCount, activityType);
690
+ }
691
+ /**
692
+ * Records one `activitypub.inbox.activity` measurement. The
693
+ * `activitypub.processing.result` attribute is always present;
694
+ * `activitypub.activity.type` is recorded only when Fedify already knows
695
+ * the activity type.
696
+ * @since 2.3.0
697
+ */
698
+ function recordInboxActivity(meterProvider, result, activityType) {
699
+ getFederationMetrics(meterProvider).recordInboxActivity(result, activityType);
700
+ }
701
+ /**
702
+ * Records one `activitypub.outbox.activity` measurement. The
703
+ * `activitypub.processing.result` attribute is always present;
704
+ * `activitypub.activity.type` is recorded only when Fedify already knows
705
+ * the activity type (it is always known for outbox lifecycle events).
706
+ * @since 2.3.0
707
+ */
708
+ function recordOutboxActivity(meterProvider, result, activityType) {
709
+ getFederationMetrics(meterProvider).recordOutboxActivity(result, activityType);
710
+ }
711
+ /**
712
+ * Records one outbound delivery circuit breaker state transition.
713
+ * @since 2.3.0
714
+ */
715
+ function recordCircuitBreakerStateChange(meterProvider, remoteHost, state) {
716
+ getFederationMetrics(meterProvider).recordCircuitBreakerStateChange(remoteHost, state);
717
+ }
718
+ /**
719
+ * Records one measurement on `activitypub.key.lookup` (counter) and
720
+ * `activitypub.key.lookup.duration` (histogram) for a public-key lookup.
721
+ *
722
+ * `activitypub.lookup.kind` is always recorded as `public_key`; the result
723
+ * classification, remote host, HTTP status code (when an HTTP response was
724
+ * received), and `activitypub.cache.enabled` are recorded as attributes on
725
+ * both measurements. Full key URLs and key IDs are deliberately omitted to
726
+ * keep cardinality bounded.
727
+ * @since 2.3.0
728
+ */
729
+ function recordKeyLookup(meterProvider, attrs) {
730
+ getFederationMetrics(meterProvider).recordKeyLookup(attrs);
731
+ }
732
+ /**
733
+ * Records one measurement each on `activitypub.document.fetch` (counter)
734
+ * and `activitypub.document.fetch.duration` (histogram) for one remote
735
+ * JSON-LD document loader invocation, with bounded
736
+ * `activitypub.lookup.kind` and `activitypub.lookup.result` attributes
737
+ * plus the optional remote-host, cache-enabled, and HTTP status-code
738
+ * attributes. Counter and histogram are always recorded together so
739
+ * aggregate rate and latency views stay in sync.
740
+ * @since 2.3.0
741
+ */
742
+ function recordDocumentFetch(meterProvider, attrs) {
743
+ getFederationMetrics(meterProvider).recordDocumentFetch(attrs);
744
+ }
745
+ /**
746
+ * Records one `activitypub.document.cache` measurement, classifying the
747
+ * lookup as `hit` (the cache returned an entry) or `miss` (the cache was
748
+ * consulted and returned nothing, prompting a delegate fetch).
749
+ * @since 2.3.0
750
+ */
751
+ function recordDocumentCache(meterProvider, attrs) {
752
+ getFederationMetrics(meterProvider).recordDocumentCache(attrs);
753
+ }
754
+ /**
755
+ * Records one measurement on `webfinger.handle` (counter) and
756
+ * `webfinger.handle.duration` (histogram) for an incoming WebFinger
757
+ * request handled by Fedify. Counter and histogram are always recorded
758
+ * together, with `webfinger.handle.result` set to one of `resolved`,
759
+ * `invalid`, `not_found`, `tombstoned`, or `error`. The queried
760
+ * resource string is deliberately excluded; it remains on the
761
+ * `webfinger.handle` span for trace-level investigation.
762
+ * @since 2.3.0
763
+ */
764
+ function recordWebFingerHandle(meterProvider, attrs) {
765
+ getFederationMetrics(meterProvider).recordWebFingerHandle(attrs);
766
+ }
767
+ /**
768
+ * Records one `activitypub.collection.request` measurement for a
769
+ * collection or collection-page request handled by Fedify.
770
+ * @since 2.3.0
771
+ */
772
+ function recordCollectionRequest(meterProvider, attrs) {
773
+ getFederationMetrics(meterProvider).recordCollectionRequest(attrs);
774
+ }
775
+ /**
776
+ * Records one `activitypub.collection.dispatch.duration` measurement for a
777
+ * collection dispatcher callback invocation.
778
+ * @since 2.3.0
779
+ */
780
+ function recordCollectionDispatchDuration(meterProvider, durationMs, attrs) {
781
+ getFederationMetrics(meterProvider).recordCollectionDispatchDuration(durationMs, attrs);
782
+ }
783
+ /**
784
+ * Records one `activitypub.collection.page.items` measurement when Fedify
785
+ * has materialized collection items in memory.
786
+ * @since 2.3.0
787
+ */
788
+ function recordCollectionPageItems(meterProvider, itemCount, attrs) {
789
+ getFederationMetrics(meterProvider).recordCollectionPageItems(itemCount, attrs);
790
+ }
791
+ /**
792
+ * Records one `activitypub.collection.total_items` measurement when a
793
+ * collection counter has already reported a total item count.
794
+ * @since 2.3.0
795
+ */
796
+ function recordCollectionTotalItems(meterProvider, totalItems, attrs) {
797
+ getFederationMetrics(meterProvider).recordCollectionTotalItems(totalItems, attrs);
798
+ }
799
+ /**
800
+ * Classifies a thrown value from a key or document fetch into the bounded
801
+ * {@link LookupResult} taxonomy and, when an HTTP response was received,
802
+ * surfaces its status code.
803
+ *
804
+ * - `FetchError` with a `Response` whose status is `404` or `410`:
805
+ * `result=not_found` and the response status code.
806
+ * - `FetchError` with any other `Response`: `result=error` and the
807
+ * response status code.
808
+ * - `FetchError` without a `Response`: `result=network_error`.
809
+ * - An `AbortError` (typically from a cancelled fetch): `result=network_error`.
810
+ * - A bare `TypeError` (the shape native `fetch()` raises on DNS, connect,
811
+ * and TLS failures before any response is observed):
812
+ * `result=network_error`.
813
+ * - Any other value: `result=error`.
814
+ * @since 2.3.0
815
+ */
816
+ function classifyFetchError(error) {
817
+ if (error instanceof _fedify_vocab_runtime.FetchError) {
818
+ if (error.response != null) {
819
+ const status = error.response.status;
820
+ return {
821
+ result: status === 404 || status === 410 ? "not_found" : "error",
822
+ statusCode: status
823
+ };
824
+ }
825
+ return { result: "network_error" };
826
+ }
827
+ if (isAbortError$1(error)) return { result: "network_error" };
828
+ if (error instanceof TypeError) return { result: "network_error" };
829
+ return { result: "error" };
830
+ }
831
+ /**
832
+ * Wraps a {@link DocumentLoader} so each invocation records one
833
+ * measurement on `activitypub.document.fetch` (counter) and one on
834
+ * `activitypub.document.fetch.duration` (histogram), classifying the
835
+ * outcome via {@link classifyFetchError} when the wrapped loader throws
836
+ * and as `fetched` on success. The wrapper rethrows whatever the
837
+ * wrapped loader throws so caller behavior is unchanged.
838
+ *
839
+ * The wrapper records the host of the requested URL, including any
840
+ * non-default port, on `activitypub.remote.host` when the URL parses; full
841
+ * URLs, paths, and query strings are deliberately excluded to keep
842
+ * cardinality bounded.
843
+ * HTTP status codes are recorded only when the failure carries a
844
+ * `Response` (currently, when the wrapped loader throws a
845
+ * {@link FetchError} with a non-`null` `response`).
846
+ * @since 2.3.0
847
+ */
848
+ function instrumentDocumentLoader(loader, options) {
849
+ const meterProvider = options.meterProvider;
850
+ if (meterProvider == null) return loader;
851
+ return async (url, opts) => {
852
+ const start = performance.now();
853
+ let remoteUrl;
854
+ try {
855
+ remoteUrl = new URL(url);
856
+ } catch {
857
+ remoteUrl = void 0;
858
+ }
859
+ try {
860
+ const result = await loader(url, opts);
861
+ recordDocumentFetch(meterProvider, {
862
+ durationMs: getDurationMs(start),
863
+ kind: options.kind,
864
+ result: "fetched",
865
+ remoteUrl,
866
+ cacheEnabled: options.cacheEnabled
867
+ });
868
+ return result;
869
+ } catch (error) {
870
+ const classified = classifyFetchError(error);
871
+ recordDocumentFetch(meterProvider, {
872
+ durationMs: getDurationMs(start),
873
+ kind: options.kind,
874
+ result: classified.result,
875
+ remoteUrl,
876
+ cacheEnabled: options.cacheEnabled,
877
+ statusCode: classified.statusCode
878
+ });
879
+ throw error;
880
+ }
881
+ };
882
+ }
883
+ /**
884
+ * Times an awaited public key fetch and records exactly one
885
+ * `activitypub.signature.key_fetch.duration` measurement, classifying the
886
+ * outcome as `hit`, `fetched`, or `error` based on the `cached` flag and
887
+ * whether the returned key is non-null. Errors thrown by the fetch are
888
+ * reported as `error` and rethrown, so verifier behavior is unchanged.
889
+ *
890
+ * Shared by the three signature verifiers (HTTP, Linked Data, Object
891
+ * Integrity Proofs); the only per-call variation is the
892
+ * `activitypub.signature.kind` attribute value.
893
+ * @since 2.3.0
894
+ */
895
+ async function measureSignatureKeyFetch(meterProvider, kind, fetch) {
896
+ const start = performance.now();
897
+ try {
898
+ const result = await fetch();
899
+ getFederationMetrics(meterProvider).recordSignatureKeyFetchDuration(getDurationMs(start), kind, result.key != null ? result.cached ? "hit" : "fetched" : "error");
900
+ return result;
901
+ } catch (error) {
902
+ getFederationMetrics(meterProvider).recordSignatureKeyFetchDuration(getDurationMs(start), kind, "error");
903
+ throw error;
904
+ }
905
+ }
906
+ /**
907
+ * Whether the given thrown value is an `AbortError`.
908
+ *
909
+ * `processQueuedTask` distinguishes aborted tasks (recorded as
910
+ * `fedify.queue.task.result=aborted`) from other failures so that backend
911
+ * shutdown signals do not inflate the `fedify.queue.task.failed` counter.
912
+ * @since 2.3.0
913
+ */
914
+ function isAbortError$1(error) {
915
+ if (error == null || typeof error !== "object") return false;
916
+ const name = error.name;
917
+ return typeof name === "string" && name === "AbortError";
918
+ }
919
+ const KNOWN_HTTP_METHODS = new Set([
920
+ "CONNECT",
921
+ "DELETE",
922
+ "GET",
923
+ "HEAD",
924
+ "OPTIONS",
925
+ "PATCH",
926
+ "POST",
927
+ "PUT",
928
+ "QUERY",
929
+ "TRACE"
930
+ ]);
931
+ function normalizeHttpMethod(method) {
932
+ const upper = method.toUpperCase();
933
+ return KNOWN_HTTP_METHODS.has(upper) ? upper : "_OTHER";
934
+ }
935
+ const federationMetrics = /* @__PURE__ */ new WeakMap();
936
+ /**
937
+ * Gets the cached Fedify metric instruments for a meter provider.
938
+ * @since 2.3.0
939
+ */
940
+ function getFederationMetrics(meterProvider = _opentelemetry_api.metrics.getMeterProvider()) {
941
+ let instruments = federationMetrics.get(meterProvider);
942
+ if (instruments == null) {
943
+ instruments = new FederationMetrics(meterProvider);
944
+ federationMetrics.set(meterProvider, instruments);
945
+ }
946
+ return instruments;
947
+ }
948
+ /**
949
+ * Gets the bounded remote host attribute value for a URL.
950
+ * @since 2.3.0
951
+ */
952
+ function getRemoteHost(url) {
953
+ return url.host;
954
+ }
955
+ /**
956
+ * Gets an elapsed duration in milliseconds from a `performance.now()` value.
957
+ * @since 2.3.0
958
+ */
959
+ function getDurationMs(start) {
960
+ return Math.max(0, performance.now() - start);
961
+ }
962
+ //#endregion
155
963
  //#region src/sig/key.ts
156
964
  /**
157
965
  * Checks if the given key is valid and supported. No-op if the key is valid,
@@ -452,24 +1260,48 @@ async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoade
452
1260
  };
453
1261
  }
454
1262
  async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, onFetchError) {
455
- const logger = (0, _logtape_logtape.getLogger)([
456
- "fedify",
457
- "sig",
458
- "key"
459
- ]);
460
- const keyId = cacheKey.href;
461
- const keyCache = options.keyCache;
462
- const cached = await getCachedFetchKey(cacheKey, keyId, cls, keyCache, logger);
463
- if (cached?.key === null && cached.cached) return await onCachedUnavailable(cacheKey, keyId, keyCache, logger);
464
- if (cached != null) return cached;
465
- logger.debug("Fetching key {keyId} to verify signature...", { keyId });
466
- let document;
1263
+ const start = performance.now();
1264
+ let outcome = { result: "error" };
467
1265
  try {
468
- document = (await (options.documentLoader ?? (0, _fedify_vocab_runtime.getDocumentLoader)())(keyId)).document;
469
- } catch (error) {
470
- return await onFetchError(error, cacheKey, keyId, keyCache, logger);
1266
+ const logger = (0, _logtape_logtape.getLogger)([
1267
+ "fedify",
1268
+ "sig",
1269
+ "key"
1270
+ ]);
1271
+ const keyId = cacheKey.href;
1272
+ const keyCache = options.keyCache;
1273
+ const cached = await getCachedFetchKey(cacheKey, keyId, cls, keyCache, logger);
1274
+ if (cached?.key === null && cached.cached) {
1275
+ const cachedUnavailable = await onCachedUnavailable(cacheKey, keyId, keyCache, logger);
1276
+ outcome = { result: "hit" };
1277
+ return cachedUnavailable;
1278
+ }
1279
+ if (cached != null) {
1280
+ outcome = { result: "hit" };
1281
+ return cached;
1282
+ }
1283
+ logger.debug("Fetching key {keyId} to verify signature...", { keyId });
1284
+ let document;
1285
+ try {
1286
+ document = (await (options.documentLoader ?? (0, _fedify_vocab_runtime.getDocumentLoader)())(keyId)).document;
1287
+ } catch (error) {
1288
+ const classified = classifyFetchError(error);
1289
+ const errored = await onFetchError(error, cacheKey, keyId, keyCache, logger);
1290
+ outcome = classified;
1291
+ return errored;
1292
+ }
1293
+ const resolved = await resolveFetchedKey(document, cacheKey, keyId, cls, options, logger);
1294
+ outcome = { result: resolved.key != null ? "fetched" : "invalid" };
1295
+ return resolved;
1296
+ } finally {
1297
+ recordKeyLookup(options.meterProvider, {
1298
+ durationMs: getDurationMs(start),
1299
+ result: outcome.result,
1300
+ remoteUrl: cacheKey,
1301
+ cacheEnabled: options.keyCache != null,
1302
+ statusCode: outcome.statusCode
1303
+ });
471
1304
  }
472
- return await resolveFetchedKey(document, cacheKey, keyId, cls, options, logger);
473
1305
  }
474
1306
  async function fetchKeyInternal(keyId, cls, options = {}) {
475
1307
  return await fetchKeyWithResult(typeof keyId === "string" ? new URL(keyId) : keyId, cls, options, (_cacheKey, _keyId, _keyCache, _logger) => {
@@ -497,6 +1329,7 @@ async function fetchKeyInternal(keyId, cls, options = {}) {
497
1329
  //#endregion
498
1330
  //#region src/sig/http.ts
499
1331
  const DEFAULT_MAX_REDIRECTION = 20;
1332
+ const DOUBLE_KNOCK_TRANSPORT_RETRY_DELAY_MS = 100;
500
1333
  /**
501
1334
  * Signs a request using the given private key.
502
1335
  * @param request The request to sign.
@@ -799,6 +1632,27 @@ function parseKeyId(value) {
799
1632
  function getKeyFetchErrorName(error) {
800
1633
  return error.name || error.constructor.name || "Error";
801
1634
  }
1635
+ /**
1636
+ * Known draft-cavage `algorithm` parameter values, used to keep the
1637
+ * `http_signatures.algorithm` metric attribute on a bounded set. The header
1638
+ * field is attacker-controlled and not used to select the verification
1639
+ * algorithm, so unknown values are dropped from the metric to prevent
1640
+ * cardinality blow-up.
1641
+ */
1642
+ const DRAFT_KNOWN_ALGORITHMS = new Set([
1643
+ "ecdsa-sha256",
1644
+ "ecdsa-sha384",
1645
+ "ecdsa-sha512",
1646
+ "ed25519",
1647
+ "hs2019",
1648
+ "rsa-sha1",
1649
+ "rsa-sha256",
1650
+ "rsa-sha512"
1651
+ ]);
1652
+ function classifyHttpVerifyResult(result) {
1653
+ if (result.verified) return "verified";
1654
+ return result.reason.type === "noSignature" ? "missing" : "rejected";
1655
+ }
802
1656
  function recordVerificationResult(span, result) {
803
1657
  span.setAttribute("http_signatures.verified", result.verified);
804
1658
  if (result.verified === true) return;
@@ -842,27 +1696,37 @@ async function verifyRequestDetailed(request, options = {}) {
842
1696
  span.setAttribute(_opentelemetry_semantic_conventions.ATTR_URL_FULL, request.url);
843
1697
  for (const [name, value] of request.headers) span.setAttribute((0, _opentelemetry_semantic_conventions.ATTR_HTTP_REQUEST_HEADER)(name), value);
844
1698
  }
1699
+ const start = performance.now();
1700
+ const metricsContext = {};
1701
+ let result;
1702
+ let threw = false;
845
1703
  try {
846
1704
  let spec = options.spec;
847
1705
  if (spec == null) spec = request.headers.has("Signature-Input") ? "rfc9421" : "draft-cavage-http-signatures-12";
848
- let result;
849
- if (spec === "rfc9421") result = await verifyRequestRfc9421(request, span, options);
850
- else result = await verifyRequestDraft(request, span, options);
1706
+ if (spec === "rfc9421") result = await verifyRequestRfc9421(request, span, metricsContext, options);
1707
+ else result = await verifyRequestDraft(request, span, metricsContext, options);
851
1708
  recordVerificationResult(span, result);
852
1709
  if (!result.verified) span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
853
1710
  return result;
854
1711
  } catch (error) {
1712
+ threw = true;
855
1713
  span.setStatus({
856
1714
  code: _opentelemetry_api.SpanStatusCode.ERROR,
857
1715
  message: String(error)
858
1716
  });
859
1717
  throw error;
860
1718
  } finally {
1719
+ const classified = threw ? "error" : classifyHttpVerifyResult(result);
1720
+ const failureReason = result != null && !result.verified && result.reason.type !== "noSignature" ? result.reason.type : void 0;
1721
+ getFederationMetrics(options.meterProvider).recordSignatureVerificationDuration(getDurationMs(start), "http", classified, {
1722
+ algorithm: metricsContext.algorithm,
1723
+ failureReason
1724
+ });
861
1725
  span.end();
862
1726
  }
863
1727
  });
864
1728
  }
865
- async function verifyRequestDraft(request, span, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, tracerProvider } = {}) {
1729
+ async function verifyRequestDraft(request, span, metricsContext, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, meterProvider, tracerProvider } = {}) {
866
1730
  const logger = (0, _logtape_logtape.getLogger)([
867
1731
  "fedify",
868
1732
  "sig",
@@ -1010,13 +1874,18 @@ async function verifyRequestDraft(request, span, { documentLoader, contextLoader
1010
1874
  const keyIdUrl = parseKeyId(keyId);
1011
1875
  if (keyIdUrl == null) return invalidSignatureResult(null);
1012
1876
  span?.setAttribute("http_signatures.key_id", keyId);
1013
- if ("algorithm" in sigValues) span?.setAttribute("http_signatures.algorithm", sigValues.algorithm);
1014
- const { key, cached, fetchError } = await fetchKeyDetailed(keyIdUrl, _fedify_vocab.CryptographicKey, {
1877
+ if ("algorithm" in sigValues) {
1878
+ span?.setAttribute("http_signatures.algorithm", sigValues.algorithm);
1879
+ const normalizedAlgorithm = sigValues.algorithm.toLowerCase();
1880
+ if (DRAFT_KNOWN_ALGORITHMS.has(normalizedAlgorithm)) metricsContext.algorithm = normalizedAlgorithm;
1881
+ }
1882
+ const { key, cached, fetchError } = await measureSignatureKeyFetch(meterProvider, "http", () => fetchKeyDetailed(keyIdUrl, _fedify_vocab.CryptographicKey, {
1015
1883
  documentLoader,
1016
1884
  contextLoader,
1017
1885
  keyCache,
1018
- tracerProvider
1019
- });
1886
+ tracerProvider,
1887
+ meterProvider
1888
+ }));
1020
1889
  if (fetchError != null) return keyFetchErrorResult(keyIdUrl, fetchError);
1021
1890
  if (key == null) return invalidSignatureResult(keyIdUrl);
1022
1891
  const headerNames = headers.split(/\s+/g);
@@ -1038,7 +1907,7 @@ async function verifyRequestDraft(request, span, { documentLoader, contextLoader
1038
1907
  signature,
1039
1908
  message
1040
1909
  });
1041
- return await verifyRequestDetailed(originalRequest, {
1910
+ return await verifyRequestDraft(originalRequest, span, metricsContext, {
1042
1911
  documentLoader,
1043
1912
  contextLoader,
1044
1913
  timeWindow,
@@ -1046,7 +1915,9 @@ async function verifyRequestDraft(request, span, { documentLoader, contextLoader
1046
1915
  keyCache: {
1047
1916
  get: () => Promise.resolve(void 0),
1048
1917
  set: async (keyId, key) => await keyCache?.set(keyId, key)
1049
- }
1918
+ },
1919
+ meterProvider,
1920
+ tracerProvider
1050
1921
  });
1051
1922
  }
1052
1923
  logger.debug("Failed to verify with the fetched key {keyId}; signature {signature} is invalid. Check if the key is correct or if the signed message is correct. The message to sign is:\n{message}", {
@@ -1122,7 +1993,7 @@ async function verifyRfc9421ContentDigest(digestHeader, body) {
1122
1993
  }
1123
1994
  return false;
1124
1995
  }
1125
- async function verifyRequestRfc9421(request, span, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, tracerProvider } = {}) {
1996
+ async function verifyRequestRfc9421(request, span, metricsContext, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, meterProvider, tracerProvider } = {}) {
1126
1997
  const logger = (0, _logtape_logtape.getLogger)([
1127
1998
  "fedify",
1128
1999
  "sig",
@@ -1156,9 +2027,14 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1156
2027
  return invalidSignatureResult(null);
1157
2028
  }
1158
2029
  let failure = noSignatureResult();
2030
+ let failureAlgorithm;
2031
+ const setFailure = (result, algorithm) => {
2032
+ failure = result;
2033
+ failureAlgorithm = algorithm;
2034
+ };
1159
2035
  for (const sigName of signatureNames) {
1160
2036
  if (!signatures[sigName]) {
1161
- failure = invalidSignatureResult(parseKeyId(signatureInputs[sigName]?.keyId));
2037
+ setFailure(invalidSignatureResult(parseKeyId(signatureInputs[sigName]?.keyId)));
1162
2038
  continue;
1163
2039
  }
1164
2040
  const sigInput = signatureInputs[sigName];
@@ -1169,7 +2045,7 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1169
2045
  signatureName: sigName,
1170
2046
  signatureInput: signatureInputHeader
1171
2047
  });
1172
- failure = invalidSignatureResult(null);
2048
+ setFailure(invalidSignatureResult(null));
1173
2049
  continue;
1174
2050
  }
1175
2051
  if (!sigInput.created) {
@@ -1177,7 +2053,7 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1177
2053
  signatureName: sigName,
1178
2054
  signatureInput: signatureInputHeader
1179
2055
  });
1180
- failure = invalidSignatureResult(keyId);
2056
+ setFailure(invalidSignatureResult(keyId));
1181
2057
  continue;
1182
2058
  }
1183
2059
  const signatureCreated = Temporal.Instant.fromEpochMilliseconds(sigInput.created * 1e3);
@@ -1189,14 +2065,14 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1189
2065
  created: signatureCreated.toString(),
1190
2066
  now: now.toString()
1191
2067
  });
1192
- failure = invalidSignatureResult(keyId);
2068
+ setFailure(invalidSignatureResult(keyId));
1193
2069
  continue;
1194
2070
  } else if (Temporal.Instant.compare(signatureCreated, now.subtract(tw)) < 0) {
1195
2071
  logger.debug("Failed to verify; signature created time is too far in the past.", {
1196
2072
  created: signatureCreated.toString(),
1197
2073
  now: now.toString()
1198
2074
  });
1199
- failure = invalidSignatureResult(keyId);
2075
+ setFailure(invalidSignatureResult(keyId));
1200
2076
  continue;
1201
2077
  }
1202
2078
  }
@@ -1204,34 +2080,35 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1204
2080
  const contentDigestHeader = request.headers.get("Content-Digest");
1205
2081
  if (!contentDigestHeader) {
1206
2082
  logger.debug("Failed to verify; Content-Digest header required but not found.", { components: sigInput.components });
1207
- failure = invalidSignatureResult(keyId);
2083
+ setFailure(invalidSignatureResult(keyId));
1208
2084
  continue;
1209
2085
  }
1210
2086
  if (!await verifyRfc9421ContentDigest(contentDigestHeader, await request.arrayBuffer())) {
1211
2087
  logger.debug("Failed to verify; Content-Digest verification failed.", { contentDigest: contentDigestHeader });
1212
- failure = invalidSignatureResult(keyId);
2088
+ setFailure(invalidSignatureResult(keyId));
1213
2089
  continue;
1214
2090
  }
1215
2091
  }
1216
2092
  span?.setAttribute("http_signatures.key_id", sigInput.keyId);
1217
2093
  span?.setAttribute("http_signatures.created", sigInput.created.toString());
1218
2094
  if (keyId == null) {
1219
- failure = invalidSignatureResult(null);
2095
+ setFailure(invalidSignatureResult(null));
1220
2096
  continue;
1221
2097
  }
1222
- const { key, cached, fetchError } = await fetchKeyDetailed(keyId, _fedify_vocab.CryptographicKey, {
2098
+ const { key, cached, fetchError } = await measureSignatureKeyFetch(meterProvider, "http", () => fetchKeyDetailed(keyId, _fedify_vocab.CryptographicKey, {
1223
2099
  documentLoader,
1224
2100
  contextLoader,
1225
2101
  keyCache,
1226
- tracerProvider
1227
- });
2102
+ tracerProvider,
2103
+ meterProvider
2104
+ }));
1228
2105
  if (fetchError != null) {
1229
- failure = keyFetchErrorResult(keyId, fetchError);
2106
+ setFailure(keyFetchErrorResult(keyId, fetchError));
1230
2107
  continue;
1231
2108
  }
1232
2109
  if (!key) {
1233
2110
  logger.debug("Failed to fetch key: {keyId}", { keyId: sigInput.keyId });
1234
- failure = invalidSignatureResult(keyId);
2111
+ setFailure(invalidSignatureResult(keyId));
1235
2112
  continue;
1236
2113
  }
1237
2114
  let alg = sigInput.alg?.toLowerCase();
@@ -1243,12 +2120,13 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1243
2120
  }
1244
2121
  if (alg) span?.setAttribute("http_signatures.algorithm", alg);
1245
2122
  const algorithm = alg && rfc9421AlgorithmMap[alg];
2123
+ const candidateAlgorithm = algorithm ? alg : void 0;
1246
2124
  if (!algorithm) {
1247
2125
  logger.debug("Failed to verify; unsupported algorithm: {algorithm}", {
1248
2126
  algorithm: sigInput.alg,
1249
2127
  supported: Object.keys(rfc9421AlgorithmMap)
1250
2128
  });
1251
- failure = invalidSignatureResult(keyId);
2129
+ setFailure(invalidSignatureResult(keyId));
1252
2130
  continue;
1253
2131
  }
1254
2132
  let signatureBase;
@@ -1259,20 +2137,22 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1259
2137
  error,
1260
2138
  signatureInput: sigInput
1261
2139
  });
1262
- failure = invalidSignatureResult(keyId);
2140
+ setFailure(invalidSignatureResult(keyId), candidateAlgorithm);
1263
2141
  continue;
1264
2142
  }
1265
2143
  const signatureBaseBytes = new TextEncoder().encode(signatureBase);
1266
2144
  span?.setAttribute("http_signatures.signature", (0, byte_encodings_hex.encodeHex)(sigBytes));
1267
2145
  try {
1268
- if (await crypto.subtle.verify(algorithm, key.publicKey, sigBytes.slice(), signatureBaseBytes)) return {
1269
- verified: true,
1270
- key,
1271
- signatureLabel: sigName
1272
- };
1273
- else if (cached) {
2146
+ if (await crypto.subtle.verify(algorithm, key.publicKey, sigBytes.slice(), signatureBaseBytes)) {
2147
+ metricsContext.algorithm = candidateAlgorithm;
2148
+ return {
2149
+ verified: true,
2150
+ key,
2151
+ signatureLabel: sigName
2152
+ };
2153
+ } else if (cached) {
1274
2154
  logger.debug("Failed to verify with cached key {keyId}; retrying with fresh key...", { keyId: sigInput.keyId });
1275
- return await verifyRequestDetailed(originalRequest, {
2155
+ return await verifyRequestRfc9421(originalRequest, span, metricsContext, {
1276
2156
  documentLoader,
1277
2157
  contextLoader,
1278
2158
  timeWindow,
@@ -1281,14 +2161,16 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1281
2161
  get: () => Promise.resolve(void 0),
1282
2162
  set: async (keyId, key) => await keyCache?.set(keyId, key)
1283
2163
  },
1284
- spec: "rfc9421"
2164
+ spec: "rfc9421",
2165
+ meterProvider,
2166
+ tracerProvider
1285
2167
  });
1286
2168
  } else {
1287
2169
  logger.debug("Failed to verify signature with fetched key {keyId}; signature invalid.", {
1288
2170
  keyId: sigInput.keyId,
1289
2171
  signatureBase
1290
2172
  });
1291
- failure = invalidSignatureResult(keyId);
2173
+ setFailure(invalidSignatureResult(keyId), candidateAlgorithm);
1292
2174
  }
1293
2175
  } catch (error) {
1294
2176
  logger.debug("Error during signature verification: {error}", {
@@ -1296,9 +2178,10 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1296
2178
  keyId: sigInput.keyId,
1297
2179
  algorithm: sigInput.alg
1298
2180
  });
1299
- failure = invalidSignatureResult(keyId);
2181
+ setFailure(invalidSignatureResult(keyId), candidateAlgorithm);
1300
2182
  }
1301
2183
  }
2184
+ metricsContext.algorithm = failureAlgorithm;
1302
2185
  return failure;
1303
2186
  }
1304
2187
  /**
@@ -1325,6 +2208,59 @@ function createRedirectRequest(request, location, body) {
1325
2208
  cache: request.cache
1326
2209
  });
1327
2210
  }
2211
+ async function fetchDoubleKnockRequest(request, signedRequest, signal) {
2212
+ const maxAttempts = request.method === "GET" || request.method === "HEAD" ? 2 : 1;
2213
+ for (let attempt = 1;; attempt++) try {
2214
+ return await fetch(signedRequest, {
2215
+ redirect: "manual",
2216
+ signal
2217
+ });
2218
+ } catch (error) {
2219
+ const abortedSignal = getAbortedSignal(signal, request.signal, signedRequest.signal);
2220
+ if (abortedSignal != null) throw getAbortReason(abortedSignal);
2221
+ if (isAbortError(error)) throw error;
2222
+ if (attempt >= maxAttempts) throw createFetchError(request.url, error);
2223
+ await sleep(DOUBLE_KNOCK_TRANSPORT_RETRY_DELAY_MS, signal, request.signal, signedRequest.signal);
2224
+ }
2225
+ }
2226
+ function createFetchError(url, cause) {
2227
+ const error = new _fedify_vocab_runtime.FetchError(url, cause instanceof Error ? cause.message : String(cause));
2228
+ error.cause = cause;
2229
+ return error;
2230
+ }
2231
+ function isAbortError(error) {
2232
+ return error instanceof Error && error.name === "AbortError";
2233
+ }
2234
+ async function sleep(ms, ...signals) {
2235
+ const abortSignals = signals.filter((signal) => signal != null);
2236
+ const abortedSignal = getAbortedSignal(...abortSignals);
2237
+ if (abortedSignal != null) throw getAbortReason(abortedSignal);
2238
+ if (abortSignals.length < 1) {
2239
+ await new Promise((resolve) => setTimeout(resolve, ms));
2240
+ return;
2241
+ }
2242
+ await new Promise((resolve, reject) => {
2243
+ const removeAbortListeners = () => {
2244
+ for (const signal of abortSignals) signal.removeEventListener("abort", handleAbort);
2245
+ };
2246
+ const timeout = setTimeout(() => {
2247
+ removeAbortListeners();
2248
+ resolve();
2249
+ }, ms);
2250
+ function handleAbort(event) {
2251
+ clearTimeout(timeout);
2252
+ removeAbortListeners();
2253
+ reject(getAbortReason(event.currentTarget));
2254
+ }
2255
+ for (const signal of abortSignals) signal.addEventListener("abort", handleAbort, { once: true });
2256
+ });
2257
+ }
2258
+ function getAbortedSignal(...signals) {
2259
+ return signals.find((signal) => signal?.aborted);
2260
+ }
2261
+ function getAbortReason(signal) {
2262
+ return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
2263
+ }
1328
2264
  /**
1329
2265
  * Performs a double-knock request to the given URL. For the details of
1330
2266
  * double-knocking, see
@@ -1351,10 +2287,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1351
2287
  body
1352
2288
  });
1353
2289
  log?.(signedRequest);
1354
- let response = await fetch(signedRequest, {
1355
- redirect: "manual",
1356
- signal
1357
- });
2290
+ let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1358
2291
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1359
2292
  if (redirected >= maximumRedirection) throw new _fedify_vocab_runtime.FetchError(request.url, `Too many redirections (${redirected + 1})`);
1360
2293
  const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
@@ -1429,10 +2362,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1429
2362
  body
1430
2363
  });
1431
2364
  log?.(signedRequest);
1432
- response = await fetch(signedRequest, {
1433
- redirect: "manual",
1434
- signal
1435
- });
2365
+ response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1436
2366
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1437
2367
  if (redirected >= maximumRedirection) throw new _fedify_vocab_runtime.FetchError(request.url, `Too many redirections (${redirected + 1})`);
1438
2368
  const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
@@ -1515,12 +2445,48 @@ Object.defineProperty(exports, "generateCryptoKeyPair", {
1515
2445
  return generateCryptoKeyPair;
1516
2446
  }
1517
2447
  });
2448
+ Object.defineProperty(exports, "getDurationMs", {
2449
+ enumerable: true,
2450
+ get: function() {
2451
+ return getDurationMs;
2452
+ }
2453
+ });
2454
+ Object.defineProperty(exports, "getFederationMetrics", {
2455
+ enumerable: true,
2456
+ get: function() {
2457
+ return getFederationMetrics;
2458
+ }
2459
+ });
2460
+ Object.defineProperty(exports, "getRemoteHost", {
2461
+ enumerable: true,
2462
+ get: function() {
2463
+ return getRemoteHost;
2464
+ }
2465
+ });
1518
2466
  Object.defineProperty(exports, "importJwk", {
1519
2467
  enumerable: true,
1520
2468
  get: function() {
1521
2469
  return importJwk;
1522
2470
  }
1523
2471
  });
2472
+ Object.defineProperty(exports, "instrumentDocumentLoader", {
2473
+ enumerable: true,
2474
+ get: function() {
2475
+ return instrumentDocumentLoader;
2476
+ }
2477
+ });
2478
+ Object.defineProperty(exports, "isAbortError", {
2479
+ enumerable: true,
2480
+ get: function() {
2481
+ return isAbortError$1;
2482
+ }
2483
+ });
2484
+ Object.defineProperty(exports, "measureSignatureKeyFetch", {
2485
+ enumerable: true,
2486
+ get: function() {
2487
+ return measureSignatureKeyFetch;
2488
+ }
2489
+ });
1524
2490
  Object.defineProperty(exports, "name", {
1525
2491
  enumerable: true,
1526
2492
  get: function() {
@@ -1539,6 +2505,78 @@ Object.defineProperty(exports, "parseRfc9421SignatureInput", {
1539
2505
  return parseRfc9421SignatureInput;
1540
2506
  }
1541
2507
  });
2508
+ Object.defineProperty(exports, "recordCircuitBreakerStateChange", {
2509
+ enumerable: true,
2510
+ get: function() {
2511
+ return recordCircuitBreakerStateChange;
2512
+ }
2513
+ });
2514
+ Object.defineProperty(exports, "recordCollectionDispatchDuration", {
2515
+ enumerable: true,
2516
+ get: function() {
2517
+ return recordCollectionDispatchDuration;
2518
+ }
2519
+ });
2520
+ Object.defineProperty(exports, "recordCollectionPageItems", {
2521
+ enumerable: true,
2522
+ get: function() {
2523
+ return recordCollectionPageItems;
2524
+ }
2525
+ });
2526
+ Object.defineProperty(exports, "recordCollectionRequest", {
2527
+ enumerable: true,
2528
+ get: function() {
2529
+ return recordCollectionRequest;
2530
+ }
2531
+ });
2532
+ Object.defineProperty(exports, "recordCollectionTotalItems", {
2533
+ enumerable: true,
2534
+ get: function() {
2535
+ return recordCollectionTotalItems;
2536
+ }
2537
+ });
2538
+ Object.defineProperty(exports, "recordDocumentCache", {
2539
+ enumerable: true,
2540
+ get: function() {
2541
+ return recordDocumentCache;
2542
+ }
2543
+ });
2544
+ Object.defineProperty(exports, "recordFanoutRecipients", {
2545
+ enumerable: true,
2546
+ get: function() {
2547
+ return recordFanoutRecipients;
2548
+ }
2549
+ });
2550
+ Object.defineProperty(exports, "recordInboxActivity", {
2551
+ enumerable: true,
2552
+ get: function() {
2553
+ return recordInboxActivity;
2554
+ }
2555
+ });
2556
+ Object.defineProperty(exports, "recordOutboxActivity", {
2557
+ enumerable: true,
2558
+ get: function() {
2559
+ return recordOutboxActivity;
2560
+ }
2561
+ });
2562
+ Object.defineProperty(exports, "recordOutboxEnqueue", {
2563
+ enumerable: true,
2564
+ get: function() {
2565
+ return recordOutboxEnqueue;
2566
+ }
2567
+ });
2568
+ Object.defineProperty(exports, "recordWebFingerHandle", {
2569
+ enumerable: true,
2570
+ get: function() {
2571
+ return recordWebFingerHandle;
2572
+ }
2573
+ });
2574
+ Object.defineProperty(exports, "registerQueueDepthGauge", {
2575
+ enumerable: true,
2576
+ get: function() {
2577
+ return registerQueueDepthGauge;
2578
+ }
2579
+ });
1542
2580
  Object.defineProperty(exports, "signRequest", {
1543
2581
  enumerable: true,
1544
2582
  get: function() {