Skip to content

htlin222/team-plus-server

Repository files navigation

team-plus-server

Own your TeamPlus history — capture every message (and image, and file) into your own cloud database, queryable from anywhere. No laptop required.

License: MIT Cloudflare Workers Turso TypeScript Python last commit

Self-hosted tooling around a TeamPlus account:

  1. Cloud archive — an always-on Cloudflare Worker that captures every message into your own Turso (SQLite) database, so you have a private, queryable log of who said what, when, where — DMs, groups, and bots — without keeping a laptop running.
  2. Read & reply from the CLI — Claude Code skills (dms, fetch-hx) and small Node scripts read your history and send messages, straight over TeamPlus's authenticated REST endpoints or through the worker.

Everything talks to TeamPlus over the same authenticated WebSocket + REST endpoints. The TeamPlus instance URL is configured via TEAMPLUS_BASE; nothing about a specific organisation is baked into the source.

Heads-up: TeamPlus has no public API. This drives the same endpoints the web client uses, authenticated with session cookies you refresh yourself. Use it only with your own account and within your organisation's policies.

Features

  • 🗄️ Cloud message archive — a Durable Object holds the TeamPlus WebSocket and writes every message to Turso: who, when, which chat, direction, content. DMs, groups, and bots.
  • 🏷️ Name resolution — numeric sender/chat IDs are resolved to real names via the TeamPlus REST API (cached per session).
  • 🖼️ Attachment archive — images and files are downloaded and stored in R2; rich flex cards are kept as JSON.
  • 🔗 Time-limited viewer links — signed, browser-openable URLs for any attachment that the worker hard-caps to expire within a week.
  • 🔑 Read APIGET /v1/logs returns recent messages as JSON (default 24h, up to 7 days), gated by a shareable read-only key. Browse from the CLI with ./scripts/logs.mjs (see the Playbook).
  • ✉️ Send from anywhere./scripts/send.mjs --to <userNo> --text "…" sends a TeamPlus DM (or group message) through the worker, no local process required.
  • 🤖 Claude Code skillsdms triages your inbox (read, draft, send, ignore lists); fetch-hx jumps straight to one person's or group's recent thread by name.
  • ♻️ Self-healing — the Durable Object reconnects on drops, with a cron keepalive as backstop.
  • ☁️ No laptop required — cookie refresh runs as a GitHub Actions cron.

Architecture

                          ┌─────────────────────────────┐
   your TeamPlus account  │  TeamPlus (TEAMPLUS_BASE)    │
                          └───────────┬─────────────────┘
              WebSocket + REST (session cookies)
                          ┌───────────┴───────────────────┐
            ┌─────────────▼──────────┐   ┌────────────────▼────────────┐
            │ scripts/ + .claude/    │   │ worker/  (Cloudflare Worker)│
            │ • dms / fetch-hx skills│   │ • Durable Object holds the  │
            │ • logs.mjs (read API)  │   │   cookie + WS, self-heals   │
            │ • send.mjs (cloud send)│   │ • normalises every message  │
            │ • cookie refresh (OCR) │   │ • resolves sender/chat names│
            └────────────────────────┘   │ • Turso + R2 attachments    │
                                          └─────────────┬───────────────┘
                                                        │
                                                  Turso (SQLite)
                                          who / when / where / what

The cloud archive needs no local process once deployed; the only recurring task is re-uploading fresh cookies (~daily), which a GitHub Actions cron handles for you. The CLI scripts and skills read that same archive and send replies on demand.

The retired Telegram-bridge daemon (a Bun process that mirrored messages to a Telegram bot and drafted replies) is preserved under archive/telegram-bridge/ for reference; it is no longer part of the setup.

Repo layout

Path What
worker/ Cloudflare Worker + Durable Object → Turso archive (see worker/README.md)
scripts/ Cookie refresh (Patchright + Tesseract OCR), signed upload, logs.mjs/send.mjs/attachment_url.mjs/cf_worker_request.mjs helpers
docs/ Operations playbook — querying logs, monitoring, key rotation, troubleshooting
.claude/ dms + fetch-hx skills for reading and replying from Claude Code
Makefile make refresh (cookie capture) + make setup-creds
archive/ telegram-bridge/ — the retired Telegram bridge daemon, kept for reference

Prerequisites

  • Node.js + pnpm — runs the worker tooling and CLI scripts
  • Python 3 — cookie refresh (a venv is bootstrapped automatically)
  • Tesseract — captcha OCR (brew install tesseract)
  • For the cloud archive: wrangler, the turso CLI, and a Cloudflare + Turso account

Setup

# 1. Configuration
cp .env.example .env          # set TEAMPLUS_BASE + your TeamPlus login

# 2. First cookie capture (also fills my_id in .config.json)
make refresh                  # headless login + OCR; ./scripts/refresh.sh --headful to watch

# 3. Deploy the cloud archive
cd worker
pnpm install
turso auth login
./scripts/setup_turso.sh teamplus-messages   # creates DB + schema + secrets
#   → edit worker/.dev.vars and set TEAMPLUS_BASE
./scripts/push_secrets.sh && wrangler deploy
#   → set CF_TEAMPLUS_WORKER_URL in ../.cf-worker.env to the deployed URL
cd ..
./scripts/refresh_and_upload_cf.sh           # refresh cookies + push to worker

The TeamPlus session token (TSSID) lives ~1 day, so schedule ./scripts/refresh_and_upload_cf.sh to keep the cloud session alive. A local cron works, but to drop the laptop entirely, run it from CI (see below).

Keeping cookies fresh in the cloud (GitHub Actions)

.github/workflows/refresh-cookies.yml.example runs the cookie refresh on a GitHub-hosted runner (Chromium + Tesseract) and uploads to your worker — no machine of your own needed. Recommended split for open-sourcing:

  • Public repo — the code, with the workflow as a .example template only.
  • Private repo — your actual deployment: copy the template to .github/workflows/refresh-cookies.yml and add the five Secrets it lists (TEAMPLUS_ACCOUNT, TEAMPLUS_PASSWORD, TEAMPLUS_BASE, CF_TEAMPLUS_WORKER_URL, CF_TEAMPLUS_UPLOAD_SECRET).

GitHub Actions Secrets are encrypted, never stored in the repo, and masked in logs — open-sourcing the code does not expose them. Keep the running workflow in the private repo and use only schedule / workflow_dispatch triggers (never pull_request) so fork PRs can never reach the secrets.

Configuration & secrets

All secrets live in gitignored files; templates are committed:

File Holds Template
.env TEAMPLUS_BASE, TeamPlus login .env.example
.config.json your TeamPlus my_id + mute lists auto-filled
cookies.json captured session cookies scripts/refresh.sh
worker/.dev.vars Turso creds, upload secret, TEAMPLUS_BASE, TEAMPLUS_DB_KEY worker/.dev.vars.example
.cf-worker.env deployed worker URL + upload secret worker/scripts/setup_turso.sh

Nothing in version control contains a real credential or organisation URL.

License

MIT.

About

Self-hosted server for syncing, archiving, and exporting team chat messages with conversational AI search over the message history.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors