commits
Remove dependency on the legacy Lemmy `site` API for the sidebar,
navbar, meta tags, legal page, and favicon. Introduce Coves-branded
components with aggregated stats fetched from the Coves API.
Changes:
- Add CovesSidebar component with mascot, description, and site stats
- Add siteStats reactive store with 5-minute cache
- Add LilDude mascot SVG component and brand assets
- Add static favicon.svg and community-guidelines.md
- Move Home button from navbar to sidebar with exact URL matching
- Simplify layout meta tags to use static Coves branding
- Load legal/community guidelines from local markdown file
- Remove InstanceCard usage from layout, profile, and navbar
- Remove sidebar footer (version, source, donate links)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Thread loadFeed callback through PostListShell and VirtualFeed to
restore infinite scroll pagination on home and community pages. Add
auth error detection (401/403) that shows session-expired message
with login button. Improve feed robustness with null-safe responses,
cursor-based hasMore logic, and proper error re-throwing.
Changes:
- Add loadFeed prop to PostListShell and pass to VirtualFeed
- Create loadFeed functions in home and community page loaders
- Detect XrpcError 401/403 and show login prompt instead of retry
- Move loading=false to finally block in VirtualFeed
- Guard against null feed responses with ?? []
- Add empty state placeholder on home page
- Fix /communities link to /explore/communities
- Update empty feed description copy
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the Photon-era PascalCase sort mapping layer (Hot, TopDay, Subscribed,
etc.) and replace it with direct Coves API values (hot/new/top, discover/timeline).
Adds a timeframe parameter for top sort and introduces FeedTabs and SortMenu
components for the home feed.
Changes:
- Rewrite mapSort() to validate Coves sort/timeframe values directly
- Rewrite mapListing() for discover/timeline with auth guard
- Add CovesSortParams discriminated union for type-safe sort params
- Replace SortType/ListingType/CommentSortType with Coves-native literals
- Add timeframe field to settings.defaultSort
- Create FeedTabs.svelte (Discover/For You tab bar)
- Create SortMenu.svelte (sort type + timeframe dropdown)
- Update home page, community, and post routes to pass timeframe
- Make searchParam() async with error handling
- Add feed.discover/feed.forYou i18n keys
- Rewrite sort tests for Coves-native values
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate the voting UI from a dual up/down chevron system to a single
heart-based like/unlike toggle, aligning with the Coves social model.
Changes:
- Replace PostVote and CommentVote chevron buttons with AnimatedHeart
- Add AnimatedHeart.svelte with pop/circle-burst/particle animation
- Simplify computeVoteState to only handle 'up' direction (like toggle)
- Score now equals upvotes count (no downvote subtraction)
- Remove vote ratio bar, voteColor, and shouldShowVoteColor utilities
- Add dev-mode hostname normalization for ATProto OAuth cookie domain
- Extract validateProxyPath into dedicated validate.ts module
- Fix proxy body forwarding: use blob() instead of streaming to avoid
Node.js undici "expected non-null body source" errors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rebrand the forked Photon project to Kelp, the Coves web frontend.
This is standard practice after forking - users should see Coves/Kelp
branding, not the upstream Photon name.
Changes:
- Rename package from "photon-lemmy" to "kelp-coves"
- Update PWA manifest name/description for Kelp/Coves
- Rename photonify() to localizeLink() across codebase and tests
- Rename Photon icon export to Kelp, PHOTON_DEFAULT to KELP_DEFAULT
- Update all 17 i18n files (Photon -> Kelp, with proper declension)
- Update source links to tangled.org/bretton.dev/coves-frontend
- Rewrite README with Kelp identity and Photon attribution
- Fix NSID casing: getprofile -> getProfile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate user profiles from /u/[handle] to /profile/[handle=handle] with
a validated SvelteKit param matcher that accepts handles and DIDs while
rejecting reserved route segments. The old /u/[handle] route now
301-redirects, and the legacy /profile/user route is removed entirely.
Changes:
- Add handle param matcher validating handles/DIDs against reserved segments
- Move profile page + UserActions from /u/[handle] to /profile/[handle=handle]
- Add 301 redirect from /u/[handle] to /profile/[handle] for backwards compat
- Redirect /profile to /profile/{handle} for authenticated users, /login for guests
- Move profile tabs and auth guard into (local_user) layout group
- Update all navigation links (sidebar, navbar, command palette) to use new paths
- Fix API NSIDs: getCommunityFeed and getProfile to match backend
- Rewrite markdown link generation (photonify, linkify) from /u/ to /profile/
- Add tests for handle matcher, profile redirect, /u/ redirect, and photonify
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace client-side image optimization (query param thumbnail/format)
with the Coves backend image proxy system. The proxy serves images at
/img/{preset}/plain/{did}/{cid} with presets like avatar, banner,
content_preview, content_full, and embed_thumbnail.
Changes:
- Add image-proxy module with parseProxyUrl, withPreset, imageUrl helpers
- Add thumb/fullsize fields to EmbedImage type
- Widen embed $type discriminants to accept non-#view variants
- Migrate Avatar, MdImage, PostLink, PostIframe, PostImage,
PostMediaCompact to use proxy presets instead of query params
- Add onerror handlers for graceful image fallbacks
- Simplify <picture> srcset generation across components
- Make all embed type switches exhaustive with never checks
- Deprecate optimizeImageURL in favor of withPreset
- Add comprehensive tests for image-proxy module
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix sort parameter handling in the post route to use mapSort for consistency
with the Coves migration. Previously the raw URL parameter was passed directly
to the API, but after migrating to Coves XRPC, sort values need to be mapped
from legacy Lemmy format to the new format.
Also expanded .gitignore to exclude Playwright browser testing artifacts that
were being generated during development.
Changes:
- Import and use mapSort to transform legacy sort parameter
- Rename 'sort' variable to 'legacySort' for clarity
- Add .gitignore patterns for Playwright outputs (.playwright-output, *.png, console-*.txt, network-*.txt, *-snapshot.md)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Migrate remaining components from Lemmy/PieFed data model to Coves XRPC API,
focusing on moderation system, type guards, and post creation. This builds on
previous migration work to complete the transition to Coves-native types.
Changes:
- Refactor moderation system with Svelte 5 runes ($state) in moderation.svelte.ts
- Create ModerationModals.svelte for lazy-loading modal components
- Delete legacy moderation.ts and Moderation.svelte
- Migrate item type guards from item.ts to item.svelte.ts with Coves types
- Add backward-compatible type guards for legacy Lemmy data during transition
- Simplify PostForm by removing PieFed features (events, polls, extended data)
- Update contentview.ts to use AtUri and AuthorView instead of Lemmy types
- Refactor report.ts with placeholder types for pending Coves moderation API
- Update ~50 route files across admin, community, profile, and moderation areas
- Fix session, settings, sorting, and utility modules for Coves data model
- Mark deprecated functions that await Coves API implementation (save, favorites)
Breaking Changes:
- PostForm no longer supports events, polls, or PieFed-specific features
- Moderation API calls are stubs pending Coves backend implementation
- Save/favorite functions display warnings until Coves API is available
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Migrate the entire comment feature module (data model, tree logic, and
7 UI components) from Lemmy's flat path-based comment model to Coves'
server-computed ThreadViewComment tree structure with AT-URI identifiers.
Changes:
- Rewrite buildCommentsTree() to walk ThreadViewComment[] instead of
parsing flat path strings — delete getCommentParentId/getDepthFromComment
- Migrate CommentNodeI from comment_view (Lemmy) to comment (Coves CommentView)
- Add createOptimisticCommentView() for instant reply rendering
- Migrate CommentVote to call coves().createVote()/deleteVote() with
optimistic updates and rollback on error
- Migrate CommentForm to use StrongRef props and coves().createComment()
- Migrate CommentActions to use coves().deleteComment() and Coves types
- Remove @ts-nocheck from Comment, CommentItem, CommentVote
- Disable unavailable features in UI (save, report, moderation, edit)
- Temporarily simplify InboxItem comment rendering until inbox migration
- Add comprehensive unit tests for tree building, searching, and insertion
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restructure community and user routes from [name] to [handle] params,
migrate the home feed and explore pages to use Coves XRPC endpoints,
and introduce sort/listing mapping for the legacy Photon filter UI.
Changes:
- Replace /c/[name] and /u/[name] routes with /c/[handle] and /u/[handle]
- Add /c/[handle]/post/[rkey] route for clean post permalinks
- Migrate home feed to getTimeline()/getDiscover() XRPC calls
- Migrate explore communities to searchCommunities()/listCommunities()
- Add sort.ts mapping layer (legacy PascalCase -> Coves sort+timeframe)
- Add communitySlug()/communityHandleFromSlug() for c- prefix convention
- Add parseAtUri() for extracting did/collection/rkey from AT-URIs
- Fix postLink() to generate /c/{slug}/post/{rkey} URLs from AT-URIs
- Fix computeVoteState to clear voteUri on vote toggle-off
- Fix getSessionStorage to handle null/corrupted JSON gracefully
- Fix operator precedence bug in explore communities showTop filter
- Replace Feed generic `any` types with `unknown` + safe casts
- Widen community API params to accept DID | Handle
- Add @ts-nocheck markers to ~20 unmigrated legacy files
- Export ApiMeResponse from server session types
- Add error boundary with retry button to home feed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate post, community, user, and feed components to use Coves
ATProto types (PostView, CommunityView, AuthorView) instead of
legacy Lemmy types. This completes the data model migration for
the core UI layer.
Changes:
- API: add getPost() method, strengthen param types (string → DID/AtUri/Handle),
narrow $type literals, make ImageEmbed.images a non-empty tuple
- Utilities: add communityLink() and userLink() supporting both Coves
and legacy types, add isImage/isVideo explicit return types, make
fullCommunityName resilient to invalid URLs
- Post components: migrate Post, PostItem, PostLink, PostMeta, PostVote,
PostActions, PostActionsMenu, PostMedia, PostImage, PostMediaCompact
to use Coves PostView and embed types
- Post helpers: add embed extraction functions (extractEmbedUrl,
extractEmbedThumbnail, extractEmbedTitle, extractEmbedAlt),
computeVoteState(), mediaType() for Coves embeds
- Community components: migrate CommunityCard, CommunityHeader,
CommunityItem, CommunityItemBig, CommunityLink to CommunityView/
CommunityViewDetailed; add communityIdentifier/communityDisplayName helpers
- User components: migrate UserItem, UserLink to AuthorView;
remove legacy addSubscription
- Feed types: update FeedTypes to Coves response shapes; add Feed.error state
- Remove Lemmy-specific features: flair, NSFW badges, instance blocking,
banned_from_community, resolveObject
- Tests: add util.svelte.test.ts, helpers.test.ts; update client.test.ts
with branded types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use `new Headers(init?.headers)` instead of spreading into a plain
object, which silently drops all entries when the caller passes a
Headers instance
- Guard `await res.text()` in error paths with `.catch()` so a
secondary failure doesn't mask the original HTTP error
- Replace User-Agent string from "Photon" to "Coves"
- Remove no-op ternary `auth ?? (browser ? undefined : undefined)`
- Update stale TODO now that CovesClient exists
- Replace informal "forgor" comment on getClient with @deprecated JSDoc
- Update toProxyUrl JSDoc example to XRPC-style URL
- Clarify customFetch JSDoc to document that it throws SvelteKit error()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a complete XRPC transport layer and typed API client for the Coves
backend, replacing the need for Lemmy/PiFed adapters for Coves-native
endpoints.
Changes:
- Add XrpcClient with query (GET) and procedure (POST) methods that
parse structured XRPC error bodies into typed XrpcError instances
- Add CovesClient with typed methods for all 18 Coves API endpoints
(feed, comments, votes, actor, community, posts)
- Add covesCustomFetch that returns raw Response (unlike customFetch)
so XrpcClient can parse XRPC error bodies before throwing
- Add coves() factory function integrated with profile/proxy routing
- Strengthen types: add PostRecord, CommentRecord, CommunityVisibility
union type, and replace generic string types with literal unions
- Add 46 tests covering XRPC transport, client delegation, and type
validation utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract DID, Handle, and InstanceURL branded types from session.ts into
a shared $lib/types/atproto.ts module so both client and server code can
import them. Add comprehensive Coves API data model types derived from
Go backend structs to $lib/api/coves/types.ts.
Changes:
- Extract ATProto branded types + validators to $lib/types/atproto.ts
- Add Coves view types: posts, comments, communities, profiles
- Add embed discriminated union (images, external, video, record)
- Add request/response types for all XRPC endpoints
- Add AtUri and CID branded types with validators
- Update session.ts to re-export from shared module
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
isNetworkError no longer blanket-matches all TypeError instances — it
now requires a fetch/network keyword in the message, so programming bugs
(e.g. "Cannot read properties of undefined") surface as errors instead
of being silently retried as transient network failures.
parseApiMeResponse upgrades DID/handle validation failures from
console.warn to console.error so log aggregation tools will alert on
broken backend contracts. Avatar URL rejection remains console.warn.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, the frontend maintained its own encrypted session store
(kelp_session) with AES-256-GCM, managing account lists, active account
switching, and re-validating credentials locally. This duplicated auth
logic that the Go backend already handles.
The new model is stateless on the frontend:
- The Go backend sets `coves_session` (an opaque cookie) during OAuth
- hooks.server.ts validates every request by calling /api/me
- The frontend stores no user data locally — auth state comes entirely
from the server's response to /api/me
Changes:
- Remove AES-256-GCM session crypto (session.ts, cookies.ts)
- Simplify OAuth callback to just validate CSRF state and redirect
- Delete multi-account switch endpoint (/api/auth/switch)
- Rewrite hooks.server.ts to fetch /api/me with typed error handling
(network_error vs validation_error) and sessionExpired signaling
- Add authError and sessionExpired to locals/PageData types
- Simplify auth.svelte.ts: remove switchTo(), single-account syncFromServer()
- Update proxy to read authToken from flattened locals.auth.authToken
- Rename postform.svelte.ts -> post-form.svelte.ts
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhance ATProto OAuth with encrypted server-side sessions, eliminating
client-side token exposure for improved security.
Changes:
- Add encrypted session storage with AES-256-GCM (src/lib/server/session.ts)
- Add CSRF state validation for OAuth flow (src/lib/server/csrf.ts)
- Add API routes: /api/auth/{login,callback,logout,switch}
- Add API proxy that injects auth from session cookies
- Add discriminated union types for auth state (App.Locals)
- Add branded types: DID, Handle, InstanceURL, AccountId, SealedToken
- Update client to route requests through auth-injecting proxy
- Update hooks.server.ts to decrypt sessions into locals.auth
- Add Vitest configuration and comprehensive test coverage
- Remove client-side OAuth callback (now server-side)
- Remove legacy Lemmy password management pages
Security improvements:
- Tokens never exposed to browser JavaScript
- Session cookies encrypted with AES-256-GCM
- CSRF protection via OAuth state parameter
- Open redirect prevention in login flow
- Path traversal protection in API proxy
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace Lemmy username/password authentication with ATProto's OAuth flow
for the Coves migration. This removes legacy Lemmy-specific code and
simplifies the auth model for ATProto's identity system.
Changes:
- Add /oauth/callback route for handling OAuth redirects
- Rewrite login page for handle-based OAuth initiation
- Update ProfileInfo to store ATProto fields (did, sessionId, handle)
- Add automatic token refresh with 401 retry in API client
- Remove Lemmy-specific code (cookie migration, donation polling)
- Stub legacy subscription/favorites APIs with migration TODOs
- Remove inbox notification badges pending Coves API
- Fix localStorage error handling and type safety
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prepare codebase for migration to Coves backend by excluding legacy code from
type checking while fixing remaining TypeScript errors in active code.
Changes:
- Exclude legacy markdown, piefed, and lemmy/adapter from tsconfig and eslint
- Add @ts-nocheck to legacy files pending migration
- Update pnpm check to use --diagnostic-sources and --threshold error
- Fix Button.svelte Props interface to use explicit props with index signature
- Update UserAutocomplete.onselect to accept optional Person
- Add Icon prop type declarations to app.d.ts
- Remove unused props from CommentItem, ProfileButton, RemoveModal
- Fix CommunityLink Icon title accessibility (wrap in span)
- Replace deprecated preventDefault import in ImagePreviewInput
- Add class prop to Tabs and PostIframe components
- Use $derived instead of $state for derived values in saved/signup pages
- Add DEFAULT_CLIENT_TYPE to validateInstance calls
- Fix route paths to consistently use [id=integer] matcher
- Simplify navigation using template literals
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensure reproducible dependency installation across all environments.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Configure Claude Code for the Kelp (Coves Frontend) project with
project-specific instructions, hooks, and custom commands.
Changes:
- Add CLAUDE.md with project context, tech stack, and coding guidelines
- Configure Svelte MCP plugin for Svelte 5 development
- Add PostToolUse hook for auto-formatting .svelte/.ts/.js files
- Add /merge-to-main custom command for streamlined git workflow
- Configure local permissions for grep operations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* impr: use one resize observer that observes all elements 1984 style instead of 1 agent per element
* design: tweak VirtualFeed.svelte to have a more modern retry window
This reverts commit c9ca98eb305f9eecc7fccf22075d8ed77e43f3a3.
Remove dependency on the legacy Lemmy `site` API for the sidebar,
navbar, meta tags, legal page, and favicon. Introduce Coves-branded
components with aggregated stats fetched from the Coves API.
Changes:
- Add CovesSidebar component with mascot, description, and site stats
- Add siteStats reactive store with 5-minute cache
- Add LilDude mascot SVG component and brand assets
- Add static favicon.svg and community-guidelines.md
- Move Home button from navbar to sidebar with exact URL matching
- Simplify layout meta tags to use static Coves branding
- Load legal/community guidelines from local markdown file
- Remove InstanceCard usage from layout, profile, and navbar
- Remove sidebar footer (version, source, donate links)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Thread loadFeed callback through PostListShell and VirtualFeed to
restore infinite scroll pagination on home and community pages. Add
auth error detection (401/403) that shows session-expired message
with login button. Improve feed robustness with null-safe responses,
cursor-based hasMore logic, and proper error re-throwing.
Changes:
- Add loadFeed prop to PostListShell and pass to VirtualFeed
- Create loadFeed functions in home and community page loaders
- Detect XrpcError 401/403 and show login prompt instead of retry
- Move loading=false to finally block in VirtualFeed
- Guard against null feed responses with ?? []
- Add empty state placeholder on home page
- Fix /communities link to /explore/communities
- Update empty feed description copy
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the Photon-era PascalCase sort mapping layer (Hot, TopDay, Subscribed,
etc.) and replace it with direct Coves API values (hot/new/top, discover/timeline).
Adds a timeframe parameter for top sort and introduces FeedTabs and SortMenu
components for the home feed.
Changes:
- Rewrite mapSort() to validate Coves sort/timeframe values directly
- Rewrite mapListing() for discover/timeline with auth guard
- Add CovesSortParams discriminated union for type-safe sort params
- Replace SortType/ListingType/CommentSortType with Coves-native literals
- Add timeframe field to settings.defaultSort
- Create FeedTabs.svelte (Discover/For You tab bar)
- Create SortMenu.svelte (sort type + timeframe dropdown)
- Update home page, community, and post routes to pass timeframe
- Make searchParam() async with error handling
- Add feed.discover/feed.forYou i18n keys
- Rewrite sort tests for Coves-native values
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate the voting UI from a dual up/down chevron system to a single
heart-based like/unlike toggle, aligning with the Coves social model.
Changes:
- Replace PostVote and CommentVote chevron buttons with AnimatedHeart
- Add AnimatedHeart.svelte with pop/circle-burst/particle animation
- Simplify computeVoteState to only handle 'up' direction (like toggle)
- Score now equals upvotes count (no downvote subtraction)
- Remove vote ratio bar, voteColor, and shouldShowVoteColor utilities
- Add dev-mode hostname normalization for ATProto OAuth cookie domain
- Extract validateProxyPath into dedicated validate.ts module
- Fix proxy body forwarding: use blob() instead of streaming to avoid
Node.js undici "expected non-null body source" errors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rebrand the forked Photon project to Kelp, the Coves web frontend.
This is standard practice after forking - users should see Coves/Kelp
branding, not the upstream Photon name.
Changes:
- Rename package from "photon-lemmy" to "kelp-coves"
- Update PWA manifest name/description for Kelp/Coves
- Rename photonify() to localizeLink() across codebase and tests
- Rename Photon icon export to Kelp, PHOTON_DEFAULT to KELP_DEFAULT
- Update all 17 i18n files (Photon -> Kelp, with proper declension)
- Update source links to tangled.org/bretton.dev/coves-frontend
- Rewrite README with Kelp identity and Photon attribution
- Fix NSID casing: getprofile -> getProfile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate user profiles from /u/[handle] to /profile/[handle=handle] with
a validated SvelteKit param matcher that accepts handles and DIDs while
rejecting reserved route segments. The old /u/[handle] route now
301-redirects, and the legacy /profile/user route is removed entirely.
Changes:
- Add handle param matcher validating handles/DIDs against reserved segments
- Move profile page + UserActions from /u/[handle] to /profile/[handle=handle]
- Add 301 redirect from /u/[handle] to /profile/[handle] for backwards compat
- Redirect /profile to /profile/{handle} for authenticated users, /login for guests
- Move profile tabs and auth guard into (local_user) layout group
- Update all navigation links (sidebar, navbar, command palette) to use new paths
- Fix API NSIDs: getCommunityFeed and getProfile to match backend
- Rewrite markdown link generation (photonify, linkify) from /u/ to /profile/
- Add tests for handle matcher, profile redirect, /u/ redirect, and photonify
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace client-side image optimization (query param thumbnail/format)
with the Coves backend image proxy system. The proxy serves images at
/img/{preset}/plain/{did}/{cid} with presets like avatar, banner,
content_preview, content_full, and embed_thumbnail.
Changes:
- Add image-proxy module with parseProxyUrl, withPreset, imageUrl helpers
- Add thumb/fullsize fields to EmbedImage type
- Widen embed $type discriminants to accept non-#view variants
- Migrate Avatar, MdImage, PostLink, PostIframe, PostImage,
PostMediaCompact to use proxy presets instead of query params
- Add onerror handlers for graceful image fallbacks
- Simplify <picture> srcset generation across components
- Make all embed type switches exhaustive with never checks
- Deprecate optimizeImageURL in favor of withPreset
- Add comprehensive tests for image-proxy module
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix sort parameter handling in the post route to use mapSort for consistency
with the Coves migration. Previously the raw URL parameter was passed directly
to the API, but after migrating to Coves XRPC, sort values need to be mapped
from legacy Lemmy format to the new format.
Also expanded .gitignore to exclude Playwright browser testing artifacts that
were being generated during development.
Changes:
- Import and use mapSort to transform legacy sort parameter
- Rename 'sort' variable to 'legacySort' for clarity
- Add .gitignore patterns for Playwright outputs (.playwright-output, *.png, console-*.txt, network-*.txt, *-snapshot.md)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Migrate remaining components from Lemmy/PieFed data model to Coves XRPC API,
focusing on moderation system, type guards, and post creation. This builds on
previous migration work to complete the transition to Coves-native types.
Changes:
- Refactor moderation system with Svelte 5 runes ($state) in moderation.svelte.ts
- Create ModerationModals.svelte for lazy-loading modal components
- Delete legacy moderation.ts and Moderation.svelte
- Migrate item type guards from item.ts to item.svelte.ts with Coves types
- Add backward-compatible type guards for legacy Lemmy data during transition
- Simplify PostForm by removing PieFed features (events, polls, extended data)
- Update contentview.ts to use AtUri and AuthorView instead of Lemmy types
- Refactor report.ts with placeholder types for pending Coves moderation API
- Update ~50 route files across admin, community, profile, and moderation areas
- Fix session, settings, sorting, and utility modules for Coves data model
- Mark deprecated functions that await Coves API implementation (save, favorites)
Breaking Changes:
- PostForm no longer supports events, polls, or PieFed-specific features
- Moderation API calls are stubs pending Coves backend implementation
- Save/favorite functions display warnings until Coves API is available
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Migrate the entire comment feature module (data model, tree logic, and
7 UI components) from Lemmy's flat path-based comment model to Coves'
server-computed ThreadViewComment tree structure with AT-URI identifiers.
Changes:
- Rewrite buildCommentsTree() to walk ThreadViewComment[] instead of
parsing flat path strings — delete getCommentParentId/getDepthFromComment
- Migrate CommentNodeI from comment_view (Lemmy) to comment (Coves CommentView)
- Add createOptimisticCommentView() for instant reply rendering
- Migrate CommentVote to call coves().createVote()/deleteVote() with
optimistic updates and rollback on error
- Migrate CommentForm to use StrongRef props and coves().createComment()
- Migrate CommentActions to use coves().deleteComment() and Coves types
- Remove @ts-nocheck from Comment, CommentItem, CommentVote
- Disable unavailable features in UI (save, report, moderation, edit)
- Temporarily simplify InboxItem comment rendering until inbox migration
- Add comprehensive unit tests for tree building, searching, and insertion
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restructure community and user routes from [name] to [handle] params,
migrate the home feed and explore pages to use Coves XRPC endpoints,
and introduce sort/listing mapping for the legacy Photon filter UI.
Changes:
- Replace /c/[name] and /u/[name] routes with /c/[handle] and /u/[handle]
- Add /c/[handle]/post/[rkey] route for clean post permalinks
- Migrate home feed to getTimeline()/getDiscover() XRPC calls
- Migrate explore communities to searchCommunities()/listCommunities()
- Add sort.ts mapping layer (legacy PascalCase -> Coves sort+timeframe)
- Add communitySlug()/communityHandleFromSlug() for c- prefix convention
- Add parseAtUri() for extracting did/collection/rkey from AT-URIs
- Fix postLink() to generate /c/{slug}/post/{rkey} URLs from AT-URIs
- Fix computeVoteState to clear voteUri on vote toggle-off
- Fix getSessionStorage to handle null/corrupted JSON gracefully
- Fix operator precedence bug in explore communities showTop filter
- Replace Feed generic `any` types with `unknown` + safe casts
- Widen community API params to accept DID | Handle
- Add @ts-nocheck markers to ~20 unmigrated legacy files
- Export ApiMeResponse from server session types
- Add error boundary with retry button to home feed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate post, community, user, and feed components to use Coves
ATProto types (PostView, CommunityView, AuthorView) instead of
legacy Lemmy types. This completes the data model migration for
the core UI layer.
Changes:
- API: add getPost() method, strengthen param types (string → DID/AtUri/Handle),
narrow $type literals, make ImageEmbed.images a non-empty tuple
- Utilities: add communityLink() and userLink() supporting both Coves
and legacy types, add isImage/isVideo explicit return types, make
fullCommunityName resilient to invalid URLs
- Post components: migrate Post, PostItem, PostLink, PostMeta, PostVote,
PostActions, PostActionsMenu, PostMedia, PostImage, PostMediaCompact
to use Coves PostView and embed types
- Post helpers: add embed extraction functions (extractEmbedUrl,
extractEmbedThumbnail, extractEmbedTitle, extractEmbedAlt),
computeVoteState(), mediaType() for Coves embeds
- Community components: migrate CommunityCard, CommunityHeader,
CommunityItem, CommunityItemBig, CommunityLink to CommunityView/
CommunityViewDetailed; add communityIdentifier/communityDisplayName helpers
- User components: migrate UserItem, UserLink to AuthorView;
remove legacy addSubscription
- Feed types: update FeedTypes to Coves response shapes; add Feed.error state
- Remove Lemmy-specific features: flair, NSFW badges, instance blocking,
banned_from_community, resolveObject
- Tests: add util.svelte.test.ts, helpers.test.ts; update client.test.ts
with branded types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use `new Headers(init?.headers)` instead of spreading into a plain
object, which silently drops all entries when the caller passes a
Headers instance
- Guard `await res.text()` in error paths with `.catch()` so a
secondary failure doesn't mask the original HTTP error
- Replace User-Agent string from "Photon" to "Coves"
- Remove no-op ternary `auth ?? (browser ? undefined : undefined)`
- Update stale TODO now that CovesClient exists
- Replace informal "forgor" comment on getClient with @deprecated JSDoc
- Update toProxyUrl JSDoc example to XRPC-style URL
- Clarify customFetch JSDoc to document that it throws SvelteKit error()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a complete XRPC transport layer and typed API client for the Coves
backend, replacing the need for Lemmy/PiFed adapters for Coves-native
endpoints.
Changes:
- Add XrpcClient with query (GET) and procedure (POST) methods that
parse structured XRPC error bodies into typed XrpcError instances
- Add CovesClient with typed methods for all 18 Coves API endpoints
(feed, comments, votes, actor, community, posts)
- Add covesCustomFetch that returns raw Response (unlike customFetch)
so XrpcClient can parse XRPC error bodies before throwing
- Add coves() factory function integrated with profile/proxy routing
- Strengthen types: add PostRecord, CommentRecord, CommunityVisibility
union type, and replace generic string types with literal unions
- Add 46 tests covering XRPC transport, client delegation, and type
validation utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract DID, Handle, and InstanceURL branded types from session.ts into
a shared $lib/types/atproto.ts module so both client and server code can
import them. Add comprehensive Coves API data model types derived from
Go backend structs to $lib/api/coves/types.ts.
Changes:
- Extract ATProto branded types + validators to $lib/types/atproto.ts
- Add Coves view types: posts, comments, communities, profiles
- Add embed discriminated union (images, external, video, record)
- Add request/response types for all XRPC endpoints
- Add AtUri and CID branded types with validators
- Update session.ts to re-export from shared module
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
isNetworkError no longer blanket-matches all TypeError instances — it
now requires a fetch/network keyword in the message, so programming bugs
(e.g. "Cannot read properties of undefined") surface as errors instead
of being silently retried as transient network failures.
parseApiMeResponse upgrades DID/handle validation failures from
console.warn to console.error so log aggregation tools will alert on
broken backend contracts. Avatar URL rejection remains console.warn.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, the frontend maintained its own encrypted session store
(kelp_session) with AES-256-GCM, managing account lists, active account
switching, and re-validating credentials locally. This duplicated auth
logic that the Go backend already handles.
The new model is stateless on the frontend:
- The Go backend sets `coves_session` (an opaque cookie) during OAuth
- hooks.server.ts validates every request by calling /api/me
- The frontend stores no user data locally — auth state comes entirely
from the server's response to /api/me
Changes:
- Remove AES-256-GCM session crypto (session.ts, cookies.ts)
- Simplify OAuth callback to just validate CSRF state and redirect
- Delete multi-account switch endpoint (/api/auth/switch)
- Rewrite hooks.server.ts to fetch /api/me with typed error handling
(network_error vs validation_error) and sessionExpired signaling
- Add authError and sessionExpired to locals/PageData types
- Simplify auth.svelte.ts: remove switchTo(), single-account syncFromServer()
- Update proxy to read authToken from flattened locals.auth.authToken
- Rename postform.svelte.ts -> post-form.svelte.ts
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhance ATProto OAuth with encrypted server-side sessions, eliminating
client-side token exposure for improved security.
Changes:
- Add encrypted session storage with AES-256-GCM (src/lib/server/session.ts)
- Add CSRF state validation for OAuth flow (src/lib/server/csrf.ts)
- Add API routes: /api/auth/{login,callback,logout,switch}
- Add API proxy that injects auth from session cookies
- Add discriminated union types for auth state (App.Locals)
- Add branded types: DID, Handle, InstanceURL, AccountId, SealedToken
- Update client to route requests through auth-injecting proxy
- Update hooks.server.ts to decrypt sessions into locals.auth
- Add Vitest configuration and comprehensive test coverage
- Remove client-side OAuth callback (now server-side)
- Remove legacy Lemmy password management pages
Security improvements:
- Tokens never exposed to browser JavaScript
- Session cookies encrypted with AES-256-GCM
- CSRF protection via OAuth state parameter
- Open redirect prevention in login flow
- Path traversal protection in API proxy
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace Lemmy username/password authentication with ATProto's OAuth flow
for the Coves migration. This removes legacy Lemmy-specific code and
simplifies the auth model for ATProto's identity system.
Changes:
- Add /oauth/callback route for handling OAuth redirects
- Rewrite login page for handle-based OAuth initiation
- Update ProfileInfo to store ATProto fields (did, sessionId, handle)
- Add automatic token refresh with 401 retry in API client
- Remove Lemmy-specific code (cookie migration, donation polling)
- Stub legacy subscription/favorites APIs with migration TODOs
- Remove inbox notification badges pending Coves API
- Fix localStorage error handling and type safety
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prepare codebase for migration to Coves backend by excluding legacy code from
type checking while fixing remaining TypeScript errors in active code.
Changes:
- Exclude legacy markdown, piefed, and lemmy/adapter from tsconfig and eslint
- Add @ts-nocheck to legacy files pending migration
- Update pnpm check to use --diagnostic-sources and --threshold error
- Fix Button.svelte Props interface to use explicit props with index signature
- Update UserAutocomplete.onselect to accept optional Person
- Add Icon prop type declarations to app.d.ts
- Remove unused props from CommentItem, ProfileButton, RemoveModal
- Fix CommunityLink Icon title accessibility (wrap in span)
- Replace deprecated preventDefault import in ImagePreviewInput
- Add class prop to Tabs and PostIframe components
- Use $derived instead of $state for derived values in saved/signup pages
- Add DEFAULT_CLIENT_TYPE to validateInstance calls
- Fix route paths to consistently use [id=integer] matcher
- Simplify navigation using template literals
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Configure Claude Code for the Kelp (Coves Frontend) project with
project-specific instructions, hooks, and custom commands.
Changes:
- Add CLAUDE.md with project context, tech stack, and coding guidelines
- Configure Svelte MCP plugin for Svelte 5 development
- Add PostToolUse hook for auto-formatting .svelte/.ts/.js files
- Add /merge-to-main custom command for streamlined git workflow
- Configure local permissions for grep operations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>