Skip to content

Mastodon-style account migration import#319

Merged
dahlia merged 5 commits into
hackers-pub:mainfrom
dahlia:feature/account-migration-import
Jun 21, 2026
Merged

Mastodon-style account migration import#319
dahlia merged 5 commits into
hackers-pub:mainfrom
dahlia:feature/account-migration-import

Conversation

@dahlia

@dahlia dahlia commented Jun 21, 2026

Copy link
Copy Markdown
Member

What changed

This PR adds the Hackers' Pub side of importing an account from another fediverse server, following the Mastodon account migration flow.

Users can now add a previous account from the account settings page by entering a handle or actor/profile URL. Hackers' Pub resolves that value to the previous actor IRI, stores it on the local actor's aliases, and publishes it as alsoKnownAs in the ActivityPub actor document.

The GraphQL API now exposes Actor.aliases and provides add/remove mutations for migration aliases in graphql/account.ts. Alias edits update the current database row instead of rewriting a stale in-memory array, so overlapping add and remove requests do not resurrect or drop aliases.

The ActivityPub actor document in federation/person.ts now includes the stored aliases. Account actor update delivery is shared through models/account.ts, so migration alias changes notify followers in the same shape as other account updates.

The new account settings UI in web-next/src/routes/(root)/[handle]/settings/account.tsx explains the flow in plain steps: add the old account in Hackers' Pub, configure the move on the old server, and let the old server send the Move activity. The new UI copy is included in all supported web-next locale catalogs.

How I tested

  • Targeted migration-alias regression test in graphql/account.test.ts
  • Full graphql/account.test.ts test file
  • pnpm extract
  • mise run build:web-next
  • deno task check && deno task test

dahlia added 3 commits June 21, 2026 17:05
Expose actor aliases through ActivityPub and GraphQL, and add typed
mutations for local accounts to add or remove previous actor IRIs used
by Mastodon-style account migration. Reuse the normal actor Update
fan-out so followers can observe alias changes.

Assisted-by: Codex:gpt-5.5
Add account settings controls for preparing an inbound account
migration, including Relay mutations, localized guidance, and the
account query data needed to render previous accounts.

The guidance explains that Hackers' Pub only prepares the new account;
the actual move still starts from the old server.

Assisted-by: Codex:gpt-5.5
Update account migration alias mutations with SQL expressions that
modify the current actor alias array at update time. This prevents
overlapping add and remove requests from resurrecting or dropping
aliases based on stale GraphQL snapshots.

Add a regression test that removes an alias while a remote actor lookup
is still in progress.

Assisted-by: Codex:gpt-5.5
@dahlia dahlia requested a review from Copilot June 21, 2026 09:02
@dahlia dahlia self-assigned this Jun 21, 2026
@dahlia dahlia added web-next The new web frontend (SolidStart) graphql GraphQL API server labels Jun 21, 2026
@dahlia

dahlia commented Jun 21, 2026

Copy link
Copy Markdown
Member Author

@codex review

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 178836c1-e401-4e74-8147-4124c29b46ad

📥 Commits

Reviewing files that changed from the base of the PR and between a1dfc45 and e42047b.

📒 Files selected for processing (3)
  • graphql/account.test.ts
  • graphql/account.ts
  • web-next/src/routes/(root)/[handle]/settings/account.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • web-next/src/routes/(root)/[handle]/settings/account.tsx
  • graphql/account.test.ts
  • graphql/account.ts

📝 Walkthrough

Walkthrough

Adds ActivityPub account migration alias management. A new aliases: [URL!]! field is added to the Actor GraphQL type and exposed as alsoKnownAs on the ActivityPub Person. Two new GraphQL mutations (addAccountMigrationAlias, removeAccountMigrationAlias) manage the alias array in the database. A frontend settings card with AccountMigrationAliasesForm is added to the account settings page. Five locale PO files are updated with new migration-related strings.

Changes

Account Migration Aliases

