/**
 * Federation HUB endpoints. Cross-deployment, so mounted BEFORE the dashboard's
 * `?t=` token gate (like webhook/team routes) — they authenticate by their OWN
 * credentials instead:
 *   - POST /api/federation/join   → an invite code (single-use admission)
 *   - POST /api/federation/sync   → a syncToken (per-deployment bearer)
 *   - GET  /api/federation/roster → a syncToken
 *
 * A spoke deployment registers once with an invite, gets a long-lived syncToken,
 * then pushes bots + pulls the aggregated roster with it. See docs/federation-design.md.
 */
import type { IncomingMessage, ServerResponse } from 'node:http';
import { type LiveBot } from '../services/team-roster.js';
import { type Fetcher } from './federated-group-core.js';
export interface FederationApiDeps {
    dataDir?: string;
    fetcher?: Fetcher;
    /** Live daemon-registry bots (authoritative over bots-info.json) for the
     *  delegate-group local-bot guard. */
    liveBots?: () => LiveBot[];
    /** Injected by dashboard.ts — used when a HUB delegates 拉群 to THIS spoke
     *  (we create the chat with one of OUR local online bots as creator). */
    createTeamGroup?: (args: {
        name: string;
        larkAppIds: string[];
        ownerUnionIds?: string[];
    }) => Promise<{
        ok: boolean;
        chatId?: string;
        shareLink?: string;
        invalidBotIds?: string[];
        invalidOwnerUnionIds?: string[];
        error?: string;
    }>;
    /** Add owners to an existing chat via one of OUR local bots (defaults to
     *  ensure-client + addUsersToChatByUnionId). Test seam. Returns the rejected ids. */
    addOwners?: (viaLarkAppId: string, chatId: string, ownerUnionIds: string[]) => Promise<{
        invalidUserIds: string[];
    }>;
}
export declare function handleFederationApi(req: IncomingMessage, res: ServerResponse, url: URL, deps?: FederationApiDeps): Promise<boolean>;
//# sourceMappingURL=federation-api.d.ts.map