{"version":3,"sources":["/home/runner/work/canvas-lms-mcp/canvas-lms-mcp/dist/chunk-4P7LR66V.cjs","../src/canvas/client.ts","../src/canvas/courses.ts","../src/canvas/assignments.ts","../src/canvas/submissions.ts","../src/canvas/rubrics.ts","../src/canvas/quizzes.ts","../src/canvas/files.ts","../src/canvas/users.ts","../src/canvas/groups.ts","../src/canvas/enrollments.ts","../src/canvas/discussions.ts","../src/canvas/modules.ts","../src/canvas/pages.ts","../src/canvas/calendar.ts","../src/canvas/conversations.ts","../src/canvas/peer-reviews.ts","../src/canvas/accounts.ts","../src/canvas/analytics.ts","../src/canvas/dashboard.ts","../src/canvas/index.ts"],"names":["body"],"mappings":"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","file":"/home/runner/work/canvas-lms-mcp/canvas-lms-mcp/dist/chunk-4P7LR66V.cjs","sourcesContent":[null,"import type { CanvasClientConfig, CanvasErrorResponse } from './types'\n\nexport class CanvasApiError extends Error {\n  status: number\n  endpoint: string\n\n  constructor(message: string, status: number, endpoint: string) {\n    super(message)\n    this.name = 'CanvasApiError'\n    this.status = status\n    this.endpoint = endpoint\n  }\n}\n\nconst DEFAULT_MAX_PAGINATION_PAGES = 1000\nconst USER_AGENT = 'canvas-lms-mcp/1.0'\n\nexport class CanvasHttpClient {\n  private token: string\n  private _baseUrl: string\n  private maxPaginationPages: number\n\n  constructor(config: CanvasClientConfig) {\n    this.token = config.token\n    this._baseUrl = config.baseUrl.replace(/\\/+$/, '')\n    this.maxPaginationPages = config.maxPaginationPages ?? DEFAULT_MAX_PAGINATION_PAGES\n  }\n\n  get baseUrl(): string {\n    return this._baseUrl\n  }\n\n  /**\n   * Makes a single authenticated request to the Canvas API.\n   * Returns `undefined` (typed as `T`) when Canvas responds with 204 No Content,\n   * which is the expected response for DELETE operations.\n   */\n  async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n    const url = endpoint.startsWith('http') ? endpoint : `${this._baseUrl}${endpoint}`\n\n    const method = (options.method ?? 'GET').toUpperCase()\n    if (options.body != null && (method === 'GET' || method === 'HEAD')) {\n      throw new Error(\n        `GET requests must not include a body (Canvas CloudFront CDN rejects them with 403): ${endpoint}`,\n      )\n    }\n\n    const headers: Record<string, string> = {\n      Authorization: `Bearer ${this.token}`,\n      'User-Agent': USER_AGENT,\n    }\n    if (options.body) {\n      headers['Content-Type'] = 'application/json'\n    }\n\n    const response = await fetch(url, {\n      ...options,\n      headers: {\n        ...headers,\n        ...options.headers,\n      },\n    })\n\n    if (!response.ok) {\n      const body = (await response.json().catch(() => ({}))) as CanvasErrorResponse\n      const message =\n        body.errors?.[0]?.message ?? body.message ?? `Canvas API error: ${response.status}`\n      throw new CanvasApiError(message, response.status, endpoint)\n    }\n\n    if (response.status === 204) {\n      return undefined as T\n    }\n\n    return response.json() as Promise<T>\n  }\n\n  async paginate<T>(endpoint: string, params?: Record<string, string>): Promise<T[]> {\n    const url = new URL(`${this._baseUrl}${endpoint}`)\n    url.searchParams.set('per_page', '100')\n    if (params) {\n      for (const [key, value] of Object.entries(params)) {\n        url.searchParams.set(key, value)\n      }\n    }\n\n    const results: T[] = []\n    let nextUrl: string | null = url.toString()\n    let pages = 0\n\n    while (nextUrl && pages < this.maxPaginationPages) {\n      const response = await fetch(nextUrl, {\n        headers: {\n          Authorization: `Bearer ${this.token}`,\n          'User-Agent': USER_AGENT,\n        },\n      })\n\n      if (!response.ok) {\n        const body = (await response.json().catch(() => ({}))) as CanvasErrorResponse\n        const message =\n          body.errors?.[0]?.message ?? body.message ?? `Canvas API error: ${response.status}`\n        throw new CanvasApiError(message, response.status, endpoint)\n      }\n\n      const data = (await response.json()) as T[]\n      results.push(...data)\n      pages++\n\n      nextUrl = this.parseNextLink(response.headers.get('Link'))\n    }\n\n    return results\n  }\n\n  async paginateEnvelope<T>(\n    endpoint: string,\n    envelopeKey: string,\n    params?: Record<string, string>,\n  ): Promise<T[]> {\n    const url = new URL(`${this._baseUrl}${endpoint}`)\n    url.searchParams.set('per_page', '100')\n    if (params) {\n      for (const [key, value] of Object.entries(params)) {\n        url.searchParams.set(key, value)\n      }\n    }\n\n    const results: T[] = []\n    let nextUrl: string | null = url.toString()\n    let pages = 0\n\n    while (nextUrl && pages < this.maxPaginationPages) {\n      const response = await fetch(nextUrl, {\n        headers: {\n          Authorization: `Bearer ${this.token}`,\n          'User-Agent': USER_AGENT,\n        },\n      })\n\n      if (!response.ok) {\n        const body = (await response.json().catch(() => ({}))) as CanvasErrorResponse\n        const message =\n          body.errors?.[0]?.message ?? body.message ?? `Canvas API error: ${response.status}`\n        throw new CanvasApiError(message, response.status, endpoint)\n      }\n\n      const body = (await response.json()) as Record<string, T[]>\n      const data = body[envelopeKey] ?? []\n      results.push(...data)\n      pages++\n\n      nextUrl = this.parseNextLink(response.headers.get('Link'))\n    }\n\n    return results\n  }\n\n  private parseNextLink(linkHeader: string | null): string | null {\n    if (!linkHeader) return null\n    const match = linkHeader.match(/<([^>]+)>;\\s*rel=\"next\"/)\n    return match?.[1] ?? null\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasCourse, CreateCourseParams, UpdateCourseParams } from './types'\n\nexport class CoursesModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(params?: { enrollment_state?: string }): Promise<CanvasCourse[]> {\n    const queryParams: Record<string, string> = {\n      'include[]': 'term',\n    }\n    if (params?.enrollment_state) {\n      queryParams.enrollment_state = params.enrollment_state\n    }\n    return this.client.paginate<CanvasCourse>('/api/v1/courses', queryParams)\n  }\n\n  async get(courseId: number): Promise<CanvasCourse> {\n    return this.client.request<CanvasCourse>(\n      `/api/v1/courses/${courseId}?include[]=term&include[]=total_students`,\n    )\n  }\n\n  async getSyllabus(courseId: number): Promise<string | null> {\n    const course = await this.client.request<CanvasCourse>(\n      `/api/v1/courses/${courseId}?include[]=syllabus_body`,\n    )\n    return course.syllabus_body ?? null\n  }\n\n  async create(params: CreateCourseParams): Promise<CanvasCourse> {\n    const { account_id, ...courseFields } = params\n    return this.client.request<CanvasCourse>(`/api/v1/accounts/${account_id}/courses`, {\n      method: 'POST',\n      body: JSON.stringify({ course: courseFields }),\n    })\n  }\n\n  async update(courseId: number, params: UpdateCourseParams): Promise<CanvasCourse> {\n    return this.client.request<CanvasCourse>(`/api/v1/courses/${courseId}`, {\n      method: 'PUT',\n      body: JSON.stringify({ course: params }),\n    })\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type {\n  CanvasAssignment,\n  CanvasAssignmentGroup,\n  CreateAssignmentParams,\n  UpdateAssignmentParams,\n} from './types'\n\nexport class AssignmentsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number): Promise<CanvasAssignment[]> {\n    return this.client.paginate<CanvasAssignment>(`/api/v1/courses/${courseId}/assignments`)\n  }\n\n  async get(courseId: number, assignmentId: number): Promise<CanvasAssignment> {\n    return this.client.request<CanvasAssignment>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}`,\n    )\n  }\n\n  async listGroups(courseId: number): Promise<CanvasAssignmentGroup[]> {\n    return this.client.paginate<CanvasAssignmentGroup>(\n      `/api/v1/courses/${courseId}/assignment_groups`,\n    )\n  }\n\n  async create(courseId: number, params: CreateAssignmentParams): Promise<CanvasAssignment> {\n    return this.client.request<CanvasAssignment>(`/api/v1/courses/${courseId}/assignments`, {\n      method: 'POST',\n      body: JSON.stringify({ assignment: params }),\n    })\n  }\n\n  async update(\n    courseId: number,\n    assignmentId: number,\n    params: UpdateAssignmentParams,\n  ): Promise<CanvasAssignment> {\n    return this.client.request<CanvasAssignment>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}`,\n      {\n        method: 'PUT',\n        body: JSON.stringify({ assignment: params }),\n      },\n    )\n  }\n\n  async delete(courseId: number, assignmentId: number): Promise<void> {\n    await this.client.request<void>(`/api/v1/courses/${courseId}/assignments/${assignmentId}`, {\n      method: 'DELETE',\n    })\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasSubmission } from './types'\n\nexport class SubmissionsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number, assignmentId: number): Promise<CanvasSubmission[]> {\n    return this.client.paginate<CanvasSubmission>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}/submissions`,\n      { 'include[]': 'submission_comments' },\n    )\n  }\n\n  async get(courseId: number, assignmentId: number, userId: number): Promise<CanvasSubmission> {\n    return this.client.request<CanvasSubmission>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}/submissions/${userId}?include[]=submission_comments`,\n    )\n  }\n\n  async grade(\n    courseId: number,\n    assignmentId: number,\n    userId: number,\n    grade: string,\n  ): Promise<CanvasSubmission> {\n    return this.client.request<CanvasSubmission>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}/submissions/${userId}`,\n      {\n        method: 'PUT',\n        body: JSON.stringify({ submission: { posted_grade: grade } }),\n      },\n    )\n  }\n\n  async comment(\n    courseId: number,\n    assignmentId: number,\n    userId: number,\n    comment: string,\n  ): Promise<CanvasSubmission> {\n    return this.client.request<CanvasSubmission>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}/submissions/${userId}`,\n      {\n        method: 'PUT',\n        body: JSON.stringify({\n          comment: { text_comment: comment },\n        }),\n      },\n    )\n  }\n\n  async listMy(courseId: number): Promise<CanvasSubmission[]> {\n    return this.client.paginate<CanvasSubmission>(\n      `/api/v1/courses/${courseId}/students/submissions`,\n      { 'student_ids[]': 'self' },\n    )\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasRubric, CanvasRubricAssessment, CanvasSubmission } from './types'\n\nexport class RubricsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number): Promise<CanvasRubric[]> {\n    return this.client.paginate<CanvasRubric>(`/api/v1/courses/${courseId}/rubrics`)\n  }\n\n  async get(courseId: number, rubricId: number): Promise<CanvasRubric> {\n    return this.client.request<CanvasRubric>(`/api/v1/courses/${courseId}/rubrics/${rubricId}`)\n  }\n\n  async getAssessment(\n    courseId: number,\n    assignmentId: number,\n    userId: number,\n  ): Promise<CanvasSubmission> {\n    return this.client.request<CanvasSubmission>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}/submissions/${userId}?include[]=rubric_assessment`,\n    )\n  }\n\n  async submitAssessment(\n    courseId: number,\n    associationId: number,\n    data: CanvasRubricAssessment['data'],\n  ): Promise<CanvasRubricAssessment> {\n    return this.client.request<CanvasRubricAssessment>(\n      `/api/v1/courses/${courseId}/rubric_associations/${associationId}/rubric_assessments`,\n      {\n        method: 'POST',\n        body: JSON.stringify({ rubric_assessment: { data } }),\n      },\n    )\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type {\n  CanvasQuiz,\n  CanvasQuizSubmission,\n  CanvasQuizQuestion,\n  CanvasQuizSubmissionQuestion,\n} from './types'\n\nexport class QuizzesModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number): Promise<CanvasQuiz[]> {\n    return this.client.paginate<CanvasQuiz>(`/api/v1/courses/${courseId}/quizzes`)\n  }\n\n  async get(courseId: number, quizId: number): Promise<CanvasQuiz> {\n    return this.client.request<CanvasQuiz>(`/api/v1/courses/${courseId}/quizzes/${quizId}`)\n  }\n\n  async listSubmissions(courseId: number, quizId: number): Promise<CanvasQuizSubmission[]> {\n    return this.client.paginateEnvelope<CanvasQuizSubmission>(\n      `/api/v1/courses/${courseId}/quizzes/${quizId}/submissions`,\n      'quiz_submissions',\n    )\n  }\n\n  async listQuestions(courseId: number, quizId: number): Promise<CanvasQuizQuestion[]> {\n    return this.client.paginate<CanvasQuizQuestion>(\n      `/api/v1/courses/${courseId}/quizzes/${quizId}/questions`,\n    )\n  }\n\n  async getSubmissionAnswers(quizSubmissionId: number): Promise<CanvasQuizSubmissionQuestion[]> {\n    return this.client.paginateEnvelope<CanvasQuizSubmissionQuestion>(\n      `/api/v1/quiz_submissions/${quizSubmissionId}/questions`,\n      'quiz_submission_questions',\n      { 'include[]': 'quiz_question' },\n    )\n  }\n\n  async scoreQuestion(\n    courseId: number,\n    quizId: number,\n    submissionId: number,\n    questionId: number,\n    score: number,\n    comment?: string,\n    attempt?: number,\n  ): Promise<void> {\n    const submission: Record<string, unknown> = {\n      questions: {\n        [questionId]: { score, comment },\n      },\n    }\n    if (attempt !== undefined) {\n      submission.attempt = attempt\n    }\n    const body: Record<string, unknown> = {\n      quiz_submissions: [submission],\n    }\n    await this.client.request(\n      `/api/v1/courses/${courseId}/quizzes/${quizId}/submissions/${submissionId}`,\n      {\n        method: 'PUT',\n        body: JSON.stringify(body),\n      },\n    )\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasFile, CanvasFileUploadInfo, CanvasFolder } from './types'\n\nexport class FilesModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number): Promise<CanvasFile[]> {\n    return this.client.paginate<CanvasFile>(`/api/v1/courses/${courseId}/files`)\n  }\n\n  async listFolders(courseId: number): Promise<CanvasFolder[]> {\n    return this.client.paginate<CanvasFolder>(`/api/v1/courses/${courseId}/folders`)\n  }\n\n  async get(courseId: number, fileId: number): Promise<CanvasFile> {\n    return this.client.request<CanvasFile>(`/api/v1/courses/${courseId}/files/${fileId}`)\n  }\n\n  async upload(\n    courseId: number,\n    name: string,\n    contentBase64: string,\n    contentType: string,\n    parentFolderPath?: string,\n  ): Promise<CanvasFile> {\n    const content = Buffer.from(contentBase64, 'base64')\n    if (content.toString('base64') !== contentBase64) {\n      throw new Error('Invalid base64 content: string is not valid base64 encoding')\n    }\n\n    // Step 1: Notify Canvas of the pending upload\n    const uploadBody: Record<string, string> = {\n      name,\n      content_type: contentType,\n      size: String(content.length),\n    }\n    if (parentFolderPath) {\n      uploadBody.parent_folder_path = parentFolderPath\n    }\n\n    const uploadInfo = await this.client.request<CanvasFileUploadInfo>(\n      `/api/v1/courses/${courseId}/files`,\n      { method: 'POST', body: JSON.stringify(uploadBody) },\n    )\n\n    // Step 2: POST file to upload_url (may be S3 — must NOT add Authorization header)\n    const form = new FormData()\n    for (const [key, value] of Object.entries(uploadInfo.upload_params)) {\n      form.append(key, value)\n    }\n    form.append('file', new Blob([content], { type: contentType }), name)\n\n    // Use redirect: 'manual' so we can handle the 303 → Canvas confirm step ourselves\n    let s3Response: Response\n    try {\n      s3Response = await fetch(uploadInfo.upload_url, {\n        method: 'POST',\n        body: form,\n        redirect: 'manual',\n      })\n    } catch (networkErr) {\n      let hostname: string\n      try {\n        hostname = new URL(uploadInfo.upload_url).hostname\n      } catch {\n        hostname = uploadInfo.upload_url\n      }\n      throw new Error(`Unable to reach file storage (${hostname})`, { cause: networkErr })\n    }\n\n    // Step 3: If S3 returned a redirect, POST to Canvas confirm URL\n    if (s3Response.status >= 300 && s3Response.status < 400) {\n      const confirmUrl = s3Response.headers.get('location')\n      if (!confirmUrl) {\n        throw new Error(`File upload redirect missing Location header (HTTP ${s3Response.status})`)\n      }\n      let confirmHostname: string\n      try {\n        confirmHostname = new URL(confirmUrl).hostname\n      } catch {\n        confirmHostname = ''\n      }\n      const canvasHostname = new URL(this.client.baseUrl).hostname\n      if (confirmHostname !== canvasHostname) {\n        throw new Error(\n          `File upload redirect points to unexpected host (${confirmHostname}); expected Canvas host (${canvasHostname})`,\n        )\n      }\n      return this.client.request<CanvasFile>(confirmUrl, { method: 'POST' })\n    }\n\n    if (!s3Response.ok) {\n      const body = await s3Response.text()\n      throw new Error(\n        `File upload to storage failed (HTTP ${s3Response.status}): ${body.slice(0, 500)}`,\n      )\n    }\n\n    const responseText = await s3Response.text()\n    let parsed: unknown\n    try {\n      parsed = JSON.parse(responseText)\n    } catch (parseErr) {\n      throw new Error(\n        `File upload response is not valid JSON (${parseErr instanceof Error ? parseErr.message : String(parseErr)}): ${responseText.slice(0, 500)}`,\n        { cause: parseErr },\n      )\n    }\n    if (typeof parsed !== 'object' || parsed === null || !('id' in parsed)) {\n      throw new Error(\n        `File upload returned unexpected response (no file ID): ${responseText.slice(0, 500)}`,\n      )\n    }\n    return parsed as CanvasFile\n  }\n\n  async delete(fileId: number): Promise<CanvasFile> {\n    return this.client.request<CanvasFile>(`/api/v1/files/${fileId}`, { method: 'DELETE' })\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasUpcomingEvent, CanvasUser, CanvasUserProfile } from './types'\n\nexport class UsersModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async listStudents(courseId: number): Promise<CanvasUser[]> {\n    return this.client.paginate<CanvasUser>(`/api/v1/courses/${courseId}/users`, {\n      'enrollment_type[]': 'student',\n    })\n  }\n\n  async get(userId: number): Promise<CanvasUser> {\n    return this.client.request<CanvasUser>(`/api/v1/users/${userId}`)\n  }\n\n  async getProfile(): Promise<CanvasUserProfile> {\n    return this.client.request<CanvasUserProfile>('/api/v1/users/self/profile')\n  }\n\n  async searchUsers(\n    accountId: number,\n    searchTerm: string,\n    sort?: string,\n    order?: string,\n  ): Promise<CanvasUser[]> {\n    const params: Record<string, string> = { search_term: searchTerm }\n    if (sort) params.sort = sort\n    if (order) params.order = order\n    return this.client.paginate<CanvasUser>(`/api/v1/accounts/${accountId}/users`, params)\n  }\n\n  async listCourseUsers(courseId: number, enrollmentType?: string): Promise<CanvasUser[]> {\n    const params: Record<string, string> = {}\n    if (enrollmentType) params['enrollment_type[]'] = enrollmentType\n    return this.client.paginate<CanvasUser>(`/api/v1/courses/${courseId}/users`, params)\n  }\n\n  async getUpcomingAssignments(): Promise<CanvasUpcomingEvent[]> {\n    return this.client.request<CanvasUpcomingEvent[]>(\n      '/api/v1/users/self/upcoming_events?type=Assignment',\n    )\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasGroup, CanvasUser } from './types'\n\nexport class GroupsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number): Promise<CanvasGroup[]> {\n    return this.client.paginate<CanvasGroup>(`/api/v1/courses/${courseId}/groups`)\n  }\n\n  async listMembers(groupId: number): Promise<CanvasUser[]> {\n    return this.client.paginate<CanvasUser>(`/api/v1/groups/${groupId}/users`)\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasEnrollment } from './types'\n\nexport class EnrollmentsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(): Promise<CanvasEnrollment[]> {\n    return this.client.paginate<CanvasEnrollment>('/api/v1/users/self/enrollments')\n  }\n\n  async enroll(\n    courseId: number,\n    userId: number,\n    type: string,\n    enrollmentState?: string,\n  ): Promise<CanvasEnrollment> {\n    const body: Record<string, unknown> = {\n      enrollment: {\n        user_id: userId,\n        type,\n        ...(enrollmentState ? { enrollment_state: enrollmentState } : {}),\n      },\n    }\n    return this.client.request<CanvasEnrollment>(`/api/v1/courses/${courseId}/enrollments`, {\n      method: 'POST',\n      body: JSON.stringify(body),\n    })\n  }\n\n  async remove(courseId: number, enrollmentId: number, task: string): Promise<CanvasEnrollment> {\n    return this.client.request<CanvasEnrollment>(\n      `/api/v1/courses/${courseId}/enrollments/${enrollmentId}?task=${encodeURIComponent(task)}`,\n      { method: 'DELETE' },\n    )\n  }\n\n  async listMyGrades(courseId?: number): Promise<CanvasEnrollment[]> {\n    if (courseId !== undefined) {\n      return this.client.paginate<CanvasEnrollment>(`/api/v1/courses/${courseId}/enrollments`, {\n        user_id: 'self',\n        'include[]': 'grades',\n      })\n    }\n    return this.client.paginate<CanvasEnrollment>('/api/v1/users/self/enrollments', {\n      'include[]': 'grades',\n    })\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type {\n  CanvasDiscussionTopic,\n  CanvasDiscussionEntry,\n  CanvasAnnouncement,\n  CreateDiscussionParams,\n  UpdateDiscussionParams,\n} from './types'\n\nexport class DiscussionsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number): Promise<CanvasDiscussionTopic[]> {\n    return this.client.paginate<CanvasDiscussionTopic>(\n      `/api/v1/courses/${courseId}/discussion_topics`,\n    )\n  }\n\n  async get(courseId: number, topicId: number): Promise<CanvasDiscussionTopic> {\n    return this.client.request<CanvasDiscussionTopic>(\n      `/api/v1/courses/${courseId}/discussion_topics/${topicId}?include[]=all_dates`,\n    )\n  }\n\n  async listAnnouncements(courseId: number): Promise<CanvasAnnouncement[]> {\n    return this.client.paginate<CanvasAnnouncement>(\n      `/api/v1/courses/${courseId}/discussion_topics`,\n      { only_announcements: 'true' },\n    )\n  }\n\n  async postEntry(\n    courseId: number,\n    topicId: number,\n    message: string,\n  ): Promise<CanvasDiscussionEntry> {\n    return this.client.request<CanvasDiscussionEntry>(\n      `/api/v1/courses/${courseId}/discussion_topics/${topicId}/entries`,\n      {\n        method: 'POST',\n        body: JSON.stringify({ message }),\n      },\n    )\n  }\n\n  async create(courseId: number, params: CreateDiscussionParams): Promise<CanvasDiscussionTopic> {\n    return this.client.request<CanvasDiscussionTopic>(\n      `/api/v1/courses/${courseId}/discussion_topics`,\n      {\n        method: 'POST',\n        body: JSON.stringify(params),\n      },\n    )\n  }\n\n  async update(\n    courseId: number,\n    topicId: number,\n    params: UpdateDiscussionParams,\n  ): Promise<CanvasDiscussionTopic> {\n    return this.client.request<CanvasDiscussionTopic>(\n      `/api/v1/courses/${courseId}/discussion_topics/${topicId}`,\n      {\n        method: 'PUT',\n        body: JSON.stringify(params),\n      },\n    )\n  }\n\n  async delete(courseId: number, topicId: number): Promise<void> {\n    await this.client.request<void>(`/api/v1/courses/${courseId}/discussion_topics/${topicId}`, {\n      method: 'DELETE',\n    })\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasModule, CanvasModuleItem } from './types'\n\nexport class ModulesModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number): Promise<CanvasModule[]> {\n    return this.client.paginate<CanvasModule>(`/api/v1/courses/${courseId}/modules`)\n  }\n\n  async get(courseId: number, moduleId: number): Promise<CanvasModule> {\n    return this.client.request<CanvasModule>(`/api/v1/courses/${courseId}/modules/${moduleId}`)\n  }\n\n  async listItems(courseId: number, moduleId: number): Promise<CanvasModuleItem[]> {\n    return this.client.paginate<CanvasModuleItem>(\n      `/api/v1/courses/${courseId}/modules/${moduleId}/items`,\n    )\n  }\n\n  async create(\n    courseId: number,\n    params: {\n      name: string\n      position?: number\n      unlock_at?: string\n      prerequisite_module_ids?: number[]\n    },\n  ): Promise<CanvasModule> {\n    return this.client.request<CanvasModule>(`/api/v1/courses/${courseId}/modules`, {\n      method: 'POST',\n      body: JSON.stringify({ module: params }),\n    })\n  }\n\n  async update(\n    courseId: number,\n    moduleId: number,\n    params: { name?: string; position?: number; published?: boolean },\n  ): Promise<CanvasModule> {\n    return this.client.request<CanvasModule>(`/api/v1/courses/${courseId}/modules/${moduleId}`, {\n      method: 'PUT',\n      body: JSON.stringify({ module: params }),\n    })\n  }\n\n  async createItem(\n    courseId: number,\n    moduleId: number,\n    params: {\n      title: string\n      type: string\n      content_id?: number\n      external_url?: string\n      position?: number\n    },\n  ): Promise<CanvasModuleItem> {\n    return this.client.request<CanvasModuleItem>(\n      `/api/v1/courses/${courseId}/modules/${moduleId}/items`,\n      {\n        method: 'POST',\n        body: JSON.stringify({ module_item: params }),\n      },\n    )\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasPage } from './types'\n\nexport class PagesModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number): Promise<CanvasPage[]> {\n    return this.client.paginate<CanvasPage>(`/api/v1/courses/${courseId}/pages`)\n  }\n\n  async get(courseId: number, pageUrl: string): Promise<CanvasPage> {\n    return this.client.request<CanvasPage>(\n      `/api/v1/courses/${courseId}/pages/${encodeURIComponent(pageUrl)}`,\n    )\n  }\n\n  async create(\n    courseId: number,\n    params: { title: string; body?: string; published?: boolean; editing_roles?: string },\n  ): Promise<CanvasPage> {\n    return this.client.request<CanvasPage>(`/api/v1/courses/${courseId}/pages`, {\n      method: 'POST',\n      body: JSON.stringify({ wiki_page: params }),\n    })\n  }\n\n  async update(\n    courseId: number,\n    pageUrl: string,\n    params: { title?: string; body?: string; published?: boolean; editing_roles?: string },\n  ): Promise<CanvasPage> {\n    return this.client.request<CanvasPage>(\n      `/api/v1/courses/${courseId}/pages/${encodeURIComponent(pageUrl)}`,\n      {\n        method: 'PUT',\n        body: JSON.stringify({ wiki_page: params }),\n      },\n    )\n  }\n\n  async delete(courseId: number, pageUrl: string): Promise<void> {\n    await this.client.request<void>(\n      `/api/v1/courses/${courseId}/pages/${encodeURIComponent(pageUrl)}`,\n      { method: 'DELETE' },\n    )\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasCalendarEvent } from './types'\n\nexport class CalendarModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(courseId: number): Promise<CanvasCalendarEvent[]> {\n    return this.client.paginate<CanvasCalendarEvent>('/api/v1/calendar_events', {\n      'context_codes[]': `course_${courseId}`,\n    })\n  }\n\n  async createEvent(params: {\n    context_code: string\n    title: string\n    start_at: string\n    end_at?: string\n    description?: string\n    location_name?: string\n  }): Promise<CanvasCalendarEvent> {\n    return this.client.request<CanvasCalendarEvent>('/api/v1/calendar_events', {\n      method: 'POST',\n      body: JSON.stringify({ calendar_event: params }),\n    })\n  }\n\n  async updateEvent(\n    eventId: number,\n    params: {\n      title?: string\n      start_at?: string\n      end_at?: string\n      description?: string\n      location_name?: string\n    },\n  ): Promise<CanvasCalendarEvent> {\n    return this.client.request<CanvasCalendarEvent>(`/api/v1/calendar_events/${eventId}`, {\n      method: 'PUT',\n      body: JSON.stringify({ calendar_event: params }),\n    })\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type {\n  CanvasConversation,\n  CanvasConversationDetail,\n  CanvasConversationUnreadCount,\n} from './types'\n\nexport class ConversationsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async list(): Promise<CanvasConversation[]> {\n    return this.client.paginate<CanvasConversation>('/api/v1/conversations')\n  }\n\n  async get(conversationId: number): Promise<CanvasConversationDetail> {\n    return this.client.request<CanvasConversationDetail>(`/api/v1/conversations/${conversationId}`)\n  }\n\n  async getUnreadCount(): Promise<CanvasConversationUnreadCount> {\n    const raw = await this.client.request<{ unread_count: string }>(\n      '/api/v1/conversations/unread_count',\n    )\n    const count = parseInt(raw.unread_count, 10)\n    if (Number.isNaN(count)) {\n      throw new Error(\n        `Canvas returned unexpected unread_count value: ${JSON.stringify(raw.unread_count)}`,\n      )\n    }\n    return { unread_count: count }\n  }\n\n  async send(recipients: string[], subject: string, body: string): Promise<CanvasConversation[]> {\n    return this.client.request<CanvasConversation[]>('/api/v1/conversations', {\n      method: 'POST',\n      body: JSON.stringify({\n        recipients,\n        subject,\n        body,\n      }),\n    })\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasPeerReview } from './types'\n\nexport class PeerReviewsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async listForAssignment(courseId: number, assignmentId: number): Promise<CanvasPeerReview[]> {\n    return this.client.paginate<CanvasPeerReview>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}/peer_reviews`,\n    )\n  }\n\n  async listForSubmission(\n    courseId: number,\n    assignmentId: number,\n    submissionId: number,\n  ): Promise<CanvasPeerReview[]> {\n    return this.client.paginate<CanvasPeerReview>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}/submissions/${submissionId}/peer_reviews`,\n    )\n  }\n\n  async create(\n    courseId: number,\n    assignmentId: number,\n    submissionId: number,\n    userId: number,\n  ): Promise<CanvasPeerReview> {\n    return this.client.request<CanvasPeerReview>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}/submissions/${submissionId}/peer_reviews`,\n      {\n        method: 'POST',\n        body: JSON.stringify({ user_id: userId }),\n      },\n    )\n  }\n\n  async delete(\n    courseId: number,\n    assignmentId: number,\n    submissionId: number,\n    userId: number,\n  ): Promise<void> {\n    await this.client.request<void>(\n      `/api/v1/courses/${courseId}/assignments/${assignmentId}/submissions/${submissionId}/peer_reviews?user_id=${userId}`,\n      { method: 'DELETE' },\n    )\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type { CanvasAccount, CanvasAccountReport, CanvasCourse, CanvasUser } from './types'\n\nexport class AccountsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async get(accountId: number): Promise<CanvasAccount> {\n    return this.client.request<CanvasAccount>(`/api/v1/accounts/${accountId}`)\n  }\n\n  async list(): Promise<CanvasAccount[]> {\n    return this.client.paginate<CanvasAccount>('/api/v1/accounts')\n  }\n\n  async listSubAccounts(accountId: number): Promise<CanvasAccount[]> {\n    return this.client.paginate<CanvasAccount>(`/api/v1/accounts/${accountId}/sub_accounts`)\n  }\n\n  async listCourses(accountId: number, params?: { search_term?: string }): Promise<CanvasCourse[]> {\n    const query: Record<string, string> = {}\n    if (params?.search_term) query.search_term = params.search_term\n    return this.client.paginate<CanvasCourse>(\n      `/api/v1/accounts/${accountId}/courses`,\n      Object.keys(query).length ? query : undefined,\n    )\n  }\n\n  async listUsers(accountId: number, params?: { search_term?: string }): Promise<CanvasUser[]> {\n    const query: Record<string, string> = {}\n    if (params?.search_term) query.search_term = params.search_term\n    return this.client.paginate<CanvasUser>(\n      `/api/v1/accounts/${accountId}/users`,\n      Object.keys(query).length ? query : undefined,\n    )\n  }\n\n  async getReports(accountId: number): Promise<CanvasAccountReport[]> {\n    return this.client.request<CanvasAccountReport[]>(`/api/v1/accounts/${accountId}/reports`)\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type {\n  CanvasCourseActivitySummary,\n  CanvasStudentActivitySummary,\n  CanvasActivityStreamItem,\n  CourseSearchResult,\n} from './types'\n\nexport const SEARCH_CONTENT_TYPES = [\n  'pages',\n  'discussions',\n  'assignments',\n  'announcements',\n] as const\nexport type SearchContentType = (typeof SEARCH_CONTENT_TYPES)[number]\n\nexport class AnalyticsModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async searchContentType(\n    courseId: number,\n    searchTerm: string,\n    type: SearchContentType,\n  ): Promise<CourseSearchResult[]> {\n    switch (type) {\n      case 'pages': {\n        const pages = await this.client.paginate<{ page_id: number; title: string; url: string }>(\n          `/api/v1/courses/${courseId}/pages`,\n          { search_term: searchTerm },\n        )\n        return pages.map((p) => ({\n          id: p.page_id,\n          title: p.title,\n          type: 'page' as const,\n          url: p.url,\n          course_id: courseId,\n        }))\n      }\n      case 'assignments': {\n        const assignments = await this.client.paginate<{ id: number; name: string }>(\n          `/api/v1/courses/${courseId}/assignments`,\n          { search_term: searchTerm },\n        )\n        return assignments.map((a) => ({\n          id: a.id,\n          title: a.name,\n          type: 'assignment' as const,\n          course_id: courseId,\n        }))\n      }\n      case 'discussions': {\n        const discussions = await this.client.paginate<{ id: number; title: string }>(\n          `/api/v1/courses/${courseId}/discussion_topics`,\n          { search_term: searchTerm },\n        )\n        return discussions.map((d) => ({\n          id: d.id,\n          title: d.title,\n          type: 'discussion' as const,\n          course_id: courseId,\n        }))\n      }\n      case 'announcements': {\n        const announcements = await this.client.paginate<{ id: number; title: string }>(\n          `/api/v1/courses/${courseId}/discussion_topics`,\n          { search_term: searchTerm, only_announcements: 'true' },\n        )\n        return announcements.map((a) => ({\n          id: a.id,\n          title: a.title,\n          type: 'announcement' as const,\n          course_id: courseId,\n        }))\n      }\n      default: {\n        const _exhaustive: never = type\n        throw new Error(`Unknown content type: ${_exhaustive}`)\n      }\n    }\n  }\n\n  async getCourseActivity(courseId: number): Promise<CanvasCourseActivitySummary[]> {\n    return this.client.request<CanvasCourseActivitySummary[]>(\n      `/api/v1/courses/${courseId}/analytics/activity`,\n    )\n  }\n\n  async getStudentActivity(\n    courseId: number,\n    studentId: number,\n  ): Promise<CanvasStudentActivitySummary> {\n    return this.client.request<CanvasStudentActivitySummary>(\n      `/api/v1/courses/${courseId}/analytics/users/${studentId}/activity`,\n    )\n  }\n\n  async getCourseActivityStream(courseId: number): Promise<CanvasActivityStreamItem[]> {\n    return this.client.request<CanvasActivityStreamItem[]>(\n      `/api/v1/courses/${courseId}/activity_stream/summary`,\n    )\n  }\n}\n","import type { CanvasHttpClient } from './client'\nimport type {\n  CanvasDashboardCard,\n  CanvasTodoItem,\n  CanvasUpcomingEvent,\n  CanvasMissingSubmission,\n} from './types'\n\nexport class DashboardModule {\n  constructor(private client: CanvasHttpClient) {}\n\n  async getDashboardCards(): Promise<CanvasDashboardCard[]> {\n    return this.client.request<CanvasDashboardCard[]>('/api/v1/dashboard/dashboard_cards')\n  }\n\n  async getTodoItems(): Promise<CanvasTodoItem[]> {\n    return this.client.paginate<CanvasTodoItem>('/api/v1/users/self/todo')\n  }\n\n  async getUpcomingEvents(): Promise<CanvasUpcomingEvent[]> {\n    return this.client.request<CanvasUpcomingEvent[]>('/api/v1/users/self/upcoming_events')\n  }\n\n  async getMissingSubmissions(): Promise<CanvasMissingSubmission[]> {\n    return this.client.paginate<CanvasMissingSubmission>('/api/v1/users/self/missing_submissions')\n  }\n}\n","import { CanvasHttpClient } from './client'\nimport type { CanvasClientConfig } from './types'\nimport { CoursesModule } from './courses'\nimport { AssignmentsModule } from './assignments'\nimport { SubmissionsModule } from './submissions'\nimport { RubricsModule } from './rubrics'\nimport { QuizzesModule } from './quizzes'\nimport { FilesModule } from './files'\nimport { UsersModule } from './users'\nimport { GroupsModule } from './groups'\nimport { EnrollmentsModule } from './enrollments'\nimport { DiscussionsModule } from './discussions'\nimport { ModulesModule } from './modules'\nimport { PagesModule } from './pages'\nimport { CalendarModule } from './calendar'\nimport { ConversationsModule } from './conversations'\nimport { PeerReviewsModule } from './peer-reviews'\nimport { AccountsModule } from './accounts'\nimport { AnalyticsModule } from './analytics'\nimport { DashboardModule } from './dashboard'\n\nexport class CanvasClient {\n  private client: CanvasHttpClient\n  courses: CoursesModule\n  assignments: AssignmentsModule\n  submissions: SubmissionsModule\n  rubrics: RubricsModule\n  quizzes: QuizzesModule\n  files: FilesModule\n  users: UsersModule\n  groups: GroupsModule\n  enrollments: EnrollmentsModule\n  discussions: DiscussionsModule\n  modules: ModulesModule\n  pages: PagesModule\n  calendar: CalendarModule\n  conversations: ConversationsModule\n  peerReviews: PeerReviewsModule\n  accounts: AccountsModule\n  analytics: AnalyticsModule\n  dashboard: DashboardModule\n\n  constructor(config: CanvasClientConfig) {\n    this.client = new CanvasHttpClient(config)\n    this.courses = new CoursesModule(this.client)\n    this.assignments = new AssignmentsModule(this.client)\n    this.submissions = new SubmissionsModule(this.client)\n    this.rubrics = new RubricsModule(this.client)\n    this.quizzes = new QuizzesModule(this.client)\n    this.files = new FilesModule(this.client)\n    this.users = new UsersModule(this.client)\n    this.groups = new GroupsModule(this.client)\n    this.enrollments = new EnrollmentsModule(this.client)\n    this.discussions = new DiscussionsModule(this.client)\n    this.modules = new ModulesModule(this.client)\n    this.pages = new PagesModule(this.client)\n    this.calendar = new CalendarModule(this.client)\n    this.conversations = new ConversationsModule(this.client)\n    this.peerReviews = new PeerReviewsModule(this.client)\n    this.accounts = new AccountsModule(this.client)\n    this.analytics = new AnalyticsModule(this.client)\n    this.dashboard = new DashboardModule(this.client)\n  }\n}\n\nexport { CanvasHttpClient, CanvasApiError } from './client'\nexport type * from './types'\n"]}