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

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 (68) hide show
  1. package/dist/{builder-BCkBXxky.mjs → builder-Bjm1Jq9n.mjs} +2 -2
  2. package/dist/compat/mod.d.cts +1 -1
  3. package/dist/compat/mod.d.ts +1 -1
  4. package/dist/compat/transformers.test.mjs +1 -1
  5. package/dist/{context-DI2gRbyN.d.cts → context-CRXCkTM6.d.cts} +48 -6
  6. package/dist/{context-DCtsSHDv.d.ts → context-MgCh7YGu.d.ts} +48 -6
  7. package/dist/{deno-B_9yJW3w.mjs → deno-CKFE6Uya.mjs} +1 -1
  8. package/dist/{docloader-BT89tyFr.mjs → docloader-B-ZE1cZf.mjs} +2 -2
  9. package/dist/federation/builder.test.mjs +1 -1
  10. package/dist/federation/handler.test.mjs +1363 -44
  11. package/dist/federation/idempotency.test.mjs +2 -2
  12. package/dist/federation/metrics.test.mjs +60 -1
  13. package/dist/federation/middleware.test.mjs +1667 -163
  14. package/dist/federation/mod.cjs +1 -1
  15. package/dist/federation/mod.d.cts +2 -2
  16. package/dist/federation/mod.d.ts +2 -2
  17. package/dist/federation/mod.js +1 -1
  18. package/dist/federation/retry.test.mjs +1 -1
  19. package/dist/federation/send.test.mjs +8 -8
  20. package/dist/federation/temporal.test.d.mts +2 -0
  21. package/dist/federation/temporal.test.mjs +71 -0
  22. package/dist/federation/webfinger.test.mjs +147 -2
  23. package/dist/{getMachineId-bsd-etIyxDet.mjs → getMachineId-bsd-BY01PL1n.mjs} +1 -1
  24. package/dist/{getMachineId-darwin-D23zTf4g.mjs → getMachineId-darwin-Dr1gkBkp.mjs} +1 -1
  25. package/dist/{getMachineId-win-Dpap6v5i.mjs → getMachineId-win-QEYwcJiy.mjs} +1 -1
  26. package/dist/{http-CWoeyogl.cjs → http-DQYEA7AZ.cjs} +53 -1
  27. package/dist/{http-CToqG5ap.js → http-WbS1gKzr.js} +48 -2
  28. package/dist/{http-Cyx5SNuu.mjs → http-vHCgbhTg.mjs} +3 -3
  29. package/dist/{key-CkkMJBjF.mjs → key-N0zP_oJA.mjs} +2 -2
  30. package/dist/{kv-cache-CuCn2xvM.js → kv-cache-DM2O-Yjy.js} +1 -1
  31. package/dist/{kv-cache-DuEwFYcN.cjs → kv-cache-Dsg_bi4N.cjs} +1 -1
  32. package/dist/{kv-cache-VHFP42vY.mjs → kv-cache-GXXZEemD.mjs} +1 -1
  33. package/dist/{ld-k8yqD2a-.mjs → ld-BwKhquPx.mjs} +302 -6
  34. package/dist/{metrics-iRBg8jTk.mjs → metrics-7Vy9FvEw.mjs} +48 -2
  35. package/dist/{middleware-D7FrhN9q.js → middleware-BscgvU-m.js} +496 -115
  36. package/dist/{middleware-BWLUrbS9.cjs → middleware-D_iXrYHJ.cjs} +497 -115
  37. package/dist/{middleware-CztxpARM.mjs → middleware-Db1_qAFG.mjs} +1 -1
  38. package/dist/{middleware-DQEgdr83.mjs → middleware-ZuUcO0t1.mjs} +416 -124
  39. package/dist/{mod-C504qevA.d.cts → mod-C7HOzGqH.d.cts} +11 -2
  40. package/dist/{mod-wYfuXeDE.d.ts → mod-CpQHB3Ys.d.ts} +11 -2
  41. package/dist/mod.cjs +4 -4
  42. package/dist/mod.d.cts +2 -2
  43. package/dist/mod.d.ts +2 -2
  44. package/dist/mod.js +4 -4
  45. package/dist/nodeinfo/handler.test.mjs +1 -1
  46. package/dist/{owner-nmXdvXpc.mjs → owner-FD0H_vpj.mjs} +2 -2
  47. package/dist/{proof-CcsIJLTn.cjs → proof-CYK8T8IS.cjs} +353 -3
  48. package/dist/{proof-NRmtrTDu.js → proof-I3EokKN-.js} +300 -4
  49. package/dist/{proof-DpwO1T4S.mjs → proof-V_lafPmA.mjs} +3 -3
  50. package/dist/{send-DvX2tYyZ.mjs → send-Cc2_10tF.mjs} +3 -3
  51. package/dist/sig/http.test.mjs +2 -2
  52. package/dist/sig/key.test.mjs +1 -1
  53. package/dist/sig/ld.test.mjs +558 -2
  54. package/dist/sig/mod.cjs +2 -2
  55. package/dist/sig/mod.js +2 -2
  56. package/dist/sig/owner.test.mjs +1 -1
  57. package/dist/sig/proof.test.mjs +1 -1
  58. package/dist/temporal-BkmBfs__.mjs +95 -0
  59. package/dist/testing/mod.d.mts +48 -6
  60. package/dist/utils/docloader.test.mjs +2 -2
  61. package/dist/utils/kv-cache.test.mjs +1 -1
  62. package/dist/utils/mod.cjs +1 -1
  63. package/dist/utils/mod.js +1 -1
  64. package/package.json +6 -6
  65. /package/dist/{execAsync-DCBrgFiV.mjs → execAsync-Dxb7rNf3.mjs} +0 -0
  66. /package/dist/{getMachineId-linux-ObI47Hql.mjs → getMachineId-linux-Bbhofx-s.mjs} +0 -0
  67. /package/dist/{getMachineId-unsupported-Ddu-PFeh.mjs → getMachineId-unsupported-dIOte2Ct.mjs} +0 -0
  68. /package/dist/{retry-v_sGLH1d.mjs → retry-_VvV0h9f.mjs} +0 -0
