/** * Microsoft Teams communication adapter — bidirectional chat via Graph API. * * Auth priority: cached token → refresh → browser PKCE → device code fallback. * Uses the Microsoft Graph PowerShell first-party client ID by default (works * in every Microsoft tenant with no custom Entra registration required). * Tokens stored per-identity in /teams-tokens-{hash(tenantId:clientId)}.json * (squad-home defaults to ~/.squad/ but respects the SQUAD_HOME env var). * * @module platform/comms-teams */ import type { CommunicationAdapter, CommunicationChannel, CommunicationReply } from './types.js'; export interface TeamsCommsConfig { tenantId?: string; clientId?: string; /** User to message — UPN like "bradyg@microsoft.com" or "me" for self-chat */ recipientUpn?: string; /** Existing chat ID (skip chat creation if known) */ chatId?: string; /** Teams channel ID (alternative to 1:1 chat) */ channelId?: string; teamId?: string; } interface StoredTokens { accessToken: string; refreshToken: string; expiresAt: number; /** Configured tenant authority — validated on load to prevent cross-config reuse */ configTenantId?: string; /** Client ID (app registration) — validated on load */ clientId?: string; /** Actual tenant GUID from JWT `tid` claim — tracks real authenticated identity */ authenticatedTenantId?: string; /** Actual user object ID from JWT `oid` claim — tracks real authenticated identity */ authenticatedUserId?: string; } /** Legacy single-file path (pre-tenant-scoped) — migrated away on first use */ declare const LEGACY_TOKEN_PATH: string; /** * Derive a safe, collision-resistant filename for a token cache entry. * Uses SHA-256 hash of `tenantId + clientId` to avoid path traversal, * special character issues, and to provide collision-resistant separation for different app registrations. Uses 16 hex chars (~64 bits) of SHA-256 — sufficient for practical uniqueness across tenant/app combinations. */ declare function getTokenPath(tenantId: string, clientId: string): string; declare function loadTokens(tenantId: string, clientId: string): StoredTokens | null; declare function saveTokens(tenantId: string, clientId: string, tokens: StoredTokens): void; /** * Remove cached tokens from disk for a specific config. * Used on permanent auth errors and explicit logout. */ declare function clearTokens(tenantId: string, clientId: string): void; /** * Migrate legacy single-file token cache to identity-scoped storage. * Moves tokens from `teams-tokens.json` → `teams-tokens-{hash}.json`, * then deletes the legacy file. */ declare function migrateLegacyTokens(tenantId: string, clientId: string): void; /** * Extract `tid` (tenant GUID) and `oid` (user object ID) from a JWT access token. * Best-effort: returns empty object if the token can't be decoded. * Does NOT verify the signature — the token was just received over TLS from Microsoft. */ declare function extractJwtClaims(accessToken: string): { tid?: string; oid?: string; }; /** Errors that indicate a permanently invalid refresh token (do not retry) */ declare const PERMANENT_AUTH_ERRORS: string[]; interface TokenResponse { access_token: string; refresh_token: string; expires_in: number; error?: string; error_description?: string; } declare function parseTokens(data: TokenResponse): StoredTokens; /** Base64-URL encode (no padding). */ declare function base64url(buf: Buffer): string; /** Maximum time allowed for device-code auth flow (15 minutes) */ declare const DEVICE_CODE_TIMEOUT_MS: number; /** Minimum poll interval for device-code flow (2 seconds) */ declare const DEVICE_CODE_MIN_POLL_MS = 2000; /** Maximum poll interval for device-code flow (30 seconds) */ declare const DEVICE_CODE_MAX_POLL_MS = 30000; export declare class TeamsCommunicationAdapter implements CommunicationAdapter { private readonly config; readonly channel: CommunicationChannel; private tokens; private resolvedChatId; private readonly clientId; private readonly tenantId; /** Per-instance user ID cache — cleared on every token change to prevent cross-account leaks */ private cachedUserId; constructor(config: TeamsCommsConfig); /** Reset all identity-sensitive caches. Called on every token change. */ private resetIdentityCaches; /** * Ensure we have a valid access token. * Priority: cached → refresh → browser PKCE → device code fallback. */ private ensureAuthenticated; /** * Logout: clear cached credentials (memory + disk) for this adapter's config. * This is a local credential purge — does not call Microsoft's revocation endpoint * (public-client refresh tokens cannot be reliably revoked server-side). */ logout(): Promise; /** Resolve the current user's Graph ID, cached per auth session. */ private getMyUserId; /** * Find or create a 1:1 chat with the recipient. */ private ensureChat; postUpdate(options: { title: string; body: string; category?: string; author?: string; }): Promise<{ id: string; url?: string; }>; pollForReplies(options: { threadId: string; since: Date; }): Promise; getNotificationUrl(threadId: string): string | undefined; } /** Validate and encode a Graph API path segment. */ declare function validateGraphId(id: string, label: string): string; declare function formatTeamsMessage(title: string, body: string, author?: string): string; declare function escapeHtml(s: string): string; declare function stripHtml(html: string): string; export { escapeHtml, stripHtml, formatTeamsMessage, parseTokens, base64url, validateGraphId, getTokenPath, clearTokens, loadTokens, saveTokens, migrateLegacyTokens, extractJwtClaims, DEVICE_CODE_TIMEOUT_MS, DEVICE_CODE_MIN_POLL_MS, DEVICE_CODE_MAX_POLL_MS, LEGACY_TOKEN_PATH, PERMANENT_AUTH_ERRORS, }; //# sourceMappingURL=comms-teams.d.ts.map