code
Clone this repository
https://tangled.org/bretton.dev/coves
git@knot.bretton.dev:bretton.dev/coves
For self-hosted knots, clone URLs may differ based on your setup.
Change subscription lexicon subject field format from "at-identifier"
to "did" for consistency and correctness:
Before:
- format: "at-identifier" (accepts DIDs or handles)
- description: "DID or handle of the community"
After:
- format: "did" (only accepts DIDs)
- description: "DID of the community being subscribed to"
Rationale:
1. Matches block.json pattern (which correctly uses "did" format)
2. Aligns with service layer implementation (only supports DIDs)
3. Follows atProto convention: "subject" field references entities by DID
4. Prevents invalid handle values in federated records
This ensures subscription records are properly validated and compatible
with the broader atProto ecosystem.
E2E Tests (3 new test cases):
- Block via XRPC endpoint: Full flow from HTTP → PDS → Jetstream → AppView
- Unblock via XRPC endpoint: Complete unblock flow with DELETE event
- Block fails without authentication: Validates auth requirement (401)
Each E2E test verifies:
✓ XRPC endpoint responds correctly
✓ Record created/deleted on PDS
✓ Jetstream consumer indexes event
✓ AppView database state updated
Unit Test Updates:
- Added 6 mock methods to mockCommunityRepo for blocking operations
- Ensures service layer tests compile and pass
All tests follow existing E2E patterns (subscribe/unsubscribe) for
consistency.
Add 16 integration test cases covering:
1. Jetstream Consumer Indexing (4 tests):
- Block CREATE event indexing
- Block DELETE event indexing
- Idempotent duplicate event handling
- Graceful handling of non-existent block deletion
2. List Operations (3 tests):
- List all blocked communities for user
- Pagination with limit/offset
- Empty list for users with no blocks
3. IsBlocked Queries (3 tests):
- Returns false when not blocked
- Returns true when blocked
- Returns false after unblock
4. GetBlock Operations (3 tests):
- Error when block doesn't exist
- Retrieve block by user DID + community DID
- Retrieve block by AT-URI (for DELETE operations)
All tests verify proper database state, idempotency guarantees,
and Jetstream event processing.
Implement Jetstream consumer support for community block records:
- handleBlock: Routes CREATE/DELETE operations for social.coves.community.block
- createBlock: Indexes block CREATE events from firehose
- Extracts community DID from "subject" field (atProto convention)
- Builds AT-URI: at://user_did/social.coves.community.block/rkey
- Preserves createdAt timestamp for chronological ordering during replays
- Idempotent: handles duplicate events via ON CONFLICT
- deleteBlock: Processes block DELETE events from firehose
- Looks up block by URI (DELETE events don't include record data)
- Removes from AppView index
- Gracefully handles deletion of non-existent blocks
Completes the write-forward flow:
Client → PDS → Jetstream Firehose → Consumer → AppView DB
Register community blocking XRPC endpoints:
- POST /xrpc/social.coves.community.blockCommunity (requires auth)
- POST /xrpc/social.coves.community.unblockCommunity (requires auth)
Both routes use RequireAuth middleware to ensure proper authentication
before allowing block/unblock operations.
Add XRPC handlers for community blocking endpoints:
- HandleBlock: POST /xrpc/social.coves.community.blockCommunity
- HandleUnblock: POST /xrpc/social.coves.community.unblockCommunity
Features:
- Input validation: Community must be DID (did:plc:...) or handle (!name@instance)
- Authentication: Requires user DID and access token from middleware
- Response format: Follows atProto conventions with recordUri/recordCid
- Error handling: Uses shared handleServiceError for consistency
Addresses PR review comment on input validation.