@classroomio/mcp 0.0.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +115 -5
  2. package/dist/index.js +16 -1
  3. package/package.json +9 -4
package/README.md CHANGED
@@ -58,6 +58,84 @@ Current tools:
58
58
  - `tag_courses`
59
59
  - `publish_course_draft`
60
60
  - `publish_course_draft_to_existing_course`
61
+ - `list_course_members`
62
+ - `add_course_member`
63
+ - `get_course_member`
64
+ - `update_course_member`
65
+ - `delete_course_member`
66
+ - `reset_course_member_progress`
67
+ - `get_course_member_analytics`
68
+ - `list_course_invites`
69
+ - `create_course_invite`
70
+ - `revoke_course_invite`
71
+ - `list_org_cohorts`
72
+ - `create_cohort`
73
+ - `get_cohort`
74
+ - `update_cohort`
75
+ - `delete_cohort`
76
+ - `list_cohort_members`
77
+ - `add_cohort_members`
78
+ - `update_cohort_member`
79
+ - `delete_cohort_member`
80
+ - `list_cohort_courses`
81
+ - `add_cohort_course`
82
+ - `remove_cohort_course`
83
+ - `list_cohort_newsfeed`
84
+ - `create_cohort_newsfeed_post`
85
+ - `update_cohort_newsfeed_post`
86
+ - `update_cohort_newsfeed_reaction`
87
+ - `delete_cohort_newsfeed_post`
88
+ - `list_cohort_newsfeed_comments`
89
+ - `create_cohort_newsfeed_comment`
90
+ - `delete_cohort_newsfeed_comment`
91
+ - `list_cohort_goals`
92
+ - `create_cohort_goal`
93
+ - `get_cohort_goal`
94
+ - `update_cohort_goal`
95
+ - `archive_cohort_goal`
96
+ - `delete_cohort_goal`
97
+ - `evaluate_cohort_goal`
98
+ - `evaluate_all_cohort_goals`
99
+ - `get_org_goals_overview`
100
+ - `list_my_cohort_goals`
101
+ - `list_my_enrolled_cohorts`
102
+ - `invite_students_to_cohort`
103
+ - `assign_students_to_cohort`
104
+ - `get_cohort_invite_link`
105
+ - `create_cohort_invite_link`
106
+ - `set_cohort_invite_link_revoked`
107
+ - `get_org_analytics`
108
+ - `list_compliance_learners`
109
+ - `get_learner_analytics`
110
+ - `get_course_analytics`
111
+ - `list_course_analytics_students`
112
+
113
+ Course certificate tools:
114
+
115
+ - `get_course_certificate`
116
+ - `update_course_certificate`
117
+ - `list_course_certificates`
118
+ - `download_course_certificate`
119
+
120
+ Certificate tools call the public API certificate endpoints. MCP keys get the `course:certificate:read` and `course:certificate:write` scopes by default. Existing MCP keys that still have the default scope set were given them too; a key created with a narrower scope list is left unchanged, so create a new key to use these tools. These scopes open only the certificate endpoints.
121
+
122
+ The tools act as the person who created the key, with the same permissions that person has in the dashboard. That role is checked on every call, so if the creator loses access, the key loses it too:
123
+
124
+ - Reading the certificate settings and design needs them to be a member of the course (including access through a program) or an org admin.
125
+ - Changing the settings or design, listing who earned the certificate, and downloading a certificate need them to be a course tutor/admin or an org admin.
126
+
127
+ `get_course_certificate` and `update_course_certificate` return effective settings: stored values with the dashboard's defaults filled in where nothing is stored (`isDownloadable` false, `threshold` 100, the default design, and so on).
128
+
129
+ `update_course_certificate` is a partial update: fields you leave out keep their values, and `null` clears `deadline`, `requiredExerciseId`, `exerciseMinScorePercent`, or `emailMessage`. `design` is replaced as a whole object, so read it first and send the full design. `deadline` must be an ISO 8601 datetime with a timezone, for example `2026-12-31T23:59:59Z`. Like the dashboard, it needs a paid plan: on the Basic (free) plan it fails with 403 `UPGRADE_REQUIRED`.
130
+
131
+ `list_course_certificates` lists the students who earned the course certificate, with when they earned it and when the certificate email was sent. It takes `page` and `limit` (default 20, max 100) and an optional `search` on name or email. `download_course_certificate` takes a `memberId` from that list and a `format` of `pdf` (default) or `png`.
132
+
133
+ What the tools cover compared with the dashboard:
134
+
135
+ - Covered: certificate settings and design, the list of students who earned the certificate, and downloading an issued certificate.
136
+ - Not covered, on purpose: previewing a design, which is a UI concern.
137
+ - Not covered yet: compliance certificate history. For compliance courses, the dashboard also shows each learner's cycle-by-cycle completion and recertification history. That belongs to a separate compliance API and is not part of these tools.
138
+ - Not covered because the dashboard does not have it: manual issuance. Certificates are issued automatically when a student meets the course's completion rules.
61
139
 
62
140
  ## Auth Model
63
141
 
@@ -74,6 +152,34 @@ ClassroomIO API:
74
152
 
75
153
  The MCP package never decides permissions.
76
154
 
155
+ Course member and invite tools call the public API (`/public-api/v1/courses/:id/members` and `/public-api/v1/courses/:id/invites`) and need the key's `course:member:read` / `course:member:write` scopes. The course draft/exercise tools above call internal-only endpoints and use their own scopes (`course_import:draft:*`, `course:read`/`write`, etc.). Both kinds count toward the same MCP rate limits.
156
+
157
+ Course member and invite tools act as the person who created the API key, with the same rule as the dashboard's People and Invites pages: the key creator must be a tutor/admin of the course or an org admin. Adding a member by `profileId` or email requires that person to already be in the organization; adding someone already in the course fails with 409.
158
+
159
+ Cohort tools call the public API (`/public-api/v1/cohorts/...`) and need the key's `cohort:read` (reads) and `cohort:write` (everything else) scopes, which MCP keys have by default. Analytics tools call `/public-api/v1/analytics/...` and `/public-api/v1/courses/{courseId}/analytics/...` and need `analytics:read`, also on by default. MCP keys don't get `public_api:*`, so the only public API routes they can reach are the cohort, course member and invite, course certificate, and analytics routes. The course/draft tools above call other, internal-only endpoints and use their own scopes.
160
+
161
+ Cohort tools act as the person who created the API key and follow the same rules as the dashboard:
162
+
163
+ - Reads need the key creator to be a cohort member or an org admin.
164
+ - Other writes, including invites, invite links, and goal evaluation, need the key creator to be a cohort tutor/admin or an org admin.
165
+ - Posts, comments, and reactions are made as the key creator, so they also need the key creator to be a member of the cohort. A reaction only ever changes the key creator's own reaction.
166
+ - A comment can also be deleted by its author.
167
+ - `get_org_goals_overview` needs the key creator to be an org admin or tutor.
168
+ - `list_my_enrolled_cohorts` and `list_my_cohort_goals` return the key creator's own data in the key's organization.
169
+
170
+ `add_cohort_members` creates memberships directly and sends no email; `invite_students_to_cohort` is the dashboard invite flow (organization invites plus emails).
171
+
172
+ List tools (`list_org_cohorts`, `list_cohort_members`, `list_cohort_courses`, `list_cohort_goals`, `list_cohort_newsfeed_comments`, `list_my_enrolled_cohorts`, `list_my_cohort_goals`, `get_org_goals_overview`) take `page` and `limit` (default 20, max 100) and return `{ data, pagination }`. `list_cohort_newsfeed` is cursor-based: pass the returned `nextCursor` back as `cursor`.
173
+
174
+ Analytics tools are read-only, cost no credits, and act as the key creator:
175
+
176
+ - `get_org_analytics` returns the sections picked with `include` (default `overview`): `overview`, `traffic`, `countries`, `funnel`, `courseTypes`, `topCourses`, `loginActivity`, `compliance`. It takes `days` (7, 30, 90 or 365; default 30) and `limit` (1-20, default 5) for list sections, and returns `{ data, meta }`.
177
+ - `get_org_analytics` and `get_learner_analytics` need the key creator to be an org admin or tutor. (The dashboard server lets any org member read these; the tools follow the dashboard UI, where only admins and tutors reach the analytics pages.) `loginActivity` and `compliance` need an org admin; for a tutor they are left out and listed in `meta.omitted`.
178
+ - `list_compliance_learners` needs an org admin.
179
+ - `get_course_analytics` (sections `summary`, `funnel`) and `list_course_analytics_students` need a course tutor/admin or an org admin.
180
+ - Each section is cached for up to 10 minutes (login activity: 24 hours); `meta.generatedAt` says when the oldest one was computed.
181
+ - `list_compliance_learners` takes `page` and `limit` (default 20, max 100); `list_course_analytics_students` caps `limit` at 50. Both return `{ data, pagination }`.
182
+
77
183
  ## Required Environment Variables
78
184
 
79
185
  - `CLASSROOMIO_API_URL`
@@ -430,15 +536,19 @@ Supported `questionTypeId` values for exercise payloads:
430
536
  - `1` `RADIO` - Single answer
431
537
  - `2` `CHECKBOX` - Multiple answers
432
538
  - `3` `TEXTAREA` - Paragraph
433
- - `4` `TRUE_FALSE` - True/False
539
+ - `4` `TRUE_FALSE` - True/False (factual statements; options: True, False; auto-graded)
434
540
  - `5` `SHORT_ANSWER` - Short answer
435
541
  - `6` `NUMERIC` - Numeric answer
436
542
  - `7` `FILL_BLANK` - Fill in the blank
437
543
  - `8` `FILE_UPLOAD` - File upload
438
- - `9` `MATCHING` - Matching
439
- - `10` `ORDERING` - Ordering
440
- - `11` `HOTSPOT` - Hotspot
441
- - `12` `LINK` - Links
544
+ - `9` `ORDERING` - Ordering
545
+ - `10` `LINK` - Links
546
+ - `11` `WORD_BANK` - Word bank
547
+ - `12` `STAR` - Star rating
548
+ - `13` `VIDEO_RECORDING` - Video recording
549
+ - `14` `THUMBS` - Thumbs up/down (open-ended poll with customizable Yes/No labels; no correct answer)
550
+
551
+ `TRUE_FALSE` is auto-graded with `settings.correctValue` (boolean) and fixed True/False labels for factual statements. `THUMBS` is open-ended (not auto-graded): two customizable Yes/No-style options with thumbs icons for sentiment or poll-style questions — do not set `settings.correctValue`. `MATCHING` and `HOTSPOT` are disabled and must not be used.
442
552
 
443
553
  ## Operational Notes
444
554
 
