export interface SlackSocketEnvelope { envelope_id: string; payload: unknown; } export interface SlackPostedMessage { channel: string; ts: string; client_msg_id?: string; } export interface SlackMessageSearchResult { channel: string; ts: string; client_msg_id?: string; } export interface SlackConfigurationProbeResult { ok: boolean; detail: string; teamId?: string; userId?: string; } export interface SlackOneShotTestResult { ok: boolean; detail: string; channel?: string; timestamp?: string; uncertain?: boolean; } export interface SlackDiagnosticProvider { probeConfiguration(signal?: AbortSignal): Promise; sendOneShotTest(input: { channel: string; message: string; idempotencyKey: string; signal?: AbortSignal; }): Promise; } /** Minimal Socket Mode + Web API seam. Implementations may wrap the official Slack SDK. */ export interface SlackProviderClient { start(onEnvelope: (envelope: SlackSocketEnvelope) => void | Promise): Promise; stop?(): Promise; ack(envelopeId: string): Promise; postMessage(input: { channel: string; text: string; threadTs?: string; clientMsgId: string; signal?: AbortSignal; }): Promise; findMessageByClientMsgId?(input: { channel: string; clientMsgId: string; threadTs?: string; signal?: AbortSignal; }): Promise; /** * Prove that an operator-supplied timestamp addresses a real message in the * requested channel. Adoption of an existing root is refused when a client * cannot answer this, so verification is never silently skipped. */ findMessageByTimestamp?(input: { channel: string; ts: string; }): Promise; readonly transportHealthy?: boolean; } /** * Transport wrapper deliberately limited to Slack SDK operations. Keeping it injectable * makes Socket Mode acknowledgement and Web API failure cases deterministic in tests. */ export declare class SlackProvider { private readonly client; constructor(client: SlackProviderClient); start(onEnvelope: (envelope: SlackSocketEnvelope) => void | Promise): Promise; get transportHealthy(): boolean; stop(): Promise; ack(envelopeId: string): Promise; postMessage(input: { channel: string; text: string; threadTs?: string; clientMsgId: string; signal?: AbortSignal; }): Promise; findMessageByClientMsgId(input: { channel: string; clientMsgId: string; threadTs?: string; signal?: AbortSignal; }): Promise; /** Fail-closed root verification: a client without this capability can never confirm a root. */ findMessageByTimestamp(input: { channel: string; ts: string; }): Promise; }