fierceX/tiddly-wiki-server

An efficient, low-maintenance web server for TiddlyWikis.

★ 0Forks 0HTMLGitHub ↗Compare

README

TiddlyWiki Server (Rust Enhanced)

Contributor Covenant Rust Version License

简体中文

This is an efficient, low-maintenance, and feature-rich web server for TiddlyWiki. It is a fork of the original tiddly-wiki-server, rewritten in Rust to provide better performance, file management, cloud integration, and quick capture capabilities.

It uses the web server API provided by the TiddlyWeb plugin to save tiddlers in a SQLite database, while smartly offloading binary files to local storage or S3-compatible cloud storage.

Key Improvements & Features

Compared to the original implementation, this fork includes significant enhancements:

🚀 Performance & Rendering

  • Optimized Wiki Rendering: Dynamically injects tiddlers into empty.html via efficient memory splitting.
  • Low Footprint: Runs with approx. 10MB RAM, compared to 70MB+ for the standard NodeJS server.

📖 Integrated EPUB Reader

  • Direct Reading: Embeds a custom Foliate-js reader directly into the server binary.
  • Seamless UX: Automatically detects application/epub+zip tiddlers (via _canonical_uri) and renders them in a modern reading interface, replacing the default "Binary file" warning.
  • S3 & Local Support: Streams EPUB files directly from S3 or local storage without requiring full downloads first.
  • Note on CSP: This embedded reader does not perform client-side Content Security Policy (CSP) sanitization. If you are importing EPUBs generated by tools like Readeck that inject strict CSP meta tags, please ensure you clean/sanitize the files before uploading.

☁️ Smart Storage (S3 & Local)

  • Local File Offloading: Binary files (images, PDFs) are kept out of the SQLite database to ensure speed. They are stored in files/, and Tiddlers simply reference them via _canonical_uri.
  • S3/R2 Direct Upload:
    • Generates pre-signed URLs for secure, direct browser-to-cloud uploads.
    • Saves server bandwidth and supports huge files.
  • Metadata-Driven Robustness: Tiddlers store storage metadata (Bucket, Key, Region) directly in their fields (_s3_key, etc.). This means file management remains accurate even if server configurations change.
  • Cascade Delete: When you delete a Tiddler in the Wiki, the server automatically cleans up the corresponding file on S3 or the local disk. No more orphaned files!

🔒 Security & Auth

  • Basic Authentication: Built-in HTTP Basic Auth middleware to protect your wiki on public networks.
  • Authorization Headers: Supports standard Authorization headers for API integration.

📥 Quick Capture (Inbox)

  • A specialized Webhook endpoint (/api/inbox) designed for mobile automation.
  • Easily integrates with iOS Shortcuts or Android HTTP Shortcuts to capture thoughts instantly without loading the full interface.

Configuration

Create a config.toml file in the working directory.

Security Note: When using Basic Auth, it is highly recommended to run this server behind a reverse proxy (like Nginx/Caddy) with HTTPS enabled.

[server]
bind = "0.0.0.0"
port = 3032
db_path = "./data/tiddlers.sqlite3"
files_dir = "./files/"

# Display name for edits in the Wiki
[status]
username = "YourName" 

# [Optional] HTTP Basic Authentication
[auth]
username = "admin"
password = "change_me_please"

[s3]
enable = true
name = "r2"
access_key = "YOUR_AWS_ACCESS_KEY"
secret_key = "YOUR_AWS_SECRET_KEY"
endpoint = "https://<ACCOUNT_ID>.r2.cloudflarestorage.com"
region = "auto"
bucket_name = "your-wiki-assets"
public_url_base = "https://assets.your-domain.com"

Quick Capture API (Inbox)

Capture thoughts from external tools without opening the wiki.

  • Endpoint: POST /api/inbox
  • Content-Type: application/json

JSON Payload

{
  "text": "This is a quick thought captured from my phone.",
  "tags": "idea mobile" 
}

tags is optional. Default: "Inbox".

iOS / Android Shortcut Example

  • URL: https://your-wiki.com/api/inbox
  • Method: POST
  • Headers: Authorization: Basic <Base64_Credentials>
  • Body: JSON (Pass clipboard or input as text)

Captured items will appear in your Wiki with the tag Inbox and a timestamped title.

Installation & Running

  1. Build:
    cargo build --release
  2. Run: Ensure config.toml and empty.html are in the directory.
    ./target/release/tiddly-wiki-server --config config.toml

Development: Plugins & Assets

This server embeds custom TiddlyWiki plugins and static assets (like the reader). You can modify them as follows:

1. S3 Uploader Plugin

Handles drag-and-drop uploads to S3/Local storage.

  • Source: s3_uploader/
  • Repack Command:
    cargo run --bin pack_plugin -- ./s3_uploader/manifest.json ./s3_uploader_plugin.json

2. EPUB Viewer Plugin

Handles the TiddlyWiki UI integration for EPUB files.

  • Source: epub_plugin/
  • Repack Command:
    cargo run --bin pack_plugin -- ./epub_plugin/manifest.json ./epub_viewer_plugin.json

3. Foliate Reader (Embedded Static Assets)