@@ -1,9 +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-B_9yJW3w.mjs";
5
- import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-iRBg8jTk.mjs";
6
- import { n as fetchKey, o as validateCryptoKey } from "./key-CkkMJBjF.mjs";
4
+ import { n as version, t as name } from "./deno-CKFE6Uya.mjs";
5
+ import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-7Vy9FvEw.mjs";
6
+ import { n as fetchKey, o as validateCryptoKey } from "./key-N0zP_oJA.mjs";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
9
9
  import { SpanStatusCode, trace } from "@opentelemetry/api";
@@ -17,6 +17,290 @@ const logger = getLogger([
17
17
  "sig",
18
18
  "ld"
19
19
  ]);
20
+ const localContext = [
21
+ "https://w3id.org/identity/v1",
22
+ "https://www.w3.org/ns/activitystreams",
23
+ "https://w3id.org/security/v1",
24
+ "https://w3id.org/security/data-integrity/v1"
25
+ ];
26
+ const localContextUrls = new Set(localContext);
27
+ const builtInContextLoader = getDocumentLoader();
28
+ const disallowedJsonLdKeywords = new Set([
29
+ "@graph",
30
+ "@included",
31
+ "@reverse"
32
+ ]);
33
+ /** @internal */
34
+ var UnsafeJsonLdError = class extends TypeError {
35
+ keyword;
36
+ constructor(keyword) {
37
+ super(`Unsupported JSON-LD keyword: ${keyword}.`);
38
+ this.keyword = keyword;
39
+ this.name = "UnsafeJsonLdError";
40
+ }
41
+ };
42
+ /** @internal */
43
+ var InvalidContextReferenceError = class extends TypeError {
44
+ reference;
45
+ constructor(reference) {
46
+ super(`Invalid JSON-LD context reference: ${reference}.`);
47
+ this.reference = reference;
48
+ this.name = "InvalidContextReferenceError";
49
+ }
50
+ };
51
+ function createLoadingRemoteContextFailedError(reference, cause) {
52
+ const message = cause instanceof Error ? cause.message : String(cause);
53
+ const error = /* @__PURE__ */ new Error(`Dereferencing a URL did not result in a valid JSON-LD context: ${reference}. ${message}`);
54
+ error.name = "jsonld.InvalidUrl";
55
+ error.details = {
56
+ code: "loading remote context failed",
57
+ url: reference
58
+ };
59
+ error.cause = cause;
60
+ return error;
61
+ }
62
+ /** @internal */
63
+ function isClearlyMalformedContextReference(reference) {
64
+ for (const char of reference) {
65
+ const code = char.charCodeAt(0);
66
+ if (code <= 32 || code === 127) return true;
67
+ }
68
+ if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(reference) && !URL.canParse(reference)) return true;
69
+ for (let i = 0; i < reference.length; i++) {
70
+ if (reference[i] !== "%") continue;
71
+ if (i + 2 >= reference.length || !/[0-9A-Fa-f]/.test(reference[i + 1]) || !/[0-9A-Fa-f]/.test(reference[i + 2])) return true;
72
+ i += 2;
73
+ }
74
+ if (reference.startsWith("./") || reference.startsWith("../") || reference.startsWith("/") || reference.startsWith("//")) {
75
+ for (const char of reference) if ("[]<>\"\\^`{|}".includes(char)) return true;
76
+ }
77
+ return false;
78
+ }
79
+ function cloneRemoteDocument(remoteDocument) {
80
+ return structuredClone(remoteDocument);
81
+ }
82
+ function createMemoizedDocumentLoader(documentLoader) {
83
+ const cache = /* @__PURE__ */ new Map();
84
+ return async (url, options) => {
85
+ const cacheKey = URL.canParse(url) ? new URL(url).href : url;
86
+ let remoteDocument = cache.get(cacheKey);
87
+ if (remoteDocument == null) {
88
+ remoteDocument = Promise.resolve(documentLoader(url, options)).then(cloneRemoteDocument);
89
+ remoteDocument.catch(() => {
90
+ if (cache.get(cacheKey) === remoteDocument) cache.delete(cacheKey);
91
+ });
92
+ cache.set(cacheKey, remoteDocument);
93
+ }
94
+ return cloneRemoteDocument(await remoteDocument);
95
+ };
96
+ }
97
+ /** @internal */
98
+ function wrapContextLoaderForJsonLd(contextLoader) {
99
+ const loader = contextLoader ?? builtInContextLoader;
100
+ return async (url, options) => {
101
+ try {
102
+ return await loader(url, options);
103
+ } catch (error) {
104
+ if (!isInvalidUrlTypeError(error)) throw error;
105
+ if (isClearlyMalformedContextReference(url)) throw new InvalidContextReferenceError(url);
106
+ throw createLoadingRemoteContextFailedError(url, error);
107
+ }
108
+ };
109
+ }
110
+ /** @internal */
111
+ function getNormalizationContextLoader(contextLoader) {
112
+ const loader = wrapContextLoaderForJsonLd(contextLoader);
113
+ return createMemoizedDocumentLoader(async (url, options) => {
114
+ if (URL.canParse(url)) {
115
+ const normalizedUrl = new URL(url).href;
116
+ if (localContextUrls.has(normalizedUrl)) return await builtInContextLoader(normalizedUrl, options);
117
+ }
118
+ return await loader(url, options);
119
+ });
120
+ }
121
+ /** @internal */
122
+ async function compactJsonLd(jsonLd, contextLoader) {
123
+ const hasLds = typeof jsonLd === "object" && jsonLd != null && "signature" in jsonLd;
124
+ const signature = hasLds ? jsonLd.signature : void 0;
125
+ const normalizationContextLoader = getNormalizationContextLoader(contextLoader);
126
+ const document = hasLds ? detachSignature(jsonLd) : jsonLd;
127
+ await assertNoGraphBeforeCompaction(document, normalizationContextLoader);
128
+ const compacted = await jsonld.compact(document, localContext, { documentLoader: normalizationContextLoader });
129
+ if (hasLds && typeof compacted === "object" && compacted != null) compacted.signature = signature;
130
+ assertSafeJsonLd(compacted);
131
+ return compacted;
132
+ }
133
+ function createInvalidRemoteContextError(reference) {
134
+ const error = /* @__PURE__ */ new Error(`Dereferencing a URL did not result in a JSON object. The response was valid JSON, but it was not a JSON object. URL: "${reference}".`);
135
+ error.name = "jsonld.InvalidUrl";
136
+ error.details = {
137
+ code: "invalid remote context",
138
+ url: reference
139
+ };
140
+ return error;
141
+ }
142
+ function getRemoteContext(remoteDocument, reference) {
143
+ const { contextUrl, documentUrl } = remoteDocument;
144
+ let { document } = remoteDocument;
145
+ if (typeof document === "string") document = JSON.parse(document);
146
+ if (typeof document !== "object" || document == null || Array.isArray(document)) throw createInvalidRemoteContextError(reference);
147
+ let context = "@context" in document ? document["@context"] : {};
148
+ if (contextUrl != null) context = Array.isArray(context) ? [...context, contextUrl] : [context, contextUrl];
149
+ return {
150
+ context,
151
+ baseUrl: documentUrl ?? reference
152
+ };
153
+ }
154
+ function createGraphAliasContextState() {
155
+ return {
156
+ graphTerms: /* @__PURE__ */ new Set(),
157
+ jsonTerms: /* @__PURE__ */ new Set(),
158
+ propertyContexts: /* @__PURE__ */ new Map(),
159
+ termTargets: /* @__PURE__ */ new Map()
160
+ };
161
+ }
162
+ function cloneGraphAliasContextState(state) {
163
+ return {
164
+ graphTerms: new Set(state.graphTerms),
165
+ jsonTerms: new Set(state.jsonTerms),
166
+ propertyContexts: new Map(state.propertyContexts),
167
+ termTargets: new Map(state.termTargets)
168
+ };
169
+ }
170
+ function resolveContextTarget(target, state) {
171
+ if (target === "@graph") return target;
172
+ const mapped = state.termTargets.get(target);
173
+ if (mapped == null) return target;
174
+ return mapped;
175
+ }
176
+ function getDirectContextTarget(definition) {
177
+ if (definition === null) return null;
178
+ if (typeof definition === "string") return definition;
179
+ if (typeof definition === "object" && definition != null && "@id" in definition) {
180
+ const id = definition["@id"];
181
+ if (id === null) return null;
182
+ if (typeof id === "string") return id;
183
+ }
184
+ }
185
+ function isJsonTypedDefinition(definition) {
186
+ return typeof definition === "object" && definition != null && "@type" in definition && definition["@type"] === "@json";
187
+ }
188
+ function resolveLocalContextTarget(target, state, localTargets, seen = /* @__PURE__ */ new Set()) {
189
+ if (target === "@graph") return target;
190
+ if (seen.has(target)) return target;
191
+ seen.add(target);
192
+ if (localTargets.has(target)) {
193
+ const localTarget = localTargets.get(target);
194
+ return localTarget == null ? target : resolveLocalContextTarget(localTarget, state, localTargets, seen);
195
+ }
196
+ return resolveContextTarget(target, state);
197
+ }
198
+ function refreshGraphAliases(state) {
199
+ state.graphTerms.clear();
200
+ for (const [term, target] of state.termTargets) if (target === "@graph") state.graphTerms.add(term);
201
+ }
202
+ function normalizeContextReference(reference, baseUrl) {
203
+ if (baseUrl != null) return new URL(reference, baseUrl).href;
204
+ return URL.canParse(reference) ? new URL(reference).href : reference;
205
+ }
206
+ /** @internal */
207
+ function isInvalidUrlTypeError(error) {
208
+ const code = error.code;
209
+ return error instanceof TypeError && (code === "ERR_INVALID_URL" || /^Invalid URL(?::|$)/.test(error.message) || / cannot be parsed as a URL\.?$/.test(error.message));
210
+ }
211
+ async function applyGraphAliasContext(state, context, documentLoader, remoteContextCache, baseUrl = null, processingContexts = /* @__PURE__ */ new Set()) {
212
+ if (context === null) return createGraphAliasContextState();
213
+ let nextState = cloneGraphAliasContextState(state);
214
+ if (Array.isArray(context)) {
215
+ for (const item of context) nextState = await applyGraphAliasContext(nextState, item, documentLoader, remoteContextCache, baseUrl, processingContexts);
216
+ return nextState;
217
+ }
218
+ if (typeof context === "string") {
219
+ const reference = normalizeContextReference(context, baseUrl);
220
+ const cacheKey = `${baseUrl ?? ""}\n${reference}`;
221
+ if (processingContexts.has(cacheKey)) return nextState;
222
+ processingContexts.add(cacheKey);
223
+ try {
224
+ let remoteContext = remoteContextCache.get(cacheKey);
225
+ if (remoteContext == null) {
226
+ remoteContext = (async () => {
227
+ try {
228
+ return getRemoteContext(await documentLoader(reference), reference);
229
+ } catch (error) {
230
+ if (reference === context && isInvalidUrlTypeError(error) && isClearlyMalformedContextReference(context)) throw new InvalidContextReferenceError(context);
231
+ throw error;
232
+ }
233
+ })();
234
+ remoteContextCache.set(cacheKey, remoteContext);
235
+ }
236
+ const loadedRemoteContext = await remoteContext;
237
+ return await applyGraphAliasContext(nextState, loadedRemoteContext.context, documentLoader, remoteContextCache, loadedRemoteContext.baseUrl, processingContexts);
238
+ } finally {
239
+ processingContexts.delete(cacheKey);
240
+ }
241
+ }
242
+ if (typeof context === "object" && context != null) {
243
+ if ("@import" in context && typeof context["@import"] === "string") nextState = await applyGraphAliasContext(nextState, context["@import"], documentLoader, remoteContextCache, baseUrl, processingContexts);
244
+ const localTargets = /* @__PURE__ */ new Map();
245
+ for (const [term, definition] of globalThis.Object.entries(context)) {
246
+ if (term.startsWith("@")) continue;
247
+ const target = getDirectContextTarget(definition);
248
+ if (target == null) localTargets.set(term, null);
249
+ else if (typeof target === "string") localTargets.set(term, target);
250
+ else localTargets.delete(term);
251
+ }
252
+ for (const [term, definition] of globalThis.Object.entries(context)) {
253
+ if (term.startsWith("@")) continue;
254
+ if (localTargets.has(term)) {
255
+ const directTarget = localTargets.get(term);
256
+ if (directTarget == null) nextState.termTargets.set(term, null);
257
+ else nextState.termTargets.set(term, resolveLocalContextTarget(directTarget, nextState, localTargets));
258
+ } else nextState.termTargets.delete(term);
259
+ if (typeof definition === "object" && definition != null && "@context" in definition) nextState.propertyContexts.set(term, {
260
+ context: definition["@context"],
261
+ baseUrl
262
+ });
263
+ else nextState.propertyContexts.delete(term);
264
+ if (isJsonTypedDefinition(definition)) nextState.jsonTerms.add(term);
265
+ else nextState.jsonTerms.delete(term);
266
+ }
267
+ refreshGraphAliases(nextState);
268
+ }
269
+ return nextState;
270
+ }
271
+ async function assertNoGraphBeforeCompaction(jsonLd, documentLoader, inheritedState = createGraphAliasContextState(), propertyContext, remoteContextCache = /* @__PURE__ */ new Map()) {
272
+ if (Array.isArray(jsonLd)) {
273
+ for (const item of jsonLd) await assertNoGraphBeforeCompaction(item, documentLoader, inheritedState, propertyContext, remoteContextCache);
274
+ return;
275
+ }
276
+ if (typeof jsonLd !== "object" || jsonLd == null) return;
277
+ const jsonLiteralWrapper = isJsonLiteralWrapper(jsonLd);
278
+ let state = inheritedState;
279
+ if (propertyContext !== void 0) state = await applyGraphAliasContext(state, propertyContext.context, documentLoader, remoteContextCache, propertyContext.baseUrl);
280
+ if ("@context" in jsonLd) state = await applyGraphAliasContext(state, jsonLd["@context"], documentLoader, remoteContextCache);
281
+ for (const [key, value] of globalThis.Object.entries(jsonLd)) {
282
+ if (key === "@context") continue;
283
+ if (jsonLiteralWrapper && key === "@value") continue;
284
+ if (key === "@graph" || state.graphTerms.has(key)) throw new UnsafeJsonLdError("@graph");
285
+ if (state.jsonTerms.has(key)) continue;
286
+ await assertNoGraphBeforeCompaction(value, documentLoader, state, state.propertyContexts.get(key), remoteContextCache);
287
+ }
288
+ }
289
+ function isJsonLiteralWrapper(value) {
290
+ return "@value" in value && (value["@type"] === "@json" || value.type === "@json");
291
+ }
292
+ /** @internal */
293
+ function assertSafeJsonLd(jsonLd) {
294
+ if (Array.isArray(jsonLd)) for (const item of jsonLd) assertSafeJsonLd(item);
295
+ else if (typeof jsonLd === "object" && jsonLd != null) {
296
+ const jsonLiteralWrapper = isJsonLiteralWrapper(jsonLd);
297
+ for (const [key, value] of globalThis.Object.entries(jsonLd)) {
298
+ if (disallowedJsonLdKeywords.has(key)) throw new UnsafeJsonLdError(key);
299
+ if (jsonLiteralWrapper && key === "@value") continue;
300
+ assertSafeJsonLd(value);
301
+ }
302
+ }
303
+ }
20
304
  /**
21
305
  * Attaches a LD signature to the given JSON-LD document.
22
306
  * @param jsonLd The JSON-LD document to attach the signature to. It is not
@@ -271,13 +555,25 @@ function getLdSignatureObject(jsonLd) {
271
555
  * @returns `true` if the document is authentic; `false` otherwise.
272
556
  */