Layer / File(s) Summary
GraphQL schema contracts and Actor.aliases field
graphql/schema.graphql, graphql/actor.ts
Adds aliases: [URL!]! to the Actor type, defines AddAccountMigrationAlias and RemoveAccountMigrationAlias input/payload/result union types, wires both mutations into Mutation, and implements the Actor.aliases resolver mapping stored strings to URL objects.
Migration alias mutation helpers and resolvers
graphql/account.ts
Imports isActor, persistActor, syncActorFromAccount, lookupActorByUrl, and parseHttpUrl; adds parseActorHandle, lookupActorByHandle, lookupMigrationAliasActor, getAuthorizedMigrationAccount, and DB update helpers; implements the two Relay mutation resolvers that validate, federated-resolve, and persist alias changes.
ActivityPub Person aliases and sendAccountActorUpdate refactor
federation/person.ts, models/account.ts
Sets aliases on the ActivityPub Person from account.actor.aliases in getAccountActor. Extracts the inline fedCtx.sendActivity Update call in updateAccount into an exported sendAccountActorUpdate helper.
Account settings page with migration alias form
web-next/src/routes/(root)/[handle]/settings/account.tsx
Replaces the single delete-card page with a two-card layout; adds actor { aliases } to the page query; defines Relay mutations with typed error branches; implements AccountMigrationAliasesForm with add/remove state, toast feedback, and an alias list with empty-state fallback.
Federation and GraphQL integration tests
federation/actor.test.ts, graphql/account.test.ts
Adds a federation test asserting getAccountActor exposes seeded aliases. Adds GraphQL tests for Actor.aliases query, addAccountMigrationAlias (idempotency, federation lookup, no-resurrect, auth/input errors), and removeAccountMigrationAlias (idempotent removal and sendActivity call count).
i18n catalog updates
web-next/src/locales/en-US/messages.po, web-next/src/locales/ja-JP/messages.po, web-next/src/locales/ko-KR/messages.po, web-next/src/locales/zh-CN/messages.po, web-next/src/locales/zh-TW/messages.po
Adds new account-migration UI strings (old-account placeholder, add/remove/prepare guidance, error messages, empty state), marks deprecated migration alias wording as obsolete with #~, and updates sidebar/navigation source references across all five locales.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • hackers-pub/hackerspub#278: Modifies lookupActorByUrl and related lookup resolvers to short-circuit for guest callers, directly impacting the new actor-resolution path in the migration-alias mutations.

Suggested labels

enhancement

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Mastodon-style account migration import' accurately summarizes the main change—implementing account migration functionality following Mastodon's approach.
Description check ✅ Passed The PR description clearly explains the changes made, implementation details, and testing approach, directly relating to the changeset across multiple files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements ActivityPub account migration aliases (alsoKnownAs) to support Mastodon-style account moves, adding GraphQL mutations to add and remove aliases, updating federation and database models, and introducing a settings UI with localized strings. The review feedback highlights several critical improvement opportunities, including adding defensive nullish coalescing checks to prevent runtime crashes when aliases is null or undefined, normalizing hostnames to lowercase in Fediverse handles to avoid cache misses, and changing the mobile input field's inputmode to "email" to improve the user experience when typing handles.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread graphql/account.ts Outdated
Comment thread federation/person.ts
Comment thread graphql/actor.ts
Comment thread web-next/src/routes/(root)/[handle]/settings/account.tsx Outdated
Comment thread web-next/src/routes/(root)/[handle]/settings/account.tsx

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds end-to-end support for Mastodon-style account migration imports by letting users attach “previous account” actor IRIs to their local actor’s alsoKnownAs list, exposing those aliases via GraphQL, updating the ActivityPub actor document, and providing a settings UI to manage aliases.

Changes:

  • Add Actor.aliases to the GraphQL API plus addAccountMigrationAlias / removeAccountMigrationAlias mutations, with concurrency-safe DB updates and regression tests.
  • Publish stored aliases in the ActivityPub Person actor document and reuse a shared sendAccountActorUpdate helper to notify followers.
  • Add an account settings UI for managing migration aliases, including localized copy for all supported web-next locales.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated no comments.

