import { WORKS_SQUARE_CONFIG } from '../api/works-config'; import { proxyAwareFetch } from '../utils/proxy-fetch'; import { getValidWorksSquareAccessToken, getWorksSquareAccountBinding, isCurrentWorksSquareAccountBinding, type WorksSquareAccountBinding, } from '../services/works-square-session'; import type { TeacherAvailability, TeacherDefinition } from '../../shared/coding-teacher'; export class TeacherError extends Error { constructor( public status: number, public code: string, message: string ) { super(message); } } export interface TeacherAccount { id: string; binding: WorksSquareAccountBinding; } export function assertTeacherAccount(account: TeacherAccount) { if (!isCurrentWorksSquareAccountBinding(account.binding)) throw new TeacherError(401, 'teacher_account_changed', '登录账号已变化,请重新打开老师。'); } export async function teacherCloudRequest( account: TeacherAccount, pathname: string ): Promise { assertTeacherAccount(account); const token = await getValidWorksSquareAccessToken(); assertTeacherAccount(account); if (!token) throw new TeacherError(401, 'teacher_auth_required', '请先登录。'); const response = await proxyAwareFetch( WORKS_SQUARE_CONFIG.apiBaseUrl.replace(/\/+$/, '') + pathname, { headers: { Authorization: 'Bearer ' + token }, signal: AbortSignal.timeout(30000), } ); assertTeacherAccount(account); if (!response.ok) { const code = response.status === 403 ? 'teacher_access_denied' : response.status === 409 ? 'teacher_draft_changed' : 'teacher_config_unavailable'; const message = response.status === 403 ? '当前账号没有使用权限。' : response.status === 409 ? '草稿已变化,请在运营页面重新打开试聊。' : '老师配置暂不可用,请稍后重试。'; throw new TeacherError(response.status, code, message); } return (await response.json()) as T; } export async function currentTeacherAccount(): Promise { const binding = getWorksSquareAccountBinding(); if (!binding) throw new TeacherError(401, 'teacher_auth_required', '请先登录。'); const provisional = { id: '', binding }; const profile = await teacherCloudRequest<{ id: string }>(provisional, '/api/auth/me'); if (!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(profile.id)) throw new TeacherError(502, 'teacher_account_unavailable', '无法确认当前账号。'); return { id: profile.id, binding }; } export const teacherAvailability = (account: TeacherAccount) => teacherCloudRequest(account, '/api/coding-teacher/config'); export const teacherVersion = (account: TeacherAccount, version: number) => teacherCloudRequest<{ version: number; payload: TeacherDefinition }>( account, '/api/coding-teacher/versions/' + version ); export const teacherPreview = (account: TeacherAccount, revision: number) => teacherCloudRequest<{ draft_revision: number; payload: TeacherDefinition }>( account, '/api/admin/coding-teacher/preview?draft_revision=' + revision );