@fedify/fedify
Version:
An ActivityPub server framework
1,197 lines (1,196 loc) • 120 kB
TypeScript
/// <reference lib="esnext.temporal" />
import { o as JsonValue, s as NodeInfo, t as GetNodeInfoOptions } from "./client-CSddvgWN.js";
import { o as VerifyRequestFailureReason, t as HttpMessageSignaturesSpec } from "./http-BDZeS5om.js";
import { n as GetKeyOwnerOptions } from "./owner-CnngXDNJ.js";
import { n as KvStore, t as KvKey } from "./kv-D6hNiMTK.js";
import { Activity, Actor, Collection, CryptographicKey, Hashtag, Link, LookupObjectOptions, Multikey, Object as Object$1, Recipient, Tombstone, TraverseCollectionOptions } from "@fedify/vocab";
import { Span, Tracer, TracerProvider } from "@opentelemetry/api";
import { AuthenticatedDocumentLoaderFactory, DocumentLoader, DocumentLoaderFactory, GetUserAgentOptions } from "@fedify/vocab-runtime";
import { Link as Link$1, LookupWebFingerOptions, ResourceDescriptor } from "@fedify/webfinger";
//#region src/compat/types.d.ts
/**
* A function that transforms an activity object.
* @since 1.4.0
*/
type ActivityTransformer<TContextData> = (activity: Activity, context: Context<TContextData>) => Activity;
//#endregion
//#region src/federation/collection.d.ts
/**
* A page of items.
*/
interface PageItems<TItem> {
readonly prevCursor?: string | null;
readonly nextCursor?: string | null;
readonly items: readonly TItem[];
}
/**
* Calculates the [partial follower collection digest][1].
*
* [1]: https://w3id.org/fep/8fcf#partial-follower-collection-digest
* @param uris The URIs to calculate the digest. Duplicate URIs are ignored.
* @returns The digest.
*/
declare function digest(uris: Iterable<string | URL>): Promise<Uint8Array>;
/**
* Builds [`Collection-Synchronization`][1] header content.
*
* [1]: https://w3id.org/fep/8fcf#the-collection-synchronization-http-header
*
* @param collectionId The sender's followers collection URI.
* @param actorIds The actor URIs to digest.
* @returns The header content.
*/
declare function buildCollectionSynchronizationHeader(collectionId: string | URL, actorIds: Iterable<string | URL>): Promise<string>;
//#endregion
//#region src/federation/send.d.ts
/**
* A key pair for an actor who sends an activity.
* @since 0.10.0
*/
interface SenderKeyPair {
/**
* The actor's private key to sign the request.
*/
readonly privateKey: CryptoKey;
/**
* The public key ID that corresponds to the private key.
*/
readonly keyId: URL;
}
/**
* An error that is thrown when an activity fails to send to a remote inbox.
* It contains structured information about the failure, including the HTTP
* status code, the inbox URL, and the response body.
* @since 2.0.0
*/
declare class SendActivityError extends Error {
/**
* The inbox URL that the activity was being sent to.
*/
readonly inbox: URL;
/**
* The HTTP status code returned by the inbox.
*/
readonly statusCode: number;
/**
* The response body from the inbox, if any. Note that this may be
* truncated to a maximum of 1 KiB to prevent excessive memory consumption
* when remote servers return large error pages (e.g., Cloudflare error pages).
* If truncated, the string will end with `"… (truncated)"`.
*/
readonly responseBody: string;
/**
* Creates a new {@link SendActivityError}.
* @param inbox The inbox URL.
* @param statusCode The HTTP status code.
* @param message The error message.
* @param responseBody The response body.
*/
constructor(inbox: URL, statusCode: number, message: string, responseBody: string);
}
//#endregion
//#region src/federation/callback.d.ts
/**
* A callback that dispatches a {@link NodeInfo} object.
*
* @template TContextData The context data to pass to the {@link Context}.
*/
type NodeInfoDispatcher<TContextData> = (context: RequestContext<TContextData>) => NodeInfo | Promise<NodeInfo>;
/**
* A callback that dispatches a array of {@link Link}.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param resource The URL queried via WebFinger.
* @returns Links related to the queried resource.
*/
type WebFingerLinksDispatcher<TContextData> = (context: RequestContext<TContextData>, resource: URL) => readonly Link$1[] | Promise<readonly Link$1[]>;
/**
* A callback that dispatches an {@link Actor} object or a {@link Tombstone}.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param context The request context.
* @param identifier The actor's internal identifier or username.
*/
type ActorDispatcher<TContextData> = (context: RequestContext<TContextData>, identifier: string) => Actor | Tombstone | null | Promise<Actor | Tombstone | null>;
/**
* A callback that dispatches key pairs for an actor.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param context The context.
* @param identifier The actor's internal identifier or username.
* @returns The key pairs.
* @since 0.10.0
*/
type ActorKeyPairsDispatcher<TContextData> = (context: Context<TContextData>, identifier: string) => CryptoKeyPair[] | Promise<CryptoKeyPair[]>;
/**
* A callback that maps a WebFinger username to the corresponding actor's
* internal identifier, or `null` if the username is not found.
* @template TContextData The context data to pass to the {@link Context}.
* @param context The context.
* @param username The WebFinger username.
* @returns The actor's internal identifier, or `null` if the username is not
* found.
* @since 0.15.0
*/
type ActorHandleMapper<TContextData> = (context: Context<TContextData>, username: string) => string | null | Promise<string | null>;
/**
* A callback that maps a WebFinger query to the corresponding actor's
* internal identifier or username, or `null` if the query is not found.
* @template TContextData The context data to pass to the {@link Context}.
* @param context The request context.
* @param resource The URL that was queried through WebFinger.
* @returns The actor's internal identifier or username, or `null` if the query
* is not found.
* @since 1.4.0
*/
type ActorAliasMapper<TContextData> = (context: RequestContext<TContextData>, resource: URL) => {
identifier: string;
} | {
username: string;
} | null | Promise<{
identifier: string;
} | {
username: string;
} | null>;
/**
* A callback that dispatches an object.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TObject The type of object to dispatch.
* @template TParam The parameter names of the requested URL.
* @since 0.7.0
*/
type ObjectDispatcher<TContextData, TObject extends Object$1, TParam extends string> = (context: RequestContext<TContextData>, values: Record<TParam, string>) => TObject | null | Promise<TObject | null>;
/**
* A callback that dispatches a collection.
*
* @template TItem The type of items in the collection.
* @template TContext The type of the context. {@link Context} or
* {@link RequestContext}.
* @template TContextData The context data to pass to the `TContext`.
* @template TFilter The type of the filter, if any.
* @param context The context.
* @param identifier The internal identifier or the username of the collection
* owner.
* @param cursor The cursor to start the collection from, or `null` to dispatch
* the entire collection without pagination.
* @param filter The filter to apply to the collection, if any.
*/
type CollectionDispatcher<TItem, TContext extends Context<TContextData>, TContextData, TFilter> = (context: TContext, identifier: string, cursor: string | null, filter?: TFilter) => PageItems<TItem> | null | Promise<PageItems<TItem> | null>;
/**
* A callback that counts the number of items in a collection.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param context The context.
* @param identifier The internal identifier or the username of the collection
* owner.
* @param filter The filter to apply to the collection, if any.
*/
type CollectionCounter<TContextData, TFilter> = (context: RequestContext<TContextData>, identifier: string, filter?: TFilter) => number | bigint | null | Promise<number | bigint | null>;
/**
* A callback that returns a cursor for a collection.
*
* @template TContext The type of the context. {@link Context} or
* {@link RequestContext}.
* @template TContextData The context data to pass to the {@link Context}.
* @template TFilter The type of the filter, if any.
* @param context The context.
* @param identifier The internal identifier or the username of the collection
* owner.
* @param filter The filter to apply to the collection, if any.
*/
type CollectionCursor<TContext extends Context<TContextData>, TContextData, TFilter> = (context: TContext, identifier: string, filter?: TFilter) => string | null | Promise<string | null>;
/**
* A callback that listens for activities in an inbox.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TActivity The type of activity to listen for.
* @param context The inbox context.
* @param activity The activity that was received.
*/
type InboxListener<TContextData, TActivity extends Activity> = (context: InboxContext<TContextData>, activity: TActivity) => void | Promise<void>;
/**
* A callback that listens for activities in an outbox.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TActivity The type of activity to listen for.
* @param context The outbox context.
* @param activity The activity that was received.
* @since 2.2.0
*/
type OutboxListener<TContextData, TActivity extends Activity> = (context: OutboxContext<TContextData>, activity: TActivity) => void | Promise<void>;
/**
* The reason why an incoming activity could not be verified.
*
* Unlike inbox listeners registered through {@link InboxListenerSetters.on},
* unverified activity handlers are called only when the activity payload could
* be parsed but its HTTP signatures could not be verified.
*
* @since 2.1.0
*/
type UnverifiedActivityReason = VerifyRequestFailureReason;
/**
* A callback that handles activities whose signatures could not be verified.
*
* Returning a {@link Response} overrides Fedify's default `401 Unauthorized`
* response. Returning `void` keeps the default behavior.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param context The request context.
* @param activity The incoming activity that could be parsed.
* @param reason The reason why signature verification failed.
* @since 2.1.0
*/
type UnverifiedActivityHandler<TContextData> = (context: RequestContext<TContextData>, activity: Activity, reason: UnverifiedActivityReason) => void | Response | Promise<void | Response>;
/**
* A callback that handles errors in an inbox.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param context The inbox context.
*/
type InboxErrorHandler<TContextData> = (context: Context<TContextData>, error: Error) => void | Promise<void>;
/**
* A callback that handles errors in an outbox listener.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param context The outbox context.
* @param error The error that occurred.
* @since 2.2.0
*/
type OutboxListenerErrorHandler<TContextData> = (context: OutboxContext<TContextData>, error: Error) => void | Promise<void>;
/**
* A callback that dispatches the key pair for the authenticated document loader
* of the {@link Context} passed to the shared inbox listener.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param context The context.
* @returns The username or the internal identifier of the actor or the key pair
* for the authenticated document loader of the {@link Context} passed
* to the shared inbox listener. If `null` is returned, the request is
* not authorized.
* @since 0.11.0
*/
type SharedInboxKeyDispatcher<TContextData> = (context: Context<TContextData>) => SenderKeyPair | {
identifier: string;
} | {
username: string;
} | null | Promise<SenderKeyPair | {
identifier: string;
} | {
username: string;
} | null>;
/**
* A callback that handles errors during outbox processing.
*
* @param error The error that occurred.
* @param activity The activity that caused the error. If it is `null`, the
* error occurred during deserializing the activity.
* @since 0.6.0
*/
type OutboxErrorHandler = (error: Error, activity: Activity | null) => void | Promise<void>;
/**
* A callback that handles permanent delivery failures when sending activities
* to remote inboxes.
*
* This handler is called when an inbox returns an HTTP status code that
* indicates permanent failure (such as `410 Gone` or `404 Not Found`),
* allowing the application to clean up followers that are no longer reachable.
*
* Unlike {@link OutboxErrorHandler}, which is called for every delivery failure
* (including retries), this handler is called only once for permanent failures,
* after which delivery is not retried.
*
* If any errors are thrown in this callback, they are caught, logged,
* and ignored.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param context The context.
* @param values The delivery failure information.
* @since 2.0.0
*/
type OutboxPermanentFailureHandler<TContextData> = (context: Context<TContextData>, values: {
/** The inbox URL that failed. */readonly inbox: URL; /** The activity that failed to deliver. */
readonly activity: Activity; /** The error that occurred. */
readonly error: SendActivityError; /** The HTTP status code returned by the inbox. */
readonly statusCode: number;
/**
* The actor IDs that were supposed to receive the activity at this inbox.
*/
readonly actorIds: readonly URL[];
}) => void | Promise<void>;
/**
* A callback that determines if a request is authorized or not.
*
* @template TContextData The context data to pass to the {@link Context}.
* @param context The request context.
* @param identifier The internal identifier of the actor that is being
* requested.
* @returns `true` if the request is authorized, `false` otherwise.
* @since 0.7.0
*/
type AuthorizePredicate<TContextData> = (context: RequestContext<TContextData>, identifier: string) => boolean | Promise<boolean>;
/**
* A callback that determines if a request is authorized or not.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TParam The parameter names of the requested URL.
* @param context The request context.
* @param values The parameters of the requested URL.
* @returns `true` if the request is authorized, `false` otherwise.
* @since 0.7.0
*/
type ObjectAuthorizePredicate<TContextData, TParam extends string> = (context: RequestContext<TContextData>, values: Record<TParam, string>) => boolean | Promise<boolean>;
/**
* A callback that dispatches a custom collection.
*
* @template TItem The type of items in the collection.
* @template TParams The parameter names of the requested URL.
* @template TContext The type of the context. {@link Context} or
* {@link RequestContext}.
* @template TContextData The context data to pass to the `TContext`.
* @template TFilter The type of the filter, if any.
* @param context The context.
* @param values The parameters of the requested URL.
* @param cursor The cursor to start the collection from, or `null` to dispatch
* the entire collection without pagination.
* @since 1.8.0
*/
type CustomCollectionDispatcher<TItem, TParam extends string, TContext extends Context<TContextData>, TContextData> = (context: TContext, values: Record<TParam, string>, cursor: string | null) => PageItems<TItem> | null | Promise<PageItems<TItem> | null>;
/**
* A callback that counts the number of items in a custom collection.
*
* @template TParams The parameter names of the requested URL.
* @template TContextData The context data to pass to the {@link Context}.
* @param context The context.
* @param values The parameters of the requested URL.
* @since 1.8.0
*/
type CustomCollectionCounter<TParam extends string, TContextData> = (context: RequestContext<TContextData>, values: Record<TParam, string>) => number | bigint | null | Promise<number | bigint | null>;
/**
* A callback that returns a cursor for a custom collection.
*
* @template TParams The parameter names of the requested URL.
* @template TContext The type of the context. {@link Context} or
* {@link RequestContext}.
* @template TContextData The context data to pass to the {@link Context}.
* @template TFilter The type of the filter, if any.
* @param context The context.
* @param values The parameters of the requested URL.
* @since 1.8.0
*/
type CustomCollectionCursor<TParam extends string, TContext extends Context<TContextData>, TContextData> = (context: TContext, values: Record<TParam, string>) => string | null | Promise<string | null>;
//#endregion
//#region src/federation/mq.d.ts
/**
* Additional options for enqueuing a message in a queue.
*
* @since 0.5.0
*/
interface MessageQueueEnqueueOptions {
/**
* The delay before the message is enqueued. No delay by default.
*
* It must not be negative.
*/
readonly delay?: Temporal.Duration;
/**
* An optional key that ensures messages with the same ordering key are
* processed sequentially (one at a time). Messages with different ordering
* keys (or no ordering key) may be processed in parallel.
*
* This is useful for ensuring that related messages are processed in order,
* such as ensuring that a `Delete` activity is processed after a `Create`
* activity for the same object.
*
* @since 2.0.0
*/
readonly orderingKey?: string;
}
/**
* Additional options for listening to a message queue.
*
* @since 1.0.0
*/
interface MessageQueueListenOptions {
/**
* The signal to abort listening to the message queue.
*/
signal?: AbortSignal;
}
/**
* An abstract interface for a message queue.
*
* @since 0.5.0
*/
interface MessageQueue {
/**
* Whether the message queue backend provides native retry mechanisms.
* When `true`, Fedify will skip its own retry logic and rely on the backend
* to handle retries. When `false` or omitted, Fedify will handle retries
* using its own retry policies.
*
* @default `false`
* @since 1.7.0
*/
readonly nativeRetrial?: boolean;
/**
* Enqueues a message in the queue.
* @param message The message to enqueue.
* @param options Additional options for enqueuing the message.
*/
enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
/**
* Enqueues multiple messages in the queue. This operation is optional,
* and may not be supported by all implementations. If not supported,
* Fedify will invoke {@link enqueue} for each message.
*
* @param messages The messages to enqueue.
* @param options Additional options for enqueuing the messages.
*/
enqueueMany?: (messages: readonly any[], options?: MessageQueueEnqueueOptions) => Promise<void>;
/**
* Listens for messages in the queue.
* @param handler The handler for messages in the queue.
* @param options Additional options for listening to the message queue.
* @returns A promise that resolves when the listening is done. It never
* rejects, and is resolved when the signal is aborted. If no
* signal is provided, it never resolves.
*/
listen(handler: (message: any) => Promise<void> | void, options?: MessageQueueListenOptions): Promise<void>;
}
/**
* Additional options for {@link InProcessMessageQueue}.
* @since 1.0.0
*/
interface InProcessMessageQueueOptions {
/**
* The interval to poll for messages in the queue. 5 seconds by default.
* @default `{ seconds: 5 }`
*/
pollInterval?: Temporal.Duration | Temporal.DurationLike;
}
/**
* A message queue that processes messages in the same process.
* Do not use this in production as it does neither persist messages nor
* distribute them across multiple processes.
*
* @since 0.5.0
*/
declare class InProcessMessageQueue implements MessageQueue {
#private;
/**
* In-process message queue does not provide native retry mechanisms.
* @since 1.7.0
*/
readonly nativeRetrial = false;
/**
* Constructs a new {@link InProcessMessageQueue} with the given options.
* @param options Additional options for the in-process message queue.
*/
constructor(options?: InProcessMessageQueueOptions);
enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
enqueueMany(messages: readonly any[], options?: MessageQueueEnqueueOptions): Promise<void>;
listen(handler: (message: any) => Promise<void> | void, options?: MessageQueueListenOptions): Promise<void>;
}
/**
* A message queue that processes messages in parallel. It takes another
* {@link MessageQueue}, and processes messages in parallel up to a certain
* number of workers.
*
* Actually, it's rather a decorator than a queue itself.
*
* Note that the workers do not run in truly parallel, in the sense that they
* are not running in separate threads or processes. They are running in the
* same process, but are scheduled to run in parallel. Hence, this is useful
* for I/O-bound tasks, but not for CPU-bound tasks, which is okay for Fedify's
* workloads.
*
* When using `ParallelMessageQueue`, the ordering guarantee is preserved
* *only if* the underlying queue implementation delivers messages in a wrapper
* format that includes the `__fedify_ordering_key__` property. Currently,
* only `DenoKvMessageQueue` and `WorkersMessageQueue` use this format.
* For other queue implementations (e.g., `InProcessMessageQueue`,
* `RedisMessageQueue`, `PostgresMessageQueue`, `SqliteMessageQueue`,
* `AmqpMessageQueue`), the ordering key cannot be detected by
* `ParallelMessageQueue`, so ordering guarantees are handled by those
* implementations directly rather than at the `ParallelMessageQueue` level.
*
* Messages with the same ordering key will never be processed concurrently
* by different workers, ensuring sequential processing within each key.
* Messages with different ordering keys (or no ordering key) can still be
* processed in parallel.
*
* @since 1.0.0
*/
declare class ParallelMessageQueue implements MessageQueue {
#private;
readonly queue: MessageQueue;
readonly workers: number;
/**
* Inherits the native retry capability from the wrapped queue.
* @since 1.7.0
*/
readonly nativeRetrial?: boolean;
/**
* Constructs a new {@link ParallelMessageQueue} with the given queue and
* number of workers.
* @param queue The message queue to use under the hood. Note that
* {@link ParallelMessageQueue} cannot be nested.
* @param workers The number of workers to process messages in parallel.
* @throws {TypeError} If the given queue is an instance of
* {@link ParallelMessageQueue}.
*/
constructor(queue: MessageQueue, workers: number);
enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
enqueueMany(messages: readonly any[], options?: MessageQueueEnqueueOptions): Promise<void>;
listen(handler: (message: any) => Promise<void> | void, options?: MessageQueueListenOptions): Promise<void>;
}
//#endregion
//#region src/federation/handler.d.ts
/**
* Options for the {@link respondWithObject} and
* {@link respondWithObjectIfAcceptable} functions.
* @since 0.3.0
*/
interface RespondWithObjectOptions {
/**
* The document loader to use for compacting JSON-LD.
* @since 0.8.0
*/
contextLoader: DocumentLoader;
}
/**
* Responds with the given object in JSON-LD format.
*
* @param object The object to respond with.
* @param options Options.
* @since 0.3.0
*/
declare function respondWithObject(object: Object$1, options?: RespondWithObjectOptions): Promise<Response>;
/**
* Responds with the given object in JSON-LD format if the request accepts
* JSON-LD.
*
* @param object The object to respond with.
* @param request The request to check for JSON-LD acceptability.
* @param options Options.
* @since 0.3.0
*/
declare function respondWithObjectIfAcceptable(object: Object$1, request: Request, options?: RespondWithObjectOptions): Promise<Response | null>;
//#endregion
//#region src/federation/router.d.ts
/**
* Options for the {@link Router}.
* @since 0.12.0
*/
interface RouterOptions {
/**
* Whether to ignore trailing slashes when matching paths.
*/
trailingSlashInsensitive?: boolean;
}
/**
* The result of {@link Router.route} method.
* @since 1.3.0
*/
interface RouterRouteResult {
/**
* The matched route name.
*/
name: string;
/**
* The URL template of the matched route.
*/
template: string;
/**
* The values extracted from the URL.
*/
values: Record<string, string>;
}
/**
* URL router and constructor based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)).
*/
declare class Router {
#private;
/**
* Whether to ignore trailing slashes when matching paths.
* @since 1.6.0
*/
trailingSlashInsensitive: boolean;
/**
* Create a new {@link Router}.
* @param options Options for the router.
*/
constructor(options?: RouterOptions);
clone(): Router;
/**
* Checks if a path name exists in the router.
* @param name The name of the path.
* @returns `true` if the path name exists, otherwise `false`.
*/
has(name: string): boolean;
/**
* Adds a new path rule to the router.
* @param template The path pattern.
* @param name The name of the path.
* @returns The names of the variables in the path pattern.
*/
add(template: string, name: string): Set<string>;
/**
* Resolves a path name and values from a URL, if any match.
* @param url The URL to resolve.
* @returns The name of the path and its values, if any match. Otherwise,
* `null`.
*/
route(url: string): RouterRouteResult | null;
/**
* Constructs a URL/path from a path name and values.
* @param name The name of the path.
* @param values The values to expand the path with.
* @returns The URL/path, if the name exists. Otherwise, `null`.
*/
build(name: string, values: Record<string, string>): string | null;
}
/**
* An error thrown by the {@link Router}.
*/
declare class RouterError extends Error {
/**
* Create a new {@link RouterError}.
* @param message The error message.
*/
constructor(message: string);
}
//#endregion
//#region src/federation/builder.d.ts
/**
* Creates a new {@link FederationBuilder} instance.
* @returns A new {@link FederationBuilder} instance.
* @since 1.6.0
*/
declare function createFederationBuilder<TContextData>(): FederationBuilder<TContextData>;
//#endregion
//#region src/federation/queue.d.ts
interface SenderKeyJwkPair {
readonly keyId: string;
readonly privateKey: JsonWebKey;
}
/**
* A message that represents a task to be processed by the background worker.
* The concrete type of the message depends on the `type` property.
*
* Please do not depend on the concrete types of the messages, as they may
* change in the future. You should treat the `Message` type as an opaque
* type.
* @since 1.6.0
*/
type Message = FanoutMessage | OutboxMessage | InboxMessage;
interface FanoutMessage {
readonly type: "fanout";
readonly id: ReturnType<typeof crypto.randomUUID>;
readonly baseUrl: string;
readonly keys: readonly SenderKeyJwkPair[];
readonly inboxes: Readonly<Record<string, {
readonly actorIds: readonly string[];
readonly sharedInbox: boolean;
}>>;
readonly activity: unknown;
readonly activityId?: string;
readonly activityType: string;
readonly collectionSync?: string;
readonly orderingKey?: string;
/**
* Whether to apply outgoing JSON-LD wire-format normalization to queued
* activities that already carry Object Integrity Proofs.
*
* `true` is used for proofs Fedify created before fanout, or when callers
* explicitly request normalization for locally pre-signed activities.
* `false`/`undefined` preserves existing proofs as-is.
*/
readonly normalizeExistingProofs?: boolean;
readonly traceContext: Readonly<Record<string, string>>;
}
interface OutboxMessage {
readonly type: "outbox";
readonly id: ReturnType<typeof crypto.randomUUID>;
readonly baseUrl: string;
readonly keys: readonly SenderKeyJwkPair[];
readonly activity: unknown;
readonly activityId?: string;
readonly activityType: string;
readonly inbox: string;
readonly sharedInbox: boolean;
readonly actorIds?: readonly string[];
readonly started: string;
readonly attempt: number;
readonly headers: Readonly<Record<string, string>>;
readonly orderingKey?: string;
readonly traceContext: Readonly<Record<string, string>>;
}
interface InboxMessage {
readonly type: "inbox";
readonly id: ReturnType<typeof crypto.randomUUID>;
readonly baseUrl: string;
readonly activity: unknown;
/**
* The normalized JSON-LD representation of a signed inbox activity that
* Fedify already compacted successfully while accepting the request. Queue
* workers can reuse this producer-side parse cache under stricter loader or
* network constraints without changing the raw payload preserved for
* forwarding.
*
* This may exist even when {@link ldSignatureVerified} is `false`, because
* fallback-authenticated traffic and already-queued backlog items can still
* depend on the cached normalized form to avoid re-fetching remote custom
* contexts during worker processing.
*
* This is optional for backward compatibility with messages that were
* queued by older Fedify versions or that were already in a queue before
* upgrading.
*
* Fedify keeps this on the queued message itself instead of an external
* sidecar because generic queue backends do not provide reliable lifecycle
* guarantees for auxiliary storage across retries and redeliveries.
*
* @internal
*/
readonly normalizedActivity?: unknown;
/**
* Whether the producer actually verified the Linked Data Signature before
* queueing this message. This lets workers distinguish verified LDS replay
* from other authenticated inbox traffic that merely happened to include a
* signature block. This provenance marker is separate from the optional
* normalizedActivity parse cache.
*
* `undefined` preserves backward compatibility with older queued messages
* that predate this marker.
*
* @internal
*/
readonly ldSignatureVerified?: boolean;
readonly started: string;
readonly attempt: number;
readonly identifier: string | null;
readonly traceContext: Readonly<Record<string, string>>;
}
//#endregion
//#region src/federation/retry.d.ts
/**
* The context passed to a {@link RetryPolicy} callback.
* @since 0.12.0
*/
interface RetryContext {
/**
* The elapsed time since the first attempt.
*/
readonly elapsedTime: Temporal.Duration;
/**
* The number of attempts so far.
*/
readonly attempts: number;
}
/**
* A policy that determines the delay before the next retry.
* @param context The retry context.
* @returns The delay before the next retry, or `null` to stop retrying.
* It must not negative.
* @since 0.12.0
*/
type RetryPolicy = (context: RetryContext) => Temporal.Duration | null;
/**
* Options for {@link createExponentialBackoffPolicy} function.
* @since 0.12.0
*/
interface CreateExponentialBackoffPolicyOptions {
/**
* The initial delay before the first retry. Defaults to 1 second.
*/
readonly initialDelay?: Temporal.DurationLike;
/**
* The maximum delay between retries. Defaults to 12 hours.
*/
readonly maxDelay?: Temporal.DurationLike;
/**
* The maximum number of attempts before giving up.
* Defaults to 10.
*/
readonly maxAttempts?: number;
/**
* The factor to multiply the previous delay by for each retry.
* Defaults to 2.
*/
readonly factor?: number;
/**
* Whether to add jitter to the delay to avoid synchronization.
* Turned on by default.
*/
readonly jitter?: boolean;
}
/**
* Creates an exponential backoff retry policy. The delay between retries
* starts at the `initialDelay` and is multiplied by the `factor` for each
* subsequent retry, up to the `maxDelay`. The policy will give up after
* `maxAttempts` attempts. The actual delay is randomized to avoid
* synchronization (jitter).
* @param options The options for the policy.
* @returns The retry policy.
* @since 0.12.0
*/
declare function createExponentialBackoffPolicy(options?: CreateExponentialBackoffPolicyOptions): RetryPolicy;
//#endregion
//#region src/federation/middleware.d.ts
/**
* Configures the task queues for sending and receiving activities.
* @since 1.3.0
*/
interface FederationQueueOptions {
/**
* The message queue for incoming activities. If not provided, incoming
* activities will not be queued and will be processed immediately.
*/
readonly inbox?: MessageQueue;
/**
* The message queue for outgoing activities. If not provided, outgoing
* activities will not be queued and will be sent immediately.
*/
readonly outbox?: MessageQueue;
/**
* The message queue for fanning out outgoing activities. If not provided,
* outgoing activities will not be fanned out in the background, but will be
* fanned out immediately, which causes slow response times on
* {@link Context.sendActivity} calls.
*/
readonly fanout?: MessageQueue;
}
/**
* Prefixes for namespacing keys in the Deno KV store.
*/
interface FederationKvPrefixes {
/**
* The key prefix used for storing whether activities have already been
* processed or not.
* @default `["_fedify", "activityIdempotence"]`
*/
readonly activityIdempotence: KvKey;
/**
* The key prefix used for storing remote JSON-LD documents.
* @default `["_fedify", "remoteDocument"]`
*/
readonly remoteDocument: KvKey;
/**
* The key prefix used for caching public keys.
* @default `["_fedify", "publicKey"]`
* @since 0.12.0
*/
readonly publicKey: KvKey;
/**
* The key prefix used for caching HTTP Message Signatures specs.
* The cached spec is used to reduce the number of requests to make signed
* requests ("double-knocking" technique).
* @default `["_fedify", "httpMessageSignaturesSpec"]`
* @since 1.6.0
*/
readonly httpMessageSignaturesSpec: KvKey;
/**
* The key prefix used for storing `Accept-Signature` challenge nonces.
* Only used when {@link InboxChallengePolicy.requestNonce} is `true`.
* @default `["_fedify", "acceptSignatureNonce"]`
* @since 2.1.0
*/
readonly acceptSignatureNonce: KvKey;
}
/**
* Options for {@link FederationOptions.origin} when it is not a string.
* @since 1.5.0
*/
interface FederationOrigin {
/**
* The canonical hostname for fediverse handles (which are looked up through
* WebFinger). This is used for WebFinger lookups. It has to be a valid
* hostname, e.g., `"example.com"`.
*/
handleHost: string;
/**
* The canonical origin for web URLs. This is used for constructing absolute
* URLs. It has to start with either `"http://"` or `"https://"`, and must
* not contain a path or query string, e.g., `"https://example.com"`.
*/
webOrigin: string;
}
/**
* Create a new {@link Federation} instance.
* @param parameters Parameters for initializing the instance.
* @returns A new {@link Federation} instance.
* @since 0.10.0
*/
declare function createFederation<TContextData>(options: FederationOptions<TContextData>): Federation<TContextData>;
//#endregion
//#region src/federation/federation.d.ts
/**
* Options for {@link Federation.startQueue} method.
* @since 1.0.0
*/
interface FederationStartQueueOptions {
/**
* The signal to abort the task queue.
*/
signal?: AbortSignal;
/**
* Starts the task worker only for the specified queue. If unspecified,
* which is the default, the task worker starts for all three queues:
* inbox, outbox, and fanout.
* @since 1.3.0
*/
queue?: "inbox" | "outbox" | "fanout";
}
/**
* A common interface between {@link Federation} and {@link FederationBuilder}.
* @template TContextData The context data to pass to the {@link Context}.
* @since 1.6.0
*/
interface Federatable<TContextData> {
/**
* Registers a NodeInfo dispatcher.
* @param path The URI path pattern for the NodeInfo dispatcher. The syntax
* is based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have no variables.
* @param dispatcher A NodeInfo dispatcher callback to register.
* @throws {RouterError} Thrown if the path pattern is invalid.
*/
setNodeInfoDispatcher(path: string, dispatcher: NodeInfoDispatcher<TContextData>): void;
/**
* Registers a links dispatcher to WebFinger
* @param dispatcher A links dispatcher callback to register.
*/
setWebFingerLinksDispatcher(dispatcher: WebFingerLinksDispatcher<TContextData>): void;
/**
* Registers an actor dispatcher.
*
* @example
* ``` typescript
* federation.setActorDispatcher(
* "/users/{identifier}",
* async (ctx, identifier) => {
* return new Person({
* id: ctx.getActorUri(identifier),
* // ...
* });
* }
* );
* ```
*
* @param path The URI path pattern for the actor dispatcher. The syntax is
* based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one variable: `{identifier}`.
* @param dispatcher An actor dispatcher callback to register. It may return
* an actor, a `Tombstone`, or `null` if the actor is not
* found.
* @returns An object with methods to set other actor dispatcher callbacks.
* @throws {RouterError} Thrown if the path pattern is invalid.
*/
setActorDispatcher(path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: ActorDispatcher<TContextData>): ActorCallbackSetters<TContextData>;
/**
* Registers an object dispatcher.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TObject The type of object to dispatch.
* @template TParam The parameter names of the requested URL.
* @param cls The Activity Vocabulary class of the object to dispatch.
* @param path The URI path pattern for the object dispatcher. The syntax is
* based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one or more variables.
* @param dispatcher An object dispatcher callback to register.
*/
setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
/**
* Registers an object dispatcher.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TObject The type of object to dispatch.
* @template TParam The parameter names of the requested URL.
* @param cls The Activity Vocabulary class of the object to dispatch.
* @param path The URI path pattern for the object dispatcher. The syntax is
* based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one or more variables.
* @param dispatcher An object dispatcher callback to register.
*/
setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
/**
* Registers an object dispatcher.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TObject The type of object to dispatch.
* @template TParam The parameter names of the requested URL.
* @param cls The Activity Vocabulary class of the object to dispatch.
* @param path The URI path pattern for the object dispatcher. The syntax is
* based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one or more variables.
* @param dispatcher An object dispatcher callback to register.
*/
setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
/**
* Registers an object dispatcher.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TObject The type of object to dispatch.
* @template TParam The parameter names of the requested URL.
* @param cls The Activity Vocabulary class of the object to dispatch.
* @param path The URI path pattern for the object dispatcher. The syntax is
* based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one or more variables.
* @param dispatcher An object dispatcher callback to register.
*/
setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}${Rfc6570Expression<TParam>}${string}${Rfc6570Expression<TParam>}${string}${Rfc6570Expression<TParam>}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
/**
* Registers an object dispatcher.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TObject The type of object to dispatch.
* @template TParam The parameter names of the requested URL.
* @param cls The Activity Vocabulary class of the object to dispatch.
* @param path The URI path pattern for the object dispatcher. The syntax is
* based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one or more variables.
* @param dispatcher An object dispatcher callback to register.
*/
setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}${Rfc6570Expression<TParam>}${string}${Rfc6570Expression<TParam>}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
/**
* Registers an object dispatcher.
*
* @template TContextData The context data to pass to the {@link Context}.
* @template TObject The type of object to dispatch.
* @template TParam The parameter names of the requested URL.
* @param cls The Activity Vocabulary class of the object to dispatch.
* @param path The URI path pattern for the object dispatcher. The syntax is
* based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one or more variables.
* @param dispatcher An object dispatcher callback to register.
*/
setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}${Rfc6570Expression<TParam>}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
/**
* Registers an inbox dispatcher.
*
* @param path The URI path pattern for the inbox dispatcher. The syntax is
* based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one variable: `{identifier}`, and must match
* the inbox listener path.
* @param dispatcher An inbox dispatcher callback to register.
* @throws {@link RouterError} Thrown if the path pattern is invalid.
*/
setInboxDispatcher(path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher<Activity, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
/**
* Registers an outbox dispatcher.
*
* @example
* ``` typescript
* federation.setOutboxDispatcher(
* "/users/{identifier}/outbox",
* async (ctx, identifier, options) => {
* let items: Activity[];
* let nextCursor: string;
* // ...
* return { items, nextCursor };
* }
* );
* ```
*
* @param path The URI path pattern for the outbox dispatcher. The syntax is
* based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one variable: `{identifier}`.
* @param dispatcher An outbox dispatcher callback to register.
* @throws {@link RouterError} Thrown if the path pattern is invalid.
*/
setOutboxDispatcher(path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher<Activity, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
/**
* Assigns the URL path for the outbox and starts setting outbox listeners.
*
* @example
* ``` typescript
* federation
* .setOutboxListeners("/users/{identifier}/outbox")
* .on(Activity, async (ctx, activity) => {
* await ctx.sendActivity({ identifier: ctx.identifier }, "followers", activity);
* })
* .authorize(async (ctx, identifier) => {
* return ctx.request.headers.get("authorization") === `Bearer ${identifier}`;
* });
* ```
*
* @param outboxPath The URI path pattern for the outbox. The syntax is based
* on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The
* path must have one variable: `{identifier}`. If an
* outbox dispatcher is configured, this path must match
* the outbox dispatcher path.
* @returns An object to register outbox listeners.
* @throws {RouterError} Thrown if the path pattern is invalid.
* @since 2.2.0
*/
setOutboxListeners(outboxPath: `${string}${Rfc6570Expression<"identifier">}${string}`): OutboxListenerSetters<TContextData>;
/**
* Registers a following collection dispatcher.
* @param path The URI path pattern for the following collection. The syntax
* is based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one variable: `{identifier}`.
* @param dispatcher A following collection callback to register.
* @returns An object with methods to set other following collection
* callbacks.
* @throws {RouterError} Thrown if the path pattern is invalid.
*/
setFollowingDispatcher(path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher<Actor | URL, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
/**
* Registers a followers collection dispatcher.
* @param path The URI path pattern for the followers collection. The syntax
* is based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one variable: `{identifier}`.
* @param dispatcher A followers collection callback to register.
* @returns An object with methods to set other followers collection
* callbacks.
* @throws {@link RouterError} Thrown if the path pattern is invalid.
*/
setFollowersDispatcher(path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher<Recipient, Context<TContextData>, TContextData, URL>): CollectionCallbackSetters<Context<TContextData>, TContextData, URL>;
/**
* Registers a liked collection dispatcher.
* @param path The URI path pattern for the liked collection. The syntax
* is based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one variable: `{identifier}`.
* @param dispatcher A liked collection callback to register.
* @returns An object with methods to set other liked collection
* callbacks.
* @throws {@link RouterError} Thrown if the path pattern is invalid.
*/
setLikedDispatcher(path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher<Object$1 | URL, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
/**
* Registers a featured collection dispatcher.
* @param path The URI path pattern for the featured collection. The syntax
* is based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one variable: `{identifier}`.
* @param dispatcher A featured collection callback to register.
* @returns An object with methods to set other featured collection
* callbacks.
* @throws {@link RouterError} Thrown if the path pattern is invalid.
*/
setFeaturedDispatcher(path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher<Object$1, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
/**
* Registers a featured tags collection dispatcher.
* @param path The URI path pattern for the featured tags collection.
* The syntax is based on URI Template
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
* must have one variable: `{identifier}`.
* @param dispatcher A featured tags collection callback to register.
* @returns An obje