Part of #47. This issue covers the sending side of account migration: letting a bot move its followers to another actor, which may be another BotKit bot (on a new domain, say) or an account on a different server entirely.
This is the largest of the three sub-issues and the least urgent. The receiving side (#48) is what current users are asking for; moving a bot away mostly matters when its operator changes domains, which BotKit otherwise has no answer for.
The Session.move() method
Add a method to Session:
/**
* Moves the bot to another actor. Sends a `Move` activity to the bot's
* followers and marks the bot as moved, so that its actor object carries
* `movedTo` from then on. The target must list the bot's actor URI in its
* `alsoKnownAs`.
* @param target The actor to move to.
* @throws {TypeError} If the target does not list the bot as an alias, or
* if the bot has already moved.
* @since 0.6.0
*/
move(target: Actor | URL | string): Promise<void>;
In order, it:
- Resolves the target and checks that its
aliasIds contains the bot's actor URI. Mastodon refuses to start a migration when this fails, and receiving servers would drop the Move anyway, so throwing here is better than sending an activity that goes nowhere.
- Stores the target as the bot's successor in the repository.
- Sends an
Update of the actor, which now carries movedTo (Fedify's successor), to the bot's followers.
- Sends a
Move with the bot as both actor and object and the target as target, addressed to the public collection and the bot's followers, as in FEP-7628's push-mode example.
The moved state has to live in the repository and not in CreateBotOptions, because the bot is defined in code: a movedTo option would give no way to tell whether the Move for it had already been sent. Storing it means new required methods on the Repository interface (something like getSuccessor(identifier) and setSuccessor(identifier, successorId)), implemented in the in-memory, KV, and cached repositories and in @fedify/botkit-postgres, @fedify/botkit-redis, and @fedify/botkit-sqlite. This is a breaking change for third-party Repository implementations, which is acceptable before 1.0 and will be called out in the changelog.
What a moved bot does
FEP-7628 says an actor carrying movedTo should be considered inactive, so after the move:
dispatchActor() sets successor on the actor.
Session.publish() throws, since publishing from an inactive actor would miss the followers who moved and could confuse those who stayed.
- Incoming follow requests are rejected regardless of
followerPolicy. This matches Mastodon, where a moved account cannot be followed.
- The profile page says the bot has moved and links to the target, and the follow button is hidden. The wording and placement should follow the Canvas mode rules in DESIGN.md.
Existing posts stay where they are. Only followers move.
Open questions
Should a move be reversible? Mastodon lets a user cancel a redirect, which removes movedTo but leaves the followers wherever they went. An unmove() (under a better name) would be easy once the successor is in the repository, but I'm not sure anyone needs it.
Should the other event handlers keep firing on a moved bot? Replies and mentions will still trickle in for a while. Letting them through is simpler and lets a bot answer with a pointer to its new home. Ignoring them is closer to “inactive.”
Part of #47. This issue covers the sending side of account migration: letting a bot move its followers to another actor, which may be another BotKit bot (on a new domain, say) or an account on a different server entirely.
This is the largest of the three sub-issues and the least urgent. The receiving side (#48) is what current users are asking for; moving a bot away mostly matters when its operator changes domains, which BotKit otherwise has no answer for.
The
Session.move()methodAdd a method to
Session:In order, it:
aliasIdscontains the bot's actor URI. Mastodon refuses to start a migration when this fails, and receiving servers would drop theMoveanyway, so throwing here is better than sending an activity that goes nowhere.Updateof the actor, which now carriesmovedTo(Fedify'ssuccessor), to the bot's followers.Movewith the bot as bothactorandobjectand the target astarget, addressed to the public collection and the bot's followers, as in FEP-7628's push-mode example.The moved state has to live in the repository and not in
CreateBotOptions, because the bot is defined in code: amovedTooption would give no way to tell whether theMovefor it had already been sent. Storing it means new required methods on theRepositoryinterface (something likegetSuccessor(identifier)andsetSuccessor(identifier, successorId)), implemented in the in-memory, KV, and cached repositories and in @fedify/botkit-postgres, @fedify/botkit-redis, and @fedify/botkit-sqlite. This is a breaking change for third-partyRepositoryimplementations, which is acceptable before 1.0 and will be called out in the changelog.What a moved bot does
FEP-7628 says an actor carrying
movedToshould be considered inactive, so after the move:dispatchActor()setssuccessoron the actor.Session.publish()throws, since publishing from an inactive actor would miss the followers who moved and could confuse those who stayed.followerPolicy. This matches Mastodon, where a moved account cannot be followed.Existing posts stay where they are. Only followers move.
Open questions
Should a move be reversible? Mastodon lets a user cancel a redirect, which removes
movedTobut leaves the followers wherever they went. Anunmove()(under a better name) would be easy once the successor is in the repository, but I'm not sure anyone needs it.Should the other event handlers keep firing on a moved bot? Replies and mentions will still trickle in for a while. Letting them through is simpler and lets a bot answer with a pointer to its new home. Ignoring them is closer to “inactive.”