@memizy/oqse 0.1.3 → 0.1.4

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/dist/index.cjs CHANGED
@@ -1,2 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`zod`);function t(e){return e.type===`note`}function n(e){return e.type===`flashcard`}function r(e){return e.type===`true-false`}function i(e){return e.type===`mcq-single`}function a(e){return e.type===`mcq-multi`}function o(e){return e.type===`short-answer`}function ee(e){return e.type===`fill-in-blanks`}function te(e){return e.type===`fill-in-select`}function ne(e){return e.type===`match-pairs`}function re(e){return e.type===`match-complex`}function ie(e){return e.type===`sort-items`}function ae(e){return e.type===`slider`}function oe(e){return e.type===`pin-on-image`}function se(e){return e.type===`categorize`}function ce(e){return e.type===`timeline`}function le(e){return e.type===`matrix`}function ue(e){return e.type===`math-input`}function de(e){return e.type===`diagram-label`}function fe(e){return e.type===`open-ended`}function pe(e){return e.type===`numeric-input`}function me(e){return e.type===`pin-on-model`}function he(e){return e.type===`chess-puzzle`}function s(e){return[`note`,`flashcard`,`mcq-single`,`short-answer`].includes(e.type)}function ge(e){return!s(e)}var c=[`render`,`edit`,`validate`,`import`,`export`],l=[`markdown`,`math`,`rtl`,`html`,`syntax-highlighting`,`mermaid`,`smiles`,`abc-notation`,`text-to-speech`,`voice-input`,`handwriting-recognition`],u=[`hints`,`explanation`,`incorrectFeedback`,`sources`,`relatedItems`,`dependencyItems`,`timeLimit`,`lang`,`topic`,`pedagogy`],d=[`description`,`thumbnail`,`subject`,`language`,`author`,`contributors`,`license`,`ageRestriction`,`tags`,`tagDefinitions`,`sourceMaterials`,`estimatedTime`,`prerequisites`,`translations`,`relatedSets`];function f(e){return/^\d+\.\d+$/.test(e)}function _e(e){return/^\d+\.\d+\.\d+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/.test(e)}function p(e,t){let[n=0,r=0]=e.split(`.`).map(Number),[i=0,a=0]=t.split(`.`).map(Number);return n===i?r-a:n-i}function ve(e){if(typeof e!=`object`||!e)return!1;let t=e,n=t.author;return typeof t.version==`string`&&typeof t.id==`string`&&typeof t.appName==`string`&&t.appName!==``&&(n===void 0||typeof n==`object`&&!!n)&&typeof t.capabilities==`object`&&t.capabilities!==null&&Array.isArray(t.capabilities.actions)}function ye(e,t){return!(!f(e)||t.minOqseVersion&&f(t.minOqseVersion)&&p(e,t.minOqseVersion)<0||t.maxOqseVersion&&f(t.maxOqseVersion)&&p(e,t.maxOqseVersion)>0)}var be=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;function xe(e){return typeof e==`string`&&be.test(e)}var m=[];for(let e=0;e<256;++e)m.push((e+256).toString(16).slice(1));function Se(e,t=0){return(m[e[t+0]]+m[e[t+1]]+m[e[t+2]]+m[e[t+3]]+`-`+m[e[t+4]]+m[e[t+5]]+`-`+m[e[t+6]]+m[e[t+7]]+`-`+m[e[t+8]]+m[e[t+9]]+`-`+m[e[t+10]]+m[e[t+11]]+m[e[t+12]]+m[e[t+13]]+m[e[t+14]]+m[e[t+15]]).toLowerCase()}var h,Ce=new Uint8Array(16);function we(){if(!h){if(typeof crypto>`u`||!crypto.getRandomValues)throw Error(`crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported`);h=crypto.getRandomValues.bind(crypto)}return h(Ce)}var g={};function Te(e,t,n){let r;if(e)r=De(e.random??e.rng?.()??we(),e.msecs,e.seq,t,n);else{let e=Date.now(),i=we();Ee(g,e,i),r=De(i,g.msecs,g.seq,t,n)}return t??Se(r)}function Ee(e,t,n){return e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=n[6]<<23|n[7]<<16|n[8]<<8|n[9],e.msecs=t):(e.seq=e.seq+1|0,e.seq===0&&e.msecs++),e}function De(e,t,n,r,i=0){if(e.length<16)throw Error(`Random bytes length must be >= 16`);if(!r)r=new Uint8Array(16),i=0;else if(i<0||i+16>r.length)throw RangeError(`UUID byte range ${i}:${i+15} is out of buffer bounds`);return t??=Date.now(),n??=e[6]*127<<24|e[7]<<16|e[8]<<8|e[9],r[i++]=t/1099511627776&255,r[i++]=t/4294967296&255,r[i++]=t/16777216&255,r[i++]=t/65536&255,r[i++]=t/256&255,r[i++]=t&255,r[i++]=112|n>>>28&15,r[i++]=n>>>20&255,r[i++]=128|n>>>14&63,r[i++]=n>>>6&255,r[i++]=n<<2&255|e[10]&3,r[i++]=e[11],r[i++]=e[12],r[i++]=e[13],r[i++]=e[14],r[i++]=e[15],r}function Oe(e){return xe(e)}function ke(){return Te()}function _(e,t=10,n=0){if(n>t)throw Error(`OQSE Security Error: Maximum nesting depth exceeded limit of ${t} levels.`);if(typeof e==`object`&&e){let r=Array.isArray(e)?e:Object.values(e);for(let e of r)_(e,t,n+1)}}var v=e.z.string().uuid({message:`Invalid UUID format`}),y=e.z.string().min(2,`Language code must have at least 2 characters`).regex(/^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2})?$/,`Invalid BCP 47 format (e.g. "cs", "en-US")`),b=e.z.string().min(1,`License identifier must not be empty`),x=e.z.string().regex(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?(Z|[+-]\d{2}:\d{2})?)?$/,`Invalid ISO 8601 format (e.g. "2025-11-21T14:30:00Z")`),S=e.z.string().url({message:`Must be a valid absolute URL`}),C=e.z.string().regex(/^[a-z0-9_-]+$/,`Asset key must contain only lowercase letters, numbers, hyphens and underscores`),w=e.z.string().min(1,`Text must not be empty`),T=e.z.string().min(1,`Content must not be empty`),E=e.z.string().max(1e4,`Question must not be longer than 10000 characters`).optional(),D=e.z.string().regex(/^[a-zA-Z0-9_-]{1,64}$/,`Token must be alphanumeric, max 64 chars`),O=e.z.object({lang:y,value:e.z.string().min(1,`Subtitle URI must not be empty`).regex(/\.(vtt|srt)(\?.*)?$/i,`Subtitle URI must end with .vtt or .srt`),label:e.z.string().optional(),kind:e.z.enum([`captions`,`subtitles`,`descriptions`]).optional()}),k=e.z.object({type:e.z.enum([`image`,`audio`,`video`,`model`]),value:e.z.string().min(1,`Media URI must not be empty`),mimeType:e.z.string().optional(),altText:e.z.string().optional(),transcript:T.optional(),caption:T.optional(),width:e.z.number().int().positive().optional(),height:e.z.number().int().positive().optional(),start:e.z.number().nonnegative().optional(),end:e.z.number().positive().optional(),loop:e.z.boolean().optional(),subtitles:e.z.array(O).optional(),license:b.optional(),attribution:e.z.string().optional(),checksums:e.z.record(e.z.string(),e.z.string()).optional()}).refine(e=>e.start!==void 0&&e.end!==void 0?e.start<e.end:!0,{message:`Start time must be less than end time`,path:[`end`]}).refine(e=>!(e.type===`image`&&!e.altText),{message:`Images must have alternative text (altText) defined for accessibility`,path:[`altText`]}),A=e.z.record(C,k),j=e.z.object({name:w,role:e.z.string().optional(),email:e.z.string().email(`Invalid email format`).optional(),url:S.optional()}),M=e.z.enum([`url`,`doi`,`isbn`,`pdf`,`textbook`,`video`,`audio`,`image`,`model`,`other`]),N=e.z.object({id:w,type:M,value:w,title:w,description:e.z.string().optional(),authors:e.z.array(w).optional(),publishedDate:x.optional(),retrievedAt:x.optional(),license:b.optional()}).refine(e=>{if([`url`,`pdf`,`video`,`audio`,`image`].includes(e.type))try{return new URL(e.value),!0}catch{return!1}return!0},{message:`For url, pdf, video, audio and image types, value must be a valid URL`,path:[`value`]}),P=e.z.object({id:w,location:e.z.string().optional(),quote:T.optional()}),Ae=e.z.object({wikidataId:e.z.string().regex(/^Q\d+$/,`Wikidata ID must have format Q followed by number`).optional(),description:e.z.string().optional()}),je=e.z.record(e.z.string(),Ae),F=e.z.object({features:e.z.array(e.z.string().refine(e=>l.includes(e)||e.startsWith(`x-`),{message:`Feature must be an official key or have prefix "x-"`})).optional(),latexPackages:e.z.array(e.z.string().min(1,`Package name must not be empty`)).optional(),itemProperties:e.z.array(e.z.string().refine(e=>u.includes(e)||e.startsWith(`x-`),{message:`Item property must be an official key or have prefix "x-"`})).optional(),metaProperties:e.z.array(e.z.string().refine(e=>d.includes(e)||e.startsWith(`x-`),{message:`Meta property must be an official key or have prefix "x-"`})).optional()}),Me=e.z.object({lang:y,id:v,title:w,downloadUrl:S.optional()}),I=e.z.object({id:v,title:w,downloadUrl:S.optional()}),Ne=e.z.enum([`remember`,`understand`,`apply`,`analyze`,`evaluate`,`create`]),Pe=e.z.enum([`low`,`medium`,`high`]),Fe=e.z.object({bloomLevel:Ne.optional(),irtDifficulty:e.z.number().optional(),irtDiscrimination:e.z.number().optional(),irtGuessing:e.z.number().min(0).max(1,`IRT guessing must be between 0 and 1`).optional(),avgTime:e.z.number().positive().optional(),cognitiveLoad:Pe.optional(),partialCredit:e.z.boolean().optional(),penaltyPerWrong:e.z.number().min(0).max(1,`Penalty must be between 0 and 1`).optional()}),L=e.z.object({id:v,language:y,title:w.max(500,`Title must not be longer than 500 characters`),description:T.max(5e3,`Description must not be longer than 5000 characters`).optional(),thumbnail:C.optional(),assets:A.optional(),ageMin:e.z.number().int().nonnegative().optional(),ageMax:e.z.number().int().nonnegative().optional(),subject:e.z.string().optional(),createdAt:x,updatedAt:x,author:j.optional(),contributors:e.z.array(j).optional(),license:b.optional(),licenseUrl:S.optional(),requirements:F.optional(),tags:e.z.array(w).optional(),tagDefinitions:je.optional(),translations:e.z.array(Me).optional(),sourceMaterials:e.z.array(N).optional(),estimatedTime:e.z.number().positive().optional(),prerequisites:e.z.array(I).optional(),relatedSets:e.z.array(I).optional(),customData:e.z.record(e.z.string(),e.z.unknown()).optional(),appSpecific:e.z.record(e.z.string(),e.z.unknown()).optional()}).refine(e=>e.ageMin!==void 0&&e.ageMax!==void 0?e.ageMin<=e.ageMax:!0,{message:`Minimum age (ageMin) must be less than or equal to maximum age (ageMax)`,path:[`ageMax`]}).refine(e=>new Date(e.createdAt)<=new Date(e.updatedAt),{message:`Creation date (createdAt) must be before or equal to update date (updatedAt)`,path:[`updatedAt`]}),R=e.z.object({id:v,type:e.z.string(),assets:A.optional(),lang:y.optional(),tags:e.z.array(w).optional(),topic:w.optional(),difficulty:e.z.number().int().min(1,`Difficulty must be at least 1`).max(5,`Difficulty must be at most 5`).optional(),timeLimit:e.z.number().positive(`Time limit must be a positive number`).optional(),hints:e.z.array(T.max(2e3,`Hint must not be longer than 2000 characters`)).max(20,`Maximum 20 hints per item`).optional(),explanation:T.max(1e4,`Explanation must not be longer than 10000 characters`).optional(),incorrectFeedback:T.optional(),sources:e.z.array(P).optional(),relatedItems:e.z.array(v).optional(),dependencyItems:e.z.array(v).optional(),pedagogy:Fe.optional(),customData:e.z.record(e.z.string(),e.z.unknown()).optional(),appSpecific:e.z.record(e.z.string(),e.z.unknown()).optional()}),Ie=e.z.object({options:e.z.array(T).min(1,`Must have at least 1 option`),correctIndex:e.z.number().int().nonnegative()}).refine(e=>e.correctIndex<e.options.length,{message:`Correct answer index references non-existent option`,path:[`correctIndex`]}),z=e.z.object({type:e.z.literal(`rect`),label:e.z.string().optional(),x:e.z.number().min(0).max(100,`X must be in range 0-100%`),y:e.z.number().min(0).max(100,`Y must be in range 0-100%`),width:e.z.number().min(0).max(100,`Width must be in range 0-100%`),height:e.z.number().min(0).max(100,`Height must be in range 0-100%`)}),B=e.z.object({type:e.z.literal(`circle`),label:e.z.string().optional(),x:e.z.number().min(0).max(100,`X must be in range 0-100%`),y:e.z.number().min(0).max(100,`Y must be in range 0-100%`),radius:e.z.number().min(0).max(100,`Radius must be in range 0-100%`)}),V=e.z.object({type:e.z.literal(`polygon`),label:e.z.string().optional(),points:e.z.array(e.z.object({x:e.z.number().min(0).max(100),y:e.z.number().min(0).max(100)})).min(3,`Polygon must have at least 3 points`)}),H=e.z.object({type:e.z.literal(`mesh`),label:e.z.string().optional(),targetName:w}),Le=e.z.discriminatedUnion(`type`,[z,B,V,H]),Re=e.z.discriminatedUnion(`type`,[z,B,V]),U=e.z.object({x:e.z.number(),y:e.z.number(),z:e.z.number()}),ze=e.z.object({position:U.optional(),target:U.optional()}),Be=e.z.object({id:w,text:T,correctCategoryIndex:e.z.number().int().nonnegative()}),Ve=e.z.enum([`year`,`month`,`day`,`datetime`]),He=e.z.object({id:w,text:T,date:x,precision:Ve.optional()}),Ue=e.z.union([z.extend({correctLabelIndex:e.z.number().int().nonnegative()}),B.extend({correctLabelIndex:e.z.number().int().nonnegative()}),V.extend({correctLabelIndex:e.z.number().int().nonnegative()})]),W=e.z.object({label:w,percentage:e.z.number().min(0,`Percentage must be non-negative`).max(100,`Percentage must not exceed 100`),description:e.z.string().optional()}),We=e.z.object({criteria:e.z.array(W).min(1,`Rubric must have at least 1 criterion`)}).refine(e=>e.criteria.reduce((e,t)=>e+t.percentage,0)>0,{message:`Sum of percentages of all criteria must be greater than 0`,path:[`criteria`]}),Ge=e.z.object({min:e.z.number(),max:e.z.number()}).refine(e=>e.min<=e.max,{message:`Minimum value must be less than or equal to maximum value`,path:[`max`]}),Ke=R.extend({type:e.z.literal(`note`),title:e.z.string().optional(),content:T.max(1e4,`Content must not be longer than 10000 characters`),hiddenContent:T.max(1e4,`Content must not be longer than 10000 characters`).optional()}),qe=R.extend({type:e.z.literal(`flashcard`),front:T.max(1e4,`Front side must not be longer than 10000 characters`),back:T.max(1e4,`Back side must not be longer than 10000 characters`)}),Je=R.extend({type:e.z.literal(`true-false`),question:T.max(1e4,`Question must not be longer than 10000 characters`),answer:e.z.boolean()}),Ye=R.extend({type:e.z.literal(`mcq-single`),question:T.max(1e4,`Question must not be longer than 10000 characters`),options:e.z.array(T.max(2e3,`Option must not be longer than 2000 characters`)).min(2,`Question must have at least 2 options`).max(100,`Maximum 100 options`),correctIndex:e.z.number().int().nonnegative(),shuffleOptions:e.z.boolean().optional(),optionExplanations:e.z.array(e.z.union([T,e.z.null()])).optional()}).refine(e=>e.correctIndex<e.options.length,{message:`Correct answer index references non-existent option`,path:[`correctIndex`]}).refine(e=>e.optionExplanations?e.optionExplanations.length===e.options.length:!0,{message:`Number of option explanations must match number of options`,path:[`optionExplanations`]}).refine(e=>new Set(e.options.map(e=>e.toLowerCase())).size===e.options.length,{message:`Options must not contain duplicates (case-insensitive)`,path:[`options`]}),Xe=R.extend({type:e.z.literal(`mcq-multi`),question:T.max(1e4,`Question must not be longer than 10000 characters`),options:e.z.array(T.max(2e3,`Option must not be longer than 2000 characters`)).min(2,`Question must have at least 2 options`).max(100,`Maximum 100 options`),correctIndices:e.z.array(e.z.number().int().nonnegative()).min(1,`Must have at least 1 correct answer`),minSelections:e.z.number().int().positive().optional(),maxSelections:e.z.number().int().positive().optional(),shuffleOptions:e.z.boolean().optional(),optionExplanations:e.z.array(e.z.union([T,e.z.null()])).optional()}).refine(e=>e.correctIndices.every(t=>t<e.options.length),{message:`Some of correct answer indices reference non-existent option`,path:[`correctIndices`]}).refine(e=>new Set(e.correctIndices).size===e.correctIndices.length,{message:`Correct answer indices contain duplicates`,path:[`correctIndices`]}).refine(e=>e.minSelections&&e.maxSelections?e.minSelections<=e.maxSelections:!0,{message:`Minimum number of selections must be less than or equal to maximum`,path:[`maxSelections`]}).refine(e=>e.maxSelections?e.maxSelections<=e.options.length:!0,{message:`Maximum number of selections must not exceed number of options`,path:[`maxSelections`]}).refine(e=>e.minSelections?e.minSelections<=e.options.length:!0,{message:`minSelections cannot be greater than the number of options`,path:[`minSelections`]}).refine(e=>e.optionExplanations?e.optionExplanations.length===e.options.length:!0,{message:`Number of option explanations must match number of options`,path:[`optionExplanations`]}).refine(e=>new Set(e.options.map(e=>e.toLowerCase())).size===e.options.length,{message:`Options must not contain duplicates (case-insensitive)`,path:[`options`]}),Ze=R.extend({type:e.z.literal(`short-answer`),question:T.max(1e4,`Question must not be longer than 10000 characters`),answers:e.z.array(w).min(1,`Must have at least 1 correct answer`),caseSensitive:e.z.boolean().optional(),trimWhitespace:e.z.boolean().optional(),acceptPartial:e.z.boolean().optional(),ignoreDiacritics:e.z.boolean().optional()}),Qe=R.extend({type:e.z.literal(`fill-in-blanks`),question:E,text:T.max(1e4,`Text must not be longer than 10000 characters`),blanks:e.z.record(D,e.z.array(w).min(1,`Each blank must have at least 1 correct answer`)),caseSensitive:e.z.boolean().optional(),trimWhitespace:e.z.boolean().optional()}).refine(e=>Object.keys(e.blanks).length>0,{message:`Text must contain at least 1 blank to fill`,path:[`blanks`]}).refine(e=>{let t=/<blank:([a-zA-Z0-9_-]{1,64})\s*\/>/g,n=new Set,r;for(;(r=t.exec(e.text))!==null;)r[1]&&n.add(r[1]);let i=new Set(Object.keys(e.blanks));for(let e of n)if(!i.has(e))return!1;for(let e of i)if(!n.has(e))return!1;return!0},{message:`All tokens in text must have definition in blanks and all definitions must be used in text`,path:[`blanks`]}),$e=R.extend({type:e.z.literal(`fill-in-select`),question:E,text:T.max(1e4,`Text must not be longer than 10000 characters`),blanks:e.z.record(D,Ie)}).refine(e=>Object.keys(e.blanks).length>0,{message:`Text must contain at least 1 blank to select`,path:[`blanks`]}).refine(e=>{let t=/<blank:([a-zA-Z0-9_-]{1,64})\s*\/>/g,n=new Set,r;for(;(r=t.exec(e.text))!==null;)r[1]&&n.add(r[1]);let i=new Set(Object.keys(e.blanks));for(let e of n)if(!i.has(e))return!1;for(let e of i)if(!n.has(e))return!1;return!0},{message:`All tokens in text must have definition in blanks and all definitions must be used in text`,path:[`blanks`]}),et=R.extend({type:e.z.literal(`match-pairs`),question:E,prompts:e.z.array(T).min(2,`Must have at least 2 pairs to match`).max(100,`Maximum 100 pairs`),matches:e.z.array(T).min(2,`Must have at least 2 pairs to match`).max(100,`Maximum 100 pairs`)}).refine(e=>e.prompts.length===e.matches.length,{message:`Number of prompts must match number of matches`,path:[`matches`]}),tt=R.extend({type:e.z.literal(`match-complex`),question:E,leftItems:e.z.array(T).min(1,`Must have at least 1 item on left`),rightItems:e.z.array(T).min(1,`Must have at least 1 item on right`),connections:e.z.array(e.z.tuple([e.z.number().int().nonnegative(),e.z.number().int().nonnegative()])).min(1,`Must have at least 1 connection`),minCorrect:e.z.number().int().positive().optional()}).refine(e=>e.connections.every(([t,n])=>t<e.leftItems.length&&n<e.rightItems.length),{message:`Some connection references non-existent item`,path:[`connections`]}).refine(e=>new Set(e.connections.map(e=>`${e[0]}-${e[1]}`)).size===e.connections.length,{message:`Connections contain duplicates`,path:[`connections`]}).refine(e=>e.minCorrect?e.minCorrect<=e.connections.length:!0,{message:`Minimum correct answers must not exceed total number of connections`,path:[`minCorrect`]}),nt=R.extend({type:e.z.literal(`sort-items`),question:T.max(1e4,`Question must not be longer than 10000 characters`),items:e.z.array(T).min(2,`Must have at least 2 items to sort`)}),rt=R.extend({type:e.z.literal(`slider`),question:T.max(1e4,`Question must not be longer than 10000 characters`),min:e.z.number(),max:e.z.number(),step:e.z.number().positive(`Step must be a positive number`),correctAnswer:e.z.number(),tolerance:e.z.number().nonnegative(`Tolerance must be non-negative`),unit:e.z.string().optional()}).refine(e=>e.min<e.max,{message:`Minimum value must be less than maximum value`,path:[`max`]}).refine(e=>e.correctAnswer>=e.min&&e.correctAnswer<=e.max,{message:`Correct answer must be in range min-max`,path:[`correctAnswer`]}).refine(e=>{let t=(e.correctAnswer-e.min)/e.step;return Math.abs(t-Math.round(t))<1e-4},{message:`Correct answer must be reachable by defined step`,path:[`correctAnswer`]}).refine(e=>e.tolerance<=(e.max-e.min)/2,{message:`Tolerance must not be greater than half of value range`,path:[`tolerance`]}),it=R.extend({type:e.z.literal(`pin-on-image`),question:T.max(1e4,`Question must not be longer than 10000 characters`),targetAsset:C,hotspots:e.z.array(Re).min(1,`Must have at least 1 hotspot`),multipleCorrect:e.z.boolean().optional(),minCorrect:e.z.number().int().positive().optional()}).refine(e=>e.minCorrect?e.minCorrect<=e.hotspots.length:!0,{message:`Minimum correct answers must not exceed number of hotspots`,path:[`minCorrect`]}),at=R.extend({type:e.z.literal(`categorize`),question:T.max(1e4,`Question must not be longer than 10000 characters`),categories:e.z.array(w).min(2,`Must have at least 2 categories`),items:e.z.array(Be).min(1,`Must have at least 1 item to categorize`)}).refine(e=>new Set(e.categories.map(e=>e.toLowerCase())).size===e.categories.length,{message:`Categories must not contain duplicates (case-insensitive)`,path:[`categories`]}).refine(e=>e.items.every(t=>t.correctCategoryIndex<e.categories.length),{message:`Some item references non-existent category`,path:[`items`]}),ot=R.extend({type:e.z.literal(`timeline`),question:T.max(1e4,`Question must not be longer than 10000 characters`),events:e.z.array(He).min(2,`Must have at least 2 events`),randomize:e.z.boolean().optional()}),st=R.extend({type:e.z.literal(`matrix`),question:T.max(1e4,`Question must not be longer than 10000 characters`),rows:e.z.array(w).min(1,`Must have at least 1 row`),columns:e.z.array(w).min(1,`Must have at least 1 column`),correctCells:e.z.array(e.z.tuple([e.z.number().int().nonnegative(),e.z.number().int().nonnegative()])).min(1,`Must have at least 1 correct cell`),multiplePerRow:e.z.boolean().optional()}).refine(e=>e.correctCells.every(([t,n])=>t<e.rows.length&&n<e.columns.length),{message:`Some cell coordinates reference non-existent row or column`,path:[`correctCells`]}).refine(e=>new Set(e.correctCells.map(e=>`${e[0]}-${e[1]}`)).size===e.correctCells.length,{message:`Correct cells contain duplicates`,path:[`correctCells`]}).refine(e=>{if(!e.multiplePerRow){let t=new Map;for(let[n]of e.correctCells)t.set(n,(t.get(n)||0)+1);return Array.from(t.values()).every(e=>e<=1)}return!0},{message:`If multiplePerRow is false, each row may have maximum 1 correct cell`,path:[`correctCells`]}),ct=R.extend({type:e.z.literal(`math-input`),question:T.max(1e4,`Question must not be longer than 10000 characters`),correctAnswer:w,alternativeAnswers:e.z.array(w).optional(),tolerance:e.z.number().nonnegative().optional()}),lt=R.extend({type:e.z.literal(`diagram-label`),question:T.max(1e4,`Question must not be longer than 10000 characters`),targetAsset:C,labels:e.z.array(T).min(1,`Must have at least 1 label`),caseSensitive:e.z.boolean().optional(),requireTyping:e.z.boolean().optional(),zones:e.z.array(Ue).min(1,`Must have at least 1 zone`)}).refine(e=>e.zones.every(t=>t.correctLabelIndex<e.labels.length),{message:`Some zone references non-existent label`,path:[`zones`]}),ut=R.extend({type:e.z.literal(`open-ended`),question:T.max(1e4,`Question must not be longer than 10000 characters`),minWords:e.z.number().int().positive().optional(),maxWords:e.z.number().int().positive().optional(),sampleAnswer:T.optional(),rubric:We.optional()}).refine(e=>e.minWords&&e.maxWords?e.minWords<=e.maxWords:!0,{message:`Minimum word count must be less than or equal to maximum`,path:[`maxWords`]}),dt=R.extend({type:e.z.literal(`numeric-input`),question:T.max(1e4,`Question must not be longer than 10000 characters`),value:e.z.number(),tolerance:e.z.number().nonnegative().optional(),range:Ge.optional(),unit:e.z.string().optional()}),ft=R.extend({type:e.z.literal(`pin-on-model`),question:T.max(1e4,`Question must not be longer than 10000 characters`),targetAsset:C,hotspots:e.z.array(H).min(1,`Must have at least 1 hotspot`),multipleCorrect:e.z.boolean().optional(),minCorrect:e.z.number().int().positive().optional(),camera:ze.optional()}).refine(e=>e.minCorrect?e.minCorrect<=e.hotspots.length:!0,{message:`Minimum correct answers must not exceed number of hotspots`,path:[`minCorrect`]}),pt=R.extend({type:e.z.literal(`chess-puzzle`),question:T.max(1e4,`Question must not be longer than 10000 characters`),fen:w,answers:e.z.array(e.z.array(w).min(1,`Move sequence must not be empty`)).min(1,`Must have at least 1 correct move sequence`),elo:e.z.number().int().nonnegative(`ELO must be non-negative integer`).optional()}),G=e.z.discriminatedUnion(`type`,[Ke,qe,Je,Ye,Xe,Ze,Qe,$e,et,tt,nt,rt,it,at,ot,st,ct,lt,ut,dt,ft,pt]),K=e.z.object({$schema:e.z.string().url().optional(),version:e.z.string().regex(/^\d+\.\d+$/,`Version must be in MAJOR.MINOR format (e.g. "0.1")`),meta:L,items:e.z.array(G).max(1e4,`Maximum 10000 items per set`)}).refine(e=>{let t=new Set(e.items.map(e=>e.id));for(let n of e.items){if(n.relatedItems){for(let e of n.relatedItems)if(!t.has(e)||n.id===e)return!1}if(n.dependencyItems){for(let e of n.dependencyItems)if(!t.has(e)||n.id===e)return!1}}return!0},{message:`Some item references non-existent relatedItems, dependencyItems, or references itself`,path:[`items`]}).refine(e=>e.meta.thumbnail&&e.meta.assets?e.meta.thumbnail in e.meta.assets:!0,{message:`Thumbnail references non-existent asset`,path:[`meta`,`thumbnail`]}).refine(e=>{let t=new Set((e.meta.sourceMaterials||[]).map(e=>e.id));for(let n of e.items)if(n.sources){for(let e of n.sources)if(!t.has(e.id))return!1}return!0},{message:`Some item references non-existent source material`,path:[`items`]});function mt(t){let n=t instanceof Error?t.message:`OQSE Security Error: Maximum nesting depth exceeded limit of 10 levels.`;return new e.z.ZodError([{code:e.z.ZodIssueCode.custom,message:n,path:[]}])}function ht(e){return _(e,10),K.parse(e)}function gt(e){try{_(e,10)}catch(e){return{success:!1,error:mt(e)}}let t=K.safeParse(e);return t.success?{success:!0,data:t.data}:{success:!1,error:t.error}}function _t(e){return _(e,10),G.parse(e)}function vt(e){try{_(e,10)}catch(e){return{success:!1,error:mt(e)}}let t=G.safeParse(e);return t.success?{success:!0,data:t.data}:{success:!1,error:t.error}}function yt(e){return e.issues.map(e=>{let t=``;return e.path.forEach((n,r)=>{if(typeof n==`number`)t+=`[${n}]`;else{let i=r===0||typeof e.path[r-1]==`number`;t+=(i?``:`.`)+String(n)}}),t?`${t}: ${e.message}`:e.message})}var q=e.z.string().min(1,`Value must not be empty`).trim(),bt=e.z.string().regex(/^[a-zA-Z]{2,8}(-[a-zA-Z0-9\-]+)*$/,`Must be a valid BCP 47 locale (e.g., "en", "cs")`),J=e.z.string().url(`Must be a valid absolute URL`).refine(e=>e.startsWith(`http://`)||e.startsWith(`https://`),{message:`URL must use http or https scheme`}),xt=e.z.string().regex(/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,`Must be a valid URN UUID (urn:uuid:...)`),Y=e.z.string().regex(/^\d+\.\d+$/,`Version must be in MAJOR.MINOR format (e.g. "0.1")`),St=[`note`,`flashcard`,`true-false`,`mcq-single`,`mcq-multi`,`short-answer`,`fill-in-blanks`,`fill-in-select`,`match-pairs`,`match-complex`,`sort-items`,`slider`,`pin-on-image`,`categorize`,`timeline`,`matrix`,`math-input`,`diagram-label`,`open-ended`,`numeric-input`,`pin-on-model`,`chess-puzzle`],Ct=q.refine(e=>St.includes(e)||e.startsWith(`x-`),{message:`Custom types MUST use the "x-" prefix`}),wt=e.z.string().refine(e=>c.includes(e)||e.startsWith(`x-`),{message:`Action must be one of [render, edit, validate, import, export] or have prefix "x-"`}),Tt=e.z.enum([`game`,`fun`,`drill`]),Et=e.z.enum([`low`,`medium`,`high`]),Dt=e.z.string().refine(e=>l.includes(e)||e.startsWith(`x-`),{message:`Feature must be one of official keys or have prefix "x-"`}),Ot=e.z.string().refine(e=>u.includes(e)||e.startsWith(`x-`),{message:`Item property must be an official key or have prefix "x-"`}),kt=e.z.string().refine(e=>d.includes(e)||e.startsWith(`x-`),{message:`Meta property must be an official key or have prefix "x-"`});function X(t){return e.z.union([e.z.tuple([e.z.literal(`*`)]),e.z.array(t),e.z.null()])}var At=e.z.string().refine(e=>e.startsWith(`image/`),{message:`Must be a valid image MIME type (image/...)`}),jt=e.z.string().refine(e=>e.startsWith(`audio/`),{message:`Must be a valid audio MIME type (audio/...)`}),Mt=e.z.string().refine(e=>e.startsWith(`video/`),{message:`Must be a valid video MIME type (video/...)`}),Nt=e.z.string().refine(e=>e.startsWith(`model/`)||e===`application/octet-stream`,{message:`Must be a valid 3D model MIME type (model/... or application/octet-stream)`}),Pt=e.z.object({image:X(At).optional(),audio:X(jt).optional(),video:X(Mt).optional(),model:X(Nt).optional()}),Ft=F.extend({actions:e.z.array(wt).min(1,`Application must support at least one action`),types:X(Ct).optional(),assets:Pt.optional()}).superRefine((t,n)=>{(t.actions.includes(`render`)||t.actions.includes(`edit`))&&(!Array.isArray(t.types)||t.types.length===0)&&n.addIssue({code:e.z.ZodIssueCode.custom,message:`types array MUST be declared and non-empty when actions include "render" or "edit"`,path:[`types`]})}),Z=e.z.object({$schema:J.optional(),id:e.z.union([J,xt]),appName:q.max(200,`Name must not be longer than 200 characters`),version:Y,pluginVersion:e.z.string().optional(),minOqseVersion:Y.optional(),maxOqseVersion:Y.optional(),capabilities:Ft,author:j.optional(),contributors:e.z.array(j).optional(),license:e.z.string().max(100,`License must not be longer than 100 characters`).optional(),licenseUrl:J.optional(),locales:e.z.array(bt).optional(),description:e.z.string().max(5e3,`Description must not be longer than 5000 characters`).optional(),emoji:e.z.string().optional(),tags:e.z.array(q).optional(),studyMode:Tt.optional(),questionDensity:Et.optional(),appSpecific:e.z.record(e.z.string(),e.z.unknown()).optional()}).refine(e=>{if(!e.minOqseVersion||!e.maxOqseVersion)return!0;let t=e.minOqseVersion.split(`.`),n=e.maxOqseVersion.split(`.`),r=Number(t[0]),i=Number(t[1]),a=Number(n[0]),o=Number(n[1]);return r===a?i<=o:r<a},{message:`minOqseVersion must not be greater than maxOqseVersion`,path:[`minOqseVersion`]});function It(e){return Z.parse(e)}function Lt(e){return Z.safeParse(e)}function Rt(e){return e.issues.map(e=>{let t=e.path.map(e=>String(e)).join(`.`);return t?`${t}: ${e.message}`:e.message}).join(`
2
- `)}function zt(e){return Z.safeParse(e).success}var Bt=e.z.object({attempts:e.z.number().int().nonnegative(),incorrect:e.z.number().int().nonnegative(),streak:e.z.number().int().nonnegative()}).refine(e=>e.incorrect<=e.attempts,{message:`incorrect cannot be higher than attempts`,path:[`incorrect`]}),Vt=e.z.object({isCorrect:e.z.boolean(),confidence:e.z.union([e.z.literal(1),e.z.literal(2),e.z.literal(3),e.z.literal(4)]).optional(),answeredAt:x,timeSpent:e.z.number().int().nonnegative().optional(),hintsUsed:e.z.number().int().nonnegative().default(0),isSkipped:e.z.boolean().optional()}),Ht=e.z.object({bucket:e.z.union([e.z.literal(0),e.z.literal(1),e.z.literal(2),e.z.literal(3),e.z.literal(4)]),nextReviewAt:x.optional(),stats:Bt,lastAnswer:Vt.optional(),appSpecific:e.z.record(e.z.string(),e.z.unknown()).optional()}),Ut=e.z.object({setId:v,exportedAt:x,algorithm:e.z.string().regex(/^[a-z0-9-]+$/,`algorithm must be lowercase alphanumeric with hyphens format`).optional()}),Q=e.z.object({$schema:e.z.url().optional(),version:e.z.string().regex(/^\d+\.\d+$/,`Version must be in MAJOR.MINOR format`),meta:Ut,records:e.z.record(v,Ht)});function Wt(e){return Q.parse(e)}function Gt(e){return Q.safeParse(e)}var $=e.z.object(L.shape).pick({id:!0,title:!0,language:!0,updatedAt:!0,description:!0,author:!0,subject:!0,tags:!0,createdAt:!0,estimatedTime:!0,requirements:!0}).partial({createdAt:!0}).extend({url:S,$schema:e.z.string().url().optional()});function Kt(e){return $.parse(e)}function qt(e){return $.safeParse(e)}function Jt(e){let t={};return{text:e.replace(/<(asset|blank):([a-zA-Z0-9_-]+)\s*\/>/gi,(e,n,r)=>{let i=`[[__OQSE_TOKEN_${Math.random().toString(36).substring(2,15)}__]]`;return t[i]={type:n.toLowerCase(),key:r.toLowerCase(),originalTag:e},i}),tokens:t}}function Yt(e){let t=e.replace(/`{1,}[^`]*`{1,}/g,``).replace(/~{3,}[\s\S]*?~{3,}/g,``);if(/<[a-zA-Z\/][^>]*>/.test(t))throw Error(`OQSE Security Error: Raw HTML tags are not allowed in Tier 1 (Pure Markdown). If the set requires HTML formatting, it MUST declare the 'html' feature in meta.requirements.`)}function Xt(e,t,n){let r=e;for(let[e,i]of Object.entries(t)){let t=i.originalTag;i.type===`asset`&&n.assetReplacer?t=n.assetReplacer(i.key):i.type===`blank`&&n.blankReplacer&&(t=n.blankReplacer(i.key)),r=r.replace(e,t)}return r}function Zt(e,t,n){if(!e)return``;let r=t?.features?.includes(`html`)??!1,{text:i,tokens:a}=Jt(e);r||Yt(i);let o=n.markdownParser(i);if(r){if(!n.htmlSanitizer)throw Error(`OQSE Security Error: Set requires 'html' (Tier 2), but no htmlSanitizer (like DOMPurify) was provided to the options.`);o=n.htmlSanitizer(o)}return Xt(o,a,n)}exports.AbsoluteURLSchema=S,exports.AssetDictionarySchema=A,exports.AssetKeySchema=C,exports.AudioMimeTypeSchema=jt,exports.BaseItemSchema=R,exports.BlankTokenSchema=D,exports.BloomLevelSchema=Ne,exports.CameraSetupSchema=ze,exports.CategorizeItemObjectSchema=Be,exports.CategorizeItemSchema=at,exports.ChessPuzzleItemSchema=pt,exports.CircleHotspotSchema=B,exports.CognitiveLoadSchema=Pe,exports.DiagramLabelItemSchema=lt,exports.DiagramZoneSchema=Ue,exports.FeatureFlagSchema=Dt,exports.FeatureProfileSchema=F,exports.FillInBlanksItemSchema=Qe,exports.FillInSelectItemSchema=$e,exports.FlashcardItemSchema=qe,exports.Hotspot2DSchema=Re,exports.HotspotObjectSchema=Le,exports.ISO8601DateTimeSchema=x,exports.ImageMimeTypeSchema=At,exports.ItemPropertyKeySchema=Ot,exports.LanguageCodeSchema=y,exports.LastAnswerObjectSchema=Vt,exports.LinkedSetObjectSchema=I,exports.MCQMultiItemSchema=Xe,exports.MCQSingleItemSchema=Ye,exports.ManifestAssetsSchema=Pt,exports.ManifestCapabilitiesSchema=Ft,exports.MatchComplexItemSchema=tt,exports.MatchPairsItemSchema=et,exports.MathInputItemSchema=ct,exports.MatrixItemSchema=st,exports.MediaObjectSchema=k,exports.MeshHotspotSchema=H,exports.MetaPropertyKeySchema=kt,exports.ModelMimeTypeSchema=Nt,exports.NoteItemSchema=Ke,exports.NumericInputItemSchema=dt,exports.NumericRangeSchema=Ge,exports.OFFICIAL_ACTIONS=c,exports.OFFICIAL_FEATURE_KEYS=l,exports.OFFICIAL_ITEM_PROPERTIES=u,exports.OFFICIAL_META_PROPERTIES=d,exports.OQSEActionSchema=wt,exports.OQSEFileSchema=K,exports.OQSEHeaderSchema=$,exports.OQSEItemSchema=G,exports.OQSEManifestSchema=Z,exports.OQSEMetaSchema=L,exports.OQSEPFileSchema=Q,exports.OQSEQuestionDensitySchema=Et,exports.OQSEStudyModeSchema=Tt,exports.OpenEndedItemSchema=ut,exports.OptionalRichContentSchema=E,exports.PedagogySchema=Fe,exports.PersonObjectSchema=j,exports.PinOnImageItemSchema=it,exports.PinOnModelItemSchema=ft,exports.PlainTextSchema=w,exports.PolygonHotspotSchema=V,exports.ProgressMetaSchema=Ut,exports.ProgressRecordSchema=Ht,exports.RectHotspotSchema=z,exports.RichContentSchema=T,exports.RubricCriterionSchema=W,exports.RubricSchema=We,exports.SPDXLicenseSchema=b,exports.SelectBlankObjectSchema=Ie,exports.ShortAnswerItemSchema=Ze,exports.SliderItemSchema=rt,exports.SortItemsItemSchema=nt,exports.SourceMaterialSchema=N,exports.SourceMaterialTypeSchema=M,exports.SourceReferenceSchema=P,exports.StatsObjectSchema=Bt,exports.SubtitleTrackSchema=O,exports.TagDefinitionDictionarySchema=je,exports.TagDefinitionSchema=Ae,exports.TimelineEventSchema=He,exports.TimelineItemSchema=ot,exports.TimelinePrecisionSchema=Ve,exports.TranslationObjectSchema=Me,exports.TrueFalseItemSchema=Je,exports.UUIDSchema=v,exports.Vector3Schema=U,exports.VideoMimeTypeSchema=Mt,exports.compareManifestVersions=p,exports.detokenizeOqseTags=Xt,exports.formatManifestErrors=Rt,exports.formatValidationErrors=yt,exports.generateUUID=ke,exports.isCategorize=se,exports.isChessPuzzle=he,exports.isCoreItem=s,exports.isDiagramLabel=de,exports.isExtendedItem=ge,exports.isFillInBlanks=ee,exports.isFillInSelect=te,exports.isFlashcard=n,exports.isMCQMulti=a,exports.isMCQSingle=i,exports.isMatchComplex=re,exports.isMatchPairs=ne,exports.isMathInput=ue,exports.isMatrix=le,exports.isNote=t,exports.isNumericInput=pe,exports.isOQSEManifest=ve,exports.isOpenEnded=fe,exports.isPinOnImage=oe,exports.isPinOnModel=me,exports.isShortAnswer=o,exports.isSlider=ae,exports.isSortItems=ie,exports.isTimeline=ce,exports.isTrueFalse=r,exports.isValidManifestVersion=f,exports.isValidOQSEManifest=zt,exports.isValidSemVer=_e,exports.isValidUUID=Oe,exports.isVersionCompatible=ye,exports.prepareRichTextForDisplay=Zt,exports.safeValidateManifest=Lt,exports.safeValidateOQSEFile=gt,exports.safeValidateOQSEHeader=qt,exports.safeValidateOQSEItem=vt,exports.safeValidateOQSEPFile=Gt,exports.tokenizeOqseTags=Jt,exports.validateJsonDepth=_,exports.validateManifest=It,exports.validateOQSEFile=ht,exports.validateOQSEHeader=Kt,exports.validateOQSEItem=_t,exports.validateOQSEPFile=Wt,exports.validateTier1Markdown=Yt;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`zod`);function t(e){return e.type===`note`}function n(e){return e.type===`flashcard`}function r(e){return e.type===`true-false`}function i(e){return e.type===`mcq-single`}function a(e){return e.type===`mcq-multi`}function o(e){return e.type===`short-answer`}function ee(e){return e.type===`fill-in-blanks`}function te(e){return e.type===`fill-in-select`}function ne(e){return e.type===`match-pairs`}function re(e){return e.type===`match-complex`}function ie(e){return e.type===`sort-items`}function ae(e){return e.type===`slider`}function oe(e){return e.type===`pin-on-image`}function se(e){return e.type===`categorize`}function ce(e){return e.type===`timeline`}function le(e){return e.type===`matrix`}function ue(e){return e.type===`math-input`}function de(e){return e.type===`diagram-label`}function fe(e){return e.type===`open-ended`}function pe(e){return e.type===`numeric-input`}function me(e){return e.type===`pin-on-model`}function he(e){return e.type===`chess-puzzle`}function s(e){return[`note`,`flashcard`,`mcq-single`,`short-answer`].includes(e.type)}function ge(e){return!s(e)}var c=[`render`,`edit`,`validate`,`import`,`export`],l=[`markdown`,`math`,`rtl`,`html`,`syntax-highlighting`,`mermaid`,`smiles`,`abc-notation`,`text-to-speech`,`voice-input`,`handwriting-recognition`],u=[`hints`,`explanation`,`incorrectFeedback`,`sources`,`relatedItems`,`dependencyItems`,`timeLimit`,`lang`,`topic`,`pedagogy`],d=[`description`,`thumbnail`,`subject`,`language`,`author`,`contributors`,`license`,`ageRestriction`,`tags`,`tagDefinitions`,`sourceMaterials`,`estimatedTime`,`prerequisites`,`translations`,`relatedSets`];function f(e){return/^\d+\.\d+$/.test(e)}function _e(e){return/^\d+\.\d+\.\d+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/.test(e)}function p(e,t){let[n=0,r=0]=e.split(`.`).map(Number),[i=0,a=0]=t.split(`.`).map(Number);return n===i?r-a:n-i}function ve(e){if(typeof e!=`object`||!e)return!1;let t=e,n=t.author;return typeof t.version==`string`&&typeof t.id==`string`&&typeof t.appName==`string`&&t.appName!==``&&(n===void 0||typeof n==`object`&&!!n)&&typeof t.capabilities==`object`&&t.capabilities!==null&&Array.isArray(t.capabilities.actions)}function ye(e,t){return!(!f(e)||t.minOqseVersion&&f(t.minOqseVersion)&&p(e,t.minOqseVersion)<0||t.maxOqseVersion&&f(t.maxOqseVersion)&&p(e,t.maxOqseVersion)>0)}var be=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;function xe(e){return typeof e==`string`&&be.test(e)}var m=[];for(let e=0;e<256;++e)m.push((e+256).toString(16).slice(1));function Se(e,t=0){return(m[e[t+0]]+m[e[t+1]]+m[e[t+2]]+m[e[t+3]]+`-`+m[e[t+4]]+m[e[t+5]]+`-`+m[e[t+6]]+m[e[t+7]]+`-`+m[e[t+8]]+m[e[t+9]]+`-`+m[e[t+10]]+m[e[t+11]]+m[e[t+12]]+m[e[t+13]]+m[e[t+14]]+m[e[t+15]]).toLowerCase()}var h,Ce=new Uint8Array(16);function we(){if(!h){if(typeof crypto>`u`||!crypto.getRandomValues)throw Error(`crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported`);h=crypto.getRandomValues.bind(crypto)}return h(Ce)}var g={};function Te(e,t,n){let r;if(e)r=De(e.random??e.rng?.()??we(),e.msecs,e.seq,t,n);else{let e=Date.now(),i=we();Ee(g,e,i),r=De(i,g.msecs,g.seq,t,n)}return t??Se(r)}function Ee(e,t,n){return e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=n[6]<<23|n[7]<<16|n[8]<<8|n[9],e.msecs=t):(e.seq=e.seq+1|0,e.seq===0&&e.msecs++),e}function De(e,t,n,r,i=0){if(e.length<16)throw Error(`Random bytes length must be >= 16`);if(!r)r=new Uint8Array(16),i=0;else if(i<0||i+16>r.length)throw RangeError(`UUID byte range ${i}:${i+15} is out of buffer bounds`);return t??=Date.now(),n??=e[6]*127<<24|e[7]<<16|e[8]<<8|e[9],r[i++]=t/1099511627776&255,r[i++]=t/4294967296&255,r[i++]=t/16777216&255,r[i++]=t/65536&255,r[i++]=t/256&255,r[i++]=t&255,r[i++]=112|n>>>28&15,r[i++]=n>>>20&255,r[i++]=128|n>>>14&63,r[i++]=n>>>6&255,r[i++]=n<<2&255|e[10]&3,r[i++]=e[11],r[i++]=e[12],r[i++]=e[13],r[i++]=e[14],r[i++]=e[15],r}function Oe(e){return xe(e)}function ke(){return Te()}function _(e,t=10,n=0){if(n>t)throw Error(`OQSE Security Error: Maximum nesting depth exceeded limit of ${t} levels.`);if(typeof e==`object`&&e){let r=Array.isArray(e)?e:Object.values(e);for(let e of r)_(e,t,n+1)}}function Ae(e){return e.issues.map(e=>{let t=``;return e.path.forEach((n,r)=>{if(typeof n==`number`)t+=`[${n}]`;else{let i=r===0||typeof e.path[r-1]==`number`;t+=(i?``:`.`)+String(n)}}),t?`${t}: ${e.message}`:e.message})}var v=e.z.string().uuid({message:`Invalid UUID format`}),y=e.z.string().min(2,`Language code must have at least 2 characters`).regex(/^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2})?$/,`Invalid BCP 47 format (e.g. "cs", "en-US")`),b=e.z.string().min(1,`License identifier must not be empty`),x=e.z.string().regex(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?(Z|[+-]\d{2}:\d{2})?)?$/,`Invalid ISO 8601 format (e.g. "2025-11-21T14:30:00Z")`),S=e.z.string().url({message:`Must be a valid absolute URL`}),C=e.z.string().regex(/^[a-z0-9_-]+$/,`Asset key must contain only lowercase letters, numbers, hyphens and underscores`),w=e.z.string().min(1,`Text must not be empty`),T=e.z.string().min(1,`Content must not be empty`),E=e.z.string().max(1e4,`Question must not be longer than 10000 characters`).optional(),D=e.z.string().regex(/^[a-zA-Z0-9_-]{1,64}$/,`Token must be alphanumeric, max 64 chars`),O=e.z.object({lang:y,value:e.z.string().min(1,`Subtitle URI must not be empty`).regex(/\.(vtt|srt)(\?.*)?$/i,`Subtitle URI must end with .vtt or .srt`),label:e.z.string().optional(),kind:e.z.enum([`captions`,`subtitles`,`descriptions`]).optional()}),k=e.z.object({type:e.z.enum([`image`,`audio`,`video`,`model`]),value:e.z.string().min(1,`Media URI must not be empty`),mimeType:e.z.string().optional(),altText:e.z.string().optional(),transcript:T.optional(),caption:T.optional(),width:e.z.number().int().positive().optional(),height:e.z.number().int().positive().optional(),start:e.z.number().nonnegative().optional(),end:e.z.number().positive().optional(),loop:e.z.boolean().optional(),subtitles:e.z.array(O).optional(),license:b.optional(),attribution:e.z.string().optional(),checksums:e.z.record(e.z.string(),e.z.string()).optional()}).refine(e=>e.start!==void 0&&e.end!==void 0?e.start<e.end:!0,{message:`Start time must be less than end time`,path:[`end`]}).refine(e=>!(e.type===`image`&&!e.altText),{message:`Images must have alternative text (altText) defined for accessibility`,path:[`altText`]}),A=e.z.record(C,k),j=e.z.object({name:w,role:e.z.string().optional(),email:e.z.string().email(`Invalid email format`).optional(),url:S.optional()}),M=e.z.enum([`url`,`doi`,`isbn`,`pdf`,`textbook`,`video`,`audio`,`image`,`model`,`other`]),N=e.z.object({id:w,type:M,value:w,title:w,description:e.z.string().optional(),authors:e.z.array(w).optional(),publishedDate:x.optional(),retrievedAt:x.optional(),license:b.optional()}).refine(e=>{if([`url`,`pdf`,`video`,`audio`,`image`].includes(e.type))try{return new URL(e.value),!0}catch{return!1}return!0},{message:`For url, pdf, video, audio and image types, value must be a valid URL`,path:[`value`]}),P=e.z.object({id:w,location:e.z.string().optional(),quote:T.optional()}),je=e.z.object({wikidataId:e.z.string().regex(/^Q\d+$/,`Wikidata ID must have format Q followed by number`).optional(),description:e.z.string().optional()}),Me=e.z.record(e.z.string(),je),F=e.z.object({features:e.z.array(e.z.string().refine(e=>l.includes(e)||e.startsWith(`x-`),{message:`Feature must be an official key or have prefix "x-"`})).optional(),latexPackages:e.z.array(e.z.string().min(1,`Package name must not be empty`)).optional(),itemProperties:e.z.array(e.z.string().refine(e=>u.includes(e)||e.startsWith(`x-`),{message:`Item property must be an official key or have prefix "x-"`})).optional(),metaProperties:e.z.array(e.z.string().refine(e=>d.includes(e)||e.startsWith(`x-`),{message:`Meta property must be an official key or have prefix "x-"`})).optional()}),Ne=e.z.object({lang:y,id:v,title:w,downloadUrl:S.optional()}),I=e.z.object({id:v,title:w,downloadUrl:S.optional()}),Pe=e.z.enum([`remember`,`understand`,`apply`,`analyze`,`evaluate`,`create`]),Fe=e.z.enum([`low`,`medium`,`high`]),Ie=e.z.object({bloomLevel:Pe.optional(),irtDifficulty:e.z.number().optional(),irtDiscrimination:e.z.number().optional(),irtGuessing:e.z.number().min(0).max(1,`IRT guessing must be between 0 and 1`).optional(),avgTime:e.z.number().positive().optional(),cognitiveLoad:Fe.optional(),partialCredit:e.z.boolean().optional(),penaltyPerWrong:e.z.number().min(0).max(1,`Penalty must be between 0 and 1`).optional()}),L=e.z.object({id:v,language:y,title:w.max(500,`Title must not be longer than 500 characters`),description:T.max(5e3,`Description must not be longer than 5000 characters`).optional(),thumbnail:C.optional(),assets:A.optional(),ageMin:e.z.number().int().nonnegative().optional(),ageMax:e.z.number().int().nonnegative().optional(),subject:e.z.string().optional(),createdAt:x,updatedAt:x,author:j.optional(),contributors:e.z.array(j).optional(),license:b.optional(),licenseUrl:S.optional(),requirements:F.optional(),tags:e.z.array(w).optional(),tagDefinitions:Me.optional(),translations:e.z.array(Ne).optional(),sourceMaterials:e.z.array(N).optional(),estimatedTime:e.z.number().positive().optional(),prerequisites:e.z.array(I).optional(),relatedSets:e.z.array(I).optional(),customData:e.z.record(e.z.string(),e.z.unknown()).optional(),appSpecific:e.z.record(e.z.string(),e.z.unknown()).optional()}).refine(e=>e.ageMin!==void 0&&e.ageMax!==void 0?e.ageMin<=e.ageMax:!0,{message:`Minimum age (ageMin) must be less than or equal to maximum age (ageMax)`,path:[`ageMax`]}).refine(e=>new Date(e.createdAt)<=new Date(e.updatedAt),{message:`Creation date (createdAt) must be before or equal to update date (updatedAt)`,path:[`updatedAt`]}),R=e.z.object({id:v,type:e.z.string(),assets:A.optional(),lang:y.optional(),tags:e.z.array(w).optional(),topic:w.optional(),difficulty:e.z.number().int().min(1,`Difficulty must be at least 1`).max(5,`Difficulty must be at most 5`).optional(),timeLimit:e.z.number().positive(`Time limit must be a positive number`).optional(),hints:e.z.array(T.max(2e3,`Hint must not be longer than 2000 characters`)).max(20,`Maximum 20 hints per item`).optional(),explanation:T.max(1e4,`Explanation must not be longer than 10000 characters`).optional(),incorrectFeedback:T.optional(),sources:e.z.array(P).optional(),relatedItems:e.z.array(v).optional(),dependencyItems:e.z.array(v).optional(),pedagogy:Ie.optional(),customData:e.z.record(e.z.string(),e.z.unknown()).optional(),appSpecific:e.z.record(e.z.string(),e.z.unknown()).optional()}),Le=e.z.object({options:e.z.array(T).min(1,`Must have at least 1 option`),correctIndex:e.z.number().int().nonnegative()}).refine(e=>e.correctIndex<e.options.length,{message:`Correct answer index references non-existent option`,path:[`correctIndex`]}),z=e.z.object({type:e.z.literal(`rect`),label:e.z.string().optional(),x:e.z.number().min(0).max(100,`X must be in range 0-100%`),y:e.z.number().min(0).max(100,`Y must be in range 0-100%`),width:e.z.number().min(0).max(100,`Width must be in range 0-100%`),height:e.z.number().min(0).max(100,`Height must be in range 0-100%`)}),B=e.z.object({type:e.z.literal(`circle`),label:e.z.string().optional(),x:e.z.number().min(0).max(100,`X must be in range 0-100%`),y:e.z.number().min(0).max(100,`Y must be in range 0-100%`),radius:e.z.number().min(0).max(100,`Radius must be in range 0-100%`)}),V=e.z.object({type:e.z.literal(`polygon`),label:e.z.string().optional(),points:e.z.array(e.z.object({x:e.z.number().min(0).max(100),y:e.z.number().min(0).max(100)})).min(3,`Polygon must have at least 3 points`)}),H=e.z.object({type:e.z.literal(`mesh`),label:e.z.string().optional(),targetName:w}),Re=e.z.discriminatedUnion(`type`,[z,B,V,H]),ze=e.z.discriminatedUnion(`type`,[z,B,V]),U=e.z.object({x:e.z.number(),y:e.z.number(),z:e.z.number()}),W=e.z.object({position:U.optional(),target:U.optional()}),Be=e.z.object({id:w,text:T,correctCategoryIndex:e.z.number().int().nonnegative()}),Ve=e.z.enum([`year`,`month`,`day`,`datetime`]),He=e.z.object({id:w,text:T,date:x,precision:Ve.optional()}),Ue=e.z.union([z.extend({correctLabelIndex:e.z.number().int().nonnegative()}),B.extend({correctLabelIndex:e.z.number().int().nonnegative()}),V.extend({correctLabelIndex:e.z.number().int().nonnegative()})]),We=e.z.object({label:w,percentage:e.z.number().min(0,`Percentage must be non-negative`).max(100,`Percentage must not exceed 100`),description:e.z.string().optional()}),Ge=e.z.object({criteria:e.z.array(We).min(1,`Rubric must have at least 1 criterion`)}).refine(e=>e.criteria.reduce((e,t)=>e+t.percentage,0)>0,{message:`Sum of percentages of all criteria must be greater than 0`,path:[`criteria`]}),Ke=e.z.object({min:e.z.number(),max:e.z.number()}).refine(e=>e.min<=e.max,{message:`Minimum value must be less than or equal to maximum value`,path:[`max`]}),qe=R.extend({type:e.z.literal(`note`),title:e.z.string().optional(),content:T.max(1e4,`Content must not be longer than 10000 characters`),hiddenContent:T.max(1e4,`Content must not be longer than 10000 characters`).optional()}),Je=R.extend({type:e.z.literal(`flashcard`),front:T.max(1e4,`Front side must not be longer than 10000 characters`),back:T.max(1e4,`Back side must not be longer than 10000 characters`)}),Ye=R.extend({type:e.z.literal(`true-false`),question:T.max(1e4,`Question must not be longer than 10000 characters`),answer:e.z.boolean()}),Xe=R.extend({type:e.z.literal(`mcq-single`),question:T.max(1e4,`Question must not be longer than 10000 characters`),options:e.z.array(T.max(2e3,`Option must not be longer than 2000 characters`)).min(2,`Question must have at least 2 options`).max(100,`Maximum 100 options`),correctIndex:e.z.number().int().nonnegative(),shuffleOptions:e.z.boolean().optional(),optionExplanations:e.z.array(e.z.union([T,e.z.null()])).optional()}).refine(e=>e.correctIndex<e.options.length,{message:`Correct answer index references non-existent option`,path:[`correctIndex`]}).refine(e=>e.optionExplanations?e.optionExplanations.length===e.options.length:!0,{message:`Number of option explanations must match number of options`,path:[`optionExplanations`]}).refine(e=>new Set(e.options.map(e=>e.toLowerCase())).size===e.options.length,{message:`Options must not contain duplicates (case-insensitive)`,path:[`options`]}),Ze=R.extend({type:e.z.literal(`mcq-multi`),question:T.max(1e4,`Question must not be longer than 10000 characters`),options:e.z.array(T.max(2e3,`Option must not be longer than 2000 characters`)).min(2,`Question must have at least 2 options`).max(100,`Maximum 100 options`),correctIndices:e.z.array(e.z.number().int().nonnegative()).min(1,`Must have at least 1 correct answer`),minSelections:e.z.number().int().positive().optional(),maxSelections:e.z.number().int().positive().optional(),shuffleOptions:e.z.boolean().optional(),optionExplanations:e.z.array(e.z.union([T,e.z.null()])).optional()}).refine(e=>e.correctIndices.every(t=>t<e.options.length),{message:`Some of correct answer indices reference non-existent option`,path:[`correctIndices`]}).refine(e=>new Set(e.correctIndices).size===e.correctIndices.length,{message:`Correct answer indices contain duplicates`,path:[`correctIndices`]}).refine(e=>e.minSelections&&e.maxSelections?e.minSelections<=e.maxSelections:!0,{message:`Minimum number of selections must be less than or equal to maximum`,path:[`maxSelections`]}).refine(e=>e.maxSelections?e.maxSelections<=e.options.length:!0,{message:`Maximum number of selections must not exceed number of options`,path:[`maxSelections`]}).refine(e=>e.minSelections?e.minSelections<=e.options.length:!0,{message:`minSelections cannot be greater than the number of options`,path:[`minSelections`]}).refine(e=>e.optionExplanations?e.optionExplanations.length===e.options.length:!0,{message:`Number of option explanations must match number of options`,path:[`optionExplanations`]}).refine(e=>new Set(e.options.map(e=>e.toLowerCase())).size===e.options.length,{message:`Options must not contain duplicates (case-insensitive)`,path:[`options`]}),Qe=R.extend({type:e.z.literal(`short-answer`),question:T.max(1e4,`Question must not be longer than 10000 characters`),answers:e.z.array(w).min(1,`Must have at least 1 correct answer`),caseSensitive:e.z.boolean().optional(),trimWhitespace:e.z.boolean().optional(),acceptPartial:e.z.boolean().optional(),ignoreDiacritics:e.z.boolean().optional()}),$e=R.extend({type:e.z.literal(`fill-in-blanks`),question:E,text:T.max(1e4,`Text must not be longer than 10000 characters`),blanks:e.z.record(D,e.z.array(w).min(1,`Each blank must have at least 1 correct answer`)),caseSensitive:e.z.boolean().optional(),trimWhitespace:e.z.boolean().optional()}).refine(e=>Object.keys(e.blanks).length>0,{message:`Text must contain at least 1 blank to fill`,path:[`blanks`]}).refine(e=>{let t=/<blank:([a-zA-Z0-9_-]{1,64})\s*\/>/g,n=new Set,r;for(;(r=t.exec(e.text))!==null;)r[1]&&n.add(r[1]);let i=new Set(Object.keys(e.blanks));for(let e of n)if(!i.has(e))return!1;for(let e of i)if(!n.has(e))return!1;return!0},{message:`All tokens in text must have definition in blanks and all definitions must be used in text`,path:[`blanks`]}),et=R.extend({type:e.z.literal(`fill-in-select`),question:E,text:T.max(1e4,`Text must not be longer than 10000 characters`),blanks:e.z.record(D,Le)}).refine(e=>Object.keys(e.blanks).length>0,{message:`Text must contain at least 1 blank to select`,path:[`blanks`]}).refine(e=>{let t=/<blank:([a-zA-Z0-9_-]{1,64})\s*\/>/g,n=new Set,r;for(;(r=t.exec(e.text))!==null;)r[1]&&n.add(r[1]);let i=new Set(Object.keys(e.blanks));for(let e of n)if(!i.has(e))return!1;for(let e of i)if(!n.has(e))return!1;return!0},{message:`All tokens in text must have definition in blanks and all definitions must be used in text`,path:[`blanks`]}),tt=R.extend({type:e.z.literal(`match-pairs`),question:E,prompts:e.z.array(T).min(2,`Must have at least 2 pairs to match`).max(100,`Maximum 100 pairs`),matches:e.z.array(T).min(2,`Must have at least 2 pairs to match`).max(100,`Maximum 100 pairs`)}).refine(e=>e.prompts.length===e.matches.length,{message:`Number of prompts must match number of matches`,path:[`matches`]}),nt=R.extend({type:e.z.literal(`match-complex`),question:E,leftItems:e.z.array(T).min(1,`Must have at least 1 item on left`),rightItems:e.z.array(T).min(1,`Must have at least 1 item on right`),connections:e.z.array(e.z.tuple([e.z.number().int().nonnegative(),e.z.number().int().nonnegative()])).min(1,`Must have at least 1 connection`),minCorrect:e.z.number().int().positive().optional()}).refine(e=>e.connections.every(([t,n])=>t<e.leftItems.length&&n<e.rightItems.length),{message:`Some connection references non-existent item`,path:[`connections`]}).refine(e=>new Set(e.connections.map(e=>`${e[0]}-${e[1]}`)).size===e.connections.length,{message:`Connections contain duplicates`,path:[`connections`]}).refine(e=>e.minCorrect?e.minCorrect<=e.connections.length:!0,{message:`Minimum correct answers must not exceed total number of connections`,path:[`minCorrect`]}),rt=R.extend({type:e.z.literal(`sort-items`),question:T.max(1e4,`Question must not be longer than 10000 characters`),items:e.z.array(T).min(2,`Must have at least 2 items to sort`)}),it=R.extend({type:e.z.literal(`slider`),question:T.max(1e4,`Question must not be longer than 10000 characters`),min:e.z.number(),max:e.z.number(),step:e.z.number().positive(`Step must be a positive number`),correctAnswer:e.z.number(),tolerance:e.z.number().nonnegative(`Tolerance must be non-negative`),unit:e.z.string().optional()}).refine(e=>e.min<e.max,{message:`Minimum value must be less than maximum value`,path:[`max`]}).refine(e=>e.correctAnswer>=e.min&&e.correctAnswer<=e.max,{message:`Correct answer must be in range min-max`,path:[`correctAnswer`]}).refine(e=>{let t=(e.correctAnswer-e.min)/e.step;return Math.abs(t-Math.round(t))<1e-4},{message:`Correct answer must be reachable by defined step`,path:[`correctAnswer`]}).refine(e=>e.tolerance<=(e.max-e.min)/2,{message:`Tolerance must not be greater than half of value range`,path:[`tolerance`]}),at=R.extend({type:e.z.literal(`pin-on-image`),question:T.max(1e4,`Question must not be longer than 10000 characters`),targetAsset:C,hotspots:e.z.array(ze).min(1,`Must have at least 1 hotspot`),multipleCorrect:e.z.boolean().optional(),minCorrect:e.z.number().int().positive().optional()}).refine(e=>e.minCorrect?e.minCorrect<=e.hotspots.length:!0,{message:`Minimum correct answers must not exceed number of hotspots`,path:[`minCorrect`]}),ot=R.extend({type:e.z.literal(`categorize`),question:T.max(1e4,`Question must not be longer than 10000 characters`),categories:e.z.array(w).min(2,`Must have at least 2 categories`),items:e.z.array(Be).min(1,`Must have at least 1 item to categorize`)}).refine(e=>new Set(e.categories.map(e=>e.toLowerCase())).size===e.categories.length,{message:`Categories must not contain duplicates (case-insensitive)`,path:[`categories`]}).refine(e=>e.items.every(t=>t.correctCategoryIndex<e.categories.length),{message:`Some item references non-existent category`,path:[`items`]}),st=R.extend({type:e.z.literal(`timeline`),question:T.max(1e4,`Question must not be longer than 10000 characters`),events:e.z.array(He).min(2,`Must have at least 2 events`),randomize:e.z.boolean().optional()}),ct=R.extend({type:e.z.literal(`matrix`),question:T.max(1e4,`Question must not be longer than 10000 characters`),rows:e.z.array(w).min(1,`Must have at least 1 row`),columns:e.z.array(w).min(1,`Must have at least 1 column`),correctCells:e.z.array(e.z.tuple([e.z.number().int().nonnegative(),e.z.number().int().nonnegative()])).min(1,`Must have at least 1 correct cell`),multiplePerRow:e.z.boolean().optional()}).refine(e=>e.correctCells.every(([t,n])=>t<e.rows.length&&n<e.columns.length),{message:`Some cell coordinates reference non-existent row or column`,path:[`correctCells`]}).refine(e=>new Set(e.correctCells.map(e=>`${e[0]}-${e[1]}`)).size===e.correctCells.length,{message:`Correct cells contain duplicates`,path:[`correctCells`]}).refine(e=>{if(!e.multiplePerRow){let t=new Map;for(let[n]of e.correctCells)t.set(n,(t.get(n)||0)+1);return Array.from(t.values()).every(e=>e<=1)}return!0},{message:`If multiplePerRow is false, each row may have maximum 1 correct cell`,path:[`correctCells`]}),lt=R.extend({type:e.z.literal(`math-input`),question:T.max(1e4,`Question must not be longer than 10000 characters`),correctAnswer:w,alternativeAnswers:e.z.array(w).optional(),tolerance:e.z.number().nonnegative().optional()}),ut=R.extend({type:e.z.literal(`diagram-label`),question:T.max(1e4,`Question must not be longer than 10000 characters`),targetAsset:C,labels:e.z.array(T).min(1,`Must have at least 1 label`),caseSensitive:e.z.boolean().optional(),requireTyping:e.z.boolean().optional(),zones:e.z.array(Ue).min(1,`Must have at least 1 zone`)}).refine(e=>e.zones.every(t=>t.correctLabelIndex<e.labels.length),{message:`Some zone references non-existent label`,path:[`zones`]}),dt=R.extend({type:e.z.literal(`open-ended`),question:T.max(1e4,`Question must not be longer than 10000 characters`),minWords:e.z.number().int().positive().optional(),maxWords:e.z.number().int().positive().optional(),sampleAnswer:T.optional(),rubric:Ge.optional()}).refine(e=>e.minWords&&e.maxWords?e.minWords<=e.maxWords:!0,{message:`Minimum word count must be less than or equal to maximum`,path:[`maxWords`]}),ft=R.extend({type:e.z.literal(`numeric-input`),question:T.max(1e4,`Question must not be longer than 10000 characters`),value:e.z.number(),tolerance:e.z.number().nonnegative().optional(),range:Ke.optional(),unit:e.z.string().optional()}),pt=R.extend({type:e.z.literal(`pin-on-model`),question:T.max(1e4,`Question must not be longer than 10000 characters`),targetAsset:C,hotspots:e.z.array(H).min(1,`Must have at least 1 hotspot`),multipleCorrect:e.z.boolean().optional(),minCorrect:e.z.number().int().positive().optional(),camera:W.optional()}).refine(e=>e.minCorrect?e.minCorrect<=e.hotspots.length:!0,{message:`Minimum correct answers must not exceed number of hotspots`,path:[`minCorrect`]}),mt=R.extend({type:e.z.literal(`chess-puzzle`),question:T.max(1e4,`Question must not be longer than 10000 characters`),fen:w,answers:e.z.array(e.z.array(w).min(1,`Move sequence must not be empty`)).min(1,`Must have at least 1 correct move sequence`),elo:e.z.number().int().nonnegative(`ELO must be non-negative integer`).optional()}),G=e.z.discriminatedUnion(`type`,[qe,Je,Ye,Xe,Ze,Qe,$e,et,tt,nt,rt,it,at,ot,st,ct,lt,ut,dt,ft,pt,mt]),K=e.z.object({$schema:e.z.string().url().optional(),version:e.z.string().regex(/^\d+\.\d+$/,`Version must be in MAJOR.MINOR format (e.g. "0.1")`),meta:L,items:e.z.array(G).max(1e4,`Maximum 10000 items per set`)}).refine(e=>{let t=new Set(e.items.map(e=>e.id));for(let n of e.items){if(n.relatedItems){for(let e of n.relatedItems)if(!t.has(e)||n.id===e)return!1}if(n.dependencyItems){for(let e of n.dependencyItems)if(!t.has(e)||n.id===e)return!1}}return!0},{message:`Some item references non-existent relatedItems, dependencyItems, or references itself`,path:[`items`]}).refine(e=>e.meta.thumbnail&&e.meta.assets?e.meta.thumbnail in e.meta.assets:!0,{message:`Thumbnail references non-existent asset`,path:[`meta`,`thumbnail`]}).refine(e=>{let t=new Set((e.meta.sourceMaterials||[]).map(e=>e.id));for(let n of e.items)if(n.sources){for(let e of n.sources)if(!t.has(e.id))return!1}return!0},{message:`Some item references non-existent source material`,path:[`items`]});function ht(t){let n=t instanceof Error?t.message:`OQSE Security Error: Maximum nesting depth exceeded limit of 10 levels.`;return new e.z.ZodError([{code:e.z.ZodIssueCode.custom,message:n,path:[]}])}function gt(e){return _(e,10),K.parse(e)}function _t(e){try{_(e,10)}catch(e){return{success:!1,error:ht(e)}}let t=K.safeParse(e);return t.success?{success:!0,data:t.data}:{success:!1,error:t.error}}function vt(e){return _(e,10),G.parse(e)}function yt(e){try{_(e,10)}catch(e){return{success:!1,error:ht(e)}}let t=G.safeParse(e);return t.success?{success:!0,data:t.data}:{success:!1,error:t.error}}var q=e.z.string().min(1,`Value must not be empty`).trim(),bt=e.z.string().regex(/^[a-zA-Z]{2,8}(-[a-zA-Z0-9\-]+)*$/,`Must be a valid BCP 47 locale (e.g., "en", "cs")`),J=e.z.string().url(`Must be a valid absolute URL`).refine(e=>e.startsWith(`http://`)||e.startsWith(`https://`),{message:`URL must use http or https scheme`}),xt=e.z.string().regex(/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,`Must be a valid URN UUID (urn:uuid:...)`),Y=e.z.string().regex(/^\d+\.\d+$/,`Version must be in MAJOR.MINOR format (e.g. "0.1")`),St=[`note`,`flashcard`,`true-false`,`mcq-single`,`mcq-multi`,`short-answer`,`fill-in-blanks`,`fill-in-select`,`match-pairs`,`match-complex`,`sort-items`,`slider`,`pin-on-image`,`categorize`,`timeline`,`matrix`,`math-input`,`diagram-label`,`open-ended`,`numeric-input`,`pin-on-model`,`chess-puzzle`],Ct=q.refine(e=>St.includes(e)||e.startsWith(`x-`),{message:`Custom types MUST use the "x-" prefix`}),wt=e.z.string().refine(e=>c.includes(e)||e.startsWith(`x-`),{message:`Action must be one of [render, edit, validate, import, export] or have prefix "x-"`}),Tt=e.z.enum([`game`,`fun`,`drill`]),Et=e.z.enum([`low`,`medium`,`high`]),Dt=e.z.string().refine(e=>l.includes(e)||e.startsWith(`x-`),{message:`Feature must be one of official keys or have prefix "x-"`}),Ot=e.z.string().refine(e=>u.includes(e)||e.startsWith(`x-`),{message:`Item property must be an official key or have prefix "x-"`}),kt=e.z.string().refine(e=>d.includes(e)||e.startsWith(`x-`),{message:`Meta property must be an official key or have prefix "x-"`});function X(t){return e.z.union([e.z.tuple([e.z.literal(`*`)]),e.z.array(t),e.z.null()])}var At=e.z.string().refine(e=>e.startsWith(`image/`),{message:`Must be a valid image MIME type (image/...)`}),jt=e.z.string().refine(e=>e.startsWith(`audio/`),{message:`Must be a valid audio MIME type (audio/...)`}),Mt=e.z.string().refine(e=>e.startsWith(`video/`),{message:`Must be a valid video MIME type (video/...)`}),Nt=e.z.string().refine(e=>e.startsWith(`model/`)||e===`application/octet-stream`,{message:`Must be a valid 3D model MIME type (model/... or application/octet-stream)`}),Pt=e.z.object({image:X(At).optional(),audio:X(jt).optional(),video:X(Mt).optional(),model:X(Nt).optional()}),Ft=F.extend({actions:e.z.array(wt).min(1,`Application must support at least one action`),types:X(Ct).optional(),assets:Pt.optional()}).superRefine((t,n)=>{(t.actions.includes(`render`)||t.actions.includes(`edit`))&&(!Array.isArray(t.types)||t.types.length===0)&&n.addIssue({code:e.z.ZodIssueCode.custom,message:`types array MUST be declared and non-empty when actions include "render" or "edit"`,path:[`types`]})}),Z=e.z.object({$schema:J.optional(),id:e.z.union([J,xt]),appName:q.max(200,`Name must not be longer than 200 characters`),version:Y,pluginVersion:e.z.string().optional(),minOqseVersion:Y.optional(),maxOqseVersion:Y.optional(),capabilities:Ft,author:j.optional(),contributors:e.z.array(j).optional(),license:e.z.string().max(100,`License must not be longer than 100 characters`).optional(),licenseUrl:J.optional(),locales:e.z.array(bt).optional(),description:e.z.string().max(5e3,`Description must not be longer than 5000 characters`).optional(),emoji:e.z.string().optional(),tags:e.z.array(q).optional(),studyMode:Tt.optional(),questionDensity:Et.optional(),appSpecific:e.z.record(e.z.string(),e.z.unknown()).optional()}).refine(e=>{if(!e.minOqseVersion||!e.maxOqseVersion)return!0;let t=e.minOqseVersion.split(`.`),n=e.maxOqseVersion.split(`.`),r=Number(t[0]),i=Number(t[1]),a=Number(n[0]),o=Number(n[1]);return r===a?i<=o:r<a},{message:`minOqseVersion must not be greater than maxOqseVersion`,path:[`minOqseVersion`]});function It(e){return Z.parse(e)}function Lt(e){return Z.safeParse(e)}function Rt(e){return Z.safeParse(e).success}var zt=e.z.object({attempts:e.z.number().int().nonnegative(),incorrect:e.z.number().int().nonnegative(),streak:e.z.number().int().nonnegative()}).refine(e=>e.incorrect<=e.attempts,{message:`incorrect cannot be higher than attempts`,path:[`incorrect`]}),Bt=e.z.object({isCorrect:e.z.boolean(),confidence:e.z.union([e.z.literal(1),e.z.literal(2),e.z.literal(3),e.z.literal(4)]).optional(),answeredAt:x,timeSpent:e.z.number().int().nonnegative().optional(),hintsUsed:e.z.number().int().nonnegative().default(0),isSkipped:e.z.boolean().optional()}),Vt=e.z.object({bucket:e.z.union([e.z.literal(0),e.z.literal(1),e.z.literal(2),e.z.literal(3),e.z.literal(4)]),nextReviewAt:x.optional(),stats:zt,lastAnswer:Bt.optional(),appSpecific:e.z.record(e.z.string(),e.z.unknown()).optional()}),Ht=e.z.object({setId:v,exportedAt:x,algorithm:e.z.string().regex(/^[a-z0-9-]+$/,`algorithm must be lowercase alphanumeric with hyphens format`).optional()}),Q=e.z.object({$schema:e.z.url().optional(),version:e.z.string().regex(/^\d+\.\d+$/,`Version must be in MAJOR.MINOR format`),meta:Ht,records:e.z.record(v,Vt)});function Ut(e){return Q.parse(e)}function Wt(e){return Q.safeParse(e)}var $=e.z.object(L.shape).pick({id:!0,title:!0,language:!0,updatedAt:!0,description:!0,author:!0,subject:!0,tags:!0,createdAt:!0,estimatedTime:!0,requirements:!0}).partial({createdAt:!0}).extend({url:S,$schema:e.z.string().url().optional()});function Gt(e){return $.parse(e)}function Kt(e){return $.safeParse(e)}function qt(e){let t={};return{text:e.replace(/<(asset|blank):([a-zA-Z0-9_-]+)\s*\/>/gi,(e,n,r)=>{let i=`[[__OQSE_TOKEN_${Math.random().toString(36).substring(2,15)}__]]`;return t[i]={type:n.toLowerCase(),key:r.toLowerCase(),originalTag:e},i}),tokens:t}}function Jt(e){let t=e.replace(/`{1,}[^`]*`{1,}/g,``).replace(/~{3,}[\s\S]*?~{3,}/g,``);if(/<[a-zA-Z\/][^>]*>/.test(t))throw Error(`OQSE Security Error: Raw HTML tags are not allowed in Tier 1 (Pure Markdown). If the set requires HTML formatting, it MUST declare the 'html' feature in meta.requirements.`)}function Yt(e,t,n){let r=e;for(let[e,i]of Object.entries(t)){let t=i.originalTag;i.type===`asset`&&n.assetReplacer?t=n.assetReplacer(i.key):i.type===`blank`&&n.blankReplacer&&(t=n.blankReplacer(i.key)),r=r.replace(e,t)}return r}function Xt(e,t,n){if(!e)return``;let r=t?.features?.includes(`html`)??!1,{text:i,tokens:a}=qt(e);r||Jt(i);let o=n.markdownParser(i);if(r){if(!n.htmlSanitizer)throw Error(`OQSE Security Error: Set requires 'html' (Tier 2), but no htmlSanitizer (like DOMPurify) was provided to the options.`);o=n.htmlSanitizer(o)}return Yt(o,a,n)}exports.AbsoluteURLSchema=S,exports.AssetDictionarySchema=A,exports.AssetKeySchema=C,exports.AudioMimeTypeSchema=jt,exports.BaseItemSchema=R,exports.BlankTokenSchema=D,exports.BloomLevelSchema=Pe,exports.CameraSetupSchema=W,exports.CategorizeItemObjectSchema=Be,exports.CategorizeItemSchema=ot,exports.ChessPuzzleItemSchema=mt,exports.CircleHotspotSchema=B,exports.CognitiveLoadSchema=Fe,exports.DiagramLabelItemSchema=ut,exports.DiagramZoneSchema=Ue,exports.FeatureFlagSchema=Dt,exports.FeatureProfileSchema=F,exports.FillInBlanksItemSchema=$e,exports.FillInSelectItemSchema=et,exports.FlashcardItemSchema=Je,exports.Hotspot2DSchema=ze,exports.HotspotObjectSchema=Re,exports.ISO8601DateTimeSchema=x,exports.ImageMimeTypeSchema=At,exports.ItemPropertyKeySchema=Ot,exports.LanguageCodeSchema=y,exports.LastAnswerObjectSchema=Bt,exports.LinkedSetObjectSchema=I,exports.MCQMultiItemSchema=Ze,exports.MCQSingleItemSchema=Xe,exports.ManifestAssetsSchema=Pt,exports.ManifestCapabilitiesSchema=Ft,exports.MatchComplexItemSchema=nt,exports.MatchPairsItemSchema=tt,exports.MathInputItemSchema=lt,exports.MatrixItemSchema=ct,exports.MediaObjectSchema=k,exports.MeshHotspotSchema=H,exports.MetaPropertyKeySchema=kt,exports.ModelMimeTypeSchema=Nt,exports.NoteItemSchema=qe,exports.NumericInputItemSchema=ft,exports.NumericRangeSchema=Ke,exports.OFFICIAL_ACTIONS=c,exports.OFFICIAL_FEATURE_KEYS=l,exports.OFFICIAL_ITEM_PROPERTIES=u,exports.OFFICIAL_META_PROPERTIES=d,exports.OQSEActionSchema=wt,exports.OQSEFileSchema=K,exports.OQSEHeaderSchema=$,exports.OQSEItemSchema=G,exports.OQSEManifestSchema=Z,exports.OQSEMetaSchema=L,exports.OQSEProgressSchema=Q,exports.OQSEQuestionDensitySchema=Et,exports.OQSEStudyModeSchema=Tt,exports.OpenEndedItemSchema=dt,exports.OptionalRichContentSchema=E,exports.PedagogySchema=Ie,exports.PersonObjectSchema=j,exports.PinOnImageItemSchema=at,exports.PinOnModelItemSchema=pt,exports.PlainTextSchema=w,exports.PolygonHotspotSchema=V,exports.ProgressMetaSchema=Ht,exports.ProgressRecordSchema=Vt,exports.RectHotspotSchema=z,exports.RichContentSchema=T,exports.RubricCriterionSchema=We,exports.RubricSchema=Ge,exports.SPDXLicenseSchema=b,exports.SelectBlankObjectSchema=Le,exports.ShortAnswerItemSchema=Qe,exports.SliderItemSchema=it,exports.SortItemsItemSchema=rt,exports.SourceMaterialSchema=N,exports.SourceMaterialTypeSchema=M,exports.SourceReferenceSchema=P,exports.StatsObjectSchema=zt,exports.SubtitleTrackSchema=O,exports.TagDefinitionDictionarySchema=Me,exports.TagDefinitionSchema=je,exports.TimelineEventSchema=He,exports.TimelineItemSchema=st,exports.TimelinePrecisionSchema=Ve,exports.TranslationObjectSchema=Ne,exports.TrueFalseItemSchema=Ye,exports.UUIDSchema=v,exports.Vector3Schema=U,exports.VideoMimeTypeSchema=Mt,exports.compareManifestVersions=p,exports.detokenizeOqseTags=Yt,exports.formatOQSEErrors=Ae,exports.generateUUID=ke,exports.isCategorize=se,exports.isChessPuzzle=he,exports.isCoreItem=s,exports.isDiagramLabel=de,exports.isExtendedItem=ge,exports.isFillInBlanks=ee,exports.isFillInSelect=te,exports.isFlashcard=n,exports.isMCQMulti=a,exports.isMCQSingle=i,exports.isMatchComplex=re,exports.isMatchPairs=ne,exports.isMathInput=ue,exports.isMatrix=le,exports.isNote=t,exports.isNumericInput=pe,exports.isOQSEManifest=ve,exports.isOpenEnded=fe,exports.isPinOnImage=oe,exports.isPinOnModel=me,exports.isShortAnswer=o,exports.isSlider=ae,exports.isSortItems=ie,exports.isTimeline=ce,exports.isTrueFalse=r,exports.isValidManifestVersion=f,exports.isValidOQSEManifest=Rt,exports.isValidSemVer=_e,exports.isValidUUID=Oe,exports.isVersionCompatible=ye,exports.prepareRichTextForDisplay=Xt,exports.safeValidateOQSEFile=_t,exports.safeValidateOQSEHeader=Kt,exports.safeValidateOQSEItem=yt,exports.safeValidateOQSEManifest=Lt,exports.safeValidateOQSEProgress=Wt,exports.tokenizeOqseTags=qt,exports.validateJsonDepth=_,exports.validateOQSEFile=gt,exports.validateOQSEHeader=Gt,exports.validateOQSEItem=vt,exports.validateOQSEManifest=It,exports.validateOQSEProgress=Ut,exports.validateTier1Markdown=Jt;
package/dist/index.js CHANGED
@@ -204,6 +204,18 @@ function _(e, t = 10, n = 0) {
204
204
  for (let e of r) _(e, t, n + 1);
205
205
  }
206
206
  }
207
+ function Ae(e) {
208
+ return e.issues.map((e) => {
209
+ let t = "";
210
+ return e.path.forEach((n, r) => {
211
+ if (typeof n == "number") t += `[${n}]`;
212
+ else {
213
+ let i = r === 0 || typeof e.path[r - 1] == "number";
214
+ t += (i ? "" : ".") + String(n);
215
+ }
216
+ }), t ? `${t}: ${e.message}` : e.message;
217
+ });
218
+ }
207
219
  //#endregion
208
220
  //#region src/oqseValidation.ts
209
221
  var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(2, "Language code must have at least 2 characters").regex(/^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2})?$/, "Invalid BCP 47 format (e.g. \"cs\", \"en-US\")"), b = e.string().min(1, "License identifier must not be empty"), x = e.string().regex(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?(Z|[+-]\d{2}:\d{2})?)?$/, "Invalid ISO 8601 format (e.g. \"2025-11-21T14:30:00Z\")"), S = e.string().url({ message: "Must be a valid absolute URL" }), C = e.string().regex(/^[a-z0-9_-]+$/, "Asset key must contain only lowercase letters, numbers, hyphens and underscores"), w = e.string().min(1, "Text must not be empty"), T = e.string().min(1, "Content must not be empty"), E = e.string().max(1e4, "Question must not be longer than 10000 characters").optional(), D = e.string().regex(/^[a-zA-Z0-9_-]{1,64}$/, "Token must be alphanumeric, max 64 chars"), O = e.object({
@@ -288,15 +300,15 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
288
300
  id: w,
289
301
  location: e.string().optional(),
290
302
  quote: T.optional()
291
- }), Ae = e.object({
303
+ }), je = e.object({
292
304
  wikidataId: e.string().regex(/^Q\d+$/, "Wikidata ID must have format Q followed by number").optional(),
293
305
  description: e.string().optional()
294
- }), je = e.record(e.string(), Ae), F = e.object({
306
+ }), Me = e.record(e.string(), je), F = e.object({
295
307
  features: e.array(e.string().refine((e) => l.includes(e) || e.startsWith("x-"), { message: "Feature must be an official key or have prefix \"x-\"" })).optional(),
296
308
  latexPackages: e.array(e.string().min(1, "Package name must not be empty")).optional(),
297
309
  itemProperties: e.array(e.string().refine((e) => u.includes(e) || e.startsWith("x-"), { message: "Item property must be an official key or have prefix \"x-\"" })).optional(),
298
310
  metaProperties: e.array(e.string().refine((e) => d.includes(e) || e.startsWith("x-"), { message: "Meta property must be an official key or have prefix \"x-\"" })).optional()
299
- }), Me = e.object({
311
+ }), Ne = e.object({
300
312
  lang: y,
301
313
  id: v,
302
314
  title: w,
@@ -305,24 +317,24 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
305
317
  id: v,
306
318
  title: w,
307
319
  downloadUrl: S.optional()
308
- }), Ne = e.enum([
320
+ }), Pe = e.enum([
309
321
  "remember",
310
322
  "understand",
311
323
  "apply",
312
324
  "analyze",
313
325
  "evaluate",
314
326
  "create"
315
- ]), Pe = e.enum([
327
+ ]), Fe = e.enum([
316
328
  "low",
317
329
  "medium",
318
330
  "high"
319
- ]), Fe = e.object({
320
- bloomLevel: Ne.optional(),
331
+ ]), Ie = e.object({
332
+ bloomLevel: Pe.optional(),
321
333
  irtDifficulty: e.number().optional(),
322
334
  irtDiscrimination: e.number().optional(),
323
335
  irtGuessing: e.number().min(0).max(1, "IRT guessing must be between 0 and 1").optional(),
324
336
  avgTime: e.number().positive().optional(),
325
- cognitiveLoad: Pe.optional(),
337
+ cognitiveLoad: Fe.optional(),
326
338
  partialCredit: e.boolean().optional(),
327
339
  penaltyPerWrong: e.number().min(0).max(1, "Penalty must be between 0 and 1").optional()
328
340
  }), L = e.object({
@@ -343,8 +355,8 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
343
355
  licenseUrl: S.optional(),
344
356
  requirements: F.optional(),
345
357
  tags: e.array(w).optional(),
346
- tagDefinitions: je.optional(),
347
- translations: e.array(Me).optional(),
358
+ tagDefinitions: Me.optional(),
359
+ translations: e.array(Ne).optional(),
348
360
  sourceMaterials: e.array(N).optional(),
349
361
  estimatedTime: e.number().positive().optional(),
350
362
  prerequisites: e.array(I).optional(),
@@ -372,10 +384,10 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
372
384
  sources: e.array(P).optional(),
373
385
  relatedItems: e.array(v).optional(),
374
386
  dependencyItems: e.array(v).optional(),
375
- pedagogy: Fe.optional(),
387
+ pedagogy: Ie.optional(),
376
388
  customData: e.record(e.string(), e.unknown()).optional(),
377
389
  appSpecific: e.record(e.string(), e.unknown()).optional()
378
- }), Ie = e.object({
390
+ }), Le = e.object({
379
391
  options: e.array(T).min(1, "Must have at least 1 option"),
380
392
  correctIndex: e.number().int().nonnegative()
381
393
  }).refine((e) => e.correctIndex < e.options.length, {
@@ -405,12 +417,12 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
405
417
  type: e.literal("mesh"),
406
418
  label: e.string().optional(),
407
419
  targetName: w
408
- }), Le = e.discriminatedUnion("type", [
420
+ }), Re = e.discriminatedUnion("type", [
409
421
  z,
410
422
  B,
411
423
  V,
412
424
  H
413
- ]), Re = e.discriminatedUnion("type", [
425
+ ]), ze = e.discriminatedUnion("type", [
414
426
  z,
415
427
  B,
416
428
  V
@@ -418,7 +430,7 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
418
430
  x: e.number(),
419
431
  y: e.number(),
420
432
  z: e.number()
421
- }), ze = e.object({
433
+ }), W = e.object({
422
434
  position: U.optional(),
423
435
  target: U.optional()
424
436
  }), Be = e.object({
@@ -439,33 +451,33 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
439
451
  z.extend({ correctLabelIndex: e.number().int().nonnegative() }),
440
452
  B.extend({ correctLabelIndex: e.number().int().nonnegative() }),
441
453
  V.extend({ correctLabelIndex: e.number().int().nonnegative() })
442
- ]), W = e.object({
454
+ ]), We = e.object({
443
455
  label: w,
444
456
  percentage: e.number().min(0, "Percentage must be non-negative").max(100, "Percentage must not exceed 100"),
445
457
  description: e.string().optional()
446
- }), We = e.object({ criteria: e.array(W).min(1, "Rubric must have at least 1 criterion") }).refine((e) => e.criteria.reduce((e, t) => e + t.percentage, 0) > 0, {
458
+ }), Ge = e.object({ criteria: e.array(We).min(1, "Rubric must have at least 1 criterion") }).refine((e) => e.criteria.reduce((e, t) => e + t.percentage, 0) > 0, {
447
459
  message: "Sum of percentages of all criteria must be greater than 0",
448
460
  path: ["criteria"]
449
- }), Ge = e.object({
461
+ }), Ke = e.object({
450
462
  min: e.number(),
451
463
  max: e.number()
452
464
  }).refine((e) => e.min <= e.max, {
453
465
  message: "Minimum value must be less than or equal to maximum value",
454
466
  path: ["max"]
455
- }), Ke = R.extend({
467
+ }), qe = R.extend({
456
468
  type: e.literal("note"),
457
469
  title: e.string().optional(),
458
470
  content: T.max(1e4, "Content must not be longer than 10000 characters"),
459
471
  hiddenContent: T.max(1e4, "Content must not be longer than 10000 characters").optional()
460
- }), qe = R.extend({
472
+ }), Je = R.extend({
461
473
  type: e.literal("flashcard"),
462
474
  front: T.max(1e4, "Front side must not be longer than 10000 characters"),
463
475
  back: T.max(1e4, "Back side must not be longer than 10000 characters")
464
- }), Je = R.extend({
476
+ }), Ye = R.extend({
465
477
  type: e.literal("true-false"),
466
478
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
467
479
  answer: e.boolean()
468
- }), Ye = R.extend({
480
+ }), Xe = R.extend({
469
481
  type: e.literal("mcq-single"),
470
482
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
471
483
  options: e.array(T.max(2e3, "Option must not be longer than 2000 characters")).min(2, "Question must have at least 2 options").max(100, "Maximum 100 options"),
@@ -481,7 +493,7 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
481
493
  }).refine((e) => new Set(e.options.map((e) => e.toLowerCase())).size === e.options.length, {
482
494
  message: "Options must not contain duplicates (case-insensitive)",
483
495
  path: ["options"]
484
- }), Xe = R.extend({
496
+ }), Ze = R.extend({
485
497
  type: e.literal("mcq-multi"),
486
498
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
487
499
  options: e.array(T.max(2e3, "Option must not be longer than 2000 characters")).min(2, "Question must have at least 2 options").max(100, "Maximum 100 options"),
@@ -511,7 +523,7 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
511
523
  }).refine((e) => new Set(e.options.map((e) => e.toLowerCase())).size === e.options.length, {
512
524
  message: "Options must not contain duplicates (case-insensitive)",
513
525
  path: ["options"]
514
- }), Ze = R.extend({
526
+ }), Qe = R.extend({
515
527
  type: e.literal("short-answer"),
516
528
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
517
529
  answers: e.array(w).min(1, "Must have at least 1 correct answer"),
@@ -519,7 +531,7 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
519
531
  trimWhitespace: e.boolean().optional(),
520
532
  acceptPartial: e.boolean().optional(),
521
533
  ignoreDiacritics: e.boolean().optional()
522
- }), Qe = R.extend({
534
+ }), $e = R.extend({
523
535
  type: e.literal("fill-in-blanks"),
524
536
  question: E,
525
537
  text: T.max(1e4, "Text must not be longer than 10000 characters"),
@@ -539,11 +551,11 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
539
551
  }, {
540
552
  message: "All tokens in text must have definition in blanks and all definitions must be used in text",
541
553
  path: ["blanks"]
542
- }), $e = R.extend({
554
+ }), et = R.extend({
543
555
  type: e.literal("fill-in-select"),
544
556
  question: E,
545
557
  text: T.max(1e4, "Text must not be longer than 10000 characters"),
546
- blanks: e.record(D, Ie)
558
+ blanks: e.record(D, Le)
547
559
  }).refine((e) => Object.keys(e.blanks).length > 0, {
548
560
  message: "Text must contain at least 1 blank to select",
549
561
  path: ["blanks"]
@@ -557,7 +569,7 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
557
569
  }, {
558
570
  message: "All tokens in text must have definition in blanks and all definitions must be used in text",
559
571
  path: ["blanks"]
560
- }), et = R.extend({
572
+ }), tt = R.extend({
561
573
  type: e.literal("match-pairs"),
562
574
  question: E,
563
575
  prompts: e.array(T).min(2, "Must have at least 2 pairs to match").max(100, "Maximum 100 pairs"),
@@ -565,7 +577,7 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
565
577
  }).refine((e) => e.prompts.length === e.matches.length, {
566
578
  message: "Number of prompts must match number of matches",
567
579
  path: ["matches"]
568
- }), tt = R.extend({
580
+ }), nt = R.extend({
569
581
  type: e.literal("match-complex"),
570
582
  question: E,
571
583
  leftItems: e.array(T).min(1, "Must have at least 1 item on left"),
@@ -581,11 +593,11 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
581
593
  }).refine((e) => e.minCorrect ? e.minCorrect <= e.connections.length : !0, {
582
594
  message: "Minimum correct answers must not exceed total number of connections",
583
595
  path: ["minCorrect"]
584
- }), nt = R.extend({
596
+ }), rt = R.extend({
585
597
  type: e.literal("sort-items"),
586
598
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
587
599
  items: e.array(T).min(2, "Must have at least 2 items to sort")
588
- }), rt = R.extend({
600
+ }), it = R.extend({
589
601
  type: e.literal("slider"),
590
602
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
591
603
  min: e.number(),
@@ -609,17 +621,17 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
609
621
  }).refine((e) => e.tolerance <= (e.max - e.min) / 2, {
610
622
  message: "Tolerance must not be greater than half of value range",
611
623
  path: ["tolerance"]
612
- }), it = R.extend({
624
+ }), at = R.extend({
613
625
  type: e.literal("pin-on-image"),
614
626
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
615
627
  targetAsset: C,
616
- hotspots: e.array(Re).min(1, "Must have at least 1 hotspot"),
628
+ hotspots: e.array(ze).min(1, "Must have at least 1 hotspot"),
617
629
  multipleCorrect: e.boolean().optional(),
618
630
  minCorrect: e.number().int().positive().optional()
619
631
  }).refine((e) => e.minCorrect ? e.minCorrect <= e.hotspots.length : !0, {
620
632
  message: "Minimum correct answers must not exceed number of hotspots",
621
633
  path: ["minCorrect"]
622
- }), at = R.extend({
634
+ }), ot = R.extend({
623
635
  type: e.literal("categorize"),
624
636
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
625
637
  categories: e.array(w).min(2, "Must have at least 2 categories"),
@@ -630,12 +642,12 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
630
642
  }).refine((e) => e.items.every((t) => t.correctCategoryIndex < e.categories.length), {
631
643
  message: "Some item references non-existent category",
632
644
  path: ["items"]
633
- }), ot = R.extend({
645
+ }), st = R.extend({
634
646
  type: e.literal("timeline"),
635
647
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
636
648
  events: e.array(He).min(2, "Must have at least 2 events"),
637
649
  randomize: e.boolean().optional()
638
- }), st = R.extend({
650
+ }), ct = R.extend({
639
651
  type: e.literal("matrix"),
640
652
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
641
653
  rows: e.array(w).min(1, "Must have at least 1 row"),
@@ -658,13 +670,13 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
658
670
  }, {
659
671
  message: "If multiplePerRow is false, each row may have maximum 1 correct cell",
660
672
  path: ["correctCells"]
661
- }), ct = R.extend({
673
+ }), lt = R.extend({
662
674
  type: e.literal("math-input"),
663
675
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
664
676
  correctAnswer: w,
665
677
  alternativeAnswers: e.array(w).optional(),
666
678
  tolerance: e.number().nonnegative().optional()
667
- }), lt = R.extend({
679
+ }), ut = R.extend({
668
680
  type: e.literal("diagram-label"),
669
681
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
670
682
  targetAsset: C,
@@ -675,42 +687,41 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
675
687
  }).refine((e) => e.zones.every((t) => t.correctLabelIndex < e.labels.length), {
676
688
  message: "Some zone references non-existent label",
677
689
  path: ["zones"]
678
- }), ut = R.extend({
690
+ }), dt = R.extend({
679
691
  type: e.literal("open-ended"),
680
692
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
681
693
  minWords: e.number().int().positive().optional(),
682
694
  maxWords: e.number().int().positive().optional(),
683
695
  sampleAnswer: T.optional(),
684
- rubric: We.optional()
696
+ rubric: Ge.optional()
685
697
  }).refine((e) => e.minWords && e.maxWords ? e.minWords <= e.maxWords : !0, {
686
698
  message: "Minimum word count must be less than or equal to maximum",
687
699
  path: ["maxWords"]
688
- }), dt = R.extend({
700
+ }), ft = R.extend({
689
701
  type: e.literal("numeric-input"),
690
702
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
691
703
  value: e.number(),
692
704
  tolerance: e.number().nonnegative().optional(),
693
- range: Ge.optional(),
705
+ range: Ke.optional(),
694
706
  unit: e.string().optional()
695
- }), ft = R.extend({
707
+ }), pt = R.extend({
696
708
  type: e.literal("pin-on-model"),
697
709
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
698
710
  targetAsset: C,
699
711
  hotspots: e.array(H).min(1, "Must have at least 1 hotspot"),
700
712
  multipleCorrect: e.boolean().optional(),
701
713
  minCorrect: e.number().int().positive().optional(),
702
- camera: ze.optional()
714
+ camera: W.optional()
703
715
  }).refine((e) => e.minCorrect ? e.minCorrect <= e.hotspots.length : !0, {
704
716
  message: "Minimum correct answers must not exceed number of hotspots",
705
717
  path: ["minCorrect"]
706
- }), pt = R.extend({
718
+ }), mt = R.extend({
707
719
  type: e.literal("chess-puzzle"),
708
720
  question: T.max(1e4, "Question must not be longer than 10000 characters"),
709
721
  fen: w,
710
722
  answers: e.array(e.array(w).min(1, "Move sequence must not be empty")).min(1, "Must have at least 1 correct move sequence"),
711
723
  elo: e.number().int().nonnegative("ELO must be non-negative integer").optional()
712
724
  }), G = e.discriminatedUnion("type", [
713
- Ke,
714
725
  qe,
715
726
  Je,
716
727
  Ye,
@@ -731,7 +742,8 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
731
742
  ut,
732
743
  dt,
733
744
  ft,
734
- pt
745
+ pt,
746
+ mt
735
747
  ]), K = e.object({
736
748
  $schema: e.string().url().optional(),
737
749
  version: e.string().regex(/^\d+\.\d+$/, "Version must be in MAJOR.MINOR format (e.g. \"0.1\")"),
@@ -764,7 +776,7 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
764
776
  message: "Some item references non-existent source material",
765
777
  path: ["items"]
766
778
  });
