@fedify/fedify 1.3.0-dev.568 → 1.3.0-dev.570

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/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "@fedify/fedify",
3
- "version": "1.3.0-dev.568+35cde4e3",
3
+ "version": "1.3.0-dev.570+61d94afc",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./mod.ts",
@@ -1,10 +1,13 @@
1
1
  import * as dntShim from "../_dnt.shims.js";
2
2
  import { getLogger } from "@logtape/logtape";
3
+ import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
3
4
  import { accepts } from "../deps/jsr.io/@std/http/1.0.11/negotiation.js";
5
+ import metadata from "../deno.js";
4
6
  import { verifyRequest } from "../sig/http.js";
5
7
  import { detachSignature, verifyJsonLd } from "../sig/ld.js";
6
8
  import { doesActorOwnKey } from "../sig/owner.js";
7
9
  import { verifyObject } from "../sig/proof.js";
10
+ import { getTypeId } from "../vocab/type.js";
8
11
  import { Activity, CryptographicKey, Link, Multikey, Object, OrderedCollection, OrderedCollectionPage, } from "../vocab/vocab.js";
9
12
  export function acceptsJsonLd(request) {
10
13
  const types = accepts(request);
@@ -68,21 +71,46 @@ export async function handleObject(request, { values, context, objectDispatcher,
68
71
  },
69
72
  });
70
73
  }
71
- export async function handleCollection(request, { name, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, onUnauthorized, onNotFound, onNotAcceptable, }) {
72
- if (collectionCallbacks == null)
73
- return await onNotFound(request);
74
+ export function handleCollection(request, params) {
75
+ const name = params.name.trim().replace(/\s+/g, "_");
76
+ const tracerProvider = params.tracerProvider ?? trace.getTracerProvider();
77
+ const tracer = tracerProvider.getTracer(metadata.name, metadata.version);
74
78
  const url = new URL(request.url);
75
79
  const cursor = url.searchParams.get("cursor");
80
+ return tracer.startActiveSpan(cursor == null
81
+ ? `activitypub.dispatch_collection ${name}`
82
+ : `activitypub.dispatch_collection_page ${name}`, { kind: SpanKind.SERVER }, async (span) => {
83
+ try {
84
+ return await handleCollectionInternal(request, cursor, params, span);
85
+ }
86
+ catch (e) {
87
+ span.setStatus({ code: SpanStatusCode.ERROR, message: String(e) });
88
+ throw e;
89
+ }
90
+ finally {
91
+ span.end();
92
+ }
93
+ });
94
+ }
95
+ async function handleCollectionInternal(request, cursor, { name, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, onUnauthorized, onNotFound, onNotAcceptable, }, span) {
96
+ if (collectionCallbacks == null)
97
+ return await onNotFound(request);
76
98
  let collection;
77
99
  const baseUri = uriGetter(identifier);
78
100
  if (cursor == null) {
79
101
  const firstCursor = await collectionCallbacks.firstCursor?.(context, identifier);
80
102
  const totalItems = await collectionCallbacks.counter?.(context, identifier);
103
+ if (totalItems != null) {
104
+ span.setAttribute("activitypub.collection.total_items", Number(totalItems));
105
+ }
81
106
  if (firstCursor == null) {
82
107
  const page = await collectionCallbacks.dispatcher(context, identifier, null, filter);
83
- if (page == null)
108
+ if (page == null) {
109
+ span.setStatus({ code: SpanStatusCode.ERROR });
84
110
  return await onNotFound(request);
111
+ }
85
112
  const { items } = page;
113
+ span.setAttribute("fedify.collection.items", items.length);
86
114
  collection = new OrderedCollection({
87
115
  id: baseUri,
88
116
  totalItems: totalItems == null ? null : Number(totalItems),
@@ -107,12 +135,16 @@ export async function handleCollection(request, { name, identifier, uriGetter, f
107
135
  }
108
136
  }
109
137
  else {
138
+ span.setAttribute("fedify.collection.cursor", cursor);
110
139
  const uri = new URL(baseUri);
111
140
  uri.searchParams.set("cursor", cursor);
112
141
  const page = await collectionCallbacks.dispatcher(context, identifier, cursor, filter);
113
- if (page == null)
142
+ if (page == null) {
143
+ span.setStatus({ code: SpanStatusCode.ERROR });
114
144
  return await onNotFound(request);
145
+ }
115
146
  const { items, prevCursor, nextCursor } = page;
147
+ span.setAttribute("fedify.collection.items", items.length);
116
148
  let prev = null;
117
149
  if (prevCursor != null) {
118
150
  prev = new URL(context.url);
@@ -142,6 +174,10 @@ export async function handleCollection(request, { name, identifier, uriGetter, f
142
174
  return await onUnauthorized(request);
143
175
  }
144
176
  }
177
+ if (collection.id != null) {
178
+ span.setAttribute("activitypub.collection.id", collection.id.href);
179
+ }
180
+ span.setAttribute("activitypub.collection.type", getTypeId(collection).href);
145
181
  const jsonLd = await collection.toJsonLd(context);
146
182
  return new Response(JSON.stringify(jsonLd), {
147
183
  headers: {
@@ -11,6 +11,7 @@ import { hasSignature, signJsonLd } from "../sig/ld.js";
11
11
  import { getKeyOwner } from "../sig/owner.js";
12
12
  import { signObject } from "../sig/proof.js";
13
13
  import { lookupObject, traverseCollection, } from "../vocab/lookup.js";
14
+ import { getTypeId } from "../vocab/type.js";
14
15
  import { Activity, CryptographicKey, Multikey, } from "../vocab/vocab.js";
15
16
  import { handleWebFinger } from "../webfinger/handler.js";
16
17
  import { buildCollectionSynchronizationHeader } from "./collection.js";
@@ -402,7 +403,32 @@ export class FederationImpl {
402
403
  }
403
404
  const callbacks = {
404
405
  dispatcher: async (context, identifier) => {
405
- const actor = await dispatcher(context, identifier);
406
+ const actor = await this.#getTracer().startActiveSpan("activitypub.dispatch_actor", {
407
+ kind: SpanKind.SERVER,
408
+ attributes: { "fedify.actor.identifier": identifier },
409
+ }, async (span) => {
410
+ try {
411
+ const actor = await dispatcher(context, identifier);
412
+ span.setAttribute("activitypub.actor.id", (actor?.id ?? context.getActorUri(identifier)).href);
413
+ if (actor == null) {
414
+ span.setStatus({ code: SpanStatusCode.ERROR });
415
+ }
416
+ else {
417
+ span.setAttribute("activitypub.actor.type", getTypeId(actor).href);
418
+ }
419
+ return actor;
420
+ }
421
+ catch (error) {
422
+ span.setStatus({
423
+ code: SpanStatusCode.ERROR,
424
+ message: String(error),
425
+ });
426
+ throw error;
427
+ }
428
+ finally {
429
+ span.end();
430
+ }
431
+ });
406
432
  if (actor == null)
407
433
  return null;
408
434
  const logger = getLogger(["fedify", "federation", "actor"]);
@@ -536,8 +562,28 @@ export class FederationImpl {
536
562
  };
537
563
  this.actorCallbacks = callbacks;
538
564
  const setters = {
539
- setKeyPairsDispatcher(dispatcher) {
540
- callbacks.keyPairsDispatcher = dispatcher;
565
+ setKeyPairsDispatcher: (dispatcher) => {
566
+ callbacks.keyPairsDispatcher = (ctx, identifier) => this.#getTracer().startActiveSpan("activitypub.dispatch_actor_key_pairs", {
567
+ kind: SpanKind.SERVER,
568
+ attributes: {
569
+ "activitypub.actor.id": ctx.getActorUri(identifier).href,
570
+ "fedify.actor.identifier": identifier,
571
+ },
572
+ }, async (span) => {
573
+ try {
574
+ return await dispatcher(ctx, identifier);
575
+ }
576
+ catch (e) {
577
+ span.setStatus({
578
+ code: SpanStatusCode.ERROR,
579
+ message: String(e),
580
+ });
581
+ throw e;
582
+ }
583
+ finally {
584
+ span.end();
585
+ }
586
+ });
541
587
  return setters;
542
588
  },
543
589
  mapHandle(mapper) {
@@ -563,7 +609,41 @@ export class FederationImpl {
563
609
  throw new RouterError("Path for object dispatcher must have at least one variable.");
564
610
  }
565
611
  const callbacks = {
566
- dispatcher,
612
+ dispatcher: (ctx, values) => {
613
+ const tracer = this.#getTracer();
614
+ return tracer.startActiveSpan("activitypub.dispatch_object", {
615
+ kind: SpanKind.SERVER,
616
+ attributes: {
617
+ "fedify.object.type": cls.typeId.href,
618
+ ...globalThis.Object.fromEntries(globalThis.Object.entries(values).map(([k, v]) => [
619
+ `fedify.object.values.${k}`,
620
+ v,
621
+ ])),
622
+ },
623
+ }, async (span) => {
624
+ try {
625
+ const object = await dispatcher(ctx, values);
626
+ span.setAttribute("activitypub.object.id", (object?.id ?? ctx.getObjectUri(cls, values)).href);
627
+ if (object == null) {
628
+ span.setStatus({ code: SpanStatusCode.ERROR });
629
+ }
630
+ else {
631
+ span.setAttribute("activitypub.object.type", getTypeId(object).href);
632
+ }
633
+ return object;
634
+ }
635
+ catch (e) {
636
+ span.setStatus({
637
+ code: SpanStatusCode.ERROR,
638
+ message: String(e),
639
+ });
640
+ throw e;
641
+ }
642
+ finally {
643
+ span.end();
644
+ }
645
+ });
646
+ },
567
647
  parameters: variables,
568
648
  };
569
649
  this.objectCallbacks[cls.typeId.href] = callbacks;
@@ -1143,6 +1223,7 @@ export class FederationImpl {
1143
1223
  uriGetter: context.getOutboxUri.bind(context),
1144
1224
  context,
1145
1225
  collectionCallbacks: this.outboxCallbacks,
1226
+ tracerProvider: this.tracerProvider,
1146
1227
  onUnauthorized,
1147
1228
  onNotFound,
1148
1229
  onNotAcceptable,
@@ -1155,6 +1236,7 @@ export class FederationImpl {
1155
1236
  uriGetter: context.getInboxUri.bind(context),
1156
1237
  context,
1157
1238
  collectionCallbacks: this.inboxCallbacks,
1239
+ tracerProvider: this.tracerProvider,
1158
1240
  onUnauthorized,
1159
1241
  onNotFound,
1160
1242
  onNotAcceptable,
@@ -1202,6 +1284,7 @@ export class FederationImpl {
1202
1284
  uriGetter: context.getFollowingUri.bind(context),
1203
1285
  context,
1204
1286
  collectionCallbacks: this.followingCallbacks,
1287
+ tracerProvider: this.tracerProvider,
1205
1288
  onUnauthorized,
1206
1289
  onNotFound,
1207
1290
  onNotAcceptable,
@@ -1222,6 +1305,7 @@ export class FederationImpl {
1222
1305
  ? ((i) => (i instanceof URL ? i.href : i.id?.href ?? "").startsWith(baseUrl))
1223
1306
  : undefined,
1224
1307
  collectionCallbacks: this.followersCallbacks,
1308
+ tracerProvider: this.tracerProvider,
1225
1309
  onUnauthorized,
1226
1310
  onNotFound,
1227
1311
  onNotAcceptable,
@@ -1234,6 +1318,7 @@ export class FederationImpl {
1234
1318
  uriGetter: context.getLikedUri.bind(context),
1235
1319
  context,
1236
1320
  collectionCallbacks: this.likedCallbacks,
1321
+ tracerProvider: this.tracerProvider,
1237
1322
  onUnauthorized,
1238
1323
  onNotFound,
1239
1324
  onNotAcceptable,
@@ -1245,6 +1330,7 @@ export class FederationImpl {
1245
1330
  uriGetter: context.getFeaturedUri.bind(context),
1246
1331
  context,
1247
1332
  collectionCallbacks: this.featuredCallbacks,
1333
+ tracerProvider: this.tracerProvider,
1248
1334
  onUnauthorized,
1249
1335
  onNotFound,
1250
1336
  onNotAcceptable,
@@ -1256,6 +1342,7 @@ export class FederationImpl {
1256
1342
  uriGetter: context.getFeaturedTagsUri.bind(context),
1257
1343
  context,
1258
1344
  collectionCallbacks: this.featuredTagsCallbacks,
1345
+ tracerProvider: this.tracerProvider,
1259
1346
  onUnauthorized,
1260
1347
  onNotFound,
1261
1348
  onNotAcceptable,