@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
@@ -1,6 +1,7 @@
1
+ /// <reference lib="esnext.temporal" />
1
2
  import { CryptographicKey, Multikey } from "@fedify/vocab";
3
+ import { MeterProvider, TracerProvider } from "@opentelemetry/api";
2
4
  import { DocumentLoader } from "@fedify/vocab-runtime";
3
- import { TracerProvider } from "@opentelemetry/api";
4
5
 
5
6
  //#region src/sig/key.d.ts
6
7
  /**
@@ -51,6 +52,13 @@ interface FetchKeyOptions {
51
52
  * @since 1.3.0
52
53
  */
53
54
  tracerProvider?: TracerProvider;
55
+ /**
56
+ * The OpenTelemetry meter provider to use for recording
57
+ * `activitypub.key.lookup` and `activitypub.key.lookup.duration`. If
58
+ * omitted, the global meter provider is used.
59
+ * @since 2.3.0
60
+ */
61
+ meterProvider?: MeterProvider;
54
62
  }
55
63
  /**
56
64
  * The result of {@link fetchKey}.
@@ -463,6 +471,12 @@ interface VerifyRequestOptions {
463
471
  * @since 1.3.0
464
472
  */
465
473
  tracerProvider?: TracerProvider;
474
+ /**
475
+ * The OpenTelemetry meter provider. If omitted, the global meter provider
476
+ * is used.
477
+ * @since 2.3.0
478
+ */
479
+ meterProvider?: MeterProvider;
466
480
  }
467
481
  /**
468
482
  * The reason why {@link verifyRequestDetailed} could not verify a request.
@@ -1,11 +1,12 @@
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-XBVlKnOX.mjs";
4
+ import { n as version, t as name } from "./deno-DCdM7d93.mjs";
5
+ import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-BHeWd24f.mjs";
6
+ import { getLogger } from "@logtape/logtape";
5
7
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
6
8
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
9
  import { FetchError, getDocumentLoader } from "@fedify/vocab-runtime";
8
- import { getLogger } from "@logtape/logtape";
9
10
  //#region src/sig/key.ts
10
11
  /**
11
12
  * Checks if the given key is valid and supported. No-op if the key is valid,
@@ -306,24 +307,48 @@ async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoade
306
307
  };
307
308
  }
308
309
  async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, onFetchError) {
309
- const logger = getLogger([
310
- "fedify",
311
- "sig",
312
- "key"
313
- ]);
314
- const keyId = cacheKey.href;
315
- const keyCache = options.keyCache;
316
- const cached = await getCachedFetchKey(cacheKey, keyId, cls, keyCache, logger);
317
- if (cached?.key === null && cached.cached) return await onCachedUnavailable(cacheKey, keyId, keyCache, logger);
318
- if (cached != null) return cached;
319
- logger.debug("Fetching key {keyId} to verify signature...", { keyId });
320
- let document;
310
+ const start = performance.now();
311
+ let outcome = { result: "error" };
321
312
  try {
322
- document = (await (options.documentLoader ?? getDocumentLoader())(keyId)).document;
323
- } catch (error) {
324
- return await onFetchError(error, cacheKey, keyId, keyCache, logger);
313
+ const logger = getLogger([
314
+ "fedify",
315
+ "sig",
316
+ "key"
317
+ ]);
318
+ const keyId = cacheKey.href;
319
+ const keyCache = options.keyCache;
320
+ const cached = await getCachedFetchKey(cacheKey, keyId, cls, keyCache, logger);
321
+ if (cached?.key === null && cached.cached) {
322
+ const cachedUnavailable = await onCachedUnavailable(cacheKey, keyId, keyCache, logger);
323
+ outcome = { result: "hit" };
324
+ return cachedUnavailable;
325
+ }
326
+ if (cached != null) {
327
+ outcome = { result: "hit" };
328
+ return cached;
329
+ }
330
+ logger.debug("Fetching key {keyId} to verify signature...", { keyId });
331
+ let document;
332
+ try {
333
+ document = (await (options.documentLoader ?? getDocumentLoader())(keyId)).document;
334
+ } catch (error) {
335
+ const classified = classifyFetchError(error);
336
+ const errored = await onFetchError(error, cacheKey, keyId, keyCache, logger);
337
+ outcome = classified;
338
+ return errored;
339
+ }
340
+ const resolved = await resolveFetchedKey(document, cacheKey, keyId, cls, options, logger);
341
+ outcome = { result: resolved.key != null ? "fetched" : "invalid" };
342
+ return resolved;
343
+ } finally {
344
+ recordKeyLookup(options.meterProvider, {
345
+ durationMs: getDurationMs(start),
346
+ result: outcome.result,
347
+ remoteUrl: cacheKey,
348
+ cacheEnabled: options.keyCache != null,
349
+ statusCode: outcome.statusCode
350
+ });
325
351
  }
326
- return await resolveFetchedKey(document, cacheKey, keyId, cls, options, logger);
327
352
  }
328
353
  async function fetchKeyInternal(keyId, cls, options = {}) {
329
354
  return await fetchKeyWithResult(typeof keyId === "string" ? new URL(keyId) : keyId, cls, options, (_cacheKey, _keyId, _keyCache, _logger) => {
@@ -1,3 +1,4 @@
1
+ /// <reference lib="esnext.temporal" />
1
2
  //#region src/federation/kv.d.ts
2
3
  /**
3
4
  * A key for a key–value store. An array of one or more strings.
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-BrGqJDXL.cjs");
4
+ const require_http = require("./http-gOiudB3g.cjs");
5
5
  let _logtape_logtape = require("@logtape/logtape");
6
6
  let es_toolkit = require("es-toolkit");
7
7
  let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
@@ -56,10 +56,25 @@ const logger = (0, _logtape_logtape.getLogger)([
56
56
  * @param parameters The parameters for the cache.
57
57
  * @returns The decorated document loader which is cache-enabled.
58
58
  */
