import type { MSTeamsConfig } from "openclaw/plugin-sdk"; import { GRAPH_ROOT } from "./attachments/shared.js"; import { loadMSTeamsSdkWithAuth } from "./sdk.js"; import { resolveMSTeamsCredentials } from "./token.js"; export type GraphUser = { id?: string; displayName?: string; userPrincipalName?: string; mail?: string; }; export type GraphGroup = { id?: string; displayName?: string; }; export type GraphChannel = { id?: string; displayName?: string; }; export type GraphResponse = { value?: T[] }; function readAccessToken(value: unknown): string | null { if (typeof value === "string") { return value; } if (value && typeof value === "object") { const token = (value as { accessToken?: unknown }).accessToken ?? (value as { token?: unknown }).token; return typeof token === "string" ? token : null; } return null; } export function normalizeQuery(value?: string | null): string { return value?.trim() ?? ""; } export function escapeOData(value: string): string { return value.replace(/'/g, "''"); } export async function fetchGraphJson(params: { token: string; path: string; headers?: Record; }): Promise { const res = await fetch(`${GRAPH_ROOT}${params.path}`, { headers: { Authorization: `Bearer ${params.token}`, ...params.headers, }, }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error(`Graph ${params.path} failed (${res.status}): ${text || "unknown error"}`); } return (await res.json()) as T; } export async function resolveGraphToken(cfg: unknown): Promise { const creds = resolveMSTeamsCredentials( (cfg as { channels?: { msteams?: unknown } })?.channels?.msteams as MSTeamsConfig | undefined, ); if (!creds) { throw new Error("MS Teams credentials missing"); } const { sdk, authConfig } = await loadMSTeamsSdkWithAuth(creds); const tokenProvider = new sdk.MsalTokenProvider(authConfig); const token = await tokenProvider.getAccessToken("https://graph.microsoft.com"); const accessToken = readAccessToken(token); if (!accessToken) { throw new Error("MS Teams graph token unavailable"); } return accessToken; } export async function listTeamsByName(token: string, query: string): Promise { const escaped = escapeOData(query); const filter = `resourceProvisioningOptions/Any(x:x eq 'Team') and startsWith(displayName,'${escaped}')`; const path = `/groups?$filter=${encodeURIComponent(filter)}&$select=id,displayName`; const res = await fetchGraphJson>({ token, path }); return res.value ?? []; } export async function listChannelsForTeam(token: string, teamId: string): Promise { const path = `/teams/${encodeURIComponent(teamId)}/channels?$select=id,displayName`; const res = await fetchGraphJson>({ token, path }); return res.value ?? []; }