@classroomio/mcp 0.0.8 → 0.0.9
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.
- package/README.md +40 -3
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ The package does not parse PDFs or generate course structures. The agent does th
|
|
|
10
10
|
Teacher / Admin
|
|
11
11
|
|
|
|
12
12
|
v
|
|
13
|
-
Claude Code / Codex / Cursor / other MCP client
|
|
13
|
+
Claude Code / Codex / Cursor / OpenCode / other MCP client
|
|
14
14
|
|
|
|
15
15
|
| 1. Reads prompt, PDF, or existing course goal
|
|
16
16
|
| 2. Produces or edits normalized course JSON
|
|
@@ -43,6 +43,7 @@ Current tools:
|
|
|
43
43
|
|
|
44
44
|
- `list_org_courses`
|
|
45
45
|
- `get_course_structure`
|
|
46
|
+
- `reorder_course_content`
|
|
46
47
|
- `update_course_landing_page`
|
|
47
48
|
- `create_course_draft`
|
|
48
49
|
- `create_course_draft_from_course`
|
|
@@ -122,6 +123,25 @@ codex mcp add classroomio \
|
|
|
122
123
|
-- npx -y @classroomio/mcp
|
|
123
124
|
```
|
|
124
125
|
|
|
126
|
+
### OpenCode
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"$schema": "https://opencode.ai/config.json",
|
|
131
|
+
"mcp": {
|
|
132
|
+
"classroomio": {
|
|
133
|
+
"type": "local",
|
|
134
|
+
"command": ["npx", "-y", "@classroomio/mcp"],
|
|
135
|
+
"enabled": true,
|
|
136
|
+
"environment": {
|
|
137
|
+
"CLASSROOMIO_API_URL": "https://api.classroomio.com",
|
|
138
|
+
"CLASSROOMIO_API_KEY": "<cio_mcp_key>"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
125
145
|
### Cursor
|
|
126
146
|
|
|
127
147
|
```json
|
|
@@ -167,7 +187,9 @@ Drafts support:
|
|
|
167
187
|
Lesson authoring rule:
|
|
168
188
|
|
|
169
189
|
- `lessonLanguages[].content` should contain only the lesson body HTML
|
|
170
|
-
- do not include the lesson title
|
|
190
|
+
- do not include the lesson title
|
|
191
|
+
- do not use `h1` or `h2` in lesson content
|
|
192
|
+
- start headings at `h3`
|
|
171
193
|
- ClassroomIO already renders the lesson title in the course UI
|
|
172
194
|
|
|
173
195
|
## After Publish
|
|
@@ -323,7 +345,22 @@ What this publish does today:
|
|
|
323
345
|
- upserts lesson language content
|
|
324
346
|
- merges draft tags into the existing course
|
|
325
347
|
|
|
326
|
-
### Flow 6:
|
|
348
|
+
### Flow 6: Reorder live course content
|
|
349
|
+
|
|
350
|
+
User says:
|
|
351
|
+
|
|
352
|
+
```text
|
|
353
|
+
Move the quiz before lesson 2 and put the recap lesson into the last section.
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Expected tool sequence:
|
|
357
|
+
|
|
358
|
+
1. Agent calls `reorder_course_content`.
|
|
359
|
+
|
|
360
|
+
Use this direct path when the live course only needs section ordering or lesson or exercise moves between sections.
|
|
361
|
+
It avoids the full draft round-trip for simple structural changes.
|
|
362
|
+
|
|
363
|
+
### Flow 7: Add exercises to a live course
|
|
327
364
|
|
|
328
365
|
User says:
|
|
329
366
|
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{McpServer as ht}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as St}from"@modelcontextprotocol/sdk/server/stdio.js";var b=class extends Error{constructor(n,i,u,l){super(n);this.status=i;this.code=u;this.field=l;this.name="ClassroomIoApiError"}},S=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 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 i=n.toString()?`?${n.toString()}`:"";return this.request(`/organization/courses${i}`,{method:"GET"})}async listCourseExercises(t,n={}){let i=new URLSearchParams;n.lessonId&&i.set("lessonId",n.lessonId),n.sectionId&&i.set("sectionId",n.sectionId);let u=i.toString()?`?${i.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,i){return this.request(`/course/${t}/exercise/${n}`,{method:"PUT",body:i})}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 i=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 i.json().catch(()=>null);if(!i.ok){let l=u;throw new b(l?.error??l?.message??`ClassroomIO request failed with status ${i.status}`,i.status,l?.code,l?.field)}if(!u||typeof u!="object"||!("success"in u)||!u.success)throw new b("ClassroomIO returned an invalid response payload",i.status);return u.data}};import{z as O}from"zod";var be=O.object({CLASSROOMIO_API_URL:O.url().default("https://api.classroomio.com"),CLASSROOMIO_API_KEY:O.string().min(1),CLASSROOMIO_USER_AGENT:O.string().min(1).default("classroomio-mcp/0.0.1")});function F(o=process.env){return be.parse(o)}import*as p from"zod";var Te=["#EF4444","#F97316","#F59E0B","#84CC16","#22C55E","#14B8A6","#06B6D4","#3B82F6","#8B5CF6","#EC4899"],M=p.enum(Te),wt=p.object({groupId:p.uuid()}),he=p.object({name:p.string().min(1).max(80),description:p.string().max(240).optional(),order:p.number().int().min(0).optional()}),Lt=he.partial().refine(o=>Object.keys(o).length>0,{message:"At least one field is required"}),Rt=p.object({tagId:p.uuid()}),Dt=p.object({name:p.string().min(1).max(80),description:p.string().max(240).optional(),groupId:p.uuid(),color:M}),Nt=p.object({name:p.string().min(1).max(80).optional(),description:p.string().max(240).optional(),groupId:p.uuid().optional(),color:M.optional()}).refine(o=>Object.keys(o).length>0,{message:"At least one field is required"}),Zt=p.object({courseId:p.uuid()}),Ut=p.object({tagIds:p.array(p.uuid()).max(100).default([])}),Se=p.enum(["merge","replace"]).default("merge"),Oe=p.string().trim().min(1).max(80),K=p.object({draftId:p.string().uuid()}),L=p.object({tagNames:p.array(Oe).min(1).max(100),mode:Se,groupName:p.string().trim().min(1).max(80).optional()}),R=L.extend({courseIds:p.array(p.string().uuid()).min(1).max(100)});import*as a from"zod";var H=["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 q;(function(o){o.Section="SECTION",o.Lesson="LESSON",o.Exercise="EXERCISE"})(q||(q={}));var Yt=a.object({siteName:a.string().min(1).optional(),customDomain:a.string().min(1).optional(),isCustomDomainVerified:a.boolean().optional()}),Xt=a.object({siteName:a.string().min(1),tags:a.string().optional()}),D=a.object({tags:a.string().optional()}),$t=a.object({siteName:a.string().min(1)}),Vt=a.object({orgId:a.uuid(),planName:a.enum(["EARLY_ADOPTER","ENTERPRISE","BASIC"]),subscriptionId:a.string().min(1),triggeredBy:a.number().int().positive(),payload:a.record(a.string(),a.unknown())}),Jt=a.object({subscriptionId:a.string().min(1),payload:a.record(a.string(),a.unknown())}),Wt=a.object({subscriptionId:a.string().min(1),payload:a.record(a.string(),a.unknown())}),eo=a.object({name:a.string().min(5).refine(o=>!/^[-]|[-]$/.test(o),{message:"Organization name cannot start or end with a hyphen"}),siteName:a.string().min(5).refine(o=>!/^[-]|[-]$/.test(o),{message:"Site name cannot start or end with a hyphen"}).refine(o=>!H.includes(o),{message:"Sitename already exists."})}),to=a.object({name:a.string().min(5).refine(o=>!/^[-]|[-]$/.test(o),{message:"Organization name cannot start or end with a hyphen"}).optional(),avatarUrl:a.url().optional(),theme:a.string().optional(),landingpage:a.record(a.string(),a.unknown()).optional(),siteName:a.string().min(1).optional(),customDomain:a.string().nullable().optional(),isCustomDomainVerified:a.boolean().optional(),customization:a.record(a.string(),a.unknown()).optional(),disableSignup:a.boolean().optional(),disableSignupMessage:a.string().optional(),disableEmailPassword:a.boolean().optional(),disableGoogleAuth:a.boolean().optional(),settings:a.object({signup:a.object({inviteOnly:a.boolean().optional()}).optional()}).optional()}),oo=a.object({emails:a.array(a.string().email()).min(1).max(50),roleId:a.number().int().positive()}),ro=a.object({memberId:a.coerce.number().int().positive()}),no=a.object({userId:a.uuid()});import*as g from"zod";var ao=g.object({orgId:g.uuid(),quizId:g.uuid()}),io=g.object({orgId:g.uuid()}),uo=g.object({title:g.string().min(1),questions:g.array(g.any()).optional(),timelimit:g.string().optional(),theme:g.string().optional()}),po=g.object({title:g.string().min(1).optional(),questions:g.array(g.any()).optional(),timelimit:g.string().optional(),theme:g.string().optional()});import*as A from"zod";var lo=A.object({orgId:A.uuid()});import*as _ from"zod";var go=_.object({token:_.string().min(10).max(512)});import*as c from"zod";var Ae=["OKTA","GOOGLE_WORKSPACE","AUTH0"],fo=c.object({provider:c.enum(Ae),displayName:c.string().min(1,"Display name is required"),issuer:c.url("Must be a valid URL"),domain:c.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:c.string().min(1,"Client ID is required"),clientSecret:c.string().min(1,"Client secret is required"),scopes:c.string().default("openid profile email")}),Io=c.object({displayName:c.string().min(1).optional(),issuer:c.url().optional(),domain:c.string().optional(),clientId:c.string().optional(),clientSecret:c.string().optional(),scopes:c.string().optional(),isActive:c.boolean().optional()}),Co=c.object({forceSso:c.boolean().optional(),autoJoinSsoDomains:c.boolean().optional(),breakGlassEnabled:c.boolean().optional(),defaultRoleId:c.number().int().positive().optional(),roleMapping:c.record(c.string(),c.number()).optional()}),xo=c.object({email:c.email("Valid email is required")}),yo=c.object({orgId:c.uuid()});import{z as E}from"zod";var To=E.object({token:E.string().min(1),redirect:E.string().optional()}),ho=E.object({sub:E.uuid(),email:E.email(),type:E.literal("login-link")});import{z as C}from"zod";var Ao=C.object({token:C.string().min(1),redirect:C.string().optional()}),_o=C.object({sub:C.string(),email:C.email(),name:C.string().optional(),avatar:C.url().optional(),iat:C.number(),exp:C.number()});import{z as x}from"zod";var N=x.enum(["mcp","api","zapier"]),_e=x.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:*"]),Lo=x.object({type:N.optional()}),Ro=x.object({type:N.default("mcp")}),Do=x.object({type:N,label:x.string().min(1).max(120).optional(),expiresAt:x.string().datetime().optional(),scopes:x.array(_e).min(1).optional()}),No=x.object({keyId:x.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"},qo=[m.RADIO,m.CHECKBOX,m.TEXTAREA];var P=[{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}],Pe=Object.freeze(P.reduce((o,t)=>(o[t.key]=t,o),{})),Z=Object.freeze(P.reduce((o,t)=>(o[t.key]=t.id,o),{})),we=Object.freeze(P.reduce((o,t)=>(o[t.typename]=t.key,o),{})),Le=Object.freeze(P.reduce((o,t)=>(o[t.id]=t.key,o),{}));var Re=new Set(["true","1","yes"]),De=new Set(["false","0","no"]);function Ne(o){let t=o.trim().toLowerCase();if(Re.has(t))return!0;if(De.has(t))return!1}var Ze={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}}},Ue={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}},je={type:"TRUE_FALSE",toApiPayload(o,t){return{questionId:t,answer:String(o.value)}},fromApiPayload(o){if(o.answer===void 0)return null;let t=Ne(o.answer);return t===void 0?null:{type:"TRUE_FALSE",value:t}}},ve={type:"TEXTAREA",toApiPayload(o,t){return{questionId:t,answer:o.text}},fromApiPayload(o){return o.answer===void 0?null:{type:"TEXTAREA",text:o.answer}}},Ge={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}}},ke={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}}},Fe={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(i=>String(i).trim()).filter(Boolean);return n.length>0?{type:"FILL_BLANK",values:n}:null}},Me={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}}},Ke={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}},He={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}},qe={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(i=>String(i).trim()).filter(Boolean);return n.length>0?{type:"LINK",urls:n}:null}},Be={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}},nr={[m.RADIO]:Ze,[m.CHECKBOX]:Ue,[m.TRUE_FALSE]:je,[m.TEXTAREA]:ve,[m.SHORT_ANSWER]:Ge,[m.NUMERIC]:ke,[m.FILL_BLANK]:Fe,[m.FILE_UPLOAD]:Me,[m.MATCHING]:Ke,[m.ORDERING]:He,[m.LINK]:qe,[m.HOTSPOT]:Be};var B=["video/mp4","video/quicktime","video/x-msvideo","video/x-matroska"],Q=["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/msword"];var h=Z;var Qe={[h.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}],[h.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}],[h.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}],[h.TEXTAREA]:[]},Ye=s.object({id:s.number().int().optional(),question:s.string().min(1),questionTypeId:s.number().int().min(1).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 Xe(o,t){if(o.deletedAt)return;let n=Qe[o.questionTypeId??-1]??[];for(let i of n){let u=i(o);u&&t.addIssue({code:"custom",message:u,path:["options"]})}}var $e=Ye.superRefine(Xe),Y=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(s.object({question:s.string().min(1),questionTypeId:s.number().int().min(1).optional(),points: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()})).min(2)})).optional()}),X=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($e).optional()}),U=s.object({exerciseId:s.string().min(1)}),$=s.object({lessonId:s.string().optional(),sectionId:s.string().optional()}),hr=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)}),V=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 Pr=e.object({title:e.string().min(1),description:e.string().optional(),slug:e.string().min(1),organizationId:e.string().min(1)}),wr=e.object({courseId:e.string().min(1)}),Ve=e.object({courseId:e.string().min(1)}),Lr=e.object({slug:e.string().optional()}),Rr=e.object({slug:e.string().min(1)}),Dr=e.object({courseId:e.string().min(1)}),Nr=e.object({inviteToken:e.string().min(1).optional()}),Zr=e.object({courseId:e.string().min(1)}),Ur=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()}),jr=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()}))}),vr=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)}),Gr=e.object({fileName:e.string().min(1),fileType:e.enum(B)}),kr=e.object({fileName:e.string().min(1),fileType:e.enum(Q)}),Fr=e.object({keys:e.array(e.string().min(1)).min(1)}),Je=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()}),Mr=e.object({items:e.array(Je).min(1)}),We=e.object({id:e.string().min(1),type:e.enum(["LESSON","EXERCISE"])}),Kr=e.object({sectionId:e.string().min(1).optional(),items:e.array(We).min(1).optional()}).refine(o=>!!o.sectionId!=!!o.items,{message:"Provide either sectionId or items",path:["sectionId"]}),Hr=e.object({title:e.string().min(1),description:e.string().min(1),type:e.enum(["LIVE_CLASS","SELF_PACED"]),organizationId:e.string().min(1)}),J=e.object({show:e.boolean(),description:e.string()}),W=e.object({name:e.string(),role:e.string(),coursesNo:e.number(),description:e.string(),imgUrl:e.string()}),ee=e.object({templateUrl:e.string()}),te=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()}),oe=e.array(e.object({id:e.union([e.literal(1),e.literal(2),e.literal(3),e.literal(4)]),name:e.string()})),w=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:J.optional(),instructor:W.optional(),certificate:ee.optional(),reviews:e.array(te).optional(),lessonTabsOrder:oe.optional(),grading:e.boolean().optional(),lessonDownload:e.boolean().optional(),allowNewStudent:e.boolean(),sectionDisplay:e.record(e.string(),e.boolean()).optional(),isContentGroupingEnabled:e.boolean().optional()}),et=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:J.partial().optional(),instructor:W.partial().optional(),certificate:ee.partial().optional(),reviews:e.array(te).optional(),lessonTabsOrder:oe.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()}),qr=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:w.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()}),Br=e.object({courseId:e.string().min(1)}),re=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:et.optional()}),Qr=e.object({courseId:e.string().min(1)}),Yr=e.object({courseId:e.string().min(1)}),Xr=e.object({profileId:e.string().uuid()}),$r=e.object({courseId:e.string().min(1),userId:e.string().uuid()});var ne=r.enum(["en","hi","fr","pt","de","vi","ru","es","pl","da"]),tt="Lesson body HTML only. Do not include the lesson title or a top-level heading that repeats lessons[].title because the ClassroomIO UI already renders the lesson title separately.",se=r.object({code:r.string().min(1),message:r.string().min(1),severity:r.enum(["info","warning","error"])}),ot=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()}),rt=r.object({title:r.string().min(1),description:r.string().min(1),type:r.enum(["LIVE_CLASS","SELF_PACED"]),locale:ne.default("en"),metadata:w.optional()}),nt=r.object({externalId:r.string().min(1),title:r.string().min(1),order:r.number().int().min(0)}),st=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()}),at=r.object({lessonExternalId:r.string().min(1),locale:ne,content:r.string().min(1).describe(tt)}),ae=r.object({course:rt,tags:r.array(r.string().trim().min(1).max(80)).max(100).default([]),sections:r.array(nt).min(1),lessons:r.array(st).min(1),lessonLanguages:r.array(at).min(1),exercises:r.array(r.record(r.string(),r.unknown())).optional(),sourceReferences:r.array(ot).optional(),warnings:r.array(se).default([])}).superRefine((o,t)=>{let n=new Set;o.tags.forEach((l,I)=>{let k=l.trim().toLowerCase();n.has(k)&&t.addIssue({code:r.ZodIssueCode.custom,path:["tags",I],message:"Draft tags must be unique"}),n.add(k)});let i=new Set;o.sections.forEach((l,I)=>{i.has(l.externalId)&&t.addIssue({code:r.ZodIssueCode.custom,path:["sections",I,"externalId"],message:"Section externalId must be unique"}),i.add(l.externalId)});let u=new Set;o.lessons.forEach((l,I)=>{u.has(l.externalId)&&t.addIssue({code:r.ZodIssueCode.custom,path:["lessons",I,"externalId"],message:"Lesson externalId must be unique"}),u.add(l.externalId),i.has(l.sectionExternalId)||t.addIssue({code:r.ZodIssueCode.custom,path:["lessons",I,"sectionExternalId"],message:"Lesson sectionExternalId must reference an existing section"})}),o.lessonLanguages.forEach((l,I)=>{u.has(l.lessonExternalId)||t.addIssue({code:r.ZodIssueCode.custom,path:["lessonLanguages",I,"lessonExternalId"],message:"Lesson language must reference an existing lesson"})})}),j=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:ae}),y=r.object({courseId:r.string().min(1)}),v=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()}),T=r.object({draftId:r.string().uuid()}),ie=r.object({summary:r.record(r.string(),r.unknown()).optional(),sourceArtifacts:r.array(r.record(r.string(),r.unknown())).optional(),warnings:r.array(se).optional(),draft:ae.optional()}),G=r.object({title:r.string().min(1).optional(),description:r.string().min(1).optional(),type:r.enum(["LIVE_CLASS","SELF_PACED"]).optional(),metadata:w.optional(),bannerImageUrl:r.string().url().optional(),bannerImageQuery:r.string().min(1).max(120).optional(),generateBannerImage:r.boolean().optional()}),ue=G.extend({courseId:r.string().min(1)});import*as z from"zod";var on=z.object({title:z.string().min(1),courseId:z.string().min(1),order:z.number().int().min(0).optional()}),rn=z.object({title:z.string().min(1).optional(),order:z.number().int().min(0).optional()}),nn=z.object({title:z.string().min(1)}),sn=z.object({sectionId:z.string().min(1)}),an=z.object({sections:z.array(z.object({id:z.string().min(1),order:z.number().int().min(0)})).min(1)});import*as d from"zod";var pn=d.object({courseId:d.string().min(1)}),cn=d.object({courseId:d.string().min(1),inviteId:d.string().uuid()}),ln=d.object({courseId:d.string().min(1),inviteId:d.string().uuid()}),dn=d.object({token:d.string().min(1)}),mn=d.object({courseId:d.uuid()}),it=d.enum(["ONE_TIME_24H","MULTI_USE_7D","MULTI_USE_30D","CUSTOM"]),gn=d.object({preset:it.default("MULTI_USE_30D"),expiresAt:d.string().min(1).optional(),maxUses:d.number().int().min(1).max(1e3).optional(),allowedEmails:d.array(d.string().email()).max(100).optional(),allowedDomains:d.array(d.string().min(1)).max(100).optional(),recipientEmails:d.array(d.string().email()).max(500).optional(),recipientCsv:d.string().max(25e3).optional(),sendEmail:d.boolean().default(!1),metadata:d.record(d.string(),d.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 le=ie.extend({draftId:T.shape.draftId}),de=L.extend({draftId:K.shape.draftId}),me=$.extend({courseId:y.shape.courseId}),ge=U.extend({courseId:y.shape.courseId}),ze=Y.omit({courseId:!0}).extend({courseId:y.shape.courseId}),fe=V.extend({courseId:y.shape.courseId}),Ie=X.extend({courseId:y.shape.courseId,exerciseId:U.shape.exerciseId}),Ce=re.extend({courseId:y.shape.courseId}),xe=G.extend({draftId:T.shape.draftId}),ye=ue.extend({draftId:T.shape.draftId}),ut=j.shape,pt=v.shape,ct=D.shape,lt=y.shape,dt=T.shape,mt=le.shape,gt=de.shape,zt=me.shape,ft=ge.shape,It=ze.shape,Ct=fe.shape,xt=Ie.shape,yt=Ce.shape,Et=xe.shape,bt=ye.shape,Tt=R.shape,pe="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.",ce="For draft lesson HTML, put only the lesson body in lessonLanguages[].content. Do not include the lesson title or a top-level heading that repeats lessons[].title because the ClassroomIO UI already renders the lesson title.";function Ee(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.",ct,async n=>{let i=D.parse(n),u=await t.listOrganizationCourses(i);return f(u)}),o.tool("get_course_structure","Read the current live course structure. Use this before creating a fresh draft for post-publish edits.",lt,async n=>{let{courseId:i}=y.parse(n),u=await t.getCourseStructure(i);return f(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.",yt,async n=>{let{courseId:i,...u}=Ce.parse(n),l=await t.updateCourseLandingPage(i,u);return f(l)}),o.tool("create_course_draft",`Create a new unpublished course draft from structured course JSON. Use this before the first publish. ${ce}`,ut,async n=>{let i=j.parse(n),u=await t.createCourseDraft(i);return f(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.",pt,async n=>{let i=v.parse(n),u=await t.createCourseDraftFromCourse(i);return f(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.",dt,async n=>{let{draftId:i}=T.parse(n),u=await t.getCourseDraft(i);return f(u)}),o.tool("list_course_exercises","List exercises for a live course, optionally filtered by lessonId or sectionId.",zt,async n=>{let{courseId:i,...u}=me.parse(n),l=await t.listCourseExercises(i,u);return f(l)}),o.tool("get_course_exercise","Fetch a single exercise from a live course, including its questions and options.",ft,async n=>{let{courseId:i,exerciseId:u}=ge.parse(n),l=await t.getCourseExercise(i,u);return f(l)}),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. ${pe}`,It,async n=>{let{courseId:i,...u}=ze.parse(n),l=await t.createCourseExercise(i,u);return f(l)}),o.tool("create_course_exercise_from_template","Create a new exercise on a live course from an existing template.",Ct,async n=>{let{courseId:i,...u}=fe.parse(n),l=await t.createCourseExerciseFromTemplate(i,u);return f(l)}),o.tool("update_course_exercise",`Update an existing exercise on a live course, including questions and options. ${pe}`,xt,async n=>{let{courseId:i,exerciseId:u,...l}=Ie.parse(n),I=await t.updateCourseExercise(i,u,l);return f(I)}),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. ${ce}`,mt,async n=>{let{draftId:i,...u}=le.parse(n),l=await t.updateCourseDraft(i,u);return f(l)}),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.",gt,async n=>{let{draftId:i,...u}=de.parse(n),l=await t.tagCourseDraft(i,u);return f(l)}),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.",Et,async n=>{let{draftId:i,...u}=xe.parse(n),l=await t.publishCourseDraft(i,u);return f(l)}),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.",bt,async n=>{let{draftId:i,...u}=ye.parse(n),l=await t.publishCourseDraftToExistingCourse(i,u);return f(l)}),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.",Tt,async n=>{let i=R.parse(n),u=await t.tagCourses(i);return f(u)})}function f(o){return{content:[{type:"text",text:JSON.stringify(o)}]}}async function Ot(){let o=F(),t=new S(o),n=new ht({name:"classroomio-course-authoring",version:"0.0.1"});Ee(n,t);let i=new St;await n.connect(i),process.stdin.on("close",()=>{n.close()})}Ot().catch(o=>{o instanceof b&&(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{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)});
|