feat: remote-editor invites by AP actor URL (#9) #64

Merged
claude-bot merged 1 commit from feat/v7-remote-editor-invites into main 2026-06-30 01:28:17 +00:00
Contributor

Closes #9. Second slice of v7 (host-inbound-first), building on the #12 schema.

What it does

POST /api/projects/:id/invite-remote (owner only) — invite a researcher on another instance as a project editor, named by their ActivityPub actor URL:

  • Validates the URL (isSafeUrl), rejects an actor on this instance (use the local invite path), and requires the actor's host to be an enabled federated_instance (the admin prerequisite from the issue).
  • Resolves + caches the actor via fetchAndCacheActor() — which also caches its public key, exactly what #10's inbox needs to verify the signature on that actor's future write activities.
  • Inserts a project_collaborators row with remote_actor_url set / collaborator_user_id null. Owner-initiated, so auto-accepted (accepted_at = now()) — the owner is explicitly trusting a known actor; there's no second human on this instance to accept. Duplicate (project, actor)409.

GET /:id/shares now surfaces remote editors (cached display name, type: 'remote_editor'); revoke works through the existing DELETE.

Frontend: an "Invite remote editor" input on the project collaborators panel, and remote editors render in the list (display name + actor URL + ✓ remote).

Design note

Auto-accept matches the milestone's trust posture (invited + signed writes apply automatically). An AP handshake to the remote actor's inbox is the editor-side concern, tracked in #62.

Verification (dev server)

  • projectInviteRemote.test.ts6 tests (invite + auto-accept; appears in shares; duplicate→409; non-federated→400; bad URL→400; non-owner→403; pre-seeds ap_remote_actors so fetchAndCacheActor resolves from cache, no network).
  • Full API suite 190 passed (was 184); app npm run build (tsc+vite) green.

🤖 Generated with Claude Code

Closes #9. Second slice of v7 (host-inbound-first), building on the #12 schema. ## What it does `POST /api/projects/:id/invite-remote` (owner only) — invite a researcher on another instance as a project **editor**, named by their ActivityPub actor URL: - Validates the URL (`isSafeUrl`), rejects an actor on **this** instance (use the local invite path), and requires the actor's host to be an **enabled `federated_instance`** (the admin prerequisite from the issue). - Resolves + caches the actor via `fetchAndCacheActor()` — which also caches its **public key**, exactly what #10's inbox needs to verify the signature on that actor's future write activities. - Inserts a `project_collaborators` row with `remote_actor_url` set / `collaborator_user_id` null. **Owner-initiated, so auto-accepted** (`accepted_at = now()`) — the owner is explicitly trusting a known actor; there's no second human on this instance to accept. Duplicate `(project, actor)` → `409`. `GET /:id/shares` now surfaces remote editors (cached display name, `type: 'remote_editor'`); revoke works through the existing `DELETE`. **Frontend:** an "Invite remote editor" input on the project collaborators panel, and remote editors render in the list (display name + actor URL + ✓ remote). ## Design note Auto-accept matches the milestone's trust posture (invited + signed writes apply automatically). An AP handshake *to* the remote actor's inbox is the editor-side concern, tracked in #62. ## Verification (dev server) - `projectInviteRemote.test.ts` — **6 tests** (invite + auto-accept; appears in shares; duplicate→409; non-federated→400; bad URL→400; non-owner→403; pre-seeds `ap_remote_actors` so `fetchAndCacheActor` resolves from cache, no network). - Full API suite **190 passed** (was 184); app `npm run build` (tsc+vite) green. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(p9): remote-editor invites by AP actor URL (#9)
All checks were successful
CI / App — typecheck, test & build (push) Successful in 1m35s
CI / API — typecheck & tests (push) Successful in 2m39s
CI / App — typecheck, test & build (pull_request) Successful in 1m37s
CI / API — typecheck & tests (pull_request) Successful in 2m35s
2a4da3ee50
POST /api/projects/:id/invite-remote (owner only): invite a researcher on
another instance as an editor, named by their ActivityPub actor URL.

- Validates the URL (isSafeUrl), rejects self-instance actors, and requires
  the actor's host to be an enabled federated_instance (admin prerequisite).
- Resolves + caches the actor via fetchAndCacheActor — this also caches its
  public key, which #10's inbox needs to verify signed write activities.
- Writes a project_collaborators row with remote_actor_url set; owner-initiated
  so it's auto-accepted. Duplicate (project, actor) -> 409.
- GET /:id/shares surfaces remote editors (cached display name, type
  'remote_editor'); revoke works via the existing DELETE.
- ProjectDetailPage: an "Invite remote editor" input + remote editors render
  in the collaborators list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
claude-bot scheduled this pull request to auto merge when all checks succeed 2026-06-30 01:24:39 +00:00
claude-bot deleted branch feat/v7-remote-editor-invites 2026-06-30 01:28:18 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rbrooks/TeaLeaves!64
No description provided.