a standard.site publication renderer for SvelteKit.
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 212 lines 6.2 kB view raw view rendered
1# CLAUDE.md 2 3## What 4 5SvelteKit library for ATProto longform publishing via the `standard.site` lexicon. Provides both read and write capabilities: display content from ATProto (Leaflet/WhiteWind), publish content TO ATProto, and aggregate federated comments. 6 7**Package:** `svelte-standard-site` 8 9## Project Structure 10 11``` 12src/lib/ 13 client.ts # Read from ATProto (fetch documents/publications) 14 publisher.ts # Write to ATProto (publish documents/publications) 15 schemas.ts # Zod schemas for validation 16 types.ts # TypeScript type definitions 17 components/ 18 Comments.svelte # Federated comments from Bluesky 19 DocumentCard.svelte 20 PublicationCard.svelte 21 StandardSiteLayout.svelte 22 ThemeToggle.svelte 23 common/ # Reusable utility components 24 document/ # Document rendering components 25 utils/ 26 content.ts # Markdown transformation (sidenotes, links, etc.) 27 comments.ts # Fetch Bluesky replies 28 verification.ts # Ownership verification helpers 29 at-uri.ts # AT-URI parsing and conversion 30 theme.ts # Theme utilities 31 cache.ts # Caching layer 32 stores/ 33 theme.ts # Dark/light mode store 34 styles/ 35 base.css # Core design system 36 themes.css # Theme definitions 37``` 38 39## Commands 40 41```bash 42pnpm dev # Start dev server 43pnpm build # Build package 44pnpm test # Run tests 45pnpm check # Type check 46``` 47 48## Critical: TID Format 49 50Record keys for `site.standard.document` and `site.standard.publication` MUST be TIDs. Schema validation will reject anything else. 51 52**TID requirements:** 53- 13 characters, base32-sortable charset: `234567abcdefghijklmnopqrstuvwxyz` 54- First char must be `234567abcdefghij` (top bit = 0) 55- Regex: `/^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$/` 56 57See `generateTid()` in `src/lib/publisher.ts` — do not modify without reading https://atproto.com/specs/tid 58 59## Critical: ES Modules 60 61`package.json` must have `"type": "module"`. Without this, imports break. 62 63## Key Concepts 64 65### Read vs Write 66 67- **SiteStandardClient** (`client.ts`): Read-only. Fetches content from ATProto. 68- **StandardSitePublisher** (`publisher.ts`): Write operations. Publishes content to ATProto. 69 70### Content Transformation 71 72The `content.ts` utilities transform markdown for ATProto compatibility: 73- Convert HTML sidenotes → markdown blockquotes 74- Resolve relative links → absolute URLs 75- Extract plain text for search indexing 76- Calculate word count and reading time 77 78### Comments System 79 80The Comments component fetches Bluesky replies and displays them as comments on blog posts. It uses the ATProto API to recursively fetch threaded conversations. 81 82### Verification 83 84Verification helpers generate `.well-known` endpoints and `<link>` tags to prove content ownership. This allows platforms to verify that you control the content you've published. 85 86## Testing Against Real PDS 87 88```bash 89# Set your app password 90export ATPROTO_APP_PASSWORD="xxxx-xxxx-xxxx-xxxx" 91 92# Run publisher test 93node scripts/test-publisher.js 94``` 95 96For integration testing, use `pds.rip` (throwaway test accounts). 97 98## Design System 99 100The library uses semantic color tokens that automatically adapt to light/dark mode: 101 102- **Ink**: Text colors (ink-50 to ink-950) 103- **Canvas**: Background colors (canvas-50 to canvas-950) 104- **Primary**: Brand colors (primary-50 to primary-950) 105- **Secondary**: Secondary brand (secondary-50 to secondary-950) 106- **Accent**: Accent colors (accent-50 to accent-950) 107 108All styled using Tailwind v4 with `light-dark()` function. 109 110## Publishing to ATProto 111 112```typescript 113import { StandardSitePublisher } from 'svelte-standard-site/publisher'; 114 115const publisher = new StandardSitePublisher({ 116 identifier: 'you.bsky.social', 117 password: process.env.ATPROTO_APP_PASSWORD!, 118}); 119 120await publisher.login(); 121 122await publisher.publishDocument({ 123 site: 'https://yourblog.com', 124 title: 'My Post', 125 publishedAt: new Date().toISOString(), 126 content: { 127 $type: 'site.standard.content.markdown', 128 text: markdownContent, 129 version: '1.0', 130 }, 131 textContent: plainTextContent, 132}); 133``` 134 135## Reading from ATProto 136 137```typescript 138import { createClient } from 'svelte-standard-site'; 139import { getConfigFromEnv } from 'svelte-standard-site/config/env'; 140 141const config = getConfigFromEnv(); 142const client = createClient(config); 143 144const documents = await client.fetchAllDocuments(fetch); 145const publications = await client.fetchAllPublications(fetch); 146``` 147 148## Comments 149 150```svelte 151<script> 152 import { Comments } from 'svelte-standard-site'; 153</script> 154 155<Comments 156 bskyPostUri="at://did:plc:xxx/app.bsky.feed.post/abc123" 157 canonicalUrl="https://yourblog.com/posts/my-post" 158 maxDepth={3} 159/> 160``` 161 162## Content Transformation 163 164```typescript 165import { transformContent } from 'svelte-standard-site/content'; 166 167const result = transformContent(rawMarkdown, { 168 baseUrl: 'https://yourblog.com', 169}); 170 171// result.markdown - cleaned for ATProto 172// result.textContent - plain text for search 173// result.wordCount 174// result.readingTime 175``` 176 177## Verification 178 179```typescript 180// src/routes/.well-known/site.standard.publication/+server.ts 181import { generatePublicationWellKnown } from 'svelte-standard-site/verification'; 182import { text } from '@sveltejs/kit'; 183 184export function GET() { 185 return text( 186 generatePublicationWellKnown({ 187 did: 'did:plc:xxx', 188 publicationRkey: '3abc123xyz', 189 }) 190 ); 191} 192``` 193 194## Important Notes 195 1961. **App Passwords**: Always use app passwords, never main account passwords 1972. **PDS Resolution**: The publisher auto-resolves PDS from DID documents 1983. **Caching**: The client has built-in caching (5-minute TTL by default) 1994. **SSR**: All fetch operations support SvelteKit's `fetch` for SSR 2005. **Theme Store**: Call `themeStore.init()` in `onMount()` to enable theme toggle 2016. **Blob URLs**: Cover images and icons are converted from blob refs to HTTPS URLs 202 203## External References 204 205- ATProto specs: https://atproto.com/ 206- standard.site: https://standard.site/ 207- Lexicon explorer: https://pdsls.dev/ 208- Bluesky: https://bsky.app/ 209 210## License 211 212AGPL-3.0 (stricter than Astro version's MIT)