Show a summary per file
File Description
web-next/src/routes/(root)/[handle]/settings/account.tsx Adds “Account migration” settings card with UI to add/remove previous-account aliases via Relay mutations.
web-next/src/locales/en-US/messages.po Adds localized strings for the new migration UI and updates source references.
web-next/src/locales/ja-JP/messages.po Adds localized strings for the new migration UI and updates source references.
web-next/src/locales/ko-KR/messages.po Adds localized strings for the new migration UI and updates source references.
web-next/src/locales/zh-CN/messages.po Adds localized strings for the new migration UI and updates source references.
web-next/src/locales/zh-TW/messages.po Adds localized strings for the new migration UI and updates source references.
models/account.ts Extracts and exports sendAccountActorUpdate and reuses it from updateAccount.
graphql/actor.ts Exposes Actor.aliases as [URL!]! backed by the actorTable.aliases column.
graphql/account.ts Implements alias resolution + add/remove mutations, including federation lookup and follower update delivery.
graphql/schema.graphql Updates generated schema with Actor.aliases and the new migration alias mutations/types.
graphql/account.test.ts Adds coverage for alias querying, add/remove behavior, error typing, and update delivery behavior.
federation/person.ts Includes stored aliases in the local ActivityPub actor document.
federation/actor.test.ts Adds ActivityPub actor document test coverage for aliases exposure.
deno.lock Updates npm dependency resolution entries (likely from tooling/codegen).

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: a1dfc45799

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@graphql/account.test.ts`:
- Around line 1463-1465: The inline type assertion in the toPlainJson call
contains duplicate property key declarations within the type literal, which
causes TypeScript compilation errors. Locate the type assertion in the
toPlainJson call around the addAccountMigrationAlias property and remove any
duplicate key declarations from the type literal object. Ensure each property
key appears only once in the type literal. Apply the same fix to all other
instances mentioned around line 1483-1485 where similar duplicate property
signatures exist in inline type assertions.

In `@web-next/src/routes/`(root)/[handle]/settings/account.tsx:
- Around line 178-181: The Title component only updates page metadata and does
not render a visible heading in the DOM, which removes the page-level h1 heading
needed for accessibility and semantic HTML structure. Add a visible or
screen-reader-only h1 heading element before the SettingsTabs component in the
JSX. This h1 should display the account settings title and maintain proper
heading hierarchy, either as a visible heading or using a screen-reader-only
utility class if you want to hide it visually while keeping it available to
assistive technologies.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a462a80-4b31-4a03-980f-668351c435ab

📥 Commits

Reviewing files that changed from the base of the PR and between b9ba16e and a1dfc45.

⛔ Files ignored due to path filters (1)
  • deno.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • federation/actor.test.ts
  • federation/person.ts
  • graphql/account.test.ts
  • graphql/account.ts
  • graphql/actor.ts
  • graphql/schema.graphql
  • models/account.ts
  • web-next/src/locales/en-US/messages.po
  • web-next/src/locales/ja-JP/messages.po
  • web-next/src/locales/ko-KR/messages.po
  • web-next/src/locales/zh-CN/messages.po
  • web-next/src/locales/zh-TW/messages.po
  • web-next/src/routes/(root)/[handle]/settings/account.tsx

Comment thread graphql/account.test.ts
Comment thread web-next/src/routes/(root)/[handle]/settings/account.tsx
dahlia added 2 commits June 21, 2026 19:48
Lowercase the host part of account migration handles before looking up cached
actors or doing federation lookup. This keeps mixed-case domains from missing
an actor row that is already stored under the canonical lowercase host.

hackers-pub#319 (comment)

Assisted-by: Codex:gpt-5.5
Add a screen-reader-only page heading to restore the account settings heading
hierarchy, and use the email keyboard hint for the old-account field so mobile
users can type fediverse handles more easily.

hackers-pub#319 (comment)
hackers-pub#319 (comment)

Assisted-by: Codex:gpt-5.5
@dahlia

dahlia commented Jun 21, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements support for ActivityPub account migration aliases (alsoKnownAs), allowing users to prepare their local accounts as destinations for Mastodon-style moves. It introduces new GraphQL mutations (addAccountMigrationAlias and removeAccountMigrationAlias), updates the database models and federation logic to propagate these changes, and adds a dedicated settings UI in the SolidStart stack. Feedback on the changes highlights critical runtime issues: Drizzle ORM's Relational Query API is incorrectly queried using Prisma-like nested objects instead of callback functions in several files, and potential TypeError crashes exist in graphql/actor.ts and federation/person.ts if the aliases field is null or undefined in the database.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread graphql/account.ts
Comment thread graphql/account.ts
Comment thread graphql/account.ts
Comment thread federation/actor.test.ts
Comment thread graphql/account.test.ts
Comment thread graphql/actor.ts
Comment thread federation/person.ts
@dahlia dahlia merged commit 9e920d9 into hackers-pub:main Jun 21, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

graphql GraphQL API server web-next The new web frontend (SolidStart)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants