@fedify/fedify 2.3.0-dev.1119 → 2.3.0-dev.1137

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 (116) hide show
  1. package/README.md +3 -0
  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-DQP-q39h.mjs → assert_rejects-DN60FHPX.mjs} +2 -2
  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-Ond_h57y.mjs → builder-BCkBXxky.mjs} +60 -41
  9. package/dist/compat/mod.d.cts +1 -1
  10. package/dist/compat/mod.d.ts +1 -1
  11. package/dist/compat/outgoing-jsonld.test.mjs +3 -3
  12. package/dist/compat/public-audience.test.mjs +3 -3
  13. package/dist/compat/transformers.test.mjs +5 -5
  14. package/dist/{context-cSUMk2da.d.ts → context-DCtsSHDv.d.ts} +4 -293
  15. package/dist/{context-Ch-ZLyTQ.d.cts → context-DI2gRbyN.d.cts} +3 -294
  16. package/dist/{context-BAE7AKLA.mjs → context-DVoTs_wM.mjs} +1 -1
  17. package/dist/{deno-DVsHS7rA.mjs → deno-B_9yJW3w.mjs} +1 -1
  18. package/dist/{docloader-WsWfKaE5.mjs → docloader-BT89tyFr.mjs} +3 -3
  19. package/dist/federation/builder.test.mjs +138 -10
  20. package/dist/federation/collection.test.mjs +3 -3
  21. package/dist/federation/handler.test.mjs +12 -12
  22. package/dist/federation/idempotency.test.mjs +6 -6
  23. package/dist/federation/inbox.test.mjs +3 -3
  24. package/dist/federation/keycache.test.mjs +5 -5
  25. package/dist/federation/kv.test.mjs +3 -3
  26. package/dist/federation/metrics.test.mjs +231 -3
  27. package/dist/federation/middleware.test.mjs +88 -18
  28. package/dist/federation/mod.cjs +155 -3
  29. package/dist/federation/mod.d.cts +3 -2
  30. package/dist/federation/mod.d.ts +3 -2
  31. package/dist/federation/mod.js +153 -1
  32. package/dist/federation/mq.test.mjs +5 -5
  33. package/dist/federation/negotiation.test.mjs +4 -4
  34. package/dist/federation/retry.test.mjs +3 -3
  35. package/dist/federation/router.test.mjs +190 -9
  36. package/dist/federation/send.test.mjs +16 -16
  37. package/dist/federation/webfinger.test.mjs +5 -5
  38. package/dist/{getMachineId-bsd-BY01PL1n.mjs → getMachineId-bsd-etIyxDet.mjs} +1 -1
  39. package/dist/{getMachineId-darwin-Dr1gkBkp.mjs → getMachineId-darwin-D23zTf4g.mjs} +1 -1
  40. package/dist/{getMachineId-win-QEYwcJiy.mjs → getMachineId-win-Dpap6v5i.mjs} +1 -1
  41. package/dist/{http-CouJSFVK.js → http-CToqG5ap.js} +252 -20
  42. package/dist/{http-CubOB9wq.cjs → http-CWoeyogl.cjs} +263 -19
  43. package/dist/{http-DUV8ysti.mjs → http-Cyx5SNuu.mjs} +8 -6
  44. package/dist/{http-D6LP89UO.d.ts → http-VyDTd4G3.d.cts} +8 -1
  45. package/dist/{http-D6aw3j2U.d.cts → http-lf8Hsd91.d.ts} +8 -1
  46. package/dist/{key-BoWaYRHm.mjs → key-CkkMJBjF.mjs} +42 -17
  47. package/dist/{kv-cache-DBNpsneh.js → kv-cache-CuCn2xvM.js} +19 -2
  48. package/dist/{kv-cache-Dz31ATUT.cjs → kv-cache-DuEwFYcN.cjs} +19 -2
  49. package/dist/{kv-cache-DihufyAQ.mjs → kv-cache-VHFP42vY.mjs} +19 -1
  50. package/dist/{ld-B5K1mSuG.mjs → ld-k8yqD2a-.mjs} +3 -3
  51. package/dist/{metrics-C4attqv0.mjs → metrics-iRBg8jTk.mjs} +209 -2
  52. package/dist/{middleware-CmsDtIHI.cjs → middleware-BWLUrbS9.cjs} +137 -210
  53. package/dist/{middleware-BDKFRjue.mjs → middleware-CztxpARM.mjs} +1 -1
  54. package/dist/{middleware-Dtjz-hSk.js → middleware-D7FrhN9q.js} +101 -162
  55. package/dist/{middleware-t0jC8I99.mjs → middleware-DQEgdr83.mjs} +64 -36
  56. package/dist/{mod-BDhgfjP7.d.cts → mod-B0hW12_O.d.cts} +1 -1
  57. package/dist/mod-C504qevA.d.cts +173 -0
  58. package/dist/{mod-B-Lin9Sy.d.ts → mod-COIAjwRS.d.ts} +1 -1
  59. package/dist/{mod-DLrRb0dx.d.ts → mod-DFvNJcNb.d.ts} +54 -3
  60. package/dist/mod-wYfuXeDE.d.ts +173 -0
  61. package/dist/{mod-BR_BB0bh.d.cts → mod-yvIXFAEi.d.cts} +54 -3
  62. package/dist/mod.cjs +6 -6
  63. package/dist/mod.d.cts +6 -5
  64. package/dist/mod.d.ts +6 -5
  65. package/dist/mod.js +5 -5
  66. package/dist/mq-D-nlpY04.d.ts +208 -0
  67. package/dist/mq-D8uSFzxe.d.cts +208 -0
  68. package/dist/nodeinfo/client.test.mjs +4 -4
  69. package/dist/nodeinfo/handler.test.mjs +5 -5
  70. package/dist/nodeinfo/types.test.mjs +4 -4
  71. package/dist/otel/exporter.test.mjs +3 -3
  72. package/dist/{outgoing-jsonld-BNL8AC14.mjs → outgoing-jsonld-BgFLCJQ_.mjs} +1 -1
  73. package/dist/{owner-hDxI0ufu.mjs → owner-nmXdvXpc.mjs} +2 -2
  74. package/dist/{proof-BUWfVr6Q.cjs → proof-CcsIJLTn.cjs} +1 -1
  75. package/dist/{proof-DhVuz4bc.mjs → proof-DpwO1T4S.mjs} +5 -5
  76. package/dist/{proof-n60t8o9P.js → proof-NRmtrTDu.js} +1 -1
  77. package/dist/{send-BPhyR5Oo.mjs → send-DvX2tYyZ.mjs} +3 -3
  78. package/dist/sig/accept.test.mjs +1 -1
  79. package/dist/sig/http.test.mjs +13 -9
  80. package/dist/sig/key.test.mjs +104 -7
  81. package/dist/sig/ld.test.mjs +7 -7
  82. package/dist/sig/mod.cjs +2 -2
  83. package/dist/sig/mod.d.cts +2 -2
  84. package/dist/sig/mod.d.ts +2 -2
  85. package/dist/sig/mod.js +2 -2
  86. package/dist/sig/owner.test.mjs +6 -6
  87. package/dist/sig/proof.test.mjs +8 -8
  88. package/dist/{std__assert-BTEgfoJo.mjs → std__assert-BBjXFNOb.mjs} +4 -4
  89. package/dist/testing/mod.d.mts +1 -0
  90. package/dist/testing/mod.mjs +1 -1
  91. package/dist/utils/docloader.test.mjs +7 -7
  92. package/dist/utils/kv-cache.test.mjs +67 -2
  93. package/dist/utils/mod.cjs +1 -1
  94. package/dist/utils/mod.d.cts +1 -1
  95. package/dist/utils/mod.d.ts +1 -1
  96. package/dist/utils/mod.js +1 -1
  97. package/package.json +6 -7
  98. package/dist/mod-C6E8rkcz.d.ts +0 -63
  99. package/dist/mod-P9tE2WmM.d.cts +0 -63
  100. package/dist/router-BT_F5748.mjs +0 -114
  101. /package/dist/{accept-CgDcxvjV.mjs → accept-CceiKpCy.mjs} +0 -0
  102. /package/dist/{activity-listener-BeTGV3wc.mjs → activity-listener-tztVvlNb.mjs} +0 -0
  103. /package/dist/{assert_equals-Ew3jOFa3.mjs → assert_equals-C-ZRDbaf.mjs} +0 -0
  104. /package/dist/{client-Bneh_DYR.mjs → client-B_A6mfn3.mjs} +0 -0
  105. /package/dist/{collection-Cc3DVAhE.mjs → collection-CA3V5zyK.mjs} +0 -0
  106. /package/dist/{esm-sdtqOUPu.mjs → esm-BQRw925N.mjs} +0 -0
  107. /package/dist/{execAsync-Dxb7rNf3.mjs → execAsync-DCBrgFiV.mjs} +0 -0
  108. /package/dist/{getMachineId-linux-Bbhofx-s.mjs → getMachineId-linux-ObI47Hql.mjs} +0 -0
  109. /package/dist/{getMachineId-unsupported-dIOte2Ct.mjs → getMachineId-unsupported-Ddu-PFeh.mjs} +0 -0
  110. /package/dist/{keycache-BeU0LCII.mjs → keycache-BYMd8q7F.mjs} +0 -0
  111. /package/dist/{keys-CSYsOMFG.mjs → keys-C3kae-6B.mjs} +0 -0
  112. /package/dist/{kv-QHE0oeM3.mjs → kv-x2IvBUyq.mjs} +0 -0
  113. /package/dist/{negotiation-DDstyBvc.mjs → negotiation-CDW-_gUU.mjs} +0 -0
  114. /package/dist/{public-audience-c9zmYKgA.mjs → public-audience-N3pyOx2p.mjs} +0 -0
  115. /package/dist/{retry-_VvV0h9f.mjs → retry-v_sGLH1d.mjs} +0 -0
  116. /package/dist/{types-D09GN0uZ.mjs → types-BFowWFTT.mjs} +0 -0
