@vue-skuilder/standalone-ui 0.1.39 → 0.1.40

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.html CHANGED
@@ -9,11 +9,11 @@
9
9
  href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons"
10
10
  rel="stylesheet"
11
11
  />
12
- <script type="module" crossorigin src="/assets/index-CgJHLYRy.js"></script>
12
+ <script type="module" crossorigin src="/assets/index-Di-iurxs.js"></script>
13
13
  <link rel="modulepreload" crossorigin href="/assets/dist-DCANvFNh.js">
14
- <link rel="modulepreload" crossorigin href="/assets/dist-D0Pw05KO.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/dist-BoYWClge.js">
15
15
  <link rel="modulepreload" crossorigin href="/assets/MarkdownRenderer-DoVbFpA6-DYVMsbBP.js">
16
- <link rel="modulepreload" crossorigin href="/assets/common-ui.es-DQVvqecz.js">
16
+ <link rel="modulepreload" crossorigin href="/assets/common-ui.es-Dli7wjjJ.js">
17
17
  <link rel="stylesheet" crossorigin href="/assets/common-ui-BY2Ut5jf.css">
18
18
  <link rel="stylesheet" crossorigin href="/assets/index-CwbD9tGY.css">
19
19
  </head>
@@ -313,7 +313,7 @@ ${JSON.stringify(t)}`)})}async function GET_CACHED(t,c){return CLIENT_CACHE[t]?C
313
313
  💡 Inspect: window.skuilder.pipeline`)}function logResultCards(t){if(!(!VERBOSE_RESULTS||t.length===0)){logger.info(`[Pipeline] Results (${t.length} cards):`);for(let c=0;c<t.length;c++){let u=t[c],d=u.tags?.slice(0,3).join(`, `)||``,m=u.provenance.filter(t=>t.strategy===`hierarchyDefinition`||t.strategy===`priorityDefinition`||t.strategy===`interferenceFilter`||t.strategy===`letterGating`||t.strategy===`ephemeralHint`).map(t=>{let c=t.action===`boosted`?`↑`:t.action===`penalized`?`↓`:`=`;return`${t.strategyName}${c}${t.score.toFixed(2)}`}).join(` | `);logger.info(`[Pipeline] ${String(c+1).padStart(2)}. ${u.score.toFixed(4)} ${u.cardId} [${d}]${m?` {${m}}`:``}`)}}}function logCardProvenance(t,c=3){let u=t.slice(0,c);logger.debug(`[Pipeline] Provenance for top ${u.length} cards:`);for(let t of u){logger.debug(`[Pipeline] ${t.cardId} (final score: ${t.score.toFixed(3)}):`);for(let c of t.provenance){let t=c.score.toFixed(3),u=c.action.padEnd(9);logger.debug(`[Pipeline] ${u} ${t} - ${c.strategyName}: ${c.reason}`)}}}function createDefaultEloStrategy(t){return{_id:`NAVIGATION_STRATEGY-ELO-default`,docType:`NAVIGATION_STRATEGY`,name:`ELO (default)`,description:`Default ELO-based navigation strategy for new cards`,implementingClass:`elo`,course:t,serializedData:``}}function createDefaultSrsStrategy(t){return{_id:`NAVIGATION_STRATEGY-SRS-default`,docType:`NAVIGATION_STRATEGY`,name:`SRS (default)`,description:`Default SRS-based navigation strategy for reviews`,implementingClass:`srs`,course:t,serializedData:``}}function createDefaultPipeline(t,c){let u=c.getCourseID(),d=new ELONavigator(t,c,createDefaultEloStrategy(u)),m=new SRSNavigator(t,c,createDefaultSrsStrategy(u)),g=new CompositeGenerator([d,m]),b=createEloDistanceFilter();return new Pipeline(g,[b],t,c)}function registerNavigator(t,c,u){navigatorRegistry.set(t,{constructor:c,role:u}),logger.debug(`[NavigatorRegistry] Registered: ${t}${u?` (${u})`:``}`)}function getRegisteredNavigator(t){return navigatorRegistry.get(t)?.constructor}function hasRegisteredNavigator(t){return navigatorRegistry.has(t)}function getRegisteredNavigatorRole(t){return navigatorRegistry.get(t)?.role}function getRegisteredNavigatorNames(){return Array.from(navigatorRegistry.keys())}async function initializeNavigatorRegistry(){logger.debug(`[NavigatorRegistry] Initializing built-in navigators...`);let[t,c]=await Promise.all([Promise.resolve().then(()=>(init_elo(),elo_exports)),Promise.resolve().then(()=>(init_srs(),srs_exports))]),u=await Promise.resolve().then(()=>(init_prescribed(),prescribed_exports));registerNavigator(`elo`,t.default),registerNavigator(`srs`,c.default),registerNavigator(`prescribed`,u.default);let[d,m,g,b]=await Promise.all([Promise.resolve().then(()=>(init_hierarchyDefinition(),hierarchyDefinition_exports)),Promise.resolve().then(()=>(init_interferenceMitigator(),interferenceMitigator_exports)),Promise.resolve().then(()=>(init_relativePriority(),relativePriority_exports)),Promise.resolve().then(()=>(init_userTagPreference(),userTagPreference_exports))]);registerNavigator(`hierarchyDefinition`,d.default),registerNavigator(`interferenceMitigator`,m.default),registerNavigator(`relativePriority`,g.default),registerNavigator(`userTagPreference`,b.default),logger.debug(`[NavigatorRegistry] Initialized ${navigatorRegistry.size} navigators: ${getRegisteredNavigatorNames().join(`, `)}`)}function getCardOrigin(t){if(t.provenance.length===0)throw Error(`Card has no provenance - cannot determine origin`);let c=t.provenance[0].reason.toLowerCase();return c.includes(`failed`)?`failed`:c.includes(`review`)?`review`:`new`}function isGenerator(t){return NavigatorRoles[t]===`generator`?!0:getRegisteredNavigatorRole(t)===`generator`}function isFilter(t){return NavigatorRoles[t]===`filter`?!0:getRegisteredNavigatorRole(t)===`filter`}function randIntWeightedTowardZero(t){return Math.floor(Math.random()*Math.random()*Math.random()*t)}async function getCourseTagStubs(t){logger.debug(`Getting tag stubs for course: ${t}`);let c=await filterAllDocsByPrefix2(getCourseDB2(t),`TAG`.valueOf()+`-`);return c.rows.forEach(t=>{logger.debug(` Tag stub for doc: ${t.id}`)}),c}async function createTag(t,c,u){logger.debug(`Creating tag: ${c}...`);let d=getTagID(c);return await getCourseDB2(t).put({course:t,docType:`TAG`,name:c,snippet:``,taggedCards:[],wiki:``,author:u,_id:d})}async function updateTag(t){let c=await getTag(t.course,t.name);return await getCourseDB2(t.course).put({...t,_rev:c._rev})}async function getTag(t,c){let u=getTagID(c);return getCourseDB2(t).get(u)}async function removeTagFromCard(t,c,u){u=getTagID(u);let d=getCourseDB2(t),m=await d.get(u);return m.taggedCards=m.taggedCards.filter(t=>c!==t),d.put(m)}async function getAppliedTags(t,c){return await getCourseDB2(t).query(`getTags`,{startkey:c,endkey:c})}async function updateCredentialledCourseConfig(t,c){logger.debug(`Updating course config:
314
314
 
315
315
  ${JSON.stringify(c)}
316
- `);let u=getCourseDB2(t),d=await getCredentialledCourseConfig(t);return await u.put({...c,_rev:d._rev})}function isSuccessRow(t){return`doc`in t&&t.doc!==null&&t.doc!==void 0}async function getCurrentSession(){try{if(ENV.COUCHDB_SERVER_URL===NOT_SET||ENV.COUCHDB_SERVER_PROTOCOL===NOT_SET)throw Error(`CouchDB server configuration not properly initialized. Protocol: "${ENV.COUCHDB_SERVER_PROTOCOL}", URL: "${ENV.COUCHDB_SERVER_URL}"`);let t=ENV.COUCHDB_SERVER_URL.endsWith(`/`)?ENV.COUCHDB_SERVER_URL.slice(0,-1):ENV.COUCHDB_SERVER_URL,c=`${ENV.COUCHDB_SERVER_PROTOCOL}://${t}/_session`;logger.debug(`Attempting session check at: ${c}`);let u=await(0,import_browser_ponyfill.default)(c,{method:`GET`,credentials:`include`});if(!u.ok)throw Error(`Session check failed: ${u.status}`);return await u.json()}catch(t){let c=ENV.COUCHDB_SERVER_URL.endsWith(`/`)?ENV.COUCHDB_SERVER_URL.slice(0,-1):ENV.COUCHDB_SERVER_URL,u=`${ENV.COUCHDB_SERVER_PROTOCOL}://${c}/_session`;throw logger.error(`Session check error attempting to connect to: ${u} - ${t}`),Error(`Session check failed connecting to ${u}: ${t}`)}}async function getLoggedInUsername(){let t=await getCurrentSession();if(t.userCtx.name&&t.userCtx.name!==``)return t.userCtx.name;throw Error(`No logged in user`)}function createPouchDBConfig(){return ENV.COUCHDB_USERNAME&&ENV.COUCHDB_PASSWORD&&typeof window>`u`?{fetch(t,c={}){let u=btoa(`${ENV.COUCHDB_USERNAME}:${ENV.COUCHDB_PASSWORD}`),d=new Headers(c.headers||{});d.set(`Authorization`,`Basic ${u}`);let m={...c,headers:d};return pouchdb_setup_default.fetch(t,m)}}:pouchDBincludeCredentialsConfig}function getCourseDB2(t){return new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+`coursedb-`+t,createPouchDBConfig())}function filterAllDocsByPrefix2(t,c,u){let d={startkey:c,endkey:c+`￰`,include_docs:!0};return u&&Object.assign(d,u),t.allDocs(d)}function getStartAndEndKeys2(t){return{startkey:t,endkey:t+`￰`}}function accomodateGuest(){if(logger.log(`[funnel] accomodateGuest() called`),typeof localStorage>`u`)return logger.log(`[funnel] localStorage not available (Node.js environment), returning default guest`),{username:GuestUsername+`nodejs-test`,firstVisit:!0};let t=`sk-guest-uuid`,c,u=localStorage.getItem(t);if(logger.log(`[funnel] Checking localStorage for key:`,t),logger.log(`[funnel] Existing UUID value:`,u),logger.log(`[funnel] existingUUID !== null:`,u!==null),u!==null)c=!1,logger.log(`[funnel] Returning guest ${u} "logging in".`);else{c=!0,logger.log(`[funnel] No existing UUID, generating new one...`);let u=generateUUID();logger.log(`[funnel] Generated UUID:`,u),logger.log(`[funnel] UUID length:`,u.length);try{localStorage.setItem(t,u),logger.log(`[funnel] Successfully stored UUID in localStorage`);let c=localStorage.getItem(t);logger.log(`[funnel] Verification read from localStorage:`,c)}catch(t){logger.error(`[funnel] ERROR storing UUID:`,t)}logger.log(`[funnel] Accommodating a new guest with account: ${u}`)}let d=localStorage.getItem(t),m=GuestUsername+d;return logger.log(`[funnel] Final UUID from localStorage:`,d),logger.log(`[funnel] GuestUsername constant:`,GuestUsername),logger.log(`[funnel] Final username to return:`,m),{username:m,firstVisit:c};function generateUUID(){if(logger.log(`[funnel] Inside generateUUID()`),typeof crypto<`u`&&typeof crypto.randomUUID==`function`){let t=crypto.randomUUID();return logger.log(`[funnel] Generated UUID using crypto.randomUUID():`,t),t}if(typeof crypto<`u`&&typeof crypto.getRandomValues==`function`){let t=new Uint8Array(16);crypto.getRandomValues(t),t[6]=t[6]&15|64,t[8]=t[8]&63|128;let c=[Array.from(t.slice(0,4)).map(t=>t.toString(16).padStart(2,`0`)).join(``),Array.from(t.slice(4,6)).map(t=>t.toString(16).padStart(2,`0`)).join(``),Array.from(t.slice(6,8)).map(t=>t.toString(16).padStart(2,`0`)).join(``),Array.from(t.slice(8,10)).map(t=>t.toString(16).padStart(2,`0`)).join(``),Array.from(t.slice(10,16)).map(t=>t.toString(16).padStart(2,`0`)).join(``)].join(`-`);return logger.log(`[funnel] Generated UUID using crypto.getRandomValues():`,c),c}logger.warn(`[funnel] crypto API not available, using timestamp-based UUID (NOT SECURE)`);let t=new Date().getTime();typeof performance<`u`&&typeof performance.now==`function`&&(t+=performance.now());let c=`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,c=>{let u=(t+Math.random()*16)%16|0;return t=Math.floor(t/16),(c===`x`?u:u&3|8).toString(16)});return logger.log(`[funnel] Generated UUID (fallback):`,c),c}}async function getOrCreateClassroomRegistrationsDoc(t){let c;try{c=await getLocalUserDB(t).get(userClassroomsDoc)}catch(u){let d=u;if(d.status===404)await getLocalUserDB(t).put({_id:userClassroomsDoc,registrations:[]}),c=await getOrCreateClassroomRegistrationsDoc(t);else{let t={name:d.name,status:d.status,message:d.message,reason:d.reason,error:d.error};throw logger.error(`Database error in getOrCreateClassroomRegistrationsDoc (standalone function):`,t),Error(`Database error accessing classroom registrations: ${d.message||d.name||`Unknown error`} (status: ${d.status})`)}}return c}async function getOrCreateCourseRegistrationsDoc(t){let c;try{c=await getLocalUserDB(t).get(userCoursesDoc)}catch(u){if(u.status===404)await getLocalUserDB(t).put({_id:userCoursesDoc,courses:[],studyWeight:{}}),c=await getOrCreateCourseRegistrationsDoc(t);else throw Error(`Unexpected error ${JSON.stringify(u)} in getOrCreateCourseRegistrationDoc...`)}return c}async function updateUserElo(t,c,u){let d=await getOrCreateCourseRegistrationsDoc(t),m=d.courses.find(t=>t.courseID===c);return m.elo=u,getLocalUserDB(t).put(d)}async function registerUserForClassroom(t,c,u){return log4(`Registering user: ${t} in course: ${c}`),getOrCreateClassroomRegistrationsDoc(t).then(d=>{let m={classID:c,registeredAs:u};return d.registrations.filter(t=>t.classID===m.classID&&t.registeredAs===m.registeredAs).length===0?d.registrations.push(m):log4(`User ${t} is already registered for class ${c}`),getLocalUserDB(t).put(d)})}async function dropUserFromClassroom(t,c){return getOrCreateClassroomRegistrationsDoc(t).then(u=>{let d=-1;for(let t=0;t<u.registrations.length;t++)u.registrations[t].classID===c&&(d=t);return d!==-1&&u.registrations.splice(d,1),getLocalUserDB(t).put(u)})}async function getUserClassrooms(t){return getOrCreateClassroomRegistrationsDoc(t)}async function initializeDataLayer(t){if(dataLayerInstance)return logger.warn(`Data layer already initialized. Returning existing instance.`),dataLayerInstance;if(await initializeNavigatorRegistry(),t.options.localStoragePrefix&&(ENV.LOCAL_STORAGE_PREFIX=t.options.localStoragePrefix),t.type===`couch`){if(!t.options.COUCHDB_SERVER_URL||!t.options.COUCHDB_SERVER_PROTOCOL)throw Error(`Missing CouchDB server URL or protocol`);if(ENV.COUCHDB_SERVER_PROTOCOL=t.options.COUCHDB_SERVER_PROTOCOL,ENV.COUCHDB_SERVER_URL=t.options.COUCHDB_SERVER_URL,ENV.COUCHDB_USERNAME=t.options.COUCHDB_USERNAME,ENV.COUCHDB_PASSWORD=t.options.COUCHDB_PASSWORD,t.options.COUCHDB_PASSWORD&&t.options.COUCHDB_USERNAME&&typeof window<`u`){let{CouchDBSyncStrategy:c}=await Promise.resolve().then(()=>(init_CouchDBSyncStrategy(),CouchDBSyncStrategy_exports)),u=new c,d=await(await BaseUser.instance(u,t.options.COUCHDB_USERNAME)).login(t.options.COUCHDB_USERNAME,t.options.COUCHDB_PASSWORD);d.ok?logger.info(`Successfully authenticated as ${t.options.COUCHDB_USERNAME}`):logger.warn(`Authentication failed: ${d.error}`)}let{CouchDataLayerProvider:c}=await Promise.resolve().then(()=>(init_PouchDataLayerProvider(),PouchDataLayerProvider_exports));dataLayerInstance=new c(t.options.COURSE_IDS)}else if(t.type===`static`){let{StaticDataLayerProvider:c}=await Promise.resolve().then(()=>(init_StaticDataLayerProvider(),StaticDataLayerProvider_exports));dataLayerInstance=new c(t.options)}else throw Error(`Unknown data layer type: ${t.type}`);return await dataLayerInstance.initialize(),dataLayerInstance}function getDataLayer(){if(!dataLayerInstance)throw Error(`Data layer not initialized. Call initializeDataLayer first.`);return dataLayerInstance}async function _resetDataLayer(){dataLayerInstance&&await dataLayerInstance.teardown(),dataLayerInstance=null}function isReview(t){return t.status===`review`||t.status===`failed-review`||`reviewID`in t}async function getStudySource(t,c){return t.type===`classroom`?await StudentClassroomDB.factory(t.id,c):hasActiveFilter(t.tagFilter)?new TagFilteredContentSource(t.id,t.tagFilter,c):getDataLayer().getCourseDB(t.id)}function buildStrategyStateId(t,c){return`STRATEGY_STATE::${t}::${c}`}async function importParsedCards(t,c,u){let d=[];for(let m of t)try{let t=await processCard(m,c,u);d.push(t)}catch(t){logger.error(`Error processing card:`,t);let c=m.markdown;m.tags&&m.tags.length>0&&(c+=`
316
+ `);let u=getCourseDB2(t),d=await getCredentialledCourseConfig(t);return await u.put({...c,_rev:d._rev})}function isSuccessRow(t){return`doc`in t&&t.doc!==null&&t.doc!==void 0}async function getCurrentSession(){try{if(ENV.COUCHDB_SERVER_URL===NOT_SET||ENV.COUCHDB_SERVER_PROTOCOL===NOT_SET)throw Error(`CouchDB server configuration not properly initialized. Protocol: "${ENV.COUCHDB_SERVER_PROTOCOL}", URL: "${ENV.COUCHDB_SERVER_URL}"`);let t=ENV.COUCHDB_SERVER_URL.endsWith(`/`)?ENV.COUCHDB_SERVER_URL.slice(0,-1):ENV.COUCHDB_SERVER_URL,c=`${ENV.COUCHDB_SERVER_PROTOCOL}://${t}/_session`;logger.debug(`Attempting session check at: ${c}`);let u=await(0,import_browser_ponyfill.default)(c,{method:`GET`,credentials:`include`});if(!u.ok)throw Error(`Session check failed: ${u.status}`);return await u.json()}catch(t){let c=ENV.COUCHDB_SERVER_URL.endsWith(`/`)?ENV.COUCHDB_SERVER_URL.slice(0,-1):ENV.COUCHDB_SERVER_URL,u=`${ENV.COUCHDB_SERVER_PROTOCOL}://${c}/_session`;throw logger.error(`Session check error attempting to connect to: ${u} - ${t}`),Error(`Session check failed connecting to ${u}: ${t}`)}}async function getLoggedInUsername(){let t=await getCurrentSession();if(t.userCtx.name&&t.userCtx.name!==``)return t.userCtx.name;throw Error(`No logged in user`)}function createPouchDBConfig(){return ENV.COUCHDB_USERNAME&&ENV.COUCHDB_PASSWORD&&typeof window>`u`?{fetch(t,c={}){let u=btoa(`${ENV.COUCHDB_USERNAME}:${ENV.COUCHDB_PASSWORD}`),d=new Headers(c.headers||{});d.set(`Authorization`,`Basic ${u}`);let m={...c,headers:d};return pouchdb_setup_default.fetch(t,m)}}:pouchDBincludeCredentialsConfig}function getCourseDB2(t){return new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+`coursedb-`+t,createPouchDBConfig())}function filterAllDocsByPrefix2(t,c,u){let d={startkey:c,endkey:c+`￰`,include_docs:!0};return u&&Object.assign(d,u),t.allDocs(d)}function getStartAndEndKeys2(t){return{startkey:t,endkey:t+`￰`}}function accomodateGuest(){if(logger.log(`[funnel] accomodateGuest() called`),typeof localStorage>`u`)return logger.log(`[funnel] localStorage not available (Node.js environment), returning default guest`),{username:GuestUsername+`nodejs-test`,firstVisit:!0};let t=`sk-guest-uuid`,c,u=localStorage.getItem(t);if(logger.log(`[funnel] Checking localStorage for key:`,t),logger.log(`[funnel] Existing UUID value:`,u),logger.log(`[funnel] existingUUID !== null:`,u!==null),u!==null)c=!1,logger.log(`[funnel] Returning guest ${u} "logging in".`);else{c=!0,logger.log(`[funnel] No existing UUID, generating new one...`);let u=generateUUID();logger.log(`[funnel] Generated UUID:`,u),logger.log(`[funnel] UUID length:`,u.length);try{localStorage.setItem(t,u),logger.log(`[funnel] Successfully stored UUID in localStorage`);let c=localStorage.getItem(t);logger.log(`[funnel] Verification read from localStorage:`,c)}catch(t){logger.error(`[funnel] ERROR storing UUID:`,t)}logger.log(`[funnel] Accommodating a new guest with account: ${u}`)}let d=localStorage.getItem(t),m=GuestUsername+d;return logger.log(`[funnel] Final UUID from localStorage:`,d),logger.log(`[funnel] GuestUsername constant:`,GuestUsername),logger.log(`[funnel] Final username to return:`,m),{username:m,firstVisit:c};function generateUUID(){if(logger.log(`[funnel] Inside generateUUID()`),typeof crypto<`u`&&typeof crypto.randomUUID==`function`){let t=crypto.randomUUID();return logger.log(`[funnel] Generated UUID using crypto.randomUUID():`,t),t}if(typeof crypto<`u`&&typeof crypto.getRandomValues==`function`){let t=new Uint8Array(16);crypto.getRandomValues(t),t[6]=t[6]&15|64,t[8]=t[8]&63|128;let c=[Array.from(t.slice(0,4)).map(t=>t.toString(16).padStart(2,`0`)).join(``),Array.from(t.slice(4,6)).map(t=>t.toString(16).padStart(2,`0`)).join(``),Array.from(t.slice(6,8)).map(t=>t.toString(16).padStart(2,`0`)).join(``),Array.from(t.slice(8,10)).map(t=>t.toString(16).padStart(2,`0`)).join(``),Array.from(t.slice(10,16)).map(t=>t.toString(16).padStart(2,`0`)).join(``)].join(`-`);return logger.log(`[funnel] Generated UUID using crypto.getRandomValues():`,c),c}logger.warn(`[funnel] crypto API not available, using timestamp-based UUID (NOT SECURE)`);let t=new Date().getTime();typeof performance<`u`&&typeof performance.now==`function`&&(t+=performance.now());let c=`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,c=>{let u=(t+Math.random()*16)%16|0;return t=Math.floor(t/16),(c===`x`?u:u&3|8).toString(16)});return logger.log(`[funnel] Generated UUID (fallback):`,c),c}}async function getOrCreateClassroomRegistrationsDoc(t){let c;try{c=await getLocalUserDB(t).get(userClassroomsDoc)}catch(u){let d=u;if(d.status===404)await getLocalUserDB(t).put({_id:userClassroomsDoc,registrations:[]}),c=await getOrCreateClassroomRegistrationsDoc(t);else{let t={name:d.name,status:d.status,message:d.message,reason:d.reason,error:d.error};throw logger.error(`Database error in getOrCreateClassroomRegistrationsDoc (standalone function):`,t),Error(`Database error accessing classroom registrations: ${d.message||d.name||`Unknown error`} (status: ${d.status})`)}}return c}async function getOrCreateCourseRegistrationsDoc(t){let c;try{c=await getLocalUserDB(t).get(userCoursesDoc)}catch(u){if(u.status===404)await getLocalUserDB(t).put({_id:userCoursesDoc,courses:[],studyWeight:{}}),c=await getOrCreateCourseRegistrationsDoc(t);else throw Error(`Unexpected error ${JSON.stringify(u)} in getOrCreateCourseRegistrationDoc...`)}return c}async function updateUserElo(t,c,u){let d=await getOrCreateCourseRegistrationsDoc(t),m=d.courses.find(t=>t.courseID===c);return m.elo=u,getLocalUserDB(t).put(d)}async function registerUserForClassroom(t,c,u){return log4(`Registering user: ${t} in course: ${c}`),getOrCreateClassroomRegistrationsDoc(t).then(d=>{let m={classID:c,registeredAs:u};return d.registrations.filter(t=>t.classID===m.classID&&t.registeredAs===m.registeredAs).length===0?d.registrations.push(m):log4(`User ${t} is already registered for class ${c}`),getLocalUserDB(t).put(d)})}async function dropUserFromClassroom(t,c){return getOrCreateClassroomRegistrationsDoc(t).then(u=>{let d=-1;for(let t=0;t<u.registrations.length;t++)u.registrations[t].classID===c&&(d=t);return d!==-1&&u.registrations.splice(d,1),getLocalUserDB(t).put(u)})}async function getUserClassrooms(t){return getOrCreateClassroomRegistrationsDoc(t)}async function initializeDataLayer(t){if(dataLayerInstance)return logger.warn(`Data layer already initialized. Returning existing instance.`),dataLayerInstance;if(await initializeNavigatorRegistry(),t.options.localStoragePrefix&&(ENV.LOCAL_STORAGE_PREFIX=t.options.localStoragePrefix),t.type===`couch`){if(!t.options.COUCHDB_SERVER_URL||!t.options.COUCHDB_SERVER_PROTOCOL)throw Error(`Missing CouchDB server URL or protocol`);if(ENV.COUCHDB_SERVER_PROTOCOL=t.options.COUCHDB_SERVER_PROTOCOL,ENV.COUCHDB_SERVER_URL=t.options.COUCHDB_SERVER_URL,ENV.COUCHDB_USERNAME=t.options.COUCHDB_USERNAME,ENV.COUCHDB_PASSWORD=t.options.COUCHDB_PASSWORD,t.options.courseSync){let{CourseSyncService:c}=await Promise.resolve().then(()=>(init_CourseSyncService(),CourseSyncService_exports));c.getInstance().configure(t.options.courseSync)}if(t.options.COUCHDB_PASSWORD&&t.options.COUCHDB_USERNAME&&typeof window<`u`){let{CouchDBSyncStrategy:c}=await Promise.resolve().then(()=>(init_CouchDBSyncStrategy(),CouchDBSyncStrategy_exports)),u=new c,d=await(await BaseUser.instance(u,t.options.COUCHDB_USERNAME)).login(t.options.COUCHDB_USERNAME,t.options.COUCHDB_PASSWORD);d.ok?logger.info(`Successfully authenticated as ${t.options.COUCHDB_USERNAME}`):logger.warn(`Authentication failed: ${d.error}`)}let{CouchDataLayerProvider:c}=await Promise.resolve().then(()=>(init_PouchDataLayerProvider(),PouchDataLayerProvider_exports));dataLayerInstance=new c(t.options.COURSE_IDS)}else if(t.type===`static`){let{StaticDataLayerProvider:c}=await Promise.resolve().then(()=>(init_StaticDataLayerProvider(),StaticDataLayerProvider_exports));dataLayerInstance=new c(t.options)}else throw Error(`Unknown data layer type: ${t.type}`);return await dataLayerInstance.initialize(),dataLayerInstance}function getDataLayer(){if(!dataLayerInstance)throw Error(`Data layer not initialized. Call initializeDataLayer first.`);return dataLayerInstance}async function _resetDataLayer(){dataLayerInstance&&await dataLayerInstance.teardown(),dataLayerInstance=null}function isReview(t){return t.status===`review`||t.status===`failed-review`||`reviewID`in t}async function getStudySource(t,c){return t.type===`classroom`?await StudentClassroomDB.factory(t.id,c):hasActiveFilter(t.tagFilter)?new TagFilteredContentSource(t.id,t.tagFilter,c):getDataLayer().getCourseDB(t.id)}function buildStrategyStateId(t,c){return`STRATEGY_STATE::${t}::${c}`}async function importParsedCards(t,c,u){let d=[];for(let m of t)try{let t=await processCard(m,c,u);d.push(t)}catch(t){logger.error(`Error processing card:`,t);let c=m.markdown;m.tags&&m.tags.length>0&&(c+=`
317
317
  tags: ${m.tags.join(`, `)}`),m.elo!==void 0&&(c+=`
318
318
  elo: ${m.elo}`),d.push({originalText:c,status:`error`,message:`Error processing card: ${t instanceof Error?t.message:`Unknown error`}`})}return d}async function processCard(t,c,u){let{markdown:d,tags:m,elo:g}=t,b=d;m.length>0&&(b+=`
319
319
  tags: ${m.join(`, `)}`),g!==void 0&&(b+=`
@@ -321,7 +321,7 @@ elo: ${g}`);let S={Input:d,Uploads:[]},C={};for(let t of m)C[t]={score:g||0,coun
321
321
  (${c.lapses} * ${b} + ${c.streak} * ${c.bestInterval}) / (${c.lapses} + ${c.streak}) = ${t}`),t}else return b}else return 0}function lastSuccessfulInterval(t){for(let c=t.length-1;c>=1;c--)if(t[c].priorAttemps===0&&t[c].isCorrect){let u=secondsBetween(t[c-1].timeStamp,t[c].timeStamp),d=Math.max(u,1200*60);return logger.debug(`Last interval w/ this card was: ${u}s, returning ${d}s`),d}return getInitialInterval(t)}function getStreak(t){let c=0,u=t.length-1;for(;u>=0&&t[u].isCorrect;)u--,c++;return c}function getLapses(t){return t.filter(t=>t.isCorrect===!1).length}function getInitialInterval(t){return logger.warn(`history of length: ${t.length} ignored!`),3600*24*3}function secondsBetween(t,c){return t=hooks(t),c=hooks(c),duration(c.diff(t)).asSeconds()}function parseAudioURIs(t){return typeof t==`string`?t.match(/https?:\/\/[^\s"'<>]+\.(wav|mp3|ogg|m4a|aac|webm)/gi)??[]:[]}function prefetchAudio(t){return new Promise(c=>{let u=new Audio;u.preload=`auto`;let cleanup=()=>{u.oncanplaythrough=null,u.onerror=null};u.oncanplaythrough=()=>{cleanup(),c()},u.onerror=()=>{cleanup(),logger.warn(`[CardHydrationService] Failed to prefetch audio: ${t}`),c()},u.src=t})}async function validateStaticCourse(t,c){let u={valid:!0,manifestExists:!1,chunksExist:!1,attachmentsExist:!1,errors:[],warnings:[]};try{if(c){if(!(await c.stat(t)).isDirectory())return u.errors.push(`Path is not a directory: ${t}`),u.valid=!1,u}else if(!nodeFS2)return u.errors.push(`File system access not available - validation skipped`),u.valid=!1,u;else if(!(await nodeFS2.promises.stat(t)).isDirectory())return u.errors.push(`Path is not a directory: ${t}`),u.valid=!1,u;let d=`${t}/manifest.json`;try{if(c)if(d=c.joinPath(t,`manifest.json`),await c.exists(d)){u.manifestExists=!0;let t=await c.readFile(d),m=JSON.parse(t);u.courseId=m.courseId,u.courseName=m.courseName,(!m.version||!m.courseId||!m.chunks||!Array.isArray(m.chunks))&&(u.errors.push(`Invalid manifest structure`),u.valid=!1)}else u.errors.push(`Manifest not found: ${d}`),u.valid=!1;else{d=`${t}/manifest.json`,await nodeFS2.promises.access(d),u.manifestExists=!0;let c=await nodeFS2.promises.readFile(d,`utf8`),m=JSON.parse(c);u.courseId=m.courseId,u.courseName=m.courseName,(!m.version||!m.courseId||!m.chunks||!Array.isArray(m.chunks))&&(u.errors.push(`Invalid manifest structure`),u.valid=!1)}}catch(t){let c=t instanceof FileSystemError?t.message:`Manifest not found or invalid: ${d}`;u.errors.push(c),u.valid=!1}let m=`${t}/chunks`;try{c?(m=c.joinPath(t,`chunks`),await c.exists(m)?(await c.stat(m)).isDirectory()?u.chunksExist=!0:(u.errors.push(`Chunks path is not a directory: ${m}`),u.valid=!1):(u.errors.push(`Chunks directory not found: ${m}`),u.valid=!1)):(m=`${t}/chunks`,(await nodeFS2.promises.stat(m)).isDirectory()?u.chunksExist=!0:(u.errors.push(`Chunks path is not a directory: ${m}`),u.valid=!1))}catch(t){let c=t instanceof FileSystemError?t.message:`Chunks directory not found: ${m}`;u.errors.push(c),u.valid=!1}let g;try{c?(g=c.joinPath(t,`attachments`),await c.exists(g)?(await c.stat(g)).isDirectory()&&(u.attachmentsExist=!0):u.warnings.push(`Attachments directory not found: ${g} (this is OK if course has no attachments)`)):(g=`${t}/attachments`,(await nodeFS2.promises.stat(g)).isDirectory()&&(u.attachmentsExist=!0))}catch(c){g=g||`${t}/attachments`;let d=c instanceof FileSystemError?c.message:`Attachments directory not found: ${g} (this is OK if course has no attachments)`;u.warnings.push(d)}}catch(t){u.errors.push(`Failed to validate static course: ${t instanceof Error?t.message:String(t)}`),u.valid=!1}return u}async function validateMigration(t,c,u){let d={valid:!0,documentCountMatch:!1,attachmentIntegrity:!1,viewFunctionality:!1,issues:[]};try{logger.info(`Starting migration validation...`),d.documentCountMatch=compareDocumentCounts(c,await getActualDocumentCounts(t),d.issues),await validateCourseConfig(t,u,d.issues),d.viewFunctionality=await validateViews(t,u,d.issues),d.attachmentIntegrity=await validateAttachmentIntegrity(t,d.issues),d.valid=d.documentCountMatch&&d.viewFunctionality&&d.attachmentIntegrity,logger.info(`Migration validation completed. Valid: ${d.valid}`),d.issues.length>0&&(logger.info(`Validation issues: ${d.issues.length}`),d.issues.forEach(t=>{t.type===`error`?logger.error(`${t.category}: ${t.message}`):logger.warn(`${t.category}: ${t.message}`)}))}catch(t){d.valid=!1,d.issues.push({type:`error`,category:`metadata`,message:`Validation failed: ${t instanceof Error?t.message:String(t)}`})}return d}async function getActualDocumentCounts(t){let c={};try{let u=await t.allDocs({include_docs:!0});for(let t of u.rows){if(t.id.startsWith(`_design/`)){c._design=(c._design||0)+1;continue}let u=t.doc;u&&u.docType?c[u.docType]=(c[u.docType]||0)+1:c.unknown=(c.unknown||0)+1}}catch(t){logger.error(`Failed to get actual document counts:`,t)}return c}function compareDocumentCounts(t,c,u){let d=!0;for(let[m,g]of Object.entries(t)){let t=c[m]||0;t!==g&&(d=!1,u.push({type:`error`,category:`documents`,message:`Document count mismatch for ${m}: expected ${g}, got ${t}`}))}for(let[d,m]of Object.entries(c))!t[d]&&d!==`_design`&&u.push({type:`warning`,category:`documents`,message:`Unexpected document type found: ${d} (${m} documents)`});return d}async function validateCourseConfig(t,c,u){try{let d=await t.get(`CourseConfig`);if(!d){u.push({type:`error`,category:`course_config`,message:`CourseConfig document not found after migration`});return}d.courseID||u.push({type:`warning`,category:`course_config`,message:`CourseConfig document missing courseID field`}),d.courseID!==c.courseId&&u.push({type:`warning`,category:`course_config`,message:`CourseConfig courseID mismatch: expected ${c.courseId}, got ${d.courseID}`}),logger.debug(`CourseConfig document validation passed`)}catch(t){t.status===404?u.push({type:`error`,category:`course_config`,message:`CourseConfig document not found in database`}):u.push({type:`error`,category:`course_config`,message:`Failed to validate CourseConfig document: ${t instanceof Error?t.message:String(t)}`})}}async function validateViews(t,c,u){let d=!0;try{for(let m of c.designDocs)try{if(!await t.get(m._id)){d=!1,u.push({type:`error`,category:`views`,message:`Design document not found: ${m._id}`});continue}for(let c of Object.keys(m.views))try{let u=`${m._id}/${c}`;await t.query(u,{limit:1})}catch(t){d=!1,u.push({type:`error`,category:`views`,message:`View not accessible: ${m._id}/${c} - ${t}`})}}catch(t){d=!1,u.push({type:`error`,category:`views`,message:`Failed to validate design document ${m._id}: ${t}`})}}catch(t){d=!1,u.push({type:`error`,category:`views`,message:`View validation failed: ${t instanceof Error?t.message:String(t)}`})}return d}async function validateAttachmentIntegrity(t,c){let u=!0;try{let d=await t.allDocs({include_docs:!0,limit:10}),m=0,g=0;for(let b of d.rows){let d=b.doc;if(d&&d._attachments)for(let[b,S]of Object.entries(d._attachments)){m++;try{await t.getAttachment(d._id,b)&&g++}catch(t){u=!1,c.push({type:`error`,category:`attachments`,message:`Attachment not accessible: ${d._id}/${b} - ${t}`})}}}m===0?c.push({type:`warning`,category:`attachments`,message:`No attachments found in sampled documents`}):logger.info(`Validated ${g}/${m} sampled attachments`)}catch(t){u=!1,c.push({type:`error`,category:`attachments`,message:`Attachment validation failed: ${t instanceof Error?t.message:String(t)}`})}return u}function buildSourceSummary(t,c,u){let d=t.weighted.map(t=>t.score),m=t.weighted.filter(t=>getCardOrigin(t)===`review`).length,g=t.weighted.filter(t=>getCardOrigin(t)===`new`).length;return{sourceIndex:t.sourceIndex,sourceId:c,sourceName:u,totalCards:t.weighted.length,reviewCount:m,newCount:g,topScore:d.length>0?Math.max(...d):0,bottomScore:d.length>0?Math.min(...d):0,scoreRange:d.length>0?[Math.min(...d),Math.max(...d)]:[0,0],avgScore:d.length>0?d.reduce((t,c)=>t+c,0)/d.length:0}}function buildSourceBreakdown(t,c,u){let d=u.filter(c=>c.courseId===t),m=d.filter(t=>t.selected);return{sourceId:t,sourceName:c,reviewsProvided:d.filter(t=>t.origin===`review`).length,newProvided:d.filter(t=>t.origin===`new`).length,reviewsSelected:m.filter(t=>t.origin===`review`).length,newSelected:m.filter(t=>t.origin===`new`).length,totalSelected:m.length,selectionRate:d.length>0?m.length/d.length*100:0}}function captureMixerRun(t,c,u,d,m,g,b){let S=c.map((t,c)=>buildSourceSummary(t,u[c]||`source-${c}`,d[c])),C=new Set(b.map(t=>t.cardId)),w=new Map;c.forEach(t=>{let c=[...t.weighted].sort((t,c)=>c.score-t.score),d=new Map;c.forEach((t,c)=>{d.set(t.cardId,c+1)}),w.set(u[t.sourceIndex]||`source-${t.sourceIndex}`,d)});let T=new Map;b.forEach((t,c)=>{T.set(t.cardId,c+1)});let E=new Map;c.forEach(t=>{t.weighted.forEach(t=>{E.set(t.cardId,t)})});let D=Array.from(E.values()).map(t=>({cardId:t.cardId,courseId:t.courseId,origin:getCardOrigin(t),score:t.score,sourceIndex:c.findIndex(c=>c.weighted.some(c=>c.cardId===t.cardId)),selected:C.has(t.cardId),rankInSource:w.get(t.courseId)?.get(t.cardId),rankInMix:T.get(t.cardId)})),O=Array.from(new Set(u.filter(t=>t))).map((t,c)=>buildSourceBreakdown(t,d[c],D)),Or={runId:`mix-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,timestamp:new Date,mixerType:t,requestedLimit:m,quotaPerSource:g,sourceSummaries:S,cards:D,finalCount:b.length,reviewsSelected:b.filter(t=>getCardOrigin(t)===`review`).length,newSelected:b.filter(t=>getCardOrigin(t)===`new`).length,sourceBreakdowns:O};runHistory2.unshift(Or),runHistory2.length>MAX_RUNS2&&runHistory2.pop()}function printMixerSummary(t){console.group(`\u{1F3A8} Mixer Run: ${t.mixerType}`),logger.info(`Run ID: ${t.runId}`),logger.info(`Time: ${t.timestamp.toISOString()}`),logger.info(`Config: limit=${t.requestedLimit}${t.quotaPerSource?`, quota/source=${t.quotaPerSource}`:``}`),console.group(`\u{1F4E5} Input: ${t.sourceSummaries.length} sources`);for(let c of t.sourceSummaries)logger.info(` ${c.sourceName||c.sourceId}: ${c.totalCards} cards (${c.reviewCount} reviews, ${c.newCount} new)`),logger.info(` Score range: [${c.scoreRange[0].toFixed(2)}, ${c.scoreRange[1].toFixed(2)}], avg: ${c.avgScore.toFixed(2)}`);console.groupEnd(),console.group(`\u{1F4E4} Output: ${t.finalCount} cards selected (${t.reviewsSelected} reviews, ${t.newSelected} new)`);for(let c of t.sourceBreakdowns){let t=c.sourceName||c.sourceId;logger.info(` ${t}: ${c.totalSelected} selected (${c.reviewsSelected} reviews, ${c.newSelected} new) - ${c.selectionRate.toFixed(1)}% selection rate`)}console.groupEnd(),console.groupEnd()}function mountMixerDebugger(){if(typeof window>`u`)return;let t=window;t.skuilder=t.skuilder||{},t.skuilder.mixer=mixerDebugAPI}function startSessionTracking(t,c,u){clearRunHistory();let d=`session-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;activeSession={sessionId:d,startTime:new Date,initialQueues:{timestamp:new Date,reviewQLength:t,newQLength:c,failedQLength:u},presentations:[],queueSnapshots:[]},logger.debug(`[SessionDebugger] Started tracking session: ${d}`)}function recordCardPresentation(t,c,u,d,m,g){if(!activeSession){logger.warn(`[SessionDebugger] No active session to record presentation`);return}activeSession.presentations.push({timestamp:new Date,sequenceNumber:activeSession.presentations.length+1,cardId:t,courseId:c,courseName:u,origin:d,queueSource:m,score:g})}function snapshotQueues(t,c,u,d,m){activeSession&&activeSession.queueSnapshots.push({timestamp:new Date,reviewQLength:t,newQLength:c,failedQLength:u,reviewQNext3:d,newQNext3:m})}function endSessionTracking(){activeSession&&(activeSession.endTime=new Date,sessionHistory.unshift(activeSession),sessionHistory.length>MAX_HISTORY&&sessionHistory.pop(),logger.debug(`[SessionDebugger] Ended session: ${activeSession.sessionId}`),activeSession=null)}function showCurrentQueue(){if(!activeSession){logger.info(`[Session Debug] No active session.`);return}let t=activeSession.queueSnapshots[activeSession.queueSnapshots.length-1]||activeSession.initialQueues;console.group(`📊 Current Queue State`),logger.info(`Review Queue: ${t.reviewQLength} cards`),t.reviewQNext3&&t.reviewQNext3.length>0&&logger.info(` Next: ${t.reviewQNext3.join(`, `)}`),logger.info(`New Queue: ${t.newQLength} cards`),t.newQNext3&&t.newQNext3.length>0&&logger.info(` Next: ${t.newQNext3.join(`, `)}`),logger.info(`Failed Queue: ${t.failedQLength} cards`),console.groupEnd()}function showPresentationHistory(t=0){let c=t===0&&activeSession?activeSession:sessionHistory[t];if(!c){logger.info(`[Session Debug] No session found at index ${t}`);return}console.group(`\u{1F4DC} Session History: ${c.sessionId}`),logger.info(`Started: ${c.startTime.toLocaleTimeString()}`),c.endTime&&logger.info(`Ended: ${c.endTime.toLocaleTimeString()}`),logger.info(`Cards presented: ${c.presentations.length}`),c.presentations.length>0&&console.table(c.presentations.map(t=>({"#":t.sequenceNumber,course:t.courseName||t.courseId.slice(0,8),origin:t.origin,queue:t.queueSource,score:t.score?.toFixed(3)||`-`,time:t.timestamp.toLocaleTimeString()}))),console.groupEnd()}function showInterleaving(t=0){let c=t===0&&activeSession?activeSession:sessionHistory[t];if(!c){logger.info(`[Session Debug] No session found at index ${t}`);return}console.group(`🔀 Interleaving Analysis`);let u=new Map,d=new Map;if(c.presentations.forEach(t=>{let c=t.courseName||t.courseId;u.set(c,(u.get(c)||0)+1),d.has(c)||d.set(c,{review:0,new:0,failed:0});let m=d.get(c);m[t.origin]++}),logger.info(`Course distribution:`),console.table(Array.from(u.entries()).map(([t,u])=>{let m=d.get(t);return{course:t,total:u,reviews:m.review,new:m.new,failed:m.failed,percentage:(u/c.presentations.length*100).toFixed(1)+`%`}})),c.presentations.length>0){logger.info(`
322
322
  Presentation sequence (first 20):`);let t=c.presentations.slice(0,20).map((t,c)=>`${c+1}. ${t.courseName||t.courseId.slice(0,8)} (${t.origin})`).join(`
323
323
  `);logger.info(t)}let m=0,g=1,b=c.presentations[0]?.courseId;for(let t=1;t<c.presentations.length;t++)c.presentations[t].courseId===b?(g++,m=Math.max(m,g)):(b=c.presentations[t].courseId,g=1);m>3&&(logger.info(`
324
- \u26A0\uFE0F Detected clustering: max ${m} cards from same course in a row`),logger.info(`This suggests cards are sorted by score rather than round-robin by course.`)),console.groupEnd()}function mountSessionDebugger(){if(typeof window>`u`)return;let t=window;t.skuilder=t.skuilder||{},t.skuilder.session=sessionDebugAPI}var import___vite_browser_external,import___vite_browser_external$1,import___vite_browser_external$2,import_browser_ponyfill,import_browser_ponyfill$1,import_browser,_SessionController2,__defProp,__getOwnPropNames,__glob,__esm,__export,init_adminDB,init_classroomDB,init_SyncStrategy,isDevelopment,logger,init_logger,GuestUsername,log,DocType,DocTypePrefixes,init_types_legacy,init_util,pouchdb_setup_default,init_pouchdb_setup,init_dataDirectory,REVIEW_TIME_FORMAT,log2,init_userDBHelpers,Loggable,init_Loggable,UpdateQueue,init_updateQueue,UsrCrsData,init_user_course_relDB,CLIENT_CACHE,init_clientCache,AlreadyTaggedErr,init_courseAPI,courseLookupDBTitle,CourseLookup,init_courseLookupDB,PipelineDebugger_exports,_activePipeline,MAX_RUNS,runHistory,DISCARDED_KEEP_TOP,_uiContainer,_selectedRunIndex,_cardSearchQuery,pipelineDebugAPI,init_PipelineDebugger,CompositeGenerator_exports,AggregationMode,DEFAULT_AGGREGATION_MODE,FREQUENCY_BOOST_FACTOR,CompositeGenerator,init_CompositeGenerator,elo_exports,ELONavigator,init_elo,generators_exports,init_generators,prescribed_exports,DEFAULT_FRESHNESS_WINDOW,DEFAULT_MAX_DIRECT_PER_RUN,DEFAULT_MAX_SUPPORT_PER_RUN,DEFAULT_HIERARCHY_DEPTH,DEFAULT_MIN_COUNT,BASE_TARGET_SCORE,BASE_SUPPORT_SCORE,DISCOVERED_SUPPORT_SCORE,MAX_TARGET_MULTIPLIER,MAX_SUPPORT_MULTIPLIER,PRESCRIBED_DEBUG_VERSION,PrescribedCardsGenerator,init_prescribed,srs_exports,DEFAULT_HEALTHY_BACKLOG,MAX_BACKLOG_PRESSURE,SRSNavigator,init_srs,types_exports,init_types,globImport_generators,init_,DEFAULT_LEARNABLE_WEIGHT,init_contentNavigationStrategy,WeightedFilter_exports,WeightedFilter,init_WeightedFilter,eloDistance_exports,DEFAULT_HALF_LIFE,DEFAULT_MIN_MULTIPLIER,DEFAULT_MAX_MULTIPLIER,init_eloDistance,hierarchyDefinition_exports,DEFAULT_MIN_COUNT2,HierarchyDefinitionNavigator,init_hierarchyDefinition,userTagPreference_exports,UserTagPreferenceFilter,init_userTagPreference,filters_exports,init_filters,inferredPreferenceStub_exports,INFERRED_PREFERENCE_NAVIGATOR_STUB,init_inferredPreferenceStub,interferenceMitigator_exports,DEFAULT_MIN_COUNT3,DEFAULT_MIN_ELAPSED_DAYS,DEFAULT_INTERFERENCE_DECAY,InterferenceMitigatorNavigator,init_interferenceMitigator,relativePriority_exports,DEFAULT_PRIORITY,DEFAULT_PRIORITY_INFLUENCE,DEFAULT_COMBINE_MODE,RelativePriorityNavigator,init_relativePriority,types_exports2,init_types2,userGoalStub_exports,USER_GOAL_NAVIGATOR_STUB,init_userGoalStub,globImport_filters,init_2,init_gradient,MIN_OBSERVATIONS_FOR_UPDATE,LEARNING_RATE,MAX_WEIGHT_DELTA,MIN_R_SQUARED_FOR_GRADIENT,FLAT_GRADIENT_THRESHOLD,MAX_HISTORY_LENGTH,init_learning,init_signal,init_recording,MIN_SPREAD,MAX_SPREAD,MIN_WEIGHT,MAX_WEIGHT,init_orchestration,Pipeline_exports,VERBOSE_RESULTS,Pipeline,init_Pipeline,defaults_exports,init_defaults,PipelineAssembler_exports,PipelineAssembler,init_PipelineAssembler,globImport,init_3,navigators_exports,navigatorRegistry,Navigators,NavigatorRole,NavigatorRoles,ContentNavigator,init_navigators,CoursesDB,CourseDB,init_courseDB,classroomLookupDBTitle,CLASSROOM_CONFIG,ClassroomDBBase,StudentClassroomDB,TeacherClassroomDB,ClassroomLookupDB,init_classroomDB2,AdminDB,init_adminDB2,CourseSyncService,init_CourseSyncService,init_auth,CouchDBSyncStrategy_exports,log3,CouchDBSyncStrategy,init_CouchDBSyncStrategy,isBrowser,GUEST_LOCAL_DB,localUserDB,pouchDBincludeCredentialsConfig,REVIEW_TIME_FORMAT2,init_couch,log4,BaseUser,userCoursesDoc,userClassroomsDoc,init_BaseUserDB,init_common,PouchDataLayerProvider_exports,CouchDataLayerProvider,init_PouchDataLayerProvider,pathUtils,nodeFS,StaticDataUnpacker,init_StaticDataUnpacker,StaticCourseDB,init_courseDB2,StaticCoursesDB,init_coursesDB,NoOpSyncStrategy,init_NoOpSyncStrategy,StaticDataLayerProvider_exports,StaticDataLayerProvider,init_StaticDataLayerProvider,NOT_SET,ENV,dataLayerInstance,init_factory,TagFilteredContentSource,init_TagFilteredContentSource,init_contentSource,init_courseDB3,init_dataLayerProvider,init_userDB,init_interfaces,init_user,init_strategyState,init_userOutcome,init_cardProcessor,init_types3,init_bulkImport,userDBDebugAPI,init_UserDBDebugger,init_core,duration,SrsService,EloService,ResponseProcessor,CardHydrationService,ItemQueue,CouchDBToStaticPacker,DEFAULT_MIGRATION_OPTIONS,FileSystemError,nodeFS2,nodeFS3,nodePath,StaticToCouchDBMigrator,QuotaRoundRobinMixer,MAX_RUNS2,runHistory2,mixerDebugAPI,activeSession,sessionHistory,MAX_HISTORY,sessionDebugAPI,SessionController,init_dist=__esmMin((()=>{init_defineProperty(),init_index_browser_es$5(),init_index_browser_es(),init_index_es(),import___vite_browser_external=__toESM$2(require___vite_browser_external(),1),import___vite_browser_external$1=__toESM$2(require___vite_browser_external(),1),import___vite_browser_external$2=__toESM$2(require___vite_browser_external(),1),init_moment(),init_dist$1(),init_esm_browser(),import_browser_ponyfill=__toESM$2(require_browser_ponyfill(),1),import_browser_ponyfill$1=__toESM$2(require_browser_ponyfill(),1),import_browser=__toESM$2(require_browser(),1),__defProp=Object.defineProperty,__getOwnPropNames=Object.getOwnPropertyNames,__glob=t=>c=>{var u=t[c];if(u)return u();throw Error(`Module not found in bundle: `+c)},__esm=(t,c)=>function __init(){return t&&(c=(0,t[__getOwnPropNames(t)[0]])(t=0)),c},__export=(t,c)=>{for(var u in c)__defProp(t,u,{get:c[u],enumerable:!0})},init_adminDB=__esm({"src/core/interfaces/adminDB.ts"(){"use strict";}}),init_classroomDB=__esm({"src/core/interfaces/classroomDB.ts"(){"use strict";}}),init_SyncStrategy=__esm({"src/impl/common/SyncStrategy.ts"(){"use strict";}}),init_logger=__esm({"src/util/logger.ts"(){"use strict";isDevelopment=typeof process<`u`&&process.env.NODE_ENV===`development`,logger={debug:(t,...c)=>{isDevelopment&&console.debug(`[DB:DEBUG] ${t}`,...c)},info:(t,...c)=>{console.info(`[DB:INFO] ${t}`,...c)},warn:(t,...c)=>{console.warn(`[DB:WARN] ${t}`,...c)},error:(t,...c)=>{console.error(`[DB:ERROR] ${t}`,...c)},log:(t,...c)=>{isDevelopment&&console.log(`[DB:LOG] ${t}`,...c)}}}}),init_types_legacy=__esm({"src/core/types/types-legacy.ts"(){"use strict";init_logger(),GuestUsername=`sk-guest-`,log=t=>{logger.log(t)},DocType=(t=>(t.DISPLAYABLE_DATA=`DISPLAYABLE_DATA`,t.CARD=`CARD`,t.DATASHAPE=`DATASHAPE`,t.QUESTIONTYPE=`QUESTION`,t.VIEW=`VIEW`,t.PEDAGOGY=`PEDAGOGY`,t.CARDRECORD=`CARDRECORD`,t.SCHEDULED_CARD=`SCHEDULED_CARD`,t.TAG=`TAG`,t.NAVIGATION_STRATEGY=`NAVIGATION_STRATEGY`,t.STRATEGY_STATE=`STRATEGY_STATE`,t.USER_OUTCOME=`USER_OUTCOME`,t.STRATEGY_LEARNING_STATE=`STRATEGY_LEARNING_STATE`,t))(DocType||{}),DocTypePrefixes={CARD:`c`,DISPLAYABLE_DATA:`dd`,TAG:`TAG`,CARDRECORD:`cardH`,SCHEDULED_CARD:`card_review_`,DATASHAPE:`DATASHAPE`,QUESTION:`QUESTION`,VIEW:`VIEW`,PEDAGOGY:`PEDAGOGY`,NAVIGATION_STRATEGY:`NAVIGATION_STRATEGY`,STRATEGY_STATE:`STRATEGY_STATE`,USER_OUTCOME:`USER_OUTCOME`,STRATEGY_LEARNING_STATE:`STRATEGY_LEARNING_STATE`}}}),init_util=__esm({"src/core/util/index.ts"(){"use strict";init_types_legacy()}}),init_pouchdb_setup=__esm({"src/impl/couch/pouchdb-setup.ts"(){"use strict";PouchDB.plugin(plugin$1),PouchDB.plugin(plugin),PouchDB.debug!==void 0&&PouchDB.debug.disable(),PouchDB.defaults({}),pouchdb_setup_default=PouchDB}}),init_dataDirectory=__esm({"src/util/dataDirectory.ts"(){"use strict";init_logger(),init_factory()}}),init_userDBHelpers=__esm({"src/impl/common/userDBHelpers.ts"(){"use strict";init_core(),init_logger(),init_pouchdb_setup(),init_dataDirectory(),REVIEW_TIME_FORMAT=`YYYY-MM-DD--kk:mm:ss-SSS`,log2=t=>{logger.info(t)}}}),init_Loggable=__esm({"src/util/Loggable.ts"(){"use strict";Loggable=class{log(...t){console.log(`LOG-${this._className}@${new Date}:`,...t)}error(...t){console.error(`ERROR-${this._className}@${new Date}:`,...t)}}}}),init_updateQueue=__esm({"src/impl/couch/updateQueue.ts"(){"use strict";init_Loggable(),init_logger(),UpdateQueue=class extends Loggable{update(t,c){return logger.debug(`Update requested on doc: ${t}`),this.pendingUpdates[t]?this.pendingUpdates[t].push(c):this.pendingUpdates[t]=[c],this.applyUpdates(t)}constructor(t,c){super(),_defineProperty$2(this,`_className`,`UpdateQueue`),_defineProperty$2(this,`pendingUpdates`,{}),_defineProperty$2(this,`inprogressUpdates`,{}),_defineProperty$2(this,`readDB`,void 0),_defineProperty$2(this,`writeDB`,void 0),this.readDB=t,this.writeDB=c||t,logger.debug(`UpdateQ initialized...`),this.readDB.info().then(t=>{logger.debug(`db info: ${JSON.stringify(t)}`)})}async applyUpdates(t){if(logger.debug(`Applying updates on doc: ${t}`),this.inprogressUpdates[t]){for(;this.inprogressUpdates[t];)await new Promise(t=>setTimeout(t,Math.random()*50));return this.applyUpdates(t)}else if(this.pendingUpdates[t]&&this.pendingUpdates[t].length>0){this.inprogressUpdates[t]=!0;let c=5;for(let c=0;c<5;c++)try{let c={...await this.readDB.get(t)},u=[...this.pendingUpdates[t]];for(let t of u)c=typeof t==`function`?{...c,...t(c)}:{...c,...t};if(await this.writeDB.put(c),this.pendingUpdates[t].splice(0,u.length),this.pendingUpdates[t].length===0)this.inprogressUpdates[t]=!1,delete this.inprogressUpdates[t];else return this.applyUpdates(t);return c}catch(u){if(u.name===`conflict`&&c<4)logger.warn(`Conflict on update for doc ${t}, retry #${c+1}`),await new Promise(t=>setTimeout(t,50*Math.random()));else if(u.name===`not_found`&&c===0)throw logger.warn(`Update failed for ${t} - does not exist. Throwing to caller.`),delete this.inprogressUpdates[t],u;else throw delete this.inprogressUpdates[t],this.pendingUpdates[t]&&delete this.pendingUpdates[t],logger.error(`Error on attemped update (retry ${c}): ${JSON.stringify(u)}`),u}throw Error(`UpdateQueue failed for doc ${t} after 5 retries.`)}else throw Error(`Empty Updates Queue Triggered`)}}}}),init_user_course_relDB=__esm({"src/impl/couch/user-course-relDB.ts"(){"use strict";init_logger(),UsrCrsData=class{constructor(t,c){_defineProperty$2(this,`user`,void 0),_defineProperty$2(this,`_courseId`,void 0),this.user=t,this._courseId=c}async getReviewsForcast(t){let c=hooks.utc().add(t,`days`);return this.getReviewstoDate(c)}async getPendingReviews(){let t=hooks.utc();return this.getReviewstoDate(t)}async getScheduledReviewCount(){return(await this.getPendingReviews()).length}async getCourseSettings(){let t=(await this.user.getCourseRegistrationsDoc()).courses.find(t=>t.courseID===this._courseId);return t&&t.settings?t.settings:(logger.warn(`no settings found during lookup on course ${this._courseId}`),{})}updateCourseSettings(t){`updateCourseSettings`in this.user&&this.user.updateCourseSettings(this._courseId,t)}async getStrategyState(t){return this.user.getStrategyState(this._courseId,t)}async putStrategyState(t,c){return this.user.putStrategyState(this._courseId,t,c)}async deleteStrategyState(t){return this.user.deleteStrategyState(this._courseId,t)}async getReviewstoDate(t){let c=await this.user.getPendingReviews(this._courseId);return logger.debug(`Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`),c.filter(c=>{let u=hooks.utc(c.reviewTime);return t.isAfter(u)})}}}}),init_clientCache=__esm({"src/impl/couch/clientCache.ts"(){"use strict";CLIENT_CACHE={}}}),init_courseAPI=__esm({"src/impl/couch/courseAPI.ts"(){"use strict";init_pouchdb_setup(),init_couch(),init_factory(),init_courseDB(),init_types_legacy(),init_common(),init_logger(),AlreadyTaggedErr=class extends Error{constructor(t){super(t),this.name=`AlreadyTaggedErr`}}}}),init_courseLookupDB=__esm({"src/impl/couch/courseLookupDB.ts"(){"use strict";var t;init_pouchdb_setup(),init_factory(),init_logger(),courseLookupDBTitle=`coursedb-lookup`,logger.debug(`COURSELOOKUP FILE RUNNING`),CourseLookup=(t=class _CourseLookup{static get _db(){if(this._dbInstance)return this._dbInstance;if(ENV.COUCHDB_SERVER_URL===`NOT_SET`||!ENV.COUCHDB_SERVER_URL)throw Error(`CourseLookup.db: COUCHDB_SERVER_URL is not set. Ensure initializeDataLayer has been called with valid configuration.`);if(ENV.COUCHDB_SERVER_PROTOCOL===`NOT_SET`||!ENV.COUCHDB_SERVER_PROTOCOL)throw Error(`CourseLookup.db: COUCHDB_SERVER_PROTOCOL is not set. Ensure initializeDataLayer has been called with valid configuration.`);let t=`${ENV.COUCHDB_SERVER_PROTOCOL}://${ENV.COUCHDB_SERVER_URL}/${courseLookupDBTitle}`,c={};ENV.COUCHDB_USERNAME&&ENV.COUCHDB_PASSWORD?(c.auth={username:ENV.COUCHDB_USERNAME,password:ENV.COUCHDB_PASSWORD},logger.info(`CourseLookup: Connecting to ${t} with authentication.`)):logger.info(`CourseLookup: Connecting to ${t} without authentication.`);try{return this._dbInstance=new pouchdb_setup_default(t,c),logger.info(`CourseLookup: Database instance created for ${courseLookupDBTitle}.`),this._dbInstance}catch(c){throw logger.error(`CourseLookup: Failed to create PouchDB instance for ${t}`,c),this._dbInstance=null,Error(`CourseLookup: Failed to initialize database connection: ${c instanceof Error?c.message:String(c)}`)}}static async add(t){return(await _CourseLookup._db.post({name:t})).id}static async addWithId(t,c,u){let d={_id:t,name:c};u&&(d.disambiguator=u),await _CourseLookup._db.put(d)}static async delete(t){let c=await _CourseLookup._db.get(t);return await _CourseLookup._db.remove(c)}static async allCourseWare(){return(await _CourseLookup._db.allDocs({include_docs:!0})).rows.map(t=>t.doc)}static async updateDisambiguator(t,c){let u=await _CourseLookup._db.get(t);return u.disambiguator=c,await _CourseLookup._db.put(u)}static async isCourse(t){try{return await _CourseLookup._db.get(t),!0}catch(t){return logger.info(`Courselookup failed:`,t),!1}}},_defineProperty$2(t,`_dbInstance`,null),t)}}),PipelineDebugger_exports={},__export(PipelineDebugger_exports,{buildRunReport:()=>buildRunReport,captureRun:()=>captureRun,clearRunHistory:()=>clearRunHistory,mountPipelineDebugger:()=>mountPipelineDebugger,pipelineDebugAPI:()=>pipelineDebugAPI,registerPipelineForDebug:()=>registerPipelineForDebug}),init_PipelineDebugger=__esm({"src/core/navigators/PipelineDebugger.ts"(){"use strict";init_navigators(),init_logger(),_activePipeline=null,MAX_RUNS=10,runHistory=[],DISCARDED_KEEP_TOP=25,_uiContainer=null,_selectedRunIndex=null,_cardSearchQuery=``,pipelineDebugAPI={get runs(){return[...runHistory]},showRun(t=0){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}let c;if(typeof t==`number`){if(c=runHistory[t],!c){logger.info(`[Pipeline Debug] No run found at index ${t}. History length: ${runHistory.length}`);return}}else if(c=runHistory.find(c=>c.runId.endsWith(t)),!c){logger.info(`[Pipeline Debug] No run found matching ID '${t}'.`);return}printRunSummary(c)},showLastRun(){this.showRun(0)},showCard(t){for(let c of runHistory){let u=c.cards.find(c=>c.cardId===t);if(u){console.group(`\u{1F3B4} Card: ${t}`),logger.info(`Course: ${u.courseId}`),logger.info(`Origin: ${u.origin}`),logger.info(`Card ELO: ${u.cardElo??`unknown`} | User ELO: ${c.userElo??`unknown`}`),logger.info(`Final score: ${u.finalScore.toFixed(3)}`),logger.info(`Selected: ${u.selected?`Yes ✅`:`No ❌`}`),u.tags&&u.tags.length>0&&logger.info(`Tags (${u.tags.length}): ${u.tags.join(`, `)}`),logger.info(`Provenance:`),logger.info(formatProvenance(u.provenance)),console.groupEnd();return}}let c=runHistory.filter(t=>t.discardedTail&&t.discardedTail.count>0);c.length>0?logger.info(`[Pipeline Debug] Card '${t}' not found in retained cards. ${c.length} run(s) have discarded tails that were not retained \u2014 the card may have been a low-score candidate. See run.discardedTail for ranges.`):logger.info(`[Pipeline Debug] Card '${t}' not found in recent runs.`)},explainReviews(){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}console.group(`📋 Review Selection Analysis`);for(let t of runHistory){console.group(`Run: ${t.courseId} @ ${t.timestamp.toLocaleTimeString()}`);let c=t.cards.filter(t=>t.origin===`review`),u=c.filter(t=>t.selected);if(c.length===0)logger.info(`❌ No reviews were generated. Check SRS logs for why.`);else if(u.length===0){logger.info(`\u26A0\uFE0F ${c.length} reviews generated but none selected.`),logger.info(`Possible reasons:`);let u=Math.max(...t.cards.filter(t=>t.origin===`new`&&t.selected).map(t=>t.finalScore),0),d=Math.max(...c.map(t=>t.finalScore),0);d<u&&logger.info(` - New cards scored higher (top new: ${u.toFixed(2)}, top review: ${d.toFixed(2)})`);let m=c.sort((t,c)=>c.finalScore-t.finalScore)[0];m&&(logger.info(` - Top review score: ${m.finalScore.toFixed(3)}`),logger.info(` - Its provenance:`),logger.info(formatProvenance(m.provenance)))}else{logger.info(`\u2705 ${u.length}/${c.length} reviews selected.`),logger.info(`Top selected review:`);let t=u.sort((t,c)=>c.finalScore-t.finalScore)[0];logger.info(formatProvenance(t.provenance))}console.groupEnd()}console.groupEnd()},showPrescribed(t){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}let c=runHistory[0],u=c.cards.filter(t=>t.provenance.some(t=>t.strategy===`prescribed`));if(console.group(`\u{1F9ED} Prescribed Debug (${c.courseId})`),u.length===0){logger.info(`No prescribed-generated cards were present in the most recent run.`),console.groupEnd();return}let d=u.map(t=>{let c=t.provenance.find(t=>t.strategy===`prescribed`)?.reason??``,u=c.match(/group=([^;]+)/)?.[1]??`unknown`,d=c.match(/mode=([^;]+)/)?.[1]??`unknown`,m=c.match(/blocked=([^;]+)/)?.[1]??`unknown`,g=c.match(/blockedTargets=([^;]+)/)?.[1]??`none`,b=c.match(/supportCard=([^;]+)/)?.[1]??`none`,S=c.match(/supportTags=([^;]+)/)?.[1]??`none`,C=c.match(/multiplier=([^;]+)/)?.[1]??`unknown`;return{group:u,mode:d,supportSource:d===`discovered-support`?`discovered`:d===`support`?`authored`:`n/a`,cardId:t.cardId,selected:t.selected?`yes`:`no`,finalScore:t.finalScore.toFixed(3),blocked:m,blockedTargets:g,supportCard:b,supportTags:S,multiplier:C}}).filter(c=>!t||c.group===t).sort((t,c)=>Number(c.finalScore)-Number(t.finalScore));if(d.length===0){logger.info(`[Pipeline Debug] No prescribed cards matched group '${t}' in the most recent run.`),console.groupEnd();return}console.table(d);let m=d.filter(t=>t.selected===`yes`),g=new Set,b=new Set,S=new Set,C=new Set;for(let t of d)t.blockedTargets&&t.blockedTargets!==`none`&&t.blockedTargets.split(`|`).filter(Boolean).forEach(t=>g.add(t)),t.supportTags&&t.supportTags!==`none`&&t.supportTags.split(`|`).filter(Boolean).forEach(t=>b.add(t)),t.supportCard&&t.supportCard!==`none`&&(t.supportSource===`discovered`?C.add(t.supportCard):t.supportSource===`authored`&&S.add(t.supportCard));logger.info(`Prescribed cards in run: ${d.length}`),logger.info(`Selected prescribed cards: ${m.length}`),logger.info(`Blocked prescribed targets referenced: ${g.size>0?[...g].join(`, `):`none`}`),logger.info(`Resolved support tags referenced: ${b.size>0?[...b].join(`, `):`none`}`),logger.info(`Authored support cards emitted: ${S.size>0?[...S].join(`, `):`none`}`),logger.info(`Discovered support cards emitted: ${C.size>0?[...C].join(`, `):`none`}`),console.groupEnd()},listRuns(){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}console.table(runHistory.map(t=>({id:t.runId.slice(-8),time:t.timestamp.toLocaleTimeString(),course:t.courseName||t.courseId.slice(0,8),generated:t.generatedCount,selected:t.finalCount,new:t.newSelected,reviews:t.reviewsSelected})))},export(){let t=JSON.stringify(runHistory,null,2);return logger.info(`[Pipeline Debug] Run history exported. Copy the returned string or use:`),logger.info(` copy(window.skuilder.pipeline.export())`),t},clear(){runHistory.length=0,logger.info(`[Pipeline Debug] Run history cleared.`)},showRegistry(){let t=getRegisteredNavigatorNames();if(t.length===0){logger.info(`[Pipeline Debug] Navigator registry is empty.`);return}console.group(`📦 Navigator Registry`),console.table(t.map(t=>{let c=getRegisteredNavigatorRole(t),u=NavigatorRoles[t];return{name:t,role:u||c||`⚠️ NONE`,source:u?`built-in`:c?`consumer`:`unclassified`,isGenerator:isGenerator(t),isFilter:isFilter(t)}})),console.groupEnd()},showStrategies(){if(this.showRegistry(),runHistory.length===0){logger.info(`[Pipeline Debug] No pipeline runs captured yet — cannot show strategy doc mapping.`);return}let t=runHistory[0];if(console.group(`🔌 Pipeline Strategy Mapping (last run)`),logger.info(`Generator: ${t.generatorName}`),t.generators&&t.generators.length>0)for(let c of t.generators)logger.info(` \u{1F4E5} ${c.name}: ${c.cardCount} cards (${c.newCount} new, ${c.reviewCount} reviews)`);if(t.filters.length>0){logger.info(`Filters:`);for(let c of t.filters)logger.info(` \u{1F538} ${c.name}: \u2191${c.boosted} \u2193${c.penalized} =${c.passed} \u2715${c.removed}`)}else logger.info(`Filters: (none)`);console.groupEnd()},async diagnoseCardSpace(t){return _activePipeline?_activePipeline.diagnoseCardSpace({threshold:t}):(logger.info(`[Pipeline Debug] No active pipeline. Run a session first.`),null)},async showTagElo(t){if(!_activePipeline){logger.info(`[Pipeline Debug] No active pipeline. Run a session first.`);return}let c=await _activePipeline.getTagEloStatus(t),u=Object.entries(c).sort(([t],[c])=>t.localeCompare(c));if(u.length===0){logger.info(`[Pipeline Debug] No tag ELO data found${t?` for pattern: ${t}`:``}.`);return}console.table(Object.fromEntries(u.map(([t,c])=>[t,{score:Math.round(c.score),count:c.count}])))},ui(){if(_uiContainer){document.body.removeChild(_uiContainer),_uiContainer=null;return}_uiContainer=document.createElement(`div`),_uiContainer.id=`sk-pipeline-debugger`,document.body.appendChild(_uiContainer),_selectedRunIndex===null&&runHistory.length>0&&(_selectedRunIndex=0),renderUI()},_selectRun(t){_selectedRunIndex=t,renderUI()},_setSearch(t){_cardSearchQuery=t,renderUI()},_copyConfig(t,c){let u=runHistory.find(c=>c.runId===t);if(!u)return;let d={runId:u.runId,timestamp:u.timestamp.toISOString(),courseId:u.courseId,courseName:u.courseName,hints:u.hints??null};copyTextToClipboard(JSON.stringify(d,null,2),c)},_copyResults(t,c){let u=runHistory.find(c=>c.runId===t);if(!u)return;let d=u.cards.filter(t=>t.selected).sort((t,c)=>c.finalScore-t.finalScore).map(t=>({cardId:t.cardId,generator:t.generator,origin:t.origin,score:Number(t.finalScore.toFixed(3)),topReason:t.provenance[0]?.reason??``})),m={runId:u.runId,label:u.hints?._label??null,finalCount:u.finalCount,newSelected:u.newSelected,reviewsSelected:u.reviewsSelected,selected:d};copyTextToClipboard(JSON.stringify(m,null,2),c)},help(){logger.info(`
324
+ \u26A0\uFE0F Detected clustering: max ${m} cards from same course in a row`),logger.info(`This suggests cards are sorted by score rather than round-robin by course.`)),console.groupEnd()}function mountSessionDebugger(){if(typeof window>`u`)return;let t=window;t.skuilder=t.skuilder||{},t.skuilder.session=sessionDebugAPI}var import___vite_browser_external,import___vite_browser_external$1,import___vite_browser_external$2,import_browser_ponyfill,import_browser_ponyfill$1,import_browser,_SessionController2,__defProp,__getOwnPropNames,__glob,__esm,__export,init_adminDB,init_classroomDB,init_SyncStrategy,isDevelopment,logger,init_logger,GuestUsername,log,DocType,DocTypePrefixes,init_types_legacy,init_util,pouchdb_setup_default,init_pouchdb_setup,init_dataDirectory,REVIEW_TIME_FORMAT,log2,init_userDBHelpers,Loggable,init_Loggable,UpdateQueue,init_updateQueue,UsrCrsData,init_user_course_relDB,CLIENT_CACHE,init_clientCache,AlreadyTaggedErr,init_courseAPI,courseLookupDBTitle,CourseLookup,init_courseLookupDB,PipelineDebugger_exports,_activePipeline,MAX_RUNS,runHistory,DISCARDED_KEEP_TOP,_uiContainer,_selectedRunIndex,_cardSearchQuery,pipelineDebugAPI,init_PipelineDebugger,CompositeGenerator_exports,AggregationMode,DEFAULT_AGGREGATION_MODE,FREQUENCY_BOOST_FACTOR,CompositeGenerator,init_CompositeGenerator,elo_exports,ELONavigator,init_elo,generators_exports,init_generators,prescribed_exports,DEFAULT_FRESHNESS_WINDOW,DEFAULT_MAX_DIRECT_PER_RUN,DEFAULT_MAX_SUPPORT_PER_RUN,DEFAULT_HIERARCHY_DEPTH,DEFAULT_MIN_COUNT,BASE_TARGET_SCORE,BASE_SUPPORT_SCORE,DISCOVERED_SUPPORT_SCORE,MAX_TARGET_MULTIPLIER,MAX_SUPPORT_MULTIPLIER,PRESCRIBED_DEBUG_VERSION,PrescribedCardsGenerator,init_prescribed,srs_exports,DEFAULT_HEALTHY_BACKLOG,MAX_BACKLOG_PRESSURE,SRSNavigator,init_srs,types_exports,init_types,globImport_generators,init_,DEFAULT_LEARNABLE_WEIGHT,init_contentNavigationStrategy,WeightedFilter_exports,WeightedFilter,init_WeightedFilter,eloDistance_exports,DEFAULT_HALF_LIFE,DEFAULT_MIN_MULTIPLIER,DEFAULT_MAX_MULTIPLIER,init_eloDistance,hierarchyDefinition_exports,DEFAULT_MIN_COUNT2,HierarchyDefinitionNavigator,init_hierarchyDefinition,userTagPreference_exports,UserTagPreferenceFilter,init_userTagPreference,filters_exports,init_filters,inferredPreferenceStub_exports,INFERRED_PREFERENCE_NAVIGATOR_STUB,init_inferredPreferenceStub,interferenceMitigator_exports,DEFAULT_MIN_COUNT3,DEFAULT_MIN_ELAPSED_DAYS,DEFAULT_INTERFERENCE_DECAY,InterferenceMitigatorNavigator,init_interferenceMitigator,relativePriority_exports,DEFAULT_PRIORITY,DEFAULT_PRIORITY_INFLUENCE,DEFAULT_COMBINE_MODE,RelativePriorityNavigator,init_relativePriority,types_exports2,init_types2,userGoalStub_exports,USER_GOAL_NAVIGATOR_STUB,init_userGoalStub,globImport_filters,init_2,init_gradient,MIN_OBSERVATIONS_FOR_UPDATE,LEARNING_RATE,MAX_WEIGHT_DELTA,MIN_R_SQUARED_FOR_GRADIENT,FLAT_GRADIENT_THRESHOLD,MAX_HISTORY_LENGTH,init_learning,init_signal,init_recording,MIN_SPREAD,MAX_SPREAD,MIN_WEIGHT,MAX_WEIGHT,init_orchestration,Pipeline_exports,VERBOSE_RESULTS,Pipeline,init_Pipeline,defaults_exports,init_defaults,PipelineAssembler_exports,PipelineAssembler,init_PipelineAssembler,globImport,init_3,navigators_exports,navigatorRegistry,Navigators,NavigatorRole,NavigatorRoles,ContentNavigator,init_navigators,CoursesDB,CourseDB,init_courseDB,classroomLookupDBTitle,CLASSROOM_CONFIG,ClassroomDBBase,StudentClassroomDB,TeacherClassroomDB,ClassroomLookupDB,init_classroomDB2,AdminDB,init_adminDB2,CourseSyncService_exports,DEFAULT_REPLICATION,CourseSyncService,init_CourseSyncService,init_auth,CouchDBSyncStrategy_exports,log3,CouchDBSyncStrategy,init_CouchDBSyncStrategy,isBrowser,GUEST_LOCAL_DB,localUserDB,pouchDBincludeCredentialsConfig,REVIEW_TIME_FORMAT2,init_couch,log4,BaseUser,userCoursesDoc,userClassroomsDoc,init_BaseUserDB,init_common,PouchDataLayerProvider_exports,CouchDataLayerProvider,init_PouchDataLayerProvider,pathUtils,nodeFS,StaticDataUnpacker,init_StaticDataUnpacker,StaticCourseDB,init_courseDB2,StaticCoursesDB,init_coursesDB,NoOpSyncStrategy,init_NoOpSyncStrategy,StaticDataLayerProvider_exports,StaticDataLayerProvider,init_StaticDataLayerProvider,NOT_SET,ENV,dataLayerInstance,init_factory,TagFilteredContentSource,init_TagFilteredContentSource,init_contentSource,init_courseDB3,init_dataLayerProvider,init_userDB,init_interfaces,init_user,init_strategyState,init_userOutcome,init_cardProcessor,init_types3,init_bulkImport,userDBDebugAPI,init_UserDBDebugger,init_core,duration,SrsService,EloService,ResponseProcessor,CardHydrationService,ItemQueue,CouchDBToStaticPacker,DEFAULT_MIGRATION_OPTIONS,FileSystemError,nodeFS2,nodeFS3,nodePath,StaticToCouchDBMigrator,QuotaRoundRobinMixer,MAX_RUNS2,runHistory2,mixerDebugAPI,activeSession,sessionHistory,MAX_HISTORY,sessionDebugAPI,SessionController,init_dist=__esmMin((()=>{init_defineProperty(),init_index_browser_es$5(),init_index_browser_es(),init_index_es(),import___vite_browser_external=__toESM$2(require___vite_browser_external(),1),import___vite_browser_external$1=__toESM$2(require___vite_browser_external(),1),import___vite_browser_external$2=__toESM$2(require___vite_browser_external(),1),init_moment(),init_dist$1(),init_esm_browser(),import_browser_ponyfill=__toESM$2(require_browser_ponyfill(),1),import_browser_ponyfill$1=__toESM$2(require_browser_ponyfill(),1),import_browser=__toESM$2(require_browser(),1),__defProp=Object.defineProperty,__getOwnPropNames=Object.getOwnPropertyNames,__glob=t=>c=>{var u=t[c];if(u)return u();throw Error(`Module not found in bundle: `+c)},__esm=(t,c)=>function __init(){return t&&(c=(0,t[__getOwnPropNames(t)[0]])(t=0)),c},__export=(t,c)=>{for(var u in c)__defProp(t,u,{get:c[u],enumerable:!0})},init_adminDB=__esm({"src/core/interfaces/adminDB.ts"(){"use strict";}}),init_classroomDB=__esm({"src/core/interfaces/classroomDB.ts"(){"use strict";}}),init_SyncStrategy=__esm({"src/impl/common/SyncStrategy.ts"(){"use strict";}}),init_logger=__esm({"src/util/logger.ts"(){"use strict";isDevelopment=typeof process<`u`&&process.env.NODE_ENV===`development`,logger={debug:(t,...c)=>{isDevelopment&&console.debug(`[DB:DEBUG] ${t}`,...c)},info:(t,...c)=>{console.info(`[DB:INFO] ${t}`,...c)},warn:(t,...c)=>{console.warn(`[DB:WARN] ${t}`,...c)},error:(t,...c)=>{console.error(`[DB:ERROR] ${t}`,...c)},log:(t,...c)=>{isDevelopment&&console.log(`[DB:LOG] ${t}`,...c)}}}}),init_types_legacy=__esm({"src/core/types/types-legacy.ts"(){"use strict";init_logger(),GuestUsername=`sk-guest-`,log=t=>{logger.log(t)},DocType=(t=>(t.DISPLAYABLE_DATA=`DISPLAYABLE_DATA`,t.CARD=`CARD`,t.DATASHAPE=`DATASHAPE`,t.QUESTIONTYPE=`QUESTION`,t.VIEW=`VIEW`,t.PEDAGOGY=`PEDAGOGY`,t.CARDRECORD=`CARDRECORD`,t.SCHEDULED_CARD=`SCHEDULED_CARD`,t.TAG=`TAG`,t.NAVIGATION_STRATEGY=`NAVIGATION_STRATEGY`,t.STRATEGY_STATE=`STRATEGY_STATE`,t.USER_OUTCOME=`USER_OUTCOME`,t.STRATEGY_LEARNING_STATE=`STRATEGY_LEARNING_STATE`,t))(DocType||{}),DocTypePrefixes={CARD:`c`,DISPLAYABLE_DATA:`dd`,TAG:`TAG`,CARDRECORD:`cardH`,SCHEDULED_CARD:`card_review_`,DATASHAPE:`DATASHAPE`,QUESTION:`QUESTION`,VIEW:`VIEW`,PEDAGOGY:`PEDAGOGY`,NAVIGATION_STRATEGY:`NAVIGATION_STRATEGY`,STRATEGY_STATE:`STRATEGY_STATE`,USER_OUTCOME:`USER_OUTCOME`,STRATEGY_LEARNING_STATE:`STRATEGY_LEARNING_STATE`}}}),init_util=__esm({"src/core/util/index.ts"(){"use strict";init_types_legacy()}}),init_pouchdb_setup=__esm({"src/impl/couch/pouchdb-setup.ts"(){"use strict";PouchDB.plugin(plugin$1),PouchDB.plugin(plugin),PouchDB.debug!==void 0&&PouchDB.debug.disable(),PouchDB.defaults({}),pouchdb_setup_default=PouchDB}}),init_dataDirectory=__esm({"src/util/dataDirectory.ts"(){"use strict";init_logger(),init_factory()}}),init_userDBHelpers=__esm({"src/impl/common/userDBHelpers.ts"(){"use strict";init_core(),init_logger(),init_pouchdb_setup(),init_dataDirectory(),REVIEW_TIME_FORMAT=`YYYY-MM-DD--kk:mm:ss-SSS`,log2=t=>{logger.info(t)}}}),init_Loggable=__esm({"src/util/Loggable.ts"(){"use strict";Loggable=class{log(...t){console.log(`LOG-${this._className}@${new Date}:`,...t)}error(...t){console.error(`ERROR-${this._className}@${new Date}:`,...t)}}}}),init_updateQueue=__esm({"src/impl/couch/updateQueue.ts"(){"use strict";init_Loggable(),init_logger(),UpdateQueue=class extends Loggable{update(t,c){return logger.debug(`Update requested on doc: ${t}`),this.pendingUpdates[t]?this.pendingUpdates[t].push(c):this.pendingUpdates[t]=[c],this.applyUpdates(t)}constructor(t,c){super(),_defineProperty$2(this,`_className`,`UpdateQueue`),_defineProperty$2(this,`pendingUpdates`,{}),_defineProperty$2(this,`inprogressUpdates`,{}),_defineProperty$2(this,`readDB`,void 0),_defineProperty$2(this,`writeDB`,void 0),this.readDB=t,this.writeDB=c||t,logger.debug(`UpdateQ initialized...`),this.readDB.info().then(t=>{logger.debug(`db info: ${JSON.stringify(t)}`)})}async applyUpdates(t){if(logger.debug(`Applying updates on doc: ${t}`),this.inprogressUpdates[t]){for(;this.inprogressUpdates[t];)await new Promise(t=>setTimeout(t,Math.random()*50));return this.applyUpdates(t)}else if(this.pendingUpdates[t]&&this.pendingUpdates[t].length>0){this.inprogressUpdates[t]=!0;let c=5;for(let c=0;c<5;c++)try{let c={...await this.readDB.get(t)},u=[...this.pendingUpdates[t]];for(let t of u)c=typeof t==`function`?{...c,...t(c)}:{...c,...t};if(await this.writeDB.put(c),this.pendingUpdates[t].splice(0,u.length),this.pendingUpdates[t].length===0)this.inprogressUpdates[t]=!1,delete this.inprogressUpdates[t];else return this.applyUpdates(t);return c}catch(u){if(u.name===`conflict`&&c<4)logger.warn(`Conflict on update for doc ${t}, retry #${c+1}`),await new Promise(t=>setTimeout(t,50*Math.random()));else if(u.name===`not_found`&&c===0)throw logger.warn(`Update failed for ${t} - does not exist. Throwing to caller.`),delete this.inprogressUpdates[t],u;else throw delete this.inprogressUpdates[t],this.pendingUpdates[t]&&delete this.pendingUpdates[t],logger.error(`Error on attemped update (retry ${c}): ${JSON.stringify(u)}`),u}throw Error(`UpdateQueue failed for doc ${t} after 5 retries.`)}else throw Error(`Empty Updates Queue Triggered`)}}}}),init_user_course_relDB=__esm({"src/impl/couch/user-course-relDB.ts"(){"use strict";init_logger(),UsrCrsData=class{constructor(t,c){_defineProperty$2(this,`user`,void 0),_defineProperty$2(this,`_courseId`,void 0),this.user=t,this._courseId=c}async getReviewsForcast(t){let c=hooks.utc().add(t,`days`);return this.getReviewstoDate(c)}async getPendingReviews(){let t=hooks.utc();return this.getReviewstoDate(t)}async getScheduledReviewCount(){return(await this.getPendingReviews()).length}async getCourseSettings(){let t=(await this.user.getCourseRegistrationsDoc()).courses.find(t=>t.courseID===this._courseId);return t&&t.settings?t.settings:(logger.warn(`no settings found during lookup on course ${this._courseId}`),{})}updateCourseSettings(t){`updateCourseSettings`in this.user&&this.user.updateCourseSettings(this._courseId,t)}async getStrategyState(t){return this.user.getStrategyState(this._courseId,t)}async putStrategyState(t,c){return this.user.putStrategyState(this._courseId,t,c)}async deleteStrategyState(t){return this.user.deleteStrategyState(this._courseId,t)}async getReviewstoDate(t){let c=await this.user.getPendingReviews(this._courseId);return logger.debug(`Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`),c.filter(c=>{let u=hooks.utc(c.reviewTime);return t.isAfter(u)})}}}}),init_clientCache=__esm({"src/impl/couch/clientCache.ts"(){"use strict";CLIENT_CACHE={}}}),init_courseAPI=__esm({"src/impl/couch/courseAPI.ts"(){"use strict";init_pouchdb_setup(),init_couch(),init_factory(),init_courseDB(),init_types_legacy(),init_common(),init_logger(),AlreadyTaggedErr=class extends Error{constructor(t){super(t),this.name=`AlreadyTaggedErr`}}}}),init_courseLookupDB=__esm({"src/impl/couch/courseLookupDB.ts"(){"use strict";var t;init_pouchdb_setup(),init_factory(),init_logger(),courseLookupDBTitle=`coursedb-lookup`,logger.debug(`COURSELOOKUP FILE RUNNING`),CourseLookup=(t=class _CourseLookup{static get _db(){if(this._dbInstance)return this._dbInstance;if(ENV.COUCHDB_SERVER_URL===`NOT_SET`||!ENV.COUCHDB_SERVER_URL)throw Error(`CourseLookup.db: COUCHDB_SERVER_URL is not set. Ensure initializeDataLayer has been called with valid configuration.`);if(ENV.COUCHDB_SERVER_PROTOCOL===`NOT_SET`||!ENV.COUCHDB_SERVER_PROTOCOL)throw Error(`CourseLookup.db: COUCHDB_SERVER_PROTOCOL is not set. Ensure initializeDataLayer has been called with valid configuration.`);let t=`${ENV.COUCHDB_SERVER_PROTOCOL}://${ENV.COUCHDB_SERVER_URL}/${courseLookupDBTitle}`,c={};ENV.COUCHDB_USERNAME&&ENV.COUCHDB_PASSWORD?(c.auth={username:ENV.COUCHDB_USERNAME,password:ENV.COUCHDB_PASSWORD},logger.info(`CourseLookup: Connecting to ${t} with authentication.`)):logger.info(`CourseLookup: Connecting to ${t} without authentication.`);try{return this._dbInstance=new pouchdb_setup_default(t,c),logger.info(`CourseLookup: Database instance created for ${courseLookupDBTitle}.`),this._dbInstance}catch(c){throw logger.error(`CourseLookup: Failed to create PouchDB instance for ${t}`,c),this._dbInstance=null,Error(`CourseLookup: Failed to initialize database connection: ${c instanceof Error?c.message:String(c)}`)}}static async add(t){return(await _CourseLookup._db.post({name:t})).id}static async addWithId(t,c,u){let d={_id:t,name:c};u&&(d.disambiguator=u),await _CourseLookup._db.put(d)}static async delete(t){let c=await _CourseLookup._db.get(t);return await _CourseLookup._db.remove(c)}static async allCourseWare(){return(await _CourseLookup._db.allDocs({include_docs:!0})).rows.map(t=>t.doc)}static async updateDisambiguator(t,c){let u=await _CourseLookup._db.get(t);return u.disambiguator=c,await _CourseLookup._db.put(u)}static async isCourse(t){try{return await _CourseLookup._db.get(t),!0}catch(t){return logger.info(`Courselookup failed:`,t),!1}}},_defineProperty$2(t,`_dbInstance`,null),t)}}),PipelineDebugger_exports={},__export(PipelineDebugger_exports,{buildRunReport:()=>buildRunReport,captureRun:()=>captureRun,clearRunHistory:()=>clearRunHistory,mountPipelineDebugger:()=>mountPipelineDebugger,pipelineDebugAPI:()=>pipelineDebugAPI,registerPipelineForDebug:()=>registerPipelineForDebug}),init_PipelineDebugger=__esm({"src/core/navigators/PipelineDebugger.ts"(){"use strict";init_navigators(),init_logger(),_activePipeline=null,MAX_RUNS=10,runHistory=[],DISCARDED_KEEP_TOP=25,_uiContainer=null,_selectedRunIndex=null,_cardSearchQuery=``,pipelineDebugAPI={get runs(){return[...runHistory]},showRun(t=0){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}let c;if(typeof t==`number`){if(c=runHistory[t],!c){logger.info(`[Pipeline Debug] No run found at index ${t}. History length: ${runHistory.length}`);return}}else if(c=runHistory.find(c=>c.runId.endsWith(t)),!c){logger.info(`[Pipeline Debug] No run found matching ID '${t}'.`);return}printRunSummary(c)},showLastRun(){this.showRun(0)},showCard(t){for(let c of runHistory){let u=c.cards.find(c=>c.cardId===t);if(u){console.group(`\u{1F3B4} Card: ${t}`),logger.info(`Course: ${u.courseId}`),logger.info(`Origin: ${u.origin}`),logger.info(`Card ELO: ${u.cardElo??`unknown`} | User ELO: ${c.userElo??`unknown`}`),logger.info(`Final score: ${u.finalScore.toFixed(3)}`),logger.info(`Selected: ${u.selected?`Yes ✅`:`No ❌`}`),u.tags&&u.tags.length>0&&logger.info(`Tags (${u.tags.length}): ${u.tags.join(`, `)}`),logger.info(`Provenance:`),logger.info(formatProvenance(u.provenance)),console.groupEnd();return}}let c=runHistory.filter(t=>t.discardedTail&&t.discardedTail.count>0);c.length>0?logger.info(`[Pipeline Debug] Card '${t}' not found in retained cards. ${c.length} run(s) have discarded tails that were not retained \u2014 the card may have been a low-score candidate. See run.discardedTail for ranges.`):logger.info(`[Pipeline Debug] Card '${t}' not found in recent runs.`)},explainReviews(){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}console.group(`📋 Review Selection Analysis`);for(let t of runHistory){console.group(`Run: ${t.courseId} @ ${t.timestamp.toLocaleTimeString()}`);let c=t.cards.filter(t=>t.origin===`review`),u=c.filter(t=>t.selected);if(c.length===0)logger.info(`❌ No reviews were generated. Check SRS logs for why.`);else if(u.length===0){logger.info(`\u26A0\uFE0F ${c.length} reviews generated but none selected.`),logger.info(`Possible reasons:`);let u=Math.max(...t.cards.filter(t=>t.origin===`new`&&t.selected).map(t=>t.finalScore),0),d=Math.max(...c.map(t=>t.finalScore),0);d<u&&logger.info(` - New cards scored higher (top new: ${u.toFixed(2)}, top review: ${d.toFixed(2)})`);let m=c.sort((t,c)=>c.finalScore-t.finalScore)[0];m&&(logger.info(` - Top review score: ${m.finalScore.toFixed(3)}`),logger.info(` - Its provenance:`),logger.info(formatProvenance(m.provenance)))}else{logger.info(`\u2705 ${u.length}/${c.length} reviews selected.`),logger.info(`Top selected review:`);let t=u.sort((t,c)=>c.finalScore-t.finalScore)[0];logger.info(formatProvenance(t.provenance))}console.groupEnd()}console.groupEnd()},showPrescribed(t){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}let c=runHistory[0],u=c.cards.filter(t=>t.provenance.some(t=>t.strategy===`prescribed`));if(console.group(`\u{1F9ED} Prescribed Debug (${c.courseId})`),u.length===0){logger.info(`No prescribed-generated cards were present in the most recent run.`),console.groupEnd();return}let d=u.map(t=>{let c=t.provenance.find(t=>t.strategy===`prescribed`)?.reason??``,u=c.match(/group=([^;]+)/)?.[1]??`unknown`,d=c.match(/mode=([^;]+)/)?.[1]??`unknown`,m=c.match(/blocked=([^;]+)/)?.[1]??`unknown`,g=c.match(/blockedTargets=([^;]+)/)?.[1]??`none`,b=c.match(/supportCard=([^;]+)/)?.[1]??`none`,S=c.match(/supportTags=([^;]+)/)?.[1]??`none`,C=c.match(/multiplier=([^;]+)/)?.[1]??`unknown`;return{group:u,mode:d,supportSource:d===`discovered-support`?`discovered`:d===`support`?`authored`:`n/a`,cardId:t.cardId,selected:t.selected?`yes`:`no`,finalScore:t.finalScore.toFixed(3),blocked:m,blockedTargets:g,supportCard:b,supportTags:S,multiplier:C}}).filter(c=>!t||c.group===t).sort((t,c)=>Number(c.finalScore)-Number(t.finalScore));if(d.length===0){logger.info(`[Pipeline Debug] No prescribed cards matched group '${t}' in the most recent run.`),console.groupEnd();return}console.table(d);let m=d.filter(t=>t.selected===`yes`),g=new Set,b=new Set,S=new Set,C=new Set;for(let t of d)t.blockedTargets&&t.blockedTargets!==`none`&&t.blockedTargets.split(`|`).filter(Boolean).forEach(t=>g.add(t)),t.supportTags&&t.supportTags!==`none`&&t.supportTags.split(`|`).filter(Boolean).forEach(t=>b.add(t)),t.supportCard&&t.supportCard!==`none`&&(t.supportSource===`discovered`?C.add(t.supportCard):t.supportSource===`authored`&&S.add(t.supportCard));logger.info(`Prescribed cards in run: ${d.length}`),logger.info(`Selected prescribed cards: ${m.length}`),logger.info(`Blocked prescribed targets referenced: ${g.size>0?[...g].join(`, `):`none`}`),logger.info(`Resolved support tags referenced: ${b.size>0?[...b].join(`, `):`none`}`),logger.info(`Authored support cards emitted: ${S.size>0?[...S].join(`, `):`none`}`),logger.info(`Discovered support cards emitted: ${C.size>0?[...C].join(`, `):`none`}`),console.groupEnd()},listRuns(){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}console.table(runHistory.map(t=>({id:t.runId.slice(-8),time:t.timestamp.toLocaleTimeString(),course:t.courseName||t.courseId.slice(0,8),generated:t.generatedCount,selected:t.finalCount,new:t.newSelected,reviews:t.reviewsSelected})))},export(){let t=JSON.stringify(runHistory,null,2);return logger.info(`[Pipeline Debug] Run history exported. Copy the returned string or use:`),logger.info(` copy(window.skuilder.pipeline.export())`),t},clear(){runHistory.length=0,logger.info(`[Pipeline Debug] Run history cleared.`)},showRegistry(){let t=getRegisteredNavigatorNames();if(t.length===0){logger.info(`[Pipeline Debug] Navigator registry is empty.`);return}console.group(`📦 Navigator Registry`),console.table(t.map(t=>{let c=getRegisteredNavigatorRole(t),u=NavigatorRoles[t];return{name:t,role:u||c||`⚠️ NONE`,source:u?`built-in`:c?`consumer`:`unclassified`,isGenerator:isGenerator(t),isFilter:isFilter(t)}})),console.groupEnd()},showStrategies(){if(this.showRegistry(),runHistory.length===0){logger.info(`[Pipeline Debug] No pipeline runs captured yet — cannot show strategy doc mapping.`);return}let t=runHistory[0];if(console.group(`🔌 Pipeline Strategy Mapping (last run)`),logger.info(`Generator: ${t.generatorName}`),t.generators&&t.generators.length>0)for(let c of t.generators)logger.info(` \u{1F4E5} ${c.name}: ${c.cardCount} cards (${c.newCount} new, ${c.reviewCount} reviews)`);if(t.filters.length>0){logger.info(`Filters:`);for(let c of t.filters)logger.info(` \u{1F538} ${c.name}: \u2191${c.boosted} \u2193${c.penalized} =${c.passed} \u2715${c.removed}`)}else logger.info(`Filters: (none)`);console.groupEnd()},async diagnoseCardSpace(t){return _activePipeline?_activePipeline.diagnoseCardSpace({threshold:t}):(logger.info(`[Pipeline Debug] No active pipeline. Run a session first.`),null)},async showTagElo(t){if(!_activePipeline){logger.info(`[Pipeline Debug] No active pipeline. Run a session first.`);return}let c=await _activePipeline.getTagEloStatus(t),u=Object.entries(c).sort(([t],[c])=>t.localeCompare(c));if(u.length===0){logger.info(`[Pipeline Debug] No tag ELO data found${t?` for pattern: ${t}`:``}.`);return}console.table(Object.fromEntries(u.map(([t,c])=>[t,{score:Math.round(c.score),count:c.count}])))},ui(){if(_uiContainer){document.body.removeChild(_uiContainer),_uiContainer=null;return}_uiContainer=document.createElement(`div`),_uiContainer.id=`sk-pipeline-debugger`,document.body.appendChild(_uiContainer),_selectedRunIndex===null&&runHistory.length>0&&(_selectedRunIndex=0),renderUI()},_selectRun(t){_selectedRunIndex=t,renderUI()},_setSearch(t){_cardSearchQuery=t,renderUI()},_copyConfig(t,c){let u=runHistory.find(c=>c.runId===t);if(!u)return;let d={runId:u.runId,timestamp:u.timestamp.toISOString(),courseId:u.courseId,courseName:u.courseName,hints:u.hints??null};copyTextToClipboard(JSON.stringify(d,null,2),c)},_copyResults(t,c){let u=runHistory.find(c=>c.runId===t);if(!u)return;let d=u.cards.filter(t=>t.selected).sort((t,c)=>c.finalScore-t.finalScore).map(t=>({cardId:t.cardId,generator:t.generator,origin:t.origin,score:Number(t.finalScore.toFixed(3)),topReason:t.provenance[0]?.reason??``})),m={runId:u.runId,label:u.hints?._label??null,finalCount:u.finalCount,newSelected:u.newSelected,reviewsSelected:u.reviewsSelected,selected:d};copyTextToClipboard(JSON.stringify(m,null,2),c)},help(){logger.info(`
325
325
  🔧 Pipeline Debug API
326
326
 
327
327
  Commands:
@@ -359,7 +359,7 @@ ${g.rows.map(t=>` ${t.id}-${t.key}
359
359
  `+C),S}async getCourseConfig(){let t=await getCredentialledCourseConfig(this.id);if(t)return t;throw Error(`Course config not found for course ID: ${this.id}`)}async updateCourseConfig(t){logger.debug(`Updating: ${JSON.stringify(t)}`);try{return await updateCredentialledCourseConfig(this.id,t)}catch(t){throw logger.error(`Error updating course config in course DB: ${t}`),t}}async updateCardElo(t,c){if(!c)throw Error(`Cannot update card elo with null or undefined value for card ID: ${t}`);try{return{ok:!0,id:t,rev:(await this.updateQueue.update(t,t=>(logger.debug(`Replacing ${JSON.stringify(t.elo)} with ${JSON.stringify(c)}`),t.elo=c,t)))._rev}}catch(c){throw logger.error(`Failed to update card elo for card ID: ${t}`,c),Error(`Failed to update card elo for card ID: ${t}`)}}async getAppliedTags(t){let c=await getAppliedTags(this.id,t);if(c)return c;throw Error(`Failed to find tags for card ${this.id}-${t}`)}async getAppliedTagsBatch(t){if(t.length===0)return new Map;let c=await this.db.query(`getTags`,{keys:t,include_docs:!1}),u=new Map;for(let c of t)u.set(c,[]);for(let t of c.rows){let c=t.key,d=t.value?.name;d&&u.has(c)&&u.get(c).push(d)}return u}async getAllCardIds(){return(await this.db.allDocs({startkey:`CARD-`,endkey:`CARD-￰`,include_docs:!1})).rows.map(t=>t.id)}async addTagToCard(t,c,u){return await addTagToCard(this.id,t,c,(await this._getCurrentUser()).getUsername(),u)}async removeTagFromCard(t,c){return await removeTagFromCard(this.id,t,c)}async createTag(t,c){return await createTag(this.id,t,c)}async getTag(t){return await getTag(this.id,t)}async updateTag(t){if(t.course!==this.id)throw Error(`Tag ${JSON.stringify(t)} does not belong to course ${this.id}`);return await updateTag(t)}async getCourseTagStubs(){return getCourseTagStubs(this.id)}async addNote(t,c,u,d,m,g,b=blankCourseElo()){try{let S=await addNote55(this.id,t,c,u,d,m,g,b);return S.ok?S.cardCreationFailed?(logger.warn(`[courseDB.addNote] Note added but card creation failed: ${S.cardCreationError}`),{status:Status.error,message:`Note was added but no cards were created: ${S.cardCreationError}`,id:S.id}):{status:Status.ok,message:``,id:S.id}:{status:Status.error,message:`Unexpected error adding note`}}catch(t){let c=t;return logger.error(`[addNote] error ${c.name}
360
360
  reason: ${c.reason}
361
361
  message: ${c.message}`),{status:Status.error,message:`Error adding note to course. ${t.reason||c.message}`}}}async getCourseDoc(t,c){return await this.db.get(t,c??{})}async getCourseDocs(t,c={}){return await this.db.allDocs({...c,keys:t})}getNavigationStrategy(t){if(logger.debug(`[courseDB] Getting navigation strategy: ${t}`),t==``){let t={_id:`NAVIGATION_STRATEGY-ELO`,docType:`NAVIGATION_STRATEGY`,name:`ELO`,description:`ELO-based navigation strategy for ordering content by difficulty`,implementingClass:`elo`,course:this.id,serializedData:``};return Promise.resolve(t)}else return this.db.get(t)}async getAllNavigationStrategies(){let t=DocTypePrefixes.NAVIGATION_STRATEGY;return(await this.db.allDocs({startkey:t,endkey:`${t}\uFFF0`,include_docs:!0})).rows.map(t=>t.doc)}async addNavigationStrategy(t){return logger.debug(`[courseDB] Adding navigation strategy: ${t._id}`),this.remoteDB.put(t).then(()=>{})}updateNavigationStrategy(t,c){return logger.debug(`[courseDB] Updating navigation strategy: ${t}`),logger.debug(JSON.stringify(c)),Promise.resolve()}async createNavigator(t){try{let c=await this.getAllNavigationStrategies();if(c.length===0)return logger.debug(`[courseDB] No strategy documents found, using default Pipeline(Composite(ELO, SRS), [eloDistanceFilter])`),createDefaultPipeline(t,this);let{pipeline:u,generatorStrategies:d,filterStrategies:m,warnings:g}=await new PipelineAssembler().assemble({strategies:c,user:t,course:this});for(let t of g)logger.warn(`[PipelineAssembler] ${t}`);return u?(logger.debug(`[courseDB] Using assembled pipeline with ${d.length} generator(s) and ${m.length} filter(s)`),u):(logger.debug(`[courseDB] Pipeline assembly failed, using default pipeline`),createDefaultPipeline(t,this))}catch(t){let c=t instanceof Error?`${t.message}
362
- ${t.stack}`:JSON.stringify(t);throw logger.error(`[courseDB] Error creating navigator: ${c}`),t}}setEphemeralHints(t){this._pendingHints=t}async getWeightedCards(t){let c=await this._getCurrentUser();try{let u=await this.createNavigator(c);return this._pendingHints&&(u.setEphemeralHints(this._pendingHints),this._pendingHints=null),u.getWeightedCards(t)}catch(t){throw logger.error(`[courseDB] Error getting weighted cards: ${t}`),t}}async getCardsCenteredAtELO(t={limit:99,elo:`user`},c){let u;if(t.elo===`user`){let t=await this._getCurrentUser();u=-1;try{u=EloToNumber((await t.getCourseRegistrationsDoc()).courses.find(t=>t.courseID===this.id).elo)}catch{u=1e3}}else if(t.elo===`random`){let t=await GET_CACHED(`elo-bounds-${this.id}`,()=>this.getELOBounds());u=Math.round(t.low+Math.random()*(t.high-t.low))}else u=t.elo;let d=[],m=4,g=-1,b=0;for(;d.length<t.limit&&b!==g;)d=await this.getCardsByELO(u,m*t.limit),g=b,b=d.length,logger.debug(`Found ${d.length} elo neighbor cards...`),c&&(d=d.filter(c),logger.debug(`Filtered to ${d.length} cards...`)),m*=2;let S=[];for(;S.length<t.limit&&d.length>0;){let t=randIntWeightedTowardZero(d.length),c=d.splice(t,1)[0];S.push(c)}return S.map(t=>({courseID:this.id,cardID:t.cardID,contentSourceType:`course`,contentSourceID:this.id,elo:t.elo,status:`new`}))}async searchCards(t){logger.log(`[CourseDB ${this.id}] Searching for: "${t}"`);let c;try{c=await this.db.find({selector:{docType:`DISPLAYABLE_DATA`,"data.0.data":{$regex:`.*${t}.*`}}}),logger.log(`[CourseDB ${this.id}] Regex search on data[0].data successful`)}catch(u){logger.log(`[CourseDB ${this.id}] Regex search failed, falling back to manual search:`,u);let d=await this.db.find({selector:{docType:`DISPLAYABLE_DATA`}});logger.log(`[CourseDB ${this.id}] Retrieved ${d.docs.length} documents for manual filtering`),c={docs:d.docs.filter(c=>{let u=JSON.stringify(c).toLowerCase().includes(t.toLowerCase());return u&&logger.log(`[CourseDB ${this.id}] Manual match found in document: ${c._id}`),u})}}if(logger.log(`[CourseDB ${this.id}] Found ${c.docs.length} displayable data documents`),c.docs.length===0){let t=await this.db.find({selector:{docType:`DISPLAYABLE_DATA`},limit:5});logger.log(`[CourseDB ${this.id}] Sample displayable data:`,t.docs.map(t=>({id:t._id,docType:t.docType,dataStructure:t.data?Object.keys(t.data):`no data field`,dataContent:t.data,fullDoc:t})))}let u=[];for(let t of c.docs){let c=await this.db.find({selector:{docType:`CARD`,id_displayable_data:{$in:[t._id]}}});logger.log(`[CourseDB ${this.id}] Displayable data ${t._id} linked to ${c.docs.length} cards`),u.push(...c.docs)}return logger.log(`[CourseDB ${this.id}] Total cards found: ${u.length}`),u}async find(t){return this.db.find(t)}}}}),init_classroomDB2=__esm({"src/impl/couch/classroomDB.ts"(){"use strict";init_factory(),init_logger(),init_pouchdb_setup(),init_couch(),init_courseDB(),classroomLookupDBTitle=`classdb-lookup`,CLASSROOM_CONFIG=`ClassroomConfig`,ClassroomDBBase=class{constructor(){_defineProperty$2(this,`_id`,void 0),_defineProperty$2(this,`_db`,void 0),_defineProperty$2(this,`_cfg`,void 0),_defineProperty$2(this,`_initComplete`,!1),_defineProperty$2(this,`_content_prefix`,`content`)}get _content_searchkeys(){return getStartAndEndKeys2(this._content_prefix)}async getAssignedContent(){return logger.info(`Getting assigned content...`),(await this._db.allDocs({startkey:this._content_prefix,endkey:this._content_prefix+`￰`,include_docs:!0})).rows.map(t=>t.doc)}getContentId(t){return t.type===`tag`?`${this._content_prefix}-${t.courseID}-${t.tagID}`:`${this._content_prefix}-${t.courseID}`}get ready(){return this._initComplete}getConfig(){return this._cfg}},StudentClassroomDB=class _StudentClassroomDB extends ClassroomDBBase{constructor(t,c){super(),_defineProperty$2(this,`userMessages`,void 0),_defineProperty$2(this,`_user`,void 0),this._id=t,this._user=c}async init(){let t=`classdb-student-${this._id}`;this._db=new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+t,createPouchDBConfig());try{this._cfg=await this._db.get(CLASSROOM_CONFIG),this.userMessages=this._db.changes({since:`now`,live:!0,include_docs:!0}),this._initComplete=!0;return}catch(t){throw Error(`Error in StudentClassroomDB constructor: ${JSON.stringify(t)}`)}}static async factory(t,c){let u=new _StudentClassroomDB(t,c);return await u.init(),u}setChangeFcn(t){this.userMessages.on(`change`,t)}async getWeightedCards(t){let c=[],u=(await this._user.getPendingReviews()).filter(t=>t.scheduledFor===`classroom`&&t.schedulingAgentId===this._id);for(let t of u)c.push({cardId:t.cardId,courseId:t.courseId,score:1,reviewID:t._id,provenance:[{strategy:`classroom`,strategyName:`Classroom`,strategyId:`CLASSROOM`,action:`generated`,score:1,reason:`Classroom scheduled review`}]});let d=await this._user.getActiveCards(),m=new Set(d.map(t=>t.cardID)),g=hooks.utc(),b=(await this.getAssignedContent()).filter(t=>g.isAfter(hooks.utc(t.activeOn,REVIEW_TIME_FORMAT2)));logger.info(`[StudentClassroomDB] Due content: ${JSON.stringify(b)}`);for(let u of b)if(u.type===`course`){let{cards:d}=await new CourseDB(u.courseID,async()=>this._user).getWeightedCards(t);for(let t of d)m.has(t.cardId)||c.push({...t,provenance:[...t.provenance,{strategy:`classroom`,strategyName:`Classroom`,strategyId:`CLASSROOM`,action:`passed`,score:t.score,reason:`Assigned via classroom from course ${u.courseID}`}]})}else if(u.type===`tag`){let t=await getTag(u.courseID,u.tagID);for(let d of t.taggedCards)m.has(d)||c.push({cardId:d,courseId:u.courseID,score:1,provenance:[{strategy:`classroom`,strategyName:`Classroom`,strategyId:`CLASSROOM`,action:`generated`,score:1,reason:`Classroom assigned tag: ${u.tagID}, new card`}]})}else u.type===`card`&&(m.has(u.cardID)||c.push({cardId:u.cardID,courseId:u.courseID,score:1,provenance:[{strategy:`classroom`,strategyName:`Classroom`,strategyId:`CLASSROOM`,action:`generated`,score:1,reason:`Classroom assigned card, new card`}]}));return logger.info(`[StudentClassroomDB] New cards from classroom ${this._cfg.name}: ${c.length} total (reviews + new)`),{cards:c.sort((t,c)=>c.score-t.score).slice(0,t)}}},TeacherClassroomDB=class _TeacherClassroomDB extends ClassroomDBBase{constructor(t){super(),_defineProperty$2(this,`_stuDb`,void 0),this._id=t}async init(){let t=`classdb-teacher-${this._id}`,c=`classdb-student-${this._id}`;this._db=new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+t,createPouchDBConfig()),this._stuDb=new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+c,createPouchDBConfig());try{return this._db.get(CLASSROOM_CONFIG).then(t=>{this._cfg=t,this._initComplete=!0}).then(()=>{})}catch(t){throw Error(`Error in TeacherClassroomDB constructor: ${JSON.stringify(t)}`)}}static async factory(t){let c=new _TeacherClassroomDB(t);return await c.init(),c}async removeContent(t){let c=this.getContentId(t);try{let t=await this._db.get(c);await this._db.remove(t),this._db.replicate.to(this._stuDb,{doc_ids:[c]})}catch(t){logger.error(`Failed to remove content:`,c,t)}}async assignContent(t){let c,u=this.getContentId(t);return c=t.type===`tag`?await this._db.put({courseID:t.courseID,tagID:t.tagID,type:`tag`,_id:u,assignedBy:t.assignedBy,assignedOn:hooks.utc(),activeOn:t.activeOn||hooks.utc()}):await this._db.put({courseID:t.courseID,type:`course`,_id:u,assignedBy:t.assignedBy,assignedOn:hooks.utc(),activeOn:t.activeOn||hooks.utc()}),c.ok?(this._db.replicate.to(this._stuDb,{doc_ids:[u]}),!0):!1}},ClassroomLookupDB=()=>new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+classroomLookupDBTitle,{skip_setup:!0})}}),init_adminDB2=__esm({"src/impl/couch/adminDB.ts"(){"use strict";init_pouchdb_setup(),init_factory(),init_couch(),init_classroomDB2(),init_courseLookupDB(),init_logger(),AdminDB=class{constructor(){_defineProperty$2(this,`usersDB`,void 0),this.usersDB=new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+`_users`,createPouchDBConfig())}async getUsers(){return(await this.usersDB.allDocs({include_docs:!0,...getStartAndEndKeys2(`org.couchdb.user:`)})).rows.map(t=>t.doc)}async getCourses(){let t=await CourseLookup.allCourseWare();return await Promise.all(t.map(t=>getCredentialledCourseConfig(t._id)))}async removeCourse(t){let c=await CourseLookup.delete(t),u=await getCredentialledCourseConfig(t);u.deleted=!0;let d=await updateCredentialledCourseConfig(t,u);return{ok:c.ok&&d.ok,id:c.id,rev:c.rev}}async getClassrooms(){let t=(await ClassroomLookupDB().allDocs({include_docs:!0})).rows.map(t=>t.doc.uuid);logger.debug(t.join(`, `));let c=[];for(let u=0;u<t.length;u++)try{let d=await TeacherClassroomDB.factory(t[u]);c.push(d)}catch(c){let d=c;d.error&&d.error===`not_found`&&logger.warn(`db ${t[u]} not found`)}return c.map(t=>({...t.getConfig(),_id:t._id}))}}}}),init_CourseSyncService=__esm({"src/impl/couch/CourseSyncService.ts"(){"use strict";var t;init_pouchdb_setup(),init_couch(),init_logger(),CourseSyncService=(t=class _CourseSyncService{constructor(){_defineProperty$2(this,`entries`,new Map)}static getInstance(){return _CourseSyncService.instance||(_CourseSyncService.instance=new _CourseSyncService),_CourseSyncService.instance}static resetInstance(){if(_CourseSyncService.instance){for(let[,t]of _CourseSyncService.instance.entries)t.localDB&&t.localDB.close().catch(()=>{});_CourseSyncService.instance.entries.clear()}_CourseSyncService.instance=null}async ensureSynced(t,c){let u=this.entries.get(t);if(u?.status.state===`ready`&&u.localDB){if(!await this.isLocalEpochStale(t,u.localDB))return;logger.info(`[CourseSyncService] Remote DB epoch changed for course ${t} \u2014 destroying stale local replica`);try{await u.localDB.destroy()}catch{}u.localDB=null,u.readyPromise=null}if(u?.status.state===`disabled`)return;if(u?.readyPromise)return u.readyPromise;let d={localDB:null,status:{state:`not-started`},readyPromise:null};return this.entries.set(t,d),d.readyPromise=this.performSync(t,d,c),d.readyPromise}getLocalDB(t){let c=this.entries.get(t);return c?.status.state===`ready`&&c.localDB?c.localDB:null}isReady(t){return this.entries.get(t)?.status.state===`ready`}getStatus(t){return this.entries.get(t)?.status??{state:`not-started`}}async performSync(t,c,u){try{if(!u&&(c.status={state:`checking-config`},!await this.checkLocalSyncEnabled(t))){c.status={state:`disabled`},c.readyPromise=null,logger.debug(`[CourseSyncService] Local sync disabled for course ${t}`);return}c.status={state:`syncing`};let d=this.localDBName(t),m=new pouchdb_setup_default(d);await this.isLocalEpochStale(t,m)&&(logger.info(`[CourseSyncService] Stale local DB detected for course ${t} \u2014 destroying before sync`),await m.destroy(),m=new pouchdb_setup_default(d)),c.localDB=m;let g=this.getRemoteDB(t),b=Date.now();logger.info(`[CourseSyncService] Starting one-shot replication for course ${t}`);let S=await this.replicate(g,m),C=Date.now()-b;logger.info(`[CourseSyncService] Replication complete for course ${t}: ${S.docs_written} docs in ${C}ms`),c.status={state:`warming-views`};let w=Date.now();await this.warmViewIndices(m);let T=Date.now()-w;logger.info(`[CourseSyncService] View indices warmed for course ${t} in ${T}ms`),c.status={state:`ready`,docsReplicated:S.docs_written,syncTimeMs:C,viewWarmTimeMs:T}}catch(u){let d=u instanceof Error?u.message:String(u);if(logger.error(`[CourseSyncService] Sync failed for course ${t}: ${d}`),c.status={state:`error`,error:d},c.readyPromise=null,c.localDB){try{await c.localDB.destroy()}catch{}c.localDB=null}}}async checkLocalSyncEnabled(t){try{return(await this.getRemoteDB(t).get(`CourseConfig`)).localSync?.enabled===!0}catch(c){return logger.warn(`[CourseSyncService] Could not read CourseConfig for ${t}, assuming local sync disabled: ${c}`),!1}}replicate(t,c){return new Promise((u,d)=>{pouchdb_setup_default.replicate(t,c,{}).on(`complete`,t=>{u(t)}).on(`error`,t=>{d(t)})})}async warmViewIndices(t){for(let c of[`elo`,`getTags`])try{await t.query(c,{limit:1}),logger.debug(`[CourseSyncService] Warmed view index: ${c}`)}catch(t){logger.debug(`[CourseSyncService] Could not warm view ${c}: ${t}`)}}async isLocalEpochStale(t,c){try{let u=await this.getRemoteDB(t).get(`db-epoch`),d=null;try{d=await c.get(`db-epoch`)}catch{return!0}return u.epoch!==d.epoch}catch{return!1}}getRemoteDB(t){return getCourseDB2(t)}localDBName(t){return`coursedb-local-${t}`}},_defineProperty$2(t,`instance`,null),t)}}),init_auth=__esm({"src/impl/couch/auth.ts"(){"use strict";init_factory(),init_logger()}}),CouchDBSyncStrategy_exports={},__export(CouchDBSyncStrategy_exports,{CouchDBSyncStrategy:()=>CouchDBSyncStrategy}),init_CouchDBSyncStrategy=__esm({"src/impl/couch/CouchDBSyncStrategy.ts"(){"use strict";init_factory(),init_types_legacy(),init_logger(),init_common(),init_pouchdb_setup(),init_couch(),init_auth(),log3=t=>{logger.info(t)},CouchDBSyncStrategy=class{constructor(){_defineProperty$2(this,`syncHandle`,void 0)}setupRemoteDB(t){return t===GuestUsername||t.startsWith(GuestUsername)?getLocalUserDB(t):this.getUserDB(t)}getWriteDB(t){return t===GuestUsername||t.startsWith(GuestUsername)?getLocalUserDB(t):this.getUserDB(t)}startSync(t,c){t!==c&&(this.syncHandle=pouchdb_setup_default.sync(t,c,{live:!0,retry:!0}))}stopSync(){this.syncHandle&&(this.syncHandle.cancel(),this.syncHandle=void 0)}canCreateAccount(){return!0}canAuthenticate(){return!0}async createAccount(t,c){let u=await this.getCurrentUsername(),d=u.startsWith(GuestUsername);d&&logger.info(`Creating account for funnel user ${u} -> ${t}`);try{let m=await this.getRemoteCouchRootDB().signUp(t,c);if(m.ok){log3(`CREATEACCOUNT: Successfully created account for ${t}`);try{let t=await this.getRemoteCouchRootDB().logOut();log3(`CREATEACCOUNT: logged out: ${t.ok}`)}catch{}let m=await this.getRemoteCouchRootDB().logIn(t,c);if(log3(`CREATEACCOUNT: logged in as new user: ${m.ok}`),m.ok){if(d){logger.info(`Migrating data from funnel account ${u} to ${t}`);let c=await this.migrateFunnelData(u,t);c.success||logger.warn(`Migration failed: ${c.error}`)}return{status:Status.ok,error:void 0}}else return{status:Status.error,error:`Failed to log in after account creation`}}else return logger.warn(`Signup not OK: ${JSON.stringify(m)}`),{status:Status.error,error:`Account creation failed`}}catch(t){return t.reason===`Document update conflict.`?{status:Status.error,error:`This username is taken!`}:(logger.error(`Error on signup: ${JSON.stringify(t)}`),{status:Status.error,error:t.message||`Unknown error during account creation`})}}async authenticate(t,c){try{return(await this.getRemoteCouchRootDB().logIn(t,c)).ok?(log3(`Successfully logged in as ${t}`),{ok:!0}):(log3(`Login failed for ${t}`),{ok:!1,error:`Invalid username or password`})}catch(c){return logger.error(`Authentication error for ${t}:`,c),{ok:!1,error:c.message||`Authentication failed`}}}async logout(){try{let t=await this.getRemoteCouchRootDB().logOut();return{ok:t.ok,error:t.ok?void 0:`Logout failed`}}catch(t){return logger.error(`Logout error:`,t),{ok:!1,error:t.message||`Logout failed`}}}async getCurrentUsername(){logger.log(`[funnel] CouchDBSyncStrategy.getCurrentUsername() called`);try{let t=await getLoggedInUsername();return logger.log(`[funnel] getLoggedInUsername() returned:`,t),t}catch(t){logger.log(`[funnel] getLoggedInUsername() failed, calling accomodateGuest()`),logger.log(`[funnel] Error was:`,t);let c=accomodateGuest();return logger.log(`[funnel] accomodateGuest() returned:`,c),c.username}}async migrateFunnelData(t,c){try{logger.info(`Starting data migration from ${t} to ${c}`);let u=getLocalUserDB(t),d=getLocalUserDB(c),m=await u.allDocs({include_docs:!0});logger.info(`Found ${m.rows.length} documents in funnel account`);let g=m.rows.filter(t=>!t.id.startsWith(`_design/`)).map(t=>({...t.doc,_rev:void 0}));return g.length>0?(await d.bulkDocs(g),logger.info(`Successfully migrated ${g.length} documents from ${t} to ${c}`)):logger.info(`No documents to migrate from funnel account`),{success:!0}}catch(t){return logger.error(`Migration failed:`,t),{success:!1,error:t instanceof Error?t.message:`Unknown error`}}}getRemoteCouchRootDB(){let t=ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+`skuilder`;try{return new pouchdb_setup_default(t,{skip_setup:!0})}catch(t){throw logger.error(`Failed to initialize remote CouchDB connection:`,t),Error(`Failed to initialize CouchDB: ${JSON.stringify(t)}`)}}getUserDB(t){let c=!1,u=`userdb-${hexEncode(t)}`;return log3(`Fetching user database: ${u} (${t})`),new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+u,createPouchDBConfig())}}}}),init_couch=__esm({"src/impl/couch/index.ts"(){"use strict";init_factory(),init_types_legacy(),init_logger(),init_pouchdb_setup(),init_contentSource(),init_adminDB2(),init_classroomDB2(),init_courseAPI(),init_courseDB(),init_CourseSyncService(),init_CouchDBSyncStrategy(),isBrowser=typeof window<`u`,isBrowser&&(window.process=import_browser.default),GUEST_LOCAL_DB=`userdb-${GuestUsername}`,new pouchdb_setup_default(GUEST_LOCAL_DB),pouchDBincludeCredentialsConfig={fetch(t,c){return c.credentials=`include`,pouchdb_setup_default.fetch(t,c)}},REVIEW_TIME_FORMAT2=`YYYY-MM-DD--kk:mm:ss-SSS`}}),init_BaseUserDB=__esm({"src/impl/common/BaseUserDB.ts"(){"use strict";var t;init_core(),init_util(),init_types_legacy(),init_logger(),init_userDBHelpers(),init_updateQueue(),init_user_course_relDB(),init_couch(),log4=t=>{logger.info(t)},BaseUser=(t=class _BaseUser{static Dummy(t){return new _BaseUser(`Me`,t)}getUsername(){return this._username}isLoggedIn(){return!this._username.startsWith(GuestUsername)}remote(){return this.remoteDB}async createAccount(t,c){if(!this.syncStrategy.canCreateAccount())throw Error(`Account creation not supported by current sync strategy`);if(!this._username.startsWith(GuestUsername))throw Error(`Cannot create a new account while logged in:
362
+ ${t.stack}`:JSON.stringify(t);throw logger.error(`[courseDB] Error creating navigator: ${c}`),t}}setEphemeralHints(t){this._pendingHints=t}async getWeightedCards(t){let c=await this._getCurrentUser();try{let u=await this.createNavigator(c);return this._pendingHints&&(u.setEphemeralHints(this._pendingHints),this._pendingHints=null),u.getWeightedCards(t)}catch(t){throw logger.error(`[courseDB] Error getting weighted cards: ${t}`),t}}async getCardsCenteredAtELO(t={limit:99,elo:`user`},c){let u;if(t.elo===`user`){let t=await this._getCurrentUser();u=-1;try{u=EloToNumber((await t.getCourseRegistrationsDoc()).courses.find(t=>t.courseID===this.id).elo)}catch{u=1e3}}else if(t.elo===`random`){let t=await GET_CACHED(`elo-bounds-${this.id}`,()=>this.getELOBounds());u=Math.round(t.low+Math.random()*(t.high-t.low))}else u=t.elo;let d=[],m=4,g=-1,b=0;for(;d.length<t.limit&&b!==g;)d=await this.getCardsByELO(u,m*t.limit),g=b,b=d.length,logger.debug(`Found ${d.length} elo neighbor cards...`),c&&(d=d.filter(c),logger.debug(`Filtered to ${d.length} cards...`)),m*=2;let S=[];for(;S.length<t.limit&&d.length>0;){let t=randIntWeightedTowardZero(d.length),c=d.splice(t,1)[0];S.push(c)}return S.map(t=>({courseID:this.id,cardID:t.cardID,contentSourceType:`course`,contentSourceID:this.id,elo:t.elo,status:`new`}))}async searchCards(t){logger.log(`[CourseDB ${this.id}] Searching for: "${t}"`);let c;try{c=await this.db.find({selector:{docType:`DISPLAYABLE_DATA`,"data.0.data":{$regex:`.*${t}.*`}}}),logger.log(`[CourseDB ${this.id}] Regex search on data[0].data successful`)}catch(u){logger.log(`[CourseDB ${this.id}] Regex search failed, falling back to manual search:`,u);let d=await this.db.find({selector:{docType:`DISPLAYABLE_DATA`}});logger.log(`[CourseDB ${this.id}] Retrieved ${d.docs.length} documents for manual filtering`),c={docs:d.docs.filter(c=>{let u=JSON.stringify(c).toLowerCase().includes(t.toLowerCase());return u&&logger.log(`[CourseDB ${this.id}] Manual match found in document: ${c._id}`),u})}}if(logger.log(`[CourseDB ${this.id}] Found ${c.docs.length} displayable data documents`),c.docs.length===0){let t=await this.db.find({selector:{docType:`DISPLAYABLE_DATA`},limit:5});logger.log(`[CourseDB ${this.id}] Sample displayable data:`,t.docs.map(t=>({id:t._id,docType:t.docType,dataStructure:t.data?Object.keys(t.data):`no data field`,dataContent:t.data,fullDoc:t})))}let u=[];for(let t of c.docs){let c=await this.db.find({selector:{docType:`CARD`,id_displayable_data:{$in:[t._id]}}});logger.log(`[CourseDB ${this.id}] Displayable data ${t._id} linked to ${c.docs.length} cards`),u.push(...c.docs)}return logger.log(`[CourseDB ${this.id}] Total cards found: ${u.length}`),u}async find(t){return this.db.find(t)}}}}),init_classroomDB2=__esm({"src/impl/couch/classroomDB.ts"(){"use strict";init_factory(),init_logger(),init_pouchdb_setup(),init_couch(),init_courseDB(),classroomLookupDBTitle=`classdb-lookup`,CLASSROOM_CONFIG=`ClassroomConfig`,ClassroomDBBase=class{constructor(){_defineProperty$2(this,`_id`,void 0),_defineProperty$2(this,`_db`,void 0),_defineProperty$2(this,`_cfg`,void 0),_defineProperty$2(this,`_initComplete`,!1),_defineProperty$2(this,`_content_prefix`,`content`)}get _content_searchkeys(){return getStartAndEndKeys2(this._content_prefix)}async getAssignedContent(){return logger.info(`Getting assigned content...`),(await this._db.allDocs({startkey:this._content_prefix,endkey:this._content_prefix+`￰`,include_docs:!0})).rows.map(t=>t.doc)}getContentId(t){return t.type===`tag`?`${this._content_prefix}-${t.courseID}-${t.tagID}`:`${this._content_prefix}-${t.courseID}`}get ready(){return this._initComplete}getConfig(){return this._cfg}},StudentClassroomDB=class _StudentClassroomDB extends ClassroomDBBase{constructor(t,c){super(),_defineProperty$2(this,`userMessages`,void 0),_defineProperty$2(this,`_user`,void 0),this._id=t,this._user=c}async init(){let t=`classdb-student-${this._id}`;this._db=new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+t,createPouchDBConfig());try{this._cfg=await this._db.get(CLASSROOM_CONFIG),this.userMessages=this._db.changes({since:`now`,live:!0,include_docs:!0}),this._initComplete=!0;return}catch(t){throw Error(`Error in StudentClassroomDB constructor: ${JSON.stringify(t)}`)}}static async factory(t,c){let u=new _StudentClassroomDB(t,c);return await u.init(),u}setChangeFcn(t){this.userMessages.on(`change`,t)}async getWeightedCards(t){let c=[],u=(await this._user.getPendingReviews()).filter(t=>t.scheduledFor===`classroom`&&t.schedulingAgentId===this._id);for(let t of u)c.push({cardId:t.cardId,courseId:t.courseId,score:1,reviewID:t._id,provenance:[{strategy:`classroom`,strategyName:`Classroom`,strategyId:`CLASSROOM`,action:`generated`,score:1,reason:`Classroom scheduled review`}]});let d=await this._user.getActiveCards(),m=new Set(d.map(t=>t.cardID)),g=hooks.utc(),b=(await this.getAssignedContent()).filter(t=>g.isAfter(hooks.utc(t.activeOn,REVIEW_TIME_FORMAT2)));logger.info(`[StudentClassroomDB] Due content: ${JSON.stringify(b)}`);for(let u of b)if(u.type===`course`){let{cards:d}=await new CourseDB(u.courseID,async()=>this._user).getWeightedCards(t);for(let t of d)m.has(t.cardId)||c.push({...t,provenance:[...t.provenance,{strategy:`classroom`,strategyName:`Classroom`,strategyId:`CLASSROOM`,action:`passed`,score:t.score,reason:`Assigned via classroom from course ${u.courseID}`}]})}else if(u.type===`tag`){let t=await getTag(u.courseID,u.tagID);for(let d of t.taggedCards)m.has(d)||c.push({cardId:d,courseId:u.courseID,score:1,provenance:[{strategy:`classroom`,strategyName:`Classroom`,strategyId:`CLASSROOM`,action:`generated`,score:1,reason:`Classroom assigned tag: ${u.tagID}, new card`}]})}else u.type===`card`&&(m.has(u.cardID)||c.push({cardId:u.cardID,courseId:u.courseID,score:1,provenance:[{strategy:`classroom`,strategyName:`Classroom`,strategyId:`CLASSROOM`,action:`generated`,score:1,reason:`Classroom assigned card, new card`}]}));return logger.info(`[StudentClassroomDB] New cards from classroom ${this._cfg.name}: ${c.length} total (reviews + new)`),{cards:c.sort((t,c)=>c.score-t.score).slice(0,t)}}},TeacherClassroomDB=class _TeacherClassroomDB extends ClassroomDBBase{constructor(t){super(),_defineProperty$2(this,`_stuDb`,void 0),this._id=t}async init(){let t=`classdb-teacher-${this._id}`,c=`classdb-student-${this._id}`;this._db=new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+t,createPouchDBConfig()),this._stuDb=new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+c,createPouchDBConfig());try{return this._db.get(CLASSROOM_CONFIG).then(t=>{this._cfg=t,this._initComplete=!0}).then(()=>{})}catch(t){throw Error(`Error in TeacherClassroomDB constructor: ${JSON.stringify(t)}`)}}static async factory(t){let c=new _TeacherClassroomDB(t);return await c.init(),c}async removeContent(t){let c=this.getContentId(t);try{let t=await this._db.get(c);await this._db.remove(t),this._db.replicate.to(this._stuDb,{doc_ids:[c]})}catch(t){logger.error(`Failed to remove content:`,c,t)}}async assignContent(t){let c,u=this.getContentId(t);return c=t.type===`tag`?await this._db.put({courseID:t.courseID,tagID:t.tagID,type:`tag`,_id:u,assignedBy:t.assignedBy,assignedOn:hooks.utc(),activeOn:t.activeOn||hooks.utc()}):await this._db.put({courseID:t.courseID,type:`course`,_id:u,assignedBy:t.assignedBy,assignedOn:hooks.utc(),activeOn:t.activeOn||hooks.utc()}),c.ok?(this._db.replicate.to(this._stuDb,{doc_ids:[u]}),!0):!1}},ClassroomLookupDB=()=>new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+classroomLookupDBTitle,{skip_setup:!0})}}),init_adminDB2=__esm({"src/impl/couch/adminDB.ts"(){"use strict";init_pouchdb_setup(),init_factory(),init_couch(),init_classroomDB2(),init_courseLookupDB(),init_logger(),AdminDB=class{constructor(){_defineProperty$2(this,`usersDB`,void 0),this.usersDB=new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+`_users`,createPouchDBConfig())}async getUsers(){return(await this.usersDB.allDocs({include_docs:!0,...getStartAndEndKeys2(`org.couchdb.user:`)})).rows.map(t=>t.doc)}async getCourses(){let t=await CourseLookup.allCourseWare();return await Promise.all(t.map(t=>getCredentialledCourseConfig(t._id)))}async removeCourse(t){let c=await CourseLookup.delete(t),u=await getCredentialledCourseConfig(t);u.deleted=!0;let d=await updateCredentialledCourseConfig(t,u);return{ok:c.ok&&d.ok,id:c.id,rev:c.rev}}async getClassrooms(){let t=(await ClassroomLookupDB().allDocs({include_docs:!0})).rows.map(t=>t.doc.uuid);logger.debug(t.join(`, `));let c=[];for(let u=0;u<t.length;u++)try{let d=await TeacherClassroomDB.factory(t[u]);c.push(d)}catch(c){let d=c;d.error&&d.error===`not_found`&&logger.warn(`db ${t[u]} not found`)}return c.map(t=>({...t.getConfig(),_id:t._id}))}}}}),CourseSyncService_exports={},__export(CourseSyncService_exports,{CourseSyncService:()=>CourseSyncService}),init_CourseSyncService=__esm({"src/impl/couch/CourseSyncService.ts"(){"use strict";var t;init_pouchdb_setup(),init_couch(),init_logger(),DEFAULT_REPLICATION={batchSize:1e3,batchesLimit:5},CourseSyncService=(t=class _CourseSyncService{constructor(){_defineProperty$2(this,`entries`,new Map),_defineProperty$2(this,`replicationOptions`,DEFAULT_REPLICATION)}static getInstance(){return _CourseSyncService.instance||(_CourseSyncService.instance=new _CourseSyncService),_CourseSyncService.instance}configure(t){t.replication&&(this.replicationOptions={...DEFAULT_REPLICATION,...t.replication},logger.info(`[CourseSyncService] Replication configured: batch_size=${this.replicationOptions.batchSize}, batches_limit=${this.replicationOptions.batchesLimit}`))}static resetInstance(){if(_CourseSyncService.instance){for(let[,t]of _CourseSyncService.instance.entries)t.localDB&&t.localDB.close().catch(()=>{});_CourseSyncService.instance.entries.clear()}_CourseSyncService.instance=null}async ensureSynced(t,c){let u=this.entries.get(t);if(u?.status.state===`ready`&&u.localDB){if(!await this.isLocalEpochStale(t,u.localDB))return;logger.info(`[CourseSyncService] Remote DB epoch changed for course ${t} \u2014 destroying stale local replica`);try{await u.localDB.destroy()}catch{}u.localDB=null,u.readyPromise=null}if(u?.status.state===`disabled`)return;if(u?.readyPromise)return u.readyPromise;let d={localDB:null,status:{state:`not-started`},readyPromise:null};return this.entries.set(t,d),d.readyPromise=this.performSync(t,d,c),d.readyPromise}getLocalDB(t){let c=this.entries.get(t);return c?.status.state===`ready`&&c.localDB?c.localDB:null}isReady(t){return this.entries.get(t)?.status.state===`ready`}getStatus(t){return this.entries.get(t)?.status??{state:`not-started`}}async performSync(t,c,u){try{if(!u&&(c.status={state:`checking-config`},!await this.checkLocalSyncEnabled(t))){c.status={state:`disabled`},c.readyPromise=null,logger.debug(`[CourseSyncService] Local sync disabled for course ${t}`);return}c.status={state:`syncing`};let d=this.localDBName(t),m=new pouchdb_setup_default(d);await this.isLocalEpochStale(t,m)&&(logger.info(`[CourseSyncService] Stale local DB detected for course ${t} \u2014 destroying before sync`),await m.destroy(),m=new pouchdb_setup_default(d)),c.localDB=m;let g=this.getRemoteDB(t),b=Date.now();logger.info(`[CourseSyncService] Starting one-shot replication for course ${t} (batch_size=${this.replicationOptions.batchSize}, batches_limit=${this.replicationOptions.batchesLimit})`);let S=await this.replicate(g,m),C=Date.now()-b;logger.info(`[CourseSyncService] Replication complete for course ${t}: ${S.docs_written} docs in ${C}ms`),c.status={state:`warming-views`};let w=Date.now();await this.warmViewIndices(m);let T=Date.now()-w;logger.info(`[CourseSyncService] View indices warmed for course ${t} in ${T}ms`),c.status={state:`ready`,docsReplicated:S.docs_written,syncTimeMs:C,viewWarmTimeMs:T}}catch(u){let d=u instanceof Error?u.message:String(u);if(logger.error(`[CourseSyncService] Sync failed for course ${t}: ${d}`),c.status={state:`error`,error:d},c.readyPromise=null,c.localDB){try{await c.localDB.destroy()}catch{}c.localDB=null}}}async checkLocalSyncEnabled(t){try{return(await this.getRemoteDB(t).get(`CourseConfig`)).localSync?.enabled===!0}catch(c){return logger.warn(`[CourseSyncService] Could not read CourseConfig for ${t}, assuming local sync disabled: ${c}`),!1}}replicate(t,c){return new Promise((u,d)=>{pouchdb_setup_default.replicate(t,c,{batch_size:this.replicationOptions.batchSize,batches_limit:this.replicationOptions.batchesLimit}).on(`complete`,t=>{u(t)}).on(`error`,t=>{d(t)})})}async warmViewIndices(t){for(let c of[`elo`,`getTags`])try{await t.query(c,{limit:1}),logger.debug(`[CourseSyncService] Warmed view index: ${c}`)}catch(t){logger.debug(`[CourseSyncService] Could not warm view ${c}: ${t}`)}}async isLocalEpochStale(t,c){try{let u=await this.getRemoteDB(t).get(`db-epoch`),d=null;try{d=await c.get(`db-epoch`)}catch{return!0}return u.epoch!==d.epoch}catch{return!1}}getRemoteDB(t){return getCourseDB2(t)}localDBName(t){return`coursedb-local-${t}`}},_defineProperty$2(t,`instance`,null),t)}}),init_auth=__esm({"src/impl/couch/auth.ts"(){"use strict";init_factory(),init_logger()}}),CouchDBSyncStrategy_exports={},__export(CouchDBSyncStrategy_exports,{CouchDBSyncStrategy:()=>CouchDBSyncStrategy}),init_CouchDBSyncStrategy=__esm({"src/impl/couch/CouchDBSyncStrategy.ts"(){"use strict";init_factory(),init_types_legacy(),init_logger(),init_common(),init_pouchdb_setup(),init_couch(),init_auth(),log3=t=>{logger.info(t)},CouchDBSyncStrategy=class{constructor(){_defineProperty$2(this,`syncHandle`,void 0)}setupRemoteDB(t){return t===GuestUsername||t.startsWith(GuestUsername)?getLocalUserDB(t):this.getUserDB(t)}getWriteDB(t){return t===GuestUsername||t.startsWith(GuestUsername)?getLocalUserDB(t):this.getUserDB(t)}startSync(t,c){t!==c&&(this.syncHandle=pouchdb_setup_default.sync(t,c,{live:!0,retry:!0}))}stopSync(){this.syncHandle&&(this.syncHandle.cancel(),this.syncHandle=void 0)}canCreateAccount(){return!0}canAuthenticate(){return!0}async createAccount(t,c){let u=await this.getCurrentUsername(),d=u.startsWith(GuestUsername);d&&logger.info(`Creating account for funnel user ${u} -> ${t}`);try{let m=await this.getRemoteCouchRootDB().signUp(t,c);if(m.ok){log3(`CREATEACCOUNT: Successfully created account for ${t}`);try{let t=await this.getRemoteCouchRootDB().logOut();log3(`CREATEACCOUNT: logged out: ${t.ok}`)}catch{}let m=await this.getRemoteCouchRootDB().logIn(t,c);if(log3(`CREATEACCOUNT: logged in as new user: ${m.ok}`),m.ok){if(d){logger.info(`Migrating data from funnel account ${u} to ${t}`);let c=await this.migrateFunnelData(u,t);c.success||logger.warn(`Migration failed: ${c.error}`)}return{status:Status.ok,error:void 0}}else return{status:Status.error,error:`Failed to log in after account creation`}}else return logger.warn(`Signup not OK: ${JSON.stringify(m)}`),{status:Status.error,error:`Account creation failed`}}catch(t){return t.reason===`Document update conflict.`?{status:Status.error,error:`This username is taken!`}:(logger.error(`Error on signup: ${JSON.stringify(t)}`),{status:Status.error,error:t.message||`Unknown error during account creation`})}}async authenticate(t,c){try{return(await this.getRemoteCouchRootDB().logIn(t,c)).ok?(log3(`Successfully logged in as ${t}`),{ok:!0}):(log3(`Login failed for ${t}`),{ok:!1,error:`Invalid username or password`})}catch(c){return logger.error(`Authentication error for ${t}:`,c),{ok:!1,error:c.message||`Authentication failed`}}}async logout(){try{let t=await this.getRemoteCouchRootDB().logOut();return{ok:t.ok,error:t.ok?void 0:`Logout failed`}}catch(t){return logger.error(`Logout error:`,t),{ok:!1,error:t.message||`Logout failed`}}}async getCurrentUsername(){logger.log(`[funnel] CouchDBSyncStrategy.getCurrentUsername() called`);try{let t=await getLoggedInUsername();return logger.log(`[funnel] getLoggedInUsername() returned:`,t),t}catch(t){logger.log(`[funnel] getLoggedInUsername() failed, calling accomodateGuest()`),logger.log(`[funnel] Error was:`,t);let c=accomodateGuest();return logger.log(`[funnel] accomodateGuest() returned:`,c),c.username}}async migrateFunnelData(t,c){try{logger.info(`Starting data migration from ${t} to ${c}`);let u=getLocalUserDB(t),d=getLocalUserDB(c),m=await u.allDocs({include_docs:!0});logger.info(`Found ${m.rows.length} documents in funnel account`);let g=m.rows.filter(t=>!t.id.startsWith(`_design/`)).map(t=>({...t.doc,_rev:void 0}));return g.length>0?(await d.bulkDocs(g),logger.info(`Successfully migrated ${g.length} documents from ${t} to ${c}`)):logger.info(`No documents to migrate from funnel account`),{success:!0}}catch(t){return logger.error(`Migration failed:`,t),{success:!1,error:t instanceof Error?t.message:`Unknown error`}}}getRemoteCouchRootDB(){let t=ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+`skuilder`;try{return new pouchdb_setup_default(t,{skip_setup:!0})}catch(t){throw logger.error(`Failed to initialize remote CouchDB connection:`,t),Error(`Failed to initialize CouchDB: ${JSON.stringify(t)}`)}}getUserDB(t){let c=!1,u=`userdb-${hexEncode(t)}`;return log3(`Fetching user database: ${u} (${t})`),new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+u,createPouchDBConfig())}}}}),init_couch=__esm({"src/impl/couch/index.ts"(){"use strict";init_factory(),init_types_legacy(),init_logger(),init_pouchdb_setup(),init_contentSource(),init_adminDB2(),init_classroomDB2(),init_courseAPI(),init_courseDB(),init_CourseSyncService(),init_CouchDBSyncStrategy(),isBrowser=typeof window<`u`,isBrowser&&(window.process=import_browser.default),GUEST_LOCAL_DB=`userdb-${GuestUsername}`,new pouchdb_setup_default(GUEST_LOCAL_DB),pouchDBincludeCredentialsConfig={fetch(t,c){return c.credentials=`include`,pouchdb_setup_default.fetch(t,c)}},REVIEW_TIME_FORMAT2=`YYYY-MM-DD--kk:mm:ss-SSS`}}),init_BaseUserDB=__esm({"src/impl/common/BaseUserDB.ts"(){"use strict";var t;init_core(),init_util(),init_types_legacy(),init_logger(),init_userDBHelpers(),init_updateQueue(),init_user_course_relDB(),init_couch(),log4=t=>{logger.info(t)},BaseUser=(t=class _BaseUser{static Dummy(t){return new _BaseUser(`Me`,t)}getUsername(){return this._username}isLoggedIn(){return!this._username.startsWith(GuestUsername)}remote(){return this.remoteDB}async createAccount(t,c){if(!this.syncStrategy.canCreateAccount())throw Error(`Account creation not supported by current sync strategy`);if(!this._username.startsWith(GuestUsername))throw Error(`Cannot create a new account while logged in:
363
363
  Currently logged-in as ${this._username}.`);let u=await this.syncStrategy.createAccount(t,c);if(u.status===Status.ok){log4(`Account created successfully, updating username to ${t}`),this._username=t;try{localStorage.removeItem(`sk-guest-uuid`)}catch(t){logger.warn(`localStorage not available (Node.js environment):`,t)}await this.init()}return{status:u.status,error:u.error||``}}async login(t,c){if(!this.syncStrategy.canAuthenticate())throw Error(`Authentication not supported by current sync strategy`);if(!this._username.startsWith(GuestUsername)&&this._username!=t){if(this._username!=t)throw Error(`Cannot change accounts while logged in.
364
364
  Log out of account ${this.getUsername()} before logging in as ${t}.`);logger.warn(`User ${this._username} is already logged in, but executing login again.`)}let u=await this.syncStrategy.authenticate(t,c);if(u.ok){log4(`Logged in as ${t}`),this._username=t;try{localStorage.removeItem(`sk-guest-uuid`)}catch(t){logger.warn(`localStorage not available (Node.js environment):`,t)}await this.init()}return u}async resetUserData(){if(this.syncStrategy.canAuthenticate())return{status:Status.error,error:`Reset user data is only available for local-only mode. Use logout instead for remote sync.`};try{let t=getLocalUserDB(this._username),c=(await t.allDocs({include_docs:!1})).rows.filter(t=>{let c=t.id;return c.startsWith(DocTypePrefixes.CARDRECORD)||c.startsWith(DocTypePrefixes.SCHEDULED_CARD)||c.startsWith(DocTypePrefixes.STRATEGY_STATE)||c.startsWith(DocTypePrefixes.USER_OUTCOME)||c.startsWith(DocTypePrefixes.STRATEGY_LEARNING_STATE)||c===_BaseUser.DOC_IDS.COURSE_REGISTRATIONS||c===_BaseUser.DOC_IDS.CLASSROOM_REGISTRATIONS||c===_BaseUser.DOC_IDS.CONFIG}).map(t=>({_id:t.id,_rev:t.value.rev,_deleted:!0}));return c.length>0&&await t.bulkDocs(c),await this.init(),{status:Status.ok}}catch(t){return logger.error(`Failed to reset user data:`,t),{status:Status.error,error:t instanceof Error?t.message:`Unknown error during reset`}}}async logout(){if(!this.syncStrategy.canAuthenticate())return this._username=await this.syncStrategy.getCurrentUsername(),await this.init(),{ok:!0};let t=await this.syncStrategy.logout();return this._username=await this.syncStrategy.getCurrentUsername(),await this.init(),t}async get(t){return this.localDB.get(t)}update(t,c){return this.updateQueue.update(t,c)}async getCourseRegistrationsDoc(){logger.debug(`Fetching courseRegistrations for ${this.getUsername()}`);let t;try{return await this.localDB.get(_BaseUser.DOC_IDS.COURSE_REGISTRATIONS)}catch(c){if(c.status===404)await this.localDB.put({_id:_BaseUser.DOC_IDS.COURSE_REGISTRATIONS,courses:[],studyWeight:{}}),t=await this.getCourseRegistrationsDoc();else throw Error(`Unexpected error ${JSON.stringify(c)} in getOrCreateCourseRegistrationDoc...`)}return t}async getActiveCourses(){return(await this.getCourseRegistrationsDoc()).courses.filter(t=>t.status===void 0||t.status===`active`)}async getActiveCards(){let t=getStartAndEndKeys(DocTypePrefixes.SCHEDULED_CARD);return(await this.remoteDB.allDocs({startkey:t.startkey,endkey:t.endkey,include_docs:!0})).rows.map(t=>({courseID:t.doc.courseId,cardID:t.doc.cardId}))}async getActivityRecords(){try{let t=await this.getHistory(),c=[];if(!Array.isArray(t))return logger.error(`getHistory did not return an array:`,t),c;let u=0;for(let d=0;d<t.length;d++)try{t[d]&&Array.isArray(t[d].records)&&t[d].records.forEach(t=>{try{if(!t.timeStamp)return;let d;if(typeof t.timeStamp==`object`)if(typeof t.timeStamp.toDate==`function`)d=t.timeStamp.toISOString();else if(t.timeStamp instanceof Date)d=t.timeStamp.toISOString();else{u<3&&(logger.warn(`Unknown timestamp object type:`,t.timeStamp),u++);return}else if(typeof t.timeStamp==`string`){let c=new Date(t.timeStamp);if(isNaN(c.getTime()))return;d=t.timeStamp}else if(typeof t.timeStamp==`number`)d=new Date(t.timeStamp).toISOString();else return;c.push({timeStamp:d,courseID:t.courseID||`unknown`,cardID:t.cardID||`unknown`,timeSpent:t.timeSpent||0,type:`card_view`})}catch{}})}catch(t){logger.error(`Error processing history item:`,t)}return logger.debug(`Found ${c.length} activity records`),c}catch(t){return logger.error(`Error in getActivityRecords:`,t),[]}}async getReviewstoDate(t,c){let u=getStartAndEndKeys(DocTypePrefixes.SCHEDULED_CARD),d=await this.remoteDB.allDocs({startkey:u.startkey,endkey:u.endkey,include_docs:!0});return log4(`Fetching ${this._username}'s scheduled reviews${c?` for course ${c}`:``}.`),d.rows.filter(u=>{if(u.id.startsWith(DocTypePrefixes.SCHEDULED_CARD)){let d=hooks.utc(u.id.substr(DocTypePrefixes.SCHEDULED_CARD.length),REVIEW_TIME_FORMAT);if(t.isAfter(d)&&(c===void 0||u.doc.courseId===c))return!0}}).map(t=>t.doc)}async getReviewsForcast(t){let c=hooks.utc().add(t,`days`);return this.getReviewstoDate(c)}async getPendingReviews(t){let c=hooks.utc();return this.getReviewstoDate(c,t)}async getScheduledReviewCount(t){return(await this.getPendingReviews(t)).length}async getRegisteredCourses(){return(await this.getCourseRegistrationsDoc()).courses.filter(t=>!t.status||t.status===`active`||t.status===`maintenance-mode`)}async getCourseRegDoc(t){let c=(await this.getCourseRegistrationsDoc()).courses.find(c=>c.courseID===t);if(c)return c;throw Error(`Course registration not found for course ID: ${t}`)}async registerForCourse(t,c=!1){return this.getCourseRegistrationsDoc().then(u=>{let d=c?`preview`:`active`;logger.debug(`Registering for ${t} with status: ${d}`);let m={status:d,courseID:t,user:!0,admin:!1,moderator:!1,elo:{global:{score:1e3,count:0},tags:{},misc:{}}};return u.courses.filter(t=>t.courseID===m.courseID).length===0?(log4(`It's a new course registration!`),u.courses.push(m),u.studyWeight[t]=1):u.courses.forEach(c=>{log4(`Found the previously registered course!`),c.courseID===t&&(c.status=d)}),this.localDB.put(u)}).catch(t=>{throw log4(`Registration failed because of: ${JSON.stringify(t)}`),t})}async dropCourse(t,c=`dropped`){return this.getCourseRegistrationsDoc().then(u=>{let d=-1;for(let c=0;c<u.courses.length;c++)u.courses[c].courseID===t&&(d=c);if(d!==-1)delete u.studyWeight[t],u.courses[d].status=c;else throw Error(`User ${this.getUsername()} is not currently registered for course ${t}`);return this.localDB.put(u)})}async getCourseInterface(t){return new UsrCrsData(this,t)}async getUserEditableCourses(){let t=[],c=await this.getCourseRegistrationsDoc();return t=t.concat(c.courses.map(t=>t.courseID)),await Promise.all(t.map(async t=>await getCredentialledCourseConfig(t)))}async getConfig(){let t={_id:_BaseUser.DOC_IDS.CONFIG,darkMode:!1,likesConfetti:!1,sessionTimeLimit:5};try{let t=await this.localDB.get(_BaseUser.DOC_IDS.CONFIG);return logger.debug(`Raw config from DB:`,t),t}catch(c){let u=c;if(u.name&&u.name===`not_found`)return await this.localDB.put(t),this.getConfig();throw logger.error(`Error setting user default config:`,c),Error(`Error returning the user's configuration: ${JSON.stringify(c)}`)}}async setConfig(t){logger.debug(`Setting Config items ${JSON.stringify(t)}`);let c=await this.getConfig(),u=await this.localDB.put({...c,...t});u.ok?logger.debug(`Config items set: ${JSON.stringify(t)}`):logger.error(`Error setting config items: ${JSON.stringify(u)}`)}static async instance(t,c){return c?(_BaseUser._instance=new _BaseUser(c,t),await _BaseUser._instance.init(),_BaseUser._instance):_BaseUser._instance&&_BaseUser._initialized?_BaseUser._instance:_BaseUser._instance?new Promise(t=>{(function waitForUser(){if(_BaseUser._initialized)return t(_BaseUser._instance);setTimeout(waitForUser,50)})()}):(_BaseUser._instance=new _BaseUser(await t.getCurrentUsername(),t),await _BaseUser._instance.init(),_BaseUser._instance)}constructor(t,c){_defineProperty$2(this,`_username`,void 0),_defineProperty$2(this,`syncStrategy`,void 0),_defineProperty$2(this,`localDB`,void 0),_defineProperty$2(this,`remoteDB`,void 0),_defineProperty$2(this,`writeDB`,void 0),_defineProperty$2(this,`updateQueue`,void 0),_BaseUser._initialized=!1,this._username=t,this.syncStrategy=c,this.setDBandQ()}setDBandQ(){this.localDB=getLocalUserDB(this._username),this.remoteDB=this.syncStrategy.setupRemoteDB(this._username),this.writeDB=this.syncStrategy.getWriteDB?this.syncStrategy.getWriteDB(this._username):this.localDB,this.updateQueue=new UpdateQueue(this.localDB,this.writeDB)}async init(){if(_BaseUser._initialized=!1,this._username===`admin`){_BaseUser._initialized=!0;return}this.setDBandQ(),this.syncStrategy.startSync(this.localDB,this.remoteDB),this.applyDesignDocs().catch(t=>{log4(`Error in applyDesignDocs background task: ${t}`),t&&typeof t==`object`&&log4(`Full error details in applyDesignDocs: ${JSON.stringify(t)}`)}),this.deduplicateReviews().catch(t=>{log4(`Error in deduplicateReviews background task: ${t}`),t&&typeof t==`object`&&log4(`Full error details in background task: ${JSON.stringify(t)}`)}),_BaseUser._initialized=!0}async applyDesignDocs(){if(log4(`Starting applyDesignDocs for user: ${this._username}`),log4(`Remote DB name: ${this.remoteDB.name||`unknown`}`),this._username===`admin`){log4(`Skipping design docs for admin user`);return}log4(`Applying ${_BaseUser.designDocs.length} design docs`);for(let t of _BaseUser.designDocs){log4(`Applying design doc: ${t._id}`);try{try{let c=await this.remoteDB.get(t._id);await this.remoteDB.put({...t,_rev:c._rev})}catch(c){if(c?.name===`not_found`)await this.remoteDB.put(t);else throw c}}catch(c){if(c.name&&c.name===`conflict`)logger.warn(`Design doc ${t._id} update conflict - will retry`),await new Promise(t=>setTimeout(t,1e3)),await this.applyDesignDoc(t);else throw logger.error(`Failed to apply design doc ${t._id}:`,c),c}}}async applyDesignDoc(t,c=3){try{let c=await this.remoteDB.get(t._id);await this.remoteDB.put({...t,_rev:c._rev})}catch(u){if(u?.name===`conflict`&&c>0)return await new Promise(t=>setTimeout(t,1e3)),this.applyDesignDoc(t,c-1);throw u}}async putCardRecord(t){let c=getCardHistoryID(t.courseID,t.cardID);t.timeStamp=hooks.utc(t.timeStamp).toString();try{let u=await this.update(c,function(c){return c.records.push(t),c.bestInterval=c.bestInterval||0,c.lapses=c.lapses||0,c.streak=c.streak||0,c});return u.records=u.records.map(t=>{let c={...t};return c.timeStamp=hooks.utc(t.timeStamp),c}),u}catch(u){let d=u;if(d.status===404)try{let u={_id:c,cardID:t.cardID,courseID:t.courseID,records:[t],lapses:0,streak:0,bestInterval:0},d=await this.writeDB.put(u);return{...u,_rev:d.rev}}catch(t){throw Error(`Failed to create CardHistory for ${c}. Reason: ${t}`)}else throw Error(`putCardRecord failed because of:
365
365
  name:${d.name}
@@ -455,7 +455,7 @@ Example:
455
455
  `;if(!c)for(let t of T){let c={cardID:t.cardId,courseID:t.courseId,contentSourceType:`course`,contentSourceID:t.courseId,reviewID:t.reviewID,status:`review`};this.reviewQ.add(c,c.cardID),D+=`Review: ${t.courseId}::${t.cardId} (score: ${t.score.toFixed(2)})
456
456
  `}let O=E.filter(t=>t.score>=_SessionController.WELL_INDICATED_SCORE).length,Or=[];for(let t of E){let c={cardID:t.cardId,courseID:t.courseId,contentSourceType:`course`,contentSourceID:t.courseId,status:`new`};Or.push(c),D+=`New: ${t.courseId}::${t.cardId} (score: ${t.score.toFixed(2)})
457
457
  `}if(u){let t=this.newQ.mergeToFront(Or,t=>t.cardID);D+=`Additive merge: ${t} new cards added to front of newQ
458
- `}else if(c)this.newQ.replaceAll(Or,t=>t.cardID);else for(let t of Or)this.newQ.add(t,t.cardID);return this.log(D),O}_getItemsToHydrate(){let t=[],c=2;for(let c=0;c<Math.min(2,this.reviewQ.length);c++)t.push(this.reviewQ.peek(c));for(let c=0;c<Math.min(2,this.newQ.length);c++)t.push(this.newQ.peek(c));for(let c=0;c<Math.min(2,this.failedQ.length);c++)t.push(this.failedQ.peek(c));return t}_selectNextItemToHydrate(){let t=Math.random(),c=.1,u=.75;if(this.reviewQ.length===0&&this.failedQ.length===0&&this.newQ.length===0||this._secondsRemaining<2&&this.failedQ.length===0&&this._minCardsGuarantee<=0)return null;if(this._secondsRemaining<=0&&this._minCardsGuarantee<=0)return this.failedQ.length>0?this.failedQ.peek(0):null;if(this.newQ.dequeueCount<this.sources.length&&this.newQ.length)return this.newQ.peek(0);let d=this.estimateCleanupTime(),m=this.estimateReviewTime();return this._secondsRemaining-(d+m)>20?(c=.5,u=.9):this._secondsRemaining-d>20?(c=.05,u=.9):(c=.01,u=.1),this.failedQ.length===0&&(u=1),this.reviewQ.length===0&&(c=u),t<c&&this.newQ.length?this.newQ.peek(0):t<u&&this.reviewQ.length?this.reviewQ.peek(0):this.failedQ.length?this.failedQ.peek(0):(this.log(`No more cards available for the session!`),null)}async nextCard(t=`dismiss-success`){if(this.dismissCurrentCard(t),this._minCardsGuarantee>0&&(this._minCardsGuarantee--,this.log(`[CardGuarantee] ${this._minCardsGuarantee} guaranteed cards remaining`)),this._replanPromise&&(this.log(`nextCard: awaiting in-flight replan before drawing`),await this._replanPromise),this.newQ.length<=1&&this._secondsRemaining>0&&!this._replanPromise){this._suppressQualityReplan=!1;let t=this.reviewQ.length+this.failedQ.length;this.log(`[AutoReplan:depletion] newQ has ${this.newQ.length} card(s) (${t} in other queues) with ${this._secondsRemaining}s remaining. Triggering background replan.`),this.requestReplan()}if(!this._suppressQualityReplan&&this._wellIndicatedRemaining<=3&&this.newQ.length>0&&!this._replanPromise&&(this.log(`[AutoReplan:quality] ${this._wellIndicatedRemaining} well-indicated cards remaining (newQ: ${this.newQ.length}). Triggering background replan.`),this.requestReplan()),this._secondsRemaining<=0&&this.failedQ.length===0&&this._minCardsGuarantee<=0)return this._currentCard=null,endSessionTracking(),null;let c=3,u=250,d=0;for(;this._secondsRemaining>0&&this.newQ.length===0&&this.reviewQ.length===0&&this.failedQ.length===0;)if(this.log(`[WedgeBreaker] All queues empty with ${this._secondsRemaining}s remaining. Running pipeline (attempt ${d+1}/3).`),await this._replanUncoalesced({label:`wedge-breaker`}),this.newQ.length===0&&this.reviewQ.length===0&&this.failedQ.length===0){if(d++,d>=3){this.log(`[WedgeBreaker] Pipeline returned no content 3 consecutive times. Giving up; session will end.`);break}await new Promise(t=>setTimeout(t,250))}else d=0;let m=20;for(let t=0;t<20;t++){let t=this._selectNextItemToHydrate();if(!t)return this._currentCard=null,endSessionTracking(),null;let c=this.hydrationService.getHydratedCard(t.cardID);if(c||(c=await this.hydrationService.waitForCard(t.cardID)),this.removeItemFromQueue(t),c){await this.hydrationService.ensureHydratedCards(),this._currentCard=c;let u=t.status===`review`||t.status===`failed-review`?`review`:t.status===`new`||t.status===`failed-new`?`new`:`failed`,d=t.status.startsWith(`failed`)?`failedQ`:t.status===`review`?`reviewQ`:`newQ`;return recordCardPresentation(t.cardID,t.courseID,this.courseNameCache.get(t.courseID),u,d),snapshotQueues(this.reviewQ.length,this.newQ.length,this.failedQ.length),c}this.log(`Skipping card ${t.cardID}: hydration failed, trying next`),isReview(t)&&this.srsService.removeReview(t.reviewID)}return this.log(`Exhausted 20 skip attempts finding a hydratable card`),this._currentCard=null,endSessionTracking(),null}async submitResponse(t,c,u,d,m,g,b,S,C){let w={...d.item};return await this.services.response.processResponse(t,c,w,u,d,m,g,b,S,C)}dismissCurrentCard(t=`dismiss-success`){if(this._currentCard)if(t===`dismiss-success`)this.hydrationService.removeCard(this._currentCard.item.cardID);else if(t===`marked-failed`){let t;t=isReview(this._currentCard.item)?{cardID:this._currentCard.item.cardID,courseID:this._currentCard.item.courseID,contentSourceID:this._currentCard.item.contentSourceID,contentSourceType:this._currentCard.item.contentSourceType,status:`failed-review`,reviewID:this._currentCard.item.reviewID}:{cardID:this._currentCard.item.cardID,courseID:this._currentCard.item.courseID,contentSourceID:this._currentCard.item.contentSourceID,contentSourceType:this._currentCard.item.contentSourceType,status:`failed-new`},this.failedQ.add(t,t.cardID)}else (t===`dismiss-error`||t===`dismiss-failed`)&&this.hydrationService.removeCard(this._currentCard.item.cardID)}removeItemFromQueue(t){this.reviewQ.peek(0)?.cardID===t.cardID?this.reviewQ.dequeue(t=>t.cardID):this.newQ.peek(0)?.cardID===t.cardID?(this.newQ.dequeue(t=>t.cardID),this._wellIndicatedRemaining>0&&this._wellIndicatedRemaining--):this.failedQ.peek(0)?.cardID===t.cardID&&this.failedQ.dequeue(t=>t.cardID)}async endSession(){if(!this._sessionRecord||this._sessionRecord.length===0)return;let t=this._sessionRecord.flatMap(t=>t.records).filter(t=>t.userAnswer!==void 0);if(t.length===0)return;let c=null,u=[];for(let t of this.sources)if(t.getOrchestrationContext){try{c=await t.getOrchestrationContext(),t.getStrategyIds&&u.push(...t.getStrategyIds())}catch(t){logger.warn(`[SessionController] Failed to get orchestration context: ${t}`)}if(c)break}if(!c){logger.debug(`[SessionController] No orchestration context available, skipping outcome recording`);return}let d=new Date().toISOString(),m=new Date(this.startTime).toISOString();await recordUserOutcome(c,m,d,t,u)}},_defineProperty$2(_SessionController2,`MIN_WELL_INDICATED`,5),_defineProperty$2(_SessionController2,`WELL_INDICATED_SCORE`,.1),_SessionController2),init_TagFilteredContentSource(),init_factory()}));function useRouter(){return inject(routerKey)}function useRoute(t){return inject(routeLocationKey)}var isArray,NavigationType,NavigationDirection,NavigationFailureSymbol,NavigationFailureType,matchedRouteKey,viewDepthKey,routerKey,routeLocationKey,routerViewLocationKey,init_vue_router=__esmMin((()=>{init_vue_runtime_esm_bundler(),Array.isArray,(function(t){t.pop=`pop`,t.push=`push`})(NavigationType||(NavigationType={})),(function(t){t.back=`back`,t.forward=`forward`,t.unknown=``})(NavigationDirection||(NavigationDirection={})),Symbol(process.env.NODE_ENV===`production`?``:`navigation failure`),(function(t){t[t.aborted=4]=`aborted`,t[t.cancelled=8]=`cancelled`,t[t.duplicated=16]=`duplicated`})(NavigationFailureType||(NavigationFailureType={})),Symbol(process.env.NODE_ENV===`production`?``:`router view location matched`),Symbol(process.env.NODE_ENV===`production`?``:`router view depth`),routerKey=Symbol(process.env.NODE_ENV===`production`?``:`router`),routeLocationKey=Symbol(process.env.NODE_ENV===`production`?``:`route location`),Symbol(process.env.NODE_ENV===`production`?``:`router view location`)})),init_style=__esmMin((()=>{}));function registerRuntimeHelpers(t){Object.getOwnPropertySymbols(t).forEach(c=>{helperNameMap[c]=t[c]})}function createRoot(t,c=``){return{type:0,source:c,children:t,helpers:new Set,components:[],directives:[],hoists:[],imports:[],cached:[],temps:0,codegenNode:void 0,loc:locStub}}function createVNodeCall(t,c,u,d,m,g,b,S=!1,C=!1,w=!1,T=locStub){return t&&(S?(t.helper(OPEN_BLOCK),t.helper(getVNodeBlockHelper(t.inSSR,w))):t.helper(getVNodeHelper(t.inSSR,w)),b&&t.helper(WITH_DIRECTIVES)),{type:13,tag:c,props:u,children:d,patchFlag:m,dynamicProps:g,directives:b,isBlock:S,disableTracking:C,isComponent:w,loc:T}}function createArrayExpression(t,c=locStub){return{type:17,loc:c,elements:t}}function createObjectExpression(t,c=locStub){return{type:15,loc:c,properties:t}}function createObjectProperty(t,c){return{type:16,loc:locStub,key:isString$1(t)?createSimpleExpression(t,!0):t,value:c}}function createSimpleExpression(t,c=!1,u=locStub,d=0){return{type:4,loc:u,content:t,isStatic:c,constType:c?3:d}}function createInterpolation(t,c){return{type:5,loc:c,content:isString$1(t)?createSimpleExpression(t,!1,c):t}}function createCompoundExpression(t,c=locStub){return{type:8,loc:c,children:t}}function createCallExpression(t,c=[],u=locStub){return{type:14,loc:u,callee:t,arguments:c}}function createFunctionExpression(t,c=void 0,u=!1,d=!1,m=locStub){return{type:18,params:t,returns:c,newline:u,isSlot:d,loc:m}}function createConditionalExpression(t,c,u,d=!0){return{type:19,test:t,consequent:c,alternate:u,newline:d,loc:locStub}}function createCacheExpression(t,c,u=!1,d=!1){return{type:20,index:t,value:c,needPauseTracking:u,inVOnce:d,needArraySpread:!1,loc:locStub}}function createBlockStatement(t){return{type:21,body:t,loc:locStub}}function createTemplateLiteral(t){return{type:22,elements:t,loc:locStub}}function createIfStatement(t,c,u){return{type:23,test:t,consequent:c,alternate:u,loc:locStub}}function createAssignmentExpression(t,c){return{type:24,left:t,right:c,loc:locStub}}function createSequenceExpression(t){return{type:25,expressions:t,loc:locStub}}function createReturnStatement(t){return{type:26,returns:t,loc:locStub}}function getVNodeHelper(t,c){return t||c?CREATE_VNODE:CREATE_ELEMENT_VNODE}function getVNodeBlockHelper(t,c){return t||c?CREATE_BLOCK:CREATE_ELEMENT_BLOCK}function convertToBlock(t,{helper:c,removeHelper:u,inSSR:d}){t.isBlock||(t.isBlock=!0,u(getVNodeHelper(d,t.isComponent)),c(OPEN_BLOCK),c(getVNodeBlockHelper(d,t.isComponent)))}function isTagStartChar(t){return t>=97&&t<=122||t>=65&&t<=90}function isWhitespace(t){return t===32||t===10||t===9||t===12||t===13}function isEndOfTagSection(t){return t===47||t===62||isWhitespace(t)}function toCharCodes(t){let c=new Uint8Array(t.length);for(let u=0;u<t.length;u++)c[u]=t.charCodeAt(u);return c}function getCompatValue(t,{compatConfig:c}){let u=c&&c[t];return t===`MODE`?u||3:u}function isCompatEnabled(t,c){let u=getCompatValue(`MODE`,c),d=getCompatValue(t,c);return u===3?d===!0:d!==!1}function checkCompatEnabled(t,c,u,...d){let m=isCompatEnabled(t,c);return process.env.NODE_ENV!==`production`&&m&&warnDeprecation(t,c,u,...d),m}function warnDeprecation(t,c,u,...d){if(getCompatValue(t,c)===`suppress-warning`)return;let{message:m,link:g}=deprecationData[t],b=`(deprecation ${t}) ${typeof m==`function`?m(...d):m}${g?`
458
+ `}else if(c)this.newQ.replaceAll(Or,t=>t.cardID);else for(let t of Or)this.newQ.add(t,t.cardID);return this.log(D),O}_getItemsToHydrate(){let t=[],c=2;for(let c=0;c<Math.min(2,this.reviewQ.length);c++)t.push(this.reviewQ.peek(c));for(let c=0;c<Math.min(2,this.newQ.length);c++)t.push(this.newQ.peek(c));for(let c=0;c<Math.min(2,this.failedQ.length);c++)t.push(this.failedQ.peek(c));return t}_selectNextItemToHydrate(){let t=Math.random(),c=.1,u=.75;if(this.reviewQ.length===0&&this.failedQ.length===0&&this.newQ.length===0||this._secondsRemaining<2&&this.failedQ.length===0&&this._minCardsGuarantee<=0)return null;if(this._secondsRemaining<=0&&this._minCardsGuarantee<=0)return this.failedQ.length>0?this.failedQ.peek(0):null;if(this.newQ.dequeueCount<this.sources.length&&this.newQ.length)return this.newQ.peek(0);let d=this.estimateCleanupTime(),m=this.estimateReviewTime();return this._secondsRemaining-(d+m)>20?(c=.5,u=.9):this._secondsRemaining-d>20?(c=.05,u=.9):(c=.01,u=.1),this.failedQ.length===0&&(u=1),this.reviewQ.length===0&&(c=u),t<c&&this.newQ.length?this.newQ.peek(0):t<u&&this.reviewQ.length?this.reviewQ.peek(0):this.failedQ.length?this.failedQ.peek(0):(this.log(`No more cards available for the session!`),null)}async nextCard(t=`dismiss-success`){if(this.dismissCurrentCard(t),this._minCardsGuarantee>0&&(this._minCardsGuarantee--,this.log(`[CardGuarantee] ${this._minCardsGuarantee} guaranteed cards remaining`)),this._replanPromise&&this.newQ.length===0&&this.reviewQ.length===0&&this.failedQ.length===0&&(this.log(`nextCard: queues empty, awaiting in-flight replan before drawing`),await this._replanPromise),this.newQ.length<=1&&this._secondsRemaining>0&&!this._replanPromise){this._suppressQualityReplan=!1;let t=this.reviewQ.length+this.failedQ.length;this.log(`[AutoReplan:depletion] newQ has ${this.newQ.length} card(s) (${t} in other queues) with ${this._secondsRemaining}s remaining. Triggering background replan.`),this.requestReplan()}if(!this._suppressQualityReplan&&this._wellIndicatedRemaining<=3&&this.newQ.length>0&&!this._replanPromise&&(this.log(`[AutoReplan:quality] ${this._wellIndicatedRemaining} well-indicated cards remaining (newQ: ${this.newQ.length}). Triggering background replan.`),this.requestReplan()),this._secondsRemaining<=0&&this.failedQ.length===0&&this._minCardsGuarantee<=0)return this._currentCard=null,endSessionTracking(),null;let c=3,u=250,d=0;for(;this._secondsRemaining>0&&this.newQ.length===0&&this.reviewQ.length===0&&this.failedQ.length===0;)if(this.log(`[WedgeBreaker] All queues empty with ${this._secondsRemaining}s remaining. Running pipeline (attempt ${d+1}/3).`),await this._replanUncoalesced({label:`wedge-breaker`}),this.newQ.length===0&&this.reviewQ.length===0&&this.failedQ.length===0){if(d++,d>=3){this.log(`[WedgeBreaker] Pipeline returned no content 3 consecutive times. Giving up; session will end.`);break}await new Promise(t=>setTimeout(t,250))}else d=0;let m=20;for(let t=0;t<20;t++){let t=this._selectNextItemToHydrate();if(!t)return this._currentCard=null,endSessionTracking(),null;let c=this.hydrationService.getHydratedCard(t.cardID);if(c||(c=await this.hydrationService.waitForCard(t.cardID)),this.removeItemFromQueue(t),c){await this.hydrationService.ensureHydratedCards(),this._currentCard=c;let u=t.status===`review`||t.status===`failed-review`?`review`:t.status===`new`||t.status===`failed-new`?`new`:`failed`,d=t.status.startsWith(`failed`)?`failedQ`:t.status===`review`?`reviewQ`:`newQ`;return recordCardPresentation(t.cardID,t.courseID,this.courseNameCache.get(t.courseID),u,d),snapshotQueues(this.reviewQ.length,this.newQ.length,this.failedQ.length),c}this.log(`Skipping card ${t.cardID}: hydration failed, trying next`),isReview(t)&&this.srsService.removeReview(t.reviewID)}return this.log(`Exhausted 20 skip attempts finding a hydratable card`),this._currentCard=null,endSessionTracking(),null}async submitResponse(t,c,u,d,m,g,b,S,C){let w={...d.item};return await this.services.response.processResponse(t,c,w,u,d,m,g,b,S,C)}dismissCurrentCard(t=`dismiss-success`){if(this._currentCard)if(t===`dismiss-success`)this.hydrationService.removeCard(this._currentCard.item.cardID);else if(t===`marked-failed`){let t;t=isReview(this._currentCard.item)?{cardID:this._currentCard.item.cardID,courseID:this._currentCard.item.courseID,contentSourceID:this._currentCard.item.contentSourceID,contentSourceType:this._currentCard.item.contentSourceType,status:`failed-review`,reviewID:this._currentCard.item.reviewID}:{cardID:this._currentCard.item.cardID,courseID:this._currentCard.item.courseID,contentSourceID:this._currentCard.item.contentSourceID,contentSourceType:this._currentCard.item.contentSourceType,status:`failed-new`},this.failedQ.add(t,t.cardID)}else (t===`dismiss-error`||t===`dismiss-failed`)&&this.hydrationService.removeCard(this._currentCard.item.cardID)}removeItemFromQueue(t){this.reviewQ.peek(0)?.cardID===t.cardID?this.reviewQ.dequeue(t=>t.cardID):this.newQ.peek(0)?.cardID===t.cardID?(this.newQ.dequeue(t=>t.cardID),this._wellIndicatedRemaining>0&&this._wellIndicatedRemaining--):this.failedQ.peek(0)?.cardID===t.cardID&&this.failedQ.dequeue(t=>t.cardID)}async endSession(){if(!this._sessionRecord||this._sessionRecord.length===0)return;let t=this._sessionRecord.flatMap(t=>t.records).filter(t=>t.userAnswer!==void 0);if(t.length===0)return;let c=null,u=[];for(let t of this.sources)if(t.getOrchestrationContext){try{c=await t.getOrchestrationContext(),t.getStrategyIds&&u.push(...t.getStrategyIds())}catch(t){logger.warn(`[SessionController] Failed to get orchestration context: ${t}`)}if(c)break}if(!c){logger.debug(`[SessionController] No orchestration context available, skipping outcome recording`);return}let d=new Date().toISOString(),m=new Date(this.startTime).toISOString();await recordUserOutcome(c,m,d,t,u)}},_defineProperty$2(_SessionController2,`MIN_WELL_INDICATED`,5),_defineProperty$2(_SessionController2,`WELL_INDICATED_SCORE`,.1),_SessionController2),init_TagFilteredContentSource(),init_factory()}));function useRouter(){return inject(routerKey)}function useRoute(t){return inject(routeLocationKey)}var isArray,NavigationType,NavigationDirection,NavigationFailureSymbol,NavigationFailureType,matchedRouteKey,viewDepthKey,routerKey,routeLocationKey,routerViewLocationKey,init_vue_router=__esmMin((()=>{init_vue_runtime_esm_bundler(),Array.isArray,(function(t){t.pop=`pop`,t.push=`push`})(NavigationType||(NavigationType={})),(function(t){t.back=`back`,t.forward=`forward`,t.unknown=``})(NavigationDirection||(NavigationDirection={})),Symbol(process.env.NODE_ENV===`production`?``:`navigation failure`),(function(t){t[t.aborted=4]=`aborted`,t[t.cancelled=8]=`cancelled`,t[t.duplicated=16]=`duplicated`})(NavigationFailureType||(NavigationFailureType={})),Symbol(process.env.NODE_ENV===`production`?``:`router view location matched`),Symbol(process.env.NODE_ENV===`production`?``:`router view depth`),routerKey=Symbol(process.env.NODE_ENV===`production`?``:`router`),routeLocationKey=Symbol(process.env.NODE_ENV===`production`?``:`route location`),Symbol(process.env.NODE_ENV===`production`?``:`router view location`)})),init_style=__esmMin((()=>{}));function registerRuntimeHelpers(t){Object.getOwnPropertySymbols(t).forEach(c=>{helperNameMap[c]=t[c]})}function createRoot(t,c=``){return{type:0,source:c,children:t,helpers:new Set,components:[],directives:[],hoists:[],imports:[],cached:[],temps:0,codegenNode:void 0,loc:locStub}}function createVNodeCall(t,c,u,d,m,g,b,S=!1,C=!1,w=!1,T=locStub){return t&&(S?(t.helper(OPEN_BLOCK),t.helper(getVNodeBlockHelper(t.inSSR,w))):t.helper(getVNodeHelper(t.inSSR,w)),b&&t.helper(WITH_DIRECTIVES)),{type:13,tag:c,props:u,children:d,patchFlag:m,dynamicProps:g,directives:b,isBlock:S,disableTracking:C,isComponent:w,loc:T}}function createArrayExpression(t,c=locStub){return{type:17,loc:c,elements:t}}function createObjectExpression(t,c=locStub){return{type:15,loc:c,properties:t}}function createObjectProperty(t,c){return{type:16,loc:locStub,key:isString$1(t)?createSimpleExpression(t,!0):t,value:c}}function createSimpleExpression(t,c=!1,u=locStub,d=0){return{type:4,loc:u,content:t,isStatic:c,constType:c?3:d}}function createInterpolation(t,c){return{type:5,loc:c,content:isString$1(t)?createSimpleExpression(t,!1,c):t}}function createCompoundExpression(t,c=locStub){return{type:8,loc:c,children:t}}function createCallExpression(t,c=[],u=locStub){return{type:14,loc:u,callee:t,arguments:c}}function createFunctionExpression(t,c=void 0,u=!1,d=!1,m=locStub){return{type:18,params:t,returns:c,newline:u,isSlot:d,loc:m}}function createConditionalExpression(t,c,u,d=!0){return{type:19,test:t,consequent:c,alternate:u,newline:d,loc:locStub}}function createCacheExpression(t,c,u=!1,d=!1){return{type:20,index:t,value:c,needPauseTracking:u,inVOnce:d,needArraySpread:!1,loc:locStub}}function createBlockStatement(t){return{type:21,body:t,loc:locStub}}function createTemplateLiteral(t){return{type:22,elements:t,loc:locStub}}function createIfStatement(t,c,u){return{type:23,test:t,consequent:c,alternate:u,loc:locStub}}function createAssignmentExpression(t,c){return{type:24,left:t,right:c,loc:locStub}}function createSequenceExpression(t){return{type:25,expressions:t,loc:locStub}}function createReturnStatement(t){return{type:26,returns:t,loc:locStub}}function getVNodeHelper(t,c){return t||c?CREATE_VNODE:CREATE_ELEMENT_VNODE}function getVNodeBlockHelper(t,c){return t||c?CREATE_BLOCK:CREATE_ELEMENT_BLOCK}function convertToBlock(t,{helper:c,removeHelper:u,inSSR:d}){t.isBlock||(t.isBlock=!0,u(getVNodeHelper(d,t.isComponent)),c(OPEN_BLOCK),c(getVNodeBlockHelper(d,t.isComponent)))}function isTagStartChar(t){return t>=97&&t<=122||t>=65&&t<=90}function isWhitespace(t){return t===32||t===10||t===9||t===12||t===13}function isEndOfTagSection(t){return t===47||t===62||isWhitespace(t)}function toCharCodes(t){let c=new Uint8Array(t.length);for(let u=0;u<t.length;u++)c[u]=t.charCodeAt(u);return c}function getCompatValue(t,{compatConfig:c}){let u=c&&c[t];return t===`MODE`?u||3:u}function isCompatEnabled(t,c){let u=getCompatValue(`MODE`,c),d=getCompatValue(t,c);return u===3?d===!0:d!==!1}function checkCompatEnabled(t,c,u,...d){let m=isCompatEnabled(t,c);return process.env.NODE_ENV!==`production`&&m&&warnDeprecation(t,c,u,...d),m}function warnDeprecation(t,c,u,...d){if(getCompatValue(t,c)===`suppress-warning`)return;let{message:m,link:g}=deprecationData[t],b=`(deprecation ${t}) ${typeof m==`function`?m(...d):m}${g?`
459
459
  Details: ${g}`:``}`,S=SyntaxError(b);S.code=t,u&&(S.loc=u),c.onWarn(S)}function defaultOnError(t){throw t}function defaultOnWarn(t){process.env.NODE_ENV!==`production`&&console.warn(`[Vue warn] ${t.message}`)}function createCompilerError(t,c,u,d){let m=process.env.NODE_ENV===`production`?`https://vuejs.org/error-reference/#compiler-${t}`:(u||errorMessages)[t]+(d||``),g=SyntaxError(String(m));return g.code=t,g.loc=c,g}function walkIdentifiers(t,c,u=!1,d=[],m=Object.create(null)){}function isReferencedIdentifier(t,c,u){return!1}function isInDestructureAssignment(t,c){if(t&&(t.type===`ObjectProperty`||t.type===`ArrayPattern`)){let t=c.length;for(;t--;){let u=c[t];if(u.type===`AssignmentExpression`)return!0;if(u.type!==`ObjectProperty`&&!u.type.endsWith(`Pattern`))break}}return!1}function isInNewExpression(t){let c=t.length;for(;c--;){let u=t[c];if(u.type===`NewExpression`)return!0;if(u.type!==`MemberExpression`)break}return!1}function walkFunctionParams(t,c){for(let u of t.params)for(let t of extractIdentifiers(u))c(t)}function walkBlockDeclarations(t,c){for(let u of t.body)if(u.type===`VariableDeclaration`){if(u.declare)continue;for(let t of u.declarations)for(let u of extractIdentifiers(t.id))c(u)}else if(u.type===`FunctionDeclaration`||u.type===`ClassDeclaration`){if(u.declare||!u.id)continue;c(u.id)}else isForStatement(u)&&walkForStatement(u,!0,c)}function isForStatement(t){return t.type===`ForOfStatement`||t.type===`ForInStatement`||t.type===`ForStatement`}function walkForStatement(t,c,u){let d=t.type===`ForStatement`?t.init:t.left;if(d&&d.type===`VariableDeclaration`&&(d.kind===`var`?c:!c))for(let t of d.declarations)for(let c of extractIdentifiers(t.id))u(c)}function extractIdentifiers(t,c=[]){switch(t.type){case`Identifier`:c.push(t);break;case`MemberExpression`:let u=t;for(;u.type===`MemberExpression`;)u=u.object;c.push(u);break;case`ObjectPattern`:for(let u of t.properties)u.type===`RestElement`?extractIdentifiers(u.argument,c):extractIdentifiers(u.value,c);break;case`ArrayPattern`:t.elements.forEach(t=>{t&&extractIdentifiers(t,c)});break;case`RestElement`:extractIdentifiers(t.argument,c);break;case`AssignmentPattern`:extractIdentifiers(t.left,c);break}return c}function unwrapTSNode(t){return TS_NODE_TYPES.includes(t.type)?unwrapTSNode(t.expression):t}function isCoreComponent(t){switch(t){case`Teleport`:case`teleport`:return TELEPORT;case`Suspense`:case`suspense`:return SUSPENSE;case`KeepAlive`:case`keep-alive`:return KEEP_ALIVE;case`BaseTransition`:case`base-transition`:return BASE_TRANSITION}}function advancePositionWithClone(t,c,u=c.length){return advancePositionWithMutation({offset:t.offset,line:t.line,column:t.column},c,u)}function advancePositionWithMutation(t,c,u=c.length){let d=0,m=-1;for(let t=0;t<u;t++)c.charCodeAt(t)===10&&(d++,m=t);return t.offset+=u,t.line+=d,t.column=m===-1?t.column+u:u-m,t}function assert(t,c){if(!t)throw Error(c||`unexpected compiler condition`)}function findDir(t,c,u=!1){for(let d=0;d<t.props.length;d++){let m=t.props[d];if(m.type===7&&(u||m.exp)&&(isString$1(c)?m.name===c:c.test(m.name)))return m}}function findProp(t,c,u=!1,d=!1){for(let m=0;m<t.props.length;m++){let g=t.props[m];if(g.type===6){if(u)continue;if(g.name===c&&(g.value||d))return g}else if(g.name===`bind`&&(g.exp||d)&&isStaticArgOf(g.arg,c))return g}}function isStaticArgOf(t,c){return!!(t&&isStaticExp(t)&&t.content===c)}function hasDynamicKeyVBind(t){return t.props.some(t=>t.type===7&&t.name===`bind`&&(!t.arg||t.arg.type!==4||!t.arg.isStatic))}function isText$1(t){return t.type===5||t.type===2}function isVSlot(t){return t.type===7&&t.name===`slot`}function isTemplateNode(t){return t.type===1&&t.tagType===3}function isSlotOutlet(t){return t.type===1&&t.tagType===2}function getUnnormalizedProps(t,c=[]){if(t&&!isString$1(t)&&t.type===14){let u=t.callee;if(!isString$1(u)&&propsHelperSet.has(u))return getUnnormalizedProps(t.arguments[0],c.concat(t))}return[t,c]}function injectProp(t,c,u){let d,m=t.type===13?t.props:t.arguments[2],g=[],b;if(m&&!isString$1(m)&&m.type===14){let t=getUnnormalizedProps(m);m=t[0],g=t[1],b=g[g.length-1]}if(m==null||isString$1(m))d=createObjectExpression([c]);else if(m.type===14){let t=m.arguments[0];!isString$1(t)&&t.type===15?hasProp(c,t)||t.properties.unshift(c):m.callee===TO_HANDLERS?d=createCallExpression(u.helper(MERGE_PROPS),[createObjectExpression([c]),m]):m.arguments.unshift(createObjectExpression([c])),!d&&(d=m)}else m.type===15?(hasProp(c,m)||m.properties.unshift(c),d=m):(d=createCallExpression(u.helper(MERGE_PROPS),[createObjectExpression([c]),m]),b&&b.callee===GUARD_REACTIVE_PROPS&&(b=g[g.length-2]));t.type===13?b?b.arguments[0]=d:t.props=d:b?b.arguments[0]=d:t.arguments[2]=d}function hasProp(t,c){let u=!1;if(t.key.type===4){let d=t.key.content;u=c.properties.some(t=>t.key.type===4&&t.key.content===d)}return u}function toValidAssetId(t,c){return`_${c}_${t.replace(/[^\w]/g,(c,u)=>c===`-`?`_`:t.charCodeAt(u).toString())}`}function hasScopeRef(t,c){if(!t||Object.keys(c).length===0)return!1;switch(t.type){case 1:for(let u=0;u<t.props.length;u++){let d=t.props[u];if(d.type===7&&(hasScopeRef(d.arg,c)||hasScopeRef(d.exp,c)))return!0}return t.children.some(t=>hasScopeRef(t,c));case 11:return hasScopeRef(t.source,c)?!0:t.children.some(t=>hasScopeRef(t,c));case 9:return t.branches.some(t=>hasScopeRef(t,c));case 10:return hasScopeRef(t.condition,c)?!0:t.children.some(t=>hasScopeRef(t,c));case 4:return!t.isStatic&&isSimpleIdentifier(t.content)&&!!c[t.content];case 8:return t.children.some(t=>isObject$1(t)&&hasScopeRef(t,c));case 5:case 12:return hasScopeRef(t.content,c);case 2:case 3:case 20:return!1;default:return process.env.NODE_ENV,!1}}function getMemoedVNodeCall(t){return t.type===14&&t.callee===WITH_MEMO?t.arguments[1].returns:t}function parseForExpression(t){let c=t.loc,u=t.content,d=u.match(forAliasRE);if(!d)return;let[,m,g]=d,createAliasExpression=(t,u,d=!1)=>{let m=c.start.offset+u;return createExp(t,!1,getLoc(m,m+t.length),0,d?1:0)},b={source:createAliasExpression(g.trim(),u.indexOf(g,m.length)),value:void 0,key:void 0,index:void 0,finalized:!1},S=m.trim().replace(stripParensRE,``).trim(),C=m.indexOf(S),w=S.match(forIteratorRE);if(w){S=S.replace(forIteratorRE,``).trim();let t=w[1].trim(),c;if(t&&(c=u.indexOf(t,C+S.length),b.key=createAliasExpression(t,c,!0)),w[2]){let d=w[2].trim();d&&(b.index=createAliasExpression(d,u.indexOf(d,b.key?c+t.length:C+S.length),!0))}}return S&&(b.value=createAliasExpression(S,C,!0)),b}function getSlice(t,c){return currentInput.slice(t,c)}function endOpenTag(t){tokenizer.inSFCRoot&&(currentOpenTag.innerLoc=getLoc(t+1,t+1)),addNode(currentOpenTag);let{tag:c,ns:u}=currentOpenTag;u===0&&currentOptions.isPreTag(c)&&inPre++,currentOptions.isVoidTag(c)?onCloseTag(currentOpenTag,t):(stack.unshift(currentOpenTag),(u===1||u===2)&&(tokenizer.inXML=!0)),currentOpenTag=null}function onText(t,c,u){{let c=stack[0]&&stack[0].tag;c!==`script`&&c!==`style`&&t.includes(`&`)&&(t=currentOptions.decodeEntities(t,!1))}let d=stack[0]||currentRoot,m=d.children[d.children.length-1];m&&m.type===2?(m.content+=t,setLocEnd(m.loc,u)):d.children.push({type:2,content:t,loc:getLoc(c,u)})}function onCloseTag(t,c,u=!1){u?setLocEnd(t.loc,backTrack(c,60)):setLocEnd(t.loc,lookAhead(c,62)+1),tokenizer.inSFCRoot&&(t.children.length?t.innerLoc.end=extend$2({},t.children[t.children.length-1].loc.end):t.innerLoc.end=extend$2({},t.innerLoc.start),t.innerLoc.source=getSlice(t.innerLoc.start.offset,t.innerLoc.end.offset));let{tag:d,ns:m,children:g}=t;if(inVPre||(d===`slot`?t.tagType=2:isFragmentTemplate(t)?t.tagType=3:isComponent(t)&&(t.tagType=1)),tokenizer.inRCDATA||(t.children=condenseWhitespace(g)),m===0&&currentOptions.isIgnoreNewlineTag(d)){let t=g[0];t&&t.type===2&&(t.content=t.content.replace(/^\r?\n/,``))}m===0&&currentOptions.isPreTag(d)&&inPre--,currentVPreBoundary===t&&(inVPre=tokenizer.inVPre=!1,currentVPreBoundary=null),tokenizer.inXML&&(stack[0]?stack[0].ns:currentOptions.ns)===0&&(tokenizer.inXML=!1);{let c=t.props;if(process.env.NODE_ENV!==`production`&&isCompatEnabled(`COMPILER_V_IF_V_FOR_PRECEDENCE`,currentOptions)){let u=!1,d=!1;for(let m=0;m<c.length;m++){let g=c[m];if(g.type===7&&(g.name===`if`?u=!0:g.name===`for`&&(d=!0)),u&&d){warnDeprecation(`COMPILER_V_IF_V_FOR_PRECEDENCE`,currentOptions,t.loc);break}}}if(!tokenizer.inSFCRoot&&isCompatEnabled(`COMPILER_NATIVE_TEMPLATE`,currentOptions)&&t.tag===`template`&&!isFragmentTemplate(t)){process.env.NODE_ENV!==`production`&&warnDeprecation(`COMPILER_NATIVE_TEMPLATE`,currentOptions,t.loc);let c=stack[0]||currentRoot,u=c.children.indexOf(t);c.children.splice(u,1,...t.children)}let u=c.find(t=>t.type===6&&t.name===`inline-template`);u&&checkCompatEnabled(`COMPILER_INLINE_TEMPLATE`,currentOptions,u.loc)&&t.children.length&&(u.value={type:2,content:getSlice(t.children[0].loc.start.offset,t.children[t.children.length-1].loc.end.offset),loc:u.loc})}}function lookAhead(t,c){let u=t;for(;currentInput.charCodeAt(u)!==c&&u<currentInput.length-1;)u++;return u}function backTrack(t,c){let u=t;for(;currentInput.charCodeAt(u)!==c&&u>=0;)u--;return u}function isFragmentTemplate({tag:t,props:c}){if(t===`template`){for(let t=0;t<c.length;t++)if(c[t].type===7&&specialTemplateDir.has(c[t].name))return!0}return!1}function isComponent({tag:t,props:c}){if(currentOptions.isCustomElement(t))return!1;if(t===`component`||isUpperCase(t.charCodeAt(0))||isCoreComponent(t)||currentOptions.isBuiltInComponent&&currentOptions.isBuiltInComponent(t)||currentOptions.isNativeTag&&!currentOptions.isNativeTag(t))return!0;for(let t=0;t<c.length;t++){let u=c[t];if(u.type===6){if(u.name===`is`&&u.value&&(u.value.content.startsWith(`vue:`)||checkCompatEnabled(`COMPILER_IS_ON_ELEMENT`,currentOptions,u.loc)))return!0}else if(u.name===`bind`&&isStaticArgOf(u.arg,`is`)&&checkCompatEnabled(`COMPILER_IS_ON_ELEMENT`,currentOptions,u.loc))return!0}return!1}function isUpperCase(t){return t>64&&t<91}function condenseWhitespace(t,c){let u=currentOptions.whitespace!==`preserve`,d=!1;for(let c=0;c<t.length;c++){let m=t[c];if(m.type===2)if(inPre)m.content=m.content.replace(windowsNewlineRE,`
460
460
  `);else if(isAllWhitespace(m.content)){let g=t[c-1]&&t[c-1].type,b=t[c+1]&&t[c+1].type;!g||!b||u&&(g===3&&(b===3||b===1)||g===1&&(b===3||b===1&&hasNewlineChar(m.content)))?(d=!0,t[c]=null):m.content=` `}else u&&(m.content=condense(m.content))}return d?t.filter(Boolean):t}function isAllWhitespace(t){for(let c=0;c<t.length;c++)if(!isWhitespace(t.charCodeAt(c)))return!1;return!0}function hasNewlineChar(t){for(let c=0;c<t.length;c++){let u=t.charCodeAt(c);if(u===10||u===13)return!0}return!1}function condense(t){let c=``,u=!1;for(let d=0;d<t.length;d++)isWhitespace(t.charCodeAt(d))?u||(c+=` `,u=!0):(c+=t[d],u=!1);return c}function addNode(t){(stack[0]||currentRoot).children.push(t)}function getLoc(t,c){return{start:tokenizer.getPos(t),end:c==null?c:tokenizer.getPos(c),source:c==null?c:getSlice(t,c)}}function cloneLoc(t){return getLoc(t.start.offset,t.end.offset)}function setLocEnd(t,c){t.end=tokenizer.getPos(c),t.source=getSlice(t.start.offset,c)}function dirToAttr(t){let c={type:6,name:t.rawName,nameLoc:getLoc(t.loc.start.offset,t.loc.start.offset+t.rawName.length),value:void 0,loc:t.loc};if(t.exp){let u=t.exp.loc;u.end.offset<t.loc.end.offset&&(u.start.offset--,u.start.column--,u.end.offset++,u.end.column++),c.value={type:2,content:t.exp.content,loc:u}}return c}function createExp(t,c=!1,u,d=0,m=0){return createSimpleExpression(t,c,u,d)}function emitError(t,c,u){currentOptions.onError(createCompilerError(t,getLoc(c,c),void 0,u))}function reset(){tokenizer.reset(),currentOpenTag=null,currentProp=null,currentAttrValue=``,currentAttrStartIndex=-1,currentAttrEndIndex=-1,stack.length=0}function baseParse(t,c){if(reset(),currentInput=t,currentOptions=extend$2({},defaultParserOptions),c){let t;for(t in c)c[t]!=null&&(currentOptions[t]=c[t])}if(process.env.NODE_ENV!==`production`&&!currentOptions.decodeEntities)throw Error(`[@vue/compiler-core] decodeEntities option is required in browser builds.`);tokenizer.mode=currentOptions.parseMode===`html`?1:currentOptions.parseMode===`sfc`?2:0,tokenizer.inXML=currentOptions.ns===1||currentOptions.ns===2;let u=c&&c.delimiters;u&&(tokenizer.delimiterOpen=toCharCodes(u[0]),tokenizer.delimiterClose=toCharCodes(u[1]));let d=currentRoot=createRoot([],t);return tokenizer.parse(currentInput),d.loc=getLoc(0,t.length),d.children=condenseWhitespace(d.children),currentRoot=null,d}function cacheStatic(t,c){walk(t,void 0,c,isSingleElementRoot(t,t.children[0]))}function isSingleElementRoot(t,c){let{children:u}=t;return u.length===1&&c.type===1&&!isSlotOutlet(c)}function walk(t,c,u,d=!1,m=!1){let{children:g}=t,b=[];for(let c=0;c<g.length;c++){let S=g[c];if(S.type===1&&S.tagType===0){let t=d?0:getConstantType(S,u);if(t>0){if(t>=2){S.codegenNode.patchFlag=-1,b.push(S);continue}}else{let t=S.codegenNode;if(t.type===13){let c=t.patchFlag;if((c===void 0||c===512||c===1)&&getGeneratedPropsConstantType(S,u)>=2){let c=getNodeProps(S);c&&(t.props=u.hoist(c))}t.dynamicProps&&(t.dynamicProps=u.hoist(t.dynamicProps))}}}else if(S.type===12&&(d?0:getConstantType(S,u))>=2){b.push(S);continue}if(S.type===1){let c=S.tagType===1;c&&u.scopes.vSlot++,walk(S,t,u,!1,m),c&&u.scopes.vSlot--}else if(S.type===11)walk(S,t,u,S.children.length===1,!0);else if(S.type===9)for(let c=0;c<S.branches.length;c++)walk(S.branches[c],t,u,S.branches[c].children.length===1,m)}let S=!1;if(b.length===g.length&&t.type===1){if(t.tagType===0&&t.codegenNode&&t.codegenNode.type===13&&isArray$3(t.codegenNode.children))t.codegenNode.children=getCacheExpression(createArrayExpression(t.codegenNode.children)),S=!0;else if(t.tagType===1&&t.codegenNode&&t.codegenNode.type===13&&t.codegenNode.children&&!isArray$3(t.codegenNode.children)&&t.codegenNode.children.type===15){let c=getSlotNode(t.codegenNode,`default`);c&&(c.returns=getCacheExpression(createArrayExpression(c.returns)),S=!0)}else if(t.tagType===3&&c&&c.type===1&&c.tagType===1&&c.codegenNode&&c.codegenNode.type===13&&c.codegenNode.children&&!isArray$3(c.codegenNode.children)&&c.codegenNode.children.type===15){let u=findDir(t,`slot`,!0),d=u&&u.arg&&getSlotNode(c.codegenNode,u.arg);d&&(d.returns=getCacheExpression(createArrayExpression(d.returns)),S=!0)}}if(!S)for(let t of b)t.codegenNode=u.cache(t.codegenNode);function getCacheExpression(t){let c=u.cache(t);return m&&u.hmr&&(c.needArraySpread=!0),c}function getSlotNode(t,c){if(t.children&&!isArray$3(t.children)&&t.children.type===15){let u=t.children.properties.find(t=>t.key===c||t.key.content===c);return u&&u.value}}b.length&&u.transformHoist&&u.transformHoist(g,u,t)}function getConstantType(t,c){let{constantCache:u}=c;switch(t.type){case 1:if(t.tagType!==0)return 0;let d=u.get(t);if(d!==void 0)return d;let m=t.codegenNode;if(m.type!==13||m.isBlock&&t.tag!==`svg`&&t.tag!==`foreignObject`&&t.tag!==`math`)return 0;if(m.patchFlag===void 0){let d=3,g=getGeneratedPropsConstantType(t,c);if(g===0)return u.set(t,0),0;g<d&&(d=g);for(let m=0;m<t.children.length;m++){let g=getConstantType(t.children[m],c);if(g===0)return u.set(t,0),0;g<d&&(d=g)}if(d>1)for(let m=0;m<t.props.length;m++){let g=t.props[m];if(g.type===7&&g.name===`bind`&&g.exp){let m=getConstantType(g.exp,c);if(m===0)return u.set(t,0),0;m<d&&(d=m)}}if(m.isBlock){for(let c=0;c<t.props.length;c++)if(t.props[c].type===7)return u.set(t,0),0;c.removeHelper(OPEN_BLOCK),c.removeHelper(getVNodeBlockHelper(c.inSSR,m.isComponent)),m.isBlock=!1,c.helper(getVNodeHelper(c.inSSR,m.isComponent))}return u.set(t,d),d}else return u.set(t,0),0;case 2:case 3:return 3;case 9:case 11:case 10:return 0;case 5:case 12:return getConstantType(t.content,c);case 4:return t.constType;case 8:let g=3;for(let u=0;u<t.children.length;u++){let d=t.children[u];if(isString$1(d)||isSymbol(d))continue;let m=getConstantType(d,c);if(m===0)return 0;m<g&&(g=m)}return g;case 20:return 2;default:return process.env.NODE_ENV,0}}function getConstantTypeOfHelperCall(t,c){if(t.type===14&&!isString$1(t.callee)&&allowHoistedHelperSet.has(t.callee)){let u=t.arguments[0];if(u.type===4)return getConstantType(u,c);if(u.type===14)return getConstantTypeOfHelperCall(u,c)}return 0}function getGeneratedPropsConstantType(t,c){let u=3,d=getNodeProps(t);if(d&&d.type===15){let{properties:t}=d;for(let d=0;d<t.length;d++){let{key:m,value:g}=t[d],b=getConstantType(m,c);if(b===0)return b;b<u&&(u=b);let S;if(S=g.type===4?getConstantType(g,c):g.type===14?getConstantTypeOfHelperCall(g,c):0,S===0)return S;S<u&&(u=S)}}return u}function getNodeProps(t){let c=t.codegenNode;if(c.type===13)return c.props}function createTransformContext(t,{filename:c=``,prefixIdentifiers:u=!1,hoistStatic:d=!1,hmr:m=!1,cacheHandlers:g=!1,nodeTransforms:b=[],directiveTransforms:S={},transformHoist:C=null,isBuiltInComponent:w=NOOP,isCustomElement:T=NOOP,expressionPlugins:E=[],scopeId:D=null,slotted:O=!0,ssr:Or=!1,inSSR:kr=!1,ssrCssVars:Ar=``,bindingMetadata:jr=EMPTY_OBJ,inline:Mr=!1,isTS:Nr=!1,onError:Pr=defaultOnError,onWarn:Fr=defaultOnWarn,compatConfig:Ir}){let Lr=c.replace(/\?.*$/,``).match(/([^/\\]+)\.\w+$/),Rr={filename:c,selfName:Lr&&capitalize(camelize(Lr[1])),prefixIdentifiers:u,hoistStatic:d,hmr:m,cacheHandlers:g,nodeTransforms:b,directiveTransforms:S,transformHoist:C,isBuiltInComponent:w,isCustomElement:T,expressionPlugins:E,scopeId:D,slotted:O,ssr:Or,inSSR:kr,ssrCssVars:Ar,bindingMetadata:jr,inline:Mr,isTS:Nr,onError:Pr,onWarn:Fr,compatConfig:Ir,root:t,helpers:new Map,components:new Set,directives:new Set,hoists:[],imports:[],cached:[],constantCache:new WeakMap,temps:0,identifiers:Object.create(null),scopes:{vFor:0,vSlot:0,vPre:0,vOnce:0},parent:null,grandParent:null,currentNode:t,childIndex:0,inVOnce:!1,helper(t){let c=Rr.helpers.get(t)||0;return Rr.helpers.set(t,c+1),t},removeHelper(t){let c=Rr.helpers.get(t);if(c){let u=c-1;u?Rr.helpers.set(t,u):Rr.helpers.delete(t)}},helperString(t){return`_${helperNameMap[Rr.helper(t)]}`},replaceNode(t){if(process.env.NODE_ENV!==`production`){if(!Rr.currentNode)throw Error(`Node being replaced is already removed.`);if(!Rr.parent)throw Error(`Cannot replace root node.`)}Rr.parent.children[Rr.childIndex]=Rr.currentNode=t},removeNode(t){if(process.env.NODE_ENV!==`production`&&!Rr.parent)throw Error(`Cannot remove root node.`);let c=Rr.parent.children,u=t?c.indexOf(t):Rr.currentNode?Rr.childIndex:-1;if(process.env.NODE_ENV!==`production`&&u<0)throw Error(`node being removed is not a child of current parent`);!t||t===Rr.currentNode?(Rr.currentNode=null,Rr.onNodeRemoved()):Rr.childIndex>u&&(Rr.childIndex--,Rr.onNodeRemoved()),Rr.parent.children.splice(u,1)},onNodeRemoved:NOOP,addIdentifiers(t){},removeIdentifiers(t){},hoist(t){isString$1(t)&&(t=createSimpleExpression(t)),Rr.hoists.push(t);let c=createSimpleExpression(`_hoisted_${Rr.hoists.length}`,!1,t.loc,2);return c.hoisted=t,c},cache(t,c=!1,u=!1){let d=createCacheExpression(Rr.cached.length,t,c,u);return Rr.cached.push(d),d}};return Rr.filters=new Set,Rr}function transform(t,c){let u=createTransformContext(t,c);traverseNode(t,u),c.hoistStatic&&cacheStatic(t,u),c.ssr||createRootCodegen(t,u),t.helpers=new Set([...u.helpers.keys()]),t.components=[...u.components],t.directives=[...u.directives],t.imports=u.imports,t.hoists=u.hoists,t.temps=u.temps,t.cached=u.cached,t.transformed=!0,t.filters=[...u.filters]}function createRootCodegen(t,c){let{helper:u}=c,{children:d}=t;if(d.length===1){let u=d[0];if(isSingleElementRoot(t,u)&&u.codegenNode){let d=u.codegenNode;d.type===13&&convertToBlock(d,c),t.codegenNode=d}else t.codegenNode=u}else if(d.length>1){let m=64;process.env.NODE_ENV!==`production`&&d.filter(t=>t.type!==3).length===1&&(m|=2048),t.codegenNode=createVNodeCall(c,u(FRAGMENT),void 0,t.children,m,void 0,void 0,!0,void 0,!1)}}function traverseChildren(t,c){let u=0,nodeRemoved=()=>{u--};for(;u<t.children.length;u++){let d=t.children[u];isString$1(d)||(c.grandParent=c.parent,c.parent=t,c.childIndex=u,c.onNodeRemoved=nodeRemoved,traverseNode(d,c))}}function traverseNode(t,c){c.currentNode=t;let{nodeTransforms:u}=c,d=[];for(let m=0;m<u.length;m++){let g=u[m](t,c);if(g&&(isArray$3(g)?d.push(...g):d.push(g)),c.currentNode)t=c.currentNode;else return}switch(t.type){case 3:c.ssr||c.helper(CREATE_COMMENT);break;case 5:c.ssr||c.helper(TO_DISPLAY_STRING);break;case 9:for(let u=0;u<t.branches.length;u++)traverseNode(t.branches[u],c);break;case 10:case 11:case 1:case 0:traverseChildren(t,c);break}c.currentNode=t;let m=d.length;for(;m--;)d[m]()}function createStructuralDirectiveTransform(t,c){let u=isString$1(t)?c=>c===t:c=>t.test(c);return(t,d)=>{if(t.type===1){let{props:m}=t;if(t.tagType===3&&m.some(isVSlot))return;let g=[];for(let b=0;b<m.length;b++){let S=m[b];if(S.type===7&&u(S.name)){m.splice(b,1),b--;let u=c(t,S,d);u&&g.push(u)}}return g}}}function createCodegenContext(t,{mode:c=`function`,prefixIdentifiers:u=c===`module`,sourceMap:d=!1,filename:m=`template.vue.html`,scopeId:g=null,optimizeImports:b=!1,runtimeGlobalName:S=`Vue`,runtimeModuleName:C=`vue`,ssrRuntimeModuleName:w=`vue/server-renderer`,ssr:T=!1,isTS:E=!1,inSSR:D=!1}){let O={mode:c,prefixIdentifiers:u,sourceMap:d,filename:m,scopeId:g,optimizeImports:b,runtimeGlobalName:S,runtimeModuleName:C,ssrRuntimeModuleName:w,ssr:T,isTS:E,inSSR:D,source:t.source,code:``,column:1,line:1,offset:0,indentLevel:0,pure:!1,map:void 0,helper(t){return`_${helperNameMap[t]}`},push(t,c=-2,u){O.code+=t},indent(){newline(++O.indentLevel)},deindent(t=!1){t?--O.indentLevel:newline(--O.indentLevel)},newline(){newline(O.indentLevel)}};function newline(t){O.push(`
461
461
  `+` `.repeat(t),0)}return O}function generate(t,c={}){let u=createCodegenContext(t,c);c.onContextCreated&&c.onContextCreated(u);let{mode:d,push:m,prefixIdentifiers:g,indent:b,deindent:S,newline:C,scopeId:w,ssr:T}=u,E=Array.from(t.helpers),D=E.length>0,O=!g&&d!==`module`;if(genFunctionPreamble(t,u),m(`function ${T?`ssrRender`:`render`}(${(T?[`_ctx`,`_push`,`_parent`,`_attrs`]:[`_ctx`,`_cache`]).join(`, `)}) {`),b(),O&&(m(`with (_ctx) {`),b(),D&&(m(`const { ${E.map(aliasHelper).join(`, `)} } = _Vue