You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This fits typical multi-tenant fediverse apps where every actor maps to a user account. It does not fit applications that want to expose a single, instance-level actor at a fixed path, such as:
/actor for a relay
/site for a single-author blog that speaks as itself
/feed for an RSS-to-ActivityPub bridge that publishes one consolidated feed
/bot for a CI or notification bot
These actors have no meaningful identifier. Forcing one feels artificial and leaks the sentinel value into application code.
Current workaround
Pick a sentinel identifier, register the dispatcher under /users/{identifier}, branch on the sentinel inside the callback, and add a framework-level route that proxies the fixed path to the synthetic identifier:
federation.setActorDispatcher("/users/{identifier}",async(ctx,identifier)=>{if(identifier==="__instance__"){returnnewService({id: ctx.getActorUri("__instance__"),preferredUsername: "instance",// ...});}// normal user lookup});// Plus a framework-level route that proxies /actor to /users/__instance__.
It works, but the canonical URI sits at /users/__instance__ rather than /actor, and the sentinel string leaks into mapHandle() and any other identifier-keyed callback the app uses.
Possible API shapes
Allow path patterns without {identifier}
Drop the type constraint that forces the path to contain {identifier}. The dispatcher signature would shift based on whether the path has any template variables, similar to how setObjectDispatcher() already accepts paths with arbitrary parameter sets:
getActorUri() with no arguments would return the fixed path. Inbox, outbox, followers, and other per-actor endpoints would also need to accept paths without {identifier}. mapHandle(), mapAlias(), and setKeyPairsDispatcher() would either be skipped (the actor is a single known thing, no lookup needed) or accept callbacks that take no identifier argument.
Alias a fixed path to a sentinel identifier
The alternative #646 sketched keeps the identifier-based dispatcher and adds a method that aliases a fixed path to a synthetic identifier:
This is a much smaller change. It does not touch the signatures of inbox, outbox, or collection dispatchers. The cost: the sentinel identifier becomes a real concept the application has to know about, and the canonical URI stays at /users/__instance__ unless the alias mechanism is also wired into URI generation, which complicates getActorUri().
Note on setObjectDispatcher()
setObjectDispatcher() already accepts arbitrary URI templates dispatched per class, but it requires at least one template variable. Whatever shape we settle on for actors might want to relax that constraint there too, since the same need (a fixed Collection at a known URL) does come up.
Open questions
Is this a special case of multi-pattern support (Support multiple path patterns in actor dispatcher #646), or a separate concern? A fixed-path instance actor and a multi-tenant actor space could coexist in the same application.
How should WebFinger behave for a fixed-path actor? Is the handle simply the actor's preferredUsername, with no mapHandle() callback needed, or do we still want the callback for cases where the handle differs from the username?
How do per-actor collections (inbox, outbox, followers, following) work when the actor has no identifier? Does each fixed-path actor get its own fixed inbox path, or share a sharedInbox at a single well-known location?
Is there value in supporting multiple fixed-path actors in one application (e.g., /actor and /admin)? If so, type-based discrimination from Support multiple path patterns in actor dispatcher #646 likely becomes a prerequisite.
Does setKeyPairsDispatcher() for a fixed-path actor still take an identifier argument with a constant value, or change shape?
Background
setActorDispatcher()requires the path pattern to contain an{identifier}template variable. The signature enforces it at the type level:This fits typical multi-tenant fediverse apps where every actor maps to a user account. It does not fit applications that want to expose a single, instance-level actor at a fixed path, such as:
/actorfor a relay/sitefor a single-author blog that speaks as itself/feedfor an RSS-to-ActivityPub bridge that publishes one consolidated feed/botfor a CI or notification botThese actors have no meaningful identifier. Forcing one feels artificial and leaks the sentinel value into application code.
Current workaround
Pick a sentinel identifier, register the dispatcher under
/users/{identifier}, branch on the sentinel inside the callback, and add a framework-level route that proxies the fixed path to the synthetic identifier:It works, but the canonical URI sits at
/users/__instance__rather than/actor, and the sentinel string leaks intomapHandle()and any other identifier-keyed callback the app uses.Possible API shapes
Allow path patterns without
{identifier}Drop the type constraint that forces the path to contain
{identifier}. The dispatcher signature would shift based on whether the path has any template variables, similar to howsetObjectDispatcher()already accepts paths with arbitrary parameter sets:getActorUri()with no arguments would return the fixed path. Inbox, outbox, followers, and other per-actor endpoints would also need to accept paths without{identifier}.mapHandle(),mapAlias(), andsetKeyPairsDispatcher()would either be skipped (the actor is a single known thing, no lookup needed) or accept callbacks that take no identifier argument.Alias a fixed path to a sentinel identifier
The alternative #646 sketched keeps the identifier-based dispatcher and adds a method that aliases a fixed path to a synthetic identifier:
This is a much smaller change. It does not touch the signatures of inbox, outbox, or collection dispatchers. The cost: the sentinel identifier becomes a real concept the application has to know about, and the canonical URI stays at
/users/__instance__unless the alias mechanism is also wired into URI generation, which complicatesgetActorUri().Note on
setObjectDispatcher()setObjectDispatcher()already accepts arbitrary URI templates dispatched per class, but it requires at least one template variable. Whatever shape we settle on for actors might want to relax that constraint there too, since the same need (a fixedCollectionat a known URL) does come up.Open questions
preferredUsername, with nomapHandle()callback needed, or do we still want the callback for cases where the handle differs from the username?sharedInboxat a single well-known location?/actorand/admin)? If so, type-based discrimination from Support multiple path patterns in actor dispatcher #646 likely becomes a prerequisite.setKeyPairsDispatcher()for a fixed-path actor still take an identifier argument with a constant value, or change shape?Related: #646.