273
557
  async function verifyJsonLd(jsonLd, options = {}) {
558
+ return await verifyJsonLdInternal(jsonLd, options, true);
559
+ }
560
+ /** @internal */
561
+ async function verifyCompactJsonLd(jsonLd, options = {}) {
562
+ return await verifyJsonLdInternal(jsonLd, options, false);
563
+ }
564
+ async function verifyJsonLdInternal(jsonLd, options, compact) {
274
565
  return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("ld_signatures.verify", async (span) => {
275
566
  const start = performance.now();
276
567
  let verified = false;
277
568
  let threw = false;
278
569
  let signatureType;
279
570
  try {
280
- const object = await Object$1.fromJsonLd(jsonLd, options);
571
+ const verificationOptions = hasSignature(jsonLd) ? {
572
+ ...options,
573
+ contextLoader: getNormalizationContextLoader(options.contextLoader)
574
+ } : options;
575
+ const compacted = compact ? hasSignature(jsonLd) ? await compactJsonLd(jsonLd, options.contextLoader) : jsonLd : jsonLd;
576
+ const object = await Object$1.fromJsonLd(compacted, verificationOptions);
281
577
  if (object.id != null) span.setAttribute("activitypub.object.id", object.id.href);
282
578
  span.setAttribute("activitypub.object.type", getTypeId(object).href);
283
579
  const sig = getLdSignatureObject(jsonLd);
@@ -291,7 +587,7 @@ async function verifyJsonLd(jsonLd, options = {}) {
291
587
  }
292
588
  const attributions = new Set(object.attributionIds.map((uri) => uri.href));
293
589
  if (object instanceof Activity) for (const uri of object.actorIds) attributions.add(uri.href);
294
- const key = await verifySignature(jsonLd, options);
590
+ const key = await verifySignature(compacted, verificationOptions);
295
591
  if (key == null) return false;
296
592
  if (key.ownerId == null) {
297
593
  logger.debug("Key {keyId} has no owner.", { keyId: key.id?.href });
@@ -327,4 +623,4 @@ async function hashJsonLd(jsonLd, contextLoader) {
327
623
  return encodeHex(await crypto.subtle.digest("SHA-256", encoder.encode(canon)));
328
624
  }
329
625
  //#endregion
330
- export { signJsonLd as a, hasSignatureLike as i, createSignature as n, verifyJsonLd as o, detachSignature as r, verifySignature as s, attachSignature as t };
626
+ export { wrapContextLoaderForJsonLd as _, compactJsonLd as a, getNormalizationContextLoader as c, isClearlyMalformedContextReference as d, isInvalidUrlTypeError as f, verifySignature as g, verifyJsonLd as h, attachSignature as i, hasSignature as l, verifyCompactJsonLd as m, UnsafeJsonLdError as n, createSignature as o, signJsonLd as p, assertSafeJsonLd as r, detachSignature as s, InvalidContextReferenceError as t, hasSignatureLike as u };
@@ -1,7 +1,7 @@
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-B_9yJW3w.mjs";
4
+ import { n as version, t as name } from "./deno-CKFE6Uya.mjs";
5
5
  import { metrics } from "@opentelemetry/api";
6
6
  import { FetchError } from "@fedify/vocab-runtime";
7
7
  //#region src/federation/metrics.ts
@@ -29,6 +29,8 @@ var FederationMetrics = class {
29
29
  documentFetch;
30
30
  documentFetchDuration;
31
31
  documentCache;
32
+ webFingerHandle;
33
+ webFingerHandleDuration;
32
34
  constructor(meterProvider) {
33
35
  const meter = meterProvider.getMeter(name, version);
34
36
  this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
@@ -187,6 +189,30 @@ var FederationMetrics = class {
187
189
  description: "KV-backed document loader cache lookups, with `hit` or `miss` classification.",
188
190
  unit: "{lookup}"
189
191
  });
192
+ this.webFingerHandle = meter.createCounter("webfinger.handle", {
193
+ description: "Incoming WebFinger requests handled by Fedify, classified by terminal outcome.",
194
+ unit: "{request}"
195
+ });
196
+ this.webFingerHandleDuration = meter.createHistogram("webfinger.handle.duration", {
197
+ description: "Duration of incoming WebFinger request handling in Fedify.",
198
+ unit: "ms",
199
+ advice: { explicitBucketBoundaries: [
200
+ 5,
201
+ 10,
202
+ 25,
203
+ 50,
204
+ 75,
205
+ 100,
206
+ 250,
207
+ 500,
208
+ 750,
209
+ 1e3,
210
+ 2500,
211
+ 5e3,
212
+ 7500,
213
+ 1e4
214
+ ] }
215
+ });
190
216
  }
191
217
  recordDelivery(inbox, durationMs, success, activityType) {
192
218
  const deliveryAttributes = {
@@ -300,6 +326,13 @@ var FederationMetrics = class {
300
326
  if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
301
327
  this.documentCache.add(1, attributes);
302
328
  }
329
+ recordWebFingerHandle(attrs) {
330
+ const attributes = { "webfinger.handle.result": attrs.result };
331
+ if (attrs.scheme != null) attributes["webfinger.resource.scheme"] = attrs.scheme;
332
+ if (attrs.statusCode != null) attributes["http.response.status_code"] = attrs.statusCode;
333
+ this.webFingerHandle.add(1, attributes);
334
+ this.webFingerHandleDuration.record(attrs.durationMs, attributes);
335
+ }
303
336
  };
304
337
  function buildActivityLifecycleAttributes(result, activityType) {
305
338
  const attributes = { "activitypub.processing.result": result };
@@ -424,6 +457,19 @@ function recordDocumentCache(meterProvider, attrs) {
424
457
  getFederationMetrics(meterProvider).recordDocumentCache(attrs);
425
458
  }
426
459
  /**
460
+ * Records one measurement on `webfinger.handle` (counter) and
461
+ * `webfinger.handle.duration` (histogram) for an incoming WebFinger
462
+ * request handled by Fedify. Counter and histogram are always recorded
463
+ * together, with `webfinger.handle.result` set to one of `resolved`,
464
+ * `invalid`, `not_found`, `tombstoned`, or `error`. The queried
465
+ * resource string is deliberately excluded; it remains on the
466
+ * `webfinger.handle` span for trace-level investigation.
467
+ * @since 2.3.0
468
+ */
469
+ function recordWebFingerHandle(meterProvider, attrs) {
470
+ getFederationMetrics(meterProvider).recordWebFingerHandle(attrs);
471
+ }
472
+ /**
427
473
  * Classifies a thrown value from a key or document fetch into the bounded
428
474
  * {@link LookupResult} taxonomy and, when an HTTP response was received,
429
475
  * surfaces its status code.
@@ -586,4 +632,4 @@ function getDurationMs(start) {
586
632
  return Math.max(0, performance.now() - start);
587
633
  }
588
634
  //#endregion
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 };
635
+ export { instrumentDocumentLoader as a, recordDocumentCache as c, recordInboxActivity as d, recordKeyLookup as f, recordWebFingerHandle as h, 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 };