@@ -1,8 +1,9 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-DVsHS7rA.mjs";
4
+ import { n as version, t as name } from "./deno-B_9yJW3w.mjs";
5
5
  import { metrics } from "@opentelemetry/api";
6
+ import { FetchError } from "@fedify/vocab-runtime";
6
7
  //#region src/federation/metrics.ts
7
8
  var FederationMetrics = class {
8
9
  deliverySent;
@@ -23,6 +24,11 @@ var FederationMetrics = class {
23
24
  fanoutRecipients;
24
25
  inboxActivity;
25
26
  outboxActivity;
27
+ keyLookup;
28
+ keyLookupDuration;
29
+ documentFetch;
30
+ documentFetchDuration;
31
+ documentCache;
26
32
  constructor(meterProvider) {
27
33
  const meter = meterProvider.getMeter(name, version);
28
34
  this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
@@ -129,6 +135,58 @@ var FederationMetrics = class {
129
135
  description: "ActivityPub activities observed at the outbox lifecycle level: queued, retried, or abandoned. Per-recipient delivery counters live on `activitypub.delivery.*`.",
130
136
  unit: "{activity}"
131
137
  });
138
+ this.keyLookup = meter.createCounter("activitypub.key.lookup", {
139
+ description: "Public-key lookup attempts performed by Fedify, including both cache hits and remote fetches.",
140
+ unit: "{lookup}"
141
+ });
142
+ this.keyLookupDuration = meter.createHistogram("activitypub.key.lookup.duration", {
143
+ description: "Duration of public-key lookups performed by Fedify, including any remote fetch.",
144
+ unit: "ms",
145
+ advice: { explicitBucketBoundaries: [
146
+ 5,
147
+ 10,
148
+ 25,
149
+ 50,
150
+ 75,
151
+ 100,
152
+ 250,
153
+ 500,
154
+ 750,
155
+ 1e3,
156
+ 2500,
157
+ 5e3,
158
+ 7500,
159
+ 1e4
160
+ ] }
161
+ });
162
+ this.documentFetch = meter.createCounter("activitypub.document.fetch", {
163
+ description: "Remote JSON-LD document loader invocations made by Fedify-wrapped loaders.",
164
+ unit: "{fetch}"
165
+ });
166
+ this.documentFetchDuration = meter.createHistogram("activitypub.document.fetch.duration", {
167
+ description: "Duration of remote JSON-LD document loader invocations made by Fedify-wrapped loaders.",
168
+ unit: "ms",
169
+ advice: { explicitBucketBoundaries: [
170
+ 5,
171
+ 10,
172
+ 25,
173
+ 50,
174
+ 75,
175
+ 100,
176
+ 250,
177
+ 500,
178
+ 750,
179
+ 1e3,
180
+ 2500,
181
+ 5e3,
182
+ 7500,
183
+ 1e4
184
+ ] }
185
+ });
186
+ this.documentCache = meter.createCounter("activitypub.document.cache", {
187
+ description: "KV-backed document loader cache lookups, with `hit` or `miss` classification.",
188
+ unit: "{lookup}"
189
+ });
132
190
  }
133
191
  recordDelivery(inbox, durationMs, success, activityType) {
134
192
  const deliveryAttributes = {
@@ -212,6 +270,36 @@ var FederationMetrics = class {
212
270
  recordOutboxActivity(result, activityType) {
213
271
  this.outboxActivity.add(1, buildActivityLifecycleAttributes(result, activityType));
214
272
  }
273
+ recordKeyLookup(attrs) {
274
+ const attributes = {
275
+ "activitypub.lookup.kind": "public_key",
276
+ "activitypub.lookup.result": attrs.result,
277
+ "activitypub.cache.enabled": attrs.cacheEnabled
278
+ };
279
+ if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
280
+ if (attrs.statusCode != null) attributes["http.response.status_code"] = attrs.statusCode;
281
+ this.keyLookup.add(1, attributes);
282
+ this.keyLookupDuration.record(attrs.durationMs, attributes);
283
+ }
284
+ recordDocumentFetch(attrs) {
285
+ const attributes = {
286
+ "activitypub.lookup.kind": attrs.kind,
287
+ "activitypub.lookup.result": attrs.result
288
+ };
289
+ if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
290
+ if (attrs.cacheEnabled != null) attributes["activitypub.cache.enabled"] = attrs.cacheEnabled;
291
+ if (attrs.statusCode != null) attributes["http.response.status_code"] = attrs.statusCode;
292
+ this.documentFetch.add(1, attributes);
293
+ this.documentFetchDuration.record(attrs.durationMs, attributes);
294
+ }
295
+ recordDocumentCache(attrs) {
296
+ const attributes = {
297
+ "activitypub.lookup.kind": attrs.kind,
298
+ "activitypub.lookup.result": attrs.result
299
+ };
300
+ if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
301
+ this.documentCache.add(1, attributes);
302
+ }
215
303
  };
216
304
  function buildActivityLifecycleAttributes(result, activityType) {
217
305
  const attributes = { "activitypub.processing.result": result };
@@ -300,6 +388,125 @@ function recordOutboxActivity(meterProvider, result, activityType) {
300
388
  getFederationMetrics(meterProvider).recordOutboxActivity(result, activityType);
301
389
  }
302
390
  /**
391
+ * Records one measurement on `activitypub.key.lookup` (counter) and
392
+ * `activitypub.key.lookup.duration` (histogram) for a public-key lookup.
393
+ *
394
+ * `activitypub.lookup.kind` is always recorded as `public_key`; the result
395
+ * classification, remote host, HTTP status code (when an HTTP response was
396
+ * received), and `activitypub.cache.enabled` are recorded as attributes on
397
+ * both measurements. Full key URLs and key IDs are deliberately omitted to
398
+ * keep cardinality bounded.
399
+ * @since 2.3.0
400
+ */
401
+ function recordKeyLookup(meterProvider, attrs) {
402
+ getFederationMetrics(meterProvider).recordKeyLookup(attrs);
403
+ }
404
+ /**
405
+ * Records one measurement each on `activitypub.document.fetch` (counter)
406
+ * and `activitypub.document.fetch.duration` (histogram) for one remote
407
+ * JSON-LD document loader invocation, with bounded
408
+ * `activitypub.lookup.kind` and `activitypub.lookup.result` attributes
409
+ * plus the optional remote-host, cache-enabled, and HTTP status-code
410
+ * attributes. Counter and histogram are always recorded together so
411
+ * aggregate rate and latency views stay in sync.
412
+ * @since 2.3.0
413
+ */
414
+ function recordDocumentFetch(meterProvider, attrs) {
415
+ getFederationMetrics(meterProvider).recordDocumentFetch(attrs);
416
+ }
417
+ /**
418
+ * Records one `activitypub.document.cache` measurement, classifying the
419
+ * lookup as `hit` (the cache returned an entry) or `miss` (the cache was
420
+ * consulted and returned nothing, prompting a delegate fetch).
421
+ * @since 2.3.0
422
+ */
423
+ function recordDocumentCache(meterProvider, attrs) {
424
+ getFederationMetrics(meterProvider).recordDocumentCache(attrs);
425
+ }
426
+ /**
427
+ * Classifies a thrown value from a key or document fetch into the bounded
428
+ * {@link LookupResult} taxonomy and, when an HTTP response was received,
429
+ * surfaces its status code.
430
+ *
431
+ * - `FetchError` with a `Response` whose status is `404` or `410`:
432
+ * `result=not_found` and the response status code.
433
+ * - `FetchError` with any other `Response`: `result=error` and the
434
+ * response status code.
435
+ * - `FetchError` without a `Response`: `result=network_error`.
436
+ * - An `AbortError` (typically from a cancelled fetch): `result=network_error`.
437
+ * - A bare `TypeError` (the shape native `fetch()` raises on DNS, connect,
438
+ * and TLS failures before any response is observed):
439
+ * `result=network_error`.
440
+ * - Any other value: `result=error`.
441
+ * @since 2.3.0
442
+ */
443
+ function classifyFetchError(error) {
444
+ if (error instanceof FetchError) {
445
+ if (error.response != null) {
446
+ const status = error.response.status;
447
+ return {
448
+ result: status === 404 || status === 410 ? "not_found" : "error",
449
+ statusCode: status
450
+ };
451
+ }
452
+ return { result: "network_error" };
453
+ }
454
+ if (isAbortError(error)) return { result: "network_error" };
455
+ if (error instanceof TypeError) return { result: "network_error" };
456
+ return { result: "error" };
457
+ }
458
+ /**
459
+ * Wraps a {@link DocumentLoader} so each invocation records one
460
+ * measurement on `activitypub.document.fetch` (counter) and one on
461
+ * `activitypub.document.fetch.duration` (histogram), classifying the
462
+ * outcome via {@link classifyFetchError} when the wrapped loader throws
463
+ * and as `fetched` on success. The wrapper rethrows whatever the
464
+ * wrapped loader throws so caller behavior is unchanged.
465
+ *
466
+ * The wrapper records the hostname of the requested URL on
467
+ * `activitypub.remote.host` when the URL parses; full URLs, paths, and
468
+ * query strings are deliberately excluded to keep cardinality bounded.
469
+ * HTTP status codes are recorded only when the failure carries a
470
+ * `Response` (currently, when the wrapped loader throws a
471
+ * {@link FetchError} with a non-`null` `response`).
472
+ * @since 2.3.0
473
+ */
474
+ function instrumentDocumentLoader(loader, options) {
475
+ const meterProvider = options.meterProvider;
476
+ if (meterProvider == null) return loader;
477
+ return async (url, opts) => {
478
+ const start = performance.now();
479
+ let remoteUrl;
480
+ try {
481
+ remoteUrl = new URL(url);
482
+ } catch {
483
+ remoteUrl = void 0;
484
+ }
485
+ try {
486
+ const result = await loader(url, opts);
487
+ recordDocumentFetch(meterProvider, {
488
+ durationMs: getDurationMs(start),
489
+ kind: options.kind,
490
+ result: "fetched",
491
+ remoteUrl,
492
+ cacheEnabled: options.cacheEnabled
493
+ });
494
+ return result;
495
+ } catch (error) {
496
+ const classified = classifyFetchError(error);
497
+ recordDocumentFetch(meterProvider, {
498
+ durationMs: getDurationMs(start),
499
+ kind: options.kind,
500
+ result: classified.result,
501
+ remoteUrl,
502
+ cacheEnabled: options.cacheEnabled,
503
+ statusCode: classified.statusCode
504
+ });
505
+ throw error;
506
+ }
507
+ };
508
+ }
509
+ /**
303
510
  * Times an awaited public key fetch and records exactly one
304
511
  * `activitypub.signature.key_fetch.duration` measurement, classifying the
305
512
  * outcome as `hit`, `fetched`, or `error` based on the `cached` flag and
@@ -379,4 +586,4 @@ function getDurationMs(start) {
379
586
  return Math.max(0, performance.now() - start);
380
587
  }
381
588
  //#endregion
382
- export { measureSignatureKeyFetch as a, recordOutboxActivity as c, isAbortError as i, recordOutboxEnqueue as l, getFederationMetrics as n, recordFanoutRecipients as o, getRemoteHost as r, recordInboxActivity as s, getDurationMs as t };
589
+ export { instrumentDocumentLoader as a, recordDocumentCache as c, recordInboxActivity as d, recordKeyLookup as f, getRemoteHost as i, recordDocumentFetch as l, recordOutboxEnqueue as m, getDurationMs as n, isAbortError as o, recordOutboxActivity as p, getFederationMetrics as r, measureSignatureKeyFetch as s, classifyFetchError as t, recordFanoutRecipients as u };