59
- function kvCache({ loader, kv, prefix, rules }) {
59
+ function kvCache({ loader, kv, prefix, rules, meterProvider, kind }) {
60
60
  const keyPrefix = prefix ?? ["_fedify", "remoteDocument"];
61
61
  rules ??= [[new URLPattern({}), Temporal.Duration.from({ minutes: 5 })]];
62
62
  for (const [p, duration] of rules) if (Temporal.Duration.compare(duration, { days: 30 }) > 0) throw new TypeError("The maximum cache duration is 30 days: " + (p instanceof URLPattern ? `${p.protocol}://${p.username}:${p.password}@${p.hostname}:${p.port}/${p.pathname}?${p.search}#${p.hash}` : p.toString()));
63
+ const lookupKind = kind ?? "object";
64
+ function emitCacheMetric(url, result) {
65
+ if (meterProvider == null) return;
66
+ let remoteUrl;
67
+ try {
68
+ remoteUrl = new URL(url);
69
+ } catch {
70
+ remoteUrl = void 0;
71
+ }
72
+ require_http.recordDocumentCache(meterProvider, {
73
+ kind: lookupKind,
74
+ result,
75
+ remoteUrl
76
+ });
77
+ }
63
78
  return async (url, options) => {
64
79
  if (url in _fedify_vocab_runtime.preloadedContexts) {
65
80
  logger.debug("Using preloaded context: {url}.", { url });
@@ -82,6 +97,7 @@ function kvCache({ loader, kv, prefix, rules }) {
82
97
  });
83
98
  }
84
99
  if (cache == null) {
100
+ emitCacheMetric(url, "miss");
85
101
  const remoteDoc = await loader(url, options);
86
102
  try {
87
103
  await kv.set(key, remoteDoc, { ttl: match });
@@ -93,12 +109,13 @@ function kvCache({ loader, kv, prefix, rules }) {
93
109
  }
94
110
  return remoteDoc;
95
111
  }
112
+ emitCacheMetric(url, "hit");
96
113
  return cache;
97
114
  };
98
115
  }
99
116
  function matchRule(url, rules) {
100
117
  for (const [pattern, d] of rules) {
101
- const duration = d instanceof Temporal.Duration ? d : Temporal.Duration.from(d);
118
+ const duration = Temporal.Duration.from(d);
102
119
  if (typeof pattern === "string") {
103
120
  if (url === pattern) return duration;
104
121
  continue;
@@ -1,8 +1,9 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { preloadedContexts } from "@fedify/vocab-runtime";
4
+ import { p as recordDocumentCache } from "./metrics-BHeWd24f.mjs";
5
5
  import { getLogger } from "@logtape/logtape";
6
+ import { preloadedContexts } from "@fedify/vocab-runtime";
6
7
  //#region src/utils/kv-cache.ts
7
8
  const logger = getLogger([
8
9
  "fedify",
@@ -44,10 +45,25 @@ var MockKvStore = class {
44
45
  * @param parameters The parameters for the cache.
45
46
  * @returns The decorated document loader which is cache-enabled.
46
47
  */
47
- function kvCache({ loader, kv, prefix, rules }) {
48
+ function kvCache({ loader, kv, prefix, rules, meterProvider, kind }) {
48
49
  const keyPrefix = prefix ?? ["_fedify", "remoteDocument"];
49
50
  rules ??= [[new URLPattern({}), Temporal.Duration.from({ minutes: 5 })]];
50
51
  for (const [p, duration] of rules) if (Temporal.Duration.compare(duration, { days: 30 }) > 0) throw new TypeError("The maximum cache duration is 30 days: " + (p instanceof URLPattern ? `${p.protocol}://${p.username}:${p.password}@${p.hostname}:${p.port}/${p.pathname}?${p.search}#${p.hash}` : p.toString()));
52
+ const lookupKind = kind ?? "object";
53
+ function emitCacheMetric(url, result) {
54
+ if (meterProvider == null) return;
55
+ let remoteUrl;
56
+ try {
57
+ remoteUrl = new URL(url);
58
+ } catch {
59
+ remoteUrl = void 0;
60
+ }
61
+ recordDocumentCache(meterProvider, {
62
+ kind: lookupKind,
63
+ result,
64
+ remoteUrl
65
+ });
66
+ }
51
67
  return async (url, options) => {
52
68
  if (url in preloadedContexts) {
53
69
  logger.debug("Using preloaded context: {url}.", { url });
@@ -70,6 +86,7 @@ function kvCache({ loader, kv, prefix, rules }) {
70
86
  });
71
87
  }
72
88
  if (cache == null) {
89
+ emitCacheMetric(url, "miss");
73
90
  const remoteDoc = await loader(url, options);
74
91
  try {
75
92
  await kv.set(key, remoteDoc, { ttl: match });
@@ -81,12 +98,13 @@ function kvCache({ loader, kv, prefix, rules }) {
81
98
  }
82
99
  return remoteDoc;
83
100
  }
101
+ emitCacheMetric(url, "hit");
84
102
  return cache;
85
103
  };
86
104
  }
87
105
  function matchRule(url, rules) {
88
106
  for (const [pattern, d] of rules) {
89
- const duration = d instanceof Temporal.Duration ? d : Temporal.Duration.from(d);
107
+ const duration = Temporal.Duration.from(d);
90
108
  if (typeof pattern === "string") {
91
109
  if (url === pattern) return duration;
92
110
  continue;
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { d as validateCryptoKey, t as doubleKnock } from "./http-B4rrzxtg.js";
3
+ import { C as recordDocumentCache, d as validateCryptoKey, t as doubleKnock } from "./http-Dh18nwJg.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { curry } from "es-toolkit";
6
6
  import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
@@ -55,10 +55,25 @@ const logger = getLogger([
55
55
  * @param parameters The parameters for the cache.
56
56
  * @returns The decorated document loader which is cache-enabled.
57
57
  */
58
- function kvCache({ loader, kv, prefix, rules }) {
58
+ function kvCache({ loader, kv, prefix, rules, meterProvider, kind }) {
59
59
  const keyPrefix = prefix ?? ["_fedify", "remoteDocument"];
60
60
  rules ??= [[new URLPattern({}), Temporal.Duration.from({ minutes: 5 })]];
61
61
  for (const [p, duration] of rules) if (Temporal.Duration.compare(duration, { days: 30 }) > 0) throw new TypeError("The maximum cache duration is 30 days: " + (p instanceof URLPattern ? `${p.protocol}://${p.username}:${p.password}@${p.hostname}:${p.port}/${p.pathname}?${p.search}#${p.hash}` : p.toString()));
62
+ const lookupKind = kind ?? "object";
63
+ function emitCacheMetric(url, result) {
64
+ if (meterProvider == null) return;
65
+ let remoteUrl;
66
+ try {
67
+ remoteUrl = new URL(url);
68
+ } catch {
69
+ remoteUrl = void 0;
70
+ }
71
+ recordDocumentCache(meterProvider, {
72
+ kind: lookupKind,
73
+ result,
74
+ remoteUrl
75
+ });
76
+ }
62
77
  return async (url, options) => {
63
78
  if (url in preloadedContexts) {
64
79
  logger.debug("Using preloaded context: {url}.", { url });
@@ -81,6 +96,7 @@ function kvCache({ loader, kv, prefix, rules }) {
81
96
  });
82
97
  }
83
98
  if (cache == null) {
99
+ emitCacheMetric(url, "miss");
84
100
  const remoteDoc = await loader(url, options);
85
101
  try {
86
102
  await kv.set(key, remoteDoc, { ttl: match });
@@ -92,12 +108,13 @@ function kvCache({ loader, kv, prefix, rules }) {
92
108
  }
93
109
  return remoteDoc;
94
110
  }
111
+ emitCacheMetric(url, "hit");
95
112
  return cache;
96
113
  };
97
114
  }
98
115
  function matchRule(url, rules) {
99
116
  for (const [pattern, d] of rules) {
100
- const duration = d instanceof Temporal.Duration ? d : Temporal.Duration.from(d);
117
+ const duration = Temporal.Duration.from(d);
101
118
  if (typeof pattern === "string") {
102
119
  if (url === pattern) return duration;
103
120
  continue;
@@ -1,6 +1,4 @@
1
- import { Temporal } from "@js-temporal/polyfill";
2
- import { URLPattern } from "urlpattern-polyfill";
3
-
1
+ /// <reference lib="esnext.temporal" />
4
2
  //#region src/federation/kv.d.ts
5
3
  /**
6
4
  * A key for a key–value store. An array of one or more strings.