feat(channels): add google chat adapter and webhook route

This commit is contained in:
William Valentin
2026-02-16 02:07:55 -08:00
parent 51ff5523ae
commit 693dcd8421
15 changed files with 463 additions and 3 deletions
+2
View File
@@ -32,6 +32,7 @@ function makeBaseConfig(): Config {
matrix: undefined,
signal: undefined,
teams: undefined,
google_chat: undefined,
} as unknown as Config;
}
@@ -47,6 +48,7 @@ describe('discoverServices', () => {
expect.objectContaining({ name: 'matrix', status: 'not_configured' }),
expect.objectContaining({ name: 'signal', status: 'not_configured' }),
expect.objectContaining({ name: 'teams', status: 'not_configured' }),
expect.objectContaining({ name: 'google_chat', status: 'not_configured' }),
expect.objectContaining({ name: 'cron', status: 'not_configured' }),
expect.objectContaining({ name: 'mcp', status: 'not_configured' }),
expect.objectContaining({ name: 'web_search', status: 'configured' }),
+1
View File
@@ -55,6 +55,7 @@ export function discoverServices(
{ key: 'matrix', name: 'matrix', description: 'Matrix bot' },
{ key: 'signal', name: 'signal', description: 'Signal bot (signal-cli)' },
{ key: 'teams', name: 'teams', description: 'Microsoft Teams bot' },
{ key: 'google_chat', name: 'google_chat', description: 'Google Chat bot' },
];
for (const { key, name, description } of channelConfigs) {
+14
View File
@@ -44,6 +44,7 @@ import type { RoutingPolicy } from '../routing/index.js';
import type { ChannelRegistry } from '../channels/index.js';
import { RequestBodyTooLargeError, readRequestBody } from '../utils/httpBody.js';
import type { TeamsAdapter } from '../channels/teams/adapter.js';
import type { GoogleChatAdapter } from '../channels/googleChat/adapter.js';
export interface GatewayServerConfig {
port: number;
@@ -96,6 +97,8 @@ export interface GatewayServerConfig {
};
/** Optional Teams adapter for inbound Bot Framework activity webhooks. */
teamsHandler?: Pick<TeamsAdapter, 'handleRequest'>;
/** Optional Google Chat adapter for inbound Chat event webhooks. */
googleChatHandler?: Pick<GoogleChatAdapter, 'handleRequest'>;
}
export class GatewayServer {
@@ -485,6 +488,12 @@ export class GatewayServer {
return;
}
// Google Chat events route — bypass gateway auth (Google Chat posts directly)
if (this.config.googleChatHandler && req.method === 'POST' && req.url?.startsWith('/google-chat/events')) {
await this.config.googleChatHandler.handleRequest(req, res);
return;
}
// Apply auth to HTTP requests when configured
const authConfig = this.config.auth ?? {};
if (this.config.authHttp !== false && authConfig.token) {
@@ -577,6 +586,11 @@ export class GatewayServer {
this.config.teamsHandler = handler;
}
/** Set the Google Chat handler for inbound event HTTP routes (late binding). */
setGoogleChatHandler(handler: Pick<GoogleChatAdapter, 'handleRequest'>): void {
this.config.googleChatHandler = handler;
}
private async startDiscovery(host: string, port: number): Promise<void> {
const discovery = this.config.discovery;
if (!discovery?.enabled) {