No description
- TypeScript 97.7%
- Dockerfile 2.3%
- Import markdown from @fedify/botkit/text (not main export) - Build markdown string with **bold** labels and [link](url) syntax - Use two-space line breaks (markdown standard) for <br> tags - Properly renders: bold labels, line breaks, and clickable links - Output in ActivityPub: <strong> tags, <br> breaks, <a> links - Clean, maintainable code with single markdown string |
||
|---|---|---|
| src | ||
| .dockerignore | ||
| .gitignore | ||
| AGENTS.md | ||
| deno.json | ||
| deno.lock | ||
| docker-compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
fediCal
A Fediverse bot that announces events and generates personalized iCal feeds.
Features
- 📅 Announces events to the Fediverse
- ⭐ Tracks interactions - star or boost events you're interested in
- 📆 Generates iCal feeds personalized to each user
- 🤖 Auto-welcomes new followers with their unique calendar URL
- 🔒 Privacy-focused - deletes all your data when you unfollow
Architecture
- Runtime: Deno (TypeScript native, URL imports, built-in testing)
- Framework: BotKit (Fedify-based ActivityPub framework)
- Database: SQLite (simple, serverless, sufficient for use case)
- Web Server: Single port for all endpoints (ActivityPub + API + iCal)
Getting Started
Prerequisites
- Deno 2.0+
Installation
git clone https://wuecode.it/stesie/fedical.git
cd fedical
Configuration
Create a .env file or set environment variables (12-factor app):
# Bot configuration
BOT_HANDLE=bot # Fediverse handle (without @domain)
BOT_DOMAIN=fedical.example.com # Your domain
BOT_PORT=8000 # HTTP port
# Admin API
ADMIN_TOKEN=YOUR_SECURE_TOKEN # Required for event ingestion/deletion
# Storage
DATA_DIR=./data # SQLite database directory
Running
Development:
deno task dev
Production:
deno run --allow-net --allow-read --allow-write --allow-env --unstable-temporal src/main.ts
API
Event Ingestion
Announce a new event or update an existing one:
curl -X POST "http://localhost:8000/api/events" \
-F "token=YOUR_SECURE_TOKEN" \
-F "url=https://example.com/event.json"
The JSON should follow Schema.org Event format (JSON-LD).
Response:
{
"success": true,
"eventId": "http://example.com/event-123",
"isNew": true,
"announced": true,
"updated": false
}
announced: Event was announced to Fediverse (new events with startDate + time only)updated: Existing announcement was updated
Event Deletion
Remove an event and its announcement:
curl -X DELETE "http://localhost:8000/api/events" \
-F "token=YOUR_SECURE_TOKEN" \
-F "url=https://example.com/event.json"
Event Format
Events must be valid Schema.org Event JSON-LD:
{
"@context": "http://schema.org",
"@type": "Event",
"@id": "unique-event-id",
"name": "Concert Name",
"description": "Event description",
"startDate": "2026-05-20T20:00:00",
"endDate": "2026-05-20T23:00:00",
"location": {
"@type": "Place",
"name": "Venue Name"
},
"url": "https://example.com/event"
}
Announcement Rules
Events are announced to the Fediverse if:
- ✅ They have a startDate with time component (ISO 8601 with 'T')
- ✅ They are not cancelled or rescheduled
- ✅ They don't have subEvents (parent events with multiple dates)
Events are stored but not announced if they have subEvents (to avoid duplicate announcements).
Database
SQLite database with three main tables:
- events: Event metadata and raw JSON
- actors: Follower information with unique iCal tokens
- interactions: User star/boost interactions
Data is automatically deleted when users unfollow the bot.
License
MIT License - See LICENSE file for details.
Contributing
Contributions welcome! Please feel free to submit a Pull Request.