mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-12 21:02:17 +02:00
add whatsapp and telegram support
This commit is contained in:
parent
3ba94402d3
commit
fc9a76e1cb
15 changed files with 2244 additions and 9 deletions
54
apps/x/packages/shared/src/channels.ts
Normal file
54
apps/x/packages/shared/src/channels.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import { z } from "zod";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mobile messaging channels (WhatsApp / Telegram bridges).
|
||||
//
|
||||
// Each channel links the user's OWN account/bot to the local app: WhatsApp
|
||||
// connects as a linked device (QR pairing), Telegram long-polls the user's
|
||||
// own bot token. There is no central relay — the desktop app must be running.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const WhatsAppChannelConfig = z.object({
|
||||
enabled: z.boolean(),
|
||||
// Extra sender phone numbers (digits only, no '+') allowed to drive the
|
||||
// bridge. The linked account itself (self-chat) is always allowed.
|
||||
allowFrom: z.array(z.string()),
|
||||
});
|
||||
|
||||
export const TelegramChannelConfig = z.object({
|
||||
enabled: z.boolean(),
|
||||
botToken: z.string(),
|
||||
// Telegram chat ids (numeric strings) allowed to drive the bridge.
|
||||
// Unknown senders are told their chat id so it can be added here.
|
||||
allowFrom: z.array(z.string()),
|
||||
});
|
||||
|
||||
export const ChannelsConfig = z.object({
|
||||
whatsapp: WhatsAppChannelConfig,
|
||||
telegram: TelegramChannelConfig,
|
||||
});
|
||||
|
||||
export const DEFAULT_CHANNELS_CONFIG: z.infer<typeof ChannelsConfig> = {
|
||||
whatsapp: { enabled: false, allowFrom: [] },
|
||||
telegram: { enabled: false, botToken: "", allowFrom: [] },
|
||||
};
|
||||
|
||||
export const WhatsAppChannelStatus = z.object({
|
||||
state: z.enum(["disabled", "starting", "qr", "connected", "error"]),
|
||||
// PNG data URL of the pairing QR (present while state === "qr").
|
||||
qrDataUrl: z.string().optional(),
|
||||
// Linked account phone number (digits) once connected.
|
||||
self: z.string().optional(),
|
||||
error: z.string().optional(),
|
||||
});
|
||||
|
||||
export const TelegramChannelStatus = z.object({
|
||||
state: z.enum(["disabled", "starting", "polling", "error"]),
|
||||
botUsername: z.string().optional(),
|
||||
error: z.string().optional(),
|
||||
});
|
||||
|
||||
export const ChannelsStatus = z.object({
|
||||
whatsapp: WhatsAppChannelStatus,
|
||||
telegram: TelegramChannelStatus,
|
||||
});
|
||||
|
|
@ -19,4 +19,5 @@ export * as browserControl from './browser-control.js';
|
|||
export * as billing from './billing.js';
|
||||
export * as notificationSettings from './notification-settings.js';
|
||||
export * as codeSessions from './code-sessions.js';
|
||||
export * as channels from './channels.js';
|
||||
export { PrefixLogger };
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import { EmailBlockSchema, GmailThreadSchema } from './blocks.js';
|
|||
import { PermissionDecision, ApprovalPolicy, CodingAgent } from './code-mode.js';
|
||||
import { NotificationSettingsSchema } from './notification-settings.js';
|
||||
import { CodeProject, CodeSession, CodeSessionMode, CodeSessionStatus, GitRepoInfo, GitStatusFile, CodeAgentModelOptions } from './code-sessions.js';
|
||||
import { ChannelsConfig, ChannelsStatus } from './channels.js';
|
||||
|
||||
// ============================================================================
|
||||
// Runtime Validation Schemas (Single Source of Truth)
|
||||
|
|
@ -950,6 +951,28 @@ const ipcSchemas = {
|
|||
success: z.literal(true),
|
||||
}),
|
||||
},
|
||||
// ── Mobile channels (WhatsApp / Telegram bridge) ─────────────
|
||||
'channels:getConfig': {
|
||||
req: z.null(),
|
||||
res: ChannelsConfig,
|
||||
},
|
||||
'channels:setConfig': {
|
||||
req: ChannelsConfig,
|
||||
res: z.object({ success: z.literal(true) }),
|
||||
},
|
||||
'channels:getStatus': {
|
||||
req: z.null(),
|
||||
res: ChannelsStatus,
|
||||
},
|
||||
'channels:whatsappLogout': {
|
||||
req: z.null(),
|
||||
res: z.object({ success: z.literal(true) }),
|
||||
},
|
||||
// Push: main → renderer status updates (QR rotation, connect/disconnect).
|
||||
'channels:status': {
|
||||
req: ChannelsStatus,
|
||||
res: z.null(),
|
||||
},
|
||||
'slack:getConfig': {
|
||||
req: z.null(),
|
||||
res: z.object({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue