@memizy/oqse 0.1.3 → 0.1.5

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 Ce=new Uint8Array(16);function we(){return crypto.getRandomValues(Ce)}var h={};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(h,e,i),r=De(i,h.msecs,h.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 g(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)g(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 _=e.z.string().uuid({message:`Invalid UUID format`}),v=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")`),y=e.z.string().min(1,`License identifier must not be empty`),b=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")`),x=e.z.string().url({message:`Must be a valid absolute URL`}),S=e.z.string().regex(/^[a-z0-9_-]+$/,`Asset key must contain only lowercase letters, numbers, hyphens and underscores`),C=e.z.string().min(1,`Text must not be empty`),w=e.z.string().min(1,`Content must not be empty`),T=e.z.string().max(1e4,`Question must not be longer than 10000 characters`).optional(),E=e.z.string().regex(/^[a-zA-Z0-9_-]{1,64}$/,`Token must be alphanumeric, max 64 chars`),D=e.z.object({lang:v,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()}),O=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:w.optional(),caption:w.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(D).optional(),license:y.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`]}),k=e.z.record(S,O),A=e.z.object({name:C,role:e.z.string().optional(),email:e.z.string().email(`Invalid email format`).optional(),url:x.optional()}),j=e.z.enum([`url`,`doi`,`isbn`,`pdf`,`textbook`,`video`,`audio`,`image`,`model`,`other`]),M=e.z.object({id:C,type:j,value:C,title:C,description:e.z.string().optional(),authors:e.z.array(C).optional(),publishedDate:b.optional(),retrievedAt:b.optional(),license:y.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`]}),N=e.z.object({id:C,location:e.z.string().optional(),quote:w.optional()}),P=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(),P),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:v,id:_,title:C,downloadUrl:x.optional()}),I=e.z.object({id:_,title:C,downloadUrl:x.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:_,language:v,title:C.max(500,`Title must not be longer than 500 characters`),description:w.max(5e3,`Description must not be longer than 5000 characters`).optional(),thumbnail:S.optional(),assets:k.optional(),ageMin:e.z.number().int().nonnegative().optional(),ageMax:e.z.number().int().nonnegative().optional(),subject:e.z.string().optional(),createdAt:b,updatedAt:b,author:A.optional(),contributors:e.z.array(A).optional(),license:y.optional(),licenseUrl:x.optional(),requirements:F.optional(),tags:e.z.array(C).optional(),tagDefinitions:je.optional(),translations:e.z.array(Me).optional(),sourceMaterials:e.z.array(M).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:_,type:e.z.string(),assets:k.optional(),lang:v.optional(),tags:e.z.array(C).optional(),topic:C.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(w.max(2e3,`Hint must not be longer than 2000 characters`)).max(20,`Maximum 20 hints per item`).optional(),explanation:w.max(1e4,`Explanation must not be longer than 10000 characters`).optional(),incorrectFeedback:w.optional(),sources:e.z.array(N).optional(),relatedItems:e.z.array(_).optional(),dependencyItems:e.z.array(_).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(w).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:C}),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:C,text:w,correctCategoryIndex:e.z.number().int().nonnegative()}),Ve=e.z.enum([`year`,`month`,`day`,`datetime`]),He=e.z.object({id:C,text:w,date:b,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:C,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`]}),W=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:w.max(1e4,`Content must not be longer than 10000 characters`),hiddenContent:w.max(1e4,`Content must not be longer than 10000 characters`).optional()}),qe=R.extend({type:e.z.literal(`flashcard`),front:w.max(1e4,`Front side must not be longer than 10000 characters`),back:w.max(1e4,`Back side must not be longer than 10000 characters`)}),Je=R.extend({type:e.z.literal(`true-false`),question:w.max(1e4,`Question must not be longer than 10000 characters`),answer:e.z.boolean()}),Ye=R.extend({type:e.z.literal(`mcq-single`),question:w.max(1e4,`Question must not be longer than 10000 characters`),options:e.z.array(w.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([w,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:w.max(1e4,`Question must not be longer than 10000 characters`),options:e.z.array(w.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([w,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:w.max(1e4,`Question must not be longer than 10000 characters`),answers:e.z.array(C).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:T,text:w.max(1e4,`Text must not be longer than 10000 characters`),blanks:e.z.record(E,e.z.array(C).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:T,text:w.max(1e4,`Text must not be longer than 10000 characters`),blanks:e.z.record(E,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:T,prompts:e.z.array(w).min(2,`Must have at least 2 pairs to match`).max(100,`Maximum 100 pairs`),matches:e.z.array(w).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:T,leftItems:e.z.array(w).min(1,`Must have at least 1 item on left`),rightItems:e.z.array(w).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:w.max(1e4,`Question must not be longer than 10000 characters`),items:e.z.array(w).min(2,`Must have at least 2 items to sort`)}),rt=R.extend({type:e.z.literal(`slider`),question:w.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:w.max(1e4,`Question must not be longer than 10000 characters`),targetAsset:S,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:w.max(1e4,`Question must not be longer than 10000 characters`),categories:e.z.array(C).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:w.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:w.max(1e4,`Question must not be longer than 10000 characters`),rows:e.z.array(C).min(1,`Must have at least 1 row`),columns:e.z.array(C).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:w.max(1e4,`Question must not be longer than 10000 characters`),correctAnswer:C,alternativeAnswers:e.z.array(C).optional(),tolerance:e.z.number().nonnegative().optional()}),lt=R.extend({type:e.z.literal(`diagram-label`),question:w.max(1e4,`Question must not be longer than 10000 characters`),targetAsset:S,labels:e.z.array(w).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:w.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:w.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`]}),dt=R.extend({type:e.z.literal(`numeric-input`),question:w.max(1e4,`Question must not be longer than 10000 characters`),value:e.z.number(),tolerance:e.z.number().nonnegative().optional(),range:W.optional(),unit:e.z.string().optional()}),ft=R.extend({type:e.z.literal(`pin-on-model`),question:w.max(1e4,`Question must not be longer than 10000 characters`),targetAsset:S,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:w.max(1e4,`Question must not be longer than 10000 characters`),fen:C,answers:e.z.array(e.z.array(C).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 g(e,10),K.parse(e)}function gt(e){try{g(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 g(e,10),G.parse(e)}function vt(e){try{g(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}}var q=e.z.string().min(1,`Value must not be empty`).trim(),yt=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`}),bt=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")`),xt=[`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`],St=q.refine(e=>xt.includes(e)||e.startsWith(`x-`),{message:`Custom types MUST use the "x-" prefix`}),Ct=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-"`}),wt=e.z.enum([`game`,`fun`,`drill`]),Tt=e.z.enum([`low`,`medium`,`high`]),Et=e.z.string().refine(e=>l.includes(e)||e.startsWith(`x-`),{message:`Feature must be one of official keys or have prefix "x-"`}),Dt=e.z.string().refine(e=>u.includes(e)||e.startsWith(`x-`),{message:`Item property must be an official key or have prefix "x-"`}),Ot=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 kt=e.z.string().refine(e=>e.startsWith(`image/`),{message:`Must be a valid image MIME type (image/...)`}),At=e.z.string().refine(e=>e.startsWith(`audio/`),{message:`Must be a valid audio MIME type (audio/...)`}),jt=e.z.string().refine(e=>e.startsWith(`video/`),{message:`Must be a valid video MIME type (video/...)`}),Mt=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)`}),Nt=e.z.object({image:X(kt).optional(),audio:X(At).optional(),video:X(jt).optional(),model:X(Mt).optional()}),Pt=F.extend({actions:e.z.array(Ct).min(1,`Application must support at least one action`),types:X(St).optional(),assets:Nt.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,bt]),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:Pt,author:A.optional(),contributors:e.z.array(A).optional(),license:e.z.string().max(100,`License must not be longer than 100 characters`).optional(),licenseUrl:J.optional(),locales:e.z.array(yt).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:wt.optional(),questionDensity:Tt.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 Ft(e){return Z.parse(e)}function It(e){return Z.safeParse(e)}function Lt(e){return Z.safeParse(e).success}var Rt=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`]}),zt=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:b,timeSpent:e.z.number().int().nonnegative().optional(),hintsUsed:e.z.number().int().nonnegative().default(0),isSkipped:e.z.boolean().optional()}),Bt=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:b.optional(),stats:Rt,lastAnswer:zt.optional(),appSpecific:e.z.record(e.z.string(),e.z.unknown()).optional()}),Vt=e.z.object({setId:_,exportedAt:b,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:Vt,records:e.z.record(_,Bt)});function Ht(e){return Q.parse(e)}function Ut(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:x,$schema:e.z.string().url().optional()});function Wt(e){return $.parse(e)}function Gt(e){return $.safeParse(e)}function Kt(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 qt(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 Jt(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 Yt(e,t,n){if(!e)return``;let r=t?.features?.includes(`html`)??!1,{text:i,tokens:a}=Kt(e);r||qt(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 Jt(o,a,n)}exports.AbsoluteURLSchema=x,exports.AssetDictionarySchema=k,exports.AssetKeySchema=S,exports.AudioMimeTypeSchema=At,exports.BaseItemSchema=R,exports.BlankTokenSchema=E,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=Et,exports.FeatureProfileSchema=F,exports.FillInBlanksItemSchema=Qe,exports.FillInSelectItemSchema=$e,exports.FlashcardItemSchema=qe,exports.Hotspot2DSchema=Re,exports.HotspotObjectSchema=Le,exports.ISO8601DateTimeSchema=b,exports.ImageMimeTypeSchema=kt,exports.ItemPropertyKeySchema=Dt,exports.LanguageCodeSchema=v,exports.LastAnswerObjectSchema=zt,exports.LinkedSetObjectSchema=I,exports.MCQMultiItemSchema=Xe,exports.MCQSingleItemSchema=Ye,exports.ManifestAssetsSchema=Nt,exports.ManifestCapabilitiesSchema=Pt,exports.MatchComplexItemSchema=tt,exports.MatchPairsItemSchema=et,exports.MathInputItemSchema=ct,exports.MatrixItemSchema=st,exports.MediaObjectSchema=O,exports.MeshHotspotSchema=H,exports.MetaPropertyKeySchema=Ot,exports.ModelMimeTypeSchema=Mt,exports.NoteItemSchema=Ke,exports.NumericInputItemSchema=dt,exports.NumericRangeSchema=W,exports.OFFICIAL_ACTIONS=c,exports.OFFICIAL_FEATURE_KEYS=l,exports.OFFICIAL_ITEM_PROPERTIES=u,exports.OFFICIAL_META_PROPERTIES=d,exports.OQSEActionSchema=Ct,exports.OQSEFileSchema=K,exports.OQSEHeaderSchema=$,exports.OQSEItemSchema=G,exports.OQSEManifestSchema=Z,exports.OQSEMetaSchema=L,exports.OQSEProgressSchema=Q,exports.OQSEQuestionDensitySchema=Tt,exports.OQSEStudyModeSchema=wt,exports.OpenEndedItemSchema=ut,exports.OptionalRichContentSchema=T,exports.PedagogySchema=Fe,exports.PersonObjectSchema=A,exports.PinOnImageItemSchema=it,exports.PinOnModelItemSchema=ft,exports.PlainTextSchema=C,exports.PolygonHotspotSchema=V,exports.ProgressMetaSchema=Vt,exports.ProgressRecordSchema=Bt,exports.RectHotspotSchema=z,exports.RichContentSchema=w,exports.RubricCriterionSchema=We,exports.RubricSchema=Ge,exports.SPDXLicenseSchema=y,exports.SelectBlankObjectSchema=Ie,exports.ShortAnswerItemSchema=Ze,exports.SliderItemSchema=rt,exports.SortItemsItemSchema=nt,exports.SourceMaterialSchema=M,exports.SourceMaterialTypeSchema=j,exports.SourceReferenceSchema=N,exports.StatsObjectSchema=Rt,exports.SubtitleTrackSchema=D,exports.TagDefinitionDictionarySchema=je,exports.TagDefinitionSchema=P,exports.TimelineEventSchema=He,exports.TimelineItemSchema=ot,exports.TimelinePrecisionSchema=Ve,exports.TranslationObjectSchema=Me,exports.TrueFalseItemSchema=Je,exports.UUIDSchema=_,exports.Vector3Schema=U,exports.VideoMimeTypeSchema=jt,exports.compareManifestVersions=p,exports.detokenizeOqseTags=Jt,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=Lt,exports.isValidSemVer=_e,exports.isValidUUID=Oe,exports.isVersionCompatible=ye,exports.prepareRichTextForDisplay=Yt,exports.safeValidateOQSEFile=gt,exports.safeValidateOQSEHeader=Gt,exports.safeValidateOQSEItem=vt,exports.safeValidateOQSEManifest=It,exports.safeValidateOQSEProgress=Ut,exports.tokenizeOqseTags=Kt,exports.validateJsonDepth=g,exports.validateOQSEFile=ht,exports.validateOQSEHeader=Wt,exports.validateOQSEItem=_t,exports.validateOQSEManifest=Ft,exports.validateOQSEProgress=Ht,exports.validateTier1Markdown=qt;
package/dist/index.js CHANGED
@@ -160,23 +160,19 @@ function Se(e, t = 0) {
160
160
  }
161
161
  //#endregion
162
162
  //#region node_modules/uuid/dist/rng.js
163
- var h, Ce = new Uint8Array(16);
163
+ var Ce = new Uint8Array(16);
164
164
  function we() {
165
- if (!h) {
166
- if (typeof crypto > "u" || !crypto.getRandomValues) throw Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
167
- h = crypto.getRandomValues.bind(crypto);
168
- }
169
- return h(Ce);
165
+ return crypto.getRandomValues(Ce);
170
166
  }
171
167
  //#endregion
172
168
  //#region node_modules/uuid/dist/v7.js
173
- var g = {};
169
+ var h = {};
174
170
  function Te(e, t, n) {
175
171
  let r;
176
172
  if (e) r = De(e.random ?? e.rng?.() ?? we(), e.msecs, e.seq, t, n);
177
173
  else {
178
174
  let e = Date.now(), i = we();
179
- Ee(g, e, i), r = De(i, g.msecs, g.seq, t, n);
175
+ Ee(h, e, i), r = De(i, h.msecs, h.seq, t, n);
180
176
  }
181
177
  return t ?? Se(r);
182
178
  }
@@ -197,17 +193,29 @@ function Oe(e) {
197
193
  function ke() {
198
194
  return Te();
199
195
  }
200
- function _(e, t = 10, n = 0) {
196
+ function g(e, t = 10, n = 0) {
201
197
  if (n > t) throw Error(`OQSE Security Error: Maximum nesting depth exceeded limit of ${t} levels.`);
202
198
  if (typeof e == "object" && e) {
203
199
  let r = Array.isArray(e) ? e : Object.values(e);
204
- for (let e of r) _(e, t, n + 1);
200
+ for (let e of r) g(e, t, n + 1);
205
201
  }
206
202
  }
203
+ function Ae(e) {
204
+ return e.issues.map((e) => {
205
+ let t = "";
206
+ return e.path.forEach((n, r) => {
207
+ if (typeof n == "number") t += `[${n}]`;
208
+ else {
209
+ let i = r === 0 || typeof e.path[r - 1] == "number";
210
+ t += (i ? "" : ".") + String(n);
211
+ }
212
+ }), t ? `${t}: ${e.message}` : e.message;
213
+ });
214
+ }
207
215
  //#endregion
208
216
  //#region src/oqseValidation.ts
209
- 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({
210
- lang: y,
217
+ var _ = e.string().uuid({ message: "Invalid UUID format" }), v = 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\")"), y = e.string().min(1, "License identifier must not be empty"), b = 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\")"), x = e.string().url({ message: "Must be a valid absolute URL" }), S = e.string().regex(/^[a-z0-9_-]+$/, "Asset key must contain only lowercase letters, numbers, hyphens and underscores"), C = e.string().min(1, "Text must not be empty"), w = e.string().min(1, "Content must not be empty"), T = e.string().max(1e4, "Question must not be longer than 10000 characters").optional(), E = e.string().regex(/^[a-zA-Z0-9_-]{1,64}$/, "Token must be alphanumeric, max 64 chars"), D = e.object({
218
+ lang: v,
211
219
  value: e.string().min(1, "Subtitle URI must not be empty").regex(/\.(vtt|srt)(\?.*)?$/i, "Subtitle URI must end with .vtt or .srt"),
212
220
  label: e.string().optional(),
213
221
  kind: e.enum([
@@ -215,7 +223,7 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
215
223
  "subtitles",
216
224
  "descriptions"
217
225
  ]).optional()
218
- }), k = e.object({
226
+ }), O = e.object({
219
227
  type: e.enum([
220
228
  "image",
221
229
  "audio",
@@ -225,15 +233,15 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
225
233
  value: e.string().min(1, "Media URI must not be empty"),
226
234
  mimeType: e.string().optional(),
227
235
  altText: e.string().optional(),
228
- transcript: T.optional(),
229
- caption: T.optional(),
236
+ transcript: w.optional(),
237
+ caption: w.optional(),
230
238
  width: e.number().int().positive().optional(),
231
239
  height: e.number().int().positive().optional(),
232
240
  start: e.number().nonnegative().optional(),
233
241
  end: e.number().positive().optional(),
234
242
  loop: e.boolean().optional(),
235
- subtitles: e.array(O).optional(),
236
- license: b.optional(),
243
+ subtitles: e.array(D).optional(),
244
+ license: y.optional(),
237
245
  attribution: e.string().optional(),
238
246
  checksums: e.record(e.string(), e.string()).optional()
239
247
  }).refine((e) => e.start !== void 0 && e.end !== void 0 ? e.start < e.end : !0, {
@@ -242,12 +250,12 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
242
250
  }).refine((e) => !(e.type === "image" && !e.altText), {
243
251
  message: "Images must have alternative text (altText) defined for accessibility",
244
252
  path: ["altText"]
245
- }), A = e.record(C, k), j = e.object({
246
- name: w,
253
+ }), k = e.record(S, O), A = e.object({
254
+ name: C,
247
255
  role: e.string().optional(),
248
256
  email: e.string().email("Invalid email format").optional(),
249
- url: S.optional()
250
- }), M = e.enum([
257
+ url: x.optional()
258
+ }), j = e.enum([
251
259
  "url",
252
260
  "doi",
253
261
  "isbn",
@@ -258,16 +266,16 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
258
266
  "image",
259
267
  "model",
260
268
  "other"
261
- ]), N = e.object({
262
- id: w,
263
- type: M,
264
- value: w,
265
- title: w,
269
+ ]), M = e.object({
270
+ id: C,
271
+ type: j,
272
+ value: C,
273
+ title: C,
266
274
  description: e.string().optional(),
267
- authors: e.array(w).optional(),
268
- publishedDate: x.optional(),
269
- retrievedAt: x.optional(),
270
- license: b.optional()
275
+ authors: e.array(C).optional(),
276
+ publishedDate: b.optional(),
277
+ retrievedAt: b.optional(),
278
+ license: y.optional()
271
279
  }).refine((e) => {
272
280
  if ([
273
281
  "url",
@@ -284,27 +292,27 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
284
292
  }, {
285
293
  message: "For url, pdf, video, audio and image types, value must be a valid URL",
286
294
  path: ["value"]
287
- }), P = e.object({
288
- id: w,
295
+ }), N = e.object({
296
+ id: C,
289
297
  location: e.string().optional(),
290
- quote: T.optional()
291
- }), Ae = e.object({
298
+ quote: w.optional()
299
+ }), P = e.object({
292
300
  wikidataId: e.string().regex(/^Q\d+$/, "Wikidata ID must have format Q followed by number").optional(),
293
301
  description: e.string().optional()
294
- }), je = e.record(e.string(), Ae), F = e.object({
302
+ }), je = e.record(e.string(), P), F = e.object({
295
303
  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
304
  latexPackages: e.array(e.string().min(1, "Package name must not be empty")).optional(),
297
305
  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
306
  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
307
  }), Me = e.object({
300
- lang: y,
301
- id: v,
302
- title: w,
303
- downloadUrl: S.optional()
308
+ lang: v,
309
+ id: _,
310
+ title: C,
311
+ downloadUrl: x.optional()
304
312
  }), I = e.object({
305
- id: v,
306
- title: w,
307
- downloadUrl: S.optional()
313
+ id: _,
314
+ title: C,
315
+ downloadUrl: x.optional()
308
316
  }), Ne = e.enum([
309
317
  "remember",
310
318
  "understand",
@@ -326,26 +334,26 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
326
334
  partialCredit: e.boolean().optional(),
327
335
  penaltyPerWrong: e.number().min(0).max(1, "Penalty must be between 0 and 1").optional()
328
336
  }), L = e.object({
329
- id: v,
330
- language: y,
331
- title: w.max(500, "Title must not be longer than 500 characters"),
332
- description: T.max(5e3, "Description must not be longer than 5000 characters").optional(),
333
- thumbnail: C.optional(),
334
- assets: A.optional(),
337
+ id: _,
338
+ language: v,
339
+ title: C.max(500, "Title must not be longer than 500 characters"),
340
+ description: w.max(5e3, "Description must not be longer than 5000 characters").optional(),
341
+ thumbnail: S.optional(),
342
+ assets: k.optional(),
335
343
  ageMin: e.number().int().nonnegative().optional(),
336
344
  ageMax: e.number().int().nonnegative().optional(),
337
345
  subject: e.string().optional(),
338
- createdAt: x,
339
- updatedAt: x,
340
- author: j.optional(),
341
- contributors: e.array(j).optional(),
342
- license: b.optional(),
343
- licenseUrl: S.optional(),
346
+ createdAt: b,
347
+ updatedAt: b,
348
+ author: A.optional(),
349
+ contributors: e.array(A).optional(),
350
+ license: y.optional(),
351
+ licenseUrl: x.optional(),
344
352
  requirements: F.optional(),
345
- tags: e.array(w).optional(),
353
+ tags: e.array(C).optional(),
346
354
  tagDefinitions: je.optional(),
347
355
  translations: e.array(Me).optional(),
348
- sourceMaterials: e.array(N).optional(),
356
+ sourceMaterials: e.array(M).optional(),
349
357
  estimatedTime: e.number().positive().optional(),
350
358
  prerequisites: e.array(I).optional(),
351
359
  relatedSets: e.array(I).optional(),
@@ -358,25 +366,25 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
358
366
  message: "Creation date (createdAt) must be before or equal to update date (updatedAt)",
359
367
  path: ["updatedAt"]
360
368
  }), R = e.object({
361
- id: v,
369
+ id: _,
362
370
  type: e.string(),
363
- assets: A.optional(),
364
- lang: y.optional(),
365
- tags: e.array(w).optional(),
366
- topic: w.optional(),
371
+ assets: k.optional(),
372
+ lang: v.optional(),
373
+ tags: e.array(C).optional(),
374
+ topic: C.optional(),
367
375
  difficulty: e.number().int().min(1, "Difficulty must be at least 1").max(5, "Difficulty must be at most 5").optional(),
368
376
  timeLimit: e.number().positive("Time limit must be a positive number").optional(),
369
- hints: e.array(T.max(2e3, "Hint must not be longer than 2000 characters")).max(20, "Maximum 20 hints per item").optional(),
370
- explanation: T.max(1e4, "Explanation must not be longer than 10000 characters").optional(),
371
- incorrectFeedback: T.optional(),
372
- sources: e.array(P).optional(),
373
- relatedItems: e.array(v).optional(),
374
- dependencyItems: e.array(v).optional(),
377
+ hints: e.array(w.max(2e3, "Hint must not be longer than 2000 characters")).max(20, "Maximum 20 hints per item").optional(),
378
+ explanation: w.max(1e4, "Explanation must not be longer than 10000 characters").optional(),
379
+ incorrectFeedback: w.optional(),
380
+ sources: e.array(N).optional(),
381
+ relatedItems: e.array(_).optional(),
382
+ dependencyItems: e.array(_).optional(),
375
383
  pedagogy: Fe.optional(),
376
384
  customData: e.record(e.string(), e.unknown()).optional(),
377
385
  appSpecific: e.record(e.string(), e.unknown()).optional()
378
386
  }), Ie = e.object({
379
- options: e.array(T).min(1, "Must have at least 1 option"),
387
+ options: e.array(w).min(1, "Must have at least 1 option"),
380
388
  correctIndex: e.number().int().nonnegative()
381
389
  }).refine((e) => e.correctIndex < e.options.length, {
382
390
  message: "Correct answer index references non-existent option",
@@ -404,7 +412,7 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
404
412
  }), H = e.object({
405
413
  type: e.literal("mesh"),
406
414
  label: e.string().optional(),
407
- targetName: w
415
+ targetName: C
408
416
  }), Le = e.discriminatedUnion("type", [
409
417
  z,
410
418
  B,
@@ -422,8 +430,8 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
422
430
  position: U.optional(),
423
431
  target: U.optional()
424
432
  }), Be = e.object({
425
- id: w,
426
- text: T,
433
+ id: C,
434
+ text: w,
427
435
  correctCategoryIndex: e.number().int().nonnegative()
428
436
  }), Ve = e.enum([
429
437
  "year",
@@ -431,22 +439,22 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
431
439
  "day",
432
440
  "datetime"
433
441
  ]), He = e.object({
434
- id: w,
435
- text: T,
436
- date: x,
442
+ id: C,
443
+ text: w,
444
+ date: b,
437
445
  precision: Ve.optional()
438
446
  }), Ue = e.union([
439
447
  z.extend({ correctLabelIndex: e.number().int().nonnegative() }),
440
448
  B.extend({ correctLabelIndex: e.number().int().nonnegative() }),
441
449
  V.extend({ correctLabelIndex: e.number().int().nonnegative() })
442
- ]), W = e.object({
443
- label: w,
450
+ ]), We = e.object({
451
+ label: C,
444
452
  percentage: e.number().min(0, "Percentage must be non-negative").max(100, "Percentage must not exceed 100"),
445
453
  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, {
454
+ }), 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
455
  message: "Sum of percentages of all criteria must be greater than 0",
448
456
  path: ["criteria"]
449
- }), Ge = e.object({
457
+ }), W = e.object({
450
458
  min: e.number(),
451
459
  max: e.number()
452
460
  }).refine((e) => e.min <= e.max, {
@@ -455,23 +463,23 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
455
463
  }), Ke = R.extend({
456
464
  type: e.literal("note"),
457
465
  title: e.string().optional(),
458
- content: T.max(1e4, "Content must not be longer than 10000 characters"),
459
- hiddenContent: T.max(1e4, "Content must not be longer than 10000 characters").optional()
466
+ content: w.max(1e4, "Content must not be longer than 10000 characters"),
467
+ hiddenContent: w.max(1e4, "Content must not be longer than 10000 characters").optional()
460
468
  }), qe = R.extend({
461
469
  type: e.literal("flashcard"),
462
- front: T.max(1e4, "Front side must not be longer than 10000 characters"),
463
- back: T.max(1e4, "Back side must not be longer than 10000 characters")
470
+ front: w.max(1e4, "Front side must not be longer than 10000 characters"),
471
+ back: w.max(1e4, "Back side must not be longer than 10000 characters")
464
472
  }), Je = R.extend({
465
473
  type: e.literal("true-false"),
466
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
474
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
467
475
  answer: e.boolean()
468
476
  }), Ye = R.extend({
469
477
  type: e.literal("mcq-single"),
470
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
471
- 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"),
478
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
479
+ options: e.array(w.max(2e3, "Option must not be longer than 2000 characters")).min(2, "Question must have at least 2 options").max(100, "Maximum 100 options"),
472
480
  correctIndex: e.number().int().nonnegative(),
473
481
  shuffleOptions: e.boolean().optional(),
474
- optionExplanations: e.array(e.union([T, e.null()])).optional()
482
+ optionExplanations: e.array(e.union([w, e.null()])).optional()
475
483
  }).refine((e) => e.correctIndex < e.options.length, {
476
484
  message: "Correct answer index references non-existent option",
477
485
  path: ["correctIndex"]
@@ -483,13 +491,13 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
483
491
  path: ["options"]
484
492
  }), Xe = R.extend({
485
493
  type: e.literal("mcq-multi"),
486
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
487
- 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"),
494
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
495
+ options: e.array(w.max(2e3, "Option must not be longer than 2000 characters")).min(2, "Question must have at least 2 options").max(100, "Maximum 100 options"),
488
496
  correctIndices: e.array(e.number().int().nonnegative()).min(1, "Must have at least 1 correct answer"),
489
497
  minSelections: e.number().int().positive().optional(),
490
498
  maxSelections: e.number().int().positive().optional(),
491
499
  shuffleOptions: e.boolean().optional(),
492
- optionExplanations: e.array(e.union([T, e.null()])).optional()
500
+ optionExplanations: e.array(e.union([w, e.null()])).optional()
493
501
  }).refine((e) => e.correctIndices.every((t) => t < e.options.length), {
494
502
  message: "Some of correct answer indices reference non-existent option",
495
503
  path: ["correctIndices"]
@@ -513,17 +521,17 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
513
521
  path: ["options"]
514
522
  }), Ze = R.extend({
515
523
  type: e.literal("short-answer"),
516
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
517
- answers: e.array(w).min(1, "Must have at least 1 correct answer"),
524
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
525
+ answers: e.array(C).min(1, "Must have at least 1 correct answer"),
518
526
  caseSensitive: e.boolean().optional(),
519
527
  trimWhitespace: e.boolean().optional(),
520
528
  acceptPartial: e.boolean().optional(),
521
529
  ignoreDiacritics: e.boolean().optional()
522
530
  }), Qe = R.extend({
523
531
  type: e.literal("fill-in-blanks"),
524
- question: E,
525
- text: T.max(1e4, "Text must not be longer than 10000 characters"),
526
- blanks: e.record(D, e.array(w).min(1, "Each blank must have at least 1 correct answer")),
532
+ question: T,
533
+ text: w.max(1e4, "Text must not be longer than 10000 characters"),
534
+ blanks: e.record(E, e.array(C).min(1, "Each blank must have at least 1 correct answer")),
527
535
  caseSensitive: e.boolean().optional(),
528
536
  trimWhitespace: e.boolean().optional()
529
537
  }).refine((e) => Object.keys(e.blanks).length > 0, {
@@ -541,9 +549,9 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
541
549
  path: ["blanks"]
542
550
  }), $e = R.extend({
543
551
  type: e.literal("fill-in-select"),
544
- question: E,
545
- text: T.max(1e4, "Text must not be longer than 10000 characters"),
546
- blanks: e.record(D, Ie)
552
+ question: T,
553
+ text: w.max(1e4, "Text must not be longer than 10000 characters"),
554
+ blanks: e.record(E, Ie)
547
555
  }).refine((e) => Object.keys(e.blanks).length > 0, {
548
556
  message: "Text must contain at least 1 blank to select",
549
557
  path: ["blanks"]
@@ -559,17 +567,17 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
559
567
  path: ["blanks"]
560
568
  }), et = R.extend({
561
569
  type: e.literal("match-pairs"),
562
- question: E,
563
- prompts: e.array(T).min(2, "Must have at least 2 pairs to match").max(100, "Maximum 100 pairs"),
564
- matches: e.array(T).min(2, "Must have at least 2 pairs to match").max(100, "Maximum 100 pairs")
570
+ question: T,
571
+ prompts: e.array(w).min(2, "Must have at least 2 pairs to match").max(100, "Maximum 100 pairs"),
572
+ matches: e.array(w).min(2, "Must have at least 2 pairs to match").max(100, "Maximum 100 pairs")
565
573
  }).refine((e) => e.prompts.length === e.matches.length, {
566
574
  message: "Number of prompts must match number of matches",
567
575
  path: ["matches"]
568
576
  }), tt = R.extend({
569
577
  type: e.literal("match-complex"),
570
- question: E,
571
- leftItems: e.array(T).min(1, "Must have at least 1 item on left"),
572
- rightItems: e.array(T).min(1, "Must have at least 1 item on right"),
578
+ question: T,
579
+ leftItems: e.array(w).min(1, "Must have at least 1 item on left"),
580
+ rightItems: e.array(w).min(1, "Must have at least 1 item on right"),
573
581
  connections: e.array(e.tuple([e.number().int().nonnegative(), e.number().int().nonnegative()])).min(1, "Must have at least 1 connection"),
574
582
  minCorrect: e.number().int().positive().optional()
575
583
  }).refine((e) => e.connections.every(([t, n]) => t < e.leftItems.length && n < e.rightItems.length), {
@@ -583,11 +591,11 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
583
591
  path: ["minCorrect"]
584
592
  }), nt = R.extend({
585
593
  type: e.literal("sort-items"),
586
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
587
- items: e.array(T).min(2, "Must have at least 2 items to sort")
594
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
595
+ items: e.array(w).min(2, "Must have at least 2 items to sort")
588
596
  }), rt = R.extend({
589
597
  type: e.literal("slider"),
590
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
598
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
591
599
  min: e.number(),
592
600
  max: e.number(),
593
601
  step: e.number().positive("Step must be a positive number"),
@@ -611,8 +619,8 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
611
619
  path: ["tolerance"]
612
620
  }), it = R.extend({
613
621
  type: e.literal("pin-on-image"),
614
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
615
- targetAsset: C,
622
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
623
+ targetAsset: S,
616
624
  hotspots: e.array(Re).min(1, "Must have at least 1 hotspot"),
617
625
  multipleCorrect: e.boolean().optional(),
618
626
  minCorrect: e.number().int().positive().optional()
@@ -621,8 +629,8 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
621
629
  path: ["minCorrect"]
622
630
  }), at = R.extend({
623
631
  type: e.literal("categorize"),
624
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
625
- categories: e.array(w).min(2, "Must have at least 2 categories"),
632
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
633
+ categories: e.array(C).min(2, "Must have at least 2 categories"),
626
634
  items: e.array(Be).min(1, "Must have at least 1 item to categorize")
627
635
  }).refine((e) => new Set(e.categories.map((e) => e.toLowerCase())).size === e.categories.length, {
628
636
  message: "Categories must not contain duplicates (case-insensitive)",
@@ -632,14 +640,14 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
632
640
  path: ["items"]
633
641
  }), ot = R.extend({
634
642
  type: e.literal("timeline"),
635
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
643
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
636
644
  events: e.array(He).min(2, "Must have at least 2 events"),
637
645
  randomize: e.boolean().optional()
638
646
  }), st = R.extend({
639
647
  type: e.literal("matrix"),
640
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
641
- rows: e.array(w).min(1, "Must have at least 1 row"),
642
- columns: e.array(w).min(1, "Must have at least 1 column"),
648
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
649
+ rows: e.array(C).min(1, "Must have at least 1 row"),
650
+ columns: e.array(C).min(1, "Must have at least 1 column"),
643
651
  correctCells: e.array(e.tuple([e.number().int().nonnegative(), e.number().int().nonnegative()])).min(1, "Must have at least 1 correct cell"),
644
652
  multiplePerRow: e.boolean().optional()
645
653
  }).refine((e) => e.correctCells.every(([t, n]) => t < e.rows.length && n < e.columns.length), {
@@ -660,15 +668,15 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
660
668
  path: ["correctCells"]
661
669
  }), ct = R.extend({
662
670
  type: e.literal("math-input"),
663
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
664
- correctAnswer: w,
665
- alternativeAnswers: e.array(w).optional(),
671
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
672
+ correctAnswer: C,
673
+ alternativeAnswers: e.array(C).optional(),
666
674
  tolerance: e.number().nonnegative().optional()
667
675
  }), lt = R.extend({
668
676
  type: e.literal("diagram-label"),
669
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
670
- targetAsset: C,
671
- labels: e.array(T).min(1, "Must have at least 1 label"),
677
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
678
+ targetAsset: S,
679
+ labels: e.array(w).min(1, "Must have at least 1 label"),
672
680
  caseSensitive: e.boolean().optional(),
673
681
  requireTyping: e.boolean().optional(),
674
682
  zones: e.array(Ue).min(1, "Must have at least 1 zone")
@@ -677,25 +685,25 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
677
685
  path: ["zones"]
678
686
  }), ut = R.extend({
679
687
  type: e.literal("open-ended"),
680
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
688
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
681
689
  minWords: e.number().int().positive().optional(),
682
690
  maxWords: e.number().int().positive().optional(),
683
- sampleAnswer: T.optional(),
684
- rubric: We.optional()
691
+ sampleAnswer: w.optional(),
692
+ rubric: Ge.optional()
685
693
  }).refine((e) => e.minWords && e.maxWords ? e.minWords <= e.maxWords : !0, {
686
694
  message: "Minimum word count must be less than or equal to maximum",
687
695
  path: ["maxWords"]
688
696
  }), dt = R.extend({
689
697
  type: e.literal("numeric-input"),
690
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
698
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
691
699
  value: e.number(),
692
700
  tolerance: e.number().nonnegative().optional(),
693
- range: Ge.optional(),
701
+ range: W.optional(),
694
702
  unit: e.string().optional()
695
703
  }), ft = R.extend({
696
704
  type: e.literal("pin-on-model"),
697
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
698
- targetAsset: C,
705
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
706
+ targetAsset: S,
699
707
  hotspots: e.array(H).min(1, "Must have at least 1 hotspot"),
700
708
  multipleCorrect: e.boolean().optional(),
701
709
  minCorrect: e.number().int().positive().optional(),
@@ -705,9 +713,9 @@ var v = e.string().uuid({ message: "Invalid UUID format" }), y = e.string().min(
705
713
  path: ["minCorrect"]
706
714
  }), pt = R.extend({
707
715
  type: e.literal("chess-puzzle"),
708
- question: T.max(1e4, "Question must not be longer than 10000 characters"),
709
- fen: w,
710
- answers: e.array(e.array(w).min(1, "Move sequence must not be empty")).min(1, "Must have at least 1 correct move sequence"),
716
+ question: w.max(1e4, "Question must not be longer than 10000 characters"),
717
+ fen: C,
718
+ answers: e.array(e.array(C).min(1, "Move sequence must not be empty")).min(1, "Must have at least 1 correct move sequence"),
711
719
  elo: e.number().int().nonnegative("ELO must be non-negative integer").optional()
712
720
  }), G = e.discriminatedUnion("type", [
713
721
  Ke,
@@ -773,11 +781,11 @@ function mt(t) {
773
781
  }]);
774
782
  }
775
783
  function ht(e) {
776
- return _(e, 10), K.parse(e);
784
+ return g(e, 10), K.parse(e);
777
785
  }
778
786
  function gt(e) {
779
787
  try {
780
- _(e, 10);
788
+ g(e, 10);
781
789
  } catch (e) {
782
790
  return {
783
791
  success: !1,
@@ -794,11 +802,11 @@ function gt(e) {
794
802
  };
795
803
  }
796
804
  function _t(e) {
797
- return _(e, 10), G.parse(e);
805
+ return g(e, 10), G.parse(e);
798
806
  }
799
807
  function vt(e) {
800
808
  try {
801
- _(e, 10);
809
+ g(e, 10);
802
810
  } catch (e) {
803
811
  return {
804
812
  success: !1,
@@ -814,21 +822,9 @@ function vt(e) {
814
822
  error: t.error
815
823
  };
816
824
  }
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
825
  //#endregion
830
826
  //#region src/manifestValidation.ts
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 = [
827
+ var q = e.string().min(1, "Value must not be empty").trim(), yt = 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" }), bt = 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\")"), xt = [
832
828
  "note",
833
829
  "flashcard",
834
830
  "true-false",
@@ -851,15 +847,15 @@ var q = e.string().min(1, "Value must not be empty").trim(), bt = e.string().reg
851
847
  "numeric-input",
852
848
  "pin-on-model",
853
849
  "chess-puzzle"
854
- ], Ct = q.refine((e) => St.includes(e) || e.startsWith("x-"), { message: "Custom types MUST use the \"x-\" prefix" }), wt = e.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.enum([
850
+ ], St = q.refine((e) => xt.includes(e) || e.startsWith("x-"), { message: "Custom types MUST use the \"x-\" prefix" }), Ct = e.string().refine((e) => c.includes(e) || e.startsWith("x-"), { message: "Action must be one of [render, edit, validate, import, export] or have prefix \"x-\"" }), wt = e.enum([
855
851
  "game",
856
852
  "fun",
857
853
  "drill"
858
- ]), Et = e.enum([
854
+ ]), Tt = e.enum([
859
855
  "low",
860
856
  "medium",
861
857
  "high"
862
- ]), Dt = e.string().refine((e) => l.includes(e) || e.startsWith("x-"), { message: "Feature must be one of official keys or have prefix \"x-\"" }), Ot = e.string().refine((e) => u.includes(e) || e.startsWith("x-"), { message: "Item property must be an official key or have prefix \"x-\"" }), kt = e.string().refine((e) => d.includes(e) || e.startsWith("x-"), { message: "Meta property must be an official key or have prefix \"x-\"" });
858
+ ]), Et = e.string().refine((e) => l.includes(e) || e.startsWith("x-"), { message: "Feature must be one of official keys or have prefix \"x-\"" }), Dt = e.string().refine((e) => u.includes(e) || e.startsWith("x-"), { message: "Item property must be an official key or have prefix \"x-\"" }), Ot = e.string().refine((e) => d.includes(e) || e.startsWith("x-"), { message: "Meta property must be an official key or have prefix \"x-\"" });
863
859
  function X(t) {
864
860
  return e.union([
865
861
  e.tuple([e.literal("*")]),
@@ -867,15 +863,15 @@ function X(t) {
867
863
  e.null()
868
864
  ]);
869
865
  }
870
- var At = e.string().refine((e) => e.startsWith("image/"), { message: "Must be a valid image MIME type (image/...)" }), jt = e.string().refine((e) => e.startsWith("audio/"), { message: "Must be a valid audio MIME type (audio/...)" }), Mt = e.string().refine((e) => e.startsWith("video/"), { message: "Must be a valid video MIME type (video/...)" }), Nt = e.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.object({
871
- image: X(At).optional(),
872
- audio: X(jt).optional(),
873
- video: X(Mt).optional(),
874
- model: X(Nt).optional()
875
- }), Ft = F.extend({
876
- actions: e.array(wt).min(1, "Application must support at least one action"),
877
- types: X(Ct).optional(),
878
- assets: Pt.optional()
866
+ var kt = e.string().refine((e) => e.startsWith("image/"), { message: "Must be a valid image MIME type (image/...)" }), At = e.string().refine((e) => e.startsWith("audio/"), { message: "Must be a valid audio MIME type (audio/...)" }), jt = e.string().refine((e) => e.startsWith("video/"), { message: "Must be a valid video MIME type (video/...)" }), Mt = e.string().refine((e) => e.startsWith("model/") || e === "application/octet-stream", { message: "Must be a valid 3D model MIME type (model/... or application/octet-stream)" }), Nt = e.object({
867
+ image: X(kt).optional(),
868
+ audio: X(At).optional(),
869
+ video: X(jt).optional(),
870
+ model: X(Mt).optional()
871
+ }), Pt = F.extend({
872
+ actions: e.array(Ct).min(1, "Application must support at least one action"),
873
+ types: X(St).optional(),
874
+ assets: Nt.optional()
879
875
  }).superRefine((t, n) => {
880
876
  (t.actions.includes("render") || t.actions.includes("edit")) && (!Array.isArray(t.types) || t.types.length === 0) && n.addIssue({
881
877
  code: e.ZodIssueCode.custom,
@@ -884,23 +880,23 @@ var At = e.string().refine((e) => e.startsWith("image/"), { message: "Must be a
884
880
  });
885
881
  }), Z = e.object({
886
882
  $schema: J.optional(),
887
- id: e.union([J, xt]),
883
+ id: e.union([J, bt]),
888
884
  appName: q.max(200, "Name must not be longer than 200 characters"),
889
885
  version: Y,
890
886
  pluginVersion: e.string().optional(),
891
887
  minOqseVersion: Y.optional(),
892
888
  maxOqseVersion: Y.optional(),
893
- capabilities: Ft,
894
- author: j.optional(),
895
- contributors: e.array(j).optional(),
889
+ capabilities: Pt,
890
+ author: A.optional(),
891
+ contributors: e.array(A).optional(),
896
892
  license: e.string().max(100, "License must not be longer than 100 characters").optional(),
897
893
  licenseUrl: J.optional(),
898
- locales: e.array(bt).optional(),
894
+ locales: e.array(yt).optional(),
899
895
  description: e.string().max(5e3, "Description must not be longer than 5000 characters").optional(),
900
896
  emoji: e.string().optional(),
901
897
  tags: e.array(q).optional(),
902
- studyMode: Tt.optional(),
903
- questionDensity: Et.optional(),
898
+ studyMode: wt.optional(),
899
+ questionDensity: Tt.optional(),
904
900
  appSpecific: e.record(e.string(), e.unknown()).optional()
905
901
  }).refine((e) => {
906
902
  if (!e.minOqseVersion || !e.maxOqseVersion) return !0;
@@ -910,31 +906,25 @@ var At = e.string().refine((e) => e.startsWith("image/"), { message: "Must be a
910
906
  message: "minOqseVersion must not be greater than maxOqseVersion",
911
907
  path: ["minOqseVersion"]
912
908
  });
913
- function It(e) {
909
+ function Ft(e) {
914
910
  return Z.parse(e);
915
911
  }
916
- function Lt(e) {
912
+ function It(e) {
917
913
  return Z.safeParse(e);
918
914
  }
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) {
915
+ function Lt(e) {
926
916
  return Z.safeParse(e).success;
927
917
  }
928
918
  //#endregion
929
919
  //#region src/progressValidation.ts
930
- var Bt = e.object({
920
+ var Rt = e.object({
931
921
  attempts: e.number().int().nonnegative(),
932
922
  incorrect: e.number().int().nonnegative(),
933
923
  streak: e.number().int().nonnegative()
934
924
  }).refine((e) => e.incorrect <= e.attempts, {
935
925
  message: "incorrect cannot be higher than attempts",
936
926
  path: ["incorrect"]
937
- }), Vt = e.object({
927
+ }), zt = e.object({
938
928
  isCorrect: e.boolean(),
939
929
  confidence: e.union([
940
930
  e.literal(1),
@@ -942,11 +932,11 @@ var Bt = e.object({
942
932
  e.literal(3),
943
933
  e.literal(4)
944
934
  ]).optional(),
945
- answeredAt: x,
935
+ answeredAt: b,
946
936
  timeSpent: e.number().int().nonnegative().optional(),
947
937
  hintsUsed: e.number().int().nonnegative().default(0),
948
938
  isSkipped: e.boolean().optional()
949
- }), Ht = e.object({
939
+ }), Bt = e.object({
950
940
  bucket: e.union([
951
941
  e.literal(0),
952
942
  e.literal(1),
@@ -954,24 +944,24 @@ var Bt = e.object({
954
944
  e.literal(3),
955
945
  e.literal(4)
956
946
  ]),
957
- nextReviewAt: x.optional(),
958
- stats: Bt,
959
- lastAnswer: Vt.optional(),
947
+ nextReviewAt: b.optional(),
948
+ stats: Rt,
949
+ lastAnswer: zt.optional(),
960
950
  appSpecific: e.record(e.string(), e.unknown()).optional()
961
- }), Ut = e.object({
962
- setId: v,
963
- exportedAt: x,
951
+ }), Vt = e.object({
952
+ setId: _,
953
+ exportedAt: b,
964
954
  algorithm: e.string().regex(/^[a-z0-9-]+$/, "algorithm must be lowercase alphanumeric with hyphens format").optional()
965
955
  }), Q = e.object({
966
956
  $schema: e.url().optional(),
967
957
  version: e.string().regex(/^\d+\.\d+$/, "Version must be in MAJOR.MINOR format"),
968
- meta: Ut,
969
- records: e.record(v, Ht)
958
+ meta: Vt,
959
+ records: e.record(_, Bt)
970
960
  });
971
- function Wt(e) {
961
+ function Ht(e) {
972
962
  return Q.parse(e);
973
963
  }
974
- function Gt(e) {
964
+ function Ut(e) {
975
965
  return Q.safeParse(e);
976
966
  }
977
967
  var $ = e.object(L.shape).pick({
@@ -987,18 +977,18 @@ var $ = e.object(L.shape).pick({
987
977
  estimatedTime: !0,
988
978
  requirements: !0
989
979
  }).partial({ createdAt: !0 }).extend({
990
- url: S,
980
+ url: x,
991
981
  $schema: e.string().url().optional()
992
982
  });
993
- function Kt(e) {
983
+ function Wt(e) {
994
984
  return $.parse(e);
995
985
  }
996
- function qt(e) {
986
+ function Gt(e) {
997
987
  return $.safeParse(e);
998
988
  }
999
989
  //#endregion
1000
990
  //#region src/richTextProcessor.ts
1001
- function Jt(e) {
991
+ function Kt(e) {
1002
992
  let t = {};
1003
993
  return {
1004
994
  text: e.replace(/<(asset|blank):([a-zA-Z0-9_-]+)\s*\/>/gi, (e, n, r) => {
@@ -1012,11 +1002,11 @@ function Jt(e) {
1012
1002
  tokens: t
1013
1003
  };
1014
1004
  }
1015
- function Yt(e) {
1005
+ function qt(e) {
1016
1006
  let t = e.replace(/`{1,}[^`]*`{1,}/g, "").replace(/~{3,}[\s\S]*?~{3,}/g, "");
1017
1007
  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
1008
  }
1019
- function Xt(e, t, n) {
1009
+ function Jt(e, t, n) {
1020
1010
  let r = e;
1021
1011
  for (let [e, i] of Object.entries(t)) {
1022
1012
  let t = i.originalTag;
@@ -1024,16 +1014,16 @@ function Xt(e, t, n) {
1024
1014
  }
1025
1015
  return r;
1026
1016
  }
1027
- function Zt(e, t, n) {
1017
+ function Yt(e, t, n) {
1028
1018
  if (!e) return "";
1029
- let r = t?.features?.includes("html") ?? !1, { text: i, tokens: a } = Jt(e);
1030
- r || Yt(i);
1019
+ let r = t?.features?.includes("html") ?? !1, { text: i, tokens: a } = Kt(e);
1020
+ r || qt(i);
1031
1021
  let o = n.markdownParser(i);
1032
1022
  if (r) {
1033
1023
  if (!n.htmlSanitizer) throw Error("OQSE Security Error: Set requires 'html' (Tier 2), but no htmlSanitizer (like DOMPurify) was provided to the options.");
1034
1024
  o = n.htmlSanitizer(o);
1035
1025
  }
1036
- return Xt(o, a, n);
1026
+ return Jt(o, a, n);
1037
1027
  }
1038
1028
  //#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 };
1029
+ export { x as AbsoluteURLSchema, k as AssetDictionarySchema, S as AssetKeySchema, At as AudioMimeTypeSchema, R as BaseItemSchema, E 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, Et as FeatureFlagSchema, F as FeatureProfileSchema, Qe as FillInBlanksItemSchema, $e as FillInSelectItemSchema, qe as FlashcardItemSchema, Re as Hotspot2DSchema, Le as HotspotObjectSchema, b as ISO8601DateTimeSchema, kt as ImageMimeTypeSchema, Dt as ItemPropertyKeySchema, v as LanguageCodeSchema, zt as LastAnswerObjectSchema, I as LinkedSetObjectSchema, Xe as MCQMultiItemSchema, Ye as MCQSingleItemSchema, Nt as ManifestAssetsSchema, Pt as ManifestCapabilitiesSchema, tt as MatchComplexItemSchema, et as MatchPairsItemSchema, ct as MathInputItemSchema, st as MatrixItemSchema, O as MediaObjectSchema, H as MeshHotspotSchema, Ot as MetaPropertyKeySchema, Mt as ModelMimeTypeSchema, Ke as NoteItemSchema, dt as NumericInputItemSchema, W as NumericRangeSchema, c as OFFICIAL_ACTIONS, l as OFFICIAL_FEATURE_KEYS, u as OFFICIAL_ITEM_PROPERTIES, d as OFFICIAL_META_PROPERTIES, Ct as OQSEActionSchema, K as OQSEFileSchema, $ as OQSEHeaderSchema, G as OQSEItemSchema, Z as OQSEManifestSchema, L as OQSEMetaSchema, Q as OQSEProgressSchema, Tt as OQSEQuestionDensitySchema, wt as OQSEStudyModeSchema, ut as OpenEndedItemSchema, T as OptionalRichContentSchema, Fe as PedagogySchema, A as PersonObjectSchema, it as PinOnImageItemSchema, ft as PinOnModelItemSchema, C as PlainTextSchema, V as PolygonHotspotSchema, Vt as ProgressMetaSchema, Bt as ProgressRecordSchema, z as RectHotspotSchema, w as RichContentSchema, We as RubricCriterionSchema, Ge as RubricSchema, y as SPDXLicenseSchema, Ie as SelectBlankObjectSchema, Ze as ShortAnswerItemSchema, rt as SliderItemSchema, nt as SortItemsItemSchema, M as SourceMaterialSchema, j as SourceMaterialTypeSchema, N as SourceReferenceSchema, Rt as StatsObjectSchema, D as SubtitleTrackSchema, je as TagDefinitionDictionarySchema, P as TagDefinitionSchema, He as TimelineEventSchema, ot as TimelineItemSchema, Ve as TimelinePrecisionSchema, Me as TranslationObjectSchema, Je as TrueFalseItemSchema, _ as UUIDSchema, U as Vector3Schema, jt as VideoMimeTypeSchema, p as compareManifestVersions, Jt 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, Lt as isValidOQSEManifest, _e as isValidSemVer, Oe as isValidUUID, ye as isVersionCompatible, Yt as prepareRichTextForDisplay, gt as safeValidateOQSEFile, Gt as safeValidateOQSEHeader, vt as safeValidateOQSEItem, It as safeValidateOQSEManifest, Ut as safeValidateOQSEProgress, Kt as tokenizeOqseTags, g as validateJsonDepth, ht as validateOQSEFile, Wt as validateOQSEHeader, _t as validateOQSEItem, Ft as validateOQSEManifest, Ht as validateOQSEProgress, qt 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.5",
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",