fix: improve Zoom onboarding UX and add defensive null handling

- Add defensive String(value ?? '') wrapper to trim() calls in channel.ts
- Show both webhook and OAuth redirect URLs after credential entry
- Update docs with clear URL configuration (removed confusing :3001 port)
- Match Slack's URL pattern with gateway-host placeholder
- Clarify local dev (ngrok) vs production (reverse proxy) setup
This commit is contained in:
Pranav Katariya 2026-01-27 19:40:57 -08:00
parent 56096d81ee
commit 737ae1cdec
3 changed files with 37 additions and 11 deletions

View File

@ -10,10 +10,12 @@ Status: production-ready plugin for Zoom Team Chat direct messages via Team Chat
## Quick setup
1) Create a 'General App; in [Zoom App Marketplace](https://marketplace.zoom.us/develop/create)
1) Create a 'General App' in [Zoom App Marketplace](https://marketplace.zoom.us/develop/create)
2) Enable the Team Chat surface and note your credentials (Client ID, Client Secret, Bot JID, Webhook Secret Token)
3) Install the plugin: `pnpm install` (the zoom extension is included in the workspace)
4) Configure webhook URL pointing to your gateway (see Webhook Setup below)
4) Configure URLs (see URL Configuration below):
- Webhook URL: `https://gateway-host/webhooks/zoom`
- OAuth Redirect URL: `https://gateway-host/api/zoomapp/auth`
5) Set credentials in config:
```json5
{
@ -52,20 +54,24 @@ Status: production-ready plugin for Zoom Team Chat direct messages via Team Chat
- **Bot JID** (e.g., `bot@xmppdev.zoom.us`)
- **Secret Token** (for webhook verification)
### 2. Configure Webhooks
### 2. Configure URLs
The bot receives messages through webhooks. Configure the webhook URL in your Zoom app settings:
Configure these URLs in your Zoom app settings:
**Development (using tunnel):**
**Webhook URL** (for receiving messages):
```
https://YOUR-SUBDOMAIN.frp.zoomappgo.cloud/webhooks/zoom
https://gateway-host/webhooks/zoom
```
**Production:**
**OAuth Redirect URL** (for app installation):
```
https://your-domain.com/webhooks/zoom
https://gateway-host/api/zoomapp/auth
```
Replace `gateway-host` with:
- **Local development**: Use ngrok (`ngrok http 3001`) or another tunnel service to expose port 3001
- **Production**: Your server's public domain (configure reverse proxy to forward to port 3001)
Subscribe to these event types:
- `bot_notification` - Required for receiving messages

View File

@ -75,12 +75,12 @@ export const zoomPlugin: ChannelPlugin<ResolvedZoomAccount> = {
allowFrom: account.config.dm?.allowFrom ?? [],
allowFromPath: "channels.zoom.dm.",
approveHint: "Send a message to the bot to get started",
normalizeEntry: (raw) => raw.trim(),
normalizeEntry: (raw) => String(raw ?? "").trim(),
}),
collectWarnings: () => [],
},
messaging: {
normalizeTarget: (target) => target.trim(),
normalizeTarget: (target) => String(target ?? "").trim(),
targetResolver: {
looksLikeId: (input) => input.includes("@xmpp") || input.includes("@xmppdev"),
hint: "<userJid>",

View File

@ -35,7 +35,7 @@ async function noteZoomHelp(prompter: WizardPrompter): Promise<void> {
"1) Go to Zoom App Marketplace (marketplace.zoom.us/develop/create)",
"2) Create a Team Chat App and enable Bot feature",
"3) Copy Client ID, Client Secret, Bot JID, and Secret Token",
"4) Configure webhook URL to point to your gateway",
"4) You'll configure webhook and OAuth redirect URLs after setup",
`Docs: ${formatDocsLink("/channels/zoom")}`,
"Website: https://molt.bot",
].join("\n"),
@ -150,6 +150,26 @@ export const zoomOnboardingAdapter: ChannelOnboardingAdapter = {
},
};
// Show URL configuration instructions
await prompter.note(
[
"IMPORTANT: Configure these URLs in your Zoom app:",
"",
"Webhook URL (for receiving messages):",
" https://gateway-host/webhooks/zoom",
"",
"OAuth Redirect URL (for app installation):",
" https://gateway-host/api/zoomapp/auth",
"",
"Replace gateway-host with:",
"- For local dev: Use ngrok (ngrok http 3001)",
"- For production: Your server's public domain",
"",
"Subscribe to event type: bot_notification",
].join("\n"),
"Zoom URL Configuration Required",
);
return { cfg: next };
},
dmPolicy,