feat: add Gmail Pub/Sub watcher for inbound email automation
New ChannelAdapter that monitors Gmail via Google Cloud Pub/Sub push notifications with polling fallback. Supports OAuth2 auth, configurable watch labels, template rendering with email metadata placeholders (from, to, subject, snippet, date, id, labels). Wired into daemon lifecycle and gateway (POST /gmail/push endpoint). Includes 16 tests covering auth, templates, push notifications, and channel routing.
This commit is contained in:
@@ -25,6 +25,7 @@ import type { Config } from '../config/index.js';
|
||||
import type { ToolRegistry } from '../tools/registry.js';
|
||||
import type { ToolExecutor } from '../tools/executor.js';
|
||||
import type { WebhookHandler } from '../automation/webhooks.js';
|
||||
import type { GmailWatcher } from '../automation/gmail.js';
|
||||
|
||||
export interface GatewayServerConfig {
|
||||
port: number;
|
||||
@@ -45,6 +46,8 @@ export interface GatewayServerConfig {
|
||||
channelRegistry?: { list(): Array<{ readonly name: string; readonly status: string }> };
|
||||
/** Optional webhook handler for inbound webhook HTTP routes. */
|
||||
webhookHandler?: WebhookHandler;
|
||||
/** Optional Gmail handler for Pub/Sub push notifications. */
|
||||
gmailHandler?: GmailWatcher;
|
||||
}
|
||||
|
||||
export class GatewayServer {
|
||||
@@ -223,6 +226,25 @@ export class GatewayServer {
|
||||
}
|
||||
}
|
||||
|
||||
// Gmail Pub/Sub push route — bypass gateway auth (Google sends push notifications directly)
|
||||
if (this.config.gmailHandler && req.method === 'POST' && req.url?.startsWith('/gmail/push')) {
|
||||
try {
|
||||
const body = await this.readRequestBody(req);
|
||||
const parsed = JSON.parse(body) as { message?: { data?: string } };
|
||||
const data = parsed?.message?.data;
|
||||
if (data) {
|
||||
await this.config.gmailHandler.handlePushNotification(data);
|
||||
}
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: true }));
|
||||
} catch (err) {
|
||||
console.error('Gmail push handler error:', err instanceof Error ? err.message : err);
|
||||
res.writeHead(400, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ error: 'Invalid request' }));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply auth to HTTP requests when configured
|
||||
const authConfig = this.config.auth ?? {};
|
||||
if (this.config.authHttp !== false && authConfig.token) {
|
||||
@@ -299,4 +321,19 @@ export class GatewayServer {
|
||||
setWebhookHandler(handler: WebhookHandler): void {
|
||||
this.config.webhookHandler = handler;
|
||||
}
|
||||
|
||||
/** Set the Gmail handler for Pub/Sub push notifications (late binding). */
|
||||
setGmailHandler(handler: GmailWatcher): void {
|
||||
this.config.gmailHandler = handler;
|
||||
}
|
||||
|
||||
/** Read the full request body as a string. */
|
||||
private readRequestBody(req: IncomingMessage): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks: Buffer[] = [];
|
||||
req.on('data', (chunk: Buffer) => chunks.push(chunk));
|
||||
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
||||
req.on('error', reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user