social-federation tasks 5.1–5.6. Completes the inbound-federation story: a Mastodon follower now receives a trails user's new public activities in their home timeline. Outbox (5.1/5.2): - /users/:username/outbox — paginated OrderedCollection of public activities as Create(Note), newest first; unlisted/private never federate. Private-user 404 enforced at the route layer because Fedify builds collection-level responses from counter/cursors without consulting the page dispatcher. - Note shape: HTML content (escaped name/description/stats + link to the activity page) with structured PropertyValue attachments (distance-m, elevation-gain-m, duration-s) — Mastodon renders the text, trails consumers read the structured fields. Resolves the design open question toward Create(Note). - Authorized Fetch: signed and unsigned outbox fetches deliberately see the same (public-only) content until locked accounts exist. Push delivery (5.3–5.6): - createActivity / updateActivityVisibility(→public) enqueue one deliver-activity job per accepted remote follower; flips away from public and hard deletes enqueue Delete(Tombstone) retractions (enqueued before the row disappears). - deliver-activity job: re-reads the row at delivery time (skips if gone or no longer public), resolves the recipient inbox via the remote_actors cache with actor-document fetch fallback (priming the cache), HTTP-signs via the owner's key, and POSTs. retryLimit 8 + exponential backoff at enqueue time; outbound paced at 1 req/s per remote host. - Actor objects now advertise the outbox IRI. - @js-temporal/polyfill added (same range Fedify uses) for published timestamps; Fedify's types want the global esnext.temporal namespace, bridged with a documented cast. Tests: 9 unit tests for the AS mapping (escaping, stats, attachments, published fallback, stable ids, tombstones), 4 outbox integration tests (collection count, page shape/visibility filtering, private-404, delivery audience query). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
22 lines
864 B
TypeScript
22 lines
864 B
TypeScript
import type { Route } from "./+types/users.$username.outbox";
|
|
import {
|
|
federationEnabled,
|
|
handleFederationRequest,
|
|
isFederatableUser,
|
|
} from "~/lib/federation.server";
|
|
|
|
/**
|
|
* GET /users/:username/outbox — paginated OrderedCollection of the
|
|
* user's public activities as Create(Note) (spec: social-federation,
|
|
* "Outbox publishes user's public activities"). Served by Fedify's
|
|
* collection dispatcher; 404s for private users (checked here because
|
|
* Fedify builds the collection-level response from counter/cursors
|
|
* without consulting the page dispatcher) and while FEDERATION_ENABLED
|
|
* is off.
|
|
*/
|
|
export async function loader({ request, params }: Route.LoaderArgs) {
|
|
if (!federationEnabled() || !(await isFederatableUser(params.username))) {
|
|
return new Response("Not Found", { status: 404 });
|
|
}
|
|
return handleFederationRequest(request);
|
|
}
|