/** * OAuth route mounting for external integrations. * * Provides OAuth2 authorize/callback/disconnect flows for: * - Notion (workspace-level integration) * - Google (user-level, with token refresh) * - ClickUp (workspace-level, task sync) * * Also provides GET /status?space=X to check connection status (no tokens). * * Tokens are stored in Automerge docs per space via SyncServer. */ import { Hono } from 'hono'; import { notionOAuthRoutes } from './notion'; import { googleOAuthRoutes } from './google'; import { clickupOAuthRoutes } from './clickup'; import { connectionsDocId } from '../../modules/rnotes/schemas'; import { clickupConnectionDocId } from '../../modules/rtasks/schemas'; import type { ConnectionsDoc } from '../../modules/rnotes/schemas'; import type { ClickUpConnectionDoc } from '../../modules/rtasks/schemas'; import type { SyncServer } from '../local-first/sync-server'; const oauthRouter = new Hono(); let _syncServer: SyncServer | null = null; export function setOAuthStatusSyncServer(ss: SyncServer) { _syncServer = ss; } oauthRouter.route('/notion', notionOAuthRoutes); oauthRouter.route('/google', googleOAuthRoutes); oauthRouter.route('/clickup', clickupOAuthRoutes); // GET /status?space=X — return connection status for all providers (no tokens) oauthRouter.get('/status', (c) => { const space = c.req.query('space'); if (!space) return c.json({ error: 'space query param required' }, 400); if (!_syncServer) return c.json({ error: 'SyncServer not initialized' }, 500); // Read rNotes connections doc (Google + Notion) const connDoc = _syncServer.getDoc(connectionsDocId(space)); // Read rTasks ClickUp connection doc const clickupDoc = _syncServer.getDoc(clickupConnectionDocId(space)); const status: Record = {}; // Google if (connDoc?.google) { status.google = { connected: true, connectedAt: connDoc.google.connectedAt, email: connDoc.google.email, }; } else { status.google = { connected: false }; } // Notion if (connDoc?.notion) { status.notion = { connected: true, connectedAt: connDoc.notion.connectedAt, workspaceName: connDoc.notion.workspaceName, }; } else { status.notion = { connected: false }; } // ClickUp if (clickupDoc?.clickup) { status.clickup = { connected: true, connectedAt: clickupDoc.clickup.connectedAt, teamName: clickupDoc.clickup.teamName, }; } else { status.clickup = { connected: false }; } return c.json(status); }); export { oauthRouter };