UNPKG

@fedify/fedify

Version:

An ActivityPub server framework

1,181 lines 122 kB
/// <reference lib="esnext.temporal" /> import { o as JsonValue, s as NodeInfo, t as GetNodeInfoOptions } from "./client-CAM_bQXx.cjs"; import { o as VerifyRequestFailureReason, t as HttpMessageSignaturesSpec } from "./http-VyDTd4G3.cjs"; import { n as GetKeyOwnerOptions } from "./owner-DEvZuyOE.cjs"; import { n as KvStore, t as KvKey } from "./kv-gJ8LYbxX.cjs"; import { r as MessageQueue } from "./mq-D8uSFzxe.cjs"; import { Activity, Actor, Collection, CryptographicKey, Hashtag, Link, LookupObjectOptions, Multikey, Object as Object$1, Recipient, Tombstone, TraverseCollectionOptions } from "@fedify/vocab"; import { AuthenticatedDocumentLoaderFactory, DocumentLoader, DocumentLoaderFactory, GetUserAgentOptions } from "@fedify/vocab-runtime"; import { Link as Link$1, LookupWebFingerOptions, ResourceDescriptor } from "@fedify/webfinger"; import { MeterProvider, Span, Tracer, TracerProvider } from "@opentelemetry/api"; //#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/circuit-breaker.d.ts /** * The state of a remote host circuit breaker. * @since 2.3.0 */ type CircuitBreakerState = "closed" | "open" | "half-open"; /** * The JSON-serializable state stored in the configured {@link KvStore}. * @since 2.3.0 */ interface CircuitBreakerKvState { readonly state: CircuitBreakerState; readonly failures: readonly string[]; readonly opened?: string; readonly halfOpened?: string; } /** * Details passed to {@link CircuitBreakerOptions.onActivityDrop} when a held * activity expires before the remote host recovers. * @since 2.3.0 */ interface CircuitBreakerActivityDrop { /** The inbox URL that would have received the activity. */ readonly inbox: URL; /** The activity that was dropped. */ readonly activity: Activity; /** The activity ID, when known. */ readonly activityId?: string; /** The activity type. */ readonly activityType: string; /** The actor IDs represented by this inbox. */ readonly actorIds: readonly URL[]; /** The time when Fedify first held this activity. */ readonly heldSince: Temporal.Instant; } /** * Configures how a remote host circuit opens after repeated delivery * failures. * @since 2.3.0 */ type CircuitBreakerFailurePolicy = { failure(timestamps: readonly Temporal.Instant[]): boolean; readonly failureThreshold?: never; readonly failureWindow?: never; } | { readonly failure?: never; readonly failureThreshold?: number; readonly failureWindow?: Temporal.Duration | Temporal.DurationLike; }; /** * Options for Fedify's outbound activity circuit breaker. * @since 2.3.0 */ type CircuitBreakerOptions = CircuitBreakerFailurePolicy & { /** * How long an open circuit waits before allowing a half-open recovery probe. * @default `{ minutes: 30 }` */ readonly recoveryDelay?: Temporal.Duration | Temporal.DurationLike; /** * How long Fedify keeps requeueing activities held by an open circuit before * dropping them. * @default `{ days: 7 }` */ readonly heldActivityTtl?: Temporal.Duration | Temporal.DurationLike; /** * How often other held activities retry while a half-open probe is in * flight. The probe is treated as stale after the recovery delay. * @default `{ seconds: 1 }` */ readonly releaseInterval?: Temporal.Duration | Temporal.DurationLike; /** * Called whenever the circuit state changes. */ readonly onStateChange?: (remoteHost: string, previousState: CircuitBreakerState, newState: CircuitBreakerState) => void | Promise<void>; /** * Called when an activity held by the circuit breaker expires. */ readonly onActivityDrop?: (remoteHost: string, details: CircuitBreakerActivityDrop) => void | Promise<void>; }; /** * Normalized circuit breaker options used internally by Fedify. * @internal */ interface NormalizedCircuitBreakerOptions { readonly failure: (timestamps: readonly Temporal.Instant[]) => boolean; readonly pruneFailures: (timestamps: readonly Temporal.Instant[], now: Temporal.Instant) => readonly Temporal.Instant[]; readonly recoveryDelay: Temporal.Duration; readonly heldActivityTtl: Temporal.Duration; readonly releaseInterval: Temporal.Duration; readonly onStateChange?: CircuitBreakerOptions["onStateChange"]; readonly onActivityDrop?: CircuitBreakerOptions["onActivityDrop"]; } /** * Constructor options for {@link CircuitBreaker}. * @internal */ interface CircuitBreakerCreateOptions { readonly kv: KvStore; readonly prefix: KvKey; readonly options?: CircuitBreakerOptions; readonly now?: () => Temporal.Instant; /** * Observes state changes after user callbacks have run. * @internal */ readonly stateChangeObserver?: (remoteHost: string, previousState: CircuitBreakerState, newState: CircuitBreakerState) => void | Promise<void>; } /** * The delivery decision returned by {@link CircuitBreaker.beforeSend}. * @internal */ type CircuitBreakerBeforeSendDecision = { readonly type: "send"; readonly probe: boolean; readonly stateChange?: CircuitBreakerStateChange; } | { readonly type: "hold"; readonly state: "open" | "half-open"; readonly delay: Temporal.Duration; readonly heldSince: Temporal.Instant; } | { readonly type: "drop"; readonly heldSince: Temporal.Instant; }; /** * A circuit breaker state transition. * @since 2.3.0 */ interface CircuitBreakerStateChange { readonly previousState: CircuitBreakerState; readonly newState: CircuitBreakerState; } /** * Tracks reachability state for remote outbox delivery hosts. * @since 2.3.0 */ declare class CircuitBreaker { #private; constructor(options: CircuitBreakerCreateOptions); get options(): NormalizedCircuitBreakerOptions; capHeldDelay(heldSince: Temporal.Instant, delay: Temporal.Duration): Temporal.Duration; beforeSend(remoteHost: string, message: { readonly circuitHeldSince?: string; }): Promise<CircuitBreakerBeforeSendDecision>; recordSuccess(remoteHost: string): Promise<CircuitBreakerStateChange | undefined>; recordReachableFailure(remoteHost: string): Promise<CircuitBreakerStateChange | undefined>; recordFailure(remoteHost: string): Promise<CircuitBreakerStateChange | undefined>; dropActivity(remoteHost: string, details: CircuitBreakerActivityDrop): Promise<void>; getState(remoteHost: string): Promise<CircuitBreakerKvState | undefined>; } /** * Normalizes user-provided circuit breaker options into the internal policy * shape used while processing queued outbox deliveries. * * @param options The public circuit breaker options supplied to Fedify. * @returns The normalized failure predicate, failure pruning function, * duration values, and optional callbacks with defaults applied. * @throws {RangeError} If any configured duration is not positive. * @throws {TypeError} If `failureThreshold` is not a positive integer. */ declare function normalizeCircuitBreakerOptions(options: CircuitBreakerOptions): NormalizedCircuitBreakerOptions; /** * Parses a value loaded from the circuit breaker KV store. * * @param value The raw KV value to validate. * @returns A circuit breaker state when `value` has a recognized state and * valid instant strings, or `undefined` when the stored value is malformed. */ declare function parseCircuitBreakerKvState(value: unknown): CircuitBreakerKvState | undefined; //#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; /** * The response headers from the inbox. * @since 2.3.0 */ readonly responseHeaders: Headers; /** * 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. * @param responseHeaders The response headers. */ constructor(inbox: URL, statusCode: number, message: string, responseBody: string, responseHeaders?: HeadersInit); } //#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: { /** * Why Fedify is giving up on delivery. * * `"http"` means the inbox returned a configured permanent-failure HTTP * status. `"circuit-breaker-ttl"` means the outbound circuit breaker held * the activity until its retention period expired. * * @since 2.3.0 */ readonly reason: "http" | "circuit-breaker-ttl"; /** 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 time when the circuit breaker first held the activity, if * {@link reason} is `"circuit-breaker-ttl"`. * * @since 2.3.0 */ readonly circuitHeldSince?: Temporal.Instant; /** * 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/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/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; /** * Whether this message is currently held by the outbound circuit breaker. * @internal */ readonly circuitHeld?: true; /** * When Fedify first held this message because the remote host circuit was * open. * @internal */ readonly circuitHeldSince?: 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; /** * The key prefix used for storing outbound delivery circuit breaker state. * @default `["_fedify", "circuit"]` * @since 2.3.0 */ readonly circuitBreaker: 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 options Parameters for initializing the instance. * @returns A new {@link Federation} instance. * @throws {TypeError} If benchmark mode and `meterProvider` are both * specified. * @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 object with methods to set other featured tags collection * callbacks. * @throws {@link RouterError} Thrown if the path pattern is invalid. */ setFeaturedTagsDispatcher(path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher<Hashtag, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>; /** * Assigns the URL path for the inbox and starts setting inbox listeners. * * @example * ``` typescript * federation * .setInboxListeners("/users/{identifier}/inbox", "/inbox") * .on(Follow, async (ctx, follow) => { * const from = await follow.getActor(ctx); * if (!isActor(from)) return; * // ... * }) * .on(Undo, async (ctx, undo) => { * // ... * }); * ``` * * @param inboxPath