export interface FederatedBot {
    larkAppId: string;
    botName: string;
    cliId: string;
    /** Tenant-stable bot id (used by P2 拉群 to add the bot cross-app). */
    botUnionId?: string;
    capability?: string | null;
    hasTeamRole?: boolean;
    /** Owner (the person) of this bot, tenant-stable union_id — so 拉群 can pull
     *  the owner into the group by union_id (open_id is app-scoped, union_id not). */
    ownerUnionId?: string;
    ownerName?: string;
}
export interface FederatedDeployment {
    deploymentId: string;
    name: string;
    syncToken: string;
    bots: FederatedBot[];
    joinedAt: number;
    lastSeenAt: number;
    /** The spoke deployment's OWNER (the person), tenant-stable union_id. Hub uses
     *  this — derived from syncToken — as the trusted operator identity when this
     *  spoke initiates 拉群 (so the operator is pulled into the group). */
    ownerUnionId?: string;
    ownerName?: string;
    /** Spoke's dashboard base URL — so this hub can call back to delegate 拉群
     *  (hub→spoke) when no local online bot can be the group creator. */
    callbackUrl?: string;
    /** Token the SPOKE issued to THIS hub at join; the hub presents it on
     *  delegate calls so the spoke can verify the request is from its hub. */
    delegationToken?: string;
}
export interface RegisterInput {
    deploymentId: string;
    name: string;
    bots: FederatedBot[];
    ownerUnionId?: string;
    ownerName?: string;
    callbackUrl?: string;
    delegationToken?: string;
}
/**
 * Register a NEW remote deployment under a team and issue a fresh syncToken.
 *
 * NOT idempotent on purpose: `deploymentId` is public (it appears in the roster),
 * so re-registering an existing id must NOT hand back its long-lived syncToken —
 * otherwise anyone with an invite could claim another deployment's token by
 * guessing its id. A duplicate returns `{ created: false }` with NO token; the
 * caller surfaces `deployment_already_joined`. Ongoing bot refresh is via
 * `syncDeployment` (syncToken), not this. Re-binding/rotation is a future
 * explicit reset proving the old syncToken.
 */
export declare function registerDeployment(dataDir: string, teamId: string, input: RegisterInput, now?: number): {
    syncToken: string;
    created: boolean;
};
/** Resolve a syncToken to its {teamId, deployment}, or null. */
export declare function getDeploymentByToken(dataDir: string, syncToken: string): {
    teamId: string;
    deployment: FederatedDeployment;
} | null;
/** Refresh a deployment's advertised bots + heartbeat, by syncToken. Returns true if found. */
export declare function syncDeployment(dataDir: string, syncToken: string, bots: FederatedBot[], owner?: {
    ownerUnionId?: string;
    ownerName?: string;
    name?: string;
}, now?: number): boolean;
/** Member deployments of a team (empty if none). */
export declare function listFederatedDeployments(dataDir: string, teamId: string): FederatedDeployment[];
/** Remove a deployment from a team (leave/kick). Returns true if removed. */
export declare function removeDeployment(dataDir: string, teamId: string, deploymentId: string): boolean;
/** Remove the deployment owning a syncToken (spoke-initiated leave/revoke). Returns true if removed. */
export declare function removeDeploymentByToken(dataDir: string, syncToken: string): boolean;
/** Drop all federation records for a team (e.g. when the team is deleted). */
export declare function removeTeamFederation(dataDir: string, teamId: string): void;
//# sourceMappingURL=federation-store.d.ts.map