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