vojo/apps/widget-whatsapp/README.md

137 lines
5.5 KiB
Markdown

# @vojo/widget-whatsapp
Vojo WhatsApp bridge management widget — mounts inside `/bots/whatsapp`
in the Vojo client. Drives the mautrix-whatsapp bridge bot
(`@whatsappbot:vojo.chat`) by sending bridgev2 commands in the control DM
and rendering the bot's text replies into a typed login flow.
This is **not** a WhatsApp client — Vojo continues using the Matrix room
the bridge writes to. The widget is a panel that handles authentication
(QR scan or pairing code) and surfaces session status.
## Layout
```
src/
├── bootstrap.ts Parse URL params the host appends (mirrors BotWidgetEmbed.ts)
├── widget-api.ts Inline matrix-widget-api postMessage transport (no SDK)
├── App.tsx UI: login forms, QR / pairing-code panels, transcript pane
├── main.tsx Entry: init bootstrap, render App or diagnostic
├── styles.css Theme-aware CSS (Vojo Dawn palette)
├── state.ts Login state machine + hydrate-from-timeline
├── i18n/ Russian primary + English fallback
└── bridge-protocol/
├── types.ts LoginEvent discriminated union
├── parser.ts Dispatch shim
└── dialects/
└── bridgev2_v0264.ts Regex table pinned to mautrix-whatsapp v0.26.4
```
## Login flows
WhatsApp's mautrix bridge ships TWO login flows (see
`pkg/connector/login.go::GetLoginFlows`):
1. **QR** (`!wa login qr`) — bridge emits a rotating `m.image` whose body
is the raw whatsmeow handshake payload (`<ref>,<noise>,<identity>,<adv>`,
four base64 fields). The widget renders it as a QR matrix client-side.
Whatsmeow `qrIntervals = [60s, 20s, 20s, 20s, 20s, 20s]` — first QR
lasts 60 seconds, then five rotations of 20 seconds each. Total active
window: 2 minutes 40 seconds. Each rotation arrives as an `m.replace`
edit of the original event; the state machine matches on the original
id and repaints the matrix.
2. **Pairing code** (`!wa login phone`) — alternative for users whose
camera doesn't work or who prefer typing. The user enters a phone
number; the bridge replies with two notices:
- `Input the pairing code in the WhatsApp mobile app to log in`
- The 8-character code itself (`XXXX-XXXX`, custom base32 alphabet).
The widget renders the code prominently and the user enters it in
WhatsApp → Settings → Linked devices → Link with phone number.
There is **no 2FA cloud-password step** — multidevice handshake is
single-factor. The state machine has no `awaiting_password` arm.
## Capability contract
The widget requests EXACTLY this set (matches the host's
`BotWidgetDriver.getBotWidgetCapabilities`):
```
org.matrix.msc2762.timeline:<roomId>
org.matrix.msc2762.send.event:m.room.message#m.text
org.matrix.msc2762.receive.event:m.room.message#m.text
org.matrix.msc2762.receive.event:m.room.message#m.notice
org.matrix.msc2762.receive.event:m.room.message#m.image
org.matrix.msc2762.receive.event:m.room.redaction
org.matrix.msc2762.receive.state_event:m.room.member
```
Anything else is silently dropped by the host. The capability set is
identical to the Telegram widget's M13 expansion — the host driver
already supports `m.image` + `m.room.redaction`.
## Local development
```bash
cd apps/widget-whatsapp && npm install
cd /home/ubuntu/projects/vojo/cinny && cat > config.local.json <<'JSON'
{
"bots": [
{ "id": "whatsapp", "experience": { "type": "matrix-widget", "url": "http://localhost:8083/" } }
]
}
JSON
```
Run both servers:
```bash
# terminal 1 — widget on :8083 with HMR
cd apps/widget-whatsapp && npm run dev
# terminal 2 — host SPA on :8080
cd /home/ubuntu/projects/vojo/cinny && npm start
```
Open `http://localhost:8080/bots/whatsapp`. The host's URL validator
accepts `http://localhost:*` only in dev builds.
## Build
```bash
npm run build
```
Outputs to `apps/widget-whatsapp/dist/`. Deploy by rsyncing `dist/*` into
`~/vojo/widgets/whatsapp/` on the production host. The VSCode task
`Deploy widgets` already includes the third subshell — running it from
the host root pushes all three widgets in sequence.
## Capacitor (Android)
`capacitor.config.ts` already allows `widgets.vojo.chat` for the existing
TG / Discord widgets — no extra entry needed for WhatsApp.
## Hosting (server-side)
Same Caddy `widgets.vojo.chat` block as the other widgets — add a third
`handle_path /whatsapp/* { … }` block alongside `/telegram/*` and
`/discord/*`. Then `mkdir -p ~/vojo/widgets/whatsapp` on the server, run
the deploy task, and verify with
`curl -I https://widgets.vojo.chat/whatsapp/index.html`.
## Source-of-truth pointers
- mautrix-whatsapp connector: <https://github.com/mautrix/whatsapp/blob/main/pkg/connector/login.go>
- mautrix-whatsapp connector (post-login session events):
<https://github.com/mautrix/whatsapp/blob/main/pkg/connector/handlewhatsapp.go>
- whatsmeow QR format: <https://github.com/tulir/whatsmeow/blob/main/pair.go> (`makeQRData`)
- whatsmeow pairing-code: <https://github.com/tulir/whatsmeow/blob/main/pair-code.go> (`PairPhone`)
- bridgev2 commands layer (shared with mautrix-telegram):
<https://github.com/mautrix/go/blob/main/bridgev2/commands/login.go>
The dialect file `src/bridge-protocol/dialects/bridgev2_v0264.ts` has
inline upstream pointers per regex; when the bridge image is upgraded,
spot-check those pointers and either confirm the wording is still valid
or drop a sibling dialect file with new regexes.