@fedify/fedify 1.3.0-dev.575 → 1.3.0-dev.577

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.575+9cfc4531",
3
+ "version": "1.3.0-dev.577+bda6d57e",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./mod.ts",
@@ -1,6 +1,6 @@
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
+ import { context, propagation, SpanKind, SpanStatusCode, trace, } from "@opentelemetry/api";
4
4
  import { accepts } from "../deps/jsr.io/@std/http/1.0.11/negotiation.js";
5
5
  import metadata from "../deno.js";
6
6
  import { verifyRequest } from "../sig/http.js";
@@ -231,21 +231,55 @@ function filterCollectionItems(items, collectionName, filterPredicate) {
231
231
  }
232
232
  return result;
233
233
  }
234
- export async function handleInbox(request, { recipient, context, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider, }) {
234
+ export async function handleInbox(request, options) {
235
+ const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
236
+ const tracer = tracerProvider.getTracer(metadata.name, metadata.version);
237
+ return await tracer.startActiveSpan("activitypub.inbox", {
238
+ kind: options.queue == null ? SpanKind.SERVER : SpanKind.PRODUCER,
239
+ attributes: { "activitypub.shared_inbox": options.recipient == null },
240
+ }, async (span) => {
241
+ if (options.recipient != null) {
242
+ span.setAttribute("fedify.inbox.recipient", options.recipient);
243
+ }
244
+ try {
245
+ return await handleInboxInternal(request, options, span);
246
+ }
247
+ catch (e) {
248
+ span.setStatus({ code: SpanStatusCode.ERROR, message: String(e) });
249
+ throw e;
250
+ }
251
+ finally {
252
+ span.end();
253
+ }
254
+ });
255
+ }
256
+ async function handleInboxInternal(request, { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider, }, span) {
235
257
  const logger = getLogger(["fedify", "federation", "inbox"]);
236
258
  if (actorDispatcher == null) {
237
259
  logger.error("Actor dispatcher is not set.", { recipient });
260
+ span.setStatus({
261
+ code: SpanStatusCode.ERROR,
262
+ message: "Actor dispatcher is not set.",
263
+ });
238
264
  return await onNotFound(request);
239
265
  }
240
266
  else if (recipient != null) {
241
- const actor = await actorDispatcher(context, recipient);
267
+ const actor = await actorDispatcher(ctx, recipient);
242
268
  if (actor == null) {
243
269
  logger.error("Actor {recipient} not found.", { recipient });
270
+ span.setStatus({
271
+ code: SpanStatusCode.ERROR,
272
+ message: `Actor ${recipient} not found.`,
273
+ });
244
274
  return await onNotFound(request);
245
275
  }
246
276
  }
247
277
  if (request.bodyUsed) {
248
278
  logger.error("Request body has already been read.", { recipient });
279
+ span.setStatus({
280
+ code: SpanStatusCode.ERROR,
281
+ message: "Request body has already been read.",
282
+ });
249
283
  return new Response("Internal server error.", {
250
284
  status: 500,
251
285
  headers: { "Content-Type": "text/plain; charset=utf-8" },
@@ -253,6 +287,10 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
253
287
  }
254
288
  else if (request.body?.locked) {
255
289
  logger.error("Request body is locked.", { recipient });
290
+ span.setStatus({
291
+ code: SpanStatusCode.ERROR,
292
+ message: "Request body is locked.",
293
+ });
256
294
  return new Response("Internal server error.", {
257
295
  status: 500,
258
296
  headers: { "Content-Type": "text/plain; charset=utf-8" },
@@ -265,11 +303,15 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
265
303
  catch (error) {
266
304
  logger.error("Failed to parse JSON:\n{error}", { recipient, error });
267
305
  try {
268
- await inboxErrorHandler?.(context, error);
306
+ await inboxErrorHandler?.(ctx, error);
269
307
  }
270
308
  catch (error) {
271
309
  logger.error("An unexpected error occurred in inbox error handler:\n{error}", { error, activity: json, recipient });
272
310
  }
311
+ span.setStatus({
312
+ code: SpanStatusCode.ERROR,
313
+ message: `Failed to parse JSON:\n${error}`,
314
+ });
273
315
  return new Response("Invalid JSON.", {
274
316
  status: 400,
275
317
  headers: { "Content-Type": "text/plain; charset=utf-8" },
@@ -288,7 +330,7 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
288
330
  return undefined;
289
331
  let object;
290
332
  try {
291
- object = await Object.fromJsonLd(serialized, context);
333
+ object = await Object.fromJsonLd(serialized, ctx);
292
334
  }
293
335
  catch {
294
336
  await kv.delete([...kvPrefixes.publicKey, keyId.href]);
@@ -307,13 +349,13 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
307
349
  return;
308
350
  }
309
351
  this.nullKeys.delete(keyId.href);
310
- const serialized = await key.toJsonLd(context);
352
+ const serialized = await key.toJsonLd(ctx);
311
353
  await kv.set([...kvPrefixes.publicKey, keyId.href], serialized);
312
354
  },
313
355
  };
314
356
  const ldSigVerified = await verifyJsonLd(json, {
315
- contextLoader: context.contextLoader,
316
- documentLoader: context.documentLoader,
357
+ contextLoader: ctx.contextLoader,
358
+ documentLoader: ctx.documentLoader,
317
359
  keyCache,
318
360
  tracerProvider,
319
361
  });
@@ -321,14 +363,14 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
321
363
  let activity = null;
322
364
  if (ldSigVerified) {
323
365
  logger.debug("Linked Data Signatures are verified.", { recipient, json });
324
- activity = await Activity.fromJsonLd(jsonWithoutSig, context);
366
+ activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
325
367
  }
326
368
  else {
327
369
  logger.debug("Linked Data Signatures are not verified.", { recipient, json });
328
370
  try {
329
371
  activity = await verifyObject(Activity, jsonWithoutSig, {
330
- contextLoader: context.contextLoader,
331
- documentLoader: context.documentLoader,
372
+ contextLoader: ctx.contextLoader,
373
+ documentLoader: ctx.documentLoader,
332
374
  keyCache,
333
375
  tracerProvider,
334
376
  });
@@ -340,11 +382,15 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
340
382
  error,
341
383
  });
342
384
  try {
343
- await inboxErrorHandler?.(context, error);
385
+ await inboxErrorHandler?.(ctx, error);
344
386
  }
345
387
  catch (error) {
346
388
  logger.error("An unexpected error occurred in inbox error handler:\n{error}", { error, activity: json, recipient });
347
389
  }
390
+ span.setStatus({
391
+ code: SpanStatusCode.ERROR,
392
+ message: `Failed to parse activity:\n${error}`,
393
+ });
348
394
  return new Response("Invalid activity.", {
349
395
  status: 400,
350
396
  headers: { "Content-Type": "text/plain; charset=utf-8" },
@@ -361,14 +407,18 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
361
407
  if (activity == null) {
362
408
  if (!skipSignatureVerification) {
363
409
  const key = await verifyRequest(request, {
364
- contextLoader: context.contextLoader,
365
- documentLoader: context.documentLoader,
410
+ contextLoader: ctx.contextLoader,
411
+ documentLoader: ctx.documentLoader,
366
412
  timeWindow: signatureTimeWindow,
367
413
  keyCache,
368
414
  tracerProvider,
369
415
  });
370
416
  if (key == null) {
371
417
  logger.error("Failed to verify the request's HTTP Signatures.", { recipient });
418
+ span.setStatus({
419
+ code: SpanStatusCode.ERROR,
420
+ message: `Failed to verify the request's HTTP Signatures.`,
421
+ });
372
422
  const response = new Response("Failed to verify the request signature.", {
373
423
  status: 401,
374
424
  headers: { "Content-Type": "text/plain; charset=utf-8" },
@@ -380,8 +430,12 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
380
430
  }
381
431
  httpSigKey = key;
382
432
  }
383
- activity = await Activity.fromJsonLd(jsonWithoutSig, context);
433
+ activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
434
+ }
435
+ if (activity.id != null) {
436
+ span.setAttribute("activitypub.activity.id", activity.id.href);
384
437
  }
438
+ span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
385
439
  const cacheKey = activity.id == null
386
440
  ? null
387
441
  : [...kvPrefixes.activityIdempotence, activity.id.href];
@@ -393,6 +447,10 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
393
447
  activity: json,
394
448
  recipient,
395
449
  });
450
+ span.setStatus({
451
+ code: SpanStatusCode.UNSET,
452
+ message: `Activity ${activity.id?.href} has already been processed.`,
453
+ });
396
454
  return new Response(`Activity <${activity.id}> has already been processed.`, {
397
455
  status: 202,
398
456
  headers: { "Content-Type": "text/plain; charset=utf-8" },
@@ -401,83 +459,120 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
401
459
  }
402
460
  if (activity.actorId == null) {
403
461
  logger.error("Missing actor.", { activity: json });
404
- const response = new Response("Missing actor.", {
462
+ span.setStatus({ code: SpanStatusCode.ERROR, message: "Missing actor." });
463
+ return new Response("Missing actor.", {
405
464
  status: 400,
406
465
  headers: { "Content-Type": "text/plain; charset=utf-8" },
407
466
  });
408
- return response;
409
467
  }
410
- if (httpSigKey != null && !await doesActorOwnKey(activity, httpSigKey, context)) {
468
+ span.setAttribute("activitypub.actor.id", activity.actorId.href);
469
+ if (httpSigKey != null && !await doesActorOwnKey(activity, httpSigKey, ctx)) {
411
470
  logger.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
412
471
  activity: json,
413
472
  recipient,
414
473
  keyId: httpSigKey.id?.href,
415
474
  actorId: activity.actorId.href,
416
475
  });
417
- const response = new Response("The signer and the actor do not match.", {
476
+ span.setStatus({
477
+ code: SpanStatusCode.ERROR,
478
+ message: `The signer (${httpSigKey.id?.href}) and ` +
479
+ `the actor (${activity.actorId.href}) do not match.`,
480
+ });
481
+ return new Response("The signer and the actor do not match.", {
418
482
  status: 401,
419
483
  headers: { "Content-Type": "text/plain; charset=utf-8" },
420
484
  });
421
- return response;
422
485
  }
423
486
  if (queue != null) {
424
- await queue.enqueue({
425
- type: "inbox",
426
- id: dntShim.crypto.randomUUID(),
427
- baseUrl: request.url,
428
- activity: json,
429
- identifier: recipient,
430
- attempt: 0,
431
- started: new Date().toISOString(),
432
- });
487
+ const carrier = {};
488
+ propagation.inject(context.active(), carrier);
489
+ try {
490
+ await queue.enqueue({
491
+ type: "inbox",
492
+ id: dntShim.crypto.randomUUID(),
493
+ baseUrl: request.url,
494
+ activity: json,
495
+ identifier: recipient,
496
+ attempt: 0,
497
+ started: new Date().toISOString(),
498
+ traceContext: carrier,
499
+ });
500
+ }
501
+ catch (error) {
502
+ logger.error("Failed to enqueue the incoming activity {activityId}:\n{error}", { error, activityId: activity.id?.href, activity: json, recipient });
503
+ span.setStatus({
504
+ code: SpanStatusCode.ERROR,
505
+ message: `Failed to enqueue the incoming activity ${activity.id?.href}.`,
506
+ });
507
+ throw error;
508
+ }
433
509
  logger.info("Activity {activityId} is enqueued.", { activityId: activity.id?.href, activity: json, recipient });
434
510
  return new Response("Activity is enqueued.", {
435
511
  status: 202,
436
512
  headers: { "Content-Type": "text/plain; charset=utf-8" },
437
513
  });
438
514
  }
439
- const listener = inboxListeners?.dispatch(activity);
440
- if (listener == null) {
441
- logger.error("Unsupported activity type:\n{activity}", { activity: json, recipient });
442
- return new Response("", {
443
- status: 202,
444
- headers: { "Content-Type": "text/plain; charset=utf-8" },
445
- });
446
- }
447
- try {
448
- await listener(inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href), activity);
449
- }
450
- catch (error) {
515
+ tracerProvider = tracerProvider ?? trace.getTracerProvider();
516
+ const tracer = tracerProvider.getTracer(metadata.name, metadata.version);
517
+ const response = await tracer.startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
518
+ const dispatched = inboxListeners?.dispatchWithClass(activity);
519
+ if (dispatched == null) {
520
+ logger.error("Unsupported activity type:\n{activity}", { activity: json, recipient });
521
+ span.setStatus({
522
+ code: SpanStatusCode.UNSET,
523
+ message: `Unsupported activity type: ${getTypeId(activity).href}`,
524
+ });
525
+ span.end();
526
+ return new Response("", {
527
+ status: 202,
528
+ headers: { "Content-Type": "text/plain; charset=utf-8" },
529
+ });
530
+ }
531
+ const { class: cls, listener } = dispatched;
532
+ span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
451
533
  try {
452
- await inboxErrorHandler?.(context, error);
534
+ await listener(inboxContextFactory(recipient, json, activity?.id?.href, getTypeId(activity).href), activity);
453
535
  }
454
536
  catch (error) {
455
- logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
537
+ try {
538
+ await inboxErrorHandler?.(ctx, error);
539
+ }
540
+ catch (error) {
541
+ logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
542
+ error,
543
+ activityId: activity.id?.href,
544
+ activity: json,
545
+ recipient,
546
+ });
547
+ }
548
+ logger.error("Failed to process the incoming activity {activityId}:\n{error}", {
456
549
  error,
457
550
  activityId: activity.id?.href,
458
551
  activity: json,
459
552
  recipient,
460
553
  });
554
+ span.setStatus({ code: SpanStatusCode.ERROR, message: String(error) });
555
+ span.end();
556
+ return new Response("Internal server error.", {
557
+ status: 500,
558
+ headers: { "Content-Type": "text/plain; charset=utf-8" },
559
+ });
461
560
  }
462
- logger.error("Failed to process the incoming activity {activityId}:\n{error}", {
463
- error,
464
- activityId: activity.id?.href,
465
- activity: json,
466
- recipient,
467
- });
468
- return new Response("Internal server error.", {
469
- status: 500,
561
+ if (cacheKey != null) {
562
+ await kv.set(cacheKey, true, {
563
+ ttl: dntShim.Temporal.Duration.from({ days: 1 }),
564
+ });
565
+ }
566
+ logger.info("Activity {activityId} has been processed.", { activityId: activity.id?.href, activity: json, recipient });
567
+ span.end();
568
+ return new Response("", {
569
+ status: 202,
470
570
  headers: { "Content-Type": "text/plain; charset=utf-8" },
471
571
  });
472
- }
473
- if (cacheKey != null) {
474
- await kv.set(cacheKey, true, { ttl: dntShim.Temporal.Duration.from({ days: 1 }) });
475
- }
476
- logger.info("Activity {activityId} has been processed.", { activityId: activity.id?.href, activity: json, recipient });
477
- return new Response("", {
478
- status: 202,
479
- headers: { "Content-Type": "text/plain; charset=utf-8" },
480
572
  });
573
+ if (response.status >= 500)
574
+ span.setStatus({ code: SpanStatusCode.ERROR });
575
+ return response;
481
576
  }
482
577
  /**
483
578
  * Responds with the given object in JSON-LD format.
@@ -12,7 +12,7 @@ export class InboxListenerSet {
12
12
  }
13
13
  this.#listeners.set(type, listener);
14
14
  }
15
- dispatch(activity) {
15
+ dispatchWithClass(activity) {
16
16
  // deno-lint-ignore no-explicit-any
17
17
  let cls = activity
18
18
  // deno-lint-ignore no-explicit-any
@@ -29,6 +29,9 @@ export class InboxListenerSet {
29
29
  cls = globalThis.Object.getPrototypeOf(cls);
30
30
  }
31
31
  const listener = inboxListeners.get(cls);
32
- return listener;
32
+ return { class: cls, listener };
33
+ }
34
+ dispatch(activity) {
35
+ return this.dispatchWithClass(activity)?.listener ?? null;
33
36
  }
34
37
  }
@@ -158,18 +158,21 @@ export class FederationImpl {
158
158
  }
159
159
  #listenQueue(ctxData, message) {
160
160
  const tracer = this.#getTracer();
161
+ const extractedContext = propagation.extract(context.active(), message.traceContext);
161
162
  return withContext({ messageId: message.id }, async () => {
162
163
  if (message.type === "outbox") {
163
- const extractedContext = propagation.extract(context.active(), message.traceContext);
164
164
  await tracer.startActiveSpan("activitypub.outbox", {
165
165
  kind: SpanKind.CONSUMER,
166
- attributes: { "activitypub.activity.type": message.activityType },
166
+ attributes: {
167
+ "activitypub.activity.type": message.activityType,
168
+ "activitypub.activity.retries": message.attempt,
169
+ },
167
170
  }, extractedContext, async (span) => {
168
171
  if (message.activityId != null) {
169
172
  span.setAttribute("activitypub.activity.id", message.activityId);
170
173
  }
171
174
  try {
172
- await this.#listenOutboxMessage(ctxData, message);
175
+ await this.#listenOutboxMessage(ctxData, message, span);
173
176
  }
174
177
  catch (e) {
175
178
  span.setStatus({
@@ -184,11 +187,30 @@ export class FederationImpl {
184
187
  });
185
188
  }
186
189
  else if (message.type === "inbox") {
187
- await this.#listenInboxMessage(ctxData, message);
190
+ await tracer.startActiveSpan("activitypub.inbox", {
191
+ kind: SpanKind.CONSUMER,
192
+ attributes: {
193
+ "activitypub.shared_inbox": message.identifier == null,
194
+ },
195
+ }, extractedContext, async (span) => {
196
+ try {
197
+ await this.#listenInboxMessage(ctxData, message, span);
198
+ }
199
+ catch (e) {
200
+ span.setStatus({
201
+ code: SpanStatusCode.ERROR,
202
+ message: String(e),
203
+ });
204
+ throw e;
205
+ }
206
+ finally {
207
+ span.end();
208
+ }
209
+ });
188
210
  }
189
211
  });
190
212
  }
191
- async #listenOutboxMessage(_, message) {
213
+ async #listenOutboxMessage(_, message, span) {
192
214
  const logger = getLogger(["fedify", "federation", "outbox"]);
193
215
  const logData = {
194
216
  keyIds: message.keys.map((pair) => pair.keyId),
@@ -224,6 +246,7 @@ export class FederationImpl {
224
246
  });
225
247
  }
226
248
  catch (error) {
249
+ span.setStatus({ code: SpanStatusCode.ERROR, message: String(error) });
227
250
  const activity = await Activity.fromJsonLd(message.activity, {
228
251
  contextLoader: this.contextLoader,
229
252
  documentLoader: rsaKeyPair == null
@@ -261,7 +284,7 @@ export class FederationImpl {
261
284
  }
262
285
  logger.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
263
286
  }
264
- async #listenInboxMessage(ctxData, message) {
287
+ async #listenInboxMessage(ctxData, message, span) {
265
288
  const logger = getLogger(["fedify", "federation", "inbox"]);
266
289
  const baseUrl = new URL(message.baseUrl);
267
290
  let context = this.#createContext(baseUrl, ctxData);
@@ -284,6 +307,10 @@ export class FederationImpl {
284
307
  }
285
308
  }
286
309
  const activity = await Activity.fromJsonLd(message.activity, context);
310
+ span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
311
+ if (activity.id != null) {
312
+ span.setAttribute("activitypub.activity.id", activity.id.href);
313
+ }
287
314
  const cacheKey = activity.id == null ? null : [
288
315
  ...this.kvPrefixes.activityIdempotence,
289
316
  activity.id.href,
@@ -299,74 +326,89 @@ export class FederationImpl {
299
326
  return;
300
327
  }
301
328
  }
302
- const listener = this.inboxListeners?.dispatch(activity);
303
- if (listener == null) {
304
- logger.error("Unsupported activity type:\n{activity}", {
305
- activityId: activity.id?.href,
306
- activity: message.activity,
307
- recipient: message.identifier,
308
- trial: message.attempt,
309
- });
310
- return;
311
- }
312
- try {
313
- await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, getTypeId(activity).href), activity);
314
- }
315
- catch (error) {
316
- try {
317
- await this.inboxErrorHandler?.(context, error);
318
- }
319
- catch (error) {
320
- logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
321
- error,
322
- trial: message.attempt,
329
+ await this.#getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
330
+ const dispatched = this.inboxListeners?.dispatchWithClass(activity);
331
+ if (dispatched == null) {
332
+ logger.error("Unsupported activity type:\n{activity}", {
323
333
  activityId: activity.id?.href,
324
334
  activity: message.activity,
325
335
  recipient: message.identifier,
336
+ trial: message.attempt,
337
+ });
338
+ span.setStatus({
339
+ code: SpanStatusCode.ERROR,
340
+ message: `Unsupported activity type: ${getTypeId(activity).href}`,
326
341
  });
342
+ span.end();
343
+ return;
327
344
  }
328
- const delay = this.inboxRetryPolicy({
329
- elapsedTime: dntShim.Temporal.Instant.from(message.started).until(dntShim.Temporal.Now.instant()),
330
- attempts: message.attempt,
331
- });
332
- if (delay != null) {
333
- logger.error("Failed to process the incoming activity {activityId} (attempt " +
334
- "#{attempt}); retry...:\n{error}", {
335
- error,
336
- attempt: message.attempt,
337
- activityId: activity.id?.href,
338
- activity: message.activity,
339
- recipient: message.identifier,
345
+ const { class: cls, listener } = dispatched;
346
+ span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
347
+ try {
348
+ await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, getTypeId(activity).href), activity);
349
+ }
350
+ catch (error) {
351
+ try {
352
+ await this.inboxErrorHandler?.(context, error);
353
+ }
354
+ catch (error) {
355
+ logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
356
+ error,
357
+ trial: message.attempt,
358
+ activityId: activity.id?.href,
359
+ activity: message.activity,
360
+ recipient: message.identifier,
361
+ });
362
+ }
363
+ const delay = this.inboxRetryPolicy({
364
+ elapsedTime: dntShim.Temporal.Instant.from(message.started).until(dntShim.Temporal.Now.instant()),
365
+ attempts: message.attempt,
340
366
  });
341
- await this.inboxQueue?.enqueue({
342
- ...message,
343
- attempt: message.attempt + 1,
344
- }, {
345
- delay: dntShim.Temporal.Duration.compare(delay, { seconds: 0 }) < 0
346
- ? dntShim.Temporal.Duration.from({ seconds: 0 })
347
- : delay,
367
+ if (delay != null) {
368
+ logger.error("Failed to process the incoming activity {activityId} (attempt " +
369
+ "#{attempt}); retry...:\n{error}", {
370
+ error,
371
+ attempt: message.attempt,
372
+ activityId: activity.id?.href,
373
+ activity: message.activity,
374
+ recipient: message.identifier,
375
+ });
376
+ await this.inboxQueue?.enqueue({
377
+ ...message,
378
+ attempt: message.attempt + 1,
379
+ }, {
380
+ delay: dntShim.Temporal.Duration.compare(delay, { seconds: 0 }) < 0
381
+ ? dntShim.Temporal.Duration.from({ seconds: 0 })
382
+ : delay,
383
+ });
384
+ }
385
+ else {
386
+ logger.error("Failed to process the incoming activity {activityId} after " +
387
+ "{trial} attempts; giving up:\n{error}", {
388
+ error,
389
+ activityId: activity.id?.href,
390
+ activity: message.activity,
391
+ recipient: message.identifier,
392
+ });
393
+ }
394
+ span.setStatus({
395
+ code: SpanStatusCode.ERROR,
396
+ message: String(error),
348
397
  });
398
+ span.end();
399
+ return;
349
400
  }
350
- else {
351
- logger.error("Failed to process the incoming activity {activityId} after " +
352
- "{trial} attempts; giving up:\n{error}", {
353
- error,
354
- activityId: activity.id?.href,
355
- activity: message.activity,
356
- recipient: message.identifier,
401
+ if (cacheKey != null) {
402
+ await this.kv.set(cacheKey, true, {
403
+ ttl: dntShim.Temporal.Duration.from({ days: 1 }),
357
404
  });
358
405
  }
359
- return;
360
- }
361
- if (cacheKey != null) {
362
- await this.kv.set(cacheKey, true, {
363
- ttl: dntShim.Temporal.Duration.from({ days: 1 }),
406
+ logger.info("Activity {activityId} has been processed.", {
407
+ activityId: activity.id?.href,
408
+ activity: message.activity,
409
+ recipient: message.identifier,
364
410
  });
365
- }
366
- logger.info("Activity {activityId} has been processed.", {
367
- activityId: activity.id?.href,
368
- activity: message.activity,
369
- recipient: message.identifier,
411
+ span.end();
370
412
  });
371
413
  }
372
414
  startQueue(contextData, options = {}) {
package/esm/sig/http.js CHANGED
@@ -236,7 +236,6 @@ async function verifyRequestInternal(request, span, { documentLoader, contextLoa
236
236
  }
237
237
  const { keyId, headers, signature } = sigValues;
238
238
  span?.setAttribute("http_signatures.key_id", keyId);
239
- span?.setAttribute("http_signatures.signature", signature);
240
239
  if ("algorithm" in sigValues) {
241
240
  span?.setAttribute("http_signatures.algorithm", sigValues.algorithm);
242
241
  }
@@ -266,6 +265,7 @@ async function verifyRequestInternal(request, span, { documentLoader, contextLoa
266
265
  ? request.headers.get("host") ?? new URL(request.url).host
267
266
  : request.headers.get(name))).join("\n");
268
267
  const sig = decodeBase64(signature);
268
+ span?.setAttribute("http_signatures.signature", encodeHex(sig));
269
269
  // TODO: support other than RSASSA-PKCS1-v1_5:
270
270
  const verified = await dntShim.crypto.subtle.verify("RSASSA-PKCS1-v1_5", key.publicKey, sig, new TextEncoder().encode(message));
271
271
  if (!verified) {