···46 ./target/release/pai serve -d /var/lib/pai/pai.db -a 127.0.0.1:8080
47 ```
4849+### CORS Configuration for Self-Hosted Server
50+51+The HTTP server supports CORS configuration via `config.toml`. Add a `[cors]` section:
52+53+```toml
54+[cors]
55+# List of allowed origins for cross-origin requests
56+allowed_origins = ["https://desertthunder.dev", "http://localhost:4321"]
57+58+# Optional development key for local testing
59+dev_key = "your-secret-dev-key"
60+```
61+62+CORS features:
63+64+- **Exact matching**: `http://localhost:4321` only allows that specific origin
65+- **Same-root-domain**: `https://desertthunder.dev` also allows `https://pai.desertthunder.dev`, `https://api.desertthunder.dev`, etc.
66+- **Dev key**: Requests with `X-Local-Dev-Key` header matching the configured key bypass origin checks
67+68+The PAI server handles CORS automatically - no additional proxy configuration needed. See [README.md](./README.md#cors-configuration) for details.
69+70## nginx Deployment
7172### Host Setup
···330331# BearBlog publications (comma-separated id:url pairs)
332BEARBLOG_URLS = "desertthunder:https://desertthunder.bearblog.dev"
333+334+# CORS configuration (optional)
335+CORS_ALLOWED_ORIGINS = "https://desertthunder.dev,http://localhost:4321"
336+CORS_DEV_KEY = "your-secret-dev-key"
337```
338+339+### CORS Configuration
340+341+The Worker supports CORS to allow cross-origin requests from your web applications.
342+343+#### Environment Variables
344+345+Add to `wrangler.toml` under `[vars]`:
346+347+- **CORS_ALLOWED_ORIGINS**: Comma-separated list of allowed origins
348+ - Supports exact matching: `http://localhost:4321` only allows that exact origin
349+ - Supports same-root-domain: `https://desertthunder.dev` also allows `https://pai.desertthunder.dev`, `https://api.desertthunder.dev`, etc.
350+351+- **CORS_DEV_KEY**: Optional development key for local testing
352+ - When set, requests with the `X-Local-Dev-Key` header matching this value bypass origin checking
353+ - Useful for testing from different local ports during development
354+355+#### Example Configuration
356+357+```toml
358+[vars]
359+# Allow requests from your main domain and localhost for development
360+CORS_ALLOWED_ORIGINS = "https://desertthunder.dev,http://localhost:4321"
361+362+# Dev key for local Astro development
363+CORS_DEV_KEY = "local-dev-secret-123"
364+```
365+366+#### Usage from JavaScript
367+368+```javascript
369+// Production request from https://desertthunder.dev
370+fetch('https://pai.desertthunder.dev/api/feed', {
371+ credentials: 'include'
372+})
373+374+// Development request from http://localhost:4321
375+fetch('http://localhost:8787/api/feed', {
376+ headers: {
377+ 'X-Local-Dev-Key': 'local-dev-secret-123'
378+ }
379+})
380+```
381+382+#### Same-Root-Domain Support
383+384+When you configure `CORS_ALLOWED_ORIGINS = "https://desertthunder.dev"`:
385+386+- ✓ `https://desertthunder.dev` (exact match)
387+- ✓ `https://pai.desertthunder.dev` (subdomain)
388+- ✓ `https://api.desertthunder.dev` (subdomain)
389+- ✗ `https://evil.dev` (different root domain)
390+391+This allows you to deploy the Worker to `pai.desertthunder.dev` and access it from your main site at `desertthunder.dev` without explicitly listing every subdomain.
392393### API Endpoints
394
+76-1
README.md
···6970See [config.example.toml](./config.example.toml) for a complete example with all available options.
7100000000000000000000000000000000000000000000000000000000000000000000000000072## Documentation
7374- CLI synopsis: `pai -h`, `pai <command> -h`, or `pai man` for the generated `pai(1)` page.
75-- `pai man --install [--install-dir DIR]` copies `pai.1` into a MANPATH directory (defaults to `~/.local/share/man/man1`) so `man pai` works like any other UNIX tool.
76- Database schema and config reference: [config.example.toml](./config.example.toml).
77- Deployment topologies: [DEPLOYMENT.md](./DEPLOYMENT.md).
78
···6970See [config.example.toml](./config.example.toml) for a complete example with all available options.
7172+<details>
73+<summary>
74+CORS Configuration
75+</summary>
76+77+Both the HTTP server and Cloudflare Worker support CORS configuration to allow cross-origin requests from your web applications.
78+79+### HTTP Server (config.toml)
80+81+ Add a `[cors]` section to your config file:
82+83+ ```toml
84+ [cors]
85+ allowed_origins = ["https://desertthunder.dev", "http://localhost:4321"]
86+ dev_key = "your-secret-dev-key"
87+ ```
88+89+ Configuration options:
90+91+- **allowed_origins**: List of allowed origins. Supports:
92+ - Exact match: `http://localhost:4321` only allows that exact origin
93+ - Same-root-domain: `https://desertthunder.dev` also allows `https://pai.desertthunder.dev`, `https://api.desertthunder.dev`, etc.
94+- **dev_key**: Optional development key for local testing.
95+ When set, requests with the `X-Local-Dev-Key` header matching this value are allowed regardless of origin.
96+97+### Cloudflare Worker (Environment Variables)
98+99+ Configure CORS via environment variables in `wrangler.toml`:
100+101+ ```toml
102+ [vars]
103+ CORS_ALLOWED_ORIGINS = "https://desertthunder.dev,http://localhost:4321"
104+ CORS_DEV_KEY = "your-secret-dev-key"
105+ ```
106+107+- **CORS_ALLOWED_ORIGINS**: Comma-separated list of allowed origins
108+- **CORS_DEV_KEY**: Optional development key (same behavior as HTTP server)
109+110+#### Local Development with X-LOCAL-DEV-KEY
111+112+For local development from Astro or other frameworks:
113+114+1. Add a `dev_key` to your CORS config:
115+116+ ```toml
117+ [cors]
118+ allowed_origins = ["http://localhost:4321"]
119+ dev_key = "local-dev-secret-123"
120+ ```
121+122+2. Include the header in your API requests:
123+124+ ```javascript
125+ fetch('http://localhost:8080/api/feed', {
126+ headers: {
127+ 'X-Local-Dev-Key': 'local-dev-secret-123'
128+ }
129+ })
130+ ```
131+132+ The dev key header bypasses origin checking, useful for testing from different local ports or during development.
133+134+#### Same-Root-Domain Support
135+136+ If you configure `allowed_origins = ["https://desertthunder.dev"]`, requests from:
137+138+- `https://desertthunder.dev` ✓ (exact match)
139+- `https://pai.desertthunder.dev` ✓ (subdomain of allowed root)
140+- `https://api.desertthunder.dev` ✓ (subdomain of allowed root)
141+- `https://evil.dev` ✗ (different root domain)
142+143+ This allows you to deploy the API at `pai.desertthunder.dev` and access it from your main site at `desertthunder.dev` without explicitly listing every subdomain.
144+145+</details>
146+147## Documentation
148149- CLI synopsis: `pai -h`, `pai <command> -h`, or `pai man` for the generated `pai(1)` page.
150+- `pai man --install [--install-dir DIR]` copies `pai.1` into a MANPATH directory (defaults to `~/.local/share/man/man1`)
151- Database schema and config reference: [config.example.toml](./config.example.toml).
152- Deployment topologies: [DEPLOYMENT.md](./DEPLOYMENT.md).
153
···19d1_binding = "DB"
20database_name = "personal_activity_db"
2122+# CORS configuration for HTTP server (optional)
23+[cors]
24+# List of allowed origins for cross-origin requests
25+# Supports exact match and same-root-domain matching
26+# Example: "https://desertthunder.dev" allows pai.desertthunder.dev, api.desertthunder.dev, etc.
27+allowed_origins = ["https://desertthunder.dev", "http://localhost:4321"]
28+29+# Optional development key for local testing
30+# When set, requests with X-Local-Dev-Key header matching this value are allowed
31+dev_key = "your-secret-dev-key-change-this"
32+33# Substack RSS feed source
34[sources.substack]
35enabled = true
···36# Format: "id1:https://blog1.bearblog.dev,id2:https://blog2.bearblog.dev"
37BEARBLOG_URLS = "desertthunder:https://desertthunder.bearblog.dev"
3839+# CORS configuration (optional)
40+# Comma-separated list of allowed origins for cross-origin requests
41+# Supports exact match and same-root-domain matching
42+# Example: "https://desertthunder.dev" allows pai.desertthunder.dev, api.desertthunder.dev, etc.
43+CORS_ALLOWED_ORIGINS = "https://desertthunder.dev,http://localhost:4321"
44+45+# Optional development key for local testing
46+# When set, requests with X-Local-Dev-Key header matching this value are allowed
47+CORS_DEV_KEY = "your-secret-dev-key-change-this"
48+49# Optional: Logging level
50# LOG_LEVEL = "info"
51