Clone this repository
For self-hosted knots, clone URLs may differ based on your setup.
Download tar.gz
Add API key-based authentication allowing aggregators to post to communities
via bot-like behavior. This complements OAuth for programmatic access.
Key components:
- API key generation, validation, and revocation endpoints
- Encrypted OAuth token storage for session persistence
- DualAuthMiddleware supporting API keys alongside OAuth
- Database migrations for key storage with encryption at rest
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract external link embeds (title, description, thumb) from quoted posts
- Handle blocked quoted posts (#viewBlocked) with "This post is from a blocked account"
- Handle deleted quoted posts (#viewNotFound) with "This post has been deleted"
- Handle detached quoted posts (#viewDetached) with "This post is unavailable"
- Add Detached boolean field for consistency with Blocked/NotFound pattern
- Add logging for JSON unmarshal failures and timestamp parsing errors
- Improve doc comments for embed extraction functions
Also adds beads issue Coves-327 for Phase 3: image/video extraction
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Indigo xrpc client always sends Auth.AccessJwt as the Authorization
header, but com.atproto.server.refreshSession requires the refresh token
in that header. This was causing "InvalidToken: Invalid token type" errors
when community tokens needed refreshing.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When embedding Bluesky posts that contain external links (link cards),
the external link metadata (URI, title, description, thumbnail) is now
extracted and stored in the BlueskyPostResult.
Changes:
- Add ExternalEmbed type to capture link card data
- Add Embed field to BlueskyPostResult
- Parse app.bsky.embed.external#view from Bluesky API responses
- Add unit tests for external embed extraction
- Fix productionPLCIdentityResolver to require db parameter
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Server was using local PLC directory (localhost:3002) for resolving real
Bluesky handles like "bretton.dev", which failed with 404 errors. Now uses
a dedicated production PLC resolver (https://plc.directory) that is READ-ONLY
for looking up existing Bluesky identities.
- Add productionPLCResolver in main.go for Bluesky handle resolution
- Update tests to use production PLC helper function
- Clean up debug logging in post service
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Address PR review feedback:
- Add debug logging when URI is not a string type
- Differentiate timeout errors from other parse errors
- Include unavailable post message in log output
- Add test case for wrong URI type (int instead of string)
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a user pastes a Bluesky URL (bsky.app) as an external embed,
convert it to a social.coves.embed.post with proper strongRef
containing both URI and CID. This enables rich embedded quote posts
instead of plain external links.
Key changes:
- Implement tryConvertBlueskyURLToPostEmbed in service.go
- Detect Bluesky URLs and resolve them via blueskyService
- Parse URL to AT-URI (resolves handle to DID if needed)
- Fetch CID from Bluesky API for strongRef
- Fall back to external embed on errors (graceful degradation)
- Differentiated logging for circuit breaker vs other errors
- Keep unavailable posts as external embeds (no fake CIDs)
Test coverage:
- Unit tests for all error cases and success path
- Integration test for URL to strongRef conversion
Closes: Coves-p44
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Hot ranking formula now uses (score + 1) instead of score to prevent
new posts with 0 votes from sinking to the bottom. Previously,
0 / time_decay = 0 caused all unvoted posts to have rank 0.
Affects discover, timeline, and community feed repos.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update community handles to use c-{name}.{instance} pattern and
enable additional feeds (US News, Science).
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extend auth middleware to accept both OAuth sealed tokens (users) and
PDS service JWTs (aggregators). Uses Indigo's ServiceAuthValidator for
JWT signature verification against DID document public keys.
Security model:
- Detect token format upfront (detect-and-route, not fallback)
- JWT auth restricted to DIDs in aggregators table
- Aggregators self-register via social.coves.aggregator.service record
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>