@fedify/fedify 2.3.0-dev.1114 → 2.3.0-dev.1131
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.
- package/dist/{builder-YlEusQth.mjs → builder-DckAhD27.mjs} +2 -2
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{context-cSUMk2da.d.ts → context-Cq18Gplu.d.ts} +3 -208
- package/dist/{context-Ch-ZLyTQ.d.cts → context-tc6VOOOL.d.cts} +3 -208
- package/dist/{deno-CF3jMgip.mjs → deno--CS-SBS9.mjs} +1 -1
- package/dist/{docloader-BENj6vQ4.mjs → docloader-k6huZLQL.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.d.mts +2 -0
- package/dist/federation/metrics.test.mjs +335 -0
- package/dist/federation/middleware.test.mjs +444 -6
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +3 -2
- package/dist/federation/mod.d.ts +3 -2
- package/dist/federation/mod.js +1 -1
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{http-CKCgOPkX.cjs → http-CJfvRL7D.cjs} +352 -22
- package/dist/{http-BmOZYc-8.mjs → http-IywnQdiX.mjs} +7 -5
- package/dist/{http-D6LP89UO.d.ts → http-VyDTd4G3.d.cts} +8 -1
- package/dist/{http-CpzZ9zsb.js → http-cqujdCRz.js} +323 -23
- package/dist/{http-D6aw3j2U.d.cts → http-lf8Hsd91.d.ts} +8 -1
- package/dist/{key-B4I8H5Lc.mjs → key-Df3tMleh.mjs} +42 -17
- package/dist/{kv-cache-DY-XWOqM.cjs → kv-cache-L0SMQkcd.cjs} +19 -2
- package/dist/{kv-cache-Wc5ezcVW.js → kv-cache-pEejzYq4.js} +19 -2
- package/dist/{kv-cache-DihufyAQ.mjs → kv-cache-q9Ec2ryS.mjs} +19 -1
- package/dist/{ld-B5D5THhl.mjs → ld-BGwiJpl3.mjs} +3 -3
- package/dist/{metrics-ek3ilf6c.mjs → metrics-BTOMkW8C.mjs} +280 -5
- package/dist/{middleware-EqTYPG4F.cjs → middleware-B2rtdpFV.cjs} +75 -28
- package/dist/{middleware-DlcecZMq.mjs → middleware-BB0IbDow.mjs} +84 -37
- package/dist/{middleware-EI7OU6BR.mjs → middleware-Dnql59Y8.mjs} +1 -1
- package/dist/{middleware-CuZbBw-N.js → middleware-DtOddSVg.js} +75 -28
- package/dist/{mod-BDhgfjP7.d.cts → mod-B0hW12_O.d.cts} +1 -1
- package/dist/{mod-B-Lin9Sy.d.ts → mod-COIAjwRS.d.ts} +1 -1
- package/dist/{mod-C6E8rkcz.d.ts → mod-CajNYYkt.d.ts} +1 -1
- package/dist/{mod-DLrRb0dx.d.ts → mod-DFvNJcNb.d.ts} +54 -3
- package/dist/{mod-P9tE2WmM.d.cts → mod-DnzgcPcy.d.cts} +1 -1
- package/dist/{mod-BR_BB0bh.d.cts → mod-yvIXFAEi.d.cts} +54 -3
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +6 -5
- package/dist/mod.d.ts +6 -5
- package/dist/mod.js +4 -4
- package/dist/mq-D-nlpY04.d.ts +208 -0
- package/dist/mq-D8uSFzxe.d.cts +208 -0
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{owner-DO810N24.mjs → owner-CIt4hvmM.mjs} +2 -2
- package/dist/{proof-DIoqrKnX.cjs → proof-B1_u25UV.cjs} +1 -1
- package/dist/{proof-BgfyWv7b.mjs → proof-BYlrRSmZ.mjs} +3 -3
- package/dist/{proof-Vd8-1EWh.js → proof-DMGIjHYH.js} +1 -1
- package/dist/{send-CAYXdUTk.mjs → send-DJFpze7B.mjs} +3 -3
- package/dist/sig/http.test.mjs +6 -2
- package/dist/sig/key.test.mjs +99 -2
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +2 -2
- package/dist/sig/mod.d.ts +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/proof.test.mjs +1 -1
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/kv-cache.test.mjs +67 -2
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.d.cts +1 -1
- package/dist/utils/mod.d.ts +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +6 -6
|
@@ -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.
|
|
14
|
+
var version = "2.3.0-dev.1131+553b59b8";
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/sig/accept.ts
|
|
17
17
|
/**
|
|
@@ -169,6 +169,14 @@ var FederationMetrics = class {
|
|
|
169
169
|
queueTaskFailed;
|
|
170
170
|
queueTaskDuration;
|
|
171
171
|
queueTaskInFlight;
|
|
172
|
+
fanoutRecipients;
|
|
173
|
+
inboxActivity;
|
|
174
|
+
outboxActivity;
|
|
175
|
+
keyLookup;
|
|
176
|
+
keyLookupDuration;
|
|
177
|
+
documentFetch;
|
|
178
|
+
documentFetchDuration;
|
|
179
|
+
documentCache;
|
|
172
180
|
constructor(meterProvider) {
|
|
173
181
|
const meter = meterProvider.getMeter(name, version);
|
|
174
182
|
this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
|
|
@@ -263,6 +271,70 @@ var FederationMetrics = class {
|
|
|
263
271
|
description: "Queue tasks currently being processed in this Fedify process.",
|
|
264
272
|
unit: "{task}"
|
|
265
273
|
});
|
|
274
|
+
this.fanoutRecipients = meter.createHistogram("activitypub.fanout.recipients", {
|
|
275
|
+
description: "Number of recipient inboxes produced by an ActivityPub fanout task.",
|
|
276
|
+
unit: "{recipient}"
|
|
277
|
+
});
|
|
278
|
+
this.inboxActivity = meter.createCounter("activitypub.inbox.activity", {
|
|
279
|
+
description: "ActivityPub activities observed at the inbox lifecycle level: queued, processed, retried, rejected, or abandoned.",
|
|
280
|
+
unit: "{activity}"
|
|
281
|
+
});
|
|
282
|
+
this.outboxActivity = meter.createCounter("activitypub.outbox.activity", {
|
|
283
|
+
description: "ActivityPub activities observed at the outbox lifecycle level: queued, retried, or abandoned. Per-recipient delivery counters live on `activitypub.delivery.*`.",
|
|
284
|
+
unit: "{activity}"
|
|
285
|
+
});
|
|
286
|
+
this.keyLookup = meter.createCounter("activitypub.key.lookup", {
|
|
287
|
+
description: "Public-key lookup attempts performed by Fedify, including both cache hits and remote fetches.",
|
|
288
|
+
unit: "{lookup}"
|
|
289
|
+
});
|
|
290
|
+
this.keyLookupDuration = meter.createHistogram("activitypub.key.lookup.duration", {
|
|
291
|
+
description: "Duration of public-key lookups performed by Fedify, including any remote fetch.",
|
|
292
|
+
unit: "ms",
|
|
293
|
+
advice: { explicitBucketBoundaries: [
|
|
294
|
+
5,
|
|
295
|
+
10,
|
|
296
|
+
25,
|
|
297
|
+
50,
|
|
298
|
+
75,
|
|
299
|
+
100,
|
|
300
|
+
250,
|
|
301
|
+
500,
|
|
302
|
+
750,
|
|
303
|
+
1e3,
|
|
304
|
+
2500,
|
|
305
|
+
5e3,
|
|
306
|
+
7500,
|
|
307
|
+
1e4
|
|
308
|
+
] }
|
|
309
|
+
});
|
|
310
|
+
this.documentFetch = meter.createCounter("activitypub.document.fetch", {
|
|
311
|
+
description: "Remote JSON-LD document loader invocations made by Fedify-wrapped loaders.",
|
|
312
|
+
unit: "{fetch}"
|
|
313
|
+
});
|
|
314
|
+
this.documentFetchDuration = meter.createHistogram("activitypub.document.fetch.duration", {
|
|
315
|
+
description: "Duration of remote JSON-LD document loader invocations made by Fedify-wrapped loaders.",
|
|
316
|
+
unit: "ms",
|
|
317
|
+
advice: { explicitBucketBoundaries: [
|
|
318
|
+
5,
|
|
319
|
+
10,
|
|
320
|
+
25,
|
|
321
|
+
50,
|
|
322
|
+
75,
|
|
323
|
+
100,
|
|
324
|
+
250,
|
|
325
|
+
500,
|
|
326
|
+
750,
|
|
327
|
+
1e3,
|
|
328
|
+
2500,
|
|
329
|
+
5e3,
|
|
330
|
+
7500,
|
|
331
|
+
1e4
|
|
332
|
+
] }
|
|
333
|
+
});
|
|
334
|
+
this.documentCache = meter.createCounter("activitypub.document.cache", {
|
|
335
|
+
description: "KV-backed document loader cache lookups, with `hit` or `miss` classification.",
|
|
336
|
+
unit: "{lookup}"
|
|
337
|
+
});
|
|
266
338
|
}
|
|
267
339
|
recordDelivery(inbox, durationMs, success, activityType) {
|
|
268
340
|
const deliveryAttributes = {
|
|
@@ -335,7 +407,53 @@ var FederationMetrics = class {
|
|
|
335
407
|
else if (result === "failed") this.queueTaskFailed.add(1, attributes);
|
|
336
408
|
this.queueTaskDuration.record(durationMs, attributes);
|
|
337
409
|
}
|
|
410
|
+
recordFanoutRecipients(recipientCount, activityType) {
|
|
411
|
+
const attributes = {};
|
|
412
|
+
if (activityType != null) attributes["activitypub.activity.type"] = activityType;
|
|
413
|
+
this.fanoutRecipients.record(recipientCount, attributes);
|
|
414
|
+
}
|
|
415
|
+
recordInboxActivity(result, activityType) {
|
|
416
|
+
this.inboxActivity.add(1, buildActivityLifecycleAttributes(result, activityType));
|
|
417
|
+
}
|
|
418
|
+
recordOutboxActivity(result, activityType) {
|
|
419
|
+
this.outboxActivity.add(1, buildActivityLifecycleAttributes(result, activityType));
|
|
420
|
+
}
|
|
421
|
+
recordKeyLookup(attrs) {
|
|
422
|
+
const attributes = {
|
|
423
|
+
"activitypub.lookup.kind": "public_key",
|
|
424
|
+
"activitypub.lookup.result": attrs.result,
|
|
425
|
+
"activitypub.cache.enabled": attrs.cacheEnabled
|
|
426
|
+
};
|
|
427
|
+
if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
|
|
428
|
+
if (attrs.statusCode != null) attributes["http.response.status_code"] = attrs.statusCode;
|
|
429
|
+
this.keyLookup.add(1, attributes);
|
|
430
|
+
this.keyLookupDuration.record(attrs.durationMs, attributes);
|
|
431
|
+
}
|
|
432
|
+
recordDocumentFetch(attrs) {
|
|
433
|
+
const attributes = {
|
|
434
|
+
"activitypub.lookup.kind": attrs.kind,
|
|
435
|
+
"activitypub.lookup.result": attrs.result
|
|
436
|
+
};
|
|
437
|
+
if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
|
|
438
|
+
if (attrs.cacheEnabled != null) attributes["activitypub.cache.enabled"] = attrs.cacheEnabled;
|
|
439
|
+
if (attrs.statusCode != null) attributes["http.response.status_code"] = attrs.statusCode;
|
|
440
|
+
this.documentFetch.add(1, attributes);
|
|
441
|
+
this.documentFetchDuration.record(attrs.durationMs, attributes);
|
|
442
|
+
}
|
|
443
|
+
recordDocumentCache(attrs) {
|
|
444
|
+
const attributes = {
|
|
445
|
+
"activitypub.lookup.kind": attrs.kind,
|
|
446
|
+
"activitypub.lookup.result": attrs.result
|
|
447
|
+
};
|
|
448
|
+
if (attrs.remoteUrl != null) attributes["activitypub.remote.host"] = getRemoteHost(attrs.remoteUrl);
|
|
449
|
+
this.documentCache.add(1, attributes);
|
|
450
|
+
}
|
|
338
451
|
};
|
|
452
|
+
function buildActivityLifecycleAttributes(result, activityType) {
|
|
453
|
+
const attributes = { "activitypub.processing.result": result };
|
|
454
|
+
if (activityType != null) attributes["activitypub.activity.type"] = activityType;
|
|
455
|
+
return attributes;
|
|
456
|
+
}
|
|
339
457
|
function buildQueueTaskAttributes(common) {
|
|
340
458
|
const attributes = { "fedify.queue.role": common.role };
|
|
341
459
|
const backend = getQueueBackend(common.queue);
|
|
@@ -365,20 +483,176 @@ function getQueueBackend(queue) {
|
|
|
365
483
|
return name;
|
|
366
484
|
}
|
|
367
485
|
/**
|
|
368
|
-
* Records `fedify.queue.task.enqueued` for an outgoing outbox enqueue
|
|
486
|
+
* Records `fedify.queue.task.enqueued` for an outgoing outbox enqueue and,
|
|
487
|
+
* for the initial attempt, also records
|
|
488
|
+
* `activitypub.outbox.activity{queued}`.
|
|
369
489
|
*
|
|
370
490
|
* Both `Context.sendActivity()` and `OutboxContext.forwardActivity()` enqueue
|
|
371
491
|
* outbox messages with the same metric attributes (role, queue, activity
|
|
372
492
|
* type, attempt), so they share this helper rather than each defining a local
|
|
373
|
-
* closure.
|
|
493
|
+
* closure. Retry enqueues (attempt > 0) intentionally do not record a
|
|
494
|
+
* second `activitypub.outbox.activity{queued}`; retries are reported as
|
|
495
|
+
* `result=retried` from the retry-scheduling site, which has the failure
|
|
496
|
+
* context.
|
|
374
497
|
* @since 2.3.0
|
|
375
498
|
*/
|
|
376
499
|
function recordOutboxEnqueue(meterProvider, outboxQueue, message) {
|
|
377
|
-
getFederationMetrics(meterProvider)
|
|
500
|
+
const metrics = getFederationMetrics(meterProvider);
|
|
501
|
+
metrics.recordQueueTaskEnqueued({
|
|
378
502
|
role: "outbox",
|
|
379
503
|
queue: outboxQueue,
|
|
380
504
|
activityType: message.activityType
|
|
381
505
|
}, message.attempt);
|
|
506
|
+
if (message.attempt === 0) metrics.recordOutboxActivity("queued", message.activityType);
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Records `activitypub.fanout.recipients` with the number of recipient
|
|
510
|
+
* inboxes a single fanout produced. The histogram is unitless count
|
|
511
|
+
* (one measurement per fanout enqueue). Recipient URLs are deliberately
|
|
512
|
+
* not recorded; only the activity type, when known.
|
|
513
|
+
* @since 2.3.0
|
|
514
|
+
*/
|
|
515
|
+
function recordFanoutRecipients(meterProvider, recipientCount, activityType) {
|
|
516
|
+
getFederationMetrics(meterProvider).recordFanoutRecipients(recipientCount, activityType);
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Records one `activitypub.inbox.activity` measurement. The
|
|
520
|
+
* `activitypub.processing.result` attribute is always present;
|
|
521
|
+
* `activitypub.activity.type` is recorded only when Fedify already knows
|
|
522
|
+
* the activity type.
|
|
523
|
+
* @since 2.3.0
|
|
524
|
+
*/
|
|
525
|
+
function recordInboxActivity(meterProvider, result, activityType) {
|
|
526
|
+
getFederationMetrics(meterProvider).recordInboxActivity(result, activityType);
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Records one `activitypub.outbox.activity` measurement. The
|
|
530
|
+
* `activitypub.processing.result` attribute is always present;
|
|
531
|
+
* `activitypub.activity.type` is recorded only when Fedify already knows
|
|
532
|
+
* the activity type (it is always known for outbox lifecycle events).
|
|
533
|
+
* @since 2.3.0
|
|
534
|
+
*/
|
|
535
|
+
function recordOutboxActivity(meterProvider, result, activityType) {
|
|
536
|
+
getFederationMetrics(meterProvider).recordOutboxActivity(result, activityType);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Records one measurement on `activitypub.key.lookup` (counter) and
|
|
540
|
+
* `activitypub.key.lookup.duration` (histogram) for a public-key lookup.
|
|
541
|
+
*
|
|
542
|
+
* `activitypub.lookup.kind` is always recorded as `public_key`; the result
|
|
543
|
+
* classification, remote host, HTTP status code (when an HTTP response was
|
|
544
|
+
* received), and `activitypub.cache.enabled` are recorded as attributes on
|
|
545
|
+
* both measurements. Full key URLs and key IDs are deliberately omitted to
|
|
546
|
+
* keep cardinality bounded.
|
|
547
|
+
* @since 2.3.0
|
|
548
|
+
*/
|
|
549
|
+
function recordKeyLookup(meterProvider, attrs) {
|
|
550
|
+
getFederationMetrics(meterProvider).recordKeyLookup(attrs);
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Records one measurement each on `activitypub.document.fetch` (counter)
|
|
554
|
+
* and `activitypub.document.fetch.duration` (histogram) for one remote
|
|
555
|
+
* JSON-LD document loader invocation, with bounded
|
|
556
|
+
* `activitypub.lookup.kind` and `activitypub.lookup.result` attributes
|
|
557
|
+
* plus the optional remote-host, cache-enabled, and HTTP status-code
|
|
558
|
+
* attributes. Counter and histogram are always recorded together so
|
|
559
|
+
* aggregate rate and latency views stay in sync.
|
|
560
|
+
* @since 2.3.0
|
|
561
|
+
*/
|
|
562
|
+
function recordDocumentFetch(meterProvider, attrs) {
|
|
563
|
+
getFederationMetrics(meterProvider).recordDocumentFetch(attrs);
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Records one `activitypub.document.cache` measurement, classifying the
|
|
567
|
+
* lookup as `hit` (the cache returned an entry) or `miss` (the cache was
|
|
568
|
+
* consulted and returned nothing, prompting a delegate fetch).
|
|
569
|
+
* @since 2.3.0
|
|
570
|
+
*/
|
|
571
|
+
function recordDocumentCache(meterProvider, attrs) {
|
|
572
|
+
getFederationMetrics(meterProvider).recordDocumentCache(attrs);
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Classifies a thrown value from a key or document fetch into the bounded
|
|
576
|
+
* {@link LookupResult} taxonomy and, when an HTTP response was received,
|
|
577
|
+
* surfaces its status code.
|
|
578
|
+
*
|
|
579
|
+
* - `FetchError` with a `Response` whose status is `404` or `410`:
|
|
580
|
+
* `result=not_found` and the response status code.
|
|
581
|
+
* - `FetchError` with any other `Response`: `result=error` and the
|
|
582
|
+
* response status code.
|
|
583
|
+
* - `FetchError` without a `Response`: `result=network_error`.
|
|
584
|
+
* - An `AbortError` (typically from a cancelled fetch): `result=network_error`.
|
|
585
|
+
* - A bare `TypeError` (the shape native `fetch()` raises on DNS, connect,
|
|
586
|
+
* and TLS failures before any response is observed):
|
|
587
|
+
* `result=network_error`.
|
|
588
|
+
* - Any other value: `result=error`.
|
|
589
|
+
* @since 2.3.0
|
|
590
|
+
*/
|
|
591
|
+
function classifyFetchError(error) {
|
|
592
|
+
if (error instanceof _fedify_vocab_runtime.FetchError) {
|
|
593
|
+
if (error.response != null) {
|
|
594
|
+
const status = error.response.status;
|
|
595
|
+
return {
|
|
596
|
+
result: status === 404 || status === 410 ? "not_found" : "error",
|
|
597
|
+
statusCode: status
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
return { result: "network_error" };
|
|
601
|
+
}
|
|
602
|
+
if (isAbortError$1(error)) return { result: "network_error" };
|
|
603
|
+
if (error instanceof TypeError) return { result: "network_error" };
|
|
604
|
+
return { result: "error" };
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Wraps a {@link DocumentLoader} so each invocation records one
|
|
608
|
+
* measurement on `activitypub.document.fetch` (counter) and one on
|
|
609
|
+
* `activitypub.document.fetch.duration` (histogram), classifying the
|
|
610
|
+
* outcome via {@link classifyFetchError} when the wrapped loader throws
|
|
611
|
+
* and as `fetched` on success. The wrapper rethrows whatever the
|
|
612
|
+
* wrapped loader throws so caller behavior is unchanged.
|
|
613
|
+
*
|
|
614
|
+
* The wrapper records the hostname of the requested URL on
|
|
615
|
+
* `activitypub.remote.host` when the URL parses; full URLs, paths, and
|
|
616
|
+
* query strings are deliberately excluded to keep cardinality bounded.
|
|
617
|
+
* HTTP status codes are recorded only when the failure carries a
|
|
618
|
+
* `Response` (currently, when the wrapped loader throws a
|
|
619
|
+
* {@link FetchError} with a non-`null` `response`).
|
|
620
|
+
* @since 2.3.0
|
|
621
|
+
*/
|
|
622
|
+
function instrumentDocumentLoader(loader, options) {
|
|
623
|
+
const meterProvider = options.meterProvider;
|
|
624
|
+
if (meterProvider == null) return loader;
|
|
625
|
+
return async (url, opts) => {
|
|
626
|
+
const start = performance.now();
|
|
627
|
+
let remoteUrl;
|
|
628
|
+
try {
|
|
629
|
+
remoteUrl = new URL(url);
|
|
630
|
+
} catch {
|
|
631
|
+
remoteUrl = void 0;
|
|
632
|
+
}
|
|
633
|
+
try {
|
|
634
|
+
const result = await loader(url, opts);
|
|
635
|
+
recordDocumentFetch(meterProvider, {
|
|
636
|
+
durationMs: getDurationMs(start),
|
|
637
|
+
kind: options.kind,
|
|
638
|
+
result: "fetched",
|
|
639
|
+
remoteUrl,
|
|
640
|
+
cacheEnabled: options.cacheEnabled
|
|
641
|
+
});
|
|
642
|
+
return result;
|
|
643
|
+
} catch (error) {
|
|
644
|
+
const classified = classifyFetchError(error);
|
|
645
|
+
recordDocumentFetch(meterProvider, {
|
|
646
|
+
durationMs: getDurationMs(start),
|
|
647
|
+
kind: options.kind,
|
|
648
|
+
result: classified.result,
|
|
649
|
+
remoteUrl,
|
|
650
|
+
cacheEnabled: options.cacheEnabled,
|
|
651
|
+
statusCode: classified.statusCode
|
|
652
|
+
});
|
|
653
|
+
throw error;
|
|
654
|
+
}
|
|
655
|
+
};
|
|
382
656
|
}
|
|
383
657
|
/**
|
|
384
658
|
* Times an awaited public key fetch and records exactly one
|
|
@@ -760,24 +1034,48 @@ async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoade
|
|
|
760
1034
|
};
|
|
761
1035
|
}
|
|
762
1036
|
async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, onFetchError) {
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
"sig",
|
|
766
|
-
"key"
|
|
767
|
-
]);
|
|
768
|
-
const keyId = cacheKey.href;
|
|
769
|
-
const keyCache = options.keyCache;
|
|
770
|
-
const cached = await getCachedFetchKey(cacheKey, keyId, cls, keyCache, logger);
|
|
771
|
-
if (cached?.key === null && cached.cached) return await onCachedUnavailable(cacheKey, keyId, keyCache, logger);
|
|
772
|
-
if (cached != null) return cached;
|
|
773
|
-
logger.debug("Fetching key {keyId} to verify signature...", { keyId });
|
|
774
|
-
let document;
|
|
1037
|
+
const start = performance.now();
|
|
1038
|
+
let outcome = { result: "error" };
|
|
775
1039
|
try {
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
1040
|
+
const logger = (0, _logtape_logtape.getLogger)([
|
|
1041
|
+
"fedify",
|
|
1042
|
+
"sig",
|
|
1043
|
+
"key"
|
|
1044
|
+
]);
|
|
1045
|
+
const keyId = cacheKey.href;
|
|
1046
|
+
const keyCache = options.keyCache;
|
|
1047
|
+
const cached = await getCachedFetchKey(cacheKey, keyId, cls, keyCache, logger);
|
|
1048
|
+
if (cached?.key === null && cached.cached) {
|
|
1049
|
+
const cachedUnavailable = await onCachedUnavailable(cacheKey, keyId, keyCache, logger);
|
|
1050
|
+
outcome = { result: "hit" };
|
|
1051
|
+
return cachedUnavailable;
|
|
1052
|
+
}
|
|
1053
|
+
if (cached != null) {
|
|
1054
|
+
outcome = { result: "hit" };
|
|
1055
|
+
return cached;
|
|
1056
|
+
}
|
|
1057
|
+
logger.debug("Fetching key {keyId} to verify signature...", { keyId });
|
|
1058
|
+
let document;
|
|
1059
|
+
try {
|
|
1060
|
+
document = (await (options.documentLoader ?? (0, _fedify_vocab_runtime.getDocumentLoader)())(keyId)).document;
|
|
1061
|
+
} catch (error) {
|
|
1062
|
+
const classified = classifyFetchError(error);
|
|
1063
|
+
const errored = await onFetchError(error, cacheKey, keyId, keyCache, logger);
|
|
1064
|
+
outcome = classified;
|
|
1065
|
+
return errored;
|
|
1066
|
+
}
|
|
1067
|
+
const resolved = await resolveFetchedKey(document, cacheKey, keyId, cls, options, logger);
|
|
1068
|
+
outcome = { result: resolved.key != null ? "fetched" : "invalid" };
|
|
1069
|
+
return resolved;
|
|
1070
|
+
} finally {
|
|
1071
|
+
recordKeyLookup(options.meterProvider, {
|
|
1072
|
+
durationMs: getDurationMs(start),
|
|
1073
|
+
result: outcome.result,
|
|
1074
|
+
remoteUrl: cacheKey,
|
|
1075
|
+
cacheEnabled: options.keyCache != null,
|
|
1076
|
+
statusCode: outcome.statusCode
|
|
1077
|
+
});
|
|
779
1078
|
}
|
|
780
|
-
return await resolveFetchedKey(document, cacheKey, keyId, cls, options, logger);
|
|
781
1079
|
}
|
|
782
1080
|
async function fetchKeyInternal(keyId, cls, options = {}) {
|
|
783
1081
|
return await fetchKeyWithResult(typeof keyId === "string" ? new URL(keyId) : keyId, cls, options, (_cacheKey, _keyId, _keyCache, _logger) => {
|
|
@@ -1359,7 +1657,8 @@ async function verifyRequestDraft(request, span, metricsContext, { documentLoade
|
|
|
1359
1657
|
documentLoader,
|
|
1360
1658
|
contextLoader,
|
|
1361
1659
|
keyCache,
|
|
1362
|
-
tracerProvider
|
|
1660
|
+
tracerProvider,
|
|
1661
|
+
meterProvider
|
|
1363
1662
|
}));
|
|
1364
1663
|
if (fetchError != null) return keyFetchErrorResult(keyIdUrl, fetchError);
|
|
1365
1664
|
if (key == null) return invalidSignatureResult(keyIdUrl);
|
|
@@ -1574,7 +1873,8 @@ async function verifyRequestRfc9421(request, span, metricsContext, { documentLoa
|
|
|
1574
1873
|
documentLoader,
|
|
1575
1874
|
contextLoader,
|
|
1576
1875
|
keyCache,
|
|
1577
|
-
tracerProvider
|
|
1876
|
+
tracerProvider,
|
|
1877
|
+
meterProvider
|
|
1578
1878
|
}));
|
|
1579
1879
|
if (fetchError != null) {
|
|
1580
1880
|
setFailure(keyFetchErrorResult(keyId, fetchError));
|
|
@@ -1943,6 +2243,12 @@ Object.defineProperty(exports, "importJwk", {
|
|
|
1943
2243
|
return importJwk;
|
|
1944
2244
|
}
|
|
1945
2245
|
});
|
|
2246
|
+
Object.defineProperty(exports, "instrumentDocumentLoader", {
|
|
2247
|
+
enumerable: true,
|
|
2248
|
+
get: function() {
|
|
2249
|
+
return instrumentDocumentLoader;
|
|
2250
|
+
}
|
|
2251
|
+
});
|
|
1946
2252
|
Object.defineProperty(exports, "isAbortError", {
|
|
1947
2253
|
enumerable: true,
|
|
1948
2254
|
get: function() {
|
|
@@ -1973,6 +2279,30 @@ Object.defineProperty(exports, "parseRfc9421SignatureInput", {
|
|
|
1973
2279
|
return parseRfc9421SignatureInput;
|
|
1974
2280
|
}
|
|
1975
2281
|
});
|
|
2282
|
+
Object.defineProperty(exports, "recordDocumentCache", {
|
|
2283
|
+
enumerable: true,
|
|
2284
|
+
get: function() {
|
|
2285
|
+
return recordDocumentCache;
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2288
|
+
Object.defineProperty(exports, "recordFanoutRecipients", {
|
|
2289
|
+
enumerable: true,
|
|
2290
|
+
get: function() {
|
|
2291
|
+
return recordFanoutRecipients;
|
|
2292
|
+
}
|
|
2293
|
+
});
|
|
2294
|
+
Object.defineProperty(exports, "recordInboxActivity", {
|
|
2295
|
+
enumerable: true,
|
|
2296
|
+
get: function() {
|
|
2297
|
+
return recordInboxActivity;
|
|
2298
|
+
}
|
|
2299
|
+
});
|
|
2300
|
+
Object.defineProperty(exports, "recordOutboxActivity", {
|
|
2301
|
+
enumerable: true,
|
|
2302
|
+
get: function() {
|
|
2303
|
+
return recordOutboxActivity;
|
|
2304
|
+
}
|
|
2305
|
+
});
|
|
1976
2306
|
Object.defineProperty(exports, "recordOutboxEnqueue", {
|
|
1977
2307
|
enumerable: true,
|
|
1978
2308
|
get: function() {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import {
|
|
4
|
+
import { n as version, t as name } from "./deno--CS-SBS9.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-BTOMkW8C.mjs";
|
|
6
6
|
import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CgDcxvjV.mjs";
|
|
7
|
-
import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-
|
|
7
|
+
import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-Df3tMleh.mjs";
|
|
8
8
|
import { getLogger } from "@logtape/logtape";
|
|
9
9
|
import { CryptographicKey } from "@fedify/vocab";
|
|
10
10
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -569,7 +569,8 @@ async function verifyRequestDraft(request, span, metricsContext, { documentLoade
|
|
|
569
569
|
documentLoader,
|
|
570
570
|
contextLoader,
|
|
571
571
|
keyCache,
|
|
572
|
-
tracerProvider
|
|
572
|
+
tracerProvider,
|
|
573
|
+
meterProvider
|
|
573
574
|
}));
|
|
574
575
|
if (fetchError != null) return keyFetchErrorResult(keyIdUrl, fetchError);
|
|
575
576
|
if (key == null) return invalidSignatureResult(keyIdUrl);
|
|
@@ -784,7 +785,8 @@ async function verifyRequestRfc9421(request, span, metricsContext, { documentLoa
|
|
|
784
785
|
documentLoader,
|
|
785
786
|
contextLoader,
|
|
786
787
|
keyCache,
|
|
787
|
-
tracerProvider
|
|
788
|
+
tracerProvider,
|
|
789
|
+
meterProvider
|
|
788
790
|
}));
|
|
789
791
|
if (fetchError != null) {
|
|
790
792
|
setFailure(keyFetchErrorResult(keyId, fetchError));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
2
|
import { CryptographicKey, Multikey } from "@fedify/vocab";
|
|
3
|
-
import { MeterProvider, TracerProvider } from "@opentelemetry/api";
|
|
4
3
|
import { DocumentLoader } from "@fedify/vocab-runtime";
|
|
4
|
+
import { MeterProvider, TracerProvider } from "@opentelemetry/api";
|
|
5
5
|
|
|
6
6
|
//#region src/sig/key.d.ts
|
|
7
7
|
/**
|
|
@@ -52,6 +52,13 @@ interface FetchKeyOptions {
|
|
|
52
52
|
* @since 1.3.0
|
|
53
53
|
*/
|
|
54
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;
|
|
55
62
|
}
|
|
56
63
|
/**
|
|
57
64
|
* The result of {@link fetchKey}.
|