767
- function mt(t) {
779
+ function ht(t) {
768
780
  let n = t instanceof Error ? t.message : "OQSE Security Error: Maximum nesting depth exceeded limit of 10 levels.";
769
781
  return new e.ZodError([{
770
782
  code: e.ZodIssueCode.custom,
@@ -772,16 +784,16 @@ function mt(t) {
772
784
  path: []
773
785
  }]);
774
786
  }
775
- function ht(e) {
787
+ function gt(e) {
776
788
  return _(e, 10), K.parse(e);
777
789
  }
778
- function gt(e) {
790
+ function _t(e) {
779
791
  try {
780
792
  _(e, 10);
781
793
  } catch (e) {
782
794
  return {
783
795
  success: !1,
784
- error: mt(e)
796
+ error: ht(e)
785
797
  };
786
798
  }
787
799
  let t = K.safeParse(e);
@@ -793,16 +805,16 @@ function gt(e) {
793
805
  error: t.error
794
806
  };
795
807
  }
796
- function _t(e) {
808
+ function vt(e) {
797
809
  return _(e, 10), G.parse(e);
798
810
  }
799
- function vt(e) {
811
+ function yt(e) {
800
812
  try {
801
813
  _(e, 10);
802
814
  } catch (e) {
803
815
  return {
804
816
  success: !1,
805
- error: mt(e)
817
+ error: ht(e)
806
818
  };
807
819
  }
808
820
  let t = G.safeParse(e);
@@ -814,18 +826,6 @@ function vt(e) {
814
826
  error: t.error
815
827
  };
816
828
  }
817
- function yt(e) {
818
- return e.issues.map((e) => {
819
- let t = "";
820
- return e.path.forEach((n, r) => {
821
- if (typeof n == "number") t += `[${n}]`;
822
- else {
823
- let i = r === 0 || typeof e.path[r - 1] == "number";
824
- t += (i ? "" : ".") + String(n);
825
- }
826
- }), t ? `${t}: ${e.message}` : e.message;
827
- });
828
- }
829
829
  //#endregion
830
830
  //#region src/manifestValidation.ts
831
831
  var q = e.string().min(1, "Value must not be empty").trim(), bt = e.string().regex(/^[a-zA-Z]{2,8}(-[a-zA-Z0-9\-]+)*$/, "Must be a valid BCP 47 locale (e.g., \"en\", \"cs\")"), J = e.string().url("Must be a valid absolute URL").refine((e) => e.startsWith("http://") || e.startsWith("https://"), { message: "URL must use http or https scheme" }), xt = e.string().regex(/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, "Must be a valid URN UUID (urn:uuid:...)"), Y = e.string().regex(/^\d+\.\d+$/, "Version must be in MAJOR.MINOR format (e.g. \"0.1\")"), St = [
@@ -917,24 +917,18 @@ function Lt(e) {
917
917
  return Z.safeParse(e);
918
918
  }
919
919
  function Rt(e) {
920
- return e.issues.map((e) => {
921
- let t = e.path.map((e) => String(e)).join(".");
922
- return t ? `${t}: ${e.message}` : e.message;
923
- }).join("\n");
924
- }
925
- function zt(e) {
926
920
  return Z.safeParse(e).success;
927
921
  }
928
922
  //#endregion
929
923
  //#region src/progressValidation.ts
930
- var Bt = e.object({
924
+ var zt = e.object({
931
925
  attempts: e.number().int().nonnegative(),
932
926
  incorrect: e.number().int().nonnegative(),
933
927
  streak: e.number().int().nonnegative()
934
928
  }).refine((e) => e.incorrect <= e.attempts, {
935
929
  message: "incorrect cannot be higher than attempts",
936
930
  path: ["incorrect"]
937
- }), Vt = e.object({
931
+ }), Bt = e.object({
938
932
  isCorrect: e.boolean(),
939
933
  confidence: e.union([
940
934
  e.literal(1),
@@ -946,7 +940,7 @@ var Bt = e.object({
946
940
  timeSpent: e.number().int().nonnegative().optional(),
947
941
  hintsUsed: e.number().int().nonnegative().default(0),
948
942
  isSkipped: e.boolean().optional()
949
- }), Ht = e.object({
943
+ }), Vt = e.object({
950
944
  bucket: e.union([
951
945
  e.literal(0),
952
946
  e.literal(1),
@@ -955,23 +949,23 @@ var Bt = e.object({
955
949
  e.literal(4)
956
950
  ]),
957
951
  nextReviewAt: x.optional(),
958
- stats: Bt,
959
- lastAnswer: Vt.optional(),
952
+ stats: zt,
953
+ lastAnswer: Bt.optional(),
960
954
  appSpecific: e.record(e.string(), e.unknown()).optional()
961
- }), Ut = e.object({
955
+ }), Ht = e.object({
962
956
  setId: v,
963
957
  exportedAt: x,
964
958
  algorithm: e.string().regex(/^[a-z0-9-]+$/, "algorithm must be lowercase alphanumeric with hyphens format").optional()
965
959
  }), Q = e.object({
966
960
  $schema: e.url().optional(),
967
961
  version: e.string().regex(/^\d+\.\d+$/, "Version must be in MAJOR.MINOR format"),
968
- meta: Ut,
969
- records: e.record(v, Ht)
962
+ meta: Ht,
963
+ records: e.record(v, Vt)
970
964
  });
971
- function Wt(e) {
965
+ function Ut(e) {
972
966
  return Q.parse(e);
973
967
  }
974
- function Gt(e) {
968
+ function Wt(e) {
975
969
  return Q.safeParse(e);
976
970
  }
977
971
  var $ = e.object(L.shape).pick({
@@ -990,15 +984,15 @@ var $ = e.object(L.shape).pick({
990
984
  url: S,
991
985
  $schema: e.string().url().optional()
992
986
  });
993
- function Kt(e) {
987
+ function Gt(e) {
994
988
  return $.parse(e);
995
989
  }
996
- function qt(e) {
990
+ function Kt(e) {
997
991
  return $.safeParse(e);
998
992
  }
999
993
  //#endregion
1000
994
  //#region src/richTextProcessor.ts
1001
- function Jt(e) {
995
+ function qt(e) {
1002
996
  let t = {};
1003
997
  return {
1004
998
  text: e.replace(/<(asset|blank):([a-zA-Z0-9_-]+)\s*\/>/gi, (e, n, r) => {
@@ -1012,11 +1006,11 @@ function Jt(e) {
1012
1006
  tokens: t
1013
1007
  };
1014
1008
  }
1015
- function Yt(e) {
1009
+ function Jt(e) {
1016
1010
  let t = e.replace(/`{1,}[^`]*`{1,}/g, "").replace(/~{3,}[\s\S]*?~{3,}/g, "");
1017
1011
  if (/<[a-zA-Z\/][^>]*>/.test(t)) throw Error("OQSE Security Error: Raw HTML tags are not allowed in Tier 1 (Pure Markdown). If the set requires HTML formatting, it MUST declare the 'html' feature in meta.requirements.");
1018
1012
  }
1019
- function Xt(e, t, n) {
1013
+ function Yt(e, t, n) {
1020
1014
  let r = e;
1021
1015
  for (let [e, i] of Object.entries(t)) {
1022
1016
  let t = i.originalTag;
@@ -1024,16 +1018,16 @@ function Xt(e, t, n) {
1024
1018
  }
1025
1019
  return r;
1026
1020
  }
1027
- function Zt(e, t, n) {
1021
+ function Xt(e, t, n) {
1028
1022
  if (!e) return "";
1029
- let r = t?.features?.includes("html") ?? !1, { text: i, tokens: a } = Jt(e);
1030
- r || Yt(i);
1023
+ let r = t?.features?.includes("html") ?? !1, { text: i, tokens: a } = qt(e);
1024
+ r || Jt(i);
1031
1025
  let o = n.markdownParser(i);
1032
1026
  if (r) {
1033
1027
  if (!n.htmlSanitizer) throw Error("OQSE Security Error: Set requires 'html' (Tier 2), but no htmlSanitizer (like DOMPurify) was provided to the options.");
1034
1028
  o = n.htmlSanitizer(o);
1035
1029
  }
1036
- return Xt(o, a, n);
1030
+ return Yt(o, a, n);
1037
1031
  }
1038
1032
  //#endregion
1039
- export { S as AbsoluteURLSchema, A as AssetDictionarySchema, C as AssetKeySchema, jt as AudioMimeTypeSchema, R as BaseItemSchema, D as BlankTokenSchema, Ne as BloomLevelSchema, ze as CameraSetupSchema, Be as CategorizeItemObjectSchema, at as CategorizeItemSchema, pt as ChessPuzzleItemSchema, B as CircleHotspotSchema, Pe as CognitiveLoadSchema, lt as DiagramLabelItemSchema, Ue as DiagramZoneSchema, Dt as FeatureFlagSchema, F as FeatureProfileSchema, Qe as FillInBlanksItemSchema, $e as FillInSelectItemSchema, qe as FlashcardItemSchema, Re as Hotspot2DSchema, Le as HotspotObjectSchema, x as ISO8601DateTimeSchema, At as ImageMimeTypeSchema, Ot as ItemPropertyKeySchema, y as LanguageCodeSchema, Vt as LastAnswerObjectSchema, I as LinkedSetObjectSchema, Xe as MCQMultiItemSchema, Ye as MCQSingleItemSchema, Pt as ManifestAssetsSchema, Ft as ManifestCapabilitiesSchema, tt as MatchComplexItemSchema, et as MatchPairsItemSchema, ct as MathInputItemSchema, st as MatrixItemSchema, k as MediaObjectSchema, H as MeshHotspotSchema, kt as MetaPropertyKeySchema, Nt as ModelMimeTypeSchema, Ke as NoteItemSchema, dt as NumericInputItemSchema, Ge as NumericRangeSchema, c as OFFICIAL_ACTIONS, l as OFFICIAL_FEATURE_KEYS, u as OFFICIAL_ITEM_PROPERTIES, d as OFFICIAL_META_PROPERTIES, wt as OQSEActionSchema, K as OQSEFileSchema, $ as OQSEHeaderSchema, G as OQSEItemSchema, Z as OQSEManifestSchema, L as OQSEMetaSchema, Q as OQSEPFileSchema, Et as OQSEQuestionDensitySchema, Tt as OQSEStudyModeSchema, ut as OpenEndedItemSchema, E as OptionalRichContentSchema, Fe as PedagogySchema, j as PersonObjectSchema, it as PinOnImageItemSchema, ft as PinOnModelItemSchema, w as PlainTextSchema, V as PolygonHotspotSchema, Ut as ProgressMetaSchema, Ht as ProgressRecordSchema, z as RectHotspotSchema, T as RichContentSchema, W as RubricCriterionSchema, We as RubricSchema, b as SPDXLicenseSchema, Ie as SelectBlankObjectSchema, Ze as ShortAnswerItemSchema, rt as SliderItemSchema, nt as SortItemsItemSchema, N as SourceMaterialSchema, M as SourceMaterialTypeSchema, P as SourceReferenceSchema, Bt as StatsObjectSchema, O as SubtitleTrackSchema, je as TagDefinitionDictionarySchema, Ae as TagDefinitionSchema, He as TimelineEventSchema, ot as TimelineItemSchema, Ve as TimelinePrecisionSchema, Me as TranslationObjectSchema, Je as TrueFalseItemSchema, v as UUIDSchema, U as Vector3Schema, Mt as VideoMimeTypeSchema, p as compareManifestVersions, Xt as detokenizeOqseTags, Rt as formatManifestErrors, yt as formatValidationErrors, ke as generateUUID, se as isCategorize, he as isChessPuzzle, s as isCoreItem, de as isDiagramLabel, ge as isExtendedItem, ee as isFillInBlanks, te as isFillInSelect, n as isFlashcard, a as isMCQMulti, i as isMCQSingle, re as isMatchComplex, ne as isMatchPairs, ue as isMathInput, le as isMatrix, t as isNote, pe as isNumericInput, ve as isOQSEManifest, fe as isOpenEnded, oe as isPinOnImage, me as isPinOnModel, o as isShortAnswer, ae as isSlider, ie as isSortItems, ce as isTimeline, r as isTrueFalse, f as isValidManifestVersion, zt as isValidOQSEManifest, _e as isValidSemVer, Oe as isValidUUID, ye as isVersionCompatible, Zt as prepareRichTextForDisplay, Lt as safeValidateManifest, gt as safeValidateOQSEFile, qt as safeValidateOQSEHeader, vt as safeValidateOQSEItem, Gt as safeValidateOQSEPFile, Jt as tokenizeOqseTags, _ as validateJsonDepth, It as validateManifest, ht as validateOQSEFile, Kt as validateOQSEHeader, _t as validateOQSEItem, Wt as validateOQSEPFile, Yt as validateTier1Markdown };
1033
+ export { S as AbsoluteURLSchema, A as AssetDictionarySchema, C as AssetKeySchema, jt as AudioMimeTypeSchema, R as BaseItemSchema, D as BlankTokenSchema, Pe as BloomLevelSchema, W as CameraSetupSchema, Be as CategorizeItemObjectSchema, ot as CategorizeItemSchema, mt as ChessPuzzleItemSchema, B as CircleHotspotSchema, Fe as CognitiveLoadSchema, ut as DiagramLabelItemSchema, Ue as DiagramZoneSchema, Dt as FeatureFlagSchema, F as FeatureProfileSchema, $e as FillInBlanksItemSchema, et as FillInSelectItemSchema, Je as FlashcardItemSchema, ze as Hotspot2DSchema, Re as HotspotObjectSchema, x as ISO8601DateTimeSchema, At as ImageMimeTypeSchema, Ot as ItemPropertyKeySchema, y as LanguageCodeSchema, Bt as LastAnswerObjectSchema, I as LinkedSetObjectSchema, Ze as MCQMultiItemSchema, Xe as MCQSingleItemSchema, Pt as ManifestAssetsSchema, Ft as ManifestCapabilitiesSchema, nt as MatchComplexItemSchema, tt as MatchPairsItemSchema, lt as MathInputItemSchema, ct as MatrixItemSchema, k as MediaObjectSchema, H as MeshHotspotSchema, kt as MetaPropertyKeySchema, Nt as ModelMimeTypeSchema, qe as NoteItemSchema, ft as NumericInputItemSchema, Ke as NumericRangeSchema, c as OFFICIAL_ACTIONS, l as OFFICIAL_FEATURE_KEYS, u as OFFICIAL_ITEM_PROPERTIES, d as OFFICIAL_META_PROPERTIES, wt as OQSEActionSchema, K as OQSEFileSchema, $ as OQSEHeaderSchema, G as OQSEItemSchema, Z as OQSEManifestSchema, L as OQSEMetaSchema, Q as OQSEProgressSchema, Et as OQSEQuestionDensitySchema, Tt as OQSEStudyModeSchema, dt as OpenEndedItemSchema, E as OptionalRichContentSchema, Ie as PedagogySchema, j as PersonObjectSchema, at as PinOnImageItemSchema, pt as PinOnModelItemSchema, w as PlainTextSchema, V as PolygonHotspotSchema, Ht as ProgressMetaSchema, Vt as ProgressRecordSchema, z as RectHotspotSchema, T as RichContentSchema, We as RubricCriterionSchema, Ge as RubricSchema, b as SPDXLicenseSchema, Le as SelectBlankObjectSchema, Qe as ShortAnswerItemSchema, it as SliderItemSchema, rt as SortItemsItemSchema, N as SourceMaterialSchema, M as SourceMaterialTypeSchema, P as SourceReferenceSchema, zt as StatsObjectSchema, O as SubtitleTrackSchema, Me as TagDefinitionDictionarySchema, je as TagDefinitionSchema, He as TimelineEventSchema, st as TimelineItemSchema, Ve as TimelinePrecisionSchema, Ne as TranslationObjectSchema, Ye as TrueFalseItemSchema, v as UUIDSchema, U as Vector3Schema, Mt as VideoMimeTypeSchema, p as compareManifestVersions, Yt as detokenizeOqseTags, Ae as formatOQSEErrors, ke as generateUUID, se as isCategorize, he as isChessPuzzle, s as isCoreItem, de as isDiagramLabel, ge as isExtendedItem, ee as isFillInBlanks, te as isFillInSelect, n as isFlashcard, a as isMCQMulti, i as isMCQSingle, re as isMatchComplex, ne as isMatchPairs, ue as isMathInput, le as isMatrix, t as isNote, pe as isNumericInput, ve as isOQSEManifest, fe as isOpenEnded, oe as isPinOnImage, me as isPinOnModel, o as isShortAnswer, ae as isSlider, ie as isSortItems, ce as isTimeline, r as isTrueFalse, f as isValidManifestVersion, Rt as isValidOQSEManifest, _e as isValidSemVer, Oe as isValidUUID, ye as isVersionCompatible, Xt as prepareRichTextForDisplay, _t as safeValidateOQSEFile, Kt as safeValidateOQSEHeader, yt as safeValidateOQSEItem, Lt as safeValidateOQSEManifest, Wt as safeValidateOQSEProgress, qt as tokenizeOqseTags, _ as validateJsonDepth, gt as validateOQSEFile, Gt as validateOQSEHeader, vt as validateOQSEItem, It as validateOQSEManifest, Ut as validateOQSEProgress, Jt as validateTier1Markdown };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -132,11 +132,11 @@ export declare const OQSEManifestSchema: z.ZodObject<{
132
132
  *
133
133
  * @example
134
134
  * ```ts
135
- * const manifest = validateManifest(JSON.parse(rawJson));
135
+ * const manifest = validateOQSEManifest(JSON.parse(rawJson));
136
136
  * manifest.capabilities.actions; // string[]
137
137
  * ```
138
138
  */
139
- export declare function validateManifest(data: unknown): OQSEManifest;
139
+ export declare function validateOQSEManifest(data: unknown): OQSEManifest;
140
140
  /**
141
141
  * Safely validates an unknown value without throwing.
142
142
  *
@@ -145,34 +145,17 @@ export declare function validateManifest(data: unknown): OQSEManifest;
145
145
  *
146
146
  * @example
147
147
  * ```ts
148
- * const result = safeValidateManifest(raw);
148
+ * const result = safeValidateOQSEManifest(raw);
149
149
  * if (result.success) {
150
150
  * console.log(result.data.id);
151
- * } else {
152
- * console.error(formatManifestErrors(result.error));
153
151
  * }
154
152
  * ```
155
153
  */
156
- export declare function safeValidateManifest(data: unknown): ReturnType<typeof OQSEManifestSchema.safeParse>;
157
- /**
158
- * Formats a `ZodError` from manifest validation into a human-readable string.
159
- *
160
- * @param error - A `ZodError` returned by `safeValidateManifest`.
161
- * @returns A newline-separated string listing each validation issue with its path.
162
- *
163
- * @example
164
- * ```ts
165
- * console.error(formatManifestErrors(result.error));
166
- * // Example output:
167
- * // "id: ID must be an absolute URL or a URN-format UUID (urn:uuid:...)"
168
- * // "capabilities.actions: Application must support at least one action"
169
- * ```
170
- */
171
- export declare function formatManifestErrors(error: z.ZodError): string;
154
+ export declare function safeValidateOQSEManifest(data: unknown): ReturnType<typeof OQSEManifestSchema.safeParse>;
172
155
  /**
173
156
  * Checks whether a plain object looks like an OQSE Manifest (duck-typing).
174
157
  *
175
- * This is a fast pre-check - use `validateManifest` for full validation.
158
+ * This is a fast pre-check - use `validateOQSEManifest` for full validation.
176
159
  *
177
160
  * @param data - Any value.
178
161
  * @returns `true` if `data` has the minimum required shape.
@@ -6131,7 +6131,3 @@ export declare function safeValidateOQSEItem(data: unknown): {
6131
6131
  data?: OQSEItem;
6132
6132
  error?: z.ZodError;
6133
6133
  };
6134
- /**
6135
- * Formats Zod validation errors into human-readable messages
6136
- */
6137
- export declare function formatValidationErrors(error: z.ZodError): string[];
@@ -34,7 +34,7 @@ export interface ProgressMeta {
34
34
  algorithm?: string;
35
35
  }
36
36
  /** Root OQSEP payload for one user and one study set. */
37
- export interface OQSEPFile {
37
+ export interface OQSEProgress {
38
38
  $schema?: string;
39
39
  version: string;
40
40
  meta: ProgressMeta;
@@ -1,9 +1,9 @@
1
1
  import { z } from 'zod';
2
- import { LastAnswerObject, OQSEPFile, ProgressMeta, ProgressRecord, StatsObject } from './progress';
2
+ import { LastAnswerObject, OQSEProgress, ProgressMeta, ProgressRecord, StatsObject } from './progress';
3
3
  export declare const StatsObjectSchema: z.ZodType<StatsObject>;
4
4
  export declare const LastAnswerObjectSchema: z.ZodType<LastAnswerObject>;
5
5
  export declare const ProgressRecordSchema: z.ZodType<ProgressRecord>;
6
6
  export declare const ProgressMetaSchema: z.ZodType<ProgressMeta>;
7
- export declare const OQSEPFileSchema: z.ZodType<OQSEPFile>;
8
- export declare function validateOQSEPFile(data: unknown): OQSEPFile;
9
- export declare function safeValidateOQSEPFile(data: unknown): ReturnType<typeof OQSEPFileSchema.safeParse>;
7
+ export declare const OQSEProgressSchema: z.ZodType<OQSEProgress>;
8
+ export declare function validateOQSEProgress(data: unknown): OQSEProgress;
9
+ export declare function safeValidateOQSEProgress(data: unknown): ReturnType<typeof OQSEProgressSchema.safeParse>;
@@ -1,3 +1,4 @@
1
+ import { ZodError } from 'zod';
1
2
  export type UUID = string;
2
3
  /**
3
4
  * Validates if the given string is a syntactically valid UUID (any version).
@@ -15,3 +16,8 @@ export declare function generateUUID(): UUID;
15
16
  * OQSE specification requires a limit of 10 levels for customData and appSpecific.
16
17
  */
17
18
  export declare function validateJsonDepth(data: unknown, maxDepth?: number, currentDepth?: number): void;
19
+ /**
20
+ * Formats a ZodError into a flat array of human-readable string messages.
21
+ * Useful for displaying validation issues in UI lists or console logs.
22
+ */
23
+ export declare function formatOQSEErrors(error: ZodError): string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memizy/oqse",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "TypeScript SDK and Zod validators for the OQSE specification.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -29,6 +29,7 @@
29
29
  "prepublishOnly": "npm run build"
30
30
  },
31
31
  "devDependencies": {
32
+ "@types/node": "^25.6.0",
32
33
  "@types/uuid": "^10.0.0",
33
34
  "tsx": "^4.21.0",
34
35
  "typescript": "~6.0.2",