The actual reader engine is a customized build of Foliate-js, embedded directly into the server binary.

  • Source: web/foliate-js/ (Contains the modified source code)
  • Build Artifacts: web/foliate/ebook_reader/ (The optimized static files embedded by Rust)
  • To Update: If you modify the reader's source code, you must rebuild the frontend assets before rebuilding the Rust server:
    cd web/foliate-js
    npm install
    npx vite build
    # Ensure the output is in ./ebook_reader and includes reader.html

After modifying any plugin or asset, run cargo build to embed the new versions into the server executable.

Agent-Friendly API & Python Library

The server provides REST APIs designed for AI Agents and automation, plus a Python wrapper library and CLI.

Python Library wiki_client

Located at tools/wiki_client/. Requires requests:

pip install requests
from wiki_client import WikiClient

wiki = WikiClient(
    base_url="http://localhost:3032",
    username="admin",
    password="change_me_please",
)

# Search with Chinese word segmentation
results = wiki.search("天气", mode="fts")

# Regex search (Agent-friendly)
results = wiki.search(r"observ\w+tion", mode="regex")

# Get / Put / Inbox / List / Delete
tiddler = wiki.get("My Title")
wiki.put("New Tiddler", content="Body", tags="tag1,tag2")
wiki.inbox("Quick Note", content="From mobile", tags=["idea"])
wiki.list(tag="Inbox", limit=10)
wiki.delete("Tiddler")

# Links and backlinks
links = wiki.links("Some Title")          # → ["linked 1", "linked 2"]
backlinks = wiki.backlinks("Some Title")  # → ["referrer 1", ...]

# All tags
tags = wiki.tags()  # → [{"tag": "cognition", "count": 41}, ...]

# Unlimited results with limit=0
wiki.search("weather", limit=0)           # all results
wiki.list(tag="Inbox", limit=0)           # all inbox items

# Time-range filtering (YYYYMMDDHHMMSSmmm format)
wiki.search("", created_after="20251201000000000", limit=0)
wiki.search("", modified_after="20260501000000000", tag="cognition", full=True)

Search Modes

Mode Description Performance
fts (default) FTS5 + jieba Chinese tokenization, prefix matching O(log N)
regex Full regex via Rust regex crate O(N)

CLI Tool wiki_cli.py / wiki (Rust)

Two implementations available. Rust version recommended (zero dependencies, faster startup):

# Build the Rust CLI (one time)
cargo build --bin wiki
# Now use it directly:
./target/debug/wiki search "weather" --full --limit 5

# Rust (recommended)
wiki search "weather" --full --limit 5
wiki search ".*observation.*" --mode regex
wiki get "My Title" --text-only
wiki put "New Tiddler" --content "body" --tags "tag1,tag2"
wiki inbox "Quick Note" --content "body" --tags "idea,mobile"
wiki list --tag Inbox --limit 10
wiki list --tag Inbox --limit 0 --plain
wiki delete "Tiddler" --force
wiki links "Some Title"
wiki backlinks "Some Title"
wiki batch-links "Title1" "Title2" --plain
wiki graph "Some Title" --depth 2 --plain
wiki tags
wiki tags --plain
wiki changes
wiki changes --since 7d
wiki changes --since 20260501 --tag cognition --plain

# Python (fallback)
python3 tools/wiki_cli.py search "weather" --full --limit 5
python3 tools/wiki_cli.py search ".*observation.*" --mode regex
python3 tools/wiki_cli.py get "My Title" --text-only
python3 tools/wiki_cli.py put "New Tiddler" --content "body" --tags "tag1,tag2"
python3 tools/wiki_cli.py inbox "Quick Note" --content "body" --tags "idea,mobile"
python3 tools/wiki_cli.py list --tag Inbox --limit 10
python3 tools/wiki_cli.py list --tag Inbox --limit 0 --plain
python3 tools/wiki_cli.py delete "Tiddler" --force
python3 tools/wiki_cli.py links "Some Title"
python3 tools/wiki_cli.py backlinks "Some Title"
python3 tools/wiki_cli.py batch-links "Title1" "Title2" --plain
python3 tools/wiki_cli.py graph "Some Title" --depth 2 --plain
python3 tools/wiki_cli.py tags
python3 tools/wiki_cli.py tags --plain
python3 tools/wiki_cli.py changes
python3 tools/wiki_cli.py changes --since 7d
python3 tools/wiki_cli.py changes --since 20260501 --tag cognition --plain

REST API Endpoints

Endpoint Method Description
/api/search?q=keyword&mode=fts&tag=Inbox&limit=20 GET Search (supports modified_after/before, created_after/before)
/api/tiddlers?title=title GET Get tiddler (no URL-encoding)
/api/tags GET All tags with counts
/recipes/default/tiddlers.json GET List all
/api/tiddlers/tag/{tag} GET List by tag (supports time range params)
/api/tiddlers/{title}/links GET Forward links
/api/tiddlers/{title}/backlinks GET Backlinks
/recipes/default/tiddlers/{title} PUT Create / update
/api/inbox POST Inbox capture
/api/inbox GET List inbox
/bags/default/tiddlers/{title} DELETE Delete
/status GET Server status

License

This project is made available under [The Prosperity Public License 3.0.0].

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Code of Conduct

Contributors are expected to abide by the Contributor Covenant.

Contributors

nathanielknightfierceXgitter-badger

Issues