package/dist/index.js CHANGED
@@ -1,2 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import{McpServer as Gt}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as kt}from"@modelcontextprotocol/sdk/server/stdio.js";var S=class extends Error{constructor(n,a,u,d){super(n);this.status=a;this.code=u;this.field=d;this.name="ClassroomIoApiError"}},A=class{constructor(t){this.config=t}async createCourseDraft(t){return this.request("/organization/course-import/drafts",{method:"POST",body:t})}async createCourseDraftFromCourse(t){return this.request("/organization/course-import/drafts/from-course",{method:"POST",body:t})}async getCourseStructure(t){return this.request(`/organization/course-import/courses/${t}/structure`,{method:"GET"})}async updateCourseLandingPage(t,n){return this.request(`/course/${t}/landing-page`,{method:"PUT",body:n})}async reorderCourseContent(t,n){return this.request(`/course/${t}/content/reorder`,{method:"PUT",body:n})}async getCourseDraft(t){return this.request(`/organization/course-import/drafts/${t}`,{method:"GET"})}async listOrganizationCourses(t={}){let n=new URLSearchParams;t.tags&&n.set("tags",t.tags);let a=n.toString()?`?${n.toString()}`:"";return this.request(`/organization/courses${a}`,{method:"GET"})}async listCourseExercises(t,n={}){let a=new URLSearchParams;n.lessonId&&a.set("lessonId",n.lessonId),n.sectionId&&a.set("sectionId",n.sectionId);let u=a.toString()?`?${a.toString()}`:"";return this.request(`/course/${t}/exercise${u}`,{method:"GET"})}async getCourseExercise(t,n){return this.request(`/course/${t}/exercise/${n}`,{method:"GET"})}async createCourseExercise(t,n){return this.request(`/course/${t}/exercise`,{method:"POST",body:{...n,courseId:t}})}async createCourseExerciseFromTemplate(t,n){return this.request(`/course/${t}/exercise/from-template`,{method:"POST",body:n})}async updateCourseExercise(t,n,a){return this.request(`/course/${t}/exercise/${n}`,{method:"PUT",body:a})}async updateCourseDraft(t,n){return this.request(`/organization/course-import/drafts/${t}`,{method:"PUT",body:n})}async tagCourseDraft(t,n){return this.request(`/organization/course-import/drafts/${t}/tags`,{method:"PUT",body:n})}async publishCourseDraft(t,n){return this.request(`/organization/course-import/drafts/${t}/publish`,{method:"POST",body:n})}async publishCourseDraftToExistingCourse(t,n){return this.request(`/organization/course-import/drafts/${t}/publish-existing-course`,{method:"POST",body:n})}async tagCourses(t){return this.request("/organization/tags/courses/assign",{method:"PUT",body:t})}async request(t,n){let a=await fetch(new URL(t,this.config.CLASSROOMIO_API_URL),{method:n.method,headers:{Authorization:`Bearer ${this.config.CLASSROOMIO_API_KEY}`,"content-type":"application/json","user-agent":this.config.CLASSROOMIO_USER_AGENT},body:n.body?JSON.stringify(n.body):void 0}),u=await a.json().catch(()=>null);if(!a.ok){let d=u;throw new S(d?.error??d?.message??`ClassroomIO request failed with status ${a.status}`,a.status,d?.code,d?.field)}if(!u||typeof u!="object"||!("success"in u)||!u.success)throw new S("ClassroomIO returned an invalid response payload",a.status);return u.data}};import{z as _}from"zod";var we=_.object({CLASSROOMIO_API_URL:_.url().default("https://api.classroomio.com"),CLASSROOMIO_API_KEY:_.string().min(1),CLASSROOMIO_USER_AGENT:_.string().min(1).default("classroomio-mcp/0.0.9")});function q(o=process.env){return we.parse(o)}import*as c from"zod";var Re=["#EF4444","#F97316","#F59E0B","#84CC16","#22C55E","#14B8A6","#06B6D4","#3B82F6","#8B5CF6","#EC4899"],B=c.enum(Re),qt=c.object({groupId:c.uuid()}),Le=c.object({name:c.string().min(1).max(80),description:c.string().max(240).optional(),order:c.number().int().min(0).optional()}),Bt=Le.partial().refine(o=>Object.keys(o).length>0,{message:"At least one field is required"}),Qt=c.object({tagId:c.uuid()}),Yt=c.object({name:c.string().min(1).max(80),description:c.string().max(240).optional(),groupId:c.uuid(),color:B}),Xt=c.object({name:c.string().min(1).max(80).optional(),description:c.string().max(240).optional(),groupId:c.uuid().optional(),color:B.optional()}).refine(o=>Object.keys(o).length>0,{message:"At least one field is required"}),$t=c.object({courseId:c.uuid()}),Vt=c.object({tagIds:c.array(c.uuid()).max(100).default([])}),Ze=c.enum(["merge","replace"]).default("merge"),De=c.string().trim().min(1).max(80),Q=c.object({draftId:c.string().uuid()}),D=c.object({tagNames:c.array(De).min(1).max(100),mode:Ze,groupName:c.string().trim().min(1).max(80).optional()}),N=D.extend({courseIds:c.array(c.string().uuid()).min(1).max(100)});import*as x from"zod";var to=x.object({recipientCsv:x.string().max(25e3),courseIds:x.array(x.string().uuid()).optional(),allCourses:x.boolean().optional().default(!1),sendEmail:x.boolean().default(!0)}),oo=x.object({profileIds:x.array(x.string().uuid()).min(1).max(500),courseIds:x.array(x.string().uuid()).min(1),sendEmail:x.boolean().default(!0)});import*as i from"zod";var Y=["academy","app","apps","blog","build","campaign","church","cloud","community","conference","course","courses","demo","dev","forum","group","groups","help","launch","launchweek","mobile","play","prod","production","schools","stage","staging","support","teacher","teachers","tech","training"];var X;(function(o){o.Section="SECTION",o.Lesson="LESSON",o.Exercise="EXERCISE"})(X||(X={}));var mo=i.object({siteName:i.string().min(1).optional(),customDomain:i.string().min(1).optional(),isCustomDomainVerified:i.boolean().optional()}),go=i.object({siteName:i.string().min(1),tags:i.string().optional()}),U=i.object({tags:i.string().optional()}),zo=i.object({siteName:i.string().min(1)}),fo=i.object({orgId:i.uuid(),planName:i.enum(["EARLY_ADOPTER","ENTERPRISE","BASIC"]),subscriptionId:i.string().min(1),triggeredBy:i.number().int().positive(),payload:i.record(i.string(),i.unknown())}),Io=i.object({subscriptionId:i.string().min(1),payload:i.record(i.string(),i.unknown())}),Co=i.object({subscriptionId:i.string().min(1),payload:i.record(i.string(),i.unknown())}),xo=i.object({name:i.string().min(5).refine(o=>!/^[-]|[-]$/.test(o),{message:"Organization name cannot start or end with a hyphen"}),siteName:i.string().min(5).refine(o=>!/^[-]|[-]$/.test(o),{message:"Site name cannot start or end with a hyphen"}).refine(o=>!Y.includes(o),{message:"Sitename already exists."})}),Eo=i.object({name:i.string().min(5).refine(o=>!/^[-]|[-]$/.test(o),{message:"Organization name cannot start or end with a hyphen"}).optional(),avatarUrl:i.url().optional(),theme:i.string().optional(),landingpage:i.record(i.string(),i.unknown()).optional(),siteName:i.string().min(1).optional(),customDomain:i.string().nullable().optional(),isCustomDomainVerified:i.boolean().optional(),customization:i.record(i.string(),i.unknown()).optional(),disableSignup:i.boolean().optional(),disableSignupMessage:i.string().optional(),disableEmailPassword:i.boolean().optional(),disableGoogleAuth:i.boolean().optional(),settings:i.object({signup:i.object({inviteOnly:i.boolean().optional()}).optional()}).optional()}),yo=i.object({emails:i.array(i.string().email()).min(1).max(50),roleId:i.number().int().positive()}),bo=i.object({memberId:i.coerce.number().int().positive()}),To=i.object({userId:i.uuid()});import*as z from"zod";var So=z.object({orgId:z.uuid(),quizId:z.uuid()}),Oo=z.object({orgId:z.uuid()}),Ao=z.object({title:z.string().min(1),questions:z.array(z.any()).optional(),timelimit:z.string().optional(),theme:z.string().optional()}),_o=z.object({title:z.string().min(1).optional(),questions:z.array(z.any()).optional(),timelimit:z.string().optional(),theme:z.string().optional()});import*as P from"zod";var wo=P.object({orgId:P.uuid()});import*as w from"zod";var Lo=w.object({token:w.string().min(10).max(512)});import*as p from"zod";var Ne=["OKTA","GOOGLE_WORKSPACE","AUTH0"],Do=p.object({provider:p.enum(Ne),displayName:p.string().min(1,"Display name is required"),issuer:p.url("Must be a valid URL"),domain:p.string().min(1,"Domain is required").regex(/^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/,"Invalid domain format"),clientId:p.string().min(1,"Client ID is required"),clientSecret:p.string().min(1,"Client secret is required"),scopes:p.string().default("openid profile email")}),No=p.object({displayName:p.string().min(1).optional(),issuer:p.url().optional(),domain:p.string().optional(),clientId:p.string().optional(),clientSecret:p.string().optional(),scopes:p.string().optional(),isActive:p.boolean().optional()}),Uo=p.object({forceSso:p.boolean().optional(),autoJoinSsoDomains:p.boolean().optional(),breakGlassEnabled:p.boolean().optional(),defaultRoleId:p.number().int().positive().optional(),roleMapping:p.record(p.string(),p.number()).optional()}),jo=p.object({email:p.email("Valid email is required")}),vo=p.object({orgId:p.uuid()});import{z as h}from"zod";var Fo=h.object({token:h.string().min(1),redirect:h.string().optional()}),Mo=h.object({sub:h.uuid(),email:h.email(),type:h.literal("login-link")});import{z as y}from"zod";var qo=y.object({token:y.string().min(1),redirect:y.string().optional()}),Bo=y.object({sub:y.string(),email:y.email(),name:y.string().optional(),avatar:y.url().optional(),iat:y.number(),exp:y.number()});import{z as b}from"zod";var j=b.enum(["mcp","api","zapier"]),Ue=b.enum(["course_import:draft:create","course_import:draft:read","course_import:draft:update","course_import:draft:publish","course:read","course:write","course:tag:write","course:exercise:read","course:exercise:write","public_api:*"]),Xo=b.object({type:j.optional()}),$o=b.object({type:j.default("mcp")}),Vo=b.object({type:j,label:b.string().min(1).max(120).optional(),expiresAt:b.string().datetime().optional(),scopes:b.array(Ue).min(1).optional()}),Jo=b.object({keyId:b.string().uuid()});import*as s from"zod";var m={RADIO:"RADIO",CHECKBOX:"CHECKBOX",TEXTAREA:"TEXTAREA",TRUE_FALSE:"TRUE_FALSE",SHORT_ANSWER:"SHORT_ANSWER",NUMERIC:"NUMERIC",FILL_BLANK:"FILL_BLANK",FILE_UPLOAD:"FILE_UPLOAD",MATCHING:"MATCHING",ORDERING:"ORDERING",HOTSPOT:"HOTSPOT",LINK:"LINK"},pr=[m.RADIO,m.CHECKBOX,m.TEXTAREA];var R=[{key:m.RADIO,typename:"RADIO",label:"Single answer",id:1,autoGradable:!0,supportsPartialCredit:!1,manualGradingRequired:!1},{key:m.CHECKBOX,typename:"CHECKBOX",label:"Multiple answers",id:2,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:m.TEXTAREA,typename:"TEXTAREA",label:"Paragraph",id:3,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!0},{key:m.TRUE_FALSE,typename:"TRUE_FALSE",label:"True/False",id:4,autoGradable:!0,supportsPartialCredit:!1,manualGradingRequired:!1},{key:m.SHORT_ANSWER,typename:"SHORT_ANSWER",label:"Short answer",id:5,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!0},{key:m.NUMERIC,typename:"NUMERIC",label:"Numeric answer",id:6,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:m.FILL_BLANK,typename:"FILL_BLANK",label:"Fill in the blank",id:7,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:m.FILE_UPLOAD,typename:"FILE_UPLOAD",label:"File upload",id:8,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!0},{key:m.MATCHING,typename:"MATCHING",label:"Matching",id:9,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:m.ORDERING,typename:"ORDERING",label:"Ordering",id:10,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:m.HOTSPOT,typename:"HOTSPOT",label:"Hotspot",id:11,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:m.LINK,typename:"LINK",label:"Links",id:12,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!0}],je=Object.freeze(R.reduce((o,t)=>(o[t.key]=t,o),{})),v=Object.freeze(R.reduce((o,t)=>(o[t.key]=t.id,o),{})),ve=Object.freeze(R.reduce((o,t)=>(o[t.typename]=t.key,o),{})),Ge=Object.freeze(R.reduce((o,t)=>(o[t.id]=t.key,o),{}));var ke=new Set(["true","1","yes"]),Fe=new Set(["false","0","no"]);function Me(o){let t=o.trim().toLowerCase();if(ke.has(t))return!0;if(Fe.has(t))return!1}var Ke={type:"RADIO",toApiPayload(o,t){return{questionId:t,optionId:o.optionId}},fromApiPayload(o){let t=o.optionId;return t===void 0||Number.isNaN(t)?null:{type:"RADIO",optionId:t}}},He={type:"CHECKBOX",toApiPayload(o,t){return{questionId:t,answer:JSON.stringify({type:"CHECKBOX",optionIds:o.optionIds})}},fromApiPayload(o){if(!o.answer)return null;let{optionIds:t}=JSON.parse(o.answer);return Array.isArray(t)?{type:"CHECKBOX",optionIds:t}:null}},qe={type:"TRUE_FALSE",toApiPayload(o,t){return{questionId:t,answer:String(o.value)}},fromApiPayload(o){if(o.answer===void 0)return null;let t=Me(o.answer);return t===void 0?null:{type:"TRUE_FALSE",value:t}}},Be={type:"TEXTAREA",toApiPayload(o,t){return{questionId:t,answer:o.text}},fromApiPayload(o){return o.answer===void 0?null:{type:"TEXTAREA",text:o.answer}}},Qe={type:"SHORT_ANSWER",toApiPayload(o,t){return{questionId:t,answer:o.text}},fromApiPayload(o){return o.answer===void 0?null:{type:"SHORT_ANSWER",text:o.answer}}},Ye={type:"NUMERIC",toApiPayload(o,t){return{questionId:t,answer:JSON.stringify({type:"NUMERIC",value:o.value})}},fromApiPayload(o){if(!o.answer)return null;let{value:t}=JSON.parse(o.answer);return{type:"NUMERIC",value:t}}},Xe={type:"FILL_BLANK",toApiPayload(o,t){return{questionId:t,answer:JSON.stringify({type:"FILL_BLANK",answers:o.values})}},fromApiPayload(o){if(!o.answer)return null;let{answers:t}=JSON.parse(o.answer),n=t.map(a=>String(a).trim()).filter(Boolean);return n.length>0?{type:"FILL_BLANK",values:n}:null}},$e={type:"FILE_UPLOAD",toApiPayload(o,t){let n={fileKey:o.fileKey,fileName:o.fileName,mimeType:o.mimeType,size:o.size};return{questionId:t,answer:JSON.stringify(n)}},fromApiPayload(o){if(!o.answer)return null;let t=JSON.parse(o.answer);return{type:"FILE_UPLOAD",fileKey:t.fileKey,fileName:t.fileName??"",mimeType:t.mimeType,size:t.size}}},Ve={type:"MATCHING",toApiPayload(o,t){return{questionId:t,answer:JSON.stringify({type:"MATCHING",value:o.pairs})}},fromApiPayload(o){if(!o.answer)return null;let{value:t}=JSON.parse(o.answer);return t.length>0?{type:"MATCHING",pairs:t}:null}},Je={type:"ORDERING",toApiPayload(o,t){return{questionId:t,answer:JSON.stringify({type:"ORDERING",value:o.orderedValues})}},fromApiPayload(o){if(!o.answer)return null;let{value:t}=JSON.parse(o.answer);return t.length>0?{type:"ORDERING",orderedValues:t}:null}},We={type:"LINK",toApiPayload(o,t){return{questionId:t,answer:JSON.stringify({type:"LINK",links:o.urls})}},fromApiPayload(o){if(!o.answer)return null;let{links:t}=JSON.parse(o.answer),n=t.map(a=>String(a).trim()).filter(Boolean);return n.length>0?{type:"LINK",urls:n}:null}},et={type:"HOTSPOT",toApiPayload(o,t){return{questionId:t,answer:JSON.stringify({type:"HOTSPOT",value:o.coordinates})}},fromApiPayload(o){if(!o.answer)return null;let{value:t}=JSON.parse(o.answer);return t.length>0?{type:"HOTSPOT",coordinates:t}:null}},Tr={[m.RADIO]:Ke,[m.CHECKBOX]:He,[m.TRUE_FALSE]:qe,[m.TEXTAREA]:Be,[m.SHORT_ANSWER]:Qe,[m.NUMERIC]:Ye,[m.FILL_BLANK]:Xe,[m.FILE_UPLOAD]:$e,[m.MATCHING]:Ve,[m.ORDERING]:Je,[m.LINK]:We,[m.HOTSPOT]:et};var $=["video/mp4","video/quicktime","video/x-msvideo","video/x-matroska"],V=["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/msword"];var I=v;var tt=[s.literal(I.RADIO),s.literal(I.CHECKBOX),s.literal(I.TEXTAREA),s.literal(I.TRUE_FALSE),s.literal(I.SHORT_ANSWER),s.literal(I.NUMERIC),s.literal(I.FILL_BLANK),s.literal(I.FILE_UPLOAD),s.literal(I.MATCHING),s.literal(I.ORDERING),s.literal(I.HOTSPOT),s.literal(I.LINK)],L=s.union(tt),ot={[I.RADIO]:[o=>{let t=o.options||[];return t.length>0&&t.length<2?"Options must have at least 2 items for RADIO/CHECKBOX questions":null},o=>{let t=o.options||[];return t.length>0&&!t.some(n=>n.isCorrect===!0)?"Please mark an option as the correct answer":null}],[I.CHECKBOX]:[o=>{let t=o.options||[];return t.length>0&&t.length<2?"Options must have at least 2 items for RADIO/CHECKBOX questions":null},o=>{let t=o.options||[];return t.length>0&&!t.some(n=>n.isCorrect===!0)?"Please mark an option as the correct answer":null}],[I.TRUE_FALSE]:[o=>{let t=o.options||[];return t.length>0&&t.length<2?"True/False questions need both True and False options":null},o=>{let t=o.options||[];return t.length>0&&!t.some(n=>n.isCorrect===!0)?"Please mark an option as the correct answer":null}],[I.TEXTAREA]:[]},rt=s.object({id:s.number().int().optional(),question:s.string().min(1),questionTypeId:L.optional(),points:s.number().int().min(0).optional(),order:s.number().int().min(0).optional(),settings:s.record(s.string(),s.unknown()).optional(),deletedAt:s.string().optional(),options:s.array(s.object({id:s.number().int().optional(),label:s.string().min(1),isCorrect:s.boolean(),settings:s.record(s.string(),s.unknown()).optional(),deletedAt:s.string().optional()})).optional()});function J(o,t){if(o.deletedAt)return;let n=ot[o.questionTypeId??-1]??[];for(let a of n){let u=a(o);u&&t.addIssue({code:"custom",message:u,path:["options"]})}}var nt=rt.superRefine(J),st=s.object({question:s.string().min(1),questionTypeId:L.optional(),points:s.number().int().min(0).optional(),order:s.number().int().min(0).optional(),settings:s.record(s.string(),s.unknown()).optional(),options:s.array(s.object({label:s.string().min(1),isCorrect:s.boolean(),settings:s.record(s.string(),s.unknown()).optional()})).optional()}),it=st.superRefine(J),W=s.object({title:s.string().min(1),description:s.string().optional(),lessonId:s.string().optional(),sectionId:s.string().optional(),order:s.number().int().optional(),courseId:s.string().min(1),dueBy:s.string().optional(),questions:s.array(it).optional()}),ee=s.object({title:s.string().min(1).optional(),description:s.string().optional(),lessonId:s.string().optional(),sectionId:s.string().optional(),order:s.number().int().optional(),isUnlocked:s.boolean().optional(),dueBy:s.string().optional(),questions:s.array(nt).optional()}),G=s.object({exerciseId:s.string().min(1)}),te=s.object({lessonId:s.string().optional(),sectionId:s.string().optional()}),Kr=s.object({exerciseId:s.string().min(1),answers:s.array(s.object({questionId:s.number().int(),optionId:s.number().int().optional(),answer:s.string().optional()})).min(1)}),oe=s.object({lessonId:s.string().optional(),sectionId:s.string().optional(),order:s.number().int().optional(),templateId:s.number().int().min(1)});import*as r from"zod";import*as e from"zod";var Yr=e.object({title:e.string().min(1),description:e.string().optional(),slug:e.string().min(1),organizationId:e.string().min(1)}),Xr=e.object({courseId:e.string().min(1)}),at=e.object({courseId:e.string().min(1)}),$r=e.object({slug:e.string().optional()}),Vr=e.object({slug:e.string().min(1)}),Jr=e.object({courseId:e.string().min(1)}),Wr=e.object({inviteToken:e.string().min(1).optional()}),en=e.object({courseId:e.string().min(1)}),tn=e.object({theme:e.string().min(1),studentName:e.string().min(1),courseName:e.string().min(1),courseDescription:e.string().min(1),orgName:e.string().min(1),orgLogoUrl:e.string().url().optional(),facilitator:e.string().optional()}),on=e.object({courseTitle:e.string().min(1),orgName:e.string().min(1),orgTheme:e.string().min(1),lessons:e.array(e.object({lessonTitle:e.string().min(1),lessonNumber:e.string().min(1),lessonNote:e.string(),slideUrl:e.string().url().optional(),video:e.array(e.string().url()).optional()}))}),rn=e.object({title:e.string().min(1),number:e.string().min(1),orgName:e.string().min(1),note:e.string(),slideUrl:e.string().url().optional(),video:e.array(e.string().url()).optional(),courseTitle:e.string().min(1)}),nn=e.object({fileName:e.string().min(1),fileType:e.enum($)}),sn=e.object({fileName:e.string().min(1),fileType:e.enum(V)}),an=e.object({keys:e.array(e.string().min(1)).min(1)}),re=e.object({id:e.string().min(1),type:e.enum(["LESSON","EXERCISE"]),isUnlocked:e.boolean().optional(),order:e.number().int().min(0).optional(),sectionId:e.string().nullable().optional()}),un=e.object({items:e.array(re).min(1)}),ut=e.object({id:e.string().min(1),order:e.number().int().min(0)}),ct=re.omit({isUnlocked:!0}),k=e.object({sections:e.array(ut).min(1).optional(),items:e.array(ct).min(1).optional()}),ne=k.superRefine((o,t)=>{!o.sections?.length&&!o.items?.length&&t.addIssue({code:e.ZodIssueCode.custom,path:["sections"],message:"Provide sections or items to reorder"});let n=new Set;o.sections?.forEach((u,d)=>{n.has(u.id)&&t.addIssue({code:e.ZodIssueCode.custom,path:["sections",d,"id"],message:"Section IDs must be unique"}),n.add(u.id)});let a=new Set;o.items?.forEach((u,d)=>{u.order===void 0&&u.sectionId===void 0&&t.addIssue({code:e.ZodIssueCode.custom,path:["items",d],message:"Each item must provide order or sectionId"});let g=`${u.type}:${u.id}`;a.has(g)&&t.addIssue({code:e.ZodIssueCode.custom,path:["items",d,"id"],message:"Item IDs must be unique per content type"}),a.add(g)})}),pt=e.object({id:e.string().min(1),type:e.enum(["LESSON","EXERCISE"])}),cn=e.object({sectionId:e.string().min(1).optional(),items:e.array(pt).min(1).optional()}).refine(o=>!!o.sectionId!=!!o.items,{message:"Provide either sectionId or items",path:["sectionId"]}),pn=e.object({title:e.string().min(1),description:e.string().min(1),type:e.enum(["LIVE_CLASS","SELF_PACED"]),organizationId:e.string().min(1)}),se=e.object({show:e.boolean(),description:e.string()}),ie=e.object({name:e.string(),role:e.string(),coursesNo:e.number(),description:e.string(),imgUrl:e.string()}),ae=e.object({templateUrl:e.string()}),ue=e.object({id:e.number(),hide:e.boolean(),name:e.string(),avatar_url:e.string(),rating:e.number(),created_at:e.number(),description:e.string()}),ce=e.array(e.object({id:e.union([e.literal(1),e.literal(2),e.literal(3),e.literal(4)]),name:e.string()})),Z=e.object({requirements:e.string().optional(),description:e.string().optional(),goals:e.string().optional(),videoUrl:e.string().optional(),showDiscount:e.boolean().optional(),discount:e.number().optional(),paymentLink:e.string().optional(),reward:se.optional(),instructor:ie.optional(),certificate:ae.optional(),reviews:e.array(ue).optional(),lessonTabsOrder:ce.optional(),grading:e.boolean().optional(),lessonDownload:e.boolean().optional(),allowNewStudent:e.boolean(),sectionDisplay:e.record(e.string(),e.boolean()).optional(),isContentGroupingEnabled:e.boolean().optional()}),lt=e.object({requirements:e.string().optional(),description:e.string().optional(),goals:e.string().optional(),videoUrl:e.string().optional(),showDiscount:e.boolean().optional(),discount:e.number().optional(),paymentLink:e.string().optional(),reward:se.partial().optional(),instructor:ie.partial().optional(),certificate:ae.partial().optional(),reviews:e.array(ue).optional(),lessonTabsOrder:ce.optional(),grading:e.boolean().optional(),lessonDownload:e.boolean().optional(),allowNewStudent:e.boolean().optional(),sectionDisplay:e.record(e.string(),e.boolean()).optional(),isContentGroupingEnabled:e.boolean().optional()}),ln=e.object({title:e.string().min(1).optional(),description:e.string().min(1).optional(),type:e.enum(["LIVE_CLASS","SELF_PACED"]).optional(),logo:e.string().optional(),slug:e.string().optional(),isPublished:e.boolean().optional(),overview:e.string().optional(),metadata:Z.optional(),cost:e.number().int().min(0).optional(),currency:e.enum(["NGN","USD"]).optional(),isCertificateDownloadable:e.boolean().optional(),certificateTheme:e.string().optional(),tagIds:e.array(e.uuid()).max(100).optional()}),dn=e.object({courseId:e.string().min(1)}),pe=e.object({title:e.string().min(1).optional(),description:e.string().min(1).optional(),overview:e.string().optional(),cost:e.number().int().min(0).optional(),currency:e.enum(["NGN","USD"]).optional(),imageUrl:e.url().optional(),generateImage:e.boolean().optional(),imageQuery:e.string().min(1).max(120).optional(),metadata:lt.optional()}),mn=e.object({courseId:e.string().min(1)}),gn=e.object({courseId:e.string().min(1)}),zn=e.object({profileId:e.string().uuid()}),fn=e.object({courseId:e.string().min(1),userId:e.string().uuid()});var le=r.enum(["en","hi","fr","pt","de","vi","ru","es","pl","da"]),dt="Lesson body HTML only. Do not include the lesson title. Do not use h1 or h2 anywhere in lessonLanguages[].content. Start headings at h3 because that is the highest heading level allowed in lesson content.",de=r.object({code:r.string().min(1),message:r.string().min(1),severity:r.enum(["info","warning","error"])}),mt=r.object({type:r.enum(["prompt","pdf","course"]),label:r.string().min(1),pageStart:r.number().int().min(1).optional(),pageEnd:r.number().int().min(1).optional()}),gt=r.object({title:r.string().min(1),description:r.string().min(1),type:r.enum(["LIVE_CLASS","SELF_PACED"]),locale:le.default("en"),metadata:Z.optional()}),zt=r.object({externalId:r.string().min(1),title:r.string().min(1),order:r.number().int().min(0)}),ft=r.object({externalId:r.string().min(1),sectionExternalId:r.string().min(1),title:r.string().min(1),order:r.number().int().min(0),isUnlocked:r.boolean().optional(),public:r.boolean().optional()}),It=r.object({lessonExternalId:r.string().min(1),locale:le,content:r.string().min(1).describe(dt)}),Ct=r.object({label:r.string().min(1),isCorrect:r.boolean(),settings:r.record(r.string(),r.unknown()).optional()}),xt=r.object({question:r.string().min(1),questionTypeId:L.optional(),points:r.number().int().min(0).optional(),order:r.number().int().min(0).optional(),settings:r.record(r.string(),r.unknown()).optional(),options:r.array(Ct).optional()}),Et=r.object({externalId:r.string().min(1),lessonExternalId:r.string().min(1).optional(),sectionExternalId:r.string().min(1).optional(),title:r.string().min(1),description:r.string().optional(),order:r.number().int().min(0).optional(),dueBy:r.string().optional(),questions:r.array(xt).optional()}),me=r.object({course:gt,tags:r.array(r.string().trim().min(1).max(80)).max(100).default([]),sections:r.array(zt).min(1),lessons:r.array(ft).min(1),lessonLanguages:r.array(It).min(1),exercises:r.array(Et).optional(),sourceReferences:r.array(mt).optional(),warnings:r.array(de).default([])}).superRefine((o,t)=>{let n=new Set;o.tags.forEach((g,E)=>{let H=g.trim().toLowerCase();n.has(H)&&t.addIssue({code:r.ZodIssueCode.custom,path:["tags",E],message:"Draft tags must be unique"}),n.add(H)});let a=new Set;o.sections.forEach((g,E)=>{a.has(g.externalId)&&t.addIssue({code:r.ZodIssueCode.custom,path:["sections",E,"externalId"],message:"Section externalId must be unique"}),a.add(g.externalId)});let u=new Set;o.lessons.forEach((g,E)=>{u.has(g.externalId)&&t.addIssue({code:r.ZodIssueCode.custom,path:["lessons",E,"externalId"],message:"Lesson externalId must be unique"}),u.add(g.externalId),a.has(g.sectionExternalId)||t.addIssue({code:r.ZodIssueCode.custom,path:["lessons",E,"sectionExternalId"],message:"Lesson sectionExternalId must reference an existing section"})}),o.lessonLanguages.forEach((g,E)=>{u.has(g.lessonExternalId)||t.addIssue({code:r.ZodIssueCode.custom,path:["lessonLanguages",E,"lessonExternalId"],message:"Lesson language must reference an existing lesson"})});let d=new Set;o.exercises?.forEach((g,E)=>{d.has(g.externalId)&&t.addIssue({code:r.ZodIssueCode.custom,path:["exercises",E,"externalId"],message:"Exercise externalId must be unique"}),d.add(g.externalId),g.lessonExternalId&&!u.has(g.lessonExternalId)&&t.addIssue({code:r.ZodIssueCode.custom,path:["exercises",E,"lessonExternalId"],message:"Exercise lessonExternalId must reference an existing lesson"}),g.sectionExternalId&&!a.has(g.sectionExternalId)&&t.addIssue({code:r.ZodIssueCode.custom,path:["exercises",E,"sectionExternalId"],message:"Exercise sectionExternalId must reference an existing section"})})}),F=r.object({sourceType:r.enum(["prompt","pdf","course"]),idempotencyKey:r.string().min(1).optional(),summary:r.record(r.string(),r.unknown()).optional(),sourceArtifacts:r.array(r.record(r.string(),r.unknown())).optional(),draft:me}),T=r.object({courseId:r.string().min(1)}),M=r.object({courseId:r.string().min(1),idempotencyKey:r.string().min(1).optional(),summary:r.record(r.string(),r.unknown()).optional(),sourceArtifacts:r.array(r.record(r.string(),r.unknown())).optional()}),O=r.object({draftId:r.string().uuid()}),ge=r.object({summary:r.record(r.string(),r.unknown()).optional(),sourceArtifacts:r.array(r.record(r.string(),r.unknown())).optional(),warnings:r.array(de).optional(),draft:me.optional()}),K=r.object({title:r.string().min(1).optional(),description:r.string().min(1).optional(),type:r.enum(["LIVE_CLASS","SELF_PACED"]).optional(),metadata:Z.optional(),bannerImageUrl:r.string().url().optional(),bannerImageQuery:r.string().min(1).max(120).optional(),generateBannerImage:r.boolean().optional()}),ze=K.extend({courseId:r.string().min(1)});import*as f from"zod";var Tn=f.object({title:f.string().min(1),courseId:f.string().min(1),order:f.number().int().min(0).optional()}),hn=f.object({title:f.string().min(1).optional(),order:f.number().int().min(0).optional()}),Sn=f.object({title:f.string().min(1)}),On=f.object({sectionId:f.string().min(1)}),An=f.object({sections:f.array(f.object({id:f.string().min(1),order:f.number().int().min(0)})).min(1)});import*as l from"zod";var Pn=l.object({courseId:l.string().min(1)}),wn=l.object({courseId:l.string().min(1),inviteId:l.string().uuid()}),Rn=l.object({courseId:l.string().min(1),inviteId:l.string().uuid()}),Ln=l.object({token:l.string().min(1)}),Zn=l.object({courseId:l.uuid()}),yt=l.enum(["ONE_TIME_24H","MULTI_USE_7D","MULTI_USE_30D","CUSTOM"]),Dn=l.object({preset:yt.default("MULTI_USE_30D"),expiresAt:l.string().min(1).optional(),maxUses:l.number().int().min(1).max(1e3).optional(),allowedEmails:l.array(l.string().email()).max(100).optional(),allowedDomains:l.array(l.string().min(1)).max(100).optional(),recipientEmails:l.array(l.string().email()).max(500).optional(),recipientCsv:l.string().max(25e3).optional(),sendEmail:l.boolean().default(!1),metadata:l.record(l.string(),l.unknown()).optional()}).refine(o=>{let t=(o.recipientEmails?.length??0)>0,n=typeof o.recipientCsv=="string"&&o.recipientCsv.trim().length>0;return t||n},{message:"recipientEmails or recipientCsv is required",path:["recipientEmails"]});var Ce=ge.extend({draftId:O.shape.draftId}),xe=D.extend({draftId:Q.shape.draftId}),Ee=te.extend({courseId:T.shape.courseId}),ye=G.extend({courseId:T.shape.courseId}),be=W.omit({courseId:!0}).extend({courseId:T.shape.courseId}),Te=oe.extend({courseId:T.shape.courseId}),he=ee.extend({courseId:T.shape.courseId,exerciseId:G.shape.exerciseId}),Se=pe.extend({courseId:T.shape.courseId}),Oe=k.extend({courseId:T.shape.courseId}),Ae=K.extend({draftId:O.shape.draftId}),_e=ze.extend({draftId:O.shape.draftId}),bt=F.shape,Tt=M.shape,ht=U.shape,St=T.shape,Ot=O.shape,At=Ce.shape,_t=xe.shape,Pt=Ee.shape,wt=ye.shape,Rt=be.shape,Lt=Te.shape,Zt=he.shape,Dt=Se.shape,Nt=Oe.shape,Ut=Ae.shape,jt=_e.shape,vt=N.shape,fe="Supported questionTypeId values: RADIO=1 (Single answer), CHECKBOX=2 (Multiple answers), TEXTAREA=3 (Paragraph), TRUE_FALSE=4 (True/False), SHORT_ANSWER=5 (Short answer), NUMERIC=6 (Numeric answer), FILL_BLANK=7 (Fill in the blank), FILE_UPLOAD=8 (File upload), MATCHING=9 (Matching), ORDERING=10 (Ordering), HOTSPOT=11 (Hotspot), LINK=12 (Links). Use the numeric ids in exercise payloads.",Ie="For draft lesson HTML, put only the lesson body in lessonLanguages[].content. Do not include the lesson title. Do not use h1 or h2 anywhere in lesson HTML. Start headings at h3 because that is the highest heading level allowed in lesson content.";function Pe(o,t){o.tool("list_org_courses","List all courses in the authenticated organization. Use this when the user refers to a course by name and you need to discover the available course IDs first.",ht,async n=>{let a=U.parse(n),u=await t.listOrganizationCourses(a);return C(u)}),o.tool("get_course_structure","Read the current live course structure. Use this before creating a fresh draft for post-publish edits.",St,async n=>{let{courseId:a}=T.parse(n),u=await t.getCourseStructure(a);return C(u)}),o.tool("update_course_landing_page","Update landing-page-facing course fields on a live course, including headline copy, overview, requirements, goals, pricing, reviews, instructor information, and the course image. Use imageUrl to set an explicit cover image, or set generateImage/imageQuery to fetch a random Unsplash-based image.",Dt,async n=>{let{courseId:a,...u}=Se.parse(n),d=await t.updateCourseLandingPage(a,u);return C(d)}),o.tool("reorder_course_content","Batch reorder live course sections and lesson or exercise content without creating a draft. Use this for section ordering or moving/reordering lessons and exercises between sections. For items, pass type as LESSON or EXERCISE and use sectionId to move between sections or null for ungrouped content.",Nt,async n=>{let{courseId:a,...u}=Oe.parse(n),d=ne.parse(u),g=await t.reorderCourseContent(a,d);return C(g)}),o.tool("create_course_draft",`Create a new unpublished course draft from structured course JSON. Use this before the first publish. ${Ie}`,bt,async n=>{let a=F.parse(n),u=await t.createCourseDraft(a);return C(u)}),o.tool("create_course_draft_from_course","Create a fresh draft from an existing live course. Use this after a course has already been published and the user wants more changes.",Tt,async n=>{let a=M.parse(n),u=await t.createCourseDraftFromCourse(a);return C(u)}),o.tool("get_course_draft","Fetch an existing draft. Draft responses include status and publishedCourseId so you can decide whether to keep editing the draft or seed a fresh one from the live course.",Ot,async n=>{let{draftId:a}=O.parse(n),u=await t.getCourseDraft(a);return C(u)}),o.tool("list_course_exercises","List exercises for a live course, optionally filtered by lessonId or sectionId.",Pt,async n=>{let{courseId:a,...u}=Ee.parse(n),d=await t.listCourseExercises(a,u);return C(d)}),o.tool("get_course_exercise","Fetch a single exercise from a live course, including its questions and options.",wt,async n=>{let{courseId:a,exerciseId:u}=ye.parse(n),d=await t.getCourseExercise(a,u);return C(d)}),o.tool("create_course_exercise",`Create a new exercise directly on a live course. Use this for adding exercises after a course has already been published. ${fe}`,Rt,async n=>{let{courseId:a,...u}=be.parse(n),d=await t.createCourseExercise(a,u);return C(d)}),o.tool("create_course_exercise_from_template","Create a new exercise on a live course from an existing template.",Lt,async n=>{let{courseId:a,...u}=Te.parse(n),d=await t.createCourseExerciseFromTemplate(a,u);return C(d)}),o.tool("update_course_exercise",`Update an existing exercise on a live course, including questions and options. ${fe}`,Zt,async n=>{let{courseId:a,exerciseId:u,...d}=he.parse(n),g=await t.updateCourseExercise(a,u,d);return C(g)}),o.tool("update_course_draft",`Update an unpublished draft. If the draft is already published, do not keep editing it blindly; create a fresh draft from the live course first. ${Ie}`,At,async n=>{let{draftId:a,...u}=Ce.parse(n),d=await t.updateCourseDraft(a,u);return C(d)}),o.tool("tag_course_draft","Attach human-readable tags to a draft before publish. The tags are stored on the draft and applied during publish.",_t,async n=>{let{draftId:a,...u}=xe.parse(n),d=await t.tagCourseDraft(a,u);return C(d)}),o.tool("publish_course_draft","Publish an unpublished draft as a new live course. The result includes courseId and courseUrl. After publish, future major edits should usually start from a fresh draft created from the live course.",Ut,async n=>{let{draftId:a,...u}=Ae.parse(n),d=await t.publishCourseDraft(a,u);return C(d)}),o.tool("publish_course_draft_to_existing_course","Apply a fresh draft back onto an existing live course. Use this after reading the live course and creating a new draft from it.",jt,async n=>{let{draftId:a,...u}=_e.parse(n),d=await t.publishCourseDraftToExistingCourse(a,u);return C(d)}),o.tool("tag_courses","Assign tags directly to one or more live courses by name. Default mode is merge, so existing tags are preserved unless replace is requested.",vt,async n=>{let a=N.parse(n),u=await t.tagCourses(a);return C(u)})}function C(o){return{content:[{type:"text",text:JSON.stringify(o)}]}}async function Ft(){let o=q(),t=new A(o),n=new Gt({name:"classroomio-course-authoring",version:"0.0.1"});Pe(n,t);let a=new kt;await n.connect(a),process.stdin.on("close",()=>{n.close()})}Ft().catch(o=>{o instanceof S&&(console.error(JSON.stringify({error:o.message,status:o.status,code:o.code,field:o.field})),process.exit(1)),console.error(o),process.exit(1)});
2
+ import{Readable as gs}from"node:stream";var ue=e=>{let t=new URLSearchParams;return e.page&&t.set("page",String(e.page)),e.limit&&t.set("limit",String(e.limit)),t.toString()?`?${t.toString()}`:""},Bt=e=>{let t=new URLSearchParams;return e.include?.length&&t.set("include",e.include.join(",")),e.days&&t.set("days",String(e.days)),"limit"in e&&e.limit&&t.set("limit",String(e.limit)),t.toString()?`?${t.toString()}`:""},Ie=class extends Error{constructor(o,r,i,c){super(o);this.status=r;this.code=i;this.field=c;this.name="ClassroomIoApiError"}},Fe=class{constructor(t){this.config=t}async createCourseDraft(t){return this.request("/organization/course-import/drafts",{method:"POST",body:t})}async createCourseDraftFromCourse(t){return this.request("/organization/course-import/drafts/from-course",{method:"POST",body:t})}async getCourseStructure(t){return this.request(`/organization/course-import/courses/${t}/structure`,{method:"GET"})}async updateCourseLandingPage(t,o){return this.request(`/course/${t}/landing-page`,{method:"PUT",body:o})}async reorderCourseContent(t,o){return this.request(`/course/${t}/content/reorder`,{method:"PUT",body:o})}async getCourseDraft(t){return this.request(`/organization/course-import/drafts/${t}`,{method:"GET"})}async listOrganizationCourses(t={}){let o=new URLSearchParams;t.tags&&o.set("tags",t.tags);let r=o.toString()?`?${o.toString()}`:"";return this.request(`/organization/courses${r}`,{method:"GET"})}async listCourseExercises(t,o={}){let r=new URLSearchParams;o.lessonId&&r.set("lessonId",o.lessonId),o.sectionId&&r.set("sectionId",o.sectionId);let i=r.toString()?`?${r.toString()}`:"";return this.request(`/course/${t}/exercise${i}`,{method:"GET"})}async getCourseExercise(t,o){return this.request(`/course/${t}/exercise/${o}`,{method:"GET"})}async createCourseExercise(t,o){return this.request(`/course/${t}/exercise`,{method:"POST",body:{...o,courseId:t}})}async createCourseExerciseFromTemplate(t,o){return this.request(`/course/${t}/exercise/from-template`,{method:"POST",body:o})}async updateCourseExercise(t,o,r){return this.request(`/course/${t}/exercise/${o}`,{method:"PUT",body:r})}async updateCourseDraft(t,o){return this.request(`/organization/course-import/drafts/${t}`,{method:"PUT",body:o})}async tagCourseDraft(t,o){return this.request(`/organization/course-import/drafts/${t}/tags`,{method:"PUT",body:o})}async publishCourseDraft(t,o){return this.request(`/organization/course-import/drafts/${t}/publish`,{method:"POST",body:o})}async publishCourseDraftToExistingCourse(t,o){return this.request(`/organization/course-import/drafts/${t}/publish-existing-course`,{method:"POST",body:o})}async tagCourses(t){return this.request("/organization/tags/courses/assign",{method:"PUT",body:t})}async getCourseCertificate(t){return this.request(`/public-api/v1/courses/${t}/certificate`,{method:"GET"})}async updateCourseCertificate(t,o){return this.request(`/public-api/v1/courses/${t}/certificate`,{method:"PATCH",body:o})}async listCourseCertificates(t,o={}){let r=new URLSearchParams;o.page&&r.set("page",String(o.page)),o.limit&&r.set("limit",String(o.limit)),o.search&&r.set("search",o.search);let i=r.toString()?`?${r.toString()}`:"";return this.requestPaginated(`/public-api/v1/courses/${t}/certificates${i}`,{method:"GET"})}async downloadCourseCertificate(t,o,r){let i=await this.send(`/public-api/v1/courses/${t}/certificates/${o}/download?format=${r}`,{method:"GET"});if(!i.ok){let q=await i.json().catch(()=>null);throw Ht(i.status,q)}let c=Buffer.from(await i.arrayBuffer()),b=i.headers.get("content-type")??"application/octet-stream";return{base64:c.toString("base64"),mimeType:b}}async listCourseMembers(t,o={}){let r=new URLSearchParams;o.page&&r.set("page",String(o.page)),o.limit&&r.set("limit",String(o.limit)),o.search&&r.set("search",o.search),o.roleId&&r.set("roleId",String(o.roleId));let i=r.toString()?`?${r.toString()}`:"";return this.requestPaginated(`/public-api/v1/courses/${t}/members${i}`,{method:"GET"})}async addCourseMember(t,o){return this.request(`/public-api/v1/courses/${t}/members`,{method:"POST",body:o})}async getCourseMember(t,o){return this.request(`/public-api/v1/courses/${t}/members/${o}`,{method:"GET"})}async updateCourseMember(t,o,r){return this.request(`/public-api/v1/courses/${t}/members/${o}`,{method:"PUT",body:r})}async deleteCourseMember(t,o){return this.request(`/public-api/v1/courses/${t}/members/${o}`,{method:"DELETE"})}async resetCourseMemberProgress(t,o){return this.request(`/public-api/v1/courses/${t}/members/${o}/reset-progress`,{method:"POST"})}async getCourseMemberAnalytics(t,o,r={}){let i=new URLSearchParams;for(let[b,q]of Object.entries(r))q!==void 0&&i.set(b,String(q));let c=i.toString()?`?${i.toString()}`:"";return this.request(`/public-api/v1/courses/${t}/members/${o}/analytics${c}`,{method:"GET"})}async listCourseInvites(t,o={}){let r=new URLSearchParams;o.page&&r.set("page",String(o.page)),o.limit&&r.set("limit",String(o.limit));let i=r.toString()?`?${r.toString()}`:"";return this.requestPaginated(`/public-api/v1/courses/${t}/invites${i}`,{method:"GET"})}async createCourseInvite(t,o){return this.request(`/public-api/v1/courses/${t}/invites`,{method:"POST",body:o})}async revokeCourseInvite(t,o){return this.request(`/public-api/v1/courses/${t}/invites/${o}/revoke`,{method:"POST"})}async listCohorts(t={}){return this.requestPaginated(`/public-api/v1/cohorts${ue(t)}`,{method:"GET"})}async createCohort(t){return this.request("/public-api/v1/cohorts",{method:"POST",body:t})}async getCohort(t){return this.request(`/public-api/v1/cohorts/${t}`,{method:"GET"})}async updateCohort(t,o){return this.request(`/public-api/v1/cohorts/${t}`,{method:"PUT",body:o})}async deleteCohort(t){return this.request(`/public-api/v1/cohorts/${t}`,{method:"DELETE"})}async listCohortMembers(t,o={}){return this.requestPaginated(`/public-api/v1/cohorts/${t}/members${ue(o)}`,{method:"GET"})}async addCohortMembers(t,o){return this.request(`/public-api/v1/cohorts/${t}/members`,{method:"POST",body:o})}async updateCohortMember(t,o,r){return this.request(`/public-api/v1/cohorts/${t}/members/${o}`,{method:"PUT",body:r})}async deleteCohortMember(t,o){return this.request(`/public-api/v1/cohorts/${t}/members/${o}`,{method:"DELETE"})}async listCohortCourses(t,o={}){return this.requestPaginated(`/public-api/v1/cohorts/${t}/courses${ue(o)}`,{method:"GET"})}async addCohortCourse(t,o){return this.request(`/public-api/v1/cohorts/${t}/courses`,{method:"POST",body:o})}async removeCohortCourse(t,o){return this.request(`/public-api/v1/cohorts/${t}/courses/${o}`,{method:"DELETE"})}async listCohortNewsfeed(t,o={}){let r=new URLSearchParams;o.cursor&&r.set("cursor",o.cursor),o.limit&&r.set("limit",String(o.limit));let i=r.toString()?`?${r.toString()}`:"";return this.request(`/public-api/v1/cohorts/${t}/newsfeed${i}`,{method:"GET"})}async createCohortNewsfeedPost(t,o){return this.request(`/public-api/v1/cohorts/${t}/newsfeed`,{method:"POST",body:o})}async updateCohortNewsfeedPost(t,o,r){return this.request(`/public-api/v1/cohorts/${t}/newsfeed/${o}`,{method:"PUT",body:r})}async setCohortNewsfeedReaction(t,o,r){return this.request(`/public-api/v1/cohorts/${t}/newsfeed/${o}/react`,{method:"PUT",body:r})}async deleteCohortNewsfeedPost(t,o){return this.request(`/public-api/v1/cohorts/${t}/newsfeed/${o}`,{method:"DELETE"})}async listCohortNewsfeedComments(t,o,r={}){return this.requestPaginated(`/public-api/v1/cohorts/${t}/newsfeed/${o}/comments${ue(r)}`,{method:"GET"})}async createCohortNewsfeedComment(t,o,r){return this.request(`/public-api/v1/cohorts/${t}/newsfeed/${o}/comment`,{method:"POST",body:r})}async deleteCohortNewsfeedComment(t,o,r){return this.request(`/public-api/v1/cohorts/${t}/newsfeed/${o}/comment/${r}`,{method:"DELETE"})}async listCohortGoals(t,o={}){return this.requestPaginated(`/public-api/v1/cohorts/${t}/goals${ue(o)}`,{method:"GET"})}async createCohortGoal(t,o){return this.request(`/public-api/v1/cohorts/${t}/goals`,{method:"POST",body:o})}async getCohortGoal(t,o){return this.request(`/public-api/v1/cohorts/${t}/goals/${o}`,{method:"GET"})}async updateCohortGoal(t,o,r){return this.request(`/public-api/v1/cohorts/${t}/goals/${o}`,{method:"PUT",body:r})}async archiveCohortGoal(t,o){return this.request(`/public-api/v1/cohorts/${t}/goals/${o}/archive`,{method:"POST"})}async deleteCohortGoal(t,o){return this.request(`/public-api/v1/cohorts/${t}/goals/${o}`,{method:"DELETE"})}async evaluateCohortGoal(t,o){return this.request(`/public-api/v1/cohorts/${t}/goals/${o}/evaluate`,{method:"POST"})}async evaluateAllCohortGoals(t){return this.request(`/public-api/v1/cohorts/${t}/goals/evaluate-all`,{method:"POST"})}async getOrgGoalsOverview(t={}){return this.requestPaginated(`/public-api/v1/cohorts/goals/overview${ue(t)}`,{method:"GET"})}async listMyEnrolledCohorts(t={}){return this.requestPaginated(`/public-api/v1/cohorts/enrolled${ue(t)}`,{method:"GET"})}async listMyCohortGoals(t={}){return this.requestPaginated(`/public-api/v1/cohorts/my/goals${ue(t)}`,{method:"GET"})}async inviteStudentsToCohort(t,o){return this.request(`/public-api/v1/cohorts/${t}/invite`,{method:"POST",body:o})}async assignStudentsToCohort(t,o){return this.request(`/public-api/v1/cohorts/${t}/invite/assign`,{method:"POST",body:o})}async getCohortInviteLink(t){return this.request(`/public-api/v1/cohorts/${t}/invite-link`,{method:"GET"})}async createCohortInviteLink(t){return this.request(`/public-api/v1/cohorts/${t}/invite-link`,{method:"POST"})}async setCohortInviteLinkRevoked(t,o){return this.request(`/public-api/v1/cohorts/${t}/invite-link`,{method:"PATCH",body:o})}async getOrgAnalytics(t={}){return this.requestWithMeta(`/public-api/v1/analytics${Bt(t)}`)}async listComplianceLearners(t={}){return this.requestPaginated(`/public-api/v1/analytics/compliance/learners${ue(t)}`,{method:"GET"})}async getLearnerAnalytics(t){return this.request(`/public-api/v1/analytics/learners/${t}`,{method:"GET"})}async getCourseAnalytics(t,o={}){return this.requestWithMeta(`/public-api/v1/courses/${t}/analytics${Bt(o)}`)}async listCourseAnalyticsStudents(t,o={}){return this.requestPaginated(`/public-api/v1/courses/${t}/analytics/students${ue(o)}`,{method:"GET"})}send(t,o){return fetch(new URL(t,this.config.CLASSROOMIO_API_URL),{method:o.method,headers:{Authorization:`Bearer ${this.config.CLASSROOMIO_API_KEY}`,"content-type":"application/json","user-agent":this.config.CLASSROOMIO_USER_AGENT},body:o.body?JSON.stringify(o.body):void 0})}async requestRaw(t,o){let r=await this.send(t,o),i=await r.json().catch(()=>null);if(!r.ok)throw Ht(r.status,i);if(!i||typeof i!="object"||!("success"in i)||!i.success)throw new Ie("ClassroomIO returned an invalid response payload",r.status);return i}async createAssetUpload(t){return this.request("/public-api/v1/assets",{method:"POST",body:t})}async createLesson(t,o){return this.request(`/public-api/v1/courses/${encodeURIComponent(t)}/lessons`,{method:"POST",body:o})}async updateLesson(t,o,r){return this.request(`/public-api/v1/courses/${encodeURIComponent(t)}/lessons/${encodeURIComponent(o)}`,{method:"PUT",body:r})}async putToPresignedUrl(t,o,r,i){let c=await fetch(t,{method:"PUT",headers:{"content-type":r,"content-length":String(i)},body:gs.toWeb(o),duplex:"half"});if(!c.ok)throw new Ie(`Upload to storage failed with status ${c.status}`,c.status)}async request(t,o){return(await this.requestRaw(t,o)).data}async requestPaginated(t,o){let r=await this.requestRaw(t,o);if(!r.pagination)throw new Ie("ClassroomIO returned a response without pagination metadata",502);return{data:r.data,pagination:r.pagination}}async requestWithMeta(t){let o=await this.requestRaw(t,{method:"GET"});return{data:o.data,meta:o.meta}}};function Ht(e,t){return new Ie(t?.error??t?.message??`ClassroomIO request failed with status ${e}`,e,t?.code,t?.field)}import{McpServer as gc}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as bc}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as Be}from"zod";var bs="0.1.0",hs=Be.object({CLASSROOMIO_API_URL:Be.url().default("https://api.classroomio.com"),CLASSROOMIO_API_KEY:Be.string().min(1),CLASSROOMIO_USER_AGENT:Be.string().min(1).default(`classroomio-mcp/${bs}`)});function qt(e=process.env){return hs.parse(e)}import*as G from"zod";var He=["overview","traffic","countries","funnel","courseTypes","topCourses","loginActivity","compliance"],ut=["summary","funnel"],_s=[7,30,90,365],fs=e=>typeof e=="string"?e.split(",").map(t=>t.trim()).filter(Boolean):e,Vt=(e,t)=>G.preprocess(fs,G.array(G.enum(e)).min(1)).default([t]).describe(`Comma-separated sections to return: ${e.join(", ")}. Default: ${t}.`),$t=G.coerce.number().pipe(G.literal(_s,{error:"days must be one of 7, 30, 90, 365"})).default(30).describe("Window in days, counted back from today (UTC): 7, 30, 90 or 365. Default: 30."),Kt=G.object({include:Vt(He,"overview"),days:$t,limit:G.coerce.number().int().min(1).max(20).default(5).describe("Max rows in list sections (overview lists, topCourses, countries). 1-20, default 5.")}),Qt=G.object({include:Vt(ut,"summary"),days:$t}),Yt=G.object({page:G.coerce.number().int().min(1).default(1),limit:G.coerce.number().int().min(1).max(50).default(20)}),Wt=G.object({profileId:G.string().uuid()});import*as u from"zod";var zs=u.string(),Re=u.string().nullable(),Jt=["compliant","expiring_soon","in_grace_period","non_compliant","waived","in_progress","not_started","no_record"],Xt=u.object(Object.fromEntries(Jt.map(e=>[e,u.number()]))),Es=u.object({totalCertificates:u.number(),numberOfCourses:u.number(),totalStudents:u.number(),topCourses:u.array(u.object({id:u.string().uuid(),title:u.string(),enrollments:u.number(),completion:u.number().describe("Percentage of enrolled students who completed the course"),certification:u.number().describe("Percentage of enrolled students who earned the certificate")})).describe("Up to 5 courses with the most students"),recentCertifications:u.array(u.object({id:u.string().uuid().describe("Profile id of the learner"),avatarUrl:u.string().nullable(),name:u.string(),courseId:u.string().uuid(),course:u.string(),date:zs})).describe("Up to 5 most recent certificates")}),Is=u.object({totals:u.object({landingViews:u.number(),coursePageViews:u.number(),uniqueVisitors:u.number(),enrollments:u.number(),completions:u.number()}),sparkline:u.array(u.object({date:u.string().describe("YYYY-MM-DD"),views:u.number(),enrollments:u.number()})).describe("One entry per rolled-up day, oldest first; days with no rollup row are omitted")}),Cs=u.object({country:u.string().describe("ISO 3166-1 alpha-2 code"),views:u.number(),enrollments:u.number()}),eo=u.object({steps:u.array(u.object({name:u.enum(["landing_view","course_page_view","enrollment_completed","course_completed"]),count:u.number(),conversionFromPrev:u.number().nullable().describe("Ratio (0-1) to the previous step; null for the first step")}))}),As=u.object({type:u.string(),enrollments:u.number(),views:u.number(),completions:u.number(),courseCount:u.number()}),ys=u.object({courseId:u.string().uuid(),title:u.string(),views:u.number()}),Ts=u.object({day:u.enum(["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]),count:u.number()}),Ss=u.object({summary:u.object({totalLearners:u.number(),totalCourses:u.number(),counts:Xt}),courses:u.array(u.object({courseId:u.string().uuid(),courseTitle:u.string(),learnerCount:u.number(),counts:Xt}))}),Ac=u.object({groupMemberId:u.string().uuid(),profileId:u.string().uuid().nullable(),fullname:u.string().nullable(),email:u.string().nullable(),avatarUrl:u.string().nullable(),courseId:u.string().uuid(),courseTitle:u.string(),status:u.enum(Jt),cycleNumber:u.number().nullable(),dueDate:Re,completedAt:Re,validUntil:Re}),xs=u.object({id:u.string().uuid(),title:u.string(),lessonId:u.string().uuid().nullable(),lessonTitle:u.string(),status:u.number().nullable().describe("Submission status id; null when not submitted"),score:u.number(),totalPoints:u.number(),isCompleted:u.boolean()}),yc=u.object({user:u.object({id:u.string().uuid(),fullName:u.string(),email:u.string(),avatarUrl:u.string(),lastSeen:Re}),overallCourseProgress:u.number().describe("Percentage of lessons and exercises completed across all courses"),overallAverageGrade:u.number().nullable().describe("Average of per-course grades; null when nothing is graded"),courses:u.array(u.object({id:u.string().uuid(),title:u.string(),type:u.string().nullable(),lessonsCount:u.number(),lessonsCompleted:u.number(),exercisesCount:u.number(),exercisesCompleted:u.number(),progressPercentage:u.number(),progressFailed:u.boolean().describe("True when progress could not be loaded; the course is left out of overall progress"),averageGrade:u.number().nullable(),certificateEarnedAt:Re,complianceStatus:u.string().nullable(),exercises:u.array(xs).nullable().describe("null when exercise stats could not be loaded")}))}),Os=u.object({totalTutors:u.number(),totalStudents:u.number(),totalLessons:u.number(),totalExercises:u.number(),averageProgress:u.number().describe("Average per-student progress (lessons and exercises), as a percentage"),averageExerciseCompletion:u.number().describe("Average share of exercises submitted per student, as a percentage"),averageGrade:u.number().describe("Average per-student grade, as a percentage")}),Tc=u.object({profileId:u.string().uuid(),fullname:u.string(),email:u.string(),avatarUrl:u.string(),lessonsCompleted:u.number(),totalLessons:u.number(),exercisesSubmitted:u.number(),totalExercises:u.number(),averageGrade:u.number(),progressPercentage:u.number(),lastSeen:Re}),to=u.string().nullable().describe("When the oldest returned section was computed (ISO 8601); null when no section was returned"),Sc=u.object({overview:Es.optional(),traffic:Is.optional(),countries:u.array(Cs).optional(),funnel:eo.optional(),courseTypes:u.array(As).optional(),topCourses:u.array(ys).optional(),loginActivity:u.array(Ts).optional(),compliance:Ss.optional()}).describe("Only the requested sections the caller may see are present"),xc=u.object({include:u.array(u.enum(He)),days:u.number(),limit:u.number(),omitted:u.array(u.object({section:u.enum(He),reason:u.enum(["requires_org_admin"])})).describe("Requested sections left out because the key creator may not see them"),generatedAt:to}),Oc=u.object({summary:Os.optional(),funnel:eo.optional()}).describe("Only the requested sections are present"),Rc=u.object({include:u.array(u.enum(ut)),days:u.number(),generatedAt:to});import*as oe from"zod";var z={RADIO:"RADIO",CHECKBOX:"CHECKBOX",TEXTAREA:"TEXTAREA",TRUE_FALSE:"TRUE_FALSE",SHORT_ANSWER:"SHORT_ANSWER",NUMERIC:"NUMERIC",FILL_BLANK:"FILL_BLANK",FILE_UPLOAD:"FILE_UPLOAD",MATCHING:"MATCHING",ORDERING:"ORDERING",HOTSPOT:"HOTSPOT",LINK:"LINK",WORD_BANK:"WORD_BANK",STAR:"STAR",VIDEO_RECORDING:"VIDEO_RECORDING",THUMBS:"THUMBS"},wc=[z.RADIO,z.CHECKBOX,z.TEXTAREA];var Te=[{key:z.RADIO,typename:"RADIO",label:"Single answer",id:1,autoGradable:!0,supportsPartialCredit:!1,manualGradingRequired:!1},{key:z.CHECKBOX,typename:"CHECKBOX",label:"Multiple answers",id:2,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:z.TEXTAREA,typename:"TEXTAREA",label:"Paragraph",id:3,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!0},{key:z.TRUE_FALSE,typename:"TRUE_FALSE",label:"True/False",id:4,autoGradable:!0,supportsPartialCredit:!1,manualGradingRequired:!1},{key:z.SHORT_ANSWER,typename:"SHORT_ANSWER",label:"Short answer",id:5,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!0},{key:z.NUMERIC,typename:"NUMERIC",label:"Numeric answer",id:6,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:z.FILL_BLANK,typename:"FILL_BLANK",label:"Fill in the blank",id:7,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:z.FILE_UPLOAD,typename:"FILE_UPLOAD",label:"File upload",id:8,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!0},{key:z.ORDERING,typename:"ORDERING",label:"Ordering",id:9,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:z.LINK,typename:"LINK",label:"Links",id:10,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!0},{key:z.WORD_BANK,typename:"WORD_BANK",label:"Word bank",id:11,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1},{key:z.STAR,typename:"STAR",label:"Star rating",id:12,autoGradable:!0,supportsPartialCredit:!1,manualGradingRequired:!1},{key:z.VIDEO_RECORDING,typename:"VIDEO_RECORDING",label:"Video recording",id:13,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!0},{key:z.THUMBS,typename:"THUMBS",label:"Thumbs up/down",id:14,autoGradable:!1,supportsPartialCredit:!1,manualGradingRequired:!1},{key:z.MATCHING,typename:"MATCHING",label:"Matching",id:15,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1,disabled:!0},{key:z.HOTSPOT,typename:"HOTSPOT",label:"Hotspot",id:16,autoGradable:!0,supportsPartialCredit:!0,manualGradingRequired:!1,disabled:!0}],ct=Te.filter(e=>!e.disabled),Rs=Object.freeze(Te.reduce((e,t)=>(e[t.key]=t,e),{})),lt=Object.freeze(Te.reduce((e,t)=>(e[t.key]=t.id,e),{})),Ps=Object.freeze(Te.reduce((e,t)=>(e[t.typename]=t.key,e),{})),oo=Object.freeze(Te.reduce((e,t)=>(e[t.id]=t.key,e),{}));var Uc=new Set([z.FILE_UPLOAD,z.ORDERING,z.LINK,z.STAR,z.VIDEO_RECORDING]);var Bc=Te.filter(e=>e.autoGradable).map(e=>e.id);function Le(e){let t=e?.maxStars,o=typeof t=="number"?t:t!=null?Number(t):NaN;return!Number.isFinite(o)||o<1?5:Math.min(10,Math.max(1,Math.floor(o)))}function Ue(e,t){return typeof e=="number"&&Number.isInteger(e)&&e>=1&&e<=t}var ws=new Set(["true","1","yes"]),Ns=new Set(["false","0","no"]);function ro(e){let t=e.trim().toLowerCase();if(ws.has(t))return!0;if(Ns.has(t))return!1}var Ds={type:"RADIO",toApiPayload(e,t){return{questionId:t,optionId:e.optionId}},fromApiPayload(e){let t=e.optionId;return t===void 0||Number.isNaN(t)?null:{type:"RADIO",optionId:t}}},vs={type:"CHECKBOX",toApiPayload(e,t){return{questionId:t,answer:JSON.stringify({type:"CHECKBOX",optionIds:e.optionIds})}},fromApiPayload(e){if(!e.answer)return null;let{optionIds:t}=JSON.parse(e.answer);return Array.isArray(t)?{type:"CHECKBOX",optionIds:t}:null}},Ls={type:"TRUE_FALSE",toApiPayload(e,t){return{questionId:t,answer:String(e.value)}},fromApiPayload(e){if(e.answer===void 0)return null;let t=ro(e.answer);return t===void 0?null:{type:"TRUE_FALSE",value:t}}},Us={type:"THUMBS",toApiPayload(e,t){return{questionId:t,answer:String(e.value)}},fromApiPayload(e){if(e.answer===void 0)return null;let t=ro(e.answer);return t===void 0?null:{type:"THUMBS",value:t}}},ks={type:"TEXTAREA",toApiPayload(e,t){return{questionId:t,answer:e.text}},fromApiPayload(e){return e.answer===void 0?null:{type:"TEXTAREA",text:e.answer}}},js={type:"SHORT_ANSWER",toApiPayload(e,t){return{questionId:t,answer:e.text}},fromApiPayload(e){return e.answer===void 0?null:{type:"SHORT_ANSWER",text:e.answer}}},Ms={type:"NUMERIC",toApiPayload(e,t){return{questionId:t,answer:JSON.stringify({type:"NUMERIC",value:e.value})}},fromApiPayload(e){if(!e.answer)return null;let{value:t}=JSON.parse(e.answer);return{type:"NUMERIC",value:t}}},Zs={type:"FILL_BLANK",toApiPayload(e,t){return{questionId:t,answer:JSON.stringify({type:"FILL_BLANK",answers:e.values})}},fromApiPayload(e){if(!e.answer)return null;let{answers:t}=JSON.parse(e.answer),o=t.map(r=>String(r).trim()).filter(Boolean);return o.length>0?{type:"FILL_BLANK",values:o}:null}},Gs={type:"WORD_BANK",toApiPayload(e,t){return{questionId:t,answer:JSON.stringify({type:"WORD_BANK",filledBlanks:e.filledBlanks})}},fromApiPayload(e){if(!e.answer)return null;try{let t=JSON.parse(e.answer);return t?.type!=="WORD_BANK"||!Array.isArray(t.filledBlanks)?null:{type:"WORD_BANK",filledBlanks:t.filledBlanks.map(o=>String(o??""))}}catch{return null}}},Fs={type:"FILE_UPLOAD",toApiPayload(e,t){let o={fileKey:e.fileKey,fileName:e.fileName,mimeType:e.mimeType,size:e.size};return{questionId:t,answer:JSON.stringify(o)}},fromApiPayload(e){if(!e.answer)return null;let t=JSON.parse(e.answer);return{type:"FILE_UPLOAD",fileKey:t.fileKey,fileName:t.fileName??"",mimeType:t.mimeType,size:t.size}}},Bs={type:"MATCHING",toApiPayload(e,t){return{questionId:t,answer:JSON.stringify({type:"MATCHING",value:e.pairs})}},fromApiPayload(e){if(!e.answer)return null;let{value:t}=JSON.parse(e.answer);return t.length>0?{type:"MATCHING",pairs:t}:null}},Hs={type:"ORDERING",toApiPayload(e,t){return{questionId:t,answer:JSON.stringify({type:"ORDERING",value:e.orderedValues})}},fromApiPayload(e){if(!e.answer)return null;let{value:t}=JSON.parse(e.answer);return t.length>0?{type:"ORDERING",orderedValues:t}:null}},qs={type:"LINK",toApiPayload(e,t){return{questionId:t,answer:JSON.stringify({type:"LINK",links:e.urls})}},fromApiPayload(e){if(!e.answer)return null;let{links:t}=JSON.parse(e.answer),o=t.map(r=>String(r).trim()).filter(Boolean);return o.length>0?{type:"LINK",urls:o}:null}},Vs={type:"HOTSPOT",toApiPayload(e,t){return{questionId:t,answer:JSON.stringify({type:"HOTSPOT",value:e.coordinates})}},fromApiPayload(e){if(!e.answer)return null;let{value:t}=JSON.parse(e.answer);return t.length>0?{type:"HOTSPOT",coordinates:t}:null}},$s={type:"STAR",toApiPayload(e,t){return{questionId:t,answer:JSON.stringify({type:"STAR",value:e.value})}},fromApiPayload(e,t){if(!e.answer)return null;try{let o=JSON.parse(e.answer);if(o?.type!=="STAR")return null;let r=Le(t.settings);return Ue(o.value,r)?{type:"STAR",value:o.value}:null}catch{return null}}};function Ks(e){if(!e||typeof e!="object")return!1;let t=e;return typeof t.assetId=="string"&&t.assetId.length>0&&typeof t.storageKey=="string"&&t.storageKey.length>0&&typeof t.fileName=="string"&&typeof t.mimeType=="string"&&t.mimeType.startsWith("video/")&&typeof t.size=="number"&&Number.isFinite(t.size)&&t.size>0&&typeof t.durationSeconds=="number"&&Number.isFinite(t.durationSeconds)&&t.durationSeconds>0&&typeof t.recordedAt=="string"&&typeof t.uploadedAt=="string"&&t.provider==="cloudflare"}var Qs={type:"VIDEO_RECORDING",toApiPayload(e,t){let{playbackUrl:o,...r}=e;return{questionId:t,answer:JSON.stringify(r)}},fromApiPayload(e){if(!e.answer)return null;try{let t=JSON.parse(e.answer);return t?.type!=="VIDEO_RECORDING"||!Ks(t)?null:{type:"VIDEO_RECORDING",assetId:t.assetId,storageKey:t.storageKey,fileName:t.fileName,mimeType:t.mimeType,size:t.size,durationSeconds:t.durationSeconds,recordedAt:t.recordedAt,uploadedAt:t.uploadedAt,provider:"cloudflare",retakeCount:typeof t.retakeCount=="number"?t.retakeCount:void 0}}catch{return null}}},ul={[z.RADIO]:Ds,[z.CHECKBOX]:vs,[z.TRUE_FALSE]:Ls,[z.THUMBS]:Us,[z.TEXTAREA]:ks,[z.SHORT_ANSWER]:js,[z.NUMERIC]:Ms,[z.FILL_BLANK]:Zs,[z.WORD_BANK]:Gs,[z.FILE_UPLOAD]:Fs,[z.MATCHING]:Bs,[z.ORDERING]:Hs,[z.LINK]:qs,[z.HOTSPOT]:Vs,[z.STAR]:$s,[z.VIDEO_RECORDING]:Qs};var bl=ct.map(e=>`${e.id}=${e.typename} (${e.label})`).join(", ");function no(){return`Supported questionTypeId values: ${ct.map(t=>`${t.id}=${t.typename} (${t.label})`).join(", ")}. TRUE_FALSE (4) is auto-graded with settings.correctValue (boolean) and True/False labels for factual statements. THUMBS (14) is open-ended (no correct answer, not auto-graded): two customizable Yes/No-style options with thumbs icons for sentiment or poll-style questions. MATCHING and HOTSPOT are disabled and must not be used.`}var so=[{value:"application/pdf",label:"PDF (.pdf)",aliases:["pdf",".pdf"]},{value:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",label:"DOCX (.docx)",aliases:["docx",".docx"]},{value:"application/msword",label:"DOC (.doc)",aliases:["doc",".doc"]},{value:"text/csv",label:"CSV (.csv)",aliases:["csv",".csv","application/csv","application/vnd.ms-excel"]},{value:"application/x-ipynb+json",label:"Jupyter Notebook (.ipynb)",aliases:["ipynb",".ipynb","application/json"]},{value:"image/jpeg",label:"JPEG (.jpg, .jpeg)",aliases:["jpg",".jpg","jpeg",".jpeg","image/jpg"]},{value:"image/png",label:"PNG (.png)",aliases:["png",".png"]},{value:"image/webp",label:"WEBP (.webp)",aliases:["webp",".webp"]},{value:"image/gif",label:"GIF (.gif)",aliases:["gif",".gif"]},{value:"video/mp4",label:"MP4 (.mp4)",aliases:["mp4",".mp4"]},{value:"video/quicktime",label:"MOV (.mov)",aliases:["mov",".mov"]},{value:"video/x-msvideo",label:"AVI (.avi)",aliases:["avi",".avi"]},{value:"video/x-matroska",label:"MKV (.mkv)",aliases:["mkv",".mkv"]}],Ys=[...so.flatMap(e=>[e.value,...e.aliases.filter(t=>t.includes("/"))])],Zl=new Map(so.map(e=>[e.value,e]));var qe=["video/mp4","video/quicktime","video/x-msvideo","video/x-matroska"];var w=lt;var Vl=oe.object({kind:oe.enum(["video"]).describe("Only video uploads are supported today."),fileName:oe.string().min(1).max(255).describe("Original file name, used as the asset title."),mimeType:oe.enum(qe).describe("Content type the upload will be sent with."),byteSize:oe.number().int().positive().describe("Size of the file in bytes. Checked against the organization upload limit.")}),$l=oe.object({assetId:oe.string().uuid().describe("Reference this when attaching the asset to a lesson."),uploadUrl:oe.string().describe("Send the file bytes here with a single PUT and no authorization header."),expiresAt:oe.string().describe("ISO timestamp after which uploadUrl stops working.")});import*as X from"zod";import*as h from"zod";var Ws=h.enum(["createdAt","name","email","lastLoginAt","lastActiveAt"]),Xs=h.enum(["asc","desc"]),Js=h.enum(["ACTIVE","DEACTIVATED","ARCHIVED"]),ei=h.enum(["active","pending","expired","revoked"]),ti=h.enum(["enrolled","not_enrolled"]),oi=h.enum(["not_started","in_progress","completed"]),io=h.enum(["7d","30d","90d","180d","never"]),dt=h.object({page:h.coerce.number().int().min(1).default(1),limit:h.coerce.number().int().min(1).max(100).default(20),search:h.string().trim().optional(),sortBy:Ws.default("createdAt"),sortOrder:Xs.default("desc"),status:Js.default("ACTIVE"),inviteStatus:ei.optional(),enrollment:ti.optional(),completion:oi.optional(),lastLoginBefore:io.optional(),lastActiveBefore:io.optional(),excludeRecentJoiners:h.union([h.boolean(),h.enum(["true","false"])]).default(!0).transform(e=>e===!0||e==="true")});var pt=500;var ri=h.enum(["deactivate","reactivate","archive","unarchive","delete"]),ni=h.discriminatedUnion("mode",[h.object({mode:h.literal("ids"),memberIds:h.array(h.number().int().positive()).min(1).max(pt)}),h.object({mode:h.literal("filter"),filter:dt.omit({page:!0,limit:!0,sortBy:!0,sortOrder:!0}),expectedCount:h.number().int().positive(),expectedTargetHash:h.string().length(64)})]),Ql=h.object({target:ni,action:ri,reason:h.string().trim().max(500).optional()}),Yl=dt.omit({page:!0,limit:!0}).extend({memberIds:h.union([h.string(),h.array(h.string())]).optional().transform(e=>{if(e==null)return;let o=(Array.isArray(e)?e:[e]).flatMap(r=>r.split(",")).map(r=>Number(r.trim())).filter(r=>Number.isInteger(r)&&r>0);return o.length>0?[...new Set(o)]:void 0}).refine(e=>e==null||e.length<=pt,{message:`Select at most ${pt} learners, or export the filtered view instead`})}),Wl=h.object({undoToken:h.string().min(1).max(200)}),si=h.object({profileIds:h.array(h.uuid()).min(1).max(500),courseIds:h.array(h.uuid()).optional(),cohortIds:h.array(h.uuid()).optional(),sendEmail:h.boolean().default(!0)}).refine(e=>(e.courseIds?.length??0)>0||(e.cohortIds?.length??0)>0,{message:"At least one course or cohort must be selected",path:["courseIds"]}),Xl=h.object({email:h.email()});import*as k from"zod";var ii=1e3,ep=5*1024*1024;var tp=k.enum(["ready","already_member","invalid_email","duplicate_in_file","is_staff","over_seat_limit","missing_email"]),ai=k.object({email:k.string().trim().toLowerCase(),name:k.string().trim().max(200).optional(),courses:k.array(k.string().trim()).optional()}),op=k.object({recipients:k.array(ai).max(ii).optional(),recipientCsv:k.string().max(25e3).optional(),courseIds:k.array(k.string().uuid()).optional(),cohortIds:k.array(k.string().uuid()).optional(),allCourses:k.boolean().optional().default(!1),allCohorts:k.boolean().optional().default(!1),sendEmail:k.boolean().default(!0)}).refine(e=>!!e.recipients?.length||!!e.recipientCsv?.trim(),{message:"Provide at least one recipient",path:["recipients"]});import*as l from"zod";var ao=["en","hi","fr","pt","de","vi","ru","es","pl","da","tr","it"],uo=["studentCourseInvite","studentCourseWelcome","studentCourseCompletion","studentOrgInvite","studentCohortWelcome","studentProvePayment","cohortGoalReminder","quizAssigned","sessionReminder","sessionUpdated","submissionGraded","newsfeedPost"];var ee={ADMIN:1,TUTOR:2,STUDENT:3};var co=["academy","app","apps","blog","build","campaign","church","cloud","community","conference","course","courses","demo","dev","embed","embeds","forum","group","groups","help","launch","launchweek","mobile","play","prod","production","schools","stage","staging","support","teacher","teachers","tech","training"];var lo;(function(e){e.Section="SECTION",e.Lesson="LESSON",e.Exercise="EXERCISE"})(lo||(lo={}));var Ve=["SELF_PACED","LIVE_CLASS","COMPLIANCE","PUBLIC"];var po="embed.classroomio.com",ui=`https://${po}`;var ci=["auto","manual","publish"],fp=[...ci,"none"],zp=600*1e3,Ep=3600*1e3;var mo=15,go=10080,bo=5,ho=["pending","queued","sent","failed","skipped"];import*as _o from"zod";var Ce=_o.enum(Ve);import*as mt from"zod";var fo=/^[a-z0-9]+(?:-[a-z0-9]+)*$/,Ae=mt.string().min(1,{message:"Slug is required"}).max(80,{message:"Slug must be 80 characters or fewer"}).regex(fo,{message:"Slug must be lowercase letters, numbers, and single dashes"}),gt=mt.string().min(1,{message:"Slug is required"}).regex(fo,{message:"Slug must be lowercase letters, numbers, and single dashes"});var li=/^(https?|mailto|tel):/i,pi=/^(javascript|data|vbscript)$/i;function di(e){return!!(li.test(e)||e.startsWith("#")||e.startsWith("/")||e.startsWith("./")||e.startsWith("../")||e.startsWith("?"))}function zo(e){if(typeof e!="string")return!1;let t=e.trim();return t.length===0?!1:di(t)}function mi(e){let t=e.indexOf(":");if(t<0)return!1;let o=e.slice(0,t).replace(/[\s\x00-\x1f]+/g,"");return pi.test(o)}function $e(e){if(typeof e=="string"){let t=e.trim();return!!(t.length>0&&mi(t))}return Array.isArray(e)?e.some($e):e!==null&&typeof e=="object"?Object.values(e).some($e):!1}var $p=l.object({siteName:l.string().min(1).optional(),customDomain:l.string().min(1).optional(),isCustomDomainVerified:l.union([l.boolean(),l.literal("true").transform(()=>!0),l.literal("false").transform(()=>!1)]).optional()}),Kp=l.object({siteName:l.string().min(1),tags:l.string().optional(),types:l.string().optional(),search:l.string().trim().optional(),pricing:l.enum(["free","paid"]).optional(),page:l.coerce.number().int().min(1).optional(),limit:l.coerce.number().int().min(1).max(100).optional()}),Ke=l.object({page:l.coerce.number().int().min(1).default(1),limit:l.coerce.number().int().min(1).max(100).default(20),search:l.string().trim().optional(),tags:l.string().optional(),type:Ce.optional(),status:l.enum(["published","unpublished"]).optional(),sort:l.enum(["date_created","last_updated_at","published","lessons"]).optional(),order:l.enum(["asc","desc"]).optional()}),Qp=l.object({courses:l.array(l.object({id:l.string().uuid(),order:l.number().int().min(0)})).min(1).max(4).superRefine((e,t)=>{new Set(e.map(c=>c.id)).size!==e.length&&t.addIssue({code:"custom",path:["courses"],message:"Course ids must be unique"});let r=Array.from({length:e.length},(c,b)=>b);e.map(c=>c.order).sort((c,b)=>c-b).some((c,b)=>c!==r[b])&&t.addIssue({code:"custom",path:["courses"],message:"Orders must form a contiguous sequence starting at 0"})})}),Yp=l.object({siteName:l.string().min(1)}),Wp=l.object({orgId:l.uuid(),planName:l.enum(["EARLY_ADOPTER","ENTERPRISE","BASIC"]),subscriptionId:l.string().min(1),triggeredBy:l.number().int().positive(),payload:l.record(l.string(),l.unknown())}),Xp=l.object({subscriptionId:l.string().min(1),payload:l.record(l.string(),l.unknown())}),Jp=l.object({subscriptionId:l.string().min(1),payload:l.record(l.string(),l.unknown())}),ed=l.object({event:l.enum(["activated","updated","revoked"]),subscriptionId:l.string().min(1),customerId:l.string().min(1).nullish(),customerEmail:l.email(),checkoutId:l.string().min(1).nullish(),payload:l.record(l.string(),l.unknown())}),td=l.object({token:l.string().trim().min(20).max(200)}),od=l.object({name:l.string().min(5).refine(e=>!/^[-]|[-]$/.test(e),{message:"Organization name cannot start or end with a hyphen"}),siteName:l.string().min(5).refine(e=>!/^[-]|[-]$/.test(e),{message:"Site name cannot start or end with a hyphen"}).refine(e=>!co.includes(e),{message:"Sitename already exists."})}),rd=l.object({name:l.string().min(5).refine(e=>!/^[-]|[-]$/.test(e),{message:"Organization name cannot start or end with a hyphen"}).optional(),avatarUrl:l.url().optional(),favicon:l.union([l.url(),l.null()]).optional(),theme:l.string().optional(),landingpage:l.record(l.string(),l.unknown()).optional().refine(e=>!e||!$e(e),{message:"URLs with javascript:, data:, or vbscript: schemes are not allowed"}),siteName:l.string().min(1).optional(),customDomain:l.string().nullable().optional(),isCustomDomainVerified:l.boolean().optional(),customization:l.record(l.string(),l.unknown()).optional(),disableSignup:l.boolean().optional(),disableSignupMessage:l.string().optional(),disableEmailPassword:l.boolean().optional(),disableGoogleAuth:l.boolean().optional(),settings:l.object({signup:l.object({inviteOnly:l.boolean().optional()}).optional(),internalEnrollmentOnly:l.boolean().optional(),language:l.object({locale:l.enum(["en","hi","fr","pt","de","vi","ru","es","pl","da","tr","it"]).optional(),enforced:l.boolean().optional()}).optional(),emailNotifications:l.object({newStudent:l.boolean().optional(),newSubmission:l.boolean().optional(),gradingResult:l.boolean().optional(),newsfeed:l.boolean().optional(),quizAssigned:l.boolean().optional(),cohortReminder:l.boolean().optional(),session:l.boolean().optional(),enrollmentWelcome:l.boolean().optional(),courseCompletion:l.boolean().optional()}).optional()}).optional()}),nd=l.object({emailId:l.enum(uo),locale:l.enum(ao)}),sd=l.object({content:l.string().min(1).max(5e4),subject:l.string().min(1).max(200).nullable().optional()}),gi=l.array(l.string().trim().email()).min(1).max(5),id=l.object({content:l.string().min(1).max(5e4),subject:l.string().min(1).max(200),recipientEmails:gi}),ad=l.object({emails:l.array(l.string().email()).min(1).max(50),roleId:l.number().int().positive()}),ud=l.object({memberId:l.coerce.number().int().positive()}),cd=l.object({roleId:l.union([l.literal(ee.ADMIN),l.literal(ee.TUTOR)])}),ld=l.object({roleId:l.number().int().positive()}),pd=l.object({isRevoked:l.boolean()}),dd=l.object({userId:l.uuid()});import*as Pe from"zod";var bi=Pe.enum(["connect","refresh","remove"]),gd=Pe.object({action:bi,domain:Pe.string().min(1)});import*as L from"zod";var hd=L.object({orgId:L.uuid(),quizId:L.uuid()}),_d=L.object({orgId:L.uuid()}),fd=L.object({title:L.string().min(1),questions:L.array(L.any()).optional(),timelimit:L.string().optional(),theme:L.string().optional()}),zd=L.object({title:L.string().min(1).optional(),questions:L.array(L.any()).optional(),timelimit:L.string().optional(),theme:L.string().optional()});import*as Qe from"zod";var Id=Qe.object({orgId:Qe.uuid()});import*as Ye from"zod";var Ad=Ye.object({token:Ye.string().min(10).max(512)});import*as A from"zod";var hi=["OKTA","GOOGLE_WORKSPACE","AUTH0"],Td=A.object({provider:A.enum(hi),displayName:A.string().min(1,"Display name is required"),issuer:A.url("Must be a valid URL"),domain:A.string().min(1,"Domain is required").regex(/^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/,"Invalid domain format"),clientId:A.string().min(1,"Client ID is required"),clientSecret:A.string().min(1,"Client secret is required"),scopes:A.string().default("openid profile email")}),Sd=A.object({displayName:A.string().min(1).optional(),issuer:A.url().optional(),domain:A.string().optional(),clientId:A.string().optional(),clientSecret:A.string().optional(),scopes:A.string().optional(),isActive:A.boolean().optional()}),xd=A.object({forceSso:A.boolean().optional(),autoJoinSsoDomains:A.boolean().optional(),breakGlassEnabled:A.boolean().optional(),defaultRoleId:A.number().int().positive().optional(),roleMapping:A.record(A.string(),A.number()).optional()}),Od=A.object({email:A.email("Valid email is required")}),Rd=A.object({orgId:A.uuid()});import{z as Se}from"zod";var Nd=Se.object({token:Se.string().min(1),redirect:Se.string().optional()}),Dd=Se.object({sub:Se.uuid(),email:Se.email(),type:Se.literal("login-link")});import{z as ce}from"zod";var Ud=ce.object({token:ce.string().min(1),redirect:ce.string().optional()}),kd=ce.object({sub:ce.string(),email:ce.email(),name:ce.string().optional(),avatar:ce.url().optional(),iat:ce.number(),exp:ce.number()});import{z as le}from"zod";var bt=le.enum(["mcp","api","zapier"]),_i=le.enum(["course_import:draft:create","course_import:draft:read","course_import:draft:update","course_import:draft:publish","course:read","course:write","course:tag:write","course:exercise:read","course:exercise:write","cohort:read","cohort:write","course:member:read","course:member:write","course:certificate:read","course:certificate:write","analytics:read","media:write","public_api:*"]),Zd=le.object({type:bt.optional()}),Gd=le.object({type:bt.default("mcp")}),Fd=le.object({type:bt,label:le.string().min(1).max(120).optional(),expiresAt:le.string().datetime().optional(),scopes:le.array(_i).min(1).optional()}).refine(e=>e.type!=="mcp"||!e.scopes?.includes("public_api:*"),{message:"MCP keys cannot have the public_api:* scope",path:["scopes"]}),Bd=le.object({keyId:le.string().uuid()});import*as we from"zod";var qd=we.object({q:we.string().trim().min(1).max(200),limit:we.coerce.number().int().min(1).max(20).default(5)});var am=X.object({email:X.string().email(),courseIds:X.array(X.string().uuid()).optional(),sendEmail:X.boolean().default(!0)}),um=X.object({email:X.string().email(),sendEmail:X.boolean().default(!0)});var cm=X.object({memberId:X.coerce.number().int().positive()});import*as _ from"zod";var fi=_.string(),We=_.string().nullable(),Eo=_.enum(["ACTIVE","DEACTIVATED","ARCHIVED"]),pm=_.object({id:_.number(),profileId:_.string().uuid().nullable().describe("null until the invited person creates an account"),name:_.string(),email:_.string(),avatarUrl:_.string(),createdAt:_.string().describe('Day the member joined this organization, as a date string (e.g. "Mon Oct 05 2026")'),status:_.enum(["active","pending","expired","revoked"]).describe("Invite state"),memberStatus:Eo.describe("Lifecycle state of the membership"),lastLoginAt:We,lastActiveAt:We,enrolledCount:_.number(),completedCount:_.number(),progressPercent:_.number()}),dm=_.object({imported:_.number(),enrolled:_.number(),emailsSent:_.number(),emailsFailed:_.number(),rows:_.array(_.object({email:_.string(),name:_.string().optional(),status:_.enum(["ready","already_member","invalid_email","duplicate_in_file","is_staff","over_seat_limit","missing_email"])})),assigned:_.number(),alreadyEnrolledInCourses:_.number(),alreadyEnrolledInCohorts:_.number(),pendingInvitesRenewed:_.number(),truncated:_.number().describe("Rows beyond the import limit, which were not processed")}),mm=_.object({assigned:_.number(),alreadyEnrolled:_.number(),emailsSent:_.number()}),gm=_.object({id:_.number(),organizationId:_.string().uuid(),roleId:_.number().describe("1 = admin, 2 = tutor, 3 = student"),profileId:_.string().uuid().nullable(),email:_.string().nullable(),verified:_.boolean().nullable(),status:Eo,statusChangedAt:We,statusChangedBy:_.string().uuid().nullable(),lastActiveAt:We,createdAt:fi});import*as te from"zod";var P=te.object({cohortId:te.string().uuid()}),Io=te.object({name:te.string().min(1).max(255),description:te.string().max(2e3).optional(),coverImage:te.string().url().optional()}),ht=te.object({name:te.string().min(1).max(255).optional(),description:te.string().max(2e3).nullable().optional(),coverImage:te.string().url().nullable().optional(),status:te.enum(["ACTIVE","INACTIVE","ARCHIVED"]).optional()}).refine(e=>Object.keys(e).length>0,{message:"No fields to update"});import*as ke from"zod";var Co=P.extend({courseId:ke.string().uuid()}),Ao=ke.object({courseId:ke.string().uuid()});import*as y from"zod";var yo=["complete_all","n_of_m","score","pass_rate","readiness"],To=["absolute","relative_to_join","recurring","none"],xe=P.extend({goalId:y.string().uuid()}),So=y.object({type:y.enum(yo),title:y.string().min(1).max(255),description:y.string().max(2e3).nullable().optional(),courseIds:y.array(y.string().uuid()).max(50),requiredCount:y.number().int().min(1).max(50).nullable().optional(),scoreThreshold:y.number().int().min(0).max(100).nullable().optional(),teamPassRateThreshold:y.number().int().min(0).max(100).nullable().optional(),reminderDaysBefore:y.array(y.number().int().min(0).max(365)).max(5).default([7,1]),deadlineKind:y.enum(To).default("none"),deadlineDate:y.string().datetime().nullable().optional(),relativeDays:y.number().int().min(1).max(3650).nullable().optional(),recurringMonths:y.number().int().min(1).max(120).nullable().optional()}).refine(e=>e.courseIds.length>0,{message:"At least one course is required",path:["courseIds"]}).refine(e=>e.type!=="n_of_m"||e.requiredCount&&e.requiredCount>0,{message:"requiredCount is required for n_of_m goals",path:["requiredCount"]}).refine(e=>e.type!=="n_of_m"||!e.requiredCount||e.requiredCount<=e.courseIds.length,{message:"requiredCount cannot exceed selected courses",path:["requiredCount"]}).refine(e=>e.type!=="score"||e.scoreThreshold!==null&&e.scoreThreshold!==void 0,{message:"scoreThreshold is required for score goals",path:["scoreThreshold"]}).refine(e=>e.type!=="pass_rate"||e.scoreThreshold!==null&&e.scoreThreshold!==void 0&&e.teamPassRateThreshold!==null&&e.teamPassRateThreshold!==void 0,{message:"scoreThreshold and teamPassRateThreshold are required for pass_rate goals",path:["teamPassRateThreshold"]}).refine(e=>e.deadlineKind!=="absolute"||!!e.deadlineDate,{message:"deadlineDate is required for absolute deadlines",path:["deadlineDate"]}).refine(e=>e.deadlineKind!=="relative_to_join"||!!e.relativeDays,{message:"relativeDays is required for relative-to-join deadlines",path:["relativeDays"]}).refine(e=>e.deadlineKind!=="recurring"||!!e.recurringMonths,{message:"recurringMonths is required for recurring deadlines",path:["recurringMonths"]}).refine(e=>e.type!=="readiness"||e.deadlineKind==="none",{message:"Readiness goals do not support deadlines",path:["deadlineKind"]}),_t=y.object({type:y.enum(yo).optional(),title:y.string().min(1).max(255).optional(),description:y.string().max(2e3).nullable().optional(),courseIds:y.array(y.string().uuid()).max(50).optional(),requiredCount:y.number().int().min(1).max(50).nullable().optional(),scoreThreshold:y.number().int().min(0).max(100).nullable().optional(),teamPassRateThreshold:y.number().int().min(0).max(100).nullable().optional(),reminderDaysBefore:y.array(y.number().int().min(0).max(365)).max(5).optional(),deadlineKind:y.enum(To).optional(),deadlineDate:y.string().datetime().nullable().optional(),relativeDays:y.number().int().min(1).max(3650).nullable().optional(),recurringMonths:y.number().int().min(1).max(120).nullable().optional(),status:y.enum(["active","archived"]).optional()}).refine(e=>Object.keys(e).length>0,{message:"No fields to update"});import*as re from"zod";var xo=re.object({recipientCsv:re.string().min(1).max(25e3),sendEmail:re.boolean().default(!0)}),Oo=re.object({profileIds:re.array(re.string().uuid()).min(1).max(500),sendEmail:re.boolean().default(!0)}),Ro=re.object({isRevoked:re.boolean()});import*as W from"zod";var Po=W.union([W.literal(ee.TUTOR),W.literal(ee.STUDENT)]),Xe=P.extend({memberId:W.string().uuid()}),wo=W.object({members:W.array(W.object({profileId:W.string().uuid().optional(),email:W.string().email().optional(),name:W.string().optional(),roleId:Po})).min(1).refine(e=>e.every(t=>t.profileId||t.email),{message:"Each member must include a profileId or email"}).refine(e=>{let t=e.map(o=>o.profileId??o.email?.toLowerCase().trim());return new Set(t).size===t.length},{message:"Each profileId or email may appear only once per request"})}),No=W.object({roleId:Po});import*as F from"zod";var zi=["clap","smile","thumbsup","thumbsdown"],Ei=/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(\.\d{1,6})?(Z|[+-]\d{2}(:?\d{2})?)(\|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})?$/i,pe=P.extend({feedId:F.string().uuid()}),Do=pe.extend({commentId:F.coerce.number().int()}),vo=F.object({cursor:F.string().refine(e=>Ei.test(e)&&!Number.isNaN(Date.parse(e.split("|")[0])),{message:"Invalid cursor"}).optional(),limit:F.coerce.number().int().min(1).max(50).default(10)}),Lo=F.object({content:F.string().min(1),isPinned:F.boolean().optional()}),ft=F.object({content:F.string().min(1).optional(),isPinned:F.boolean().optional()}).refine(e=>Object.keys(e).length>0,{message:"No fields to update"}),Uo=F.object({reaction:F.enum(zi).nullable()}),ko=F.object({content:F.string().min(1)});import*as a from"zod";var _e=a.string(),Ne=a.string().nullable(),jo=["complete_all","n_of_m","score","pass_rate","readiness"],Mo=["absolute","relative_to_join","recurring","none"],Zo=["not_started","in_progress","completed","at_risk","overdue","waived"],Ii=a.object({id:a.string().uuid(),createdAt:_e,updatedAt:Ne,organizationId:a.string().uuid(),name:a.string(),description:a.string().nullable(),coverImage:a.string().nullable(),status:a.enum(["ACTIVE","INACTIVE","ARCHIVED"]),createdByProfileId:a.string().uuid().nullable()}),Ci=Ii.extend({courseCount:a.number(),studentCount:a.number()}),xm=Ci.extend({roleId:a.number()}),Go=a.object({id:a.string().uuid(),cohortId:a.string().uuid(),profileId:a.string().uuid().nullable(),roleId:a.number(),email:a.string().nullable(),createdAt:_e}),Om=Go.extend({profile:a.object({id:a.string().uuid(),fullname:a.string().nullable(),username:a.string().nullable(),avatarUrl:a.string().nullable(),email:a.string().nullable()}).nullable()}),Rm=a.object({added:a.array(Go),errors:a.array(a.object({index:a.number().describe("Position of the failed entry in the request members array"),email:a.string().nullable(),profileId:a.string().nullable(),code:a.string(),message:a.string()}))}),Ai=a.object({id:a.string().uuid(),cohortId:a.string().uuid(),courseId:a.string().uuid(),addedAt:_e}),Pm=Ai.extend({course:a.object({id:a.string().uuid(),title:a.string().nullable(),description:a.string().nullable(),coverImage:a.string().nullable(),slug:a.string().nullable(),status:a.string().nullable(),isPublished:a.boolean().nullable()})}),yi=a.object({clap:a.array(a.string()),smile:a.array(a.string()),thumbsup:a.array(a.string()),thumbsdown:a.array(a.string())}),Ti=a.object({id:a.string().uuid(),createdAt:_e,authorId:a.string().uuid().nullable().describe("Cohort member id of the author"),cohortId:a.string().uuid().nullable(),content:a.string().nullable(),reaction:yi.nullable().describe("Cohort member ids per reaction type"),isPinned:a.boolean()}),Fo={authorProfileId:a.string().nullable(),authorFullname:a.string().nullable(),authorUsername:a.string().nullable(),authorAvatarUrl:a.string().nullable()},Si=Ti.extend({...Fo,commentCount:a.number()}),wm=a.object({items:a.array(Si),totalCount:a.number(),hasMore:a.boolean(),nextCursor:a.string().nullable()}),xi=a.object({id:a.number(),createdAt:_e,authorId:a.string().uuid().nullable().describe("Cohort member id of the author"),content:a.string().nullable(),cohortNewsfeedId:a.string().uuid().nullable()}),Nm=xi.extend(Fo),Bo=a.object({id:a.string().uuid(),cohortId:a.string().uuid(),title:a.string(),description:a.string().nullable(),type:a.enum(jo),courseIds:a.array(a.string()),requiredCount:a.number().nullable(),scoreThreshold:a.number().nullable(),teamPassRateThreshold:a.number().nullable(),deadlineKind:a.enum(Mo),deadlineDate:Ne,relativeDays:a.number().nullable(),recurringMonths:a.number().nullable(),reminderDaysBefore:a.array(a.number()),status:a.enum(["active","archived"]),createdByProfileId:a.string().uuid().nullable(),createdAt:_e,updatedAt:_e}),Dm=Bo.extend({statusCounts:a.partialRecord(a.enum(Zo),a.number()).describe("Learner count per assignment status; statuses with no learners are omitted")}),vm=a.object({evaluated:a.number()}),Lm=a.object({goalId:a.string().uuid(),cohortId:a.string().uuid(),cohortName:a.string(),title:a.string(),type:a.enum(jo),deadlineKind:a.enum(Mo),totalLearners:a.number(),completedCount:a.number(),inProgressCount:a.number(),atRiskCount:a.number(),overdueCount:a.number(),notStartedCount:a.number(),waivedCount:a.number(),onTrackPct:a.number()}),Um=a.object({id:a.string().uuid(),goalId:a.string().uuid(),cohortMemberId:a.string().uuid(),dueDate:Ne,status:a.enum(Zo),completedCount:a.number(),requiredCount:a.number(),completedAt:Ne,lastEvaluatedAt:Ne,createdAt:_e,updatedAt:_e,goal:Bo,cohortId:a.string().uuid(),cohortName:a.string()}),km=a.object({imported:a.number(),enrolled:a.number(),emailsSent:a.number().describe("Emails queued for delivery, not confirmed delivered"),emailsFailed:a.number(),rows:a.array(a.object({email:a.string(),name:a.string().optional(),status:a.enum(["ready","already_member","invalid_email","duplicate_in_file","is_staff","over_seat_limit","missing_email"])})),assigned:a.number().optional(),alreadyEnrolledInCourses:a.number().optional(),alreadyEnrolledInCohorts:a.number().optional(),pendingInvitesRenewed:a.number().optional(),truncated:a.number().optional()}),jm=a.object({assigned:a.number(),alreadyEnrolled:a.number(),emailsSent:a.number()}),Mm=a.object({id:a.string().uuid(),token:a.string(),inviteLink:a.string().describe("Full join URL to share with students"),isRevoked:a.boolean(),joinCount:a.number(),lastUsedAt:Ne});import*as K from"zod";import*as n from"zod";function Ho(e){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e=="string"&&e.trim()){let t=Number(e);if(Number.isFinite(t))return t}}import*as fe from"zod";var Oi=fe.enum(["waves","dotted","none"]),Ri=fe.object({title:fe.string().min(1).max(120),description:fe.string().min(1).max(500),buttonLabel:fe.string().min(1).max(40),buttonUrl:fe.string().url(),animation:Oi.default("waves")}),qo=Ri.nullable();import*as ne from"zod";var Vo=ne.array(ne.number().int().min(mo).max(go)).max(bo).refine(e=>new Set(e).size===e.length,{message:"Reminder offsets must be unique"}),Hm=ne.object({page:ne.coerce.number().int().min(1).default(1),limit:ne.coerce.number().int().min(1).max(100).default(50),status:ne.enum(ho).optional(),lessonId:ne.uuid().optional()});var Wm=n.object({limit:n.string().transform(Number).pipe(n.number().min(1).max(50)).optional(),page:n.string().transform(Number).pipe(n.number().min(1)).optional()}),Xm=n.object({title:n.string().min(1),description:n.string().optional(),slug:n.string().min(1),organizationId:n.string().min(1)}),Jm=n.object({courseId:n.string().min(1)}),eg=n.object({courseId:n.string().min(1)}),tg=n.object({slug:n.string().optional()}),og=n.object({slug:n.string().min(1)}),rg=n.object({courseId:n.string().min(1)}),ng=n.object({inviteToken:n.string().min(1).optional()}),sg=n.object({courseId:n.string().min(1)}),$o=n.object({name:n.string().max(80).default(""),role:n.string().max(80).default(""),enabled:n.boolean().default(!0),signatureUrl:n.url().optional()}),Pi=n.enum(["classique","brutalist","noir","poster","minimal"]),wi=n.object({templateId:Pi,accentColor:n.string().regex(/^#[0-9a-fA-F]{6}$/,{message:"Accent must be a 6-digit hex color"}),subtitle:n.string().max(120).optional(),descriptionOverride:n.string().max(500).optional(),signatories:n.tuple([$o,$o]).optional(),idFormat:n.string().max(40).optional()}),ig=n.object({studentName:n.string().min(1).max(120),studentId:n.string().min(1).max(64).optional(),issuedAt:n.preprocess(e=>{if(typeof e!="string"||e.trim()==="")return;let t=new Date(e);if(!Number.isNaN(t.getTime()))return t.toISOString()},n.string().datetime().optional()),previewMode:n.boolean().optional()}),ag=n.object({courseTitle:n.string().min(1),orgName:n.string().min(1),orgTheme:n.string().min(1),lessons:n.array(n.object({lessonTitle:n.string().min(1),lessonNumber:n.string().min(1),lessonNote:n.string(),slideUrl:n.string().url().optional(),video:n.array(n.string().url()).optional()}))}),ug=n.object({title:n.string().min(1),number:n.string().min(1),orgName:n.string().min(1),note:n.string(),slideUrl:n.string().url().optional(),video:n.array(n.string().url()).optional(),courseTitle:n.string().min(1)}),cg=n.object({fileName:n.string().min(1),fileType:n.enum(qe),fileSize:n.number().int().min(0).optional()}),lg=n.object({fileName:n.string().min(1),fileType:n.string(),fileSize:n.number().int().min(0).optional(),acceptedTypes:n.array(n.string()).optional()}),pg=n.object({keys:n.array(n.string().min(1)).min(1)}),Ko=n.object({id:n.string().min(1),type:n.enum(["LESSON","EXERCISE"]),isUnlocked:n.boolean().optional(),order:n.number().int().min(1).optional(),sectionId:n.string().nullable().optional()}),dg=n.object({items:n.array(Ko).min(1)}),Ni=n.object({id:n.string().min(1),order:n.number().int().min(1)}),Di=Ko.omit({isUnlocked:!0}),zt=n.object({sections:n.array(Ni).min(1).optional(),items:n.array(Di).min(1).optional()}),Qo=zt.superRefine((e,t)=>{!e.sections?.length&&!e.items?.length&&t.addIssue({code:n.ZodIssueCode.custom,path:["sections"],message:"Provide sections or items to reorder"});let o=new Set;e.sections?.forEach((b,q)=>{o.has(b.id)&&t.addIssue({code:n.ZodIssueCode.custom,path:["sections",q,"id"],message:"Section IDs must be unique"}),o.add(b.id)});let r=e.sections?.map(b=>b.order).sort((b,q)=>b-q);r&&r.some((b,q)=>b!==q+1)&&t.addIssue({code:n.ZodIssueCode.custom,path:["sections"],message:"Section orders must be a contiguous 1-based sequence (1, 2, 3, ...)"});let i=new Set,c=new Map;e.items?.forEach((b,q)=>{b.order===void 0&&b.sectionId===void 0&&t.addIssue({code:n.ZodIssueCode.custom,path:["items",q],message:"Each item must provide order or sectionId"});let C=b.sectionId??"__unsectioned__",x=c.get(C)??{orders:[],total:0,withOrder:0};x.total+=1,b.order!==void 0&&(x.orders.push(b.order),x.withOrder+=1),c.set(C,x);let Z=`${b.type}:${b.id}`;i.has(Z)&&t.addIssue({code:n.ZodIssueCode.custom,path:["items",q,"id"],message:"Item IDs must be unique per content type"}),i.add(Z)});for(let[,b]of c)b.withOrder>0&&b.withOrder===b.total&&[...b.orders].sort((C,x)=>C-x).some((C,x)=>C!==x+1)&&t.addIssue({code:n.ZodIssueCode.custom,path:["items"],message:"Item orders within each section must be a contiguous 1-based sequence (1, 2, 3, ...)"})}),vi=n.object({id:n.string().min(1),type:n.enum(["LESSON","EXERCISE"])}),mg=n.object({sectionId:n.string().min(1).optional(),items:n.array(vi).min(1).optional()}).superRefine((e,t)=>{!!e.sectionId==!!e.items&&t.addIssue({code:n.ZodIssueCode.custom,path:["sectionId"],message:"Provide either sectionId or items"});let o=new Set;e.items?.forEach((r,i)=>{let c=`${r.type}:${r.id}`;o.has(c)&&t.addIssue({code:n.ZodIssueCode.custom,path:["items",i,"id"],message:"Item IDs must be unique per content type"}),o.add(c)})}),je=n.object({retakeIntervalMonths:n.number().int().min(1).max(120),gracePeriodDays:n.number().int().min(0).max(365).optional().default(0),reminderDaysBefore:n.array(n.number().int().min(1).max(365)).max(10).optional().default([30,7,1]),isMandatory:n.boolean().optional().default(!0),framework:n.enum(["HIPAA","OSHA","SOX","GDPR","PCI_DSS","FERPA","ISO","CUSTOM"]).nullable().optional(),maxRetakeAttempts:n.number().int().min(1).nullable().optional(),passingScore:n.number().int().min(0).max(100).optional().default(80)}),Et=n.object({title:n.string().min(1),description:n.string().min(1),type:Ce,organizationId:n.string().min(1),compliance:je.optional()}),gg=Et.refine(e=>e.type!=="COMPLIANCE"||e.compliance!==void 0,{message:"Compliance settings are required for COMPLIANCE courses",path:["compliance"]}),Yo=n.object({show:n.boolean(),description:n.string().optional()}),Li=["requirements","description","goals","videoUrl","paymentLink"];function Wo(e){if(!e||typeof e!="object"||Array.isArray(e))return e;let t={...e};for(let o of Li)t[o]===null&&(t[o]=void 0);if(t.instructor&&typeof t.instructor=="object"&&!Array.isArray(t.instructor)){let o={...t.instructor};o.coursesNo===void 0&&o.courseNo!==void 0&&(o.coursesNo=o.courseNo),delete o.courseNo,t.instructor=o}if(t.discount===null||t.discount==="")t.discount=void 0;else if(typeof t.discount=="string"){let o=Ho(t.discount);o!==void 0&&(t.discount=o)}return t}var Xo=n.object({name:n.string(),role:n.string(),coursesNo:n.coerce.number().optional(),description:n.string(),imgUrl:n.string()}),Jo=n.object({templateUrl:n.string()}),Ui=n.object({id:n.number(),hide:n.boolean(),name:n.string(),avatar_url:n.string(),rating:n.number(),created_at:n.number(),description:n.string()}),ki=n.array(n.object({id:n.union([n.literal(1),n.literal(2),n.literal(3),n.literal(4)]),name:n.string()})),er=n.object({requirements:n.string().optional(),description:n.string().optional(),goals:n.string().optional(),videoUrl:n.string().optional(),showDiscount:n.boolean().optional(),discount:n.number().optional(),paymentEnabled:n.boolean().optional(),paymentLink:n.string().optional(),reward:Yo.optional(),instructor:Xo.optional(),certificate:Jo.optional(),reviews:n.array(Ui).optional(),skills:n.array(n.string().min(1).max(80)).max(60).optional(),tools:n.array(n.string().min(1).max(80)).max(60).optional(),lessonTabsOrder:ki.optional(),grading:n.boolean().optional(),lessonDownload:n.boolean().optional(),allowSelfEnrollment:n.boolean().optional(),allowNewStudent:n.boolean().optional(),allowMarkdownExport:n.boolean().optional(),welcomeEmailMessage:n.string().max(2e4).nullish(),sessionTimezone:n.string().max(64).nullish(),liveSessionReminderOffsetsMinutes:Vo.optional(),sectionDisplay:n.record(n.string(),n.boolean()).optional(),isContentGroupingEnabled:n.boolean().optional(),progressionMode:n.enum(["free","sequential"]).optional(),commentsEnabled:n.boolean().optional()}),Je=n.preprocess(Wo,er),ji=er.extend({reward:Yo.partial().optional(),instructor:Xo.partial().optional(),certificate:Jo.partial().optional()}),Mi=n.preprocess(Wo,ji),Zi=n.object({isDownloadable:n.boolean().optional(),theme:n.string().optional(),design:wi.optional(),deadline:n.union([n.string().min(1),n.null()]).optional(),threshold:n.number().int().min(0).max(100).optional(),requiredExerciseId:n.union([n.string().uuid(),n.null()]).optional(),exerciseMinScorePercent:n.number().int().min(0).max(100).nullable().optional(),emailMessage:n.string().max(5e3).nullable().optional()}),Gi=n.url({protocol:/^https?$/});function Fi(e,t){let o=t?.paymentEnabled;return typeof o=="boolean"?o:typeof e=="number"&&e>0}function Bi(e,t){let o=[];if(!Fi(e,t))return o;let r=typeof t?.paymentLink=="string"?t.paymentLink.trim():"";return r?Gi.safeParse(r).success||o.push({message:"Payment link must be a valid http(s) URL",path:["metadata","paymentLink"]}):o.push({message:"A payment link is required for paid courses",path:["metadata","paymentLink"]}),(e==null||e<=0)&&o.push({message:"Paid courses must have a cost greater than 0",path:["cost"]}),o}function tr(e,t){for(let o of Bi(e.cost,e.metadata))t.addIssue({code:"custom",message:o.message,path:o.path})}var It=n.object({title:n.string().min(1).optional(),description:n.string().min(1).optional(),type:Ce.optional(),bannerImage:n.string().optional(),logo:n.string().optional(),slug:n.string().optional(),isPublished:n.boolean().optional(),orgOnly:n.boolean().optional(),overview:n.string().optional(),metadata:Je.optional(),cost:n.number().int().min(0).optional(),currency:n.enum(["NGN","USD"]).optional(),certificate:Zi.optional(),tagIds:n.array(n.uuid()).max(100).optional(),compliance:je.optional(),callout:qo.optional()}),bg=It.refine(e=>e.type!=="COMPLIANCE"||e.compliance!==void 0,{message:"Compliance settings are required when changing a course to COMPLIANCE",path:["compliance"]}).superRefine(tr),hg=n.object({courseId:n.string().min(1)}),Ct=n.object({title:n.string().min(1).optional(),description:n.string().min(1).optional(),overview:n.string().optional(),cost:n.number().int().min(0).optional(),currency:n.enum(["NGN","USD"]).optional(),imageUrl:n.url().optional(),generateImage:n.boolean().optional(),imageQuery:n.string().min(1).max(120).optional(),metadata:Mi.optional()}),_g=Ct.superRefine(tr),fg=n.object({courseId:n.string().min(1)}),zg=n.object({courseId:n.string().min(1)}),Eg=n.object({profileId:n.string().uuid()}),Ig=n.object({courseId:n.string().min(1),userId:n.string().uuid()}),Cg=n.object({includeProgressImpact:n.enum(["true","false"]).optional().default("false").transform(e=>e==="true")});import*as p from"zod";import*as g from"zod";import{z as $}from"zod";var Hi=$.discriminatedUnion("action",[$.object({action:$.literal("continue")}),$.object({action:$.literal("go_to_section"),exerciseSectionId:$.string().uuid()}),$.object({action:$.literal("submit")})]),et=$.object({id:$.string().uuid().optional(),title:$.string().min(1,"Section title is required"),description:$.string().optional().nullable(),order:$.number().int().min(0),colorTheme:$.enum(["blue","green","amber","rose","violet","slate"]).default("blue"),afterBehavior:Hi.default({action:"continue"}),questionIds:$.array($.union([$.string(),$.number().int()])).optional()}),Tg=et.omit({id:!0}),Sg=et.partial().required({id:!0});var qi=[g.literal(w.RADIO),g.literal(w.CHECKBOX),g.literal(w.TEXTAREA),g.literal(w.TRUE_FALSE),g.literal(w.SHORT_ANSWER),g.literal(w.NUMERIC),g.literal(w.FILL_BLANK),g.literal(w.FILE_UPLOAD),g.literal(w.MATCHING),g.literal(w.ORDERING),g.literal(w.HOTSPOT),g.literal(w.LINK),g.literal(w.WORD_BANK),g.literal(w.STAR),g.literal(w.VIDEO_RECORDING),g.literal(w.THUMBS)],ot=g.union(qi);function or(e){return t=>{let o=t.options||[];return o.length>0&&o.length<2?e:null}}function Vi(e){let t=e.options||[];return t.length>0&&!t.some(o=>o.isCorrect===!0)?"Please mark an option as the correct answer":null}var $i={[w.RADIO]:[e=>{let t=e.options||[];return t.length>0&&t.length<2?"Options must have at least 2 items for RADIO/CHECKBOX questions":null},e=>{if(typeof e.settings?.correctValue=="boolean")return null;let t=e.options||[];return t.length>0&&!t.some(o=>o.isCorrect===!0)?"Please mark an option as the correct answer":null}],[w.CHECKBOX]:[e=>{let t=e.options||[];return t.length>0&&t.length<2?"Options must have at least 2 items for RADIO/CHECKBOX questions":null},e=>{let t=e.options||[];return t.length>0&&!t.some(o=>o.isCorrect===!0)?"Please mark an option as the correct answer":null}],[w.TRUE_FALSE]:[or("True/False questions need both True and False options"),Vi],[w.THUMBS]:[or("Thumbs up/down questions need both Yes and No options")],[w.TEXTAREA]:[],[w.WORD_BANK]:[e=>{let t=e.settings,r=(String(t?.template??"").match(/_{3,}/g)??[]).length;if(r<1)return"Word bank questions need at least one ___ blank in the template";let i=t?.correctAnswers,c=Array.isArray(i)?i:[];if(c.length<r)return"Provide a correct answer for each blank";for(let b=0;b<r;b++)if(!String(c[b]??"").trim())return`Correct answer for blank ${b+1} is required`;return null}],[w.STAR]:[e=>{let t=e.settings??{},o=Le(t),r=t.correctValue,i=typeof r=="number"?r:r!=null?Number(r):NaN;return Ue(i,o)?null:"Set a correct star value from 1 up to the maximum number of stars"}],[w.VIDEO_RECORDING]:[e=>{let o=(e.settings??{}).maxDurationSeconds,r=typeof o=="number"?o:o!=null?Number(o):NaN;return!Number.isFinite(r)||r<=0?"Set a recording duration greater than 0 seconds":r>120?`Recording duration cannot exceed ${120} seconds`:null}]},Ki=g.object({id:g.number().int().optional(),exerciseSectionId:g.string().uuid().nullable().optional(),question:g.string().min(1),questionTypeId:ot.optional(),points:g.number().int().min(1),order:g.number().int().min(0).optional(),settings:g.record(g.string(),g.unknown()).optional(),deletedAt:g.string().optional(),options:g.array(g.object({id:g.number().int().optional(),label:g.string().min(1),isCorrect:g.boolean(),settings:g.record(g.string(),g.unknown()).optional(),deletedAt:g.string().optional()})).optional()});function rr(e,t){if(e.deletedAt)return;let o=$i[e.questionTypeId??-1]??[];for(let r of o){let i=r(e);i&&t.addIssue({code:"custom",message:i,path:["options"]})}}var Qi=Ki.superRefine(rr),Yi=g.object({question:g.string().min(1),questionTypeId:ot.optional(),points:g.number().int().min(1),order:g.number().int().min(0).optional(),settings:g.record(g.string(),g.unknown()).optional(),options:g.array(g.object({label:g.string().min(1),isCorrect:g.boolean(),settings:g.record(g.string(),g.unknown()).optional()})).optional()}),Wi=Yi.superRefine(rr),nr=g.object({title:g.string().min(1),description:g.string().optional(),lessonId:g.string().optional(),sectionId:g.string().optional(),order:g.number().int().min(1),courseId:g.string().min(1),dueBy:g.string().optional(),slug:Ae.optional(),questions:g.array(Wi).optional()}),sr=g.object({title:g.string().min(1).optional(),description:g.string().optional(),lessonId:g.string().optional(),sectionId:g.string().optional(),order:g.number().int().min(1).optional(),isUnlocked:g.boolean().optional(),dueBy:g.string().optional(),allowMultipleAttempts:g.boolean().optional(),slug:Ae.optional(),questions:g.array(Qi).optional(),sections:g.array(et).optional(),sectionDisplayMode:g.enum(["one_question","all_questions"]).optional(),completionPolicy:g.enum(["submitted","passed"]).optional(),passThreshold:g.number().int().min(0).max(100).optional()}),At=g.object({exerciseId:g.string().min(1)}),ir=g.object({lessonId:g.string().optional(),sectionId:g.string().optional()}),Ng=g.object({exerciseId:g.string().min(1),answers:g.array(g.object({questionId:g.number().int(),optionId:g.number().int().optional(),answer:g.string().optional()})).min(1)}),ar=g.object({lessonId:g.string().optional(),sectionId:g.string().optional(),order:g.number().int().min(1),templateId:g.number().int().min(1)});import*as m from"zod";var ur=["google-slides","canva","powerpoint","keynote","figma","prezi","pitch","gamma","slideshare","beautiful"],cr=[{id:"google-slides",name:"Google Slides",hosts:["docs.google.com"],docsHash:"google-slides",exampleEmbed:'<iframe src="https://docs.google.com/presentation/d/e/2PACX-1vTDemoPresentationId/embed?start=false&loop=false&delayms=3000" width="960" height="569" allowfullscreen="true"></iframe>'},{id:"canva",name:"Canva",hosts:["canva.com"],docsHash:"canva",exampleEmbed:'<iframe src="https://www.canva.com/design/DAFDemoDesignId/view?embed" width="960" height="540" allowfullscreen="allowfullscreen"></iframe>'},{id:"powerpoint",name:"PowerPoint",hosts:["onedrive.live.com","officeapps.live.com","1drv.ms","sharepoint.com"],docsHash:"powerpoint",exampleEmbed:'<iframe src="https://onedrive.live.com/embed?resid=DEMO123&authkey=Ademo&em=2" width="640" height="480" frameborder="0"></iframe>'},{id:"keynote",name:"Keynote",hosts:["icloud.com"],docsHash:"keynote",exampleEmbed:'<iframe src="https://www.icloud.com/keynote/0demoKeynoteShareId?embed=true" width="640" height="500" allowfullscreen></iframe>'},{id:"figma",name:"Figma Slides",hosts:["figma.com","embed.figma.com"],docsHash:"figma",exampleEmbed:'<iframe src="https://embed.figma.com/slides/DemoFileKey123?embed-host=classroomio" width="800" height="450" allowfullscreen></iframe>'},{id:"prezi",name:"Prezi",hosts:["prezi.com"],docsHash:"prezi",exampleEmbed:'<iframe src="https://prezi.com/view/demoPreziViewId/embed" width="550" height="400" allowfullscreen></iframe>'},{id:"pitch",name:"Pitch",hosts:["pitch.com"],docsHash:"pitch",exampleEmbed:'<iframe src="https://pitch.com/embed/demo-pitch-public-id" width="640" height="360" allowfullscreen></iframe>'},{id:"gamma",name:"Gamma",hosts:["gamma.app"],docsHash:"gamma",exampleEmbed:'<iframe src="https://gamma.app/embed/demo-gamma-deck-id" width="700" height="450" allowfullscreen></iframe>'},{id:"slideshare",name:"SlideShare",hosts:["slideshare.net"],docsHash:"slideshare",exampleEmbed:'<iframe src="https://www.slideshare.net/slideshow/embed_code/key/demoSlideShareKey" width="595" height="485" frameborder="0"></iframe>'},{id:"beautiful",name:"Beautiful.ai",hosts:["beautiful.ai"],docsHash:"beautiful",exampleEmbed:'<iframe src="https://www.beautiful.ai/player/-demoBeautifulAiId" width="960" height="540" allowfullscreen></iframe>'}],vg=Object.fromEntries(cr.map(e=>[e.id,e]));function Xi(e){return e.hostname.replace(/^www\./i,"").toLowerCase()}function Ji(e,t){let o=t.replace(/^www\./i,"").toLowerCase();return e===o||e.endsWith(`.${o}`)}function yt(e){let t=e.replace(/^www\./i,"").toLowerCase();return cr.find(o=>o.hosts.some(r=>Ji(t,r)))??null}function lr(e){try{let t=new URL(e);return t.protocol!=="https:"?!1:yt(Xi(t))!==null}catch{return!1}}var oa=/^\/hls\/[\w./-]+$/,rt=m.object({type:m.enum(["youtube","vimeo","generic","upload","google_drive"]),link:m.string().refine(e=>oa.test(e)||zo(e),{message:"Video link scheme is not allowed"}),key:m.string().optional(),assetId:m.string().uuid().optional(),watchEnforced:m.boolean().optional(),fileName:m.string().optional(),metadata:m.object({svid:m.string().optional(),title:m.string().optional(),description:m.string().optional(),thumbnailUrl:m.string().optional(),duration:m.number().optional(),aspectRatio:m.string().optional(),createdAt:m.string().optional(),videoId:m.string().optional(),hash:m.string().optional()}).catchall(m.unknown()).optional()}),ra=m.object({id:m.string().min(1),src:m.url().refine(e=>lr(e),{message:"Slide embed source is not from a supported platform"}),platform:m.enum(ur)}).refine(e=>{try{let t=new URL(e.src).hostname.replace(/^www\./i,"").toLowerCase();return yt(t)?.id===e.platform}catch{return!1}},{message:"Slide platform does not match embed source",path:["platform"]}),na=m.url({protocol:/^https?$/,message:"Recording link must be an http(s) URL"}),sa=m.number().int().min(15).max(480),Gg=m.object({title:m.string().min(1),note:m.string().optional(),courseId:m.string().min(1),sectionId:m.string().optional(),order:m.number().int().min(1),lessonAt:m.string().optional(),teacherId:m.string().optional(),isUnlocked:m.boolean().optional(),public:m.boolean().optional(),slug:Ae.optional(),videos:m.array(rt).optional()}),Fg=m.object({title:m.string().min(1).optional(),note:m.string().optional(),sectionId:m.string().optional(),order:m.number().int().min(1).optional(),callUrl:m.string().nullable().optional(),lessonAt:m.string().nullable().optional(),sessionDurationMinutes:sa.nullable().optional(),recordingUrl:na.nullable().optional(),teacherId:m.string().optional(),isUnlocked:m.boolean().optional(),public:m.boolean().optional(),slug:Ae.optional(),isComplete:m.boolean().optional(),completionPolicy:m.enum(["manual","video_watch","none"]).optional(),videoWatchThreshold:m.number().int().min(1).max(100).optional(),commentsEnabled:m.boolean().optional(),videoUrl:m.url().optional(),slideUrl:m.string().optional(),slides:m.array(ra).optional(),videos:m.array(rt).optional(),documents:m.array(m.object({type:m.string(),name:m.string(),link:m.string(),size:m.number().optional(),key:m.string(),assetId:m.string().uuid().optional()})).optional()}),Bg=m.object({lessonId:m.string().min(1)}),Hg=m.object({sectionId:m.string().optional(),courseId:m.string().min(1)}),qg=m.object({courseId:m.string().min(1),lessonId:m.string().min(1)}),Vg=m.object({locale:m.string().min(1),limit:m.string().transform(Number).pipe(m.number().int().min(1).max(50)).default(10),cursor:m.string().min(1).optional()}),$g=m.object({lessonId:m.string().min(1),comment:m.string().min(1)}),Kg=m.object({commentId:m.string().min(1)}),Qg=m.object({comment:m.string().min(1)}),Yg=m.object({cursor:m.string().optional(),limit:m.coerce.number().min(1).max(50).optional().default(10)}),Wg=m.object({lessonId:m.string().min(1),isComplete:m.boolean()}),Xg=m.object({isComplete:m.boolean()}),Jg=m.object({positionSeconds:m.number().min(0),playedDeltaSeconds:m.number().transform(e=>Math.round(e)).pipe(m.number().min(0).max(120)),durationSeconds:m.number().transform(e=>Math.round(e)).pipe(m.int().min(1)),assetId:m.string().optional()});var pr=p.enum(["en","hi","fr","pt","de","vi","ru","es","pl","da","tr","it"]),ia="Lesson body HTML only. Do not include the lesson title. Do not use h1 or h2 anywhere in lessonLanguages[].content. Start headings at h3 because that is the highest heading level allowed in lesson content.",dr=p.object({code:p.string().min(1),message:p.string().min(1),severity:p.enum(["info","warning","error"])}),aa=p.object({type:p.enum(["prompt","pdf","course"]),label:p.string().min(1),pageStart:p.number().int().min(1).optional(),pageEnd:p.number().int().min(1).optional()}),ua=p.object({title:p.string().min(1),description:p.string().min(1),type:Ce,locale:pr.default("en"),metadata:Je.optional(),compliance:je.optional()}).refine(e=>e.type!=="COMPLIANCE"||e.compliance!==void 0,{message:"Compliance settings are required for COMPLIANCE courses",path:["compliance"]}),ca=p.object({externalId:p.string().min(1),title:p.string().min(1),order:p.number().int().min(1)}),la=p.object({externalId:p.string().min(1),sectionExternalId:p.string().min(1),title:p.string().min(1),order:p.number().int().min(1),isUnlocked:p.boolean().optional(),public:p.boolean().optional(),videos:p.array(rt).optional()}),pa=p.object({lessonExternalId:p.string().min(1),locale:pr,content:p.string().min(1).describe(ia)}),da=p.object({label:p.string().min(1),isCorrect:p.boolean(),settings:p.record(p.string(),p.unknown()).optional()}),ma=p.object({question:p.string().min(1),questionTypeId:ot.optional(),points:p.number().int().min(1),order:p.number().int().min(1).optional(),settings:p.record(p.string(),p.unknown()).optional(),options:p.array(da).optional()}),ga=p.object({externalId:p.string().min(1),lessonExternalId:p.string().min(1).optional(),sectionExternalId:p.string().min(1).optional(),title:p.string().min(1),description:p.string().optional(),order:p.number().int().min(1),dueBy:p.string().optional(),questions:p.array(ma).optional()}),De=p.object({course:ua,tags:p.array(p.string().trim().min(1).max(80)).max(100).default([]),sections:p.array(ca).min(1),lessons:p.array(la).min(1),lessonLanguages:p.array(pa).min(1),exercises:p.array(ga).optional(),sourceReferences:p.array(aa).optional(),warnings:p.array(dr).default([])}).superRefine((e,t)=>{let o=new Set;e.tags.forEach((C,x)=>{let Z=C.trim().toLowerCase();o.has(Z)&&t.addIssue({code:p.ZodIssueCode.custom,path:["tags",x],message:"Draft tags must be unique"}),o.add(Z)});let r=new Set;e.sections.forEach((C,x)=>{r.has(C.externalId)&&t.addIssue({code:p.ZodIssueCode.custom,path:["sections",x,"externalId"],message:"Section externalId must be unique"}),r.add(C.externalId)});let i=e.sections.map(C=>C.order).sort((C,x)=>C-x);i.length>0&&i.some((C,x)=>C!==x+1)&&t.addIssue({code:p.ZodIssueCode.custom,path:["sections"],message:"Section orders must be a contiguous 1-based sequence (1, 2, 3, ...)"});let c=new Set;e.lessons.forEach((C,x)=>{c.has(C.externalId)&&t.addIssue({code:p.ZodIssueCode.custom,path:["lessons",x,"externalId"],message:"Lesson externalId must be unique"}),c.add(C.externalId),r.has(C.sectionExternalId)||t.addIssue({code:p.ZodIssueCode.custom,path:["lessons",x,"sectionExternalId"],message:"Lesson sectionExternalId must reference an existing section"})});let b=new Map;for(let C of e.lessons){let x=b.get(C.sectionExternalId)??[];x.push(C.order),b.set(C.sectionExternalId,x)}for(let[,C]of b)[...C].sort((Z,Ee)=>Z-Ee).some((Z,Ee)=>Z!==Ee+1)&&t.addIssue({code:p.ZodIssueCode.custom,path:["lessons"],message:"Lesson orders within each section must be a contiguous 1-based sequence (1, 2, 3, ...)"});e.lessonLanguages.forEach((C,x)=>{c.has(C.lessonExternalId)||t.addIssue({code:p.ZodIssueCode.custom,path:["lessonLanguages",x,"lessonExternalId"],message:"Lesson language must reference an existing lesson"})});let q=new Set;if(e.exercises?.forEach((C,x)=>{q.has(C.externalId)&&t.addIssue({code:p.ZodIssueCode.custom,path:["exercises",x,"externalId"],message:"Exercise externalId must be unique"}),q.add(C.externalId),C.lessonExternalId&&!c.has(C.lessonExternalId)&&t.addIssue({code:p.ZodIssueCode.custom,path:["exercises",x,"lessonExternalId"],message:"Exercise lessonExternalId must reference an existing lesson"}),C.sectionExternalId&&!r.has(C.sectionExternalId)&&t.addIssue({code:p.ZodIssueCode.custom,path:["exercises",x,"sectionExternalId"],message:"Exercise sectionExternalId must reference an existing section"})}),e.exercises){let C=new Map(e.lessons.map(Z=>[Z.externalId,Z])),x=new Map;for(let Z of e.exercises){let Ee=Z.sectionExternalId??"";Z.lessonExternalId&&(Ee=C.get(Z.lessonExternalId)?.sectionExternalId??Z.lessonExternalId);let Oe=x.get(Ee)??[];Oe.push(Z.order),x.set(Ee,Oe)}for(let[,Z]of x)[...Z].sort((Oe,Ge)=>Oe-Ge).some((Oe,Ge)=>Oe!==Ge+1)&&t.addIssue({code:p.ZodIssueCode.custom,path:["exercises"],message:"Exercise orders within each group must be a contiguous 1-based sequence (1, 2, 3, ...)"})}}),Tt=p.object({sourceType:p.enum(["prompt","pdf","course"]),idempotencyKey:p.string().min(1).optional(),summary:p.record(p.string(),p.unknown()).optional(),sourceArtifacts:p.array(p.record(p.string(),p.unknown())).optional(),draft:De}),de=p.object({courseId:p.string().min(1)}),St=p.object({courseId:p.string().min(1),idempotencyKey:p.string().min(1).optional(),summary:p.record(p.string(),p.unknown()).optional(),sourceArtifacts:p.array(p.record(p.string(),p.unknown())).optional()}),ve=p.object({draftId:p.string().uuid()}),mr=p.object({summary:p.record(p.string(),p.unknown()).optional(),sourceArtifacts:p.array(p.record(p.string(),p.unknown())).optional(),warnings:p.array(dr).optional(),draft:De.optional()}),nt=p.object({title:p.string().min(1).optional(),description:p.string().min(1).optional(),type:Ce.optional(),metadata:Je.optional(),compliance:je.optional(),bannerImageUrl:p.string().url().optional(),bannerImageQuery:p.string().min(1).max(120).optional(),generateBannerImage:p.boolean().optional()}),sb=nt.refine(e=>e.type!=="COMPLIANCE"||e.compliance!==void 0,{message:"Compliance settings are required for COMPLIANCE courses",path:["compliance"]}),xt=nt.extend({courseId:p.string().min(1),syncMode:p.enum(["merge","replace"]).default("merge")}),ib=xt.refine(e=>e.type!=="COMPLIANCE"||e.compliance!==void 0,{message:"Compliance settings are required for COMPLIANCE courses",path:["compliance"]});var V=K.object({courseId:K.string().uuid()}),pb=Et.omit({organizationId:!0}).refine(e=>e.type!=="COMPLIANCE"||e.compliance!==void 0,{message:"Compliance settings are required for COMPLIANCE courses",path:["compliance"]}),db=It.omit({tagIds:!0}).refine(e=>e.type!=="COMPLIANCE"||e.compliance!==void 0,{message:"Compliance settings are required when changing a course to COMPLIANCE",path:["compliance"]}),mb=K.object({mode:K.enum(["merge","replace"]).default("merge"),idempotencyKey:K.string().min(1).optional(),summary:K.record(K.string(),K.unknown()).optional(),sourceArtifacts:K.array(K.record(K.string(),K.unknown())).optional(),draft:De});import*as O from"zod";import*as Me from"zod";var B=Me.object({page:Me.coerce.number().int().min(1).default(1),limit:Me.coerce.number().int().min(1).max(100).default(20)});var ba=O.enum(["classique","brutalist","noir","poster","minimal"]),gr=O.object({name:O.string().max(80).default(""),role:O.string().max(80).default(""),enabled:O.boolean().default(!0),signatureUrl:O.url().optional()}),Ot=O.object({templateId:ba,accentColor:O.string().regex(/^#[0-9a-fA-F]{6}$/,{message:"Accent must be a 6-digit hex color"}),subtitle:O.string().max(120).optional(),descriptionOverride:O.string().max(500).optional(),signatories:O.tuple([gr,gr]),idFormat:O.string().max(40).optional()}),ha=O.iso.datetime({offset:!0,message:"deadline must be an ISO 8601 datetime with a timezone, e.g. 2026-12-31T23:59:59Z"}),br=O.object({isDownloadable:O.boolean().optional(),theme:O.string().min(1).max(40).optional(),design:Ot.optional(),deadline:ha.nullable().optional(),threshold:O.number().int().min(0).max(100).optional(),requiredExerciseId:O.string().uuid().nullable().optional(),exerciseMinScorePercent:O.number().int().min(0).max(100).nullable().optional(),emailMessage:O.string().max(5e3).nullable().optional()}),_a=Object.keys(br.shape),hr=br.refine(e=>_a.some(t=>e[t]!==void 0),{message:"Provide at least one certificate field to update"}),_r=B.extend({search:O.string().trim().max(200).optional()}),fr=V.extend({memberId:O.string().uuid()}),fa=O.enum(["pdf","png"]),zr=O.object({format:fa.default("pdf")});import*as H from"zod";var Eb=H.object({isDownloadable:H.boolean().default(!1),theme:H.string(),design:Ot,deadline:H.iso.datetime({offset:!0}).nullable(),threshold:H.number().default(100),requiredExerciseId:H.string().uuid().nullable(),exerciseMinScorePercent:H.number().nullable(),emailMessage:H.string().nullable()}),Ib=H.object({memberId:H.string(),profileId:H.string().nullable(),fullname:H.string().nullable(),email:H.string().nullable(),certificateEarnedAt:H.string(),certificationEmailSentAt:H.string().nullable()});import*as N from"zod";var Rt=V,Er=V.extend({inviteId:N.string().uuid()}),Ir=N.object({preset:N.enum(["ONE_TIME_24H","MULTI_USE_7D","MULTI_USE_30D","CUSTOM"]).default("MULTI_USE_30D"),expiresAt:N.string().min(1).optional(),maxUses:N.number().int().min(1).max(1e3).optional(),allowedEmails:N.array(N.string().email()).max(100).optional(),allowedDomains:N.array(N.string().min(1)).max(100).optional(),recipientEmails:N.array(N.string().email()).max(500).optional(),recipientCsv:N.string().max(25e3).optional(),sendEmail:N.boolean().default(!1),metadata:N.record(N.string(),N.unknown()).optional()}).refine(e=>{let t=(e.recipientEmails?.length??0)>0,o=typeof e.recipientCsv=="string"&&e.recipientCsv.trim().length>0;return t||o},{message:"recipientEmails or recipientCsv is required",path:["recipientEmails"]}),Cr=B;import*as v from"zod";var Ar=v.union([v.literal(ee.ADMIN),v.literal(ee.TUTOR),v.literal(ee.STUDENT)]).describe("1 = admin, 2 = tutor, 3 = student"),ye=V.extend({memberId:v.string().uuid()}),yr=B.extend({search:v.string().trim().max(200).optional(),roleId:v.coerce.number().int().min(1).optional()}),Tr=v.object({profileId:v.uuid().optional(),roleId:Ar,email:v.email().optional(),name:v.string().optional().describe("Used in the welcome email sent to added tutors/admins")}).refine(e=>!!e.profileId||!!e.email,{message:"Either profileId or email must be provided",path:["profileId"]}),Pt=v.object({roleId:Ar.optional(),email:v.email().optional()}).refine(e=>Object.keys(e).length>0,{message:"No fields to update"}),Sr=v.object({includeProgressImpact:v.enum(["true","false"]).optional().default("false").transform(e=>e==="true")});import*as d from"zod";import*as J from"zod";var Pb=J.object({organizationId:J.string().min(1)}),wb=J.object({templateId:J.string().min(1)}),Nb=J.object({organizationId:J.string().min(1)}),Db=J.object({title:J.string().min(1)}),vb=J.object({courseId:J.string().min(1)}),Lb=J.object({title:J.string().min(1),organizationId:J.string().min(1)});import{z as Ze}from"zod";var za=["description","bannerImage","welcomeEmail","completionDeadline","completionThreshold","finalExercise","lessonTabsOrder","contentGrouping","progression","comments","selfEnrollment","markdownExport","lessonDownload","landingRequirements","landingDescription","landingGoals","landingSkills","landingTools","landingInstructor","pricing","certificateDesign","certificateRules","aiTutor"],Gb=Ze.object({unitIds:Ze.array(Ze.string().uuid()).default([]),settingKeys:Ze.array(Ze.enum(za)).default([])});import{z as ie}from"zod";var Ea=ie.object({courseId:ie.string().uuid()}),Hb=Ea.extend({profileId:ie.string().uuid()}),wt=ie.array(ie.string().uuid()).min(1).optional(),qb=ie.object({profileIds:wt,dueDate:ie.string().datetime()}),Vb=ie.object({profileIds:wt,dueDate:ie.string().datetime()}),$b=ie.object({profileIds:wt,waiverReason:ie.string().trim().min(1).max(1e3).optional(),waiverExpiresAt:ie.string().datetime().optional()});import*as Nt from"zod";var Yb=Nt.object({courseSlug:gt}),Wb=Nt.object({courseSlug:gt,itemSlug:Ae});import*as U from"zod";var Jb=U.object({title:U.string().min(1),courseId:U.string().min(1),order:U.number().int().min(1)}),eh=U.object({title:U.string().min(1).optional(),order:U.number().int().min(1).optional()}),th=U.object({title:U.string().min(1)}),oh=U.object({sectionId:U.string().min(1)}),rh=U.object({sections:U.array(U.object({id:U.string().min(1),order:U.number().int().min(1)})).min(1)}).superRefine((e,t)=>{e.sections.map(r=>r.order).sort((r,i)=>r-i).some((r,i)=>r!==i+1)&&t.addIssue({code:U.ZodIssueCode.custom,path:["sections"],message:"Section orders must be a contiguous 1-based sequence (1, 2, 3, ...)"})});import*as S from"zod";var sh=S.object({courseId:S.string().min(1)}),ih=S.object({courseId:S.string().min(1),inviteId:S.string().uuid()}),ah=S.object({courseId:S.string().min(1),inviteId:S.string().uuid()}),uh=S.object({token:S.string().min(1)}),ch=S.object({courseId:S.uuid()}),Ia=S.enum(["ONE_TIME_24H","MULTI_USE_7D","MULTI_USE_30D","CUSTOM"]),lh=S.object({preset:Ia.default("MULTI_USE_30D"),expiresAt:S.string().min(1).optional(),maxUses:S.number().int().min(1).max(1e3).optional(),allowedEmails:S.array(S.string().email()).max(100).optional(),allowedDomains:S.array(S.string().min(1)).max(100).optional(),recipientEmails:S.array(S.string().email()).max(500).optional(),recipientCsv:S.string().max(25e3).optional(),sendEmail:S.boolean().default(!1),metadata:S.record(S.string(),S.unknown()).optional()}).refine(e=>{let t=(e.recipientEmails?.length??0)>0,o=typeof e.recipientCsv=="string"&&e.recipientCsv.trim().length>0;return t||o},{message:"recipientEmails or recipientCsv is required",path:["recipientEmails"]});import*as E from"zod";var xr=E.union([E.literal(ee.ADMIN),E.literal(ee.TUTOR),E.literal(ee.STUDENT)]),mh=E.object({courseId:E.string().min(1)}),Ca=E.enum(["name","role","progress","lastLogin","enrolledAt","certificate"]),Aa=E.enum(["asc","desc"]),Dt=E.enum(["not_started","in_progress","completed"]),ya=E.enum(["joined","invited"]),Ta=E.enum(["7d","30d","90d","180d","never"]),Sa=E.enum(["7d","30d","90d","180d"]),gh=E.object({page:E.coerce.number().int().min(1).default(1),limit:E.coerce.number().int().min(1).max(100).default(20),search:E.string().trim().max(200).optional(),roleId:E.coerce.number().int().min(1).optional(),sortBy:Ca.default("role"),sortOrder:Aa.default("asc"),progress:Dt.optional(),membership:ya.optional(),enrolledWithin:Sa.optional(),lastLoginBefore:Ta.optional(),certificateEarned:E.union([E.boolean(),E.enum(["true","false"])]).optional().transform(e=>e==null?void 0:e===!0||e==="true")});var bh=E.object({courseId:E.string().min(1),memberId:E.string().min(1)}),hh=E.array(E.object({profileId:E.uuid().optional(),roleId:xr,email:E.email().optional(),name:E.string().optional()})),_h=E.object({roleId:xr.optional(),email:E.email().optional()}).refine(e=>Object.keys(e).length>0,{message:"No fields to update"}),fh=E.object({courseId:E.string().uuid(),memberId:E.string().uuid()});var st=d.string(),me=d.string().nullable(),Or=d.number().describe("1 = admin, 2 = tutor, 3 = student"),xa=d.object({id:d.string().uuid(),groupId:d.string().uuid(),roleId:Or,profileId:d.string().uuid().nullable(),email:d.string().nullable(),createdAt:me,assignedStudentId:d.string().nullable(),certificateEarnedAt:me,certificationEmailSentAt:me}),Oa=xa.extend({profile:d.object({id:d.string().uuid(),fullname:d.string().nullable(),username:d.string().nullable(),avatarUrl:d.string().nullable(),email:d.string().nullable()}).nullable()}),Dh=Oa.extend({progressPercent:d.number().optional().describe("Students only"),progressBucket:Dt.nullable(),stage:d.discriminatedUnion("kind",[d.object({kind:d.literal("not_started")}),d.object({kind:d.literal("certificate_earned")}),d.object({kind:d.literal("content"),position:d.number(),title:d.string(),contentType:d.enum(["lesson","exercise"])})]).optional().describe("Students only"),lastLoginAt:me.optional().describe("Students only"),enrolledAt:me.optional().describe("Students only")}),vh=d.object({lessonCompletion:d.number(),lessonVideoProgress:d.number(),submissions:d.number(),groupAttendance:d.number(),lessonComments:d.number(),courseNewsfeed:d.number(),courseNewsfeedComments:d.number(),courseCertificateIssues:d.number(),courseCompletionRecords:d.number(),aiChatConversations:d.number()}),Lh=d.object({user:d.object({id:d.string().uuid(),fullName:d.string(),email:d.string(),avatarUrl:d.string(),lastSeen:st.optional()}),averageGrade:d.number().nullable().describe("Percentage across graded exercises; null when nothing is graded yet"),userExercisesStats:d.array(d.object({id:d.string().uuid(),lessonId:d.string().uuid().nullable(),lessonTitle:d.string(),title:d.string(),status:d.number().optional().describe("Submission status id; absent when not submitted"),score:d.number(),totalPoints:d.number(),isCompleted:d.boolean()})),totalExercises:d.number(),completedExercises:d.number(),lessonsCompleted:d.number(),lessonsCount:d.number(),progressPercentage:d.number(),progressImpact:d.object({completedLessons:d.number(),totalLessons:d.number(),exerciseSubmissions:d.number(),lessonComments:d.number(),courseNewsfeedActivity:d.number(),videoProgressLessons:d.number(),attendanceEntries:d.number(),hasCertificationRecords:d.boolean()}).nullable().describe("Only set when includeProgressImpact=true")}),Rr=d.enum(["ACTIVE","REVOKED","EXPIRED","USED_UP"]),Pr=d.object({id:d.string().uuid(),courseId:d.string().uuid(),roleId:Or,expiresAt:st,maxUses:d.number(),usedCount:d.number(),allowedEmails:d.array(d.string()).nullable(),allowedDomains:d.array(d.string()).nullable(),createdAt:st,status:Rr}),Uh=Pr.extend({isRevoked:d.boolean(),updatedAt:st,lastUsedAt:me,revokedAt:me,revokedByProfileId:d.string().uuid().nullable(),createdBy:d.object({id:d.string().uuid(),fullname:d.string().nullable(),email:d.string().nullable()}).nullable(),usesRemaining:d.number(),activity:d.object({previewedCount:d.number(),acceptedCount:d.number(),emailSentCount:d.number(),emailFailedCount:d.number(),lastPreviewedAt:me,lastAcceptedAt:me,lastEmailSentAt:me})}),kh=d.object({mode:d.enum(["single","bulk"]).describe("single = one shareable link, bulk = one invite per recipient email"),invites:d.array(Pr.extend({inviteLink:d.string().describe("Enroll URL containing the invite token; only returned at creation")})),inviteLink:d.string().nullable(),duplicatesSkipped:d.array(d.string()),delivery:d.object({requested:d.number(),sent:d.number(),failed:d.number(),failures:d.array(d.object({email:d.string(),error:d.string()}))})}),jh=d.object({id:d.string().uuid(),status:Rr,isRevoked:d.boolean()});import*as s from"zod";var ae=s.string().nullable(),Ra=s.number().describe("1 = admin, 2 = tutor, 3 = student"),Pa=s.object({requirements:s.string().optional(),description:s.string().optional(),goals:s.string().optional(),videoUrl:s.string().optional(),showDiscount:s.boolean().optional(),discount:s.number().optional(),paymentEnabled:s.boolean().optional(),paymentLink:s.string().optional(),reward:s.object({show:s.boolean(),description:s.string().optional()}).optional(),instructor:s.object({name:s.string(),role:s.string(),coursesNo:s.number().optional(),description:s.string(),imgUrl:s.string()}).optional(),certificate:s.object({templateUrl:s.string()}).optional(),reviews:s.array(s.object({id:s.number(),hide:s.boolean(),name:s.string(),avatar_url:s.string(),rating:s.number(),created_at:s.number(),description:s.string()})).optional(),skills:s.array(s.string()).optional(),tools:s.array(s.string()).optional(),lessonTabsOrder:s.array(s.object({id:s.number(),name:s.string()})).optional(),grading:s.boolean().optional(),lessonDownload:s.boolean().optional(),allowSelfEnrollment:s.boolean().optional(),allowNewStudent:s.boolean().optional().describe("Deprecated; use allowSelfEnrollment"),allowMarkdownExport:s.boolean().optional(),welcomeEmailMessage:s.string().nullable().optional(),sessionTimezone:s.string().nullable().optional(),liveSessionReminderOffsetsMinutes:s.array(s.number()).optional(),sectionDisplay:s.record(s.string(),s.boolean()).optional(),isContentGroupingEnabled:s.boolean().optional(),progressionMode:s.enum(["free","sequential"]).optional(),commentsEnabled:s.boolean().optional(),aiTutor:s.record(s.string(),s.unknown()).optional().describe("Per-course AI tutor overrides")}).catchall(s.unknown()),wa=s.object({name:s.string(),role:s.string(),enabled:s.boolean().optional(),signatureUrl:s.string().optional()}),Na=s.object({isDownloadable:s.boolean().optional(),theme:s.string().optional().describe("Deprecated; use design.templateId"),design:s.object({templateId:s.enum(["classique","brutalist","noir","poster","minimal"]),accentColor:s.string(),subtitle:s.string().optional(),descriptionOverride:s.string().optional(),signatories:s.array(wa).optional(),idFormat:s.string().optional()}).optional(),deadline:s.string().nullable().optional(),threshold:s.number().optional(),requiredExerciseId:s.string().uuid().nullable().optional(),exerciseMinScorePercent:s.number().nullable().optional(),emailMessage:s.string().nullable().optional()}).catchall(s.unknown()),Da=s.object({retakeIntervalMonths:s.number(),gracePeriodDays:s.number().optional(),reminderDaysBefore:s.array(s.number()).optional(),isMandatory:s.boolean().optional(),framework:s.enum(["HIPAA","OSHA","SOX","GDPR","PCI_DSS","FERPA","ISO","CUSTOM"]).nullable().optional(),maxRetakeAttempts:s.number().nullable().optional(),passingScore:s.number().optional()}).catchall(s.unknown()),va=s.object({title:s.string(),description:s.string(),buttonLabel:s.string(),buttonUrl:s.string(),animation:s.enum(["waves","dotted","none"]).optional()}),vt=s.object({id:s.string().uuid(),title:s.string(),description:s.string(),overview:s.string().nullable(),createdAt:ae,updatedAt:ae,groupId:s.string().uuid().nullable(),isTemplate:s.boolean(),templateId:s.string().uuid().nullable(),publicForAll:s.boolean(),seedKey:s.string().nullable(),logo:s.string().describe("Deprecated; use bannerImage"),slug:s.string().nullable(),metadata:Pa,cost:s.number().nullable(),currency:s.string(),bannerImage:s.string().nullable(),isPublished:s.boolean().nullable(),displayOrder:s.number().nullable(),certificate:Na.nullable(),compliance:Da.nullable(),status:s.string().describe("ACTIVE, or DELETED once the course is deleted"),type:s.enum(Ve).nullable(),callout:va.nullable()}),Fh=vt.extend({lessonCount:s.number(),totalStudents:s.number(),exerciseCount:s.number(),tags:s.array(s.object({id:s.string().uuid(),name:s.string(),slug:s.string(),color:s.string()}))}),wr=s.object({id:s.string().uuid(),type:s.enum(["LESSON","EXERCISE"]),title:s.string(),order:s.number().nullable(),createdAt:ae,sectionId:s.string().uuid().nullable(),isUnlocked:s.boolean().nullable(),isComplete:s.boolean().nullable(),lessonAt:ae,callUrl:s.string().nullable(),sessionDurationMinutes:s.number().nullable(),recordingUrl:s.string().nullable(),hasNoteContent:s.boolean().nullable(),hasSlideContent:s.boolean().nullable(),videosCount:s.number().nullable(),documentsCount:s.number().nullable(),questionCount:s.number().nullable(),dueBy:ae}),Bh=vt.extend({group:s.object({id:s.string().uuid(),name:s.string(),description:s.string().nullable(),createdAt:ae,updatedAt:ae,organizationId:s.string().uuid().nullable(),members:s.array(s.object({id:s.string().uuid(),groupId:s.string().uuid(),roleId:Ra,profileId:s.string().uuid().nullable(),email:s.string().nullable(),createdAt:ae,assignedStudentId:s.string().nullable(),certificateEarnedAt:ae,certificationEmailSentAt:ae,profile:s.object({id:s.string().uuid(),fullname:s.string().nullable(),username:s.string().nullable(),avatarUrl:s.string().nullable(),email:s.string().nullable()}).nullable()}))}).nullable(),attendance:s.array(s.object({id:s.number(),createdAt:ae,updatedAt:ae,courseId:s.string().uuid().nullable(),studentId:s.string().uuid().nullable().describe("Course member id"),isPresent:s.boolean().nullable(),lessonId:s.string().uuid()})),content:s.object({grouped:s.boolean().describe("true when content is organized into sections"),sections:s.array(s.object({id:s.string().describe('Section id, or "ungrouped" for items that belong to no section'),title:s.string(),order:s.number().nullable(),items:s.array(wr)})),items:s.array(wr).describe("Filled only when grouped is false")}),studentLimitReached:s.boolean(),org:s.object({id:s.string().uuid(),name:s.string(),siteName:s.string(),theme:s.string().optional()}).optional()}),Hh=s.object({course:vt,groupId:s.string().uuid(),memberId:s.string().uuid().describe("The key creator's course member id; they are added as a tutor")}),La=s.object({questionId:s.union([s.number(),s.string()]),questionTitle:s.string(),exerciseId:s.string(),exerciseTitle:s.string(),typeId:s.number()}),qh=s.object({conversionBlocked:s.array(La).optional().describe("Set when a type change was skipped because these questions cannot be auto-graded")}),Vh=s.object({courseId:s.string().uuid(),draft:De}),$h=s.object({draftId:s.string().uuid(),syncMode:s.enum(["merge","replace"]),courseId:s.string().uuid(),courseUrl:s.string(),bannerImageUrl:s.string().nullable(),tagNames:s.array(s.string()),localeCount:s.number(),createdSections:s.number(),createdLessons:s.number(),createdExercises:s.number(),createdLessonLanguages:s.number(),updatedSections:s.number(),updatedLessons:s.number(),updatedExercises:s.number(),updatedLessonLanguages:s.number(),deletedSections:s.number(),deletedLessons:s.number(),deletedExercises:s.number(),deletedLessonLanguages:s.number(),untouchedSections:s.number(),untouchedLessons:s.number(),untouchedExercises:s.number()});import*as I from"zod";var Ua=I.object({type:I.literal("upload"),assetId:I.string().uuid().describe("From POST /assets, after its bytes have been uploaded.")}),ka=I.object({type:I.enum(["youtube","vimeo","generic"]),link:I.url().describe("Public URL. Embedded as-is; never fetched server-side.")}),Nr=I.discriminatedUnion("type",[Ua,ka]),Yh=V.extend({lessonId:I.string().uuid()}),Wh=I.object({title:I.string().min(1).max(255),sectionId:I.string().uuid().optional(),order:I.number().int().min(1),isUnlocked:I.boolean().optional(),public:I.boolean().optional(),videos:I.array(Nr).max(20).optional()}),Xh=I.object({title:I.string().min(1).max(255).optional(),order:I.number().int().min(1).optional(),isUnlocked:I.boolean().optional(),public:I.boolean().optional(),videos:I.array(Nr).max(20).optional().describe("Replaces the lesson videos entirely. Omit to leave them unchanged.")}),Jh=I.object({id:I.string(),title:I.string(),slug:I.string().nullable(),order:I.number().nullable(),sectionId:I.string().nullable(),isUnlocked:I.boolean().nullable(),public:I.boolean().nullable(),videos:I.array(I.object({type:I.string(),assetId:I.string().optional(),link:I.string().optional()})).nullable()});var ge="The API key creator must be a member of the cohort or an org admin, otherwise 403.",D="The API key creator must be a cohort tutor/admin or an org admin, otherwise 403.",se="Paginated: page (default 1) and limit (default 20, max 100); the result includes pagination.",j={readOnlyHint:!0,destructiveHint:!1},Q={readOnlyHint:!1,destructiveHint:!1},ze={readOnlyHint:!1,destructiveHint:!0};function f(e){return{content:[{type:"text",text:JSON.stringify(e)}]}}var Dr="The API key creator must be an org admin or tutor, otherwise 403.",ja="The API key creator must be an org admin, otherwise 403.",vr="The API key creator must be a course tutor/admin or an org admin, otherwise 403.",Lr="Each section may be up to 10 minutes old (login activity: 24 hours); meta.generatedAt says when.",Ur=Kt,kr=B,jr=Wt,Mr=V.extend(Qt.shape),Zr=V.extend(Yt.shape),Ma=Ur.shape,Za=kr.shape,Ga=jr.shape,Fa=Mr.shape,Ba=Zr.shape;function Gr(e,t){e.tool("get_org_analytics",`Organization analytics. Pick sections with include (default ["overview"]): overview (totals, top courses by students, recent certificates), traffic (views, visitors, enrollments, completions, per-day series), countries, funnel (landing \u2192 course page \u2192 enrollment \u2192 completion), courseTypes, topCourses (most viewed), loginActivity (logins by day of week, org admin only), compliance (status counts, org admin only). days is 7, 30, 90 or 365 (default 30); limit (1-20, default 5) caps list sections. Sections the key creator can't see are left out and listed in meta.omitted. ${Lr} ${Dr}`,Ma,j,async o=>{let r=Ur.parse(o),i=await t.getOrgAnalytics(r);return f(i)}),e.tool("list_compliance_learners",`One row per student per compliance course with their latest status, due date and validity, ordered by course title then learner name. For the counts, use get_org_analytics with include ["compliance"]. ${se} ${ja}`,Za,j,async o=>{let r=kr.parse(o),i=await t.listComplianceLearners(r);return f(i)}),e.tool("get_learner_analytics",`A learner's progress and grades across every course they're enrolled in within this organization, with per-exercise results. profileId is the id list_compliance_learners and list_course_analytics_students return; 404 if it isn't in the organization. ${Dr}`,Ga,j,async o=>{let{profileId:r}=jr.parse(o),i=await t.getLearnerAnalytics(r);return f(i)}),e.tool("get_course_analytics",`Course analytics. Pick sections with include (default ["summary"]): summary (tutors, students, lessons, exercises, and per-student averages for progress, exercise completion and grade) and funnel (course page \u2192 enrollment \u2192 completion over days: 7, 30, 90 or 365, default 30). Use list_course_analytics_students for the per-student rows. ${Lr} ${vr}`,Fa,j,async o=>{let{courseId:r,...i}=Mr.parse(o),c=await t.getCourseAnalytics(r,i);return f(c)}),e.tool("list_course_analytics_students",`Per-student progress, exercise submissions, average grade and last seen for a course, ordered by name. Paginated: page (default 1) and limit (default 20, max 50); the result includes pagination. ${vr}`,Ba,j,async o=>{let{courseId:r,...i}=Zr.parse(o),c=await t.listCourseAnalyticsStudents(r,i);return f(c)})}var Br=P.extend(B.shape),Hr=So.safeExtend({cohortId:P.shape.cohortId}),qr=xe,Vr=_t.safeExtend({cohortId:xe.shape.cohortId,goalId:xe.shape.goalId}),$r=xe,Kr=xe,Qr=xe,Yr=P,Ha=Br.shape,qa=Hr.shape,Va=qr.shape,$a=Vr.shape,Ka=$r.shape,Qa=Kr.shape,Ya=Qr.shape,Wa=Yr.shape,Fr=B.shape,Xa=`Create a progress goal for a cohort. ${D}
3
+
4
+ Required fields depend on "type":
5
+ - complete_all: no extra fields beyond courseIds.
6
+ - n_of_m: requiredCount (must be <= courseIds.length).
7
+ - score: scoreThreshold.
8
+ - pass_rate: scoreThreshold and teamPassRateThreshold.
9
+ - readiness: no extra fields; deadlineKind must be "none".
10
+
11
+ Required fields depend on "deadlineKind":
12
+ - absolute: deadlineDate.
13
+ - relative_to_join: relativeDays.
14
+ - recurring: recurringMonths (and deadlineDate for the current cycle).
15
+ - none: no extra fields.
16
+
17
+ courseIds must be non-empty and every course must already be linked to the cohort (see add_cohort_course).`;function Wr(e,t){e.tool("list_cohort_goals",`List the active goals in a cohort, with per-status learner counts. ${se} ${ge}`,Ha,j,async o=>{let{cohortId:r,...i}=Br.parse(o),c=await t.listCohortGoals(r,i);return f(c)}),e.tool("create_cohort_goal",Xa,qa,Q,async o=>{let{cohortId:r,...i}=Hr.parse(o),c=await t.createCohortGoal(r,i);return f(c)}),e.tool("get_cohort_goal",`Get a cohort goal. ${ge}`,Va,j,async o=>{let{cohortId:r,goalId:i}=qr.parse(o),c=await t.getCohortGoal(r,i);return f(c)}),e.tool("update_cohort_goal",`Update a cohort goal. Send only the fields to change; omitted fields keep their values, and the resulting goal must still satisfy the create_cohort_goal rules. ${D}`,$a,Q,async o=>{let{cohortId:r,goalId:i,...c}=Vr.parse(o),b=await t.updateCohortGoal(r,i,_t.parse(c));return f(b)}),e.tool("archive_cohort_goal",`Archive a cohort goal. It stops being evaluated and drops out of list_cohort_goals, but its history is kept. ${D}`,Ka,Q,async o=>{let{cohortId:r,goalId:i}=$r.parse(o),c=await t.archiveCohortGoal(r,i);return f(c)}),e.tool("delete_cohort_goal",`Permanently delete a cohort goal and its learner progress. This is a hard delete; use archive_cohort_goal to keep history. ${D}`,Qa,ze,async o=>{let{cohortId:r,goalId:i}=Kr.parse(o),c=await t.deleteCohortGoal(r,i);return f(c)}),e.tool("evaluate_cohort_goal",`Re-evaluate one goal's learner statuses now instead of waiting for the scheduled run. Returns the number of learner assignments evaluated. Archived goals are not evaluated (409), so their history is kept. ${D}`,Ya,Q,async o=>{let{cohortId:r,goalId:i}=Qr.parse(o),c=await t.evaluateCohortGoal(r,i);return f(c)}),e.tool("evaluate_all_cohort_goals",`Re-evaluate every active goal in a cohort now. Returns the number of learner assignments evaluated. ${D}`,Wa,Q,async o=>{let{cohortId:r}=Yr.parse(o),i=await t.evaluateAllCohortGoals(r);return f(i)}),e.tool("get_org_goals_overview",`Organization-wide goal roll-up: one entry per active goal across all cohorts, with learner counts per status and on-track percentage. ${se} The API key creator must be an org admin or tutor, otherwise 403.`,Fr,j,async o=>{let r=await t.getOrgGoalsOverview(B.parse(o));return f(r)}),e.tool("list_my_cohort_goals",`List the API key creator's own goal assignments across their cohorts in this organization, with status and progress. ${se}`,Fr,j,async o=>{let r=await t.listMyCohortGoals(B.parse(o));return f(r)})}var Xr=vo.extend({cohortId:P.shape.cohortId}),Jr=Lo.extend({cohortId:P.shape.cohortId}),en=ft.safeExtend({cohortId:pe.shape.cohortId,feedId:pe.shape.feedId}),tn=Uo.extend({cohortId:pe.shape.cohortId,feedId:pe.shape.feedId}),on=pe,rn=pe.extend(B.shape),nn=ko.extend({cohortId:pe.shape.cohortId,feedId:pe.shape.feedId}),sn=Do,Ja=Xr.shape,eu=Jr.shape,tu=en.shape,ou=tn.shape,ru=on.shape,nu=rn.shape,su=nn.shape,iu=sn.shape;function an(e,t){e.tool("list_cohort_newsfeed",`List a cohort newsfeed, newest first. Cursor-paginated: pass the returned nextCursor back as cursor for the next page; limit defaults to 10, max 50. ${ge}`,Ja,j,async o=>{let{cohortId:r,...i}=Xr.parse(o),c=await t.listCohortNewsfeed(r,i);return f(c)}),e.tool("create_cohort_newsfeed_post",`Create a post on a cohort newsfeed, authored by the API key creator. ${D} The key creator must also be a member of the cohort to author a post.`,eu,Q,async o=>{let{cohortId:r,...i}=Jr.parse(o),c=await t.createCohortNewsfeedPost(r,i);return f(c)}),e.tool("update_cohort_newsfeed_post",`Update a cohort newsfeed post's content or pinned state. Send only the fields to change. ${D}`,tu,Q,async o=>{let{cohortId:r,feedId:i,...c}=en.parse(o),b=await t.updateCohortNewsfeedPost(r,i,ft.parse(c));return f(b)}),e.tool("update_cohort_newsfeed_reaction","Set the API key creator's own reaction on a cohort newsfeed post: clap, smile, thumbsup, thumbsdown, or null to remove it. Other members' reactions are untouched, and repeating the same value is a no-op. The key creator must be a member of the cohort (being an org admin is not enough), otherwise 403.",ou,{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0},async o=>{let{cohortId:r,feedId:i,...c}=tn.parse(o),b=await t.setCohortNewsfeedReaction(r,i,c);return f(b)}),e.tool("delete_cohort_newsfeed_post",`Permanently delete a cohort newsfeed post and its comments. This is a hard delete and cannot be undone. ${D}`,ru,ze,async o=>{let{cohortId:r,feedId:i}=on.parse(o),c=await t.deleteCohortNewsfeedPost(r,i);return f(c)}),e.tool("list_cohort_newsfeed_comments",`List the comments on a cohort newsfeed post, oldest first. ${se} ${ge}`,nu,j,async o=>{let{cohortId:r,feedId:i,...c}=rn.parse(o),b=await t.listCohortNewsfeedComments(r,i,c);return f(b)}),e.tool("create_cohort_newsfeed_comment","Add a comment to a cohort newsfeed post, authored by the API key creator. The key creator must be a member of the cohort (being an org admin is not enough), otherwise 403.",su,Q,async o=>{let{cohortId:r,feedId:i,...c}=nn.parse(o),b=await t.createCohortNewsfeedComment(r,i,c);return f(b)}),e.tool("delete_cohort_newsfeed_comment","Permanently delete a comment from a cohort newsfeed post. The API key creator must be the comment author, a cohort tutor/admin, or an org admin, otherwise 403.",iu,ze,async o=>{let{cohortId:r,feedId:i,commentId:c}=sn.parse(o),b=await t.deleteCohortNewsfeedComment(r,i,c);return f(b)})}import*as R from"zod";var cn=R.union([R.object({type:R.literal("upload"),assetId:R.string().uuid().describe("An assetId returned by upload_video.")}),R.object({type:R.enum(["youtube","vimeo","generic"]),link:R.url().describe("Public video URL. Embedded rather than downloaded.")})]),ln='Videos for this lesson. Use { "type": "upload", "assetId": "..." } for a file uploaded with upload_video, or { "type": "youtube" | "vimeo" | "generic", "link": "..." } for an external URL.',pn=R.object({courseId:R.string().min(1),title:R.string().min(1).max(255),order:R.number().int().min(1).describe("Position within the section, starting at 1."),sectionId:R.string().uuid().optional(),isUnlocked:R.boolean().optional(),public:R.boolean().optional(),videos:R.array(cn).max(20).optional().describe(ln)}),dn=R.object({courseId:R.string().min(1),lessonId:R.string().uuid(),title:R.string().min(1).max(255).optional(),order:R.number().int().min(1).optional(),isUnlocked:R.boolean().optional(),public:R.boolean().optional(),videos:R.array(cn).max(20).optional().describe(`${ln} Supplying this replaces the lesson's videos entirely.`)}),au=pn.shape,uu=dn.shape;function mn(e,t){e.tool("create_lesson","Create a lesson in a course, optionally with videos. Attaching an uploaded video here is what starts its thumbnail, transcript and adaptive-bitrate encoding.",au,async o=>{let{courseId:r,...i}=pn.parse(o),c=await t.createLesson(r,i);return un(c)}),e.tool("update_lesson","Update a lesson. Omitted fields are left unchanged; supplying videos replaces the lesson's videos entirely.",uu,async o=>{let{courseId:r,lessonId:i,...c}=dn.parse(o),b=await t.updateLesson(r,i,c);return un(b)})}function un(e){return{content:[{type:"text",text:JSON.stringify(e)}]}}import{createReadStream as cu}from"node:fs";import{stat as lu}from"node:fs/promises";import{extname as pu}from"node:path";import*as it from"zod";var gn={".mp4":"video/mp4",".mov":"video/quicktime",".avi":"video/x-msvideo",".mkv":"video/x-matroska"};function du(e){let t=pu(e).toLowerCase(),o=gn[t];if(!o)throw new Error(`Unsupported video extension "${t||"(none)"}". Supported: ${Object.keys(gn).join(", ")}`);return o}function mu(e){return e.split(/[\\/]/).pop()??e}var bn=it.object({filePath:it.string().min(1).describe("Absolute local path to the video file to upload.")}),gu=bn.shape;function hn(e,t){e.tool("upload_video",'Upload a local video file (mp4, mov, avi, mkv) to ClassroomIO. Returns { assetId } \u2014 pass that to create_lesson or update_lesson in videos[] as { "type": "upload", "assetId": "..." } to attach it. Attaching is what starts thumbnailing, transcription and adaptive-bitrate encoding, so an uploaded video should always be attached to a lesson.',gu,async o=>{let{filePath:r}=bn.parse(o),i=du(r),c=mu(r),b=(await lu(r)).size,{assetId:q,uploadUrl:C}=await t.createAssetUpload({kind:"video",fileName:c,mimeType:i,byteSize:b});return await t.putToPresignedUrl(C,cu(r),i,b),bu({assetId:q,fileName:c,mimeType:i,byteSize:b})})}function bu(e){return{content:[{type:"text",text:JSON.stringify(e)}]}}var zn=B,En=Io,In=P,Cn=ht.safeExtend({cohortId:P.shape.cohortId}),An=P,yn=P.extend(B.shape),Tn=wo.safeExtend({cohortId:P.shape.cohortId}),Sn=No.extend({cohortId:Xe.shape.cohortId,memberId:Xe.shape.memberId}),xn=Xe,On=P.extend(B.shape),Rn=Ao.extend({cohortId:P.shape.cohortId}),Pn=Co,wn=xo.extend({cohortId:P.shape.cohortId}),Nn=Oo.extend({cohortId:P.shape.cohortId}),Lt=P,Dn=Ro.extend({cohortId:P.shape.cohortId}),_n=zn.shape,hu=En.shape,_u=In.shape,fu=Cn.shape,zu=An.shape,Eu=yn.shape,Iu=Tn.shape,Cu=Sn.shape,Au=xn.shape,yu=On.shape,Tu=Rn.shape,Su=Pn.shape,xu=wn.shape,Ou=Nn.shape,fn=Lt.shape,Ru=Dn.shape;function vn(e,t){e.tool("list_org_cohorts",`List the cohorts the API key creator can see: all cohorts for an org admin, otherwise only cohorts they belong to. ${se}`,_n,j,async o=>{let r=zn.parse(o),i=await t.listCohorts(r);return f(i)}),e.tool("create_cohort","Create a cohort. The API key creator becomes its tutor.",hu,Q,async o=>{let r=En.parse(o),i=await t.createCohort(r);return f(i)}),e.tool("get_cohort",`Get a cohort by id. ${ge}`,_u,j,async o=>{let{cohortId:r}=In.parse(o),i=await t.getCohort(r);return f(i)}),e.tool("update_cohort",`Update a cohort. Send only the fields to change. ${D}`,fu,Q,async o=>{let{cohortId:r,...i}=Cn.parse(o),c=await t.updateCohort(r,ht.parse(i));return f(c)}),e.tool("delete_cohort",`Permanently delete a cohort with its memberships, newsfeed, and goals. This is a hard delete and cannot be undone; to keep history, use update_cohort with status ARCHIVED. ${D}`,zu,ze,async o=>{let{cohortId:r}=An.parse(o),i=await t.deleteCohort(r);return f(i)}),e.tool("list_cohort_members",`List the members of a cohort. ${se} ${ge}`,Eu,j,async o=>{let{cohortId:r,...i}=yn.parse(o),c=await t.listCohortMembers(r,i);return f(c)}),e.tool("add_cohort_members",`Create cohort memberships directly, each with a role. This sends no invitation email; use invite_students_to_cohort for the dashboard invite flow. A profileId must belong to someone already in the organization; an email is linked to its existing profile if there is one. Returns { added, errors }, where each error has the entry's index, email, profileId, code, and message. Retrying is safe: existing members fail with code MEMBER_ALREADY_IN_COHORT. ${D}`,Iu,Q,async o=>{let{cohortId:r,...i}=Tn.parse(o),c=await t.addCohortMembers(r,i);return f(c)}),e.tool("update_cohort_member",`Change a cohort member's role (tutor or student). ${D}`,Cu,Q,async o=>{let{cohortId:r,memberId:i,...c}=Sn.parse(o),b=await t.updateCohortMember(r,i,c);return f(b)}),e.tool("delete_cohort_member",`Remove a member from a cohort. Hard-deletes the cohort membership only; the person keeps their account, organization membership, and course enrolments. ${D}`,Au,ze,async o=>{let{cohortId:r,memberId:i}=xn.parse(o),c=await t.deleteCohortMember(r,i);return f(c)}),e.tool("list_cohort_courses",`List the courses linked to a cohort. If the API key creator is a student in the cohort, only published courses are returned. ${se} ${ge}`,yu,j,async o=>{let{cohortId:r,...i}=On.parse(o),c=await t.listCohortCourses(r,i);return f(c)}),e.tool("add_cohort_course",`Link a course from the organization to a cohort; existing cohort students are enrolled in it. Fails with 409 if already linked. ${D}`,Tu,Q,async o=>{let{cohortId:r,...i}=Rn.parse(o),c=await t.addCohortCourse(r,i);return f(c)}),e.tool("remove_cohort_course",`Unlink a course from a cohort. The course itself is not deleted. ${D}`,Su,ze,async o=>{let{cohortId:r,courseId:i}=Pn.parse(o),c=await t.removeCohortCourse(r,i);return f(c)}),e.tool("list_my_enrolled_cohorts",`List the cohorts the API key creator is enrolled in within this organization, with their role in each. ${se}`,_n,j,async o=>{let r=await t.listMyEnrolledCohorts(B.parse(o));return f(r)}),e.tool("invite_students_to_cohort",`Invite students to a cohort by email, like the dashboard invite modal. recipientCsv is a CSV of emails (optionally with names). New emails get a 7-day organization invite that joins the cohort on acceptance; existing students are enrolled directly; staff are skipped. With sendEmail true (default), invite and welcome emails are queued. Returns per-row statuses. ${D}`,xu,Q,async o=>{let{cohortId:r,...i}=wn.parse(o),c=await t.inviteStudentsToCohort(r,i);return f(c)}),e.tool("assign_students_to_cohort",`Add existing students from the organization's audience to a cohort. Profiles that are not students in this organization are skipped. With sendEmail true (default), a welcome email is queued for each newly assigned student. ${D}`,Ou,Q,async o=>{let{cohortId:r,...i}=Nn.parse(o),c=await t.assignStudentsToCohort(r,i);return f(c)}),e.tool("get_cohort_invite_link",`Get the cohort's shareable student join link, or null if none has been created. ${D}`,fn,j,async o=>{let{cohortId:r}=Lt.parse(o),i=await t.getCohortInviteLink(r);return f(i)}),e.tool("create_cohort_invite_link",`Get the cohort's shareable student join link, creating it on the first call. ${D}`,fn,{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0},async o=>{let{cohortId:r}=Lt.parse(o),i=await t.createCohortInviteLink(r);return f(i)}),e.tool("set_cohort_invite_link_revoked",`Disable (isRevoked true) or re-enable (isRevoked false) the cohort's join link. ${D}`,Ru,{readOnlyHint:!1,destructiveHint:!0,idempotentHint:!0},async o=>{let{cohortId:r,...i}=Dn.parse(o),c=await t.setCohortInviteLinkRevoked(r,i);return f(c)})}var Ut={readOnlyHint:!0,destructiveHint:!1},Pu={readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0},wu="The API key creator must be a member of the course (including access through a program) or an org admin, otherwise the call fails with 403.",kt="The API key creator must be a course tutor/admin or an org admin, otherwise the call fails with 403.",Ln=V,Un=hr.safeExtend({courseId:V.shape.courseId}),kn=_r.extend({courseId:V.shape.courseId}),jn=fr.extend(zr.shape),Nu=Ln.shape,Du=Un.shape,vu=kn.shape,Lu=jn.shape;function Mn(e,t){e.tool("get_course_certificate",`Read a course's certificate settings and design: template, accent colour, signatories, subtitle, ID format, whether learners can download it, the completion email message, and completion rules (deadline, threshold, required exercise). Returns effective values: defaults are filled in where nothing is stored, matching what the dashboard shows. ${wu}`,Nu,Ut,async o=>{let{courseId:r}=Ln.parse(o),i=await t.getCourseCertificate(r);return jt(i)}),e.tool("update_course_certificate",`Partially update a course's certificate settings and design. Only the fields you send change; omitted fields keep their current values. Send null to clear deadline, requiredExerciseId, exerciseMinScorePercent, or emailMessage. design is replaced as a whole object, so read it with get_course_certificate first and send the full design. Sending design without theme sets theme to design.templateId. deadline must be an ISO 8601 datetime with a timezone, e.g. 2026-12-31T23:59:59Z. Returns the effective settings. Certificates need a paid plan: on the Basic (free) plan this fails with 403 UPGRADE_REQUIRED. ${kt}`,Du,Pu,async o=>{let{courseId:r,...i}=Un.parse(o),c=await t.updateCourseCertificate(r,i);return jt(c)}),e.tool("list_course_certificates",`List the students who earned a course's certificate, when it was earned, and when the certificate email was sent. Compliance cycle and recertification history is not included. Optional search matches name or email. Paginated: page (default 1) and limit (default 20, max 100); the result includes pagination. ${kt}`,vu,Ut,async o=>{let{courseId:r,...i}=kn.parse(o),c=await t.listCourseCertificates(r,i);return jt(c)}),e.tool("download_course_certificate",`Download the certificate a student earned, rendered with the course's current design, as a PDF (format "pdf", default) or PNG image (format "png"). Get memberId from list_course_certificates. ${kt}`,Lu,Ut,async o=>{let{courseId:r,memberId:i,format:c}=jn.parse(o),b=await t.downloadCourseCertificate(r,i,c);return c==="png"?{content:[{type:"image",data:b.base64,mimeType:b.mimeType}]}:{content:[{type:"resource",resource:{uri:`classroomio://courses/${r}/certificates/${i}.pdf`,mimeType:b.mimeType,blob:b.base64}}]}})}function jt(e){return{content:[{type:"text",text:JSON.stringify(e)}]}}import*as T from"zod";var Uu=["#EF4444","#F97316","#F59E0B","#84CC16","#22C55E","#14B8A6","#06B6D4","#3B82F6","#8B5CF6","#EC4899"],Zn=T.enum(Uu),B_=T.object({groupId:T.uuid()}),ku=T.object({name:T.string().min(1).max(80),description:T.string().max(240).optional(),order:T.number().int().min(0).optional()}),H_=ku.partial().refine(e=>Object.keys(e).length>0,{message:"At least one field is required"}),q_=T.object({tagId:T.uuid()}),V_=T.object({name:T.string().min(1).max(80),description:T.string().max(240).optional(),groupId:T.uuid(),color:Zn}),$_=T.object({name:T.string().min(1).max(80).optional(),description:T.string().max(240).optional(),groupId:T.uuid().optional(),color:Zn.optional()}).refine(e=>Object.keys(e).length>0,{message:"At least one field is required"}),K_=T.object({courseId:T.uuid()}),Q_=T.object({tagIds:T.array(T.uuid()).max(100).default([])}),ju=T.enum(["merge","replace"]).default("merge"),Mu=T.string().trim().min(1).max(80),Gn=T.object({draftId:T.string().uuid()}),Mt=T.object({tagNames:T.array(Mu).min(1).max(100),mode:ju,groupName:T.string().trim().min(1).max(80).optional()}),Zt=Mt.extend({courseIds:T.array(T.string().uuid()).min(1).max(100)});import*as M from"zod";var Fn=["video/webm","video/mp4","video/quicktime"],Zu=M.object({exerciseId:M.string().min(1),questionId:M.string().regex(/^\d+$/).transform(Number)}),of=Zu.extend({submissionId:M.string().uuid()}),rf=M.object({fileName:M.string().min(1),mimeType:M.enum(Fn),size:M.number().int().positive()}),nf=M.object({assetId:M.string().uuid(),storageKey:M.string().min(1),fileName:M.string().min(1),mimeType:M.enum(Fn),size:M.number().int().positive(),durationSeconds:M.number().positive().max(122),recordedAt:M.string().datetime(),retakeCount:M.number().int().min(0).optional()});var qn=mr.extend({draftId:ve.shape.draftId}),Vn=Mt.extend({draftId:Gn.shape.draftId}),$n=ir.extend({courseId:de.shape.courseId}),Kn=At.extend({courseId:de.shape.courseId}),Qn=nr.omit({courseId:!0}).extend({courseId:de.shape.courseId}),Yn=ar.extend({courseId:de.shape.courseId}),Wn=sr.extend({courseId:de.shape.courseId,exerciseId:At.shape.exerciseId}),Xn=Ct.extend({courseId:de.shape.courseId}),Jn=zt.extend({courseId:de.shape.courseId}),es=nt.extend({draftId:ve.shape.draftId}).refine(e=>e.type!=="COMPLIANCE"||e.compliance!==void 0,{message:"Compliance settings are required for COMPLIANCE courses",path:["compliance"]}),ts=xt.extend({draftId:ve.shape.draftId}).refine(e=>e.type!=="COMPLIANCE"||e.compliance!==void 0,{message:"Compliance settings are required for COMPLIANCE courses",path:["compliance"]}),Gu=Tt.shape,Fu=St.shape,Bu=Ke.shape,Hu=de.shape,qu=ve.shape,Vu=qn.shape,$u=Vn.shape,Ku=$n.shape,Qu=Kn.shape,Yu=Qn.shape,Wu=Yn.shape,Xu=Wn.shape,Ju=Xn.shape,ec=Jn.shape,tc=es.shape,oc=ts.shape,rc=Zt.shape,Bn=no(),Hn="For draft lesson HTML, put only the lesson body in lessonLanguages[].content. Do not include the lesson title. Do not use h1 or h2 anywhere in lesson HTML. Start headings at h3 because that is the highest heading level allowed in lesson content. To attach a video to a lesson, set lessons[].videos[] with a { type, link } entry (type is one of youtube, vimeo, or generic for a hosted URL). To attach a local video file, call upload_video; attaching the assetId it returns needs create_lesson or update_lesson, which act on a published course, so for a draft publish it first and then attach the video to the resulting lesson.";function os(e,t){e.tool("list_org_courses","List all courses in the authenticated organization. Use this when the user refers to a course by name and you need to discover the available course IDs first.",Bu,async o=>{let r=Ke.parse(o),i=await t.listOrganizationCourses(r);return Y(i)}),e.tool("get_course_structure","Read the current live course structure. Use this before creating a fresh draft for post-publish edits.",Hu,async o=>{let{courseId:r}=de.parse(o),i=await t.getCourseStructure(r);return Y(i)}),e.tool("update_course_landing_page","Update landing-page-facing course fields on a live course, including headline copy, overview, requirements, goals, pricing, reviews, instructor information, and the course image. Use imageUrl to set an explicit cover image, or set generateImage/imageQuery to fetch a random Unsplash-based image.",Ju,async o=>{let{courseId:r,...i}=Xn.parse(o),c=await t.updateCourseLandingPage(r,i);return Y(c)}),e.tool("reorder_course_content","Batch reorder live course sections and lesson or exercise content without creating a draft. Use this for section ordering or moving/reordering lessons and exercises between sections. For items, pass type as LESSON or EXERCISE and use sectionId to move between sections or null for ungrouped content.",ec,async o=>{let{courseId:r,...i}=Jn.parse(o),c=Qo.parse(i),b=await t.reorderCourseContent(r,c);return Y(b)}),e.tool("create_course_draft",`Create a new unpublished course draft from structured course JSON. Use this before the first publish. ${Hn}`,Gu,async o=>{let r=Tt.parse(o),i=await t.createCourseDraft(r);return Y(i)}),e.tool("create_course_draft_from_course","Create a fresh draft from an existing live course. Use this after a course has already been published and the user wants more changes.",Fu,async o=>{let r=St.parse(o),i=await t.createCourseDraftFromCourse(r);return Y(i)}),e.tool("get_course_draft","Fetch an existing draft. Draft responses include status and publishedCourseId so you can decide whether to keep editing the draft or seed a fresh one from the live course.",qu,async o=>{let{draftId:r}=ve.parse(o),i=await t.getCourseDraft(r);return Y(i)}),e.tool("list_course_exercises","List exercises for a live course, optionally filtered by lessonId or sectionId.",Ku,async o=>{let{courseId:r,...i}=$n.parse(o),c=await t.listCourseExercises(r,i);return Y(c)}),e.tool("get_course_exercise","Fetch a single exercise from a live course, including its questions and options.",Qu,async o=>{let{courseId:r,exerciseId:i}=Kn.parse(o),c=await t.getCourseExercise(r,i);return Y(c)}),e.tool("create_course_exercise",`Create a new exercise directly on a live course. Use this for adding exercises after a course has already been published. ${Bn}`,Yu,async o=>{let{courseId:r,...i}=Qn.parse(o),c=await t.createCourseExercise(r,i);return Y(c)}),e.tool("create_course_exercise_from_template","Create a new exercise on a live course from an existing template.",Wu,async o=>{let{courseId:r,...i}=Yn.parse(o),c=await t.createCourseExerciseFromTemplate(r,i);return Y(c)}),e.tool("update_course_exercise",`Update an existing exercise on a live course, including questions and options. ${Bn}`,Xu,async o=>{let{courseId:r,exerciseId:i,...c}=Wn.parse(o),b=await t.updateCourseExercise(r,i,c);return Y(b)}),e.tool("update_course_draft",`Update an unpublished draft. If the draft is already published, do not keep editing it blindly; create a fresh draft from the live course first. ${Hn}`,Vu,async o=>{let{draftId:r,...i}=qn.parse(o),c=await t.updateCourseDraft(r,i);return Y(c)}),e.tool("tag_course_draft","Attach human-readable tags to a draft before publish. The tags are stored on the draft and applied during publish.",$u,async o=>{let{draftId:r,...i}=Vn.parse(o),c=await t.tagCourseDraft(r,i);return Y(c)}),e.tool("publish_course_draft","Publish an unpublished draft as a new live course. The result includes courseId and courseUrl. After publish, future major edits should usually start from a fresh draft created from the live course.",tc,async o=>{let{draftId:r,...i}=es.parse(o),c=await t.publishCourseDraft(r,i);return Y(c)}),e.tool("publish_course_draft_to_existing_course","Apply a fresh draft back onto an existing live course. Use this after reading the live course and creating a new draft from it.",oc,async o=>{let{draftId:r,...i}=ts.parse(o),c=await t.publishCourseDraftToExistingCourse(r,i);return Y(c)}),e.tool("tag_courses","Assign tags directly to one or more live courses by name. Default mode is merge, so existing tags are preserved unless replace is requested.",rc,async o=>{let r=Zt.parse(o),i=await t.tagCourses(r);return Y(i)})}function Y(e){return{content:[{type:"text",text:JSON.stringify(e)}]}}var be="The API key creator must be a course tutor/admin or an org admin, otherwise 403.",at={readOnlyHint:!0,destructiveHint:!1},Gt={readOnlyHint:!1,destructiveHint:!1},Ft={readOnlyHint:!1,destructiveHint:!0},rs=yr.safeExtend({courseId:V.shape.courseId}),ns=Tr.safeExtend({courseId:V.shape.courseId}),ss=ye,is=Pt.safeExtend({courseId:ye.shape.courseId,memberId:ye.shape.memberId}),as=ye,us=ye,cs=Sr.safeExtend({courseId:ye.shape.courseId,memberId:ye.shape.memberId}),ls=Cr.safeExtend({courseId:Rt.shape.courseId}),ps=Ir.safeExtend({courseId:Rt.shape.courseId}),ds=Er,nc=rs.shape,sc=ns.shape,ic=ss.shape,ac=is.shape,uc=as.shape,cc=us.shape,lc=cs.shape,pc=ls.shape,dc=ps.shape,mc=ds.shape;function ms(e,t){e.tool("list_course_members",`List everyone with access to a course (students and tutors), with role and progress. Paginated. ${be}`,nc,at,async o=>{let{courseId:r,...i}=rs.parse(o),c=await t.listCourseMembers(r,i);return he(c)}),e.tool("add_course_member",`Give someone access to a course, by profileId or email. Either must belong to someone already in the organization, otherwise 404. Fails with 409 if they are already a member. To onboard someone new with an invite email, use create_course_invite. ${be}`,sc,Gt,async o=>{let{courseId:r,...i}=ns.parse(o),c=await t.addCourseMember(r,i);return he(c)}),e.tool("get_course_member",`Get a single course member's detail. ${be}`,ic,at,async o=>{let{courseId:r,memberId:i}=ss.parse(o),c=await t.getCourseMember(r,i);return he(c)}),e.tool("update_course_member",`Change a course member's role or email. Send only the fields to change. ${be}`,ac,Gt,async o=>{let{courseId:r,memberId:i,...c}=is.parse(o),b=await t.updateCourseMember(r,i,Pt.parse(c));return he(b)}),e.tool("delete_course_member",`Remove someone's access to a course. This is a hard delete of the course membership; the person keeps their account and organization membership. ${be}`,uc,Ft,async o=>{let{courseId:r,memberId:i}=as.parse(o),c=await t.deleteCourseMember(r,i);return he(c)}),e.tool("reset_course_member_progress",`Clear a student's completion progress while keeping them enrolled. This cannot be undone. Only student members can have their progress reset. ${be}`,cc,Ft,async o=>{let{courseId:r,memberId:i}=us.parse(o),c=await t.resetCourseMemberProgress(r,i);return he(c)}),e.tool("get_course_member_analytics",`Fetch a student's progress and grade analytics for a course. Only student members have analytics. ${be}`,lc,at,async o=>{let{courseId:r,memberId:i,...c}=cs.parse(o),b=await t.getCourseMemberAnalytics(r,i,c);return he(b)}),e.tool("list_course_invites",`List invites for a course, of any status (active, revoked, expired, or used up). Paginated. ${be}`,pc,at,async o=>{let{courseId:r,...i}=ls.parse(o),c=await t.listCourseInvites(r,i);return he(c)}),e.tool("create_course_invite",`Invite one or more people to a course by email or CSV. Unlike add_course_member, this can onboard someone who is not yet an organization member. Requires recipientEmails or recipientCsv. Limited to 60 requests per hour per key creator per course. ${be}`,dc,Gt,async o=>{let{courseId:r,...i}=ps.parse(o),c=await t.createCourseInvite(r,i);return he(c)}),e.tool("revoke_course_invite",`Revoke a pending course invite. The invite link stops working and this cannot be undone. ${be}`,mc,Ft,async o=>{let{courseId:r,inviteId:i}=ds.parse(o),c=await t.revokeCourseInvite(r,i);return he(c)})}function he(e){return{content:[{type:"text",text:JSON.stringify(e)}]}}async function hc(){let e=qt(),t=new Fe(e),o=new gc({name:"classroomio-course-authoring",version:"0.0.1"});os(o,t),vn(o,t),an(o,t),Wr(o,t),hn(o,t),mn(o,t),ms(o,t),Mn(o,t),Gr(o,t);let r=new bc;await o.connect(r),process.stdin.on("close",()=>{o.close()})}hc().catch(e=>{e instanceof Ie&&(console.error(JSON.stringify({error:e.message,status:e.status,code:e.code,field:e.field})),process.exit(1)),console.error(e),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classroomio/mcp",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -29,6 +29,10 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@modelcontextprotocol/sdk": "^1.27.1",
32
+ "@cio/utils": "1.0.0",
33
+ "@cio/question-types": "1.0.0"
34
+ },
35
+ "peerDependencies": {
32
36
  "zod": "^4.1.8"
33
37
  },
34
38
  "devDependencies": {
@@ -36,11 +40,12 @@
36
40
  "esbuild": "^0.25.11",
37
41
  "tsx": "^4.20.3",
38
42
  "typescript": "^5.9.3",
39
- "@cio/tsconfig": "0.0.1",
40
- "@cio/utils": "1.0.0"
43
+ "zod": "^4.1.8",
44
+ "@cio/tsconfig": "0.0.1"
41
45
  },
42
46
  "scripts": {
43
- "build": "tsc --noEmit && rm -rf dist tsconfig.tsbuildinfo && node ./scripts/build.mjs",
47
+ "build": "rimraf dist tsconfig.tsbuildinfo && node ./scripts/build.mjs",
48
+ "typecheck": "tsc --noEmit",
44
49
  "dev": "tsx src/index.ts",
45
50
  "start": "node dist/index.js",
46
51
  "format": "prettier --write \"src/**/*.ts\""