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