@timeback/sdk 0.1.15-beta.20260312005805 → 0.2.0

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.js CHANGED
@@ -1 +1 @@
1
- import"./chunk-ae6bkfs5.js";import{c as E,d as Q$,e as G$}from"./chunk-2bqg0gqv.js";import{g as A$,h as z$,i as P$,j as T$,k as R$,l as N$,m as _J}from"./chunk-gqjmjeta.js";import{n as i0}from"./server/adapters/native.js";import{o as d,p as B2,q as _2,r as G2,s as o2,t as h2,u as GJ}from"./chunk-x79fk5sn.js";import{A as q$,B as C$,v as YJ,w as R,x as M2,y as k$}from"./chunk-mnj8k0pt.js";import"./chunk-gqzeagk6.js";import{I as y8,J as D$,K as S2,L as u,M as QJ,N as P,O as M,P as $8,S as a0}from"./chunk-1yn5w82n.js";import{T as w8,Y as U8}from"./chunk-hhh88wcq.js";import{TimebackClient as u0}from"@timeback/core";import{getServiceUrlsForEnv as x0}from"@timeback/core";class s extends Error{statusCode;response;name="ApiError";constructor($,J,Z){super($);this.statusCode=J,this.response=Z}get minorCodes(){let $=this.response;if(!$?.imsx_CodeMinor?.imsx_codeMinorField)return[];return $.imsx_CodeMinor.imsx_codeMinorField.map((J)=>({field:J.imsx_codeMinorFieldName,value:J.imsx_codeMinorFieldValue}))}get details(){return this.response?.imsx_error_details??[]}}class t8 extends s{name="UnauthorizedError";constructor($="Unauthorized",J){super($,401,J)}}class e8 extends s{name="ForbiddenError";constructor($="Forbidden",J){super($,403,J)}}class $9 extends s{name="NotFoundError";constructor($="Not Found",J){super($,404,J)}}class J9 extends s{name="ValidationError";constructor($="Validation Error",J){super($,422,J)}}class Z9 extends s{name="InputValidationError";issues;constructor($,J){let Z={imsx_codeMajor:"failure",imsx_severity:"error",imsx_description:$,imsx_error_details:J.map((K)=>({path:K.path,message:K.message}))};super($,400,Z);this.issues=J}}function T2($,J){return new Z9($,J)}function OJ($){if(!($ instanceof Error))return!1;return"statusCode"in $&&"response"in $}var xJ="BEYOND_AI",K9="LEARNWITH_AI",H9=xJ,DJ={staging:"https://staging-beyond-timeback-api-2-idp.auth.us-east-1.amazoncognito.com/oauth2/token",production:"https://prod-beyond-timeback-api-2-idp.auth.us-east-1.amazoncognito.com/oauth2/token"},wJ={staging:"https://api.staging.alpha-1edtech.ai",production:"https://api.alpha-1edtech.ai"},UJ={staging:"https://caliper.staging.alpha-1edtech.ai",production:"https://caliper.alpha-1edtech.ai"},MJ={staging:"https://qti.alpha-1edtech.ai/api",production:"https://qti.alpha-1edtech.ai/api"},LJ={staging:"https://platform.dev.timeback.com/auth/1.0/token",production:"https://platform.timeback.com/auth/1.0/token"},jJ={staging:"https://platform.dev.timeback.com",production:"https://platform.timeback.com"},VJ={staging:"https://platform.dev.timeback.com",production:"https://platform.timeback.com"},kJ={staging:"https://platform.dev.timeback.com",production:"https://platform.timeback.com"},qJ={BEYOND_AI:{token:DJ,tokenScope:void 0,api:wJ,caliper:UJ,qti:MJ},LEARNWITH_AI:{token:LJ,tokenScope:"https://purl.imsglobal.org/spec/caliper/v1p2/scope/events.write",api:jJ,caliper:VJ,qti:kJ}},CJ={tsc:"tsc",nativePreview:"@typescript/native-preview"},r0={package:CJ.nativePreview,bin:"tsgo"},e=null,M8=!1,L8=!1;function i8($){let Z=$.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${Z}$`)}function AJ(){if(e!==null)return;if(e=[],typeof process>"u"||!process.env?.DEBUG){L8=!1;return}L8=!0;let $=process.env.DEBUG.trim();if($==="1"||$==="true"||$==="*"){M8=!0;return}let J=$.split(",").map((K)=>K.trim()).filter(Boolean);for(let K of J)if(K.startsWith("-"))e.push({regex:i8(K.slice(1)),exclude:!0});else e.push({regex:i8(K),exclude:!1});if(!e.some((K)=>!K.exclude)&&e.length>0)M8=!0}function zJ($){if(AJ(),!L8)return!0;if(M8){if($){for(let J of e)if(J.exclude&&J.regex.test($))return!1}return!0}if(!$)return!1;for(let J of e)if(J.exclude&&J.regex.test($))return!1;for(let J of e)if(!J.exclude&&J.regex.test($))return!0;return!1}function X9(){return typeof globalThis<"u"&&"window"in globalThis}function PJ(){if(X9())return"browser";if(typeof process<"u"&&process.env){if(process.env.CI||process.env.GITHUB_ACTIONS||process.env.GITLAB_CI||process.env.CIRCLECI||process.env.JENKINS_URL||process.env.BUILDKITE)return"ci"}return"terminal"}var j8;if(!X9())try{j8=(await import("./chunk-4pa6jpyx.js")).inspect}catch{}var $2={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",red:"\x1B[31m",yellow:"\x1B[33m",blue:"\x1B[34m",cyan:"\x1B[36m"};function TJ($){switch($){case"debug":return $2.blue;case"info":return $2.cyan;case"warn":return $2.yellow;case"error":return $2.red}}function RJ($){switch($){case"debug":return console.debug;case"info":return console.info;case"warn":return console.warn;case"error":return console.error}}function NJ($){if(j8)return j8($,{depth:null,colors:!0,breakLength:80,compact:!1});return JSON.stringify($,null,2)}var IJ=($)=>{let J=TJ($.level),Z=RJ($.level),K=$.level.toUpperCase().padEnd(5),H=$.timestamp.toISOString().replace(/\.\d{3}Z$/,""),W=`${$2.dim}[${H}]${$2.reset}`,F=`${J}${K}${$2.reset}`,_=$.scope?`${$2.bold}[${$.scope}]${$2.reset} `:"",O=`${W} ${F} ${_}${$.message}`;if($.context&&Object.keys($.context).length>0)Z(O,NJ($.context));else Z(O)},bJ={debug:"[DEBUG]",info:"[INFO]",warn:"[WARN]",error:"[ERROR]"};function hJ($){return Object.entries($).map(([J,Z])=>`${J}=${SJ(Z)}`).join(" ")}function SJ($){if(typeof $==="string")return $;if(typeof $==="number")return String($);if(typeof $==="boolean")return String($);if($===null)return"null";if($===void 0)return"undefined";return JSON.stringify($)}var EJ=($)=>{let J=[];if(J.push($.timestamp.toISOString()),J.push(bJ[$.level]),$.scope)J.push(`[${$.scope}]`);if(J.push($.message),$.context&&Object.keys($.context).length>0)J.push(hJ($.context));console.log(J.join(" "))},vJ=($)=>{let J={timestamp:$.timestamp.toISOString(),level:$.level,...$.scope&&{scope:$.scope},msg:$.message};if($.context&&Object.keys($.context).length>0)Object.assign(J,$.context);console.log(JSON.stringify(J))},yJ={debug:"color: gray",info:"color: #0ea5e9",warn:"color: #f59e0b",error:"color: #ef4444; font-weight: bold"},fJ={debug:"log",info:"info",warn:"warn",error:"error"},gJ=($)=>{let J=fJ[$.level],Z=yJ[$.level],H=`%c${$.scope?`[${$.scope}]`:""} ${$.message}`;if($.context&&Object.keys($.context).length>0)console[J](H,Z,$.context);else console[J](H,Z)},s8=["debug","info","warn","error"];function dJ($){switch($){case"terminal":return IJ;case"ci":return EJ;case"production":return vJ;case"browser":return gJ;case"test":return()=>{}}}function mJ(){if(typeof process<"u"&&process.env?.DEBUG)return"debug";return"info"}function lJ($,J){return s8.indexOf($)>=s8.indexOf(J)}class g2{scope;minLevel;environment;formatter;defaultContext;constructor($={}){this.scope=$.scope,this.minLevel=$.minLevel??mJ(),this.defaultContext=$.defaultContext??{},this.environment=$.environment??PJ(),this.formatter=dJ(this.environment)}child($){let J=this.scope?`${this.scope}:${$}`:$;return new g2({scope:J,minLevel:this.minLevel,environment:this.environment,defaultContext:{...this.defaultContext}})}withContext($){return new g2({scope:this.scope,minLevel:this.minLevel,environment:this.environment,defaultContext:{...this.defaultContext,...$}})}debug($,J){this.log("debug",$,J)}info($,J){this.log("info",$,J)}warn($,J){this.log("warn",$,J)}error($,J){this.log("error",$,J)}log($,J,Z){if($==="debug"&&!zJ(this.scope))return;if(!lJ($,this.minLevel))return;let K={level:$,message:J,scope:this.scope,context:Z||Object.keys(this.defaultContext).length>0?{...this.defaultContext,...Z}:void 0,timestamp:new Date};this.formatter(K)}}function W9($={}){return new g2($)}function uJ(){try{let $=typeof process>"u"?void 0:process.env.DEBUG;return $==="1"||$==="true"}catch{return!1}}var j2=W9({scope:"auth",minLevel:uJ()?"debug":"warn"});class d2{config;accessToken=null;tokenExpiry=0;pendingRequest=null;fetchFn;constructor($){this.config=$,this.fetchFn=$.fetch??globalThis.fetch.bind(globalThis)}async getToken(){if(this.accessToken&&Date.now()<this.tokenExpiry)return j2.debug("Using cached token"),this.accessToken;if(this.pendingRequest)return j2.debug("Waiting for in-flight token request"),this.pendingRequest;this.pendingRequest=this.fetchToken();try{return await this.pendingRequest}finally{this.pendingRequest=null}}async fetchToken(){j2.debug("Fetching new access token...");let{clientId:$,clientSecret:J}=this.config.credentials,Z=btoa(`${$}:${J}`),K=performance.now(),H=await this.fetchFn(this.config.tokenUrl,{method:"POST",headers:{Authorization:`Basic ${Z}`,"Content-Type":"application/x-www-form-urlencoded"},body:this.config.scope?`grant_type=client_credentials&scope=${encodeURIComponent(this.config.scope)}`:"grant_type=client_credentials"}),W=Math.round(performance.now()-K);if(!H.ok)throw j2.error(`Token request failed: ${H.status} ${H.statusText}`),Error(`Failed to obtain access token: ${H.status} ${H.statusText}`);let F=await H.json();return this.accessToken=F.access_token,this.tokenExpiry=Date.now()+(F.expires_in-60)*1000,j2.debug(`Token acquired (${W}ms, expires in ${F.expires_in}s)`),this.accessToken}invalidate(){j2.debug("Token invalidated"),this.accessToken=null,this.tokenExpiry=0}}var m2={caliper:{send:"/caliper/event",validate:"/caliper/event/validate",list:"/caliper/events",get:"/caliper/events/{id}",jobStatus:"/jobs/{id}/status"},oneroster:{rostering:"/ims/oneroster/rostering/v1p2",gradebook:"/ims/oneroster/gradebook/v1p2",resources:"/ims/oneroster/resources/v1p2"},edubridge:{base:"/edubridge"},powerpath:{base:"/powerpath"},clr:{credentials:"/ims/clr/v2p0/credentials",discovery:"/ims/clr/v2p0/discovery"},case:{base:"/ims/case/v1p1"},webhooks:{webhookList:"/webhooks/",webhookGet:"/webhooks/{id}",webhookCreate:"/webhooks/",webhookUpdate:"/webhooks/{id}",webhookDelete:"/webhooks/{id}",webhookActivate:"/webhooks/{id}/activate",webhookDeactivate:"/webhooks/{id}/deactivate",webhookFilterList:"/webhook-filters/",webhookFilterGet:"/webhook-filters/{id}",webhookFilterCreate:"/webhook-filters/",webhookFilterUpdate:"/webhook-filters/{id}",webhookFilterDelete:"/webhook-filters/{id}",webhookFiltersByWebhook:"/webhook-filters/webhook/{webhookId}"}},cJ={caliper:{send:"/caliper/v1p2",validate:null,list:null,get:null,jobStatus:null},oneroster:{rostering:"/rostering/1.0",gradebook:"/gradebook/1.0",resources:"/resources/1.0"},webhooks:null,edubridge:null,powerpath:null,clr:null,case:{base:"/case/1.1"}},Y9={BEYOND_AI:m2,LEARNWITH_AI:cJ};function pJ($){return"env"in $&&!("baseUrl"in $)&&!("services"in $)}function aJ($){return"baseUrl"in $&&!("services"in $)}function iJ($){return"services"in $}function o8($,J){let Z=$?Y9[$]??m2:m2;return{caliper:J?.caliper??Z.caliper,oneroster:J?.oneroster??Z.oneroster,webhooks:J?.webhooks??Z.webhooks,edubridge:J?.edubridge??Z.edubridge,powerpath:J?.powerpath??Z.powerpath,clr:J?.clr??Z.clr,case:J?.case??Z.case}}class R2{platform;env;auth;timeout;endpoints;authUrl;tokenScope;pathProfiles;tokenManagers=new Map;constructor($){if(this.timeout=$.timeout??30000,pJ($)){this.auth=$.auth;let J=$.platform??H9,Z=$.env;this.platform=J,this.env=Z;let K=qJ[J];if(!K)throw Error(`Unknown platform: ${J}`);this.authUrl=K.token[Z],this.tokenScope=K.tokenScope??void 0,this.pathProfiles=Y9[J]??m2,this.endpoints={oneroster:{baseUrl:K.api[Z],authUrl:this.authUrl},edubridge:{baseUrl:K.api[Z],authUrl:this.authUrl},powerpath:{baseUrl:K.api[Z],authUrl:this.authUrl},clr:{baseUrl:K.api[Z],authUrl:this.authUrl},case:{baseUrl:K.api[Z],authUrl:this.authUrl},caliper:{baseUrl:K.caliper[Z],authUrl:this.authUrl},webhooks:{baseUrl:K.caliper[Z],authUrl:this.authUrl},qti:{baseUrl:K.qti[Z],authUrl:this.authUrl}}}else if(aJ($))this.auth=$.auth,this.authUrl=$.authUrl,this.pathProfiles=o8($.pathProfile,$.paths),this.endpoints={oneroster:{baseUrl:$.baseUrl,authUrl:this.authUrl},edubridge:{baseUrl:$.baseUrl,authUrl:this.authUrl},powerpath:{baseUrl:$.baseUrl,authUrl:this.authUrl},clr:{baseUrl:$.baseUrl,authUrl:this.authUrl},case:{baseUrl:$.baseUrl,authUrl:this.authUrl},caliper:{baseUrl:$.baseUrl,authUrl:this.authUrl},webhooks:{baseUrl:$.baseUrl,authUrl:this.authUrl},qti:{baseUrl:$.baseUrl,authUrl:this.authUrl}};else if(iJ($)){this.auth=$.auth,this.authUrl=$.authUrl,this.pathProfiles=o8($.pathProfile,$.paths),this.endpoints={};for(let[J,Z]of Object.entries($.services))if(Z)this.endpoints[J]={baseUrl:Z,authUrl:this.authUrl}}else throw Error("Invalid provider configuration");for(let J of Object.keys(this.pathProfiles))if(this.pathProfiles[J]===null)delete this.endpoints[J]}getEndpoint($){let J=this.endpoints[$];if(!J){let Z=$;if(Z in this.pathProfiles&&this.pathProfiles[Z]===null)throw Error(`Service "${$}" is not supported on ${this.platform??"this"} platform.`);throw Error(`Service "${$}" is not configured in this provider`)}return J}hasService($){return $ in this.endpoints}getAvailableServices(){return Object.keys(this.endpoints)}getTokenUrl(){return this.authUrl}getEndpointWithPaths($){let J=this.getEndpoint($),Z=this.getServicePaths($);return{...J,paths:Z}}getPaths(){return this.pathProfiles}getServicePaths($){let J=this.pathProfiles[$];if(!J)throw Error(`Service "${$}" is not supported on ${this.platform??"this"} platform.`);return J}hasServiceSupport($){return this.pathProfiles[$]!==null}getTokenProvider($){let J=this.getEndpoint($),{authUrl:Z}=J;if(!Z)return;if(!this.auth)throw Error(`Service "${$}" requires authentication but no credentials were provided`);let K=this.tokenManagers.get(Z);if(!K)K=new d2({tokenUrl:Z,credentials:{clientId:this.auth.clientId,clientSecret:this.auth.clientSecret},scope:this.tokenScope}),this.tokenManagers.set(Z,K);return K}async checkAuth(){if(!this.authUrl||!this.auth)throw Error("No auth configured on this provider");let $=Date.now(),J=this.tokenManagers.get(this.authUrl);if(!J)J=new d2({tokenUrl:this.authUrl,credentials:{clientId:this.auth.clientId,clientSecret:this.auth.clientSecret},scope:this.tokenScope}),this.tokenManagers.set(this.authUrl,J);try{return await J.getToken(),{ok:!0,latencyMs:Date.now()-$,checks:{tokenAcquisition:!0}}}catch(Z){return{ok:!1,latencyMs:Date.now()-$,error:Z instanceof Error?Z.message:String(Z),checks:{tokenAcquisition:!1}}}}invalidateTokens(){for(let $ of this.tokenManagers.values())$.invalidate?.();this.tokenManagers.clear()}}function b($){try{if(typeof process>"u")return;if(typeof $==="string")return process.env[$];for(let J of $){let Z=process.env[J];if(Z!==void 0)return Z}return}catch{return}}function F2(){let $=b("DEBUG");return $==="1"||$==="true"}function sJ(){return Math.random().toString(16).slice(2,10)}function V8($){return W9({scope:$,minLevel:F2()?"debug":"warn"})}var l2={defaultPlatform:H9,templates:{BEYOND_AI:{staging:{platform:"BEYOND_AI",env:"staging"},production:{platform:"BEYOND_AI",env:"production"}},LEARNWITH_AI:{staging:{platform:"LEARNWITH_AI",env:"staging"},production:{platform:"LEARNWITH_AI",env:"production"}}}};function oJ($){if(typeof $==="string")return $;if($.length===0)throw Error(`Missing env var key: ${$}`);return $[0]}function O2($){return oJ($)}function Q9($){if($!=="staging"&&$!=="production")throw Error(`Invalid env "${$}": must be "staging" or "production"`);return $}function G9($,J){let Z=$?.clientId??b(J.clientId),K=$?.clientSecret??b(J.clientSecret);if(!Z)throw Error(`Missing clientId: provide in config or set ${O2(J.clientId)}`);if(!K)throw Error(`Missing clientSecret: provide in config or set ${O2(J.clientSecret)}`);return{clientId:Z,clientSecret:K}}function nJ($,J,Z){if(!Z)return;return G9($,J)}function rJ($){let J=b($.baseUrl),Z=b($.authUrl),K=b($.clientId),H=b($.clientSecret);if(J===void 0&&K===void 0)return`Missing env: provide in config or set ${O2($.env??$.baseUrl)}`;let W=[];if(J===void 0)W.push(O2($.env??$.baseUrl));if(J!==void 0&&Z===void 0)W.push(O2($.authUrl));if(K===void 0)W.push(O2($.clientId));if(H===void 0)W.push(O2($.clientSecret));return`Missing environment variables: ${W.join(", ")}`}var tJ={name:"transport",matches($){return"transport"in $&&!!$.transport},resolve($){return{mode:"transport",transport:$.transport}}},eJ={name:"provider",matches($){return"provider"in $&&!!$.provider},resolve($){return{mode:"provider",provider:$.provider}}},$Z={name:"env-config",matches($){return"env"in $},resolve($,J,Z){let K=$,H=Q9(K.env),W=G9(K.auth,J),F=K.platform??Z.defaultPlatform,_=Z.templates[F];if(!_){let w=Object.keys(Z.templates).join(", ");throw Error(`Unknown platform "${F}": available platforms are ${w}`)}let O=_[H];if(!O){let w=Object.keys(_).join(", ");throw Error(`Unknown env "${H}" for platform "${F}": available environments are ${w}`)}return{mode:"provider",provider:new R2({platform:O.platform,env:O.env,auth:W,timeout:K.timeout})}}},JZ={name:"explicit-config",matches($){return"baseUrl"in $},resolve($,J){let Z=$,K=Z.authUrl??Z.auth?.authUrl,H=!!K,W=nJ(Z.auth,J,H);return{mode:"provider",provider:new R2({baseUrl:Z.baseUrl,authUrl:K,auth:W,timeout:Z.timeout,pathProfile:Z.pathProfile,paths:Z.paths})}}},ZZ={name:"env-fallback-platform",matches($,J){if(Object.keys($).length>0)return!1;let Z=J.env?b(J.env):void 0,K=b(J.clientId),H=b(J.clientSecret);return Z!==void 0&&K!==void 0&&H!==void 0},resolve($,J,Z){let K=Q9(b(J.env)),H=b(J.clientId),W=b(J.clientSecret),F=Z.defaultPlatform,_=Z.templates[F]?.[K];if(!_)throw Error(`Unknown env "${K}" for platform "${F}"`);return{mode:"provider",provider:new R2({platform:_.platform,env:_.env,auth:{clientId:H,clientSecret:W}})}}},KZ={name:"env-fallback-explicit",matches($,J){if(Object.keys($).length>0)return!1;let Z=b(J.baseUrl),K=b(J.authUrl),H=b(J.clientId),W=b(J.clientSecret);return Z!==void 0&&K!==void 0&&H!==void 0&&W!==void 0},resolve($,J){let Z=b(J.baseUrl),K=b(J.authUrl),H=b(J.clientId),W=b(J.clientSecret);return{mode:"provider",provider:new R2({baseUrl:Z,authUrl:K,auth:{clientId:H,clientSecret:W}})}}},HZ={name:"token-provider",matches($){return"tokenProvider"in $},resolve(){throw Error("TokenProvider mode is not supported with provider pattern. Use { provider: TimebackProvider } or { env, auth } instead.")}},XZ=[tJ,eJ,$Z,HZ,JZ,ZZ,KZ];function B9($,J,Z=l2){for(let K of XZ)if(K.matches($,J))return K.resolve($,J,Z);throw Error(rJ(J))}var D8=3,WZ=[429,503],n8=1000;class k8{config;log;constructor($){let{config:J,logger:Z}=$,K=J.fetch??globalThis.fetch.bind(globalThis),H;if("tokenProvider"in J&&J.tokenProvider)H=J.tokenProvider;else if("auth"in J&&J.auth)H=new d2({tokenUrl:J.auth.authUrl,credentials:{clientId:J.auth.clientId,clientSecret:J.auth.clientSecret},fetch:K});let W=J.baseUrl.endsWith("/")?J.baseUrl:`${J.baseUrl}/`;this.config={baseUrl:W,timeout:J.timeout??30000,fetch:K,tokenProvider:H},this.log=Z.child("http")}get baseUrl(){return this.config.baseUrl}async request($,J={}){let Z=await this.requestRaw($,J);return this.handleResponse(Z)}async exists($,J={}){try{return await this.requestRaw($,J),!0}catch(Z){if(OJ(Z)&&Z.statusCode===404)return!1;throw Z}}async requestRaw($,J={}){let{method:Z="GET",params:K,body:H,headers:W={}}=J,F=this.buildUrl($,K),_=J.requestId??sJ(),w=Date.now()+this.config.timeout;for(let j=0;j<D8;j++){let A=w-Date.now();if(A<=0)throw this.log.error("Request timeout before attempt",F2()?{requestId:_,path:$}:{path:$}),new s("Request timeout",408);let C=await this.getAccessToken(),q=j===D8-1,z=performance.now();this.log.debug(`→ ${Z} ${F}`,{requestId:_,attempt:j>0?j+1:void 0});let N={"Content-Type":"application/json",Accept:"application/json","X-Request-ID":_,...W};if(C)N.Authorization=`Bearer ${C}`;let I=await this.config.fetch(F,{method:Z,headers:N,body:H?JSON.stringify(H):void 0,signal:AbortSignal.timeout(Math.min(A,this.config.timeout))}),r=Math.round(performance.now()-z);if(this.log.debug(`← ${I.status} ${I.statusText} (${r}ms)`,{requestId:_}),WZ.includes(I.status)&&!q){let v2=I.headers.get("Retry-After"),p=this.parseRetryAfter(v2,j),a8=w-Date.now();if(p>=a8)throw this.log.error("Request timeout during retry backoff",F2()?{requestId:_,path:$}:{path:$}),new s("Request timeout",408);this.log.warn(`Retrying in ${p}ms (attempt ${j+1}/${D8})`,{...F2()&&{requestId:_},status:I.status}),await this.sleep(p);continue}if(!I.ok)return this.handleErrorResponse(I,_);return I}throw this.log.error("Max retries exceeded",F2()?{requestId:_,path:$}:{path:$}),new s("Max retries exceeded")}getAccessToken(){if(!this.config.tokenProvider)return Promise.resolve(void 0);return this.config.tokenProvider.getToken()}buildUrl($,J){if(/^[a-z][a-z0-9+.-]*:/i.test($))throw Error(`Absolute URLs are not allowed in path: ${$}. Use relative paths only.`);let Z=$.startsWith("/")?$.slice(1):$,K=new URL(Z,this.config.baseUrl);if(J){for(let[H,W]of Object.entries(J))if(W!==void 0)K.searchParams.set(H,String(W))}return K.toString()}async handleResponse($){if(!$.ok)await this.handleErrorResponse($);if($.status===204)return;if($.headers.get("content-length")==="0")return;return this.parseJsonResponse($)}async parseJsonResponse($){let J=await $.text();if(!J||J.trim()==="")return;try{return JSON.parse(J)}catch(Z){let K=J.length>200?J.slice(0,200)+"...":J,H=Z instanceof Error?Z.message:String(Z),W=$.url||"unknown";throw this.log.error("Failed to parse JSON response",{url:W,status:$.status,contentType:$.headers.get("content-type"),bodyPreview:K,error:H}),new s(`Invalid JSON response from ${W}`,$.status,{parseError:H,body:K})}}async handleErrorResponse($,J){let Z,K=await $.text().catch(()=>"");if(K)try{Z=JSON.parse(K)}catch(W){let F=W instanceof Error?W.message:"Unknown parse error";Z={rawBody:K.slice(0,500),parseError:F},this.log.warn("Failed to parse error response as JSON",{...F2()&&{requestId:J},url:$.url,status:$.status,parseError:F,bodyPreview:K.slice(0,200)})}let H=this.extractErrorMessage(Z,$.statusText);if($.status!==404)this.log.error(`Request failed: ${$.status} ${H}`,F2()?{requestId:J}:void 0);switch($.status){case 401:throw this.config.tokenProvider?.invalidate?.(),new t8(H,Z);case 403:throw new e8(H,Z);case 404:throw new $9(H,Z);case 422:throw new J9(H,Z);default:throw new s(H,$.status,Z)}}extractErrorMessage($,J){if(typeof $==="object"&&$!==null){let Z=$;if(typeof Z.message==="string")return Z.message;if(typeof Z.error==="string")return Z.error;if(typeof Z.imsx_description==="string")return Z.imsx_description}return J}sleep($){return new Promise((J)=>{setTimeout(J,$)})}parseRetryAfter($,J){if(!$)return n8*Math.pow(2,J);let Z=parseInt($,10);if(!isNaN(Z))return Z*1000;let K=Date.parse($);if(!isNaN(K)){let H=K-Date.now();return Math.max(0,H)}return n8*Math.pow(2,J)}}function YZ($){if($ instanceof Date)return $.toISOString();if(typeof $==="boolean")return $?"true":"false";if(typeof $==="number")return String($);return $.replaceAll("'","''")}function t($){let J=YZ($);return typeof $==="string"||$ instanceof Date?`'${J}'`:J}function QZ($,J){if(typeof J==="string"||typeof J==="number"||typeof J==="boolean"||J instanceof Date)return[`${$}=${t(J)}`];if(typeof J==="object"&&J!==null){let Z=J,K=[];if(Z.ne!==void 0)K.push(`${$}!=${t(Z.ne)}`);if(Z.gt!==void 0)K.push(`${$}>${t(Z.gt)}`);if(Z.gte!==void 0)K.push(`${$}>=${t(Z.gte)}`);if(Z.lt!==void 0)K.push(`${$}<${t(Z.lt)}`);if(Z.lte!==void 0)K.push(`${$}<=${t(Z.lte)}`);if(Z.contains!==void 0)K.push(`${$}~${t(Z.contains)}`);if(Z.in!==void 0&&Z.in.length>0){let H=Z.in.map((F)=>`${$}=${t(F)}`),W=H.join(" OR ");K.push(H.length>1?`(${W})`:W)}if(Z.notIn!==void 0&&Z.notIn.length>0){let H=Z.notIn.map((W)=>`${$}!=${t(W)}`);K.push(H.join(" AND "))}return K}return[]}function GZ($){return"OR"in $&&Array.isArray($.OR)}function _9($){if(GZ($)){let Z=$.OR.map((K)=>_9(K)).filter((K)=>K!==void 0);return Z.length>0?Z.join(" OR "):void 0}let J=[];for(let[Z,K]of Object.entries($))if(K!==void 0)J.push(...QZ(Z,K));return J.length>0?J.join(" AND "):void 0}var r8=100,BZ=1e4;class q8{fetcher;path;params;max;unwrapKey;log;transform;paginationStyle;constructor($){this.fetcher=$.fetcher,this.path=$.path,this.params=$.params??{},this.max=$.max,this.unwrapKey=$.unwrapKey,this.log=$.logger?.child("pagination")??V8("pagination"),this.transform=$.transform,this.paginationStyle=$.paginationStyle??"offset"}buildRequestParams($,J){let{where:Z,fields:K,offset:H,limit:W,...F}=this.params,_={...F,filter:Z?_9(Z):void 0,fields:K?.join(","),limit:$};if(this.paginationStyle==="page"){let O=Math.floor(J/$)+1;return{..._,page:O}}return{..._,offset:J}}extractItems($,J){let Z;if(this.unwrapKey)Z=$[this.unwrapKey]??[];else Z=$;return this.validateItems(Z,J)}validateItems($,J){if($===null||$===void 0)return this.log.warn(`Page ${J}: response data is ${$}, treating as empty`),[];if(!Array.isArray($))throw Error(`Expected array for page ${J}, got ${typeof $}. `+(this.unwrapKey?`Check unwrapKey '${this.unwrapKey}' is correct.`:""));return $}hasMorePages($,J,Z,K){if(J===0)return!1;let H=$.hasMore,W=$.total!==void 0&&Z+J<$.total;return H||W||J===K&&$.total===void 0}async*[Symbol.asyncIterator](){let $=this.params.offset??0,J=this.params.limit??r8,Z=!0,K=1,H=0;while(Z){this.log.debug(`Fetching page ${K} (offset: ${$}, limit: ${J})`);let W=await this.fetcher(this.path,{params:this.buildRequestParams(J,$)}),F=this.extractItems(W.data,K);this.log.debug(`Page ${K}: ${F.length} items`);for(let _ of F)if(yield this.transform?this.transform(_):_,H++,this.max!==void 0&&H>=this.max){this.log.debug(`Pagination complete: reached max of ${this.max} items`);return}Z=this.hasMorePages(W,F.length,$,J),$+=F.length,K++}this.log.debug(`Pagination complete: ${H} total items`)}async toArray($={}){let J=$.maxItems??BZ,Z=[];for await(let K of this){if(Z.length>=J)throw Error(`toArray() exceeded maxItems limit of ${J}. Use 'for await...of' to stream large datasets, or increase maxItems.`);Z.push(K)}return Z}async firstPage(){let $=this.params.limit??r8,J=this.params.offset??0,Z=await this.fetcher(this.path,{params:this.buildRequestParams($,J)}),K=this.extractItems(Z.data,1),H=this.transform?K.map(this.transform):K,W=this.hasMorePages(Z,H.length,J,$);return this.log.debug(`First page: ${H.length} items, total: ${Z.total}, hasMore: ${W}`),{data:H,hasMore:W,total:Z.total,nextOffset:W?J+H.length:void 0}}}function f2($,J){return{path:$,message:J}}function o($,J,Z){let K=$.safeParse(J);if(K.success)return K.data;let H=K.error.issues.map((W)=>({path:W.path.join(".")||"(root)",message:W.message}));throw T2(`Invalid ${Z} data`,H)}function u2($,J){if(typeof $!=="string"||$.trim()==="")throw T2(`Invalid ${J}`,[f2(J,"Must be a non-empty string")])}function C8($){if(!$)return;let J=[];if($.limit!==void 0){if(!Number.isInteger($.limit)||$.limit<=0)J.push(f2("limit","Must be a positive integer"))}if($.offset!==void 0){if(!Number.isInteger($.offset)||$.offset<0)J.push(f2("offset","Must be a non-negative integer"))}if($.max!==void 0){if(!Number.isInteger($.max)||$.max<=0)J.push(f2("max","Must be a positive integer"))}if(J.length>0)throw T2("Invalid list parameters",J)}var F9={baseUrl:["TIMEBACK_API_BASE_URL","TIMEBACK_BASE_URL","CALIPER_BASE_URL"],authUrl:["TIMEBACK_API_AUTH_URL","TIMEBACK_AUTH_URL","CALIPER_TOKEN_URL"],clientId:["TIMEBACK_API_CLIENT_ID","TIMEBACK_CLIENT_ID","CALIPER_CLIENT_ID"],clientSecret:["TIMEBACK_API_CLIENT_SECRET","TIMEBACK_CLIENT_SECRET","CALIPER_CLIENT_SECRET"]},V2="http://purl.imsglobal.org/ctx/caliper/v1p2",O9="QUESTION_RESULT";import{z as L}from"zod/v4";import{z as Y}from"zod/v4";import{z as J2}from"zod/v4";import{z as U}from"zod/v4";import{z as x}from"zod/v4";import{z as V}from"zod/v4";import{z as D}from"zod/v4";import{z as f}from"zod/v4";import{z as G}from"zod/v4";import{z as B}from"zod/v4";import{z as Q}from"zod/v4";var S=V8("caliper");class j9 extends k8{paths;constructor($){super({config:$,logger:S});this.paths=$.paths}async requestPaginated($,J={}){let Z=await this.request($,J),{events:K,pagination:H}=Z,F=(J.params?.offset??0)+K.length<H.total;return{data:K,hasMore:F,total:H.total}}}class V9 extends q8{constructor($,J,Z={}){C8(Z);let{max:K,...H}=Z;super({fetcher:(W,F)=>$.requestPaginated(W,F),path:J,params:H,max:K,logger:S})}}function A8($){let J=$.id??`urn:uuid:${crypto.randomUUID()}`,Z=$.metricsId??`urn:uuid:${crypto.randomUUID()}`;return{"@context":V2,id:J,type:"ActivityEvent",action:"Completed",actor:$.actor,object:$.object,eventTime:$.eventTime??new Date().toISOString(),profile:"TimebackProfile",generated:{id:Z,type:"TimebackActivityMetricsCollection",items:$.metrics,...$.attempt===void 0?{}:{attempt:$.attempt},...$.generatedExtensions?{extensions:$.generatedExtensions}:{}},extensions:$.extensions,...$.edApp===void 0?{}:{edApp:$.edApp},...$.session===void 0?{}:{session:$.session}}}function z8($){let J=$.id??`urn:uuid:${crypto.randomUUID()}`,Z=$.metricsId??`urn:uuid:${crypto.randomUUID()}`;return{"@context":V2,id:J,type:"TimeSpentEvent",action:"SpentTime",actor:$.actor,object:$.object,eventTime:$.eventTime??new Date().toISOString(),profile:"TimebackProfile",generated:{id:Z,type:"TimebackTimeSpentMetricsCollection",items:$.metrics},extensions:$.extensions,...$.edApp===void 0?{}:{edApp:$.edApp},...$.session===void 0?{}:{session:$.session}}}function _Z($){return{"@context":V2,id:$.id??`urn:uuid:${crypto.randomUUID()}`,type:"AssessmentItemEvent",action:"Started",profile:"AssessmentProfile",actor:$.actor,object:{...$.object,type:"AssessmentItem"},eventTime:$.eventTime??new Date().toISOString(),edApp:$.edApp,...$.session===void 0?{}:{session:$.session},...$.extensions===void 0?{}:{extensions:$.extensions}}}function FZ($){return{"@context":V2,id:$.id??`urn:uuid:${crypto.randomUUID()}`,type:"AssessmentItemEvent",action:"Completed",profile:"AssessmentProfile",actor:$.actor,object:{...$.object,type:"AssessmentItem"},eventTime:$.eventTime??new Date().toISOString(),edApp:$.edApp,...$.generated===void 0?{}:{generated:{...$.generated,type:"Response"}},...$.session===void 0?{}:{session:$.session},...$.extensions===void 0?{}:{extensions:$.extensions}}}function OZ($){let{id:J,...Z}=$.generated;return{"@context":V2,id:$.id??`urn:uuid:${crypto.randomUUID()}`,type:"GradeEvent",action:"Graded",profile:"GradingProfile",actor:$.actor,object:$.object,eventTime:$.eventTime??new Date().toISOString(),edApp:$.edApp,generated:{...Z,id:J??`urn:uuid:${crypto.randomUUID()}`,type:"Score",scoreType:O9},...$.session===void 0?{}:{session:$.session},...$.extensions===void 0?{}:{extensions:$.extensions}}}var xZ="http://purl.imsglobal.org/ctx/caliper/v1p2",DZ="urn:tag:auto-attach",X2={PERSON:"Person",ASSIGNABLE_DIGITAL_RESOURCE:"AssignableDigitalResource",ACTIVITY_METRIC:"ActivityMetric",TIME_SPENT_METRIC:"TimeSpentMetric",ACTIVITY_METRICS_COLLECTION:"ActivityMetricsCollection",TIME_SPENT_METRICS_COLLECTION:"TimeSpentMetricsCollection",COURSE_OFFERING:"CourseOffering",SOFTWARE_APPLICATION:"SoftwareApplication"},wZ=new Set(["ActivityEvent","TimeSpentEvent","AssignableEvent","ViewEvent"]);class k9{transformEnvelope($){let{data:J}=$;if(!Array.isArray(J))return $;let Z=J.map((K)=>x2(K)?UZ(K):K);return{...$,data:Z}}}function UZ($){let J={...$};if(!("@context"in J))J["@context"]=xZ;if(J.profile==="TimebackProfile")J.profile="AggregationProfile";if(x2(J.actor)&&J.actor.type==="TimebackUser")J.actor=MZ(J.actor);if(x2(J.object))J.object=LZ(J.object,J.type);if(x2(J.generated)){let Z=J.type;if(Z==="ActivityEvent")J.generated=jZ(J.generated);else if(Z==="TimeSpentEvent")J.generated=VZ(J.generated)}if(!J.session)J.session=DZ;return J}function MZ($){return{type:X2.PERSON,id:$.id}}function LZ($,J){if(!($.type==="TimebackActivityContext"&&J!==void 0&&wZ.has(J)))return{...$};let K={type:X2.ASSIGNABLE_DIGITAL_RESOURCE,id:$.id};if($.name)K.name=$.name;if(x2($.course)){let H={type:X2.COURSE_OFFERING,id:$.course.id};if($.course.name)H.name=$.course.name;K.isPartOf=H}if(x2($.app))K.extensions={app:{name:$.app.name,type:$.app.type??X2.SOFTWARE_APPLICATION}};return K}function q9($,J,Z,K){let W={id:typeof $?.id==="string"?$.id:`urn:uuid:${crypto.randomUUID()}`,type:J};if(Array.isArray($.items))W.items=$.items.map((F)=>{if(!x2(F))return F;let _=typeof F.type==="string"?F.type:"",O=_?_[0].toUpperCase()+_.slice(1):K;return{id:`urn:uuid:${crypto.randomUUID()}`,type:Z,metricType:O,metricValue:F.value}});for(let[F,_]of Object.entries($))if(F!=="id"&&F!=="type"&&F!=="items")W[F]=_;return W}function jZ($){return q9($,X2.ACTIVITY_METRICS_COLLECTION,X2.ACTIVITY_METRIC,"")}function VZ($){return q9($,X2.TIME_SPENT_METRICS_COLLECTION,X2.TIME_SPENT_METRIC,"Active")}function x2($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function kZ($,J=l2){return B9($,F9,J)}var qZ=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/,v=L.string().min(1).regex(qZ,"must be a valid ISO 8601 datetime"),q2=L.string().min(1).regex(/^\d{4}-\d{2}-\d{2}$/,"must be a valid ISO 8601 date (YYYY-MM-DD)"),X=L.string().trim().min(1),Z2=L.enum(["Reading","Language","Vocabulary","Social Studies","Writing","Science","FastMath","Math","None","Other"]).meta({id:"TimebackSubject",description:"Subject area"}),n=L.union([L.literal(-1),L.literal(0),L.literal(1),L.literal(2),L.literal(3),L.literal(4),L.literal(5),L.literal(6),L.literal(7),L.literal(8),L.literal(9),L.literal(10),L.literal(11),L.literal(12),L.literal(13)]).meta({id:"TimebackGrade",description:"Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"}),CZ=L.enum(["exempt","fully graded","not submitted","partially graded","submitted"]),AZ=L.enum(["department","school","district","local","state","national"]),C9=L.enum(["administrator","aide","guardian","parent","proctor","relative","student","teacher"]),zZ=L.enum(["administrator","proctor","student","teacher"]),PZ=L.enum(["qti","text","audio","video","interactive","visual","course-material","assessment-bank"]),TZ=L.enum(["qti-test","qti-question","qti-stimulus","qti-test-bank"]),RZ=L.enum(["unit","course","resource-collection"]),NZ=L.enum(["choice","order","associate","match","hotspot","hottext","select-point","graphic-order","graphic-associate","graphic-gap-match","text-entry","extended-text","inline-choice","upload","slider","drawing","media","custom"]),IZ=L.enum(["easy","medium","hard"]),bZ=L.array(L.object({source:L.string(),learningObjectiveIds:L.array(L.string())})),hZ=L.object({consecutive_failures:L.number().int().min(1).optional(),stagnation_limit:L.number().int().min(1).optional()}).optional(),H1=L.enum(["powerpath-100","quiz","test-out","placement","unit-test","alpha-read-article"]).nullable(),X1=L.object({imsx_codeMajor:L.enum(["failure","success"]),imsx_severity:L.enum(["error","warning","status"]),imsx_description:L.string(),imsx_CodeMinor:L.object({imsx_codeMinorField:L.array(L.object({imsx_codeMinorFieldName:L.string(),imsx_codeMinorFieldValue:L.string()}))}).optional()}),SZ=Y.union([Y.url(),Y.string().regex(/^urn:/,"Must be a URL or URN")]),D2=Y.object({id:Y.url(),type:Y.literal("TimebackUser"),email:Y.string()}),P8=Y.object({id:Y.url(),type:Y.literal("TimebackActivityContext"),subject:Z2,app:Y.object({name:Y.string()}),activity:Y.object({id:Y.url().optional(),name:Y.string()}).strict().optional(),course:Y.object({id:Y.url().optional(),name:Y.string().optional()}).strict(),process:Y.boolean().optional()}),A9=Y.object({"@context":Y.literal("http://purl.imsglobal.org/ctx/caliper/v1p2"),id:Y.string().regex(/^urn:uuid:/,"Event id must start with urn:uuid:"),type:Y.string(),eventTime:v,profile:Y.literal("TimebackProfile"),actor:D2,action:Y.string(),object:P8,edApp:Y.object({id:Y.string(),name:Y.string().optional()}).optional()}),z9=Y.object({type:Y.enum(["totalQuestions","correctQuestions","xpEarned","masteredUnits"]),value:Y.number()}),EZ=Y.object({id:Y.url(),type:Y.literal("TimebackActivityMetricsCollection"),attempt:Y.number().optional(),items:Y.array(z9),extensions:Y.record(Y.string(),Y.unknown()).optional()}),vZ=A9.extend({type:Y.literal("ActivityEvent"),action:Y.literal("Completed"),generated:EZ}),P9=Y.object({type:Y.enum(["active","inactive","waste","unknown","anti-pattern"]),value:Y.number(),subType:Y.string().optional()}),yZ=Y.object({id:Y.url(),type:Y.literal("TimebackTimeSpentMetricsCollection"),items:Y.array(P9)}),fZ=A9.extend({type:Y.literal("TimeSpentEvent"),action:Y.literal("SpentTime"),generated:yZ}),gZ=Y.object({actor:D2,object:P8,metrics:Y.array(z9).min(1,"metrics must contain at least one metric"),eventTime:v.optional(),metricsId:Y.string().optional(),id:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional(),edApp:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),session:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),attempt:Y.number().int().min(1).optional(),generatedExtensions:Y.object({pctCompleteApp:Y.number().optional()}).loose().optional()}).strict(),dZ=Y.object({actor:D2,object:P8,metrics:Y.array(P9).min(1,"metrics must contain at least one metric"),eventTime:v.optional(),metricsId:Y.string().optional(),id:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional(),edApp:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),session:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional()}).strict(),mZ=Y.union([vZ,fZ]),Y1=Y.object({sensor:Y.string(),sendTime:v,dataVersion:Y.literal("http://purl.imsglobal.org/ctx/caliper/v1p2"),data:Y.array(mZ)}),lZ=Y.enum(["AnnotationProfile","AssessmentProfile","ToolUseProfile","GeneralProfile","FeedbackProfile","MediaProfile","SurveyProfile","ResourceManagementProfile","ForumProfile","AssignableProfile","GradingProfile","ReadingProfile","SessionProfile","SearchProfile","ToolLaunchProfile","TimebackProfile"]),l=Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]),c2=Y.object({id:SZ,type:Y.string(),name:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),T9=Y.object({"@context":Y.string().optional(),id:Y.string().regex(/^urn:uuid:/,"Event id must start with urn:uuid:"),type:Y.string(),actor:Y.union([Y.string(),c2,D2]),action:Y.string(),object:l,eventTime:v,profile:lZ,edApp:l.optional(),generated:l.optional(),target:l.optional(),referrer:l.optional(),group:l.optional(),membership:l.optional(),session:l.optional(),federatedSession:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),x9=Y.object({sensor:X,sendTime:v,dataVersion:Y.literal("http://purl.imsglobal.org/ctx/caliper/v1p2"),data:Y.array(T9).min(1,"data must contain at least one event")}),uZ=Y.object({sensor:X,events:Y.array(T9).min(1,"events must contain at least one event")}),D9=Y.object({limit:Y.number().int().positive().optional(),offset:Y.number().int().min(0).optional(),sensor:X.optional(),startDate:v.optional(),endDate:v.optional(),actorId:X.optional(),actorEmail:Y.email().optional()}).strict(),R9=Y.object({id:Y.string(),name:Y.string().optional(),isPartOf:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}),cZ=Y.object({id:Y.string(),attempt:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),startedAtTime:v.optional(),endedAtTime:v.optional(),duration:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}),pZ=Y.object({id:Y.string().optional(),scoreGiven:Y.number(),maxScore:Y.number().optional(),attempt:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),comment:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}),aZ=Y.object({actor:Y.union([Y.string(),c2,D2]),object:R9,edApp:l,id:Y.string().optional(),eventTime:v.optional(),session:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),iZ=Y.object({actor:Y.union([Y.string(),c2,D2]),object:R9,edApp:l,generated:cZ.optional(),id:Y.string().optional(),eventTime:v.optional(),session:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),sZ=Y.object({actor:Y.union([Y.string(),c2,D2]),object:Y.string(),generated:pZ,edApp:l,id:Y.string().optional(),eventTime:v.optional(),session:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),G1=J2.object({name:X,targetUrl:J2.url("targetUrl must be a valid URL"),secret:X,active:J2.boolean(),sensor:J2.string().nullable().optional(),description:J2.string().nullable().optional()}).strict(),oZ=J2.enum(["string","number","boolean"]),nZ=J2.enum(["eq","neq","gt","gte","lt","lte","contains","notContains","in","notIn","startsWith","endsWith","regexp"]),B1=J2.object({webhookId:X,filterKey:X,filterValue:X,filterType:oZ,filterOperator:nZ,active:J2.boolean()}).strict(),p2=U.string().uuid(),w9=U.object({title:X,identifier:p2,uri:X}),rZ=U.object({identifier:p2,uri:X,lastChangeDateTime:X,title:X,creator:X,officialSourceURL:U.string().optional(),publisher:U.string().optional(),description:U.string().optional(),language:U.string().optional(),version:U.string().optional(),caseVersion:U.string().optional(),adoptionStatus:U.string().optional(),statusStartDate:U.string().optional(),statusEndDate:U.string().optional(),licenseUri:U.string().optional(),notes:U.string().optional(),subject:U.array(U.string()).optional(),extensions:U.unknown().optional()}),tZ=U.object({identifier:p2,uri:X,lastChangeDateTime:X,fullStatement:X,alternativeLabel:U.string().optional(),CFItemType:U.string().optional(),cfItemType:U.string().optional(),humanCodingScheme:U.string().optional(),listEnumeration:U.string().optional(),abbreviatedStatement:U.string().optional(),conceptKeywords:U.array(U.string()).optional(),notes:U.string().optional(),subject:U.array(U.string()).optional(),language:U.string().optional(),educationLevel:U.array(U.string()).optional(),CFItemTypeURI:U.unknown().optional(),licenseURI:U.unknown().optional(),statusStartDate:U.string().optional(),statusEndDate:U.string().optional(),extensions:U.unknown().optional()}),eZ=U.object({identifier:p2,uri:X,lastChangeDateTime:X,associationType:X,originNodeURI:w9,destinationNodeURI:w9,sequenceNumber:U.number().optional(),extensions:U.unknown().optional()}),$5=U.object({CFItemTypes:U.array(U.unknown()).optional(),CFSubjects:U.array(U.unknown()).optional(),CFConcepts:U.array(U.unknown()).optional(),CFLicenses:U.array(U.unknown()).optional(),CFAssociationGroupings:U.array(U.unknown()).optional(),extensions:U.unknown().optional()}),F1=U.object({CFDocument:rZ,CFItems:U.array(tZ),CFAssociations:U.array(eZ),CFDefinitions:$5.optional(),extensions:U.unknown().optional()}),U9="https://www.w3.org/ns/credentials/v2",J5=x.array(x.url()).min(3,"@context must include W3C, CLR, and OB context URLs").refine(($)=>$[0]===U9,`First @context entry must be "${U9}"`),N9=x.object({id:x.url(),type:x.literal("Image"),caption:x.string().optional()}),T8=x.object({id:x.url(),type:x.array(x.string()).min(1).refine(($)=>$.includes("Profile"),'type must include "Profile"'),name:x.string().optional(),url:x.string().url().optional(),phone:x.string().optional(),description:x.string().optional(),image:N9.optional(),email:x.string().email().optional()}),I9=x.object({type:X,proofPurpose:X,verificationMethod:X,created:x.iso.datetime(),proofValue:X,cryptosuite:x.string().optional()}),Z5=x.object({id:X,type:x.literal("1EdTechJsonSchemaValidator2019")}),K5=x.object({id:x.string().url().optional(),narrative:x.string().optional()}),H5=x.object({id:x.url(),type:x.array(x.string()).min(1).refine(($)=>$.includes("Achievement"),'type must include "Achievement"'),name:X,description:X,criteria:K5,image:N9.optional(),achievementType:x.string().optional(),creator:T8.optional()}),X5=x.object({type:x.literal("IdentityObject"),identityHash:X,identityType:X,hashed:x.boolean(),salt:x.string().optional()}),W5=x.enum(["exactMatchOf","isChildOf","isParentOf","isPartOf","isPeerOf","isRelatedTo","precedes","replacedBy"]),Y5=x.object({type:x.literal("Association"),associationType:W5,sourceId:x.url(),targetId:x.url()}),Q5=x.object({"@context":x.array(x.string()).min(1),id:x.url(),type:x.array(x.string()).min(1).refine(($)=>$.includes("VerifiableCredential"),'type must include "VerifiableCredential"'),issuer:T8,validFrom:x.iso.datetime(),validUntil:x.string().datetime().optional(),credentialSubject:x.object({id:x.string().optional()}),proof:x.array(I9).optional()}),G5=x.object({id:x.string().url().optional(),type:x.array(x.string()).min(1).refine(($)=>$.includes("ClrSubject"),'type must include "ClrSubject"'),identifier:x.array(X5).optional(),achievement:x.array(H5).optional(),verifiableCredential:x.array(Q5).min(1),association:x.array(Y5).optional()}),x1=x.object({"@context":J5,id:x.url(),type:x.array(x.string()).min(1).refine(($)=>$.includes("VerifiableCredential")&&$.includes("ClrCredential"),'type must include "VerifiableCredential" and "ClrCredential"'),issuer:T8,name:X,description:x.string().optional(),validFrom:x.iso.datetime(),validUntil:x.iso.datetime().optional(),credentialSubject:G5,proof:x.array(I9).optional(),credentialSchema:x.array(Z5).optional()}),B5=V.object({staging:V.string().meta({description:"Course ID in staging environment"}).optional(),production:V.string().meta({description:"Course ID in production environment"}).optional()}).meta({id:"CourseIds",description:"Environment-specific course IDs (populated by sync)"}),_5=V.enum(["base","hole-filling","optional"]).meta({id:"CourseType",description:"Course classification type"}),F5=V.enum(["draft","testing","published","deactivated"]).meta({id:"PublishStatus",description:"Course publication status"}),O5=V.object({dailyXp:V.number().int().positive().meta({description:"Target XP to earn per day"}).optional(),dailyLessons:V.number().int().positive().meta({description:"Target lessons to complete per day"}).optional(),dailyActiveMinutes:V.number().int().positive().meta({description:"Target active learning minutes per day"}).optional(),dailyAccuracy:V.number().int().min(0).max(100).meta({description:"Target accuracy percentage (0-100)"}).optional(),dailyMasteredUnits:V.number().int().positive().meta({description:"Target units to master per day"}).optional()}).meta({id:"CourseGoals",description:"Daily learning goals for a course"}),x5=V.object({totalXp:V.number().int().positive().meta({description:"Total XP available in the course"}).optional(),totalLessons:V.number().int().positive().meta({description:"Total number of lessons/activities"}).optional(),totalGrades:V.number().int().positive().meta({description:"Total grade levels covered"}).optional()}).meta({id:"CourseMetrics",description:"Aggregate metrics for a course"}),b9=V.object({courseType:_5.optional(),isSupplemental:V.boolean().meta({description:"Whether this is supplemental to a base course"}).optional(),isCustom:V.boolean().meta({description:"Whether this is a custom course for an individual student"}).optional(),publishStatus:F5.optional(),contactEmail:V.email().meta({description:"Contact email for course issues"}).optional(),primaryApp:V.string().meta({description:"Primary application identifier"}).optional(),goals:O5.optional(),metrics:x5.optional()}).meta({id:"CourseMetadata",description:"Course metadata (matches API metadata object)"}),h9=V.object({courseCode:V.string().meta({description:"Course code (e.g., 'MATH101')"}).optional(),level:V.string().meta({description:"Course level (e.g., 'AP', 'Honors')"}).optional(),metadata:b9.optional()}).meta({id:"CourseDefaults",description:"Default properties that apply to all courses unless overridden"}),M9=V.object({level:V.string().meta({description:"Course level for this environment"}).optional(),sensor:V.url().meta({description:"Caliper sensor endpoint URL for this environment"}).optional(),launchUrl:V.url().meta({description:"LTI launch URL for this environment"}).optional(),metadata:b9.optional()}).meta({id:"CourseEnvOverrides",description:"Environment-specific course overrides (non-identity fields)"}),D5=V.object({staging:M9.meta({description:"Overrides for staging environment"}).optional(),production:M9.meta({description:"Overrides for production environment"}).optional()}).meta({id:"CourseOverrides",description:"Per-environment course overrides"}),w5=h9.extend({subject:Z2.meta({description:"Subject area for this course"}),grade:n.meta({description:"Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"}).optional(),ids:B5.nullable().optional(),sensor:V.url().meta({description:"Caliper sensor endpoint URL for this course"}).optional(),launchUrl:V.url().meta({description:"LTI launch URL for this course"}).optional(),overrides:D5.optional()}).meta({id:"CourseConfig",description:"Configuration for a single course. Must have either grade or courseCode (or both)."}),w1=V.object({$schema:V.string().meta({description:"JSON Schema reference for editor support"}).optional(),name:V.string().min(1,"App name is required").meta({description:"Display name for your app"}),defaults:h9.meta({description:"Default properties applied to all courses"}).optional(),courses:V.array(w5).min(1,"At least one course is required").meta({description:"Courses available in this app"}),sensor:V.url().meta({description:"Default Caliper sensor endpoint URL for all courses"}).optional(),launchUrl:V.url().meta({description:"Default LTI launch URL for all courses"}).optional(),studio:V.object({telemetry:V.boolean().meta({description:"Enable anonymous usage telemetry for Studio (default: true)"}).optional().default(!0)}).meta({description:"Studio-specific configuration"}).optional()}).meta({id:"TimebackConfig",title:"Timeback Config",description:"Configuration schema for timeback.config.json files"}).refine(($)=>{return $.courses.every((J)=>J.grade!==void 0||J.courseCode!==void 0)},{message:"Each course must have either a grade or a courseCode",path:["courses"]}).refine(($)=>{let Z=$.courses.filter((K)=>K.grade!==void 0).map((K)=>`${K.subject}:${K.grade}`);return new Set(Z).size===Z.length},{message:"Duplicate (subject, grade) pair found; each must be unique",path:["courses"]}).refine(($)=>{let Z=$.courses.filter((K)=>K.courseCode!==void 0).map((K)=>K.courseCode);return new Set(Z).size===Z.length},{message:"Duplicate courseCode found; each must be unique",path:["courses"]}).refine(($)=>{return $.courses.every((J)=>{if(J.sensor!==void 0||$.sensor!==void 0)return!0;return[J.launchUrl,$.launchUrl,J.overrides?.staging?.launchUrl,J.overrides?.production?.launchUrl].filter(Boolean).length>0})},{message:"Each course must have an effective sensor. Either set `sensor` explicitly (top-level or per-course), or provide a `launchUrl` so sensor can be derived from its origin.",path:["courses"]}),N2=D.union([v,q2]),I2=N2.transform(($)=>$.includes("T")?$:`${$}T00:00:00.000Z`),M1=D.object({id:D.string(),role:D.string(),beginDate:N2.nullable(),endDate:N2.nullable(),metadata:D.object({goals:D.object({dailyXp:D.number().optional()}).optional(),metrics:D.object({totalXp:D.number().optional(),totalLessons:D.number().optional()}).optional()}).optional(),course:D.object({id:D.string(),title:D.string(),subjects:D.array(D.string()).nullable(),grades:D.array(D.string()).nullable()}),school:D.object({id:D.string(),name:D.string()})}),U5=D.object({activityMetrics:D.object({xpEarned:D.number(),totalQuestions:D.number(),correctQuestions:D.number(),masteredUnits:D.number()}),timeSpentMetrics:D.object({activeSeconds:D.number(),inactiveSeconds:D.number(),wasteSeconds:D.number()}),apps:D.array(D.string())}),M5=D.record(D.string(),D.record(D.string(),U5)),L1=D.object({message:D.string(),enrollmentId:D.string(),startDate:N2,endDate:N2,facts:M5,factsByApp:D.unknown()}),S9=D.object({email:D.email().optional(),studentId:X.optional()}).superRefine(($,J)=>{if(!$.email&&!$.studentId)J.addIssue({code:D.ZodIssueCode.custom,message:"must provide either email or studentId",path:["email"]}),J.addIssue({code:D.ZodIssueCode.custom,message:"must provide either email or studentId",path:["studentId"]})}),j1=D.object({subject:X,grade:X,courseId:X,orgSourcedId:X.optional()}),V1=D.object({userId:X}),k1=D.object({sourcedId:X.optional(),role:zZ.optional(),beginDate:v.optional(),metadata:D.record(D.string(),D.unknown()).optional()}),q1=D.object({fields:D.string().optional(),limit:D.number().int().positive().optional(),offset:D.number().int().nonnegative().optional(),sort:D.string().optional(),orderBy:D.enum(["asc","desc"]).optional(),filter:D.string().optional(),search:D.string().optional(),roles:D.array(C9).min(1),orgSourcedIds:D.array(X).optional()}),C1=S9.extend({startDate:I2,endDate:I2,timezone:D.string().optional()}),A1=S9.extend({weekDate:I2,timezone:D.string().optional()}),z1=D.object({enrollmentId:X,startDate:I2.optional(),endDate:I2.optional(),timezone:D.string().optional()}),T1=f.object({email:f.email()}),R1=f.object({name:X.optional(),timeback_id:X.optional(),grade:X.optional(),subject:X.optional(),all:f.boolean().optional()}),N1=f.object({student_email:f.email(),timeback_id:X.optional(),subject:X.optional(),grade_rank:f.number().int().min(0).max(12).optional(),assessment_line_item_sourced_id:X.optional(),assessment_result_sourced_id:X.optional()}).superRefine(($,J)=>{let Z=!!$.timeback_id,K=!!$.subject,H=$.grade_rank!==void 0;if(!Z&&!K)J.addIssue({code:f.ZodIssueCode.custom,message:"must provide either timeback_id or subject",path:["timeback_id"]}),J.addIssue({code:f.ZodIssueCode.custom,message:"must provide either timeback_id or subject",path:["subject"]});if(H&&!K)J.addIssue({code:f.ZodIssueCode.custom,message:"grade_rank requires subject",path:["grade_rank"]});let W=!!$.assessment_line_item_sourced_id,F=!!$.assessment_result_sourced_id;if(W!==F)J.addIssue({code:f.ZodIssueCode.custom,message:"assessment_line_item_sourced_id and assessment_result_sourced_id must be provided together",path:W?["assessment_result_sourced_id"]:["assessment_line_item_sourced_id"]})}),I1=f.object({student_email:f.email(),assignment_id:f.number().int().positive().optional(),timeback_id:X.optional(),subject:X.optional(),grade_rank:f.number().int().min(0).max(12).optional()}).superRefine(($,J)=>{let Z=$.assignment_id!==void 0,K=!!$.timeback_id,H=!!$.subject&&$.grade_rank!==void 0;if(!Z&&!K&&!H)J.addIssue({code:f.ZodIssueCode.custom,message:"Either assignment_id, timeback_id, or (subject and grade_rank) is required",path:["assignment_id"]});if($.grade_rank!==void 0&&!$.subject)J.addIssue({code:f.ZodIssueCode.custom,message:"grade_rank requires subject",path:["grade_rank"]})}),g=G.enum(["active","tobedeleted"]),y=G.record(G.string(),G.unknown()).nullable().optional(),k=G.object({sourcedId:X,type:G.string().optional(),href:G.string().optional()}).strict(),W2=G.union([q2,v]).transform(($)=>$.includes("T")?$:`${$}T00:00:00Z`),L5=G.object({roleType:G.enum(["primary","secondary"]),role:C9,org:k,userProfile:G.string().optional(),metadata:y,beginDate:W2.optional(),endDate:W2.optional()}).strict(),h1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string"),status:g.optional(),enabledUser:G.boolean(),givenName:X.describe("givenName must be a non-empty string"),familyName:X.describe("familyName must be a non-empty string"),middleName:X.optional(),username:X.optional(),email:G.email(),roles:G.array(L5).min(1,"roles must include at least one role"),userIds:G.array(G.object({type:X,identifier:X}).strict()).optional(),agents:G.array(k).optional(),grades:G.array(n).optional(),identifier:X.optional(),sms:X.optional(),phone:X.optional(),pronouns:X.optional(),password:X.optional(),metadata:y}).strict(),S1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string").optional(),status:g.optional(),title:X.describe("title must be a non-empty string"),org:k,courseCode:X.optional(),subjects:G.array(Z2).optional(),grades:G.array(n).optional(),level:X.optional(),metadata:y}).strict(),E1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string").optional(),status:g.optional(),title:X.describe("title must be a non-empty string"),terms:G.array(k).min(1,"terms must have at least one item"),course:k,org:k,classCode:X.optional(),classType:G.enum(["homeroom","scheduled"]).optional(),location:X.optional(),grades:G.array(n).optional(),subjects:G.array(Z2).optional(),subjectCodes:G.array(X).optional(),periods:G.array(X).optional(),metadata:y}).strict(),E9=G.enum(["true","false"]),v1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string").optional(),status:g.optional(),user:k,class:k,school:k.optional(),role:G.enum(["administrator","proctor","student","teacher"]),primary:E9.optional(),beginDate:q2.optional(),endDate:q2.optional(),metadata:y}).strict(),y1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),status:g,weight:G.number().nullable().optional(),metadata:y}).strict(),f1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),class:k,school:k,category:k,assignDate:W2,dueDate:W2,status:g,description:G.string().optional(),resultValueMin:G.number().nullable().optional(),resultValueMax:G.number().nullable().optional(),scoreScale:k.optional(),metadata:y}).strict(),g1=G.object({sourcedId:X.optional(),lineItem:k,student:k,class:k.optional(),scoreDate:W2,scoreStatus:G.enum(["exempt","fully graded","not submitted","partially graded","submitted"]),score:G.number().nullable().optional(),textScore:G.string().nullable().optional(),status:g,comment:G.string().nullable().optional(),metadata:y}).strict(),d1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),status:g.optional(),type:G.string(),class:k,course:k.nullable().optional(),scoreScaleValue:G.array(G.object({itemValueLHS:X,itemValueRHS:X,value:G.string().optional(),description:G.string().optional()}).strict()),minScore:G.number().optional(),maxScore:G.number().optional(),metadata:y}).strict(),m1=G.object({sourcedId:X.optional(),status:g.optional(),dateLastModified:v.optional(),title:X.describe("title must be a non-empty string"),description:G.string().nullable().optional(),class:k.nullable().optional(),parentAssessmentLineItem:k.nullable().optional(),scoreScale:k.nullable().optional(),resultValueMin:G.number().nullable().optional(),resultValueMax:G.number().nullable().optional(),component:k.nullable().optional(),componentResource:k.nullable().optional(),learningObjectiveSet:G.array(G.object({source:G.string(),learningObjectiveIds:G.array(G.string())})).optional().nullable(),course:k.nullable().optional(),metadata:y}).strict(),j5=G.object({learningObjectiveId:G.string(),score:G.number().optional(),textScore:G.string().optional()}),V5=G.array(G.object({source:G.string(),learningObjectiveResults:G.array(j5)})),l1=G.object({sourcedId:X.optional(),status:g.optional(),dateLastModified:v.optional(),metadata:y,assessmentLineItem:k,student:k,score:G.number().nullable().optional(),textScore:G.string().nullable().optional(),scoreDate:W2,scoreScale:k.nullable().optional(),scorePercentile:G.number().nullable().optional(),scoreStatus:G.enum(["exempt","fully graded","not submitted","partially graded","submitted"]),comment:G.string().nullable().optional(),learningObjectiveSet:V5.nullable().optional(),inProgress:G.string().nullable().optional(),incomplete:G.string().nullable().optional(),late:G.string().nullable().optional(),missing:G.string().nullable().optional()}).strict(),u1=G.object({sourcedId:X.optional(),status:g.optional(),name:X.describe("name must be a non-empty string"),type:AZ,identifier:X.optional(),parent:k.optional(),metadata:y}).strict(),c1=G.object({sourcedId:X.optional(),status:g.optional(),name:X.describe("name must be a non-empty string"),type:G.literal("school").optional(),identifier:X.optional(),parent:k.optional(),metadata:y}).strict(),p1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string"),status:g,title:X.describe("title must be a non-empty string"),startDate:W2,endDate:W2,type:G.enum(["gradingPeriod","semester","schoolYear","term"]),schoolYear:X.describe("schoolYear must be a non-empty string"),org:k,parent:k.optional(),children:G.array(k).optional(),metadata:y}).strict(),a1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),courseComponent:k,resource:k,status:g,metadata:y}).strict(),i1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),course:k,status:g,metadata:y}).strict(),s1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string"),role:G.enum(["student","teacher"]),primary:E9.optional(),beginDate:q2.optional(),endDate:q2.optional(),metadata:y}).strict(),o1=G.object({agentSourcedId:X.describe("agentSourcedId must be a non-empty string")}).strict(),n1=G.object({applicationName:X.describe("applicationName must be a non-empty string"),credentials:G.object({username:X.describe("username must be a non-empty string"),password:X.describe("password must be a non-empty string")})}).strict(),r1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string")}).loose(),Y2=G.object({type:PZ,subject:Z2.nullish(),grades:G.array(n).nullish(),language:G.string().nullish(),xp:G.number().nullish(),url:G.url().nullish(),keywords:G.array(G.string()).nullish(),learningObjectiveSet:bZ.nullish(),lessonType:G.string().nullish()}).passthrough(),k5=Y2.extend({type:G.literal("qti"),subType:TZ,questionType:NZ.optional(),difficulty:IZ.optional()}),q5=Y2.extend({type:G.literal("text"),format:G.string(),author:G.string().optional(),pageCount:G.number().optional()}),C5=Y2.extend({type:G.literal("audio"),duration:G.string().regex(/^\d{2}:\d{2}:\d{2}(\.\d{2})?$/).optional(),format:G.string(),speaker:G.string().optional()}),A5=Y2.extend({type:G.literal("video"),duration:G.string().regex(/^\d{2}:\d{2}:\d{2}(\.\d{2})?$/).optional(),captionsAvailable:G.boolean().optional(),format:G.string()}),z5=Y2.extend({type:G.literal("interactive"),launchUrl:G.url().optional(),toolProvider:G.string().optional(),instructionalMethod:G.string().optional(),courseIdOnFail:G.string().nullable().optional(),fail_fast:hZ}),P5=Y2.extend({type:G.literal("visual"),format:G.string(),resolution:G.string().optional()}),T5=Y2.extend({type:G.literal("course-material"),subType:RZ,author:G.string().optional(),format:G.string(),instructionalMethod:G.string().optional()}),R5=Y2.extend({type:G.literal("assessment-bank"),resources:G.array(G.string())}),N5=G.discriminatedUnion("type",[k5,q5,C5,A5,z5,P5,T5,R5]),t1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),vendorResourceId:X.describe("vendorResourceId must be a non-empty string"),roles:G.array(G.enum(["primary","secondary"])).optional(),importance:G.enum(["primary","secondary"]).optional(),vendorId:G.string().optional(),applicationId:G.string().optional(),status:g.optional(),metadata:N5.nullable().optional()}).strict(),I5=G.object({url:X.describe("courseStructure.url must be a non-empty string"),skillCode:X.describe("courseStructure.skillCode must be a non-empty string"),lessonCode:X.describe("courseStructure.lessonCode must be a non-empty string"),title:X.describe("courseStructure.title must be a non-empty string"),"unit-title":X.describe("courseStructure.unit-title must be a non-empty string"),status:X.describe("courseStructure.status must be a non-empty string"),xp:G.number()}).loose(),e1=G.object({course:G.object({sourcedId:X.describe("course.sourcedId must be a non-empty string").optional(),title:X.describe("course.title must be a non-empty string"),org:k,status:g,metadata:y}).strict(),courseStructure:G.record(G.string(),I5)}).strict(),b5=G.object({student:k}).loose(),$6=G.array(b5).min(1,"results must have at least one item"),h5=B.enum(["edulastic","mastery-track"]),S5=B.enum(["powerpath-100","quiz","test-out","placement","unit-test","alpha-read-article"]),v9=B.array(n),y9=B.record(B.string(),B.unknown()).optional(),f9=B.object({courseId:X,lessonTitle:X.optional(),launchUrl:X.optional(),toolProvider:h5,unitTitle:X.optional(),courseComponentSourcedId:X.optional(),vendorId:X.optional(),description:X.optional(),resourceMetadata:y9.nullable().optional(),grades:v9}),Z6=f9.extend({lessonType:B.literal("test-out"),xp:B.number()}),K6=f9.extend({lessonType:B.literal("placement"),courseIdOnFail:X.nullable().optional(),xp:B.number().optional()}),L9=B.object({courseId:X,lessonType:S5,lessonTitle:X.optional(),unitTitle:X.optional(),courseComponentSourcedId:X.optional(),resourceMetadata:y9.nullable().optional(),xp:B.number().optional(),grades:v9.optional(),courseIdOnFail:X.nullable().optional()}),H6=B.discriminatedUnion("testType",[L9.extend({testType:B.literal("qti"),qti:B.object({url:B.url(),title:X.optional(),metadata:B.record(B.string(),B.unknown()).optional()})}),L9.extend({testType:B.literal("assessment-bank"),assessmentBank:B.object({resources:B.array(B.object({url:B.url(),title:X.optional(),metadata:B.record(B.string(),B.unknown()).optional()})).min(1)})})]),X6=B.object({student:X,lesson:X}),W6=B.object({student:X,lesson:X}),Y6=B.object({courseId:X,userId:X,classId:X.optional()}),k2=B.object({type:B.enum(["component","resource"]),id:X}),E5=B.union([B.object({type:B.literal("set-skipped"),payload:B.object({target:k2,value:B.boolean()})}),B.object({type:B.literal("add-custom-resource"),payload:B.object({resource_id:X,parent_component_id:X,skipped:B.boolean().optional()})}),B.object({type:B.literal("move-item-before"),payload:B.object({target:k2,reference_id:X})}),B.object({type:B.literal("move-item-after"),payload:B.object({target:k2,reference_id:X})}),B.object({type:B.literal("move-item-to-start"),payload:B.object({target:k2})}),B.object({type:B.literal("move-item-to-end"),payload:B.object({target:k2})}),B.object({type:B.literal("change-item-parent"),payload:B.object({target:k2,new_parent_id:X,position:B.enum(["start","end"]).optional()})})]),Q6=B.object({operation:E5,reason:X.optional()}),G6=B.object({studentId:X,componentResourceId:X,result:B.object({status:B.enum(["active","tobedeleted"]),metadata:B.record(B.string(),B.unknown()).optional(),score:B.number().optional(),textScore:X.optional(),scoreDate:B.string().datetime(),scorePercentile:B.number().optional(),scoreStatus:CZ,comment:X.optional(),learningObjectiveSet:B.array(B.object({source:X,learningObjectiveResults:B.array(B.object({learningObjectiveId:X,score:B.number().optional(),textScore:X.optional()}))})).optional(),inProgress:X.optional(),incomplete:X.optional(),late:X.optional(),missing:X.optional()})}),B6=B.object({student:X,lesson:X,applicationName:X.optional(),testId:X.optional(),skipCourseEnrollment:B.boolean().optional()}),_6=B.object({student:X,subject:Z2}),F6=B.object({student:X,lesson:X}),O6=B.object({userId:X}),x6=B.object({userId:X,subject:B.enum(["Math","Reading","Language","Science"])}),D6=B.object({student:X,subject:Z2,grade:n,testName:X.optional()}),w6=B.object({testName:X}),v5=B.object({student:X,subject:Z2,grade:n,testName:X.optional()}),U6=B.object({items:B.array(v5)}),M6=B.object({spreadsheetUrl:B.url(),sheet:X}),L6=B.object({student:X,status:B.enum(["assigned","in_progress","completed","failed","expired","cancelled"]).optional(),subject:X.optional(),grade:n.optional(),limit:B.number().int().positive().max(3000).optional(),offset:B.number().int().nonnegative().optional()}),j6=B.object({student:X.optional(),status:B.enum(["assigned","in_progress","completed","failed","expired","cancelled"]).optional(),subject:X.optional(),grade:n.optional(),limit:B.number().int().positive().max(3000).optional(),offset:B.number().int().nonnegative().optional()}),V6=B.object({student:X,question:X,response:B.union([X,B.array(X)]).optional(),responses:B.record(B.string(),B.union([X,B.array(X)])).optional(),lesson:X,rendererOutcomes:B.object({score:B.number(),maxScore:B.number().min(0),isCorrect:B.boolean()}).optional(),playerState:B.string().optional()}).refine(($)=>$.response!==void 0||$.responses!==void 0,{message:"Either 'response' or 'responses' must be provided",path:["response","responses"]}).transform(($)=>{if($.response!==void 0&&$.responses===void 0)return{...$,responses:{RESPONSE:$.response}};return $}),k6=B.object({student:X,lesson:X,attempt:B.number().int().positive().optional()}),q6=B.object({student:X,lesson:X}),C6=B.object({student:X,lesson:X}),A6=B.object({student:X,course:X}),z6=B.object({student:X,lesson:X,applicationName:X.optional()}),P6=B.object({student:X,subject:Z2}),T6=B.object({status:B.enum(["active","tobedeleted"]).optional()}),g9=Q.enum(["choice","text-entry","extended-text","inline-choice","match","order","associate","select-point","graphic-order","graphic-associate","graphic-gap-match","hotspot","hottext","slider","drawing","media","upload"]),R8=Q.enum(["single","multiple","ordered","record"]),N8=Q.enum(["identifier","boolean","integer","float","string","point","pair","directedPair","duration","file","uri"]),y5=Q.enum(["easy","medium","hard"]),f5=Q.enum(["linear","nonlinear"]),g5=Q.enum(["individual","simultaneous"]),I8=Q.enum(["show","hide"]),d9=Q.enum(["test","item","stimulus"]),N6=Q.enum(["QUESTION","LESSON"]),d5=Q.object({value:Q.array(Q.string())}).strict(),m9=Q.object({identifier:X,cardinality:R8,baseType:N8.optional(),correctResponse:d5}).strict(),l9=Q.object({identifier:X,cardinality:R8,baseType:N8.optional()}).strict(),u9=Q.object({identifier:X,cardinality:R8.optional(),baseType:N8,normalMaximum:Q.number().optional(),normalMinimum:Q.number().optional(),defaultValue:Q.object({value:Q.unknown().optional()}).strict().optional()}).strict(),m5=Q.object({outcomeIdentifier:X,variableIdentifier:X}).strict(),c9=Q.object({templateType:Q.enum(["match_correct","map_response"]),responseDeclarationIdentifier:X,outcomeIdentifier:X,correctResponseIdentifier:X,incorrectResponseIdentifier:X,inlineFeedback:m5.optional()}).strict(),l5=Q.object({source:X,learningObjectiveIds:Q.array(Q.string())}).strict(),b8=Q.object({subject:Q.string().optional(),grade:n.optional(),difficulty:y5.optional(),learningObjectiveSet:Q.array(l5).optional()}).loose(),p9=Q.object({outcomeIdentifier:X,identifier:X,showHide:I8,content:Q.string(),title:Q.string()}).strict(),a9=Q.object({outcomeIdentifier:X,identifier:X,showHide:I8,content:Q.string(),class:Q.array(Q.string())}).strict(),i9=Q.object({outcomeIdentifier:X,identifier:X,showHide:I8,content:Q.string(),class:Q.array(Q.string())}).strict(),s9=Q.object({href:X,type:X}).strict(),o9=Q.object({id:X,support:Q.string(),content:Q.string()}).strict(),I6=Q.object({page:Q.number().int().positive().optional(),limit:Q.number().int().positive().optional(),sort:Q.string().optional(),order:Q.enum(["asc","desc"]).optional()}).strict(),u5=Q.object({format:Q.string().pipe(Q.literal("xml")),xml:X,metadata:b8.optional()}).strict(),c5=Q.object({identifier:X,title:X,type:g9,qtiVersion:Q.string().optional(),timeDependent:Q.boolean().optional(),adaptive:Q.boolean().optional(),responseDeclarations:Q.array(m9).optional(),outcomeDeclarations:Q.array(l9).optional(),responseProcessing:c9.optional(),metadata:b8.optional(),modalFeedback:Q.array(p9).optional(),feedbackInline:Q.array(a9).optional(),feedbackBlock:Q.array(i9).optional()}).strict(),b6=Q.union([u5,c5]),h6=Q.object({identifier:X.optional(),title:X,type:g9,qtiVersion:Q.string().optional(),timeDependent:Q.boolean().optional(),adaptive:Q.boolean().optional(),responseDeclarations:Q.array(m9).optional(),outcomeDeclarations:Q.array(l9).optional(),responseProcessing:c9.optional(),metadata:b8.optional(),modalFeedback:Q.array(p9).optional(),feedbackInline:Q.array(a9).optional(),feedbackBlock:Q.array(i9).optional(),rawXml:Q.string(),content:Q.record(Q.string(),Q.unknown())}).strict(),S6=Q.object({identifier:X,response:Q.union([Q.string(),Q.array(Q.string())])}).strict(),n9=Q.object({identifier:X,href:X,sequence:Q.number().int().positive().optional()}).strict(),p5=Q.object({identifier:X,title:X,visible:Q.boolean(),required:Q.boolean().optional(),fixed:Q.boolean().optional(),sequence:Q.number().int().positive(),"qti-assessment-item-ref":Q.array(n9).optional()}).strict(),r9=Q.object({identifier:X,navigationMode:Q.string().pipe(f5),submissionMode:Q.string().pipe(g5),"qti-assessment-section":Q.array(p5)}).strict(),E6=Q.object({items:Q.array(n9).min(1)}).strict(),v6=Q.object({metadata:Q.record(Q.string(),Q.unknown()).optional()}).strict(),y6=Q.object({identifier:X,title:X,qtiVersion:Q.string().optional(),toolName:Q.string().optional(),toolVersion:Q.string().optional(),timeLimit:Q.number().optional(),maxAttempts:Q.number().optional(),toolsEnabled:Q.record(Q.string(),Q.boolean()).optional(),metadata:Q.record(Q.string(),Q.unknown()).optional(),"qti-test-part":Q.array(r9),"qti-outcome-declaration":Q.array(u9).optional()}).strict(),f6=Q.object({identifier:X.optional(),title:X,qtiVersion:Q.string().optional(),toolName:Q.string().optional(),toolVersion:Q.string().optional(),timeLimit:Q.number().optional(),maxAttempts:Q.number().optional(),toolsEnabled:Q.record(Q.string(),Q.boolean()).optional(),metadata:Q.record(Q.string(),Q.unknown()).optional(),"qti-test-part":Q.array(r9),"qti-outcome-declaration":Q.array(u9).optional()}).strict(),g6=Q.object({identifier:X,title:X,label:Q.string().optional(),language:Q.string().optional(),stylesheet:s9.optional(),content:Q.string(),catalogInfo:Q.array(o9).optional(),toolName:Q.string().optional(),toolVersion:Q.string().optional(),metadata:Q.record(Q.string(),Q.unknown()).optional()}).strict(),d6=Q.object({identifier:X.optional(),title:X,label:Q.string().optional(),language:Q.string().optional(),stylesheet:s9.optional(),content:Q.string(),catalogInfo:Q.array(o9).optional(),toolName:Q.string().optional(),toolVersion:Q.string().optional(),metadata:Q.record(Q.string(),Q.unknown()).optional()}).strict(),m6=Q.object({xml:Q.string().optional(),schema:d9,entityId:Q.string().optional()}).strict(),l6=Q.object({xml:Q.array(Q.string()),schema:d9,entityIds:Q.array(Q.string())}).strict(),u6=Q.object({questionId:Q.string().optional(),userId:X,feedback:X,lessonId:X,humanApproved:Q.boolean().optional()}).strict();class t9{transport;eventTransformer;constructor($,J){this.transport=$,this.eventTransformer=J?.eventTransformer}send($,J){o(uZ,{sensor:$,events:J},"send events");let Z={sensor:$,sendTime:new Date().toISOString(),dataVersion:"http://purl.imsglobal.org/ctx/caliper/v1p2",data:J};return this.sendEnvelope(Z)}async sendEnvelope($){o(x9,$,"caliper envelope"),S.debug("Sending Caliper envelope",{sensor:$.sensor,eventCount:$.data.length});let J=this.eventTransformer?this.eventTransformer.transformEnvelope($):$,K=(await this.transport.request(this.transport.paths.send,{method:"POST",body:J}))?.jobId;return S.debug("Events sent",{jobId:K??"(none)"}),{jobId:K}}async validate($){let J=this.transport.paths.validate;if(!J)throw Error("validate() is not supported on this platform");o(x9,$,"caliper envelope"),S.debug("Validating Caliper envelope",{sensor:$.sensor,eventCount:$.data.length});let Z=await this.transport.request(J,{method:"POST",body:$});return S.debug("Validation complete",{status:Z.status}),Z}async list($={}){let J=this.transport.paths.list;if(!J)throw Error("list() is not supported on this platform");o(D9,$,"list events params"),S.debug("Listing events",{params:$});let Z={limit:$.limit??100,offset:$.offset??0};if($.sensor)Z.sensor=$.sensor;if($.startDate)Z.startDate=$.startDate;if($.endDate)Z.endDate=$.endDate;if($.actorId)Z.actorId=$.actorId;if($.actorEmail)Z.actorEmail=$.actorEmail;let K=await this.transport.request(J,{params:Z});return{events:K.events??[],pagination:K.pagination}}stream($={}){let J=this.transport.paths.list;if(!J)throw Error("stream() is not supported on this platform");let{max:Z,...K}=$;o(D9,K,"list events params"),C8($),S.debug("Streaming events",{params:$});let H={};if(K.limit!==void 0)H.limit=K.limit;if(K.offset!==void 0)H.offset=K.offset;if(K.sensor)H.sensor=K.sensor;if(K.startDate)H.startDate=K.startDate;if(K.endDate)H.endDate=K.endDate;if(K.actorId)H.actorId=K.actorId;if(K.actorEmail)H.actorEmail=K.actorEmail;return new V9(this.transport,J,{...H,max:Z})}async get($){let J=this.transport.paths.get;if(!J)throw Error("get() is not supported on this platform");u2($,"externalId"),S.debug("Getting event",{externalId:$});let Z=J.replace("{id}",encodeURIComponent($)),K=await this.transport.request(Z);if(!K.event)throw Error(`Event not found: ${$}`);return K.event}sendActivity($,J){o(gZ,J,"activity event");let Z=A8(J);return S.debug("Sending ActivityCompletedEvent",{eventId:Z.id,actor:J.actor.email,subject:J.object.subject,metricsCount:J.metrics.length}),this.send($,[Z])}sendTimeSpent($,J){o(dZ,J,"time spent event");let Z=z8(J);return S.debug("Sending TimeSpentEvent",{eventId:Z.id,actor:J.actor.email,subject:J.object.subject,metricsCount:J.metrics.length}),this.send($,[Z])}sendQuestionSeen($,J){o(aZ,J,"question seen event");let Z=_Z(J);return S.debug("Sending AssessmentItemEvent.Started",{eventId:Z.id,actor:J.actor,object:J.object.id}),this.send($,[Z])}sendQuestionAnswered($,J){o(iZ,J,"question answered event");let Z=FZ(J);return S.debug("Sending AssessmentItemEvent.Completed",{eventId:Z.id,actor:J.actor,object:J.object.id}),this.send($,[Z])}sendQuestionGraded($,J){o(sZ,J,"question graded event");let Z=OZ(J);return S.debug("Sending GradeEvent.Graded",{eventId:Z.id,actor:J.actor,object:J.object,scoreGiven:J.generated.scoreGiven}),this.send($,[Z])}}class e9{transport;constructor($){this.transport=$}async getStatus($){let J=this.transport.paths.jobStatus;if(!J)throw Error("getStatus() is not supported on this platform");u2($,"jobId"),S.debug("Getting job status",{jobId:$});let Z=J.replace("{id}",encodeURIComponent($));return(await this.transport.request(Z)).job}async waitForCompletion($,J={}){u2($,"jobId"),a5(J);let{timeoutMs:Z=30000,pollIntervalMs:K=1000}=J,H=Date.now();S.debug("Waiting for job completion",{jobId:$,timeoutMs:Z,pollIntervalMs:K});while(Date.now()-H<Z){let W=await this.getStatus($);if(W.state==="completed")return S.info("Job completed",{jobId:$}),W;if(W.state==="failed")throw S.error("Job failed",{jobId:$}),Error(`Job ${$} failed`);await new Promise((F)=>{setTimeout(F,K)})}throw Error(`Job ${$} timed out after ${Z}ms`)}}function a5($){if(!$)return;let J=[];if($.timeoutMs!==void 0){if(!Number.isInteger($.timeoutMs)||$.timeoutMs<=0)J.push({path:"timeoutMs",message:"Must be a positive integer"})}if($.pollIntervalMs!==void 0){if(!Number.isInteger($.pollIntervalMs)||$.pollIntervalMs<=0)J.push({path:"pollIntervalMs",message:"Must be a positive integer"})}if(J.length>0)throw T2("Invalid polling options",J)}function i5($=l2){return class{transport;_provider;events;jobs;constructor(Z={}){let K=kZ(Z,$),H;if(K.mode==="transport")this.transport=K.transport,S.info("Client initialized with custom transport");else{let{provider:W}=K,{baseUrl:F,paths:_}=W.getEndpointWithPaths("caliper"),O=W.getTokenProvider("caliper");if(!O)throw Error("Caliper API requires authentication");if(this._provider=W,this.transport=new j9({baseUrl:F,tokenProvider:O,timeout:W.timeout,paths:_}),W.platform===K9)H=new k9;S.info("Client initialized",{platform:W.platform,env:W.env,baseUrl:F})}this.events=new t9(this.transport,{eventTransformer:H}),this.jobs=new e9(this.transport)}getTransport(){return this.transport}checkAuth(){if(!this._provider)throw Error("Cannot check auth: client initialized with custom transport");return this._provider.checkAuth()}}}var c6=i5();class K2 extends Error{course;env;constructor($,J){let Z=$.grade===void 0?$.courseCode??$.subject:`${$.subject} grade ${$.grade}`;super(`Course "${Z}" is missing a synced ID for ${J}. Run \`timeback resources push\` first.`);this.name="MissingSyncedCourseIdError",this.course=$,this.env=J}}class a2 extends Error{sensor;constructor($){super(`Invalid sensor URL "${$}". Sensor must be a valid absolute URL (e.g., "https://sensor.example.com") to support slug-based activity IDs.`);this.name="InvalidSensorUrlError",this.sensor=$}}var $$="/ims/oneroster/rostering/v1p2";function J$($,J){return`${$.replace(/\/+$/,"")}/${J.replace(/^\/+/,"")}`}function s5($,J){return J$($,`${$$}/courses/${J}`)}function o5($,J){return J$($,`${$$}/users/${J}`)}function Z$($,J){let Z=$.ids?.[J];if(!Z)throw new K2($,J);return Z}function n5($,J,Z){let K=Z$(J,Z);return s5($,K)}function r5($){if($.courseCode)return $.courseCode;if($.grade!==void 0)return`${$.subject} G${String($.grade)}`;return $.subject}function h8($,J,Z){let K;try{K=new URL($)}catch{throw new a2($)}let H="grade"in J?`${J.subject}/g${String(J.grade)}`:J.code,W=K.pathname.replace(/\/+$/,"");return K.pathname=`${W}/activities/${H}/${encodeURIComponent(Z)}`,K.toString()}function K$($,J,Z,K,H,W,F){return{id:h8(H,$.course,$.id),type:"TimebackActivityContext",subject:J.subject,app:{name:Z},activity:{name:$.name},course:{id:n5(W,J,K),name:r5(J)},process:F??!0}}function t5($){let J=[];if($.totalQuestions!==void 0)J.push({type:"totalQuestions",value:$.totalQuestions});if($.correctQuestions!==void 0)J.push({type:"correctQuestions",value:$.correctQuestions});if($.xpEarned!==void 0)J.push({type:"xpEarned",value:$.xpEarned});if($.masteredUnits!==void 0)J.push({type:"masteredUnits",value:$.masteredUnits});return J}function e5($,J){let Z=[{type:"active",value:Math.max(0,$)/1000}];if(J>0)Z.push({type:"inactive",value:Math.max(0,J)/1000});return Z}function $0($){return $===void 0?void 0:{pctCompleteApp:$}}function H$($,J){return{courseId:Z$($,J)}}function X$($){if(!$)return;return`urn:uuid:${$}`}function W$($,J,Z){return{id:o5($,J),type:"TimebackUser",email:Z}}function Y$($){let{sensor:J,timebackId:Z,email:K,payload:H,process:W,course:F,appName:_,apiEnv:O,onerosterBaseUrl:w,attempt:j,runId:A}=$,C=W$(w,Z,K),q=K$(H,F,_,O,J,w,W??H.process),z=t5(H.metrics),N=$0(H.pctComplete),I=X$(A),r=H$(F,O),H2=A8({actor:C,object:q,metrics:z,eventTime:H.endedAt,generatedExtensions:N,extensions:r,attempt:j,session:I});return{sensor:J,actor:C,object:q,event:H2,payload:H,course:F,appName:_,apiEnv:O,email:K,timebackId:Z}}function i2($){let{sensor:J,timebackId:Z,email:K,payload:H,course:W,appName:F,apiEnv:_,onerosterBaseUrl:O,runId:w}=$,j=W$(O,Z,K),A=K$(H,W,F,_,J,O),C=e5(H.elapsedMs,H.pausedMs),q=H$(W,_),z=X$(w),N=z8({actor:j,object:A,metrics:C,eventTime:H.endedAt,extensions:q,session:z});return{sensor:J,actor:j,object:A,event:N,payload:{id:H.id,name:H.name,course:H.course,startedAt:H.startedAt,endedAt:H.endedAt,elapsedMs:H.elapsedMs,pausedMs:H.pausedMs},course:W,appName:F,apiEnv:_,email:K,timebackId:Z,runId:w}}import*as h from"zod";import*as b2 from"zod";var J0=b2.object({subject:Q$,grade:G$}),Z0=b2.object({code:E}),w2=b2.union([J0,Z0]);class Q2 extends Error{code;selector;count;constructor($,J,Z){super($);this.code=$,this.selector=J,this.count=Z}get selectorDescription(){if("grade"in this.selector)return`${this.selector.subject} grade ${this.selector.grade}`;return`code "${this.selector.code}"`}}function U2($,J){let Z;if("grade"in J)Z=$.filter((K)=>K.subject===J.subject&&K.grade===J.grade);else Z=$.filter((K)=>K.courseCode===J.code);if(Z.length===0)throw new Q2("unknown_course",J);if(Z.length>1)throw new Q2("ambiguous_course",J,Z.length);return Z[0]}var C2=R("handlers:activity:schema"),K0=h.object({totalQuestions:h.number().int().nonnegative().optional(),correctQuestions:h.number().int().nonnegative().optional(),xpEarned:h.number(),masteredUnits:h.number().int().nonnegative().optional()}).superRefine(o2);function H0($){return Math.min(100,Math.max(0,$))}function s2($){if("grade"in $)return`${$.subject} grade ${$.grade}`;return`code "${$.code}"`}var X0=h.object({id:E,name:E,course:w2,runId:h.string().uuid(),startedAt:h.iso.datetime(),endedAt:h.iso.datetime(),elapsedMs:h.number().int().nonnegative(),pausedMs:h.number().int().nonnegative()});function B$($,J,Z){let K=X0.safeParse($);if(!K.success)return{ok:!1,response:M("INVALID_PAYLOAD","Invalid payload",400,{details:K.error.flatten()})};let H=K.data,W;try{W=U2(J.courses,H.course)}catch(_){if(_ instanceof Q2){let O=s2(H.course);if(_.code==="unknown_course")return C2.warn("Unknown course selector",{selector:H.course}),{ok:!1,response:M("UNKNOWN_COURSE",`Unknown course: ${O}`,400)};return C2.error("Ambiguous course selector",{selector:H.course}),{ok:!1,response:M("AMBIGUOUS_COURSE_SELECTOR","Ambiguous course selector in timeback.config.json",500)}}throw _}let F=h2(J,W,Z);if(!F){let _=s2(H.course);return C2.error("Missing sensor for course",{selector:H.course}),{ok:!1,response:M("MISSING_SENSOR",`Course "${_}" has no sensor configured.`,500)}}return{ok:!0,payload:H,course:W,sensor:F}}var W0=h.object({id:E,name:E,course:w2,process:h.boolean().optional(),runId:h.string().uuid(),endedAt:h.iso.datetime(),metrics:K0,pctComplete:h.number().optional().transform(($)=>$===void 0?void 0:H0($))});function _$($,J,Z){let K=W0.safeParse($);if(!K.success)return{ok:!1,response:M("INVALID_PAYLOAD","Invalid payload",400,{details:K.error.flatten()})};let H=K.data,W;try{W=U2(J.courses,H.course)}catch(_){if(_ instanceof Q2){let O=s2(H.course);if(_.code==="unknown_course")return C2.warn("Unknown course selector",{selector:H.course}),{ok:!1,response:M("UNKNOWN_COURSE",`Unknown course: ${O}`,400)};return C2.error("Ambiguous course selector",{selector:H.course}),{ok:!1,response:M("AMBIGUOUS_COURSE_SELECTOR","Ambiguous course selector in timeback.config.json",500)}}throw _}let F=h2(J,W,Z);if(!F){let _=s2(H.course);return C2.error("Missing sensor for course",{selector:H.course}),{ok:!1,response:M("MISSING_SENSOR",`Course "${_}" has no sensor configured.`,500)}}return{ok:!0,payload:H,course:W,sensor:F}}import{getServiceUrlsForEnv as M$}from"@timeback/core";var S8=R("handlers:activity:attempts");async function F$($,J){let Z=[$,J].join("_");return`caliper_${await S2(Z)}`}function Y0($,J){return $.find((Z)=>Z.scoreDate===J)}function Q0($){let J=0;for(let Z of $){let H=Z.metadata?.attempt;if(typeof H==="number"&&H>J)J=H}return J}function G0($){let J=$.metadata;return typeof J?.attempt==="number"&&J.attempt>=1?J.attempt:1}async function O$($,J,Z,K){let H;try{H=await $.oneroster.assessmentResults.listAll({where:{status:"active","assessmentLineItem.sourcedId":J,"student.sourcedId":Z}})}catch{return S8.debug("No existing results found (line item may not exist yet)",{lineItemId:J}),1}if(H.length===0)return 1;let W=Y0(H,K);if(W){let O=G0(W);return S8.debug("Retry detected, reusing attempt number",{lineItemId:J,timebackId:Z,endedAt:K,attempt:O}),O}let F=Q0(H),_=F+1;return S8.debug("New attempt computed",{lineItemId:J,timebackId:Z,endedAt:K,maxAttempt:F,nextAttempt:_}),_}var x$=R("handlers:activity:completion");async function w$($){let{client:J,courseId:Z,timebackId:K,pctComplete:H,appName:W}=$;if(H!==100)return;let F=D$(Z),_=`timeback_sdk_${await S2(`mastery-completion_${Z}`)}`,O=`timeback_sdk_${await S2(`mastery-completion_${Z}_${K}`)}`;try{let w=!1;try{await J.oneroster.assessmentLineItems(_).get(),w=!0}catch{}if(!w)await J.oneroster.assessmentLineItems.create({sourcedId:_,title:`${W}: Complete`,status:"active",course:{sourcedId:F.course},componentResource:{sourcedId:F.componentResource},resultValueMin:0,resultValueMax:100,metadata:{appName:W}});let j=new Date().toISOString();await J.oneroster.assessmentResults.upsert(O,{status:"active",assessmentLineItem:{sourcedId:_},student:{sourcedId:K},score:100,scoreDate:j,scoreStatus:"fully graded",metadata:{isMasteryCompletion:!0,completedAt:j,appName:W}}),x$.debug("Created mastery completion entry",{courseId:Z,timebackId:K,lineItemId:_,resultId:O})}catch(w){let j=w instanceof Error?w.message:"Unknown error";x$.error("Failed to create mastery completion entry",{courseId:Z,timebackId:K,lineItemId:_,error:j})}}import{aggregateActivityMetrics as B0}from"@timeback/core/utils";var A2=R("handlers:activity:progress");function _0($,J){let Z=u(J),K=$.overrides?.[Z]?.metadata?.metrics,H=$.metadata?.metrics;return K?.totalLessons??H?.totalLessons}function F0($,J){let Z=$/J*100;return Math.min(100,Math.max(0,Math.round(Z)))}async function U$($){let{client:J,courseId:Z,timebackId:K,payload:H,course:W,env:F}=$;if(H.pctComplete!==void 0)return;let _=H.metrics.masteredUnits;if(typeof _!=="number"||_<=0)return;let O=_0(W,F);if(!O||O<=0){A2.debug("Skipping progress computation: totalLessons not configured",{courseId:Z});return}let w;try{w=(await J.edubridge.enrollments.list({userId:K})).find((N)=>N.course.id===Z)?.id}catch(z){let N=z instanceof Error?z.message:"Unknown error";A2.warn("Failed to fetch enrollments for progress computation",{courseId:Z,timebackId:K,error:N});return}if(!w){A2.warn("Skipping progress computation: enrollment not found for student/course",{courseId:Z,timebackId:K});return}let j=0;try{let z=await J.edubridge.analytics.getEnrollmentFacts({enrollmentId:w});j=B0(z).masteredUnits}catch(z){let N=z instanceof Error?z.message:"Unknown error";A2.warn("Failed to fetch enrollment facts for progress computation",{courseId:Z,timebackId:K,enrollmentId:w,error:N});return}let A=!0;try{if((await J.edubridge.analytics.getWeeklyFacts({studentId:K,weekDate:H.endedAt})).some((I)=>{if(I.activityId!==H.id)return!1;if(I.enrollmentId&&I.enrollmentId===w)return!0;if(I.courseId&&I.courseId===Z)return!0;return!1}))A=!1}catch(z){let N=z instanceof Error?z.message:"Unknown error";A2.warn("Failed to fetch weekly facts for retry-safe progress computation",{courseId:Z,timebackId:K,enrollmentId:w,activityId:H.id,error:N}),A=!1}let C=j+(A?_:0),q=F0(C,O);return A2.debug("Computed pctComplete",{courseId:Z,timebackId:K,enrollmentId:w,historicalMasteredUnits:j,currentMasteredUnits:_,shouldIncludeCurrentMasteredUnits:A,totalMastered:C,totalLessons:O,pctComplete:q}),{pctComplete:q}}var E8=R("handlers:activity:submit"),O0={computeProgress:U$,maybeWriteCompletionEntry:w$};function L$($,J){return $.timebackId??G2({email:$.email,client:J})}async function n2($,J,Z=O0){let K=u($.env),{userInfo:H,payload:W,course:F,sensor:_,preview:O=!1,runId:w}=J,j=F.ids?.[K];if(!j)throw new K2(F,K);let A=$.getClient(),C=await L$(H,A),q=W;if(W.pctComplete===void 0){let y2=await Z.computeProgress({client:A,courseId:j,timebackId:C,payload:W,course:F,env:$.env});if(y2)q={...W,pctComplete:y2.pctComplete}}let z;if(!O){let y2=h8(_,q.course,q.id),FJ=await F$(y2,j);z=await O$(A,FJ,C,q.endedAt)}let I=M$(K).oneroster,r=Y$({sensor:_,timebackId:C,email:H.email,payload:q,process:q.process,course:F,appName:$.appConfig.name,apiEnv:K,onerosterBaseUrl:I,attempt:z,runId:w}),H2=$.hooks?.beforeActivitySend,v2=H2?await H2(r):r,p=v2??r;if(O||v2===null)return{success:!0,preview:!0,sensor:p.sensor,actor:p.actor,object:p.object,event:p.event};return await A.caliper.events.send(p.sensor,[p.event]),await Z.maybeWriteCompletionEntry({client:A,courseId:j,timebackId:p.timebackId,pctComplete:p.payload.pctComplete,appName:p.appName}),E8.debug("Recorded completion",{courseSelector:W.course,activityId:W.id}),{success:!0}}async function j$($,J){let Z=u($.env),{userInfo:K,payload:H,course:W,sensor:F,runId:_}=J;if(!W.ids?.[Z])throw new K2(W,Z);let w=$.getClient(),j=await L$(K,w),C=M$(Z).oneroster,q=i2({sensor:F,timebackId:j,email:K.email,payload:H,course:W,appName:$.appConfig.name,apiEnv:Z,onerosterBaseUrl:C,runId:_}),z=$.hooks?.beforeTimeSpentSend,N=z?await z(q):q,I=N??q;if(N===null){E8.debug("Hook skipped time-spent send",{activityId:H.id});return}await w.caliper.events.send(I.sensor,[I.event]),E8.debug("Sent time-spent event",{activityId:H.id,elapsedMs:H.elapsedMs})}var E2=R("handlers:activity:submit");async function z2($,J){if($.mode==="custom"){let K=await $.getEmail(J);return K?{email:K}:void 0}let Z=await $.getUser(J);return Z?{email:Z.email,timebackId:Z.id}:void 0}function r2($){return async(J)=>{let Z=await z2($.identity,J);if(!Z)return M("UNAUTHORIZED","Unauthorized",401);let K=_$(await J.json(),$.appConfig,$.env);if(!K.ok)return K.response;let{payload:H,course:W,sensor:F}=K,_={id:H.id,name:H.name,course:H.course,process:H.process,endedAt:H.endedAt,metrics:H.metrics,pctComplete:H.pctComplete};try{if((await n2({env:$.env,api:$.api,appConfig:$.appConfig,getClient:$.getClient,hooks:$.hooks},{userInfo:Z,payload:_,course:W,sensor:F,preview:!1,runId:H.runId})).preview)return P({preview:!0});return E2.debug("Submitted activity",{runId:H.runId,activityId:H.id}),new Response(null,{status:204})}catch(O){if(O instanceof d)return E2.warn("Failed to resolve Timeback user",{code:O.code}),M("USER_RESOLUTION_FAILED","Unable to resolve Timeback identity",B2(O));if(O instanceof K2)return E2.warn("Course not synced",{course:O.course,env:O.env}),M("MISSING_SYNCED_COURSE_ID",O.message,503);if(O instanceof a2)return E2.error("Invalid sensor URL",{sensor:O.sensor}),M("INVALID_SENSOR_URL",O.message,500);let w=O instanceof Error?O.message:"Unknown error";return E2.error("Failed to submit activity",{error:w}),M("INTERNAL_ERROR",w,502)}}}var P2=R("handlers:activity:heartbeat"),t2=new Map,D0=300000;function w0(){let $=Date.now();for(let[J,Z]of t2)if($-Z>D0)t2.delete(J)}function U0($){return w0(),t2.has($)}function V$($){t2.set($,Date.now())}function e2($){return async(J)=>{let Z=await z2($.identity,J);if(!Z)return M("UNAUTHORIZED","Unauthorized",401);let K=B$(await J.json(),$.appConfig,$.env);if(!K.ok)return K.response;let{payload:H,course:W,sensor:F}=K,_=new Date(H.startedAt).getTime(),O=`${H.runId}:${_}`;if(U0(O))return P2.debug("Duplicate heartbeat, skipping",{runId:H.runId,windowKey:O}),P({duplicate:!0});let w=u($.env);if(!W.ids?.[w]){let C=new K2(W,w);return P2.warn("Course not synced",{course:H.course,env:w}),M("MISSING_SYNCED_COURSE_ID",C.message,503)}let A=$.getClient();try{let C=Z.timebackId??await G2({email:Z.email,client:A}),z=x0(w).oneroster,N=i2({sensor:F,timebackId:C,email:Z.email,payload:H,course:W,appName:$.appConfig.name,apiEnv:w,onerosterBaseUrl:z,runId:H.runId}),I=$.hooks?.beforeTimeSpentSend,r=I?await I(N):N,H2=r??N;if(r===null)return V$(O),P2.debug("Hook skipped heartbeat send",{runId:H.runId}),new Response(null,{status:204});return await A.caliper.events.send(H2.sensor,[H2.event]),V$(O),P2.debug("Sent heartbeat",{runId:H.runId,activityId:H.id,elapsedMs:H.elapsedMs}),new Response(null,{status:204})}catch(C){if(C instanceof d)return P2.warn("Failed to resolve Timeback user",{code:C.code}),M("USER_RESOLUTION_FAILED","Unable to resolve Timeback identity",B2(C));let q=C instanceof Error?C.message:"Unknown error";return P2.error("Failed to send heartbeat",{error:q}),M("INTERNAL_ERROR",q,502)}}}async function I$($,J,Z){if(Z.mode!=="sso")return M2.warn("SSO not configured"),P({error:"SSO not configured"},400);return await T$({req:$,env:J,clientId:Z.clientId,issuer:Z.issuer,redirectUri:Z.redirectUri,buildState:Z.buildState})}async function M0($,J,Z,K,H,W,F){try{let _=W.issuer??k$(H),O=N$(J,W.redirectUri);M2.debug("Exchanging auth code for tokens",{issuer:_,clientId:W.clientId});let w=await q$({issuer:_,clientId:W.clientId,clientSecret:W.clientSecret,code:$,redirectUri:O}),j=await C$({issuer:_,accessToken:w.access_token}),A=typeof j.identities==="string"?JSON.parse(j.identities):j.identities;M2.debug("SSO completed, resolving Timeback user",{user:{...j,identities:A}});let C=await _2({env:H,apiCredentials:F.credentials,userInfo:j,client:F.getClient()});M2.debug("Timeback user resolved",{timebackId:C.id});let q={user:C,idp:{tokens:w,userInfo:j},state:Z,req:K,redirect:$8,json:P};return W.onCallbackSuccess(q)}catch(_){let O=_ instanceof Error?_:Error("Unknown error"),w=_ instanceof d?_.code:"token_exchange_failed";if(M2.error("SSO callback failed",{error:O.message,errorCode:w}),W.onCallbackError)return W.onCallbackError(A$(O,w,Z,K));if(_ instanceof d)return P({error:O.message},B2(_));return P({error:O.message},500)}}async function b$($,J,Z,K){if(Z.mode!=="sso")return M2.warn("SSO not configured"),P({error:"SSO not configured"},400);let{url:H,code:W,errorParam:F,state:_}=R$($);if(F)return z$(F,H,_,$,Z.onCallbackError);if(!W)return P$(_,$,Z.onCallbackError);return await M0(W,H,_,$,J,Z,K)}function J8($){let{env:J,identity:Z}=$;return(K)=>I$(K,J,Z)}function Z8($){let{env:J,identity:Z,api:K}=$;return(H)=>b$(H,J,Z,K)}function K8(){return()=>$8("/")}var h$=($)=>{return async(J)=>{return await $.getClient().powerpath.assessments.getAssessmentProgress({student:J.student,lesson:J.lesson,attempt:J.attempt})}};var S$=($)=>{return async(J)=>{return(await $.getClient().powerpath.assessments.getAttempts({student:J.student,lesson:J.lesson})).attempts.map((K)=>({attempt:K.attempt??void 0,score:K.score,startedAt:K.startedAt??void 0,completedAt:K.completedAt??void 0,scoreStatus:K.scoreStatus}))}};var E$=($)=>{return async(J)=>{let Z=$.getClient().powerpath.assessments,K=await Z.getAssessmentProgress({student:J.student,lesson:J.lesson}),H;if(K.lessonType!=="powerpath-100"&&K.finalized!==!0){try{H=await Z.finalStudentAssessmentResponse({student:J.student,lesson:J.lesson})}catch{}K=await Z.getAssessmentProgress({student:J.student,lesson:J.lesson})}let W=K.lessonType==="powerpath-100"?!0:K.finalized===!0;return{...H??{},score:K.score??0,totalQuestions:K.totalQuestions,correctQuestions:K.correctQuestions,accuracy:K.accuracy,finalized:W}}};function v$($){let J=$.metadata?.questionCount;return typeof J==="number"?J:void 0}function v8($){return{id:$.id,title:$.title,difficulty:$.difficulty,content:$.content?{rawXml:$.content.rawXml}:void 0,index:$.index,url:$.url,humanApproved:$.humanApproved,response:$.response,responses:$.responses,correct:$.correct,result:$.result,resultId:$.resultId,learningObjectives:$.learningObjectives}}function y$($,J){if(!J)return{lessonId:$,lessonType:"quiz",score:0,seenQuestions:0,finalized:!1};return{lessonId:$,lessonType:J.lessonType,attempt:J.attempt,score:J.score??0,questionCount:J.totalQuestions,seenQuestions:J.lessonType==="powerpath-100"?J.seenQuestions.length:0,finalized:J.lessonType==="powerpath-100"?!1:J.finalized}}function f$($){let J=$.questions,Z=J.filter((K)=>K.response!==void 0).map((K)=>K.id);return{questions:J.map(v8),answeredIds:Z,score:$.score??0,finalized:$.finalized,complete:$.finalized}}function L0($){if($.lessonType==="powerpath-100")return $.responseResult.isCorrect;return!1}function j0($){if($.lessonType==="powerpath-100")return $.powerpathScore;return 0}function g$($){let J=j0($);return{correct:L0($),score:J,complete:$.lessonType==="powerpath-100"&&J>=100,questionResult:$.questionResult}}function d$($,J){return Array.from(new Set($.map((Z)=>Z.ids?.[J]).filter((Z)=>Boolean(Z))))}function m$($){return String($.sourcedId??"")}var l$=($)=>{return async(J={})=>{let Z=$.getClient(),K=u($.env),H;if(J.course){let _=U2($.appConfig.courses,J.course).ids?.[K];H=_?[_]:[]}else H=d$($.appConfig.courses,K);let W=[];for(let F of H){let _=await Z.oneroster.courses(F).components({where:{status:"active"}}),O=y8(_);for(let w of O){let j=m$(w);if(!j)continue;let A=await Z.oneroster.courses.componentResources({where:{"courseComponent.sourcedId":j,status:"active"}}),C=y8(A);for(let q of C){if(!q.sourcedId)continue;let z=q.metadata??{},N=v$(q);W.push({id:q.sourcedId,name:q.title??q.sourcedId,type:z.lessonType??"quiz",courseId:F,questionCount:N,metadata:z})}}}return W}};var u$=($)=>{return async(J)=>{let Z=$.getClient().powerpath.assessments;if(J.lessonType!=="powerpath-100"){let H=await Z.getAssessmentProgress({student:J.student,lesson:J.lesson});if(H.lessonType==="powerpath-100")throw Error(`Expected quiz progress but got powerpath-100 for lesson ${J.lesson}`);return f$(H)}let K=await Z.getNextQuestion({student:J.student,lesson:J.lesson});return v8(K.question)}};var V0=R("lessons:start"),c$=($)=>{return async(J)=>{let Z=$.getClient().powerpath.assessments,K=J.lesson,H=J.student,W=await Z.getAssessmentProgress({student:H,lesson:K});if(J.forceNew){if(W.lessonType!=="powerpath-100"&&W.finalized!==!0)try{await Z.finalStudentAssessmentResponse({student:H,lesson:K})}catch{}try{await Z.createNewAttempt({student:H,lesson:K}),W=await Z.getAssessmentProgress({student:H,lesson:K})}catch(F){V0.warn("Failed to create new lesson attempt",{lessonId:K,error:F})}}else if(W.lessonType!=="powerpath-100"&&W.finalized!==!0&&(W.questions?.length??0)===0)try{await Z.createNewAttempt({student:H,lesson:K}),W=await Z.getAssessmentProgress({student:H,lesson:K})}catch{}return y$(K,W)}};var p$=($)=>{return async(J)=>{let K=await $.getClient().powerpath.assessments.updateStudentQuestionResponse({student:J.student,lesson:J.lesson,question:J.question,responses:{RESPONSE:J.response}});return g$(K)}};function m($){return{list:l$($),start:c$($),next:u$($),submit:p$($),complete:E$($),attempts:S$($),attemptDetails:h$($)}}async function a($,J){let Z=await z2($.identity,J);if(!Z)return null;if(Z.timebackId)return Z.timebackId;return await G2({email:Z.email,client:$.getClient()})}async function a$($,J){let Z=await z2($.identity,J);return Boolean(Z)}var k0=R("handlers:lessons");function c($,J){if($ instanceof d)return M("USER_RESOLUTION_FAILED","Unable to resolve Timeback identity",B2($));let Z=$ instanceof Error?$.message:"Unknown error";return k0.error(J,{error:Z}),M("INTERNAL_ERROR",Z,500)}import*as i from"zod";var q0=i.object({course:w2.optional()}).partial(),C0=i.object({lessonId:E,forceNew:i.boolean().optional()}),A0=i.object({lessonId:E,lessonType:E.optional()}),z0=i.object({lessonId:E,questionId:E,response:E}),P0=i.object({lessonId:E}),T0=i.object({lessonId:E}),R0=i.object({lessonId:E,attempt:i.number().int().positive()});async function N0($){try{let J=await $.json();if(!J||typeof J!=="object"||Array.isArray(J))return null;return J}catch{return null}}async function L2($,J){let Z=await N0($);if(!Z)return{ok:!1,response:M("INVALID_PAYLOAD","Invalid JSON body",400)};let K=J.safeParse(Z);if(!K.success)return{ok:!1,response:M("INVALID_PAYLOAD","Invalid payload",400,{details:K.error.flatten()})};return{ok:!0,payload:K.data}}async function i$($){return await L2($,q0)}async function s$($){return await L2($,C0)}async function o$($){return await L2($,A0)}async function n$($){return await L2($,z0)}async function r$($){return await L2($,P0)}async function t$($){return await L2($,T0)}async function e$($){return await L2($,R0)}function H8($){let J=m($);return async(Z)=>{try{let K=await e$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.attemptDetails({lesson:K.payload.lessonId,attempt:K.payload.attempt,student:H});return P(W)}catch(K){return c(K,"Failed to fetch lesson attempt details")}}}function X8($){let J=m($);return async(Z)=>{try{let K=await t$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.attempts({lesson:K.payload.lessonId,student:H});return P({attempts:W})}catch(K){return c(K,"Failed to list lesson attempts")}}}function W8($){let J=m($);return async(Z)=>{try{let K=await r$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.complete({lesson:K.payload.lessonId,student:H});return P(W)}catch(K){return c(K,"Failed to complete lesson")}}}function Y8($){let J=m($);return async(Z)=>{try{if(!await a$($,Z))return M("UNAUTHORIZED","Unauthorized",401);let K=await i$(Z);if(!K.ok)return K.response;let H=await J.list({course:K.payload.course});return P({lessons:H})}catch(K){return c(K,"Failed to list lessons")}}}function Q8($){let J=m($);return async(Z)=>{try{let K=await o$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.next({lesson:K.payload.lessonId,lessonType:K.payload.lessonType,student:H});return P(W)}catch(K){return c(K,"Failed to fetch next lesson question")}}}function G8($){let J=m($);return async(Z)=>{try{let K=await s$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.start({lesson:K.payload.lessonId,student:H,forceNew:K.payload.forceNew});return P(W)}catch(K){return c(K,"Failed to start lesson")}}}function B8($){let J=m($);return async(Z)=>{try{let K=await n$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.submit({lesson:K.payload.lessonId,question:K.payload.questionId,response:K.payload.response,student:H});return P(W)}catch(K){return c(K,"Failed to submit lesson answer")}}}function $J($,J){let Z=new Map;for(let K of $){let H=K.ids?.[J];if(H)Z.set(H,K)}return Z}function JJ($,J){return $.map((Z)=>{let K=J.get(Z.course.id);return{id:Z.course.id,code:K?.courseCode??Z.course.id,name:Z.course.title}})}function ZJ($){return $.map((J)=>J.metadata?.goals).find(Boolean)}function KJ($){let J=new Date(Date.UTC($.getUTCFullYear(),$.getUTCMonth(),$.getUTCDate())),Z=new Date(Date.UTC($.getUTCFullYear(),$.getUTCMonth(),$.getUTCDate(),23,59,59,999));return{start:J,end:Z}}function f8($){return Object.values($).reduce((J,Z)=>{return J+Object.values(Z).reduce((K,H)=>{return K+(H.activityMetrics?.xpEarned??0)},0)},0)}async function _8($,J,Z,K){let H=await $.edubridge.enrollments.list({userId:J.id}),W=$J(Z.courses,K),F=JJ(H,W),_=ZJ(H),{start:O,end:w}=KJ(new Date),[j,A]=await Promise.all([$.edubridge.analytics.getActivity({studentId:J.id,startDate:O.toISOString(),endDate:w.toISOString()}),$.edubridge.analytics.getActivity({studentId:J.id,startDate:"2000-01-01",endDate:w.toISOString()})]);return{id:J.id,email:J.email,name:J.name,school:J.school,grade:J.grade,courses:F.length?F:void 0,goals:_,xp:{today:f8(j),all:f8(A)}}}var g8=R("handlers:user");async function I0($,J){if($.mode==="custom"){let K=await $.getEmail(J);if(!K)return;return{sub:K,email:K}}let Z=await $.getUser(J);if(!Z)return;return{sub:Z.id,email:Z.email}}function b0($){if(g8.warn("Timeback user resolution failed",{code:$.code}),$.code==="timeback_user_ambiguous")return M("USER_AMBIGUOUS","Timeback user resolution ambiguous",409);if($.code==="timeback_user_not_found")return M("USER_NOT_FOUND","Timeback user not found",404);return M("USER_RESOLUTION_FAILED",$.message,502)}function F8($){return async(J)=>{try{let Z=await I0($.identity,J);if(!Z)return M("UNAUTHORIZED","Unauthorized",401);let K=u($.env),H=$.getClient();try{let W=await _2({env:$.env,apiCredentials:$.api,userInfo:Z,client:H}),F=await _8(H,W,$.appConfig,K);return P(F)}catch(W){if(W instanceof d)return b0(W);let F=W instanceof Error?W.message:"Unknown error";return g8.error("Failed to build user profile",{error:F}),M("INTERNAL_ERROR",F,502)}}catch(Z){let K=Z instanceof Error?Z.message:"Unknown error";return g8.error("Unhandled error in user handler",{error:K}),M("INTERNAL_ERROR",K,500)}}}var d8=R("handlers:user:verify");async function h0($,J){if($.mode==="custom"){let K=await $.getEmail(J);if(!K)return;return{sub:K,email:K}}let Z=await $.getUser(J);if(!Z)return;return{sub:Z.id,email:Z.email}}function O8($){return async(J)=>{try{let Z=await h0($.identity,J);if(!Z)return M("UNAUTHORIZED","Unauthorized",401);let K=$.getClient();try{let H=await _2({env:$.env,apiCredentials:$.api,userInfo:Z,client:K});return P({verified:!0,timebackId:H.id})}catch(H){if(H instanceof d){if(d8.warn("Timeback user resolution failed",{code:H.code}),H.code==="timeback_user_ambiguous")return M("USER_AMBIGUOUS","Timeback user resolution ambiguous",409);if(H.code==="timeback_user_not_found")return P({verified:!1});return M("USER_RESOLUTION_FAILED",H.message,502)}let W=H instanceof Error?H.message:"Unknown error";return d8.error("Failed to verify user",{error:W}),M("INTERNAL_ERROR",W,502)}}catch(Z){let K=Z instanceof Error?Z.message:"Unknown error";return d8.error("Unhandled error in verify handler",{error:K}),M("INTERNAL_ERROR",K,500)}}}import*as T from"zod";var S0=T.object({email:T.email(),timebackId:T.string().optional()}),E0=T.object({id:E,name:E,course:w2}),v0=T.object({totalQuestions:T.number().int().nonnegative().optional(),correctQuestions:T.number().int().nonnegative().optional(),xpEarned:T.number(),masteredUnits:T.number().int().nonnegative().optional(),pctComplete:T.number().min(0).max(100).optional()}).superRefine(o2),y0=T.object({startedAt:T.union([T.iso.datetime(),T.date()]).optional(),endedAt:T.union([T.iso.datetime(),T.date()]).optional(),activeMs:T.number().int().nonnegative().optional(),inactiveMs:T.number().int().nonnegative().optional()}),f0=T.uuid().optional(),HJ=T.object({user:S0,activity:E0,metrics:v0,time:y0.optional(),runId:f0});var XJ=R("activity:record");class WJ extends Error{code="VALIDATION_ERROR";details;constructor($,J){super($);this.name="ActivityRecordValidationError",this.details=J}}class m8 extends Error{code="COURSE_ERROR";constructor($){super($);this.name="ActivityRecordCourseError"}}function g0($){let J=$.time?.endedAt?typeof $.time.endedAt==="string"?$.time.endedAt:$.time.endedAt.toISOString():new Date().toISOString();return{id:$.activity.id,name:$.activity.name,course:$.activity.course,endedAt:J,metrics:{totalQuestions:$.metrics.totalQuestions,correctQuestions:$.metrics.correctQuestions,xpEarned:$.metrics.xpEarned,masteredUnits:$.metrics.masteredUnits},pctComplete:$.metrics.pctComplete}}function d0($,J){let Z=$.time,K=Z.activeMs??0,H=Z.inactiveMs??0,W;if(Z.startedAt)W=typeof Z.startedAt==="string"?Z.startedAt:Z.startedAt.toISOString();else if(Z.activeMs!==void 0||Z.inactiveMs!==void 0){let F=new Date(J),_=K+H;W=new Date(F.getTime()-_).toISOString()}else W=J;return{id:$.activity.id,name:$.activity.name,course:$.activity.course,startedAt:W,endedAt:J,elapsedMs:K,pausedMs:H}}function m0($,J,Z){let K;try{K=U2($.courses,J)}catch(W){if(W instanceof Q2)throw new m8(W.code==="unknown_course"?`Unknown course: ${JSON.stringify(J)}`:"Ambiguous course selector in timeback.config.json");throw W}let H=h2($,K,Z);if(!H)throw new m8(`Course "${JSON.stringify(J)}" has no sensor configured.`);return{course:K,sensor:H}}var l0={recordCompletion:n2,sendTimeSpent:j$};function l8($,J=l0){return async(Z)=>{let K=HJ.safeParse(Z);if(!K.success)throw XJ.warn("Invalid record input",{error:K.error.flatten()}),new WJ("Invalid activity record input",K.error.flatten());let H=K.data,{course:W,sensor:F}=m0($.appConfig,H.activity.course,$.env),_=g0(H),O={env:$.env,api:$.api,appConfig:$.appConfig,getClient:$.getClient,hooks:$.hooks};if(await J.recordCompletion(O,{userInfo:{email:H.user.email,timebackId:H.user.timebackId},payload:_,course:W,sensor:F,preview:!1,runId:H.runId}),H.time){let w=d0(H,_.endedAt);await J.sendTimeSpent(O,{userInfo:{email:H.user.email,timebackId:H.user.timebackId},payload:w,course:W,sensor:F,runId:H.runId})}XJ.debug("Recorded activity",{activityId:H.activity.id,hasTime:!!H.time})}}var x8=R("user:verify");function u8($){return async(J)=>{x8.debug("Verifying user by email");let Z=$.getClient();try{let K=await G2({email:J,client:Z});return x8.debug("User verified",{timebackId:K}),{verified:!0,timebackId:K}}catch(K){if(K instanceof d){if(K.code==="timeback_user_not_found")return x8.debug("User not found in Timeback"),{verified:!1};throw K}let H=K instanceof Error?K.message:"Unknown error";throw x8.error("Failed to verify user",{error:H}),K}}}var c8=R("user:getProfile");function p8($){return async(J)=>{c8.debug("Building user profile by email");let Z=$.getClient(),K=u($.env);try{let H=await _2({env:$.env,apiCredentials:$.api,userInfo:{sub:J,email:J},client:Z}),W=await _8(Z,H,$.appConfig,K);return c8.debug("User profile built",{userId:W.id}),W}catch(H){if(H instanceof d)throw H;let W=H instanceof Error?H.message:"Unknown error";throw c8.error("Failed to build user profile",{error:W}),H}}}async function c0($){let{loadConfig:J}=await import("./chunk-k51p29gg.js");return await J($)}function p0($){return $.map((J)=>{if(J.grade!==void 0)return J;if(J.courseCode)return J;throw Error(`Invalid course config: missing both grade and courseCode for subject "${J.subject}"`)})}async function BJ($){if(!globalThis.process?.versions?.node&&!globalThis.Bun)throw Error("createTimeback() requires Node.js or Bun — it reads timeback.config.json from the filesystem. "+"For edge runtimes (Cloudflare Workers, Vercel Edge, etc.), use createTimebackIdentity() from '@timeback/sdk' instead.");YJ({logger:$.logger,logLevel:$.logLevel});let J=QJ($.env),Z=await c0({configPath:$.configPath});if(!Z.success)throw Error(`Failed to load timeback config: ${Z.error}`);let K=Z.config,H,W=()=>{if(!H)H=new u0({env:u(J),auth:{clientId:$.api.clientId,clientSecret:$.api.clientSecret}});return H},F=$.hooks,_=(j,A)=>GJ(j,F,A),O={env:J,identity:$.identity,appConfig:{name:K.name,sensor:K.sensor,launchUrl:K.launchUrl,courses:p0(K.courses)},api:$.api,getClient:W,hooks:F},w={env:J,identity:$.identity,api:{credentials:$.api,getClient:W}};return{config:$,handle:{activity:{heartbeat:_("activity.heartbeat",e2(O)),submit:_("activity.submit",r2(O))},identity:{signIn:_("identity.signIn",J8(w)),callback:_("identity.callback",Z8(w)),signOut:K8()},lessons:{list:_("lessons.list",Y8(O)),start:_("lessons.start",G8(O)),next:_("lessons.next",Q8(O)),submit:_("lessons.submit",B8(O)),complete:_("lessons.complete",W8(O)),attempts:_("lessons.attempts",X8(O)),attemptDetails:_("lessons.attemptDetails",H8(O))},user:{me:_("user.me",F8(O)),verify:_("user.verify",O8(O))}},activity:{record:l8({...O})},lessons:m({...O}),user:{verify:u8({...O}),getProfile:p8({...O})},get api(){return W()},close(){if(H)H.close(),H=void 0}}}import{TimebackClient as xH}from"@timeback/core";import{ApiError as wH,ForbiddenError as UH,isApiError as MH,NotFoundError as LH,UnauthorizedError as jH,ValidationError as VH}from"@timeback/core";export{i0 as toNativeHandler,MH as isApiError,_J as createTimebackIdentity,BJ as createTimeback,VH as ValidationError,jH as UnauthorizedError,xH as TimebackClient,a0 as ROUTES,LH as NotFoundError,UH as ForbiddenError,wH as ApiError};
1
+ import"./chunk-ae6bkfs5.js";import{a as E,b as Q$,c as G$}from"./chunk-25502p3e.js";import{e as A$,f as z$,g as P$,h as T$,i as R$,j as N$,k as _J}from"./chunk-6nybr8hs.js";import{l as i0}from"./server/adapters/native.js";import{m as d,n as B2,o as _2,p as G2,q as o2,r as h2,s as GJ}from"./chunk-bh0ewh45.js";import{t as YJ,u as R,v as M2,w as k$,y as q$,z as C$}from"./chunk-nw6brg34.js";import"./chunk-3pf3cpfk.js";import{G as y8,H as D$,I as S2,J as u,K as QJ,L as P,M,N as $8,Q as a0}from"./chunk-dbcsf5tk.js";import{R as w8,U as U8}from"./chunk-1s709w5e.js";import{TimebackClient as u0}from"@timeback/core";import{getServiceUrlsForEnv as x0}from"@timeback/core";class s extends Error{statusCode;response;name="ApiError";constructor($,J,Z){super($);this.statusCode=J,this.response=Z}get minorCodes(){let $=this.response;if(!$?.imsx_CodeMinor?.imsx_codeMinorField)return[];return $.imsx_CodeMinor.imsx_codeMinorField.map((J)=>({field:J.imsx_codeMinorFieldName,value:J.imsx_codeMinorFieldValue}))}get details(){return this.response?.imsx_error_details??[]}}class t8 extends s{name="UnauthorizedError";constructor($="Unauthorized",J){super($,401,J)}}class e8 extends s{name="ForbiddenError";constructor($="Forbidden",J){super($,403,J)}}class $9 extends s{name="NotFoundError";constructor($="Not Found",J){super($,404,J)}}class J9 extends s{name="ValidationError";constructor($="Validation Error",J){super($,422,J)}}class Z9 extends s{name="InputValidationError";issues;constructor($,J){let Z={imsx_codeMajor:"failure",imsx_severity:"error",imsx_description:$,imsx_error_details:J.map((K)=>({path:K.path,message:K.message}))};super($,400,Z);this.issues=J}}function T2($,J){return new Z9($,J)}function OJ($){if(!($ instanceof Error))return!1;return"statusCode"in $&&"response"in $}var xJ="BEYOND_AI",K9="LEARNWITH_AI",H9=xJ,DJ={staging:"https://staging-beyond-timeback-api-2-idp.auth.us-east-1.amazoncognito.com/oauth2/token",production:"https://prod-beyond-timeback-api-2-idp.auth.us-east-1.amazoncognito.com/oauth2/token"},wJ={staging:"https://api.staging.alpha-1edtech.ai",production:"https://api.alpha-1edtech.ai"},UJ={staging:"https://caliper.staging.alpha-1edtech.ai",production:"https://caliper.alpha-1edtech.ai"},MJ={staging:"https://qti.alpha-1edtech.ai/api",production:"https://qti.alpha-1edtech.ai/api"},LJ={staging:"https://platform.dev.timeback.com/auth/1.0/token",production:"https://platform.timeback.com/auth/1.0/token"},jJ={staging:"https://platform.dev.timeback.com",production:"https://platform.timeback.com"},VJ={staging:"https://platform.dev.timeback.com",production:"https://platform.timeback.com"},kJ={staging:"https://platform.dev.timeback.com",production:"https://platform.timeback.com"},qJ={BEYOND_AI:{token:DJ,tokenScope:void 0,api:wJ,caliper:UJ,qti:MJ},LEARNWITH_AI:{token:LJ,tokenScope:"https://purl.imsglobal.org/spec/caliper/v1p2/scope/events.write",api:jJ,caliper:VJ,qti:kJ}},CJ={tsc:"tsc",nativePreview:"@typescript/native-preview"},r0={package:CJ.nativePreview,bin:"tsgo"},e=null,M8=!1,L8=!1;function i8($){let Z=$.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${Z}$`)}function AJ(){if(e!==null)return;if(e=[],typeof process>"u"||!process.env?.DEBUG){L8=!1;return}L8=!0;let $=process.env.DEBUG.trim();if($==="1"||$==="true"||$==="*"){M8=!0;return}let J=$.split(",").map((K)=>K.trim()).filter(Boolean);for(let K of J)if(K.startsWith("-"))e.push({regex:i8(K.slice(1)),exclude:!0});else e.push({regex:i8(K),exclude:!1});if(!e.some((K)=>!K.exclude)&&e.length>0)M8=!0}function zJ($){if(AJ(),!L8)return!0;if(M8){if($){for(let J of e)if(J.exclude&&J.regex.test($))return!1}return!0}if(!$)return!1;for(let J of e)if(J.exclude&&J.regex.test($))return!1;for(let J of e)if(!J.exclude&&J.regex.test($))return!0;return!1}function X9(){return typeof globalThis<"u"&&"window"in globalThis}function PJ(){if(X9())return"browser";if(typeof process<"u"&&process.env){if(process.env.CI||process.env.GITHUB_ACTIONS||process.env.GITLAB_CI||process.env.CIRCLECI||process.env.JENKINS_URL||process.env.BUILDKITE)return"ci"}return"terminal"}var j8;if(!X9())try{j8=(await import("./chunk-kkajswjx.js")).inspect}catch{}var $2={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",red:"\x1B[31m",yellow:"\x1B[33m",blue:"\x1B[34m",cyan:"\x1B[36m"};function TJ($){switch($){case"debug":return $2.blue;case"info":return $2.cyan;case"warn":return $2.yellow;case"error":return $2.red}}function RJ($){switch($){case"debug":return console.debug;case"info":return console.info;case"warn":return console.warn;case"error":return console.error}}function NJ($){if(j8)return j8($,{depth:null,colors:!0,breakLength:80,compact:!1});return JSON.stringify($,null,2)}var IJ=($)=>{let J=TJ($.level),Z=RJ($.level),K=$.level.toUpperCase().padEnd(5),H=$.timestamp.toISOString().replace(/\.\d{3}Z$/,""),W=`${$2.dim}[${H}]${$2.reset}`,F=`${J}${K}${$2.reset}`,_=$.scope?`${$2.bold}[${$.scope}]${$2.reset} `:"",O=`${W} ${F} ${_}${$.message}`;if($.context&&Object.keys($.context).length>0)Z(O,NJ($.context));else Z(O)},bJ={debug:"[DEBUG]",info:"[INFO]",warn:"[WARN]",error:"[ERROR]"};function hJ($){return Object.entries($).map(([J,Z])=>`${J}=${SJ(Z)}`).join(" ")}function SJ($){if(typeof $==="string")return $;if(typeof $==="number")return String($);if(typeof $==="boolean")return String($);if($===null)return"null";if($===void 0)return"undefined";return JSON.stringify($)}var EJ=($)=>{let J=[];if(J.push($.timestamp.toISOString()),J.push(bJ[$.level]),$.scope)J.push(`[${$.scope}]`);if(J.push($.message),$.context&&Object.keys($.context).length>0)J.push(hJ($.context));console.log(J.join(" "))},vJ=($)=>{let J={timestamp:$.timestamp.toISOString(),level:$.level,...$.scope&&{scope:$.scope},msg:$.message};if($.context&&Object.keys($.context).length>0)Object.assign(J,$.context);console.log(JSON.stringify(J))},yJ={debug:"color: gray",info:"color: #0ea5e9",warn:"color: #f59e0b",error:"color: #ef4444; font-weight: bold"},fJ={debug:"log",info:"info",warn:"warn",error:"error"},gJ=($)=>{let J=fJ[$.level],Z=yJ[$.level],H=`%c${$.scope?`[${$.scope}]`:""} ${$.message}`;if($.context&&Object.keys($.context).length>0)console[J](H,Z,$.context);else console[J](H,Z)},s8=["debug","info","warn","error"];function dJ($){switch($){case"terminal":return IJ;case"ci":return EJ;case"production":return vJ;case"browser":return gJ;case"test":return()=>{}}}function mJ(){if(typeof process<"u"&&process.env?.DEBUG)return"debug";return"info"}function lJ($,J){return s8.indexOf($)>=s8.indexOf(J)}class g2{scope;minLevel;environment;formatter;defaultContext;constructor($={}){this.scope=$.scope,this.minLevel=$.minLevel??mJ(),this.defaultContext=$.defaultContext??{},this.environment=$.environment??PJ(),this.formatter=dJ(this.environment)}child($){let J=this.scope?`${this.scope}:${$}`:$;return new g2({scope:J,minLevel:this.minLevel,environment:this.environment,defaultContext:{...this.defaultContext}})}withContext($){return new g2({scope:this.scope,minLevel:this.minLevel,environment:this.environment,defaultContext:{...this.defaultContext,...$}})}debug($,J){this.log("debug",$,J)}info($,J){this.log("info",$,J)}warn($,J){this.log("warn",$,J)}error($,J){this.log("error",$,J)}log($,J,Z){if($==="debug"&&!zJ(this.scope))return;if(!lJ($,this.minLevel))return;let K={level:$,message:J,scope:this.scope,context:Z||Object.keys(this.defaultContext).length>0?{...this.defaultContext,...Z}:void 0,timestamp:new Date};this.formatter(K)}}function W9($={}){return new g2($)}function uJ(){try{let $=typeof process>"u"?void 0:process.env.DEBUG;return $==="1"||$==="true"}catch{return!1}}var j2=W9({scope:"auth",minLevel:uJ()?"debug":"warn"});class d2{config;accessToken=null;tokenExpiry=0;pendingRequest=null;fetchFn;constructor($){this.config=$,this.fetchFn=$.fetch??globalThis.fetch.bind(globalThis)}async getToken(){if(this.accessToken&&Date.now()<this.tokenExpiry)return j2.debug("Using cached token"),this.accessToken;if(this.pendingRequest)return j2.debug("Waiting for in-flight token request"),this.pendingRequest;this.pendingRequest=this.fetchToken();try{return await this.pendingRequest}finally{this.pendingRequest=null}}async fetchToken(){j2.debug("Fetching new access token...");let{clientId:$,clientSecret:J}=this.config.credentials,Z=btoa(`${$}:${J}`),K=performance.now(),H=await this.fetchFn(this.config.tokenUrl,{method:"POST",headers:{Authorization:`Basic ${Z}`,"Content-Type":"application/x-www-form-urlencoded"},body:this.config.scope?`grant_type=client_credentials&scope=${encodeURIComponent(this.config.scope)}`:"grant_type=client_credentials"}),W=Math.round(performance.now()-K);if(!H.ok)throw j2.error(`Token request failed: ${H.status} ${H.statusText}`),Error(`Failed to obtain access token: ${H.status} ${H.statusText}`);let F=await H.json();return this.accessToken=F.access_token,this.tokenExpiry=Date.now()+(F.expires_in-60)*1000,j2.debug(`Token acquired (${W}ms, expires in ${F.expires_in}s)`),this.accessToken}invalidate(){j2.debug("Token invalidated"),this.accessToken=null,this.tokenExpiry=0}}var m2={caliper:{send:"/caliper/event",validate:"/caliper/event/validate",list:"/caliper/events",get:"/caliper/events/{id}",jobStatus:"/jobs/{id}/status"},oneroster:{rostering:"/ims/oneroster/rostering/v1p2",gradebook:"/ims/oneroster/gradebook/v1p2",resources:"/ims/oneroster/resources/v1p2"},edubridge:{base:"/edubridge"},powerpath:{base:"/powerpath"},clr:{credentials:"/ims/clr/v2p0/credentials",discovery:"/ims/clr/v2p0/discovery"},case:{base:"/ims/case/v1p1"},webhooks:{webhookList:"/webhooks/",webhookGet:"/webhooks/{id}",webhookCreate:"/webhooks/",webhookUpdate:"/webhooks/{id}",webhookDelete:"/webhooks/{id}",webhookActivate:"/webhooks/{id}/activate",webhookDeactivate:"/webhooks/{id}/deactivate",webhookFilterList:"/webhook-filters/",webhookFilterGet:"/webhook-filters/{id}",webhookFilterCreate:"/webhook-filters/",webhookFilterUpdate:"/webhook-filters/{id}",webhookFilterDelete:"/webhook-filters/{id}",webhookFiltersByWebhook:"/webhook-filters/webhook/{webhookId}"}},cJ={caliper:{send:"/caliper/v1p2",validate:null,list:null,get:null,jobStatus:null},oneroster:{rostering:"/rostering/1.0",gradebook:"/gradebook/1.0",resources:"/resources/1.0"},webhooks:null,edubridge:null,powerpath:null,clr:null,case:{base:"/case/1.1"}},Y9={BEYOND_AI:m2,LEARNWITH_AI:cJ};function pJ($){return"env"in $&&!("baseUrl"in $)&&!("services"in $)}function aJ($){return"baseUrl"in $&&!("services"in $)}function iJ($){return"services"in $}function o8($,J){let Z=$?Y9[$]??m2:m2;return{caliper:J?.caliper??Z.caliper,oneroster:J?.oneroster??Z.oneroster,webhooks:J?.webhooks??Z.webhooks,edubridge:J?.edubridge??Z.edubridge,powerpath:J?.powerpath??Z.powerpath,clr:J?.clr??Z.clr,case:J?.case??Z.case}}class R2{platform;env;auth;timeout;endpoints;authUrl;tokenScope;pathProfiles;tokenManagers=new Map;constructor($){if(this.timeout=$.timeout??30000,pJ($)){this.auth=$.auth;let J=$.platform??H9,Z=$.env;this.platform=J,this.env=Z;let K=qJ[J];if(!K)throw Error(`Unknown platform: ${J}`);this.authUrl=K.token[Z],this.tokenScope=K.tokenScope??void 0,this.pathProfiles=Y9[J]??m2,this.endpoints={oneroster:{baseUrl:K.api[Z],authUrl:this.authUrl},edubridge:{baseUrl:K.api[Z],authUrl:this.authUrl},powerpath:{baseUrl:K.api[Z],authUrl:this.authUrl},clr:{baseUrl:K.api[Z],authUrl:this.authUrl},case:{baseUrl:K.api[Z],authUrl:this.authUrl},caliper:{baseUrl:K.caliper[Z],authUrl:this.authUrl},webhooks:{baseUrl:K.caliper[Z],authUrl:this.authUrl},qti:{baseUrl:K.qti[Z],authUrl:this.authUrl}}}else if(aJ($))this.auth=$.auth,this.authUrl=$.authUrl,this.pathProfiles=o8($.pathProfile,$.paths),this.endpoints={oneroster:{baseUrl:$.baseUrl,authUrl:this.authUrl},edubridge:{baseUrl:$.baseUrl,authUrl:this.authUrl},powerpath:{baseUrl:$.baseUrl,authUrl:this.authUrl},clr:{baseUrl:$.baseUrl,authUrl:this.authUrl},case:{baseUrl:$.baseUrl,authUrl:this.authUrl},caliper:{baseUrl:$.baseUrl,authUrl:this.authUrl},webhooks:{baseUrl:$.baseUrl,authUrl:this.authUrl},qti:{baseUrl:$.baseUrl,authUrl:this.authUrl}};else if(iJ($)){this.auth=$.auth,this.authUrl=$.authUrl,this.pathProfiles=o8($.pathProfile,$.paths),this.endpoints={};for(let[J,Z]of Object.entries($.services))if(Z)this.endpoints[J]={baseUrl:Z,authUrl:this.authUrl}}else throw Error("Invalid provider configuration");for(let J of Object.keys(this.pathProfiles))if(this.pathProfiles[J]===null)delete this.endpoints[J]}getEndpoint($){let J=this.endpoints[$];if(!J){let Z=$;if(Z in this.pathProfiles&&this.pathProfiles[Z]===null)throw Error(`Service "${$}" is not supported on ${this.platform??"this"} platform.`);throw Error(`Service "${$}" is not configured in this provider`)}return J}hasService($){return $ in this.endpoints}getAvailableServices(){return Object.keys(this.endpoints)}getTokenUrl(){return this.authUrl}getEndpointWithPaths($){let J=this.getEndpoint($),Z=this.getServicePaths($);return{...J,paths:Z}}getPaths(){return this.pathProfiles}getServicePaths($){let J=this.pathProfiles[$];if(!J)throw Error(`Service "${$}" is not supported on ${this.platform??"this"} platform.`);return J}hasServiceSupport($){return this.pathProfiles[$]!==null}getTokenProvider($){let J=this.getEndpoint($),{authUrl:Z}=J;if(!Z)return;if(!this.auth)throw Error(`Service "${$}" requires authentication but no credentials were provided`);let K=this.tokenManagers.get(Z);if(!K)K=new d2({tokenUrl:Z,credentials:{clientId:this.auth.clientId,clientSecret:this.auth.clientSecret},scope:this.tokenScope}),this.tokenManagers.set(Z,K);return K}async checkAuth(){if(!this.authUrl||!this.auth)throw Error("No auth configured on this provider");let $=Date.now(),J=this.tokenManagers.get(this.authUrl);if(!J)J=new d2({tokenUrl:this.authUrl,credentials:{clientId:this.auth.clientId,clientSecret:this.auth.clientSecret},scope:this.tokenScope}),this.tokenManagers.set(this.authUrl,J);try{return await J.getToken(),{ok:!0,latencyMs:Date.now()-$,checks:{tokenAcquisition:!0}}}catch(Z){return{ok:!1,latencyMs:Date.now()-$,error:Z instanceof Error?Z.message:String(Z),checks:{tokenAcquisition:!1}}}}invalidateTokens(){for(let $ of this.tokenManagers.values())$.invalidate?.();this.tokenManagers.clear()}}function b($){try{if(typeof process>"u")return;if(typeof $==="string")return process.env[$];for(let J of $){let Z=process.env[J];if(Z!==void 0)return Z}return}catch{return}}function F2(){let $=b("DEBUG");return $==="1"||$==="true"}function sJ(){return Math.random().toString(16).slice(2,10)}function V8($){return W9({scope:$,minLevel:F2()?"debug":"warn"})}var l2={defaultPlatform:H9,templates:{BEYOND_AI:{staging:{platform:"BEYOND_AI",env:"staging"},production:{platform:"BEYOND_AI",env:"production"}},LEARNWITH_AI:{staging:{platform:"LEARNWITH_AI",env:"staging"},production:{platform:"LEARNWITH_AI",env:"production"}}}};function oJ($){if(typeof $==="string")return $;if($.length===0)throw Error(`Missing env var key: ${$}`);return $[0]}function O2($){return oJ($)}function Q9($){if($!=="staging"&&$!=="production")throw Error(`Invalid env "${$}": must be "staging" or "production"`);return $}function G9($,J){let Z=$?.clientId??b(J.clientId),K=$?.clientSecret??b(J.clientSecret);if(!Z)throw Error(`Missing clientId: provide in config or set ${O2(J.clientId)}`);if(!K)throw Error(`Missing clientSecret: provide in config or set ${O2(J.clientSecret)}`);return{clientId:Z,clientSecret:K}}function nJ($,J,Z){if(!Z)return;return G9($,J)}function rJ($){let J=b($.baseUrl),Z=b($.authUrl),K=b($.clientId),H=b($.clientSecret);if(J===void 0&&K===void 0)return`Missing env: provide in config or set ${O2($.env??$.baseUrl)}`;let W=[];if(J===void 0)W.push(O2($.env??$.baseUrl));if(J!==void 0&&Z===void 0)W.push(O2($.authUrl));if(K===void 0)W.push(O2($.clientId));if(H===void 0)W.push(O2($.clientSecret));return`Missing environment variables: ${W.join(", ")}`}var tJ={name:"transport",matches($){return"transport"in $&&!!$.transport},resolve($){return{mode:"transport",transport:$.transport}}},eJ={name:"provider",matches($){return"provider"in $&&!!$.provider},resolve($){return{mode:"provider",provider:$.provider}}},$Z={name:"env-config",matches($){return"env"in $},resolve($,J,Z){let K=$,H=Q9(K.env),W=G9(K.auth,J),F=K.platform??Z.defaultPlatform,_=Z.templates[F];if(!_){let w=Object.keys(Z.templates).join(", ");throw Error(`Unknown platform "${F}": available platforms are ${w}`)}let O=_[H];if(!O){let w=Object.keys(_).join(", ");throw Error(`Unknown env "${H}" for platform "${F}": available environments are ${w}`)}return{mode:"provider",provider:new R2({platform:O.platform,env:O.env,auth:W,timeout:K.timeout})}}},JZ={name:"explicit-config",matches($){return"baseUrl"in $},resolve($,J){let Z=$,K=Z.authUrl??Z.auth?.authUrl,H=!!K,W=nJ(Z.auth,J,H);return{mode:"provider",provider:new R2({baseUrl:Z.baseUrl,authUrl:K,auth:W,timeout:Z.timeout,pathProfile:Z.pathProfile,paths:Z.paths})}}},ZZ={name:"env-fallback-platform",matches($,J){if(Object.keys($).length>0)return!1;let Z=J.env?b(J.env):void 0,K=b(J.clientId),H=b(J.clientSecret);return Z!==void 0&&K!==void 0&&H!==void 0},resolve($,J,Z){let K=Q9(b(J.env)),H=b(J.clientId),W=b(J.clientSecret),F=Z.defaultPlatform,_=Z.templates[F]?.[K];if(!_)throw Error(`Unknown env "${K}" for platform "${F}"`);return{mode:"provider",provider:new R2({platform:_.platform,env:_.env,auth:{clientId:H,clientSecret:W}})}}},KZ={name:"env-fallback-explicit",matches($,J){if(Object.keys($).length>0)return!1;let Z=b(J.baseUrl),K=b(J.authUrl),H=b(J.clientId),W=b(J.clientSecret);return Z!==void 0&&K!==void 0&&H!==void 0&&W!==void 0},resolve($,J){let Z=b(J.baseUrl),K=b(J.authUrl),H=b(J.clientId),W=b(J.clientSecret);return{mode:"provider",provider:new R2({baseUrl:Z,authUrl:K,auth:{clientId:H,clientSecret:W}})}}},HZ={name:"token-provider",matches($){return"tokenProvider"in $},resolve(){throw Error("TokenProvider mode is not supported with provider pattern. Use { provider: TimebackProvider } or { env, auth } instead.")}},XZ=[tJ,eJ,$Z,HZ,JZ,ZZ,KZ];function B9($,J,Z=l2){for(let K of XZ)if(K.matches($,J))return K.resolve($,J,Z);throw Error(rJ(J))}var D8=3,WZ=[429,503],n8=1000;class k8{config;log;constructor($){let{config:J,logger:Z}=$,K=J.fetch??globalThis.fetch.bind(globalThis),H;if("tokenProvider"in J&&J.tokenProvider)H=J.tokenProvider;else if("auth"in J&&J.auth)H=new d2({tokenUrl:J.auth.authUrl,credentials:{clientId:J.auth.clientId,clientSecret:J.auth.clientSecret},fetch:K});let W=J.baseUrl.endsWith("/")?J.baseUrl:`${J.baseUrl}/`;this.config={baseUrl:W,timeout:J.timeout??30000,fetch:K,tokenProvider:H},this.log=Z.child("http")}get baseUrl(){return this.config.baseUrl}async request($,J={}){let Z=await this.requestRaw($,J);return this.handleResponse(Z)}async exists($,J={}){try{return await this.requestRaw($,J),!0}catch(Z){if(OJ(Z)&&Z.statusCode===404)return!1;throw Z}}async requestRaw($,J={}){let{method:Z="GET",params:K,body:H,headers:W={}}=J,F=this.buildUrl($,K),_=J.requestId??sJ(),w=Date.now()+this.config.timeout;for(let j=0;j<D8;j++){let A=w-Date.now();if(A<=0)throw this.log.error("Request timeout before attempt",F2()?{requestId:_,path:$}:{path:$}),new s("Request timeout",408);let C=await this.getAccessToken(),q=j===D8-1,z=performance.now();this.log.debug(`→ ${Z} ${F}`,{requestId:_,attempt:j>0?j+1:void 0});let N={"Content-Type":"application/json",Accept:"application/json","X-Request-ID":_,...W};if(C)N.Authorization=`Bearer ${C}`;let I=await this.config.fetch(F,{method:Z,headers:N,body:H?JSON.stringify(H):void 0,signal:AbortSignal.timeout(Math.min(A,this.config.timeout))}),r=Math.round(performance.now()-z);if(this.log.debug(`← ${I.status} ${I.statusText} (${r}ms)`,{requestId:_}),WZ.includes(I.status)&&!q){let v2=I.headers.get("Retry-After"),p=this.parseRetryAfter(v2,j),a8=w-Date.now();if(p>=a8)throw this.log.error("Request timeout during retry backoff",F2()?{requestId:_,path:$}:{path:$}),new s("Request timeout",408);this.log.warn(`Retrying in ${p}ms (attempt ${j+1}/${D8})`,{...F2()&&{requestId:_},status:I.status}),await this.sleep(p);continue}if(!I.ok)return this.handleErrorResponse(I,_);return I}throw this.log.error("Max retries exceeded",F2()?{requestId:_,path:$}:{path:$}),new s("Max retries exceeded")}getAccessToken(){if(!this.config.tokenProvider)return Promise.resolve(void 0);return this.config.tokenProvider.getToken()}buildUrl($,J){if(/^[a-z][a-z0-9+.-]*:/i.test($))throw Error(`Absolute URLs are not allowed in path: ${$}. Use relative paths only.`);let Z=$.startsWith("/")?$.slice(1):$,K=new URL(Z,this.config.baseUrl);if(J){for(let[H,W]of Object.entries(J))if(W!==void 0)K.searchParams.set(H,String(W))}return K.toString()}async handleResponse($){if(!$.ok)await this.handleErrorResponse($);if($.status===204)return;if($.headers.get("content-length")==="0")return;return this.parseJsonResponse($)}async parseJsonResponse($){let J=await $.text();if(!J||J.trim()==="")return;try{return JSON.parse(J)}catch(Z){let K=J.length>200?J.slice(0,200)+"...":J,H=Z instanceof Error?Z.message:String(Z),W=$.url||"unknown";throw this.log.error("Failed to parse JSON response",{url:W,status:$.status,contentType:$.headers.get("content-type"),bodyPreview:K,error:H}),new s(`Invalid JSON response from ${W}`,$.status,{parseError:H,body:K})}}async handleErrorResponse($,J){let Z,K=await $.text().catch(()=>"");if(K)try{Z=JSON.parse(K)}catch(W){let F=W instanceof Error?W.message:"Unknown parse error";Z={rawBody:K.slice(0,500),parseError:F},this.log.warn("Failed to parse error response as JSON",{...F2()&&{requestId:J},url:$.url,status:$.status,parseError:F,bodyPreview:K.slice(0,200)})}let H=this.extractErrorMessage(Z,$.statusText);if($.status!==404)this.log.error(`Request failed: ${$.status} ${H}`,F2()?{requestId:J}:void 0);switch($.status){case 401:throw this.config.tokenProvider?.invalidate?.(),new t8(H,Z);case 403:throw new e8(H,Z);case 404:throw new $9(H,Z);case 422:throw new J9(H,Z);default:throw new s(H,$.status,Z)}}extractErrorMessage($,J){if(typeof $==="object"&&$!==null){let Z=$;if(typeof Z.message==="string")return Z.message;if(typeof Z.error==="string")return Z.error;if(typeof Z.imsx_description==="string")return Z.imsx_description}return J}sleep($){return new Promise((J)=>{setTimeout(J,$)})}parseRetryAfter($,J){if(!$)return n8*Math.pow(2,J);let Z=parseInt($,10);if(!isNaN(Z))return Z*1000;let K=Date.parse($);if(!isNaN(K)){let H=K-Date.now();return Math.max(0,H)}return n8*Math.pow(2,J)}}function YZ($){if($ instanceof Date)return $.toISOString();if(typeof $==="boolean")return $?"true":"false";if(typeof $==="number")return String($);return $.replaceAll("'","''")}function t($){let J=YZ($);return typeof $==="string"||$ instanceof Date?`'${J}'`:J}function QZ($,J){if(typeof J==="string"||typeof J==="number"||typeof J==="boolean"||J instanceof Date)return[`${$}=${t(J)}`];if(typeof J==="object"&&J!==null){let Z=J,K=[];if(Z.ne!==void 0)K.push(`${$}!=${t(Z.ne)}`);if(Z.gt!==void 0)K.push(`${$}>${t(Z.gt)}`);if(Z.gte!==void 0)K.push(`${$}>=${t(Z.gte)}`);if(Z.lt!==void 0)K.push(`${$}<${t(Z.lt)}`);if(Z.lte!==void 0)K.push(`${$}<=${t(Z.lte)}`);if(Z.contains!==void 0)K.push(`${$}~${t(Z.contains)}`);if(Z.in!==void 0&&Z.in.length>0){let H=Z.in.map((F)=>`${$}=${t(F)}`),W=H.join(" OR ");K.push(H.length>1?`(${W})`:W)}if(Z.notIn!==void 0&&Z.notIn.length>0){let H=Z.notIn.map((W)=>`${$}!=${t(W)}`);K.push(H.join(" AND "))}return K}return[]}function GZ($){return"OR"in $&&Array.isArray($.OR)}function _9($){if(GZ($)){let Z=$.OR.map((K)=>_9(K)).filter((K)=>K!==void 0);return Z.length>0?Z.join(" OR "):void 0}let J=[];for(let[Z,K]of Object.entries($))if(K!==void 0)J.push(...QZ(Z,K));return J.length>0?J.join(" AND "):void 0}var r8=100,BZ=1e4;class q8{fetcher;path;params;max;unwrapKey;log;transform;paginationStyle;constructor($){this.fetcher=$.fetcher,this.path=$.path,this.params=$.params??{},this.max=$.max,this.unwrapKey=$.unwrapKey,this.log=$.logger?.child("pagination")??V8("pagination"),this.transform=$.transform,this.paginationStyle=$.paginationStyle??"offset"}buildRequestParams($,J){let{where:Z,fields:K,offset:H,limit:W,...F}=this.params,_={...F,filter:Z?_9(Z):void 0,fields:K?.join(","),limit:$};if(this.paginationStyle==="page"){let O=Math.floor(J/$)+1;return{..._,page:O}}return{..._,offset:J}}extractItems($,J){let Z;if(this.unwrapKey)Z=$[this.unwrapKey]??[];else Z=$;return this.validateItems(Z,J)}validateItems($,J){if($===null||$===void 0)return this.log.warn(`Page ${J}: response data is ${$}, treating as empty`),[];if(!Array.isArray($))throw Error(`Expected array for page ${J}, got ${typeof $}. `+(this.unwrapKey?`Check unwrapKey '${this.unwrapKey}' is correct.`:""));return $}hasMorePages($,J,Z,K){if(J===0)return!1;let H=$.hasMore,W=$.total!==void 0&&Z+J<$.total;return H||W||J===K&&$.total===void 0}async*[Symbol.asyncIterator](){let $=this.params.offset??0,J=this.params.limit??r8,Z=!0,K=1,H=0;while(Z){this.log.debug(`Fetching page ${K} (offset: ${$}, limit: ${J})`);let W=await this.fetcher(this.path,{params:this.buildRequestParams(J,$)}),F=this.extractItems(W.data,K);this.log.debug(`Page ${K}: ${F.length} items`);for(let _ of F)if(yield this.transform?this.transform(_):_,H++,this.max!==void 0&&H>=this.max){this.log.debug(`Pagination complete: reached max of ${this.max} items`);return}Z=this.hasMorePages(W,F.length,$,J),$+=F.length,K++}this.log.debug(`Pagination complete: ${H} total items`)}async toArray($={}){let J=$.maxItems??BZ,Z=[];for await(let K of this){if(Z.length>=J)throw Error(`toArray() exceeded maxItems limit of ${J}. Use 'for await...of' to stream large datasets, or increase maxItems.`);Z.push(K)}return Z}async firstPage(){let $=this.params.limit??r8,J=this.params.offset??0,Z=await this.fetcher(this.path,{params:this.buildRequestParams($,J)}),K=this.extractItems(Z.data,1),H=this.transform?K.map(this.transform):K,W=this.hasMorePages(Z,H.length,J,$);return this.log.debug(`First page: ${H.length} items, total: ${Z.total}, hasMore: ${W}`),{data:H,hasMore:W,total:Z.total,nextOffset:W?J+H.length:void 0}}}function f2($,J){return{path:$,message:J}}function o($,J,Z){let K=$.safeParse(J);if(K.success)return K.data;let H=K.error.issues.map((W)=>({path:W.path.join(".")||"(root)",message:W.message}));throw T2(`Invalid ${Z} data`,H)}function u2($,J){if(typeof $!=="string"||$.trim()==="")throw T2(`Invalid ${J}`,[f2(J,"Must be a non-empty string")])}function C8($){if(!$)return;let J=[];if($.limit!==void 0){if(!Number.isInteger($.limit)||$.limit<=0)J.push(f2("limit","Must be a positive integer"))}if($.offset!==void 0){if(!Number.isInteger($.offset)||$.offset<0)J.push(f2("offset","Must be a non-negative integer"))}if($.max!==void 0){if(!Number.isInteger($.max)||$.max<=0)J.push(f2("max","Must be a positive integer"))}if(J.length>0)throw T2("Invalid list parameters",J)}var F9={baseUrl:["TIMEBACK_API_BASE_URL","TIMEBACK_BASE_URL","CALIPER_BASE_URL"],authUrl:["TIMEBACK_API_AUTH_URL","TIMEBACK_AUTH_URL","CALIPER_TOKEN_URL"],clientId:["TIMEBACK_API_CLIENT_ID","TIMEBACK_CLIENT_ID","CALIPER_CLIENT_ID"],clientSecret:["TIMEBACK_API_CLIENT_SECRET","TIMEBACK_CLIENT_SECRET","CALIPER_CLIENT_SECRET"]},V2="http://purl.imsglobal.org/ctx/caliper/v1p2",O9="QUESTION_RESULT";import{z as L}from"zod/v4";import{z as Y}from"zod/v4";import{z as J2}from"zod/v4";import{z as U}from"zod/v4";import{z as x}from"zod/v4";import{z as V}from"zod/v4";import{z as D}from"zod/v4";import{z as f}from"zod/v4";import{z as G}from"zod/v4";import{z as B}from"zod/v4";import{z as Q}from"zod/v4";var S=V8("caliper");class j9 extends k8{paths;constructor($){super({config:$,logger:S});this.paths=$.paths}async requestPaginated($,J={}){let Z=await this.request($,J),{events:K,pagination:H}=Z,F=(J.params?.offset??0)+K.length<H.total;return{data:K,hasMore:F,total:H.total}}}class V9 extends q8{constructor($,J,Z={}){C8(Z);let{max:K,...H}=Z;super({fetcher:(W,F)=>$.requestPaginated(W,F),path:J,params:H,max:K,logger:S})}}function A8($){let J=$.id??`urn:uuid:${crypto.randomUUID()}`,Z=$.metricsId??`urn:uuid:${crypto.randomUUID()}`;return{"@context":V2,id:J,type:"ActivityEvent",action:"Completed",actor:$.actor,object:$.object,eventTime:$.eventTime??new Date().toISOString(),profile:"TimebackProfile",generated:{id:Z,type:"TimebackActivityMetricsCollection",items:$.metrics,...$.attempt===void 0?{}:{attempt:$.attempt},...$.generatedExtensions?{extensions:$.generatedExtensions}:{}},extensions:$.extensions,...$.edApp===void 0?{}:{edApp:$.edApp},...$.session===void 0?{}:{session:$.session}}}function z8($){let J=$.id??`urn:uuid:${crypto.randomUUID()}`,Z=$.metricsId??`urn:uuid:${crypto.randomUUID()}`;return{"@context":V2,id:J,type:"TimeSpentEvent",action:"SpentTime",actor:$.actor,object:$.object,eventTime:$.eventTime??new Date().toISOString(),profile:"TimebackProfile",generated:{id:Z,type:"TimebackTimeSpentMetricsCollection",items:$.metrics},extensions:$.extensions,...$.edApp===void 0?{}:{edApp:$.edApp},...$.session===void 0?{}:{session:$.session}}}function _Z($){return{"@context":V2,id:$.id??`urn:uuid:${crypto.randomUUID()}`,type:"AssessmentItemEvent",action:"Started",profile:"AssessmentProfile",actor:$.actor,object:{...$.object,type:"AssessmentItem"},eventTime:$.eventTime??new Date().toISOString(),edApp:$.edApp,...$.session===void 0?{}:{session:$.session},...$.extensions===void 0?{}:{extensions:$.extensions}}}function FZ($){return{"@context":V2,id:$.id??`urn:uuid:${crypto.randomUUID()}`,type:"AssessmentItemEvent",action:"Completed",profile:"AssessmentProfile",actor:$.actor,object:{...$.object,type:"AssessmentItem"},eventTime:$.eventTime??new Date().toISOString(),edApp:$.edApp,...$.generated===void 0?{}:{generated:{...$.generated,type:"Response"}},...$.session===void 0?{}:{session:$.session},...$.extensions===void 0?{}:{extensions:$.extensions}}}function OZ($){let{id:J,...Z}=$.generated;return{"@context":V2,id:$.id??`urn:uuid:${crypto.randomUUID()}`,type:"GradeEvent",action:"Graded",profile:"GradingProfile",actor:$.actor,object:$.object,eventTime:$.eventTime??new Date().toISOString(),edApp:$.edApp,generated:{...Z,id:J??`urn:uuid:${crypto.randomUUID()}`,type:"Score",scoreType:O9},...$.session===void 0?{}:{session:$.session},...$.extensions===void 0?{}:{extensions:$.extensions}}}var xZ="http://purl.imsglobal.org/ctx/caliper/v1p2",DZ="urn:tag:auto-attach",X2={PERSON:"Person",ASSIGNABLE_DIGITAL_RESOURCE:"AssignableDigitalResource",ACTIVITY_METRIC:"ActivityMetric",TIME_SPENT_METRIC:"TimeSpentMetric",ACTIVITY_METRICS_COLLECTION:"ActivityMetricsCollection",TIME_SPENT_METRICS_COLLECTION:"TimeSpentMetricsCollection",COURSE_OFFERING:"CourseOffering",SOFTWARE_APPLICATION:"SoftwareApplication"},wZ=new Set(["ActivityEvent","TimeSpentEvent","AssignableEvent","ViewEvent"]);class k9{transformEnvelope($){let{data:J}=$;if(!Array.isArray(J))return $;let Z=J.map((K)=>x2(K)?UZ(K):K);return{...$,data:Z}}}function UZ($){let J={...$};if(!("@context"in J))J["@context"]=xZ;if(J.profile==="TimebackProfile")J.profile="AggregationProfile";if(x2(J.actor)&&J.actor.type==="TimebackUser")J.actor=MZ(J.actor);if(x2(J.object))J.object=LZ(J.object,J.type);if(x2(J.generated)){let Z=J.type;if(Z==="ActivityEvent")J.generated=jZ(J.generated);else if(Z==="TimeSpentEvent")J.generated=VZ(J.generated)}if(!J.session)J.session=DZ;return J}function MZ($){return{type:X2.PERSON,id:$.id}}function LZ($,J){if(!($.type==="TimebackActivityContext"&&J!==void 0&&wZ.has(J)))return{...$};let K={type:X2.ASSIGNABLE_DIGITAL_RESOURCE,id:$.id};if($.name)K.name=$.name;if(x2($.course)){let H={type:X2.COURSE_OFFERING,id:$.course.id};if($.course.name)H.name=$.course.name;K.isPartOf=H}if(x2($.app))K.extensions={app:{name:$.app.name,type:$.app.type??X2.SOFTWARE_APPLICATION}};return K}function q9($,J,Z,K){let W={id:typeof $?.id==="string"?$.id:`urn:uuid:${crypto.randomUUID()}`,type:J};if(Array.isArray($.items))W.items=$.items.map((F)=>{if(!x2(F))return F;let _=typeof F.type==="string"?F.type:"",O=_?_[0].toUpperCase()+_.slice(1):K;return{id:`urn:uuid:${crypto.randomUUID()}`,type:Z,metricType:O,metricValue:F.value}});for(let[F,_]of Object.entries($))if(F!=="id"&&F!=="type"&&F!=="items")W[F]=_;return W}function jZ($){return q9($,X2.ACTIVITY_METRICS_COLLECTION,X2.ACTIVITY_METRIC,"")}function VZ($){return q9($,X2.TIME_SPENT_METRICS_COLLECTION,X2.TIME_SPENT_METRIC,"Active")}function x2($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function kZ($,J=l2){return B9($,F9,J)}var qZ=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/,v=L.string().min(1).regex(qZ,"must be a valid ISO 8601 datetime"),q2=L.string().min(1).regex(/^\d{4}-\d{2}-\d{2}$/,"must be a valid ISO 8601 date (YYYY-MM-DD)"),X=L.string().trim().min(1),Z2=L.enum(["Reading","Language","Vocabulary","Social Studies","Writing","Science","FastMath","Math","None","Other"]).meta({id:"TimebackSubject",description:"Subject area"}),n=L.union([L.literal(-1),L.literal(0),L.literal(1),L.literal(2),L.literal(3),L.literal(4),L.literal(5),L.literal(6),L.literal(7),L.literal(8),L.literal(9),L.literal(10),L.literal(11),L.literal(12),L.literal(13)]).meta({id:"TimebackGrade",description:"Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"}),CZ=L.enum(["exempt","fully graded","not submitted","partially graded","submitted"]),AZ=L.enum(["department","school","district","local","state","national"]),C9=L.enum(["administrator","aide","guardian","parent","proctor","relative","student","teacher"]),zZ=L.enum(["administrator","proctor","student","teacher"]),PZ=L.enum(["qti","text","audio","video","interactive","visual","course-material","assessment-bank"]),TZ=L.enum(["qti-test","qti-question","qti-stimulus","qti-test-bank"]),RZ=L.enum(["unit","course","resource-collection"]),NZ=L.enum(["choice","order","associate","match","hotspot","hottext","select-point","graphic-order","graphic-associate","graphic-gap-match","text-entry","extended-text","inline-choice","upload","slider","drawing","media","custom"]),IZ=L.enum(["easy","medium","hard"]),bZ=L.array(L.object({source:L.string(),learningObjectiveIds:L.array(L.string())})),hZ=L.object({consecutive_failures:L.number().int().min(1).optional(),stagnation_limit:L.number().int().min(1).optional()}).optional(),H1=L.enum(["powerpath-100","quiz","test-out","placement","unit-test","alpha-read-article"]).nullable(),X1=L.object({imsx_codeMajor:L.enum(["failure","success"]),imsx_severity:L.enum(["error","warning","status"]),imsx_description:L.string(),imsx_CodeMinor:L.object({imsx_codeMinorField:L.array(L.object({imsx_codeMinorFieldName:L.string(),imsx_codeMinorFieldValue:L.string()}))}).optional()}),SZ=Y.union([Y.url(),Y.string().regex(/^urn:/,"Must be a URL or URN")]),D2=Y.object({id:Y.url(),type:Y.literal("TimebackUser"),email:Y.string()}),P8=Y.object({id:Y.url(),type:Y.literal("TimebackActivityContext"),subject:Z2,app:Y.object({name:Y.string()}),activity:Y.object({id:Y.url().optional(),name:Y.string()}).strict().optional(),course:Y.object({id:Y.url().optional(),name:Y.string().optional()}).strict(),process:Y.boolean().optional()}),A9=Y.object({"@context":Y.literal("http://purl.imsglobal.org/ctx/caliper/v1p2"),id:Y.string().regex(/^urn:uuid:/,"Event id must start with urn:uuid:"),type:Y.string(),eventTime:v,profile:Y.literal("TimebackProfile"),actor:D2,action:Y.string(),object:P8,edApp:Y.object({id:Y.string(),name:Y.string().optional()}).optional()}),z9=Y.object({type:Y.enum(["totalQuestions","correctQuestions","xpEarned","masteredUnits"]),value:Y.number()}),EZ=Y.object({id:Y.url(),type:Y.literal("TimebackActivityMetricsCollection"),attempt:Y.number().optional(),items:Y.array(z9),extensions:Y.record(Y.string(),Y.unknown()).optional()}),vZ=A9.extend({type:Y.literal("ActivityEvent"),action:Y.literal("Completed"),generated:EZ}),P9=Y.object({type:Y.enum(["active","inactive","waste","unknown","anti-pattern"]),value:Y.number(),subType:Y.string().optional()}),yZ=Y.object({id:Y.url(),type:Y.literal("TimebackTimeSpentMetricsCollection"),items:Y.array(P9)}),fZ=A9.extend({type:Y.literal("TimeSpentEvent"),action:Y.literal("SpentTime"),generated:yZ}),gZ=Y.object({actor:D2,object:P8,metrics:Y.array(z9).min(1,"metrics must contain at least one metric"),eventTime:v.optional(),metricsId:Y.string().optional(),id:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional(),edApp:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),session:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),attempt:Y.number().int().min(1).optional(),generatedExtensions:Y.object({pctCompleteApp:Y.number().optional()}).loose().optional()}).strict(),dZ=Y.object({actor:D2,object:P8,metrics:Y.array(P9).min(1,"metrics must contain at least one metric"),eventTime:v.optional(),metricsId:Y.string().optional(),id:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional(),edApp:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),session:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional()}).strict(),mZ=Y.union([vZ,fZ]),Y1=Y.object({sensor:Y.string(),sendTime:v,dataVersion:Y.literal("http://purl.imsglobal.org/ctx/caliper/v1p2"),data:Y.array(mZ)}),lZ=Y.enum(["AnnotationProfile","AssessmentProfile","ToolUseProfile","GeneralProfile","FeedbackProfile","MediaProfile","SurveyProfile","ResourceManagementProfile","ForumProfile","AssignableProfile","GradingProfile","ReadingProfile","SessionProfile","SearchProfile","ToolLaunchProfile","TimebackProfile"]),l=Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]),c2=Y.object({id:SZ,type:Y.string(),name:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),T9=Y.object({"@context":Y.string().optional(),id:Y.string().regex(/^urn:uuid:/,"Event id must start with urn:uuid:"),type:Y.string(),actor:Y.union([Y.string(),c2,D2]),action:Y.string(),object:l,eventTime:v,profile:lZ,edApp:l.optional(),generated:l.optional(),target:l.optional(),referrer:l.optional(),group:l.optional(),membership:l.optional(),session:l.optional(),federatedSession:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),x9=Y.object({sensor:X,sendTime:v,dataVersion:Y.literal("http://purl.imsglobal.org/ctx/caliper/v1p2"),data:Y.array(T9).min(1,"data must contain at least one event")}),uZ=Y.object({sensor:X,events:Y.array(T9).min(1,"events must contain at least one event")}),D9=Y.object({limit:Y.number().int().positive().optional(),offset:Y.number().int().min(0).optional(),sensor:X.optional(),startDate:v.optional(),endDate:v.optional(),actorId:X.optional(),actorEmail:Y.email().optional()}).strict(),R9=Y.object({id:Y.string(),name:Y.string().optional(),isPartOf:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}),cZ=Y.object({id:Y.string(),attempt:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),startedAtTime:v.optional(),endedAtTime:v.optional(),duration:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}),pZ=Y.object({id:Y.string().optional(),scoreGiven:Y.number(),maxScore:Y.number().optional(),attempt:Y.union([Y.string(),Y.record(Y.string(),Y.unknown())]).optional(),comment:Y.string().optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}),aZ=Y.object({actor:Y.union([Y.string(),c2,D2]),object:R9,edApp:l,id:Y.string().optional(),eventTime:v.optional(),session:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),iZ=Y.object({actor:Y.union([Y.string(),c2,D2]),object:R9,edApp:l,generated:cZ.optional(),id:Y.string().optional(),eventTime:v.optional(),session:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),sZ=Y.object({actor:Y.union([Y.string(),c2,D2]),object:Y.string(),generated:pZ,edApp:l,id:Y.string().optional(),eventTime:v.optional(),session:l.optional(),extensions:Y.record(Y.string(),Y.unknown()).optional()}).strict(),G1=J2.object({name:X,targetUrl:J2.url("targetUrl must be a valid URL"),secret:X,active:J2.boolean(),sensor:J2.string().nullable().optional(),description:J2.string().nullable().optional()}).strict(),oZ=J2.enum(["string","number","boolean"]),nZ=J2.enum(["eq","neq","gt","gte","lt","lte","contains","notContains","in","notIn","startsWith","endsWith","regexp"]),B1=J2.object({webhookId:X,filterKey:X,filterValue:X,filterType:oZ,filterOperator:nZ,active:J2.boolean()}).strict(),p2=U.string().uuid(),w9=U.object({title:X,identifier:p2,uri:X}),rZ=U.object({identifier:p2,uri:X,lastChangeDateTime:X,title:X,creator:X,officialSourceURL:U.string().optional(),publisher:U.string().optional(),description:U.string().optional(),language:U.string().optional(),version:U.string().optional(),caseVersion:U.string().optional(),adoptionStatus:U.string().optional(),statusStartDate:U.string().optional(),statusEndDate:U.string().optional(),licenseUri:U.string().optional(),notes:U.string().optional(),subject:U.array(U.string()).optional(),extensions:U.unknown().optional()}),tZ=U.object({identifier:p2,uri:X,lastChangeDateTime:X,fullStatement:X,alternativeLabel:U.string().optional(),CFItemType:U.string().optional(),cfItemType:U.string().optional(),humanCodingScheme:U.string().optional(),listEnumeration:U.string().optional(),abbreviatedStatement:U.string().optional(),conceptKeywords:U.array(U.string()).optional(),notes:U.string().optional(),subject:U.array(U.string()).optional(),language:U.string().optional(),educationLevel:U.array(U.string()).optional(),CFItemTypeURI:U.unknown().optional(),licenseURI:U.unknown().optional(),statusStartDate:U.string().optional(),statusEndDate:U.string().optional(),extensions:U.unknown().optional()}),eZ=U.object({identifier:p2,uri:X,lastChangeDateTime:X,associationType:X,originNodeURI:w9,destinationNodeURI:w9,sequenceNumber:U.number().optional(),extensions:U.unknown().optional()}),$5=U.object({CFItemTypes:U.array(U.unknown()).optional(),CFSubjects:U.array(U.unknown()).optional(),CFConcepts:U.array(U.unknown()).optional(),CFLicenses:U.array(U.unknown()).optional(),CFAssociationGroupings:U.array(U.unknown()).optional(),extensions:U.unknown().optional()}),F1=U.object({CFDocument:rZ,CFItems:U.array(tZ),CFAssociations:U.array(eZ),CFDefinitions:$5.optional(),extensions:U.unknown().optional()}),U9="https://www.w3.org/ns/credentials/v2",J5=x.array(x.url()).min(3,"@context must include W3C, CLR, and OB context URLs").refine(($)=>$[0]===U9,`First @context entry must be "${U9}"`),N9=x.object({id:x.url(),type:x.literal("Image"),caption:x.string().optional()}),T8=x.object({id:x.url(),type:x.array(x.string()).min(1).refine(($)=>$.includes("Profile"),'type must include "Profile"'),name:x.string().optional(),url:x.string().url().optional(),phone:x.string().optional(),description:x.string().optional(),image:N9.optional(),email:x.string().email().optional()}),I9=x.object({type:X,proofPurpose:X,verificationMethod:X,created:x.iso.datetime(),proofValue:X,cryptosuite:x.string().optional()}),Z5=x.object({id:X,type:x.literal("1EdTechJsonSchemaValidator2019")}),K5=x.object({id:x.string().url().optional(),narrative:x.string().optional()}),H5=x.object({id:x.url(),type:x.array(x.string()).min(1).refine(($)=>$.includes("Achievement"),'type must include "Achievement"'),name:X,description:X,criteria:K5,image:N9.optional(),achievementType:x.string().optional(),creator:T8.optional()}),X5=x.object({type:x.literal("IdentityObject"),identityHash:X,identityType:X,hashed:x.boolean(),salt:x.string().optional()}),W5=x.enum(["exactMatchOf","isChildOf","isParentOf","isPartOf","isPeerOf","isRelatedTo","precedes","replacedBy"]),Y5=x.object({type:x.literal("Association"),associationType:W5,sourceId:x.url(),targetId:x.url()}),Q5=x.object({"@context":x.array(x.string()).min(1),id:x.url(),type:x.array(x.string()).min(1).refine(($)=>$.includes("VerifiableCredential"),'type must include "VerifiableCredential"'),issuer:T8,validFrom:x.iso.datetime(),validUntil:x.string().datetime().optional(),credentialSubject:x.object({id:x.string().optional()}),proof:x.array(I9).optional()}),G5=x.object({id:x.string().url().optional(),type:x.array(x.string()).min(1).refine(($)=>$.includes("ClrSubject"),'type must include "ClrSubject"'),identifier:x.array(X5).optional(),achievement:x.array(H5).optional(),verifiableCredential:x.array(Q5).min(1),association:x.array(Y5).optional()}),x1=x.object({"@context":J5,id:x.url(),type:x.array(x.string()).min(1).refine(($)=>$.includes("VerifiableCredential")&&$.includes("ClrCredential"),'type must include "VerifiableCredential" and "ClrCredential"'),issuer:T8,name:X,description:x.string().optional(),validFrom:x.iso.datetime(),validUntil:x.iso.datetime().optional(),credentialSubject:G5,proof:x.array(I9).optional(),credentialSchema:x.array(Z5).optional()}),B5=V.object({staging:V.string().meta({description:"Course ID in staging environment"}).optional(),production:V.string().meta({description:"Course ID in production environment"}).optional()}).meta({id:"CourseIds",description:"Environment-specific course IDs (populated by sync)"}),_5=V.enum(["base","hole-filling","optional"]).meta({id:"CourseType",description:"Course classification type"}),F5=V.enum(["draft","testing","published","deactivated"]).meta({id:"PublishStatus",description:"Course publication status"}),O5=V.object({dailyXp:V.number().int().positive().meta({description:"Target XP to earn per day"}).optional(),dailyLessons:V.number().int().positive().meta({description:"Target lessons to complete per day"}).optional(),dailyActiveMinutes:V.number().int().positive().meta({description:"Target active learning minutes per day"}).optional(),dailyAccuracy:V.number().int().min(0).max(100).meta({description:"Target accuracy percentage (0-100)"}).optional(),dailyMasteredUnits:V.number().int().positive().meta({description:"Target units to master per day"}).optional()}).meta({id:"CourseGoals",description:"Daily learning goals for a course"}),x5=V.object({totalXp:V.number().int().positive().meta({description:"Total XP available in the course"}).optional(),totalLessons:V.number().int().positive().meta({description:"Total number of lessons/activities"}).optional(),totalGrades:V.number().int().positive().meta({description:"Total grade levels covered"}).optional()}).meta({id:"CourseMetrics",description:"Aggregate metrics for a course"}),b9=V.object({courseType:_5.optional(),isSupplemental:V.boolean().meta({description:"Whether this is supplemental to a base course"}).optional(),isCustom:V.boolean().meta({description:"Whether this is a custom course for an individual student"}).optional(),publishStatus:F5.optional(),contactEmail:V.email().meta({description:"Contact email for course issues"}).optional(),primaryApp:V.string().meta({description:"Primary application identifier"}).optional(),goals:O5.optional(),metrics:x5.optional()}).meta({id:"CourseMetadata",description:"Course metadata (matches API metadata object)"}),h9=V.object({courseCode:V.string().meta({description:"Course code (e.g., 'MATH101')"}).optional(),level:V.string().meta({description:"Course level (e.g., 'AP', 'Honors')"}).optional(),metadata:b9.optional()}).meta({id:"CourseDefaults",description:"Default properties that apply to all courses unless overridden"}),M9=V.object({level:V.string().meta({description:"Course level for this environment"}).optional(),sensor:V.url().meta({description:"Caliper sensor endpoint URL for this environment"}).optional(),launchUrl:V.url().meta({description:"LTI launch URL for this environment"}).optional(),metadata:b9.optional()}).meta({id:"CourseEnvOverrides",description:"Environment-specific course overrides (non-identity fields)"}),D5=V.object({staging:M9.meta({description:"Overrides for staging environment"}).optional(),production:M9.meta({description:"Overrides for production environment"}).optional()}).meta({id:"CourseOverrides",description:"Per-environment course overrides"}),w5=h9.extend({subject:Z2.meta({description:"Subject area for this course"}),grade:n.meta({description:"Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"}).optional(),ids:B5.nullable().optional(),sensor:V.url().meta({description:"Caliper sensor endpoint URL for this course"}).optional(),launchUrl:V.url().meta({description:"LTI launch URL for this course"}).optional(),overrides:D5.optional()}).meta({id:"CourseConfig",description:"Configuration for a single course. Must have either grade or courseCode (or both)."}),w1=V.object({$schema:V.string().meta({description:"JSON Schema reference for editor support"}).optional(),name:V.string().min(1,"App name is required").meta({description:"Display name for your app"}),defaults:h9.meta({description:"Default properties applied to all courses"}).optional(),courses:V.array(w5).min(1,"At least one course is required").meta({description:"Courses available in this app"}),sensor:V.url().meta({description:"Default Caliper sensor endpoint URL for all courses"}).optional(),launchUrl:V.url().meta({description:"Default LTI launch URL for all courses"}).optional(),studio:V.object({telemetry:V.boolean().meta({description:"Enable anonymous usage telemetry for Studio (default: true)"}).optional().default(!0)}).meta({description:"Studio-specific configuration"}).optional()}).meta({id:"TimebackConfig",title:"Timeback Config",description:"Configuration schema for timeback.config.json files"}).refine(($)=>{return $.courses.every((J)=>J.grade!==void 0||J.courseCode!==void 0)},{message:"Each course must have either a grade or a courseCode",path:["courses"]}).refine(($)=>{let Z=$.courses.filter((K)=>K.grade!==void 0).map((K)=>`${K.subject}:${K.grade}`);return new Set(Z).size===Z.length},{message:"Duplicate (subject, grade) pair found; each must be unique",path:["courses"]}).refine(($)=>{let Z=$.courses.filter((K)=>K.courseCode!==void 0).map((K)=>K.courseCode);return new Set(Z).size===Z.length},{message:"Duplicate courseCode found; each must be unique",path:["courses"]}).refine(($)=>{return $.courses.every((J)=>{if(J.sensor!==void 0||$.sensor!==void 0)return!0;return[J.launchUrl,$.launchUrl,J.overrides?.staging?.launchUrl,J.overrides?.production?.launchUrl].filter(Boolean).length>0})},{message:"Each course must have an effective sensor. Either set `sensor` explicitly (top-level or per-course), or provide a `launchUrl` so sensor can be derived from its origin.",path:["courses"]}),N2=D.union([v,q2]),I2=N2.transform(($)=>$.includes("T")?$:`${$}T00:00:00.000Z`),M1=D.object({id:D.string(),role:D.string(),beginDate:N2.nullable(),endDate:N2.nullable(),metadata:D.object({goals:D.object({dailyXp:D.number().optional()}).optional(),metrics:D.object({totalXp:D.number().optional(),totalLessons:D.number().optional()}).optional()}).optional(),course:D.object({id:D.string(),title:D.string(),subjects:D.array(D.string()).nullable(),grades:D.array(D.string()).nullable()}),school:D.object({id:D.string(),name:D.string()})}),U5=D.object({activityMetrics:D.object({xpEarned:D.number(),totalQuestions:D.number(),correctQuestions:D.number(),masteredUnits:D.number()}),timeSpentMetrics:D.object({activeSeconds:D.number(),inactiveSeconds:D.number(),wasteSeconds:D.number()}),apps:D.array(D.string())}),M5=D.record(D.string(),D.record(D.string(),U5)),L1=D.object({message:D.string(),enrollmentId:D.string(),startDate:N2,endDate:N2,facts:M5,factsByApp:D.unknown()}),S9=D.object({email:D.email().optional(),studentId:X.optional()}).superRefine(($,J)=>{if(!$.email&&!$.studentId)J.addIssue({code:D.ZodIssueCode.custom,message:"must provide either email or studentId",path:["email"]}),J.addIssue({code:D.ZodIssueCode.custom,message:"must provide either email or studentId",path:["studentId"]})}),j1=D.object({subject:X,grade:X,courseId:X,orgSourcedId:X.optional()}),V1=D.object({userId:X}),k1=D.object({sourcedId:X.optional(),role:zZ.optional(),beginDate:v.optional(),metadata:D.record(D.string(),D.unknown()).optional()}),q1=D.object({fields:D.string().optional(),limit:D.number().int().positive().optional(),offset:D.number().int().nonnegative().optional(),sort:D.string().optional(),orderBy:D.enum(["asc","desc"]).optional(),filter:D.string().optional(),search:D.string().optional(),roles:D.array(C9).min(1),orgSourcedIds:D.array(X).optional()}),C1=S9.extend({startDate:I2,endDate:I2,timezone:D.string().optional()}),A1=S9.extend({weekDate:I2,timezone:D.string().optional()}),z1=D.object({enrollmentId:X,startDate:I2.optional(),endDate:I2.optional(),timezone:D.string().optional()}),T1=f.object({email:f.email()}),R1=f.object({name:X.optional(),timeback_id:X.optional(),grade:X.optional(),subject:X.optional(),all:f.boolean().optional()}),N1=f.object({student_email:f.email(),timeback_id:X.optional(),subject:X.optional(),grade_rank:f.number().int().min(0).max(12).optional(),assessment_line_item_sourced_id:X.optional(),assessment_result_sourced_id:X.optional()}).superRefine(($,J)=>{let Z=!!$.timeback_id,K=!!$.subject,H=$.grade_rank!==void 0;if(!Z&&!K)J.addIssue({code:f.ZodIssueCode.custom,message:"must provide either timeback_id or subject",path:["timeback_id"]}),J.addIssue({code:f.ZodIssueCode.custom,message:"must provide either timeback_id or subject",path:["subject"]});if(H&&!K)J.addIssue({code:f.ZodIssueCode.custom,message:"grade_rank requires subject",path:["grade_rank"]});let W=!!$.assessment_line_item_sourced_id,F=!!$.assessment_result_sourced_id;if(W!==F)J.addIssue({code:f.ZodIssueCode.custom,message:"assessment_line_item_sourced_id and assessment_result_sourced_id must be provided together",path:W?["assessment_result_sourced_id"]:["assessment_line_item_sourced_id"]})}),I1=f.object({student_email:f.email(),assignment_id:f.number().int().positive().optional(),timeback_id:X.optional(),subject:X.optional(),grade_rank:f.number().int().min(0).max(12).optional()}).superRefine(($,J)=>{let Z=$.assignment_id!==void 0,K=!!$.timeback_id,H=!!$.subject&&$.grade_rank!==void 0;if(!Z&&!K&&!H)J.addIssue({code:f.ZodIssueCode.custom,message:"Either assignment_id, timeback_id, or (subject and grade_rank) is required",path:["assignment_id"]});if($.grade_rank!==void 0&&!$.subject)J.addIssue({code:f.ZodIssueCode.custom,message:"grade_rank requires subject",path:["grade_rank"]})}),g=G.enum(["active","tobedeleted"]),y=G.record(G.string(),G.unknown()).nullable().optional(),k=G.object({sourcedId:X,type:G.string().optional(),href:G.string().optional()}).strict(),W2=G.union([q2,v]).transform(($)=>$.includes("T")?$:`${$}T00:00:00Z`),L5=G.object({roleType:G.enum(["primary","secondary"]),role:C9,org:k,userProfile:G.string().optional(),metadata:y,beginDate:W2.optional(),endDate:W2.optional()}).strict(),h1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string"),status:g.optional(),enabledUser:G.boolean(),givenName:X.describe("givenName must be a non-empty string"),familyName:X.describe("familyName must be a non-empty string"),middleName:X.optional(),username:X.optional(),email:G.email(),roles:G.array(L5).min(1,"roles must include at least one role"),userIds:G.array(G.object({type:X,identifier:X}).strict()).optional(),agents:G.array(k).optional(),grades:G.array(n).optional(),identifier:X.optional(),sms:X.optional(),phone:X.optional(),pronouns:X.optional(),password:X.optional(),metadata:y}).strict(),S1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string").optional(),status:g.optional(),title:X.describe("title must be a non-empty string"),org:k,courseCode:X.optional(),subjects:G.array(Z2).optional(),grades:G.array(n).optional(),level:X.optional(),metadata:y}).strict(),E1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string").optional(),status:g.optional(),title:X.describe("title must be a non-empty string"),terms:G.array(k).min(1,"terms must have at least one item"),course:k,org:k,classCode:X.optional(),classType:G.enum(["homeroom","scheduled"]).optional(),location:X.optional(),grades:G.array(n).optional(),subjects:G.array(Z2).optional(),subjectCodes:G.array(X).optional(),periods:G.array(X).optional(),metadata:y}).strict(),E9=G.enum(["true","false"]),v1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string").optional(),status:g.optional(),user:k,class:k,school:k.optional(),role:G.enum(["administrator","proctor","student","teacher"]),primary:E9.optional(),beginDate:q2.optional(),endDate:q2.optional(),metadata:y}).strict(),y1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),status:g,weight:G.number().nullable().optional(),metadata:y}).strict(),f1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),class:k,school:k,category:k,assignDate:W2,dueDate:W2,status:g,description:G.string().optional(),resultValueMin:G.number().nullable().optional(),resultValueMax:G.number().nullable().optional(),scoreScale:k.optional(),metadata:y}).strict(),g1=G.object({sourcedId:X.optional(),lineItem:k,student:k,class:k.optional(),scoreDate:W2,scoreStatus:G.enum(["exempt","fully graded","not submitted","partially graded","submitted"]),score:G.number().nullable().optional(),textScore:G.string().nullable().optional(),status:g,comment:G.string().nullable().optional(),metadata:y}).strict(),d1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),status:g.optional(),type:G.string(),class:k,course:k.nullable().optional(),scoreScaleValue:G.array(G.object({itemValueLHS:X,itemValueRHS:X,value:G.string().optional(),description:G.string().optional()}).strict()),minScore:G.number().optional(),maxScore:G.number().optional(),metadata:y}).strict(),m1=G.object({sourcedId:X.optional(),status:g.optional(),dateLastModified:v.optional(),title:X.describe("title must be a non-empty string"),description:G.string().nullable().optional(),class:k.nullable().optional(),parentAssessmentLineItem:k.nullable().optional(),scoreScale:k.nullable().optional(),resultValueMin:G.number().nullable().optional(),resultValueMax:G.number().nullable().optional(),component:k.nullable().optional(),componentResource:k.nullable().optional(),learningObjectiveSet:G.array(G.object({source:G.string(),learningObjectiveIds:G.array(G.string())})).optional().nullable(),course:k.nullable().optional(),metadata:y}).strict(),j5=G.object({learningObjectiveId:G.string(),score:G.number().optional(),textScore:G.string().optional()}),V5=G.array(G.object({source:G.string(),learningObjectiveResults:G.array(j5)})),l1=G.object({sourcedId:X.optional(),status:g.optional(),dateLastModified:v.optional(),metadata:y,assessmentLineItem:k,student:k,score:G.number().nullable().optional(),textScore:G.string().nullable().optional(),scoreDate:W2,scoreScale:k.nullable().optional(),scorePercentile:G.number().nullable().optional(),scoreStatus:G.enum(["exempt","fully graded","not submitted","partially graded","submitted"]),comment:G.string().nullable().optional(),learningObjectiveSet:V5.nullable().optional(),inProgress:G.string().nullable().optional(),incomplete:G.string().nullable().optional(),late:G.string().nullable().optional(),missing:G.string().nullable().optional()}).strict(),u1=G.object({sourcedId:X.optional(),status:g.optional(),name:X.describe("name must be a non-empty string"),type:AZ,identifier:X.optional(),parent:k.optional(),metadata:y}).strict(),c1=G.object({sourcedId:X.optional(),status:g.optional(),name:X.describe("name must be a non-empty string"),type:G.literal("school").optional(),identifier:X.optional(),parent:k.optional(),metadata:y}).strict(),p1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string"),status:g,title:X.describe("title must be a non-empty string"),startDate:W2,endDate:W2,type:G.enum(["gradingPeriod","semester","schoolYear","term"]),schoolYear:X.describe("schoolYear must be a non-empty string"),org:k,parent:k.optional(),children:G.array(k).optional(),metadata:y}).strict(),a1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),courseComponent:k,resource:k,status:g,metadata:y}).strict(),i1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),course:k,status:g,metadata:y}).strict(),s1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string"),role:G.enum(["student","teacher"]),primary:E9.optional(),beginDate:q2.optional(),endDate:q2.optional(),metadata:y}).strict(),o1=G.object({agentSourcedId:X.describe("agentSourcedId must be a non-empty string")}).strict(),n1=G.object({applicationName:X.describe("applicationName must be a non-empty string"),credentials:G.object({username:X.describe("username must be a non-empty string"),password:X.describe("password must be a non-empty string")})}).strict(),r1=G.object({sourcedId:X.describe("sourcedId must be a non-empty string")}).loose(),Y2=G.object({type:PZ,subject:Z2.nullish(),grades:G.array(n).nullish(),language:G.string().nullish(),xp:G.number().nullish(),url:G.url().nullish(),keywords:G.array(G.string()).nullish(),learningObjectiveSet:bZ.nullish(),lessonType:G.string().nullish()}).passthrough(),k5=Y2.extend({type:G.literal("qti"),subType:TZ,questionType:NZ.optional(),difficulty:IZ.optional()}),q5=Y2.extend({type:G.literal("text"),format:G.string(),author:G.string().optional(),pageCount:G.number().optional()}),C5=Y2.extend({type:G.literal("audio"),duration:G.string().regex(/^\d{2}:\d{2}:\d{2}(\.\d{2})?$/).optional(),format:G.string(),speaker:G.string().optional()}),A5=Y2.extend({type:G.literal("video"),duration:G.string().regex(/^\d{2}:\d{2}:\d{2}(\.\d{2})?$/).optional(),captionsAvailable:G.boolean().optional(),format:G.string()}),z5=Y2.extend({type:G.literal("interactive"),launchUrl:G.url().optional(),toolProvider:G.string().optional(),instructionalMethod:G.string().optional(),courseIdOnFail:G.string().nullable().optional(),fail_fast:hZ}),P5=Y2.extend({type:G.literal("visual"),format:G.string(),resolution:G.string().optional()}),T5=Y2.extend({type:G.literal("course-material"),subType:RZ,author:G.string().optional(),format:G.string(),instructionalMethod:G.string().optional()}),R5=Y2.extend({type:G.literal("assessment-bank"),resources:G.array(G.string())}),N5=G.discriminatedUnion("type",[k5,q5,C5,A5,z5,P5,T5,R5]),t1=G.object({sourcedId:X.optional(),title:X.describe("title must be a non-empty string"),vendorResourceId:X.describe("vendorResourceId must be a non-empty string"),roles:G.array(G.enum(["primary","secondary"])).optional(),importance:G.enum(["primary","secondary"]).optional(),vendorId:G.string().optional(),applicationId:G.string().optional(),status:g.optional(),metadata:N5.nullable().optional()}).strict(),I5=G.object({url:X.describe("courseStructure.url must be a non-empty string"),skillCode:X.describe("courseStructure.skillCode must be a non-empty string"),lessonCode:X.describe("courseStructure.lessonCode must be a non-empty string"),title:X.describe("courseStructure.title must be a non-empty string"),"unit-title":X.describe("courseStructure.unit-title must be a non-empty string"),status:X.describe("courseStructure.status must be a non-empty string"),xp:G.number()}).loose(),e1=G.object({course:G.object({sourcedId:X.describe("course.sourcedId must be a non-empty string").optional(),title:X.describe("course.title must be a non-empty string"),org:k,status:g,metadata:y}).strict(),courseStructure:G.record(G.string(),I5)}).strict(),b5=G.object({student:k}).loose(),$6=G.array(b5).min(1,"results must have at least one item"),h5=B.enum(["edulastic","mastery-track"]),S5=B.enum(["powerpath-100","quiz","test-out","placement","unit-test","alpha-read-article"]),v9=B.array(n),y9=B.record(B.string(),B.unknown()).optional(),f9=B.object({courseId:X,lessonTitle:X.optional(),launchUrl:X.optional(),toolProvider:h5,unitTitle:X.optional(),courseComponentSourcedId:X.optional(),vendorId:X.optional(),description:X.optional(),resourceMetadata:y9.nullable().optional(),grades:v9}),Z6=f9.extend({lessonType:B.literal("test-out"),xp:B.number()}),K6=f9.extend({lessonType:B.literal("placement"),courseIdOnFail:X.nullable().optional(),xp:B.number().optional()}),L9=B.object({courseId:X,lessonType:S5,lessonTitle:X.optional(),unitTitle:X.optional(),courseComponentSourcedId:X.optional(),resourceMetadata:y9.nullable().optional(),xp:B.number().optional(),grades:v9.optional(),courseIdOnFail:X.nullable().optional()}),H6=B.discriminatedUnion("testType",[L9.extend({testType:B.literal("qti"),qti:B.object({url:B.url(),title:X.optional(),metadata:B.record(B.string(),B.unknown()).optional()})}),L9.extend({testType:B.literal("assessment-bank"),assessmentBank:B.object({resources:B.array(B.object({url:B.url(),title:X.optional(),metadata:B.record(B.string(),B.unknown()).optional()})).min(1)})})]),X6=B.object({student:X,lesson:X}),W6=B.object({student:X,lesson:X}),Y6=B.object({courseId:X,userId:X,classId:X.optional()}),k2=B.object({type:B.enum(["component","resource"]),id:X}),E5=B.union([B.object({type:B.literal("set-skipped"),payload:B.object({target:k2,value:B.boolean()})}),B.object({type:B.literal("add-custom-resource"),payload:B.object({resource_id:X,parent_component_id:X,skipped:B.boolean().optional()})}),B.object({type:B.literal("move-item-before"),payload:B.object({target:k2,reference_id:X})}),B.object({type:B.literal("move-item-after"),payload:B.object({target:k2,reference_id:X})}),B.object({type:B.literal("move-item-to-start"),payload:B.object({target:k2})}),B.object({type:B.literal("move-item-to-end"),payload:B.object({target:k2})}),B.object({type:B.literal("change-item-parent"),payload:B.object({target:k2,new_parent_id:X,position:B.enum(["start","end"]).optional()})})]),Q6=B.object({operation:E5,reason:X.optional()}),G6=B.object({studentId:X,componentResourceId:X,result:B.object({status:B.enum(["active","tobedeleted"]),metadata:B.record(B.string(),B.unknown()).optional(),score:B.number().optional(),textScore:X.optional(),scoreDate:B.string().datetime(),scorePercentile:B.number().optional(),scoreStatus:CZ,comment:X.optional(),learningObjectiveSet:B.array(B.object({source:X,learningObjectiveResults:B.array(B.object({learningObjectiveId:X,score:B.number().optional(),textScore:X.optional()}))})).optional(),inProgress:X.optional(),incomplete:X.optional(),late:X.optional(),missing:X.optional()})}),B6=B.object({student:X,lesson:X,applicationName:X.optional(),testId:X.optional(),skipCourseEnrollment:B.boolean().optional()}),_6=B.object({student:X,subject:Z2}),F6=B.object({student:X,lesson:X}),O6=B.object({userId:X}),x6=B.object({userId:X,subject:B.enum(["Math","Reading","Language","Science"])}),D6=B.object({student:X,subject:Z2,grade:n,testName:X.optional()}),w6=B.object({testName:X}),v5=B.object({student:X,subject:Z2,grade:n,testName:X.optional()}),U6=B.object({items:B.array(v5)}),M6=B.object({spreadsheetUrl:B.url(),sheet:X}),L6=B.object({student:X,status:B.enum(["assigned","in_progress","completed","failed","expired","cancelled"]).optional(),subject:X.optional(),grade:n.optional(),limit:B.number().int().positive().max(3000).optional(),offset:B.number().int().nonnegative().optional()}),j6=B.object({student:X.optional(),status:B.enum(["assigned","in_progress","completed","failed","expired","cancelled"]).optional(),subject:X.optional(),grade:n.optional(),limit:B.number().int().positive().max(3000).optional(),offset:B.number().int().nonnegative().optional()}),V6=B.object({student:X,question:X,response:B.union([X,B.array(X)]).optional(),responses:B.record(B.string(),B.union([X,B.array(X)])).optional(),lesson:X,rendererOutcomes:B.object({score:B.number(),maxScore:B.number().min(0),isCorrect:B.boolean()}).optional(),playerState:B.string().optional()}).refine(($)=>$.response!==void 0||$.responses!==void 0,{message:"Either 'response' or 'responses' must be provided",path:["response","responses"]}).transform(($)=>{if($.response!==void 0&&$.responses===void 0)return{...$,responses:{RESPONSE:$.response}};return $}),k6=B.object({student:X,lesson:X,attempt:B.number().int().positive().optional()}),q6=B.object({student:X,lesson:X}),C6=B.object({student:X,lesson:X}),A6=B.object({student:X,course:X}),z6=B.object({student:X,lesson:X,applicationName:X.optional()}),P6=B.object({student:X,subject:Z2}),T6=B.object({status:B.enum(["active","tobedeleted"]).optional()}),g9=Q.enum(["choice","text-entry","extended-text","inline-choice","match","order","associate","select-point","graphic-order","graphic-associate","graphic-gap-match","hotspot","hottext","slider","drawing","media","upload"]),R8=Q.enum(["single","multiple","ordered","record"]),N8=Q.enum(["identifier","boolean","integer","float","string","point","pair","directedPair","duration","file","uri"]),y5=Q.enum(["easy","medium","hard"]),f5=Q.enum(["linear","nonlinear"]),g5=Q.enum(["individual","simultaneous"]),I8=Q.enum(["show","hide"]),d9=Q.enum(["test","item","stimulus"]),N6=Q.enum(["QUESTION","LESSON"]),d5=Q.object({value:Q.array(Q.string())}).strict(),m9=Q.object({identifier:X,cardinality:R8,baseType:N8.optional(),correctResponse:d5}).strict(),l9=Q.object({identifier:X,cardinality:R8,baseType:N8.optional()}).strict(),u9=Q.object({identifier:X,cardinality:R8.optional(),baseType:N8,normalMaximum:Q.number().optional(),normalMinimum:Q.number().optional(),defaultValue:Q.object({value:Q.unknown().optional()}).strict().optional()}).strict(),m5=Q.object({outcomeIdentifier:X,variableIdentifier:X}).strict(),c9=Q.object({templateType:Q.enum(["match_correct","map_response"]),responseDeclarationIdentifier:X,outcomeIdentifier:X,correctResponseIdentifier:X,incorrectResponseIdentifier:X,inlineFeedback:m5.optional()}).strict(),l5=Q.object({source:X,learningObjectiveIds:Q.array(Q.string())}).strict(),b8=Q.object({subject:Q.string().optional(),grade:n.optional(),difficulty:y5.optional(),learningObjectiveSet:Q.array(l5).optional()}).loose(),p9=Q.object({outcomeIdentifier:X,identifier:X,showHide:I8,content:Q.string(),title:Q.string()}).strict(),a9=Q.object({outcomeIdentifier:X,identifier:X,showHide:I8,content:Q.string(),class:Q.array(Q.string())}).strict(),i9=Q.object({outcomeIdentifier:X,identifier:X,showHide:I8,content:Q.string(),class:Q.array(Q.string())}).strict(),s9=Q.object({href:X,type:X}).strict(),o9=Q.object({id:X,support:Q.string(),content:Q.string()}).strict(),I6=Q.object({page:Q.number().int().positive().optional(),limit:Q.number().int().positive().optional(),sort:Q.string().optional(),order:Q.enum(["asc","desc"]).optional()}).strict(),u5=Q.object({format:Q.string().pipe(Q.literal("xml")),xml:X,metadata:b8.optional()}).strict(),c5=Q.object({identifier:X,title:X,type:g9,qtiVersion:Q.string().optional(),timeDependent:Q.boolean().optional(),adaptive:Q.boolean().optional(),responseDeclarations:Q.array(m9).optional(),outcomeDeclarations:Q.array(l9).optional(),responseProcessing:c9.optional(),metadata:b8.optional(),modalFeedback:Q.array(p9).optional(),feedbackInline:Q.array(a9).optional(),feedbackBlock:Q.array(i9).optional()}).strict(),b6=Q.union([u5,c5]),h6=Q.object({identifier:X.optional(),title:X,type:g9,qtiVersion:Q.string().optional(),timeDependent:Q.boolean().optional(),adaptive:Q.boolean().optional(),responseDeclarations:Q.array(m9).optional(),outcomeDeclarations:Q.array(l9).optional(),responseProcessing:c9.optional(),metadata:b8.optional(),modalFeedback:Q.array(p9).optional(),feedbackInline:Q.array(a9).optional(),feedbackBlock:Q.array(i9).optional(),rawXml:Q.string(),content:Q.record(Q.string(),Q.unknown())}).strict(),S6=Q.object({identifier:X,response:Q.union([Q.string(),Q.array(Q.string())])}).strict(),n9=Q.object({identifier:X,href:X,sequence:Q.number().int().positive().optional()}).strict(),p5=Q.object({identifier:X,title:X,visible:Q.boolean(),required:Q.boolean().optional(),fixed:Q.boolean().optional(),sequence:Q.number().int().positive(),"qti-assessment-item-ref":Q.array(n9).optional()}).strict(),r9=Q.object({identifier:X,navigationMode:Q.string().pipe(f5),submissionMode:Q.string().pipe(g5),"qti-assessment-section":Q.array(p5)}).strict(),E6=Q.object({items:Q.array(n9).min(1)}).strict(),v6=Q.object({metadata:Q.record(Q.string(),Q.unknown()).optional()}).strict(),y6=Q.object({identifier:X,title:X,qtiVersion:Q.string().optional(),toolName:Q.string().optional(),toolVersion:Q.string().optional(),timeLimit:Q.number().optional(),maxAttempts:Q.number().optional(),toolsEnabled:Q.record(Q.string(),Q.boolean()).optional(),metadata:Q.record(Q.string(),Q.unknown()).optional(),"qti-test-part":Q.array(r9),"qti-outcome-declaration":Q.array(u9).optional()}).strict(),f6=Q.object({identifier:X.optional(),title:X,qtiVersion:Q.string().optional(),toolName:Q.string().optional(),toolVersion:Q.string().optional(),timeLimit:Q.number().optional(),maxAttempts:Q.number().optional(),toolsEnabled:Q.record(Q.string(),Q.boolean()).optional(),metadata:Q.record(Q.string(),Q.unknown()).optional(),"qti-test-part":Q.array(r9),"qti-outcome-declaration":Q.array(u9).optional()}).strict(),g6=Q.object({identifier:X,title:X,label:Q.string().optional(),language:Q.string().optional(),stylesheet:s9.optional(),content:Q.string(),catalogInfo:Q.array(o9).optional(),toolName:Q.string().optional(),toolVersion:Q.string().optional(),metadata:Q.record(Q.string(),Q.unknown()).optional()}).strict(),d6=Q.object({identifier:X.optional(),title:X,label:Q.string().optional(),language:Q.string().optional(),stylesheet:s9.optional(),content:Q.string(),catalogInfo:Q.array(o9).optional(),toolName:Q.string().optional(),toolVersion:Q.string().optional(),metadata:Q.record(Q.string(),Q.unknown()).optional()}).strict(),m6=Q.object({xml:Q.string().optional(),schema:d9,entityId:Q.string().optional()}).strict(),l6=Q.object({xml:Q.array(Q.string()),schema:d9,entityIds:Q.array(Q.string())}).strict(),u6=Q.object({questionId:Q.string().optional(),userId:X,feedback:X,lessonId:X,humanApproved:Q.boolean().optional()}).strict();class t9{transport;eventTransformer;constructor($,J){this.transport=$,this.eventTransformer=J?.eventTransformer}send($,J){o(uZ,{sensor:$,events:J},"send events");let Z={sensor:$,sendTime:new Date().toISOString(),dataVersion:"http://purl.imsglobal.org/ctx/caliper/v1p2",data:J};return this.sendEnvelope(Z)}async sendEnvelope($){o(x9,$,"caliper envelope"),S.debug("Sending Caliper envelope",{sensor:$.sensor,eventCount:$.data.length});let J=this.eventTransformer?this.eventTransformer.transformEnvelope($):$,K=(await this.transport.request(this.transport.paths.send,{method:"POST",body:J}))?.jobId;return S.debug("Events sent",{jobId:K??"(none)"}),{jobId:K}}async validate($){let J=this.transport.paths.validate;if(!J)throw Error("validate() is not supported on this platform");o(x9,$,"caliper envelope"),S.debug("Validating Caliper envelope",{sensor:$.sensor,eventCount:$.data.length});let Z=await this.transport.request(J,{method:"POST",body:$});return S.debug("Validation complete",{status:Z.status}),Z}async list($={}){let J=this.transport.paths.list;if(!J)throw Error("list() is not supported on this platform");o(D9,$,"list events params"),S.debug("Listing events",{params:$});let Z={limit:$.limit??100,offset:$.offset??0};if($.sensor)Z.sensor=$.sensor;if($.startDate)Z.startDate=$.startDate;if($.endDate)Z.endDate=$.endDate;if($.actorId)Z.actorId=$.actorId;if($.actorEmail)Z.actorEmail=$.actorEmail;let K=await this.transport.request(J,{params:Z});return{events:K.events??[],pagination:K.pagination}}stream($={}){let J=this.transport.paths.list;if(!J)throw Error("stream() is not supported on this platform");let{max:Z,...K}=$;o(D9,K,"list events params"),C8($),S.debug("Streaming events",{params:$});let H={};if(K.limit!==void 0)H.limit=K.limit;if(K.offset!==void 0)H.offset=K.offset;if(K.sensor)H.sensor=K.sensor;if(K.startDate)H.startDate=K.startDate;if(K.endDate)H.endDate=K.endDate;if(K.actorId)H.actorId=K.actorId;if(K.actorEmail)H.actorEmail=K.actorEmail;return new V9(this.transport,J,{...H,max:Z})}async get($){let J=this.transport.paths.get;if(!J)throw Error("get() is not supported on this platform");u2($,"externalId"),S.debug("Getting event",{externalId:$});let Z=J.replace("{id}",encodeURIComponent($)),K=await this.transport.request(Z);if(!K.event)throw Error(`Event not found: ${$}`);return K.event}sendActivity($,J){o(gZ,J,"activity event");let Z=A8(J);return S.debug("Sending ActivityCompletedEvent",{eventId:Z.id,actor:J.actor.email,subject:J.object.subject,metricsCount:J.metrics.length}),this.send($,[Z])}sendTimeSpent($,J){o(dZ,J,"time spent event");let Z=z8(J);return S.debug("Sending TimeSpentEvent",{eventId:Z.id,actor:J.actor.email,subject:J.object.subject,metricsCount:J.metrics.length}),this.send($,[Z])}sendQuestionSeen($,J){o(aZ,J,"question seen event");let Z=_Z(J);return S.debug("Sending AssessmentItemEvent.Started",{eventId:Z.id,actor:J.actor,object:J.object.id}),this.send($,[Z])}sendQuestionAnswered($,J){o(iZ,J,"question answered event");let Z=FZ(J);return S.debug("Sending AssessmentItemEvent.Completed",{eventId:Z.id,actor:J.actor,object:J.object.id}),this.send($,[Z])}sendQuestionGraded($,J){o(sZ,J,"question graded event");let Z=OZ(J);return S.debug("Sending GradeEvent.Graded",{eventId:Z.id,actor:J.actor,object:J.object,scoreGiven:J.generated.scoreGiven}),this.send($,[Z])}}class e9{transport;constructor($){this.transport=$}async getStatus($){let J=this.transport.paths.jobStatus;if(!J)throw Error("getStatus() is not supported on this platform");u2($,"jobId"),S.debug("Getting job status",{jobId:$});let Z=J.replace("{id}",encodeURIComponent($));return(await this.transport.request(Z)).job}async waitForCompletion($,J={}){u2($,"jobId"),a5(J);let{timeoutMs:Z=30000,pollIntervalMs:K=1000}=J,H=Date.now();S.debug("Waiting for job completion",{jobId:$,timeoutMs:Z,pollIntervalMs:K});while(Date.now()-H<Z){let W=await this.getStatus($);if(W.state==="completed")return S.info("Job completed",{jobId:$}),W;if(W.state==="failed")throw S.error("Job failed",{jobId:$}),Error(`Job ${$} failed`);await new Promise((F)=>{setTimeout(F,K)})}throw Error(`Job ${$} timed out after ${Z}ms`)}}function a5($){if(!$)return;let J=[];if($.timeoutMs!==void 0){if(!Number.isInteger($.timeoutMs)||$.timeoutMs<=0)J.push({path:"timeoutMs",message:"Must be a positive integer"})}if($.pollIntervalMs!==void 0){if(!Number.isInteger($.pollIntervalMs)||$.pollIntervalMs<=0)J.push({path:"pollIntervalMs",message:"Must be a positive integer"})}if(J.length>0)throw T2("Invalid polling options",J)}function i5($=l2){return class{transport;_provider;events;jobs;constructor(Z={}){let K=kZ(Z,$),H;if(K.mode==="transport")this.transport=K.transport,S.info("Client initialized with custom transport");else{let{provider:W}=K,{baseUrl:F,paths:_}=W.getEndpointWithPaths("caliper"),O=W.getTokenProvider("caliper");if(!O)throw Error("Caliper API requires authentication");if(this._provider=W,this.transport=new j9({baseUrl:F,tokenProvider:O,timeout:W.timeout,paths:_}),W.platform===K9)H=new k9;S.info("Client initialized",{platform:W.platform,env:W.env,baseUrl:F})}this.events=new t9(this.transport,{eventTransformer:H}),this.jobs=new e9(this.transport)}getTransport(){return this.transport}checkAuth(){if(!this._provider)throw Error("Cannot check auth: client initialized with custom transport");return this._provider.checkAuth()}}}var c6=i5();class K2 extends Error{course;env;constructor($,J){let Z=$.grade===void 0?$.courseCode??$.subject:`${$.subject} grade ${$.grade}`;super(`Course "${Z}" is missing a synced ID for ${J}. Run \`timeback resources push\` first.`);this.name="MissingSyncedCourseIdError",this.course=$,this.env=J}}class a2 extends Error{sensor;constructor($){super(`Invalid sensor URL "${$}". Sensor must be a valid absolute URL (e.g., "https://sensor.example.com") to support slug-based activity IDs.`);this.name="InvalidSensorUrlError",this.sensor=$}}var $$="/ims/oneroster/rostering/v1p2";function J$($,J){return`${$.replace(/\/+$/,"")}/${J.replace(/^\/+/,"")}`}function s5($,J){return J$($,`${$$}/courses/${J}`)}function o5($,J){return J$($,`${$$}/users/${J}`)}function Z$($,J){let Z=$.ids?.[J];if(!Z)throw new K2($,J);return Z}function n5($,J,Z){let K=Z$(J,Z);return s5($,K)}function r5($){if($.courseCode)return $.courseCode;if($.grade!==void 0)return`${$.subject} G${String($.grade)}`;return $.subject}function h8($,J,Z){let K;try{K=new URL($)}catch{throw new a2($)}let H="grade"in J?`${J.subject}/g${String(J.grade)}`:J.code,W=K.pathname.replace(/\/+$/,"");return K.pathname=`${W}/activities/${H}/${encodeURIComponent(Z)}`,K.toString()}function K$($,J,Z,K,H,W,F){return{id:h8(H,$.course,$.id),type:"TimebackActivityContext",subject:J.subject,app:{name:Z},activity:{name:$.name},course:{id:n5(W,J,K),name:r5(J)},process:F??!0}}function t5($){let J=[];if($.totalQuestions!==void 0)J.push({type:"totalQuestions",value:$.totalQuestions});if($.correctQuestions!==void 0)J.push({type:"correctQuestions",value:$.correctQuestions});if($.xpEarned!==void 0)J.push({type:"xpEarned",value:$.xpEarned});if($.masteredUnits!==void 0)J.push({type:"masteredUnits",value:$.masteredUnits});return J}function e5($,J){let Z=[{type:"active",value:Math.max(0,$)/1000}];if(J>0)Z.push({type:"inactive",value:Math.max(0,J)/1000});return Z}function $0($){return $===void 0?void 0:{pctCompleteApp:$}}function H$($,J){return{courseId:Z$($,J)}}function X$($){if(!$)return;return`urn:uuid:${$}`}function W$($,J,Z){return{id:o5($,J),type:"TimebackUser",email:Z}}function Y$($){let{sensor:J,timebackId:Z,email:K,payload:H,process:W,course:F,appName:_,apiEnv:O,onerosterBaseUrl:w,attempt:j,runId:A}=$,C=W$(w,Z,K),q=K$(H,F,_,O,J,w,W??H.process),z=t5(H.metrics),N=$0(H.pctComplete),I=X$(A),r=H$(F,O),H2=A8({actor:C,object:q,metrics:z,eventTime:H.endedAt,generatedExtensions:N,extensions:r,attempt:j,session:I});return{sensor:J,actor:C,object:q,event:H2,payload:H,course:F,appName:_,apiEnv:O,email:K,timebackId:Z}}function i2($){let{sensor:J,timebackId:Z,email:K,payload:H,course:W,appName:F,apiEnv:_,onerosterBaseUrl:O,runId:w}=$,j=W$(O,Z,K),A=K$(H,W,F,_,J,O),C=e5(H.elapsedMs,H.pausedMs),q=H$(W,_),z=X$(w),N=z8({actor:j,object:A,metrics:C,eventTime:H.endedAt,extensions:q,session:z});return{sensor:J,actor:j,object:A,event:N,payload:{id:H.id,name:H.name,course:H.course,startedAt:H.startedAt,endedAt:H.endedAt,elapsedMs:H.elapsedMs,pausedMs:H.pausedMs},course:W,appName:F,apiEnv:_,email:K,timebackId:Z,runId:w}}import*as h from"zod";import*as b2 from"zod";var J0=b2.object({subject:Q$,grade:G$}),Z0=b2.object({code:E}),w2=b2.union([J0,Z0]);class Q2 extends Error{code;selector;count;constructor($,J,Z){super($);this.code=$,this.selector=J,this.count=Z}get selectorDescription(){if("grade"in this.selector)return`${this.selector.subject} grade ${this.selector.grade}`;return`code "${this.selector.code}"`}}function U2($,J){let Z;if("grade"in J)Z=$.filter((K)=>K.subject===J.subject&&K.grade===J.grade);else Z=$.filter((K)=>K.courseCode===J.code);if(Z.length===0)throw new Q2("unknown_course",J);if(Z.length>1)throw new Q2("ambiguous_course",J,Z.length);return Z[0]}var C2=R("handlers:activity:schema"),K0=h.object({totalQuestions:h.number().int().nonnegative().optional(),correctQuestions:h.number().int().nonnegative().optional(),xpEarned:h.number(),masteredUnits:h.number().int().nonnegative().optional()}).superRefine(o2);function H0($){return Math.min(100,Math.max(0,$))}function s2($){if("grade"in $)return`${$.subject} grade ${$.grade}`;return`code "${$.code}"`}var X0=h.object({id:E,name:E,course:w2,runId:h.string().uuid(),startedAt:h.iso.datetime(),endedAt:h.iso.datetime(),elapsedMs:h.number().int().nonnegative(),pausedMs:h.number().int().nonnegative()});function B$($,J,Z){let K=X0.safeParse($);if(!K.success)return{ok:!1,response:M("INVALID_PAYLOAD","Invalid payload",400,{details:K.error.flatten()})};let H=K.data,W;try{W=U2(J.courses,H.course)}catch(_){if(_ instanceof Q2){let O=s2(H.course);if(_.code==="unknown_course")return C2.warn("Unknown course selector",{selector:H.course}),{ok:!1,response:M("UNKNOWN_COURSE",`Unknown course: ${O}`,400)};return C2.error("Ambiguous course selector",{selector:H.course}),{ok:!1,response:M("AMBIGUOUS_COURSE_SELECTOR","Ambiguous course selector in timeback.config.json",500)}}throw _}let F=h2(J,W,Z);if(!F){let _=s2(H.course);return C2.error("Missing sensor for course",{selector:H.course}),{ok:!1,response:M("MISSING_SENSOR",`Course "${_}" has no sensor configured.`,500)}}return{ok:!0,payload:H,course:W,sensor:F}}var W0=h.object({id:E,name:E,course:w2,process:h.boolean().optional(),runId:h.string().uuid(),endedAt:h.iso.datetime(),metrics:K0,pctComplete:h.number().optional().transform(($)=>$===void 0?void 0:H0($))});function _$($,J,Z){let K=W0.safeParse($);if(!K.success)return{ok:!1,response:M("INVALID_PAYLOAD","Invalid payload",400,{details:K.error.flatten()})};let H=K.data,W;try{W=U2(J.courses,H.course)}catch(_){if(_ instanceof Q2){let O=s2(H.course);if(_.code==="unknown_course")return C2.warn("Unknown course selector",{selector:H.course}),{ok:!1,response:M("UNKNOWN_COURSE",`Unknown course: ${O}`,400)};return C2.error("Ambiguous course selector",{selector:H.course}),{ok:!1,response:M("AMBIGUOUS_COURSE_SELECTOR","Ambiguous course selector in timeback.config.json",500)}}throw _}let F=h2(J,W,Z);if(!F){let _=s2(H.course);return C2.error("Missing sensor for course",{selector:H.course}),{ok:!1,response:M("MISSING_SENSOR",`Course "${_}" has no sensor configured.`,500)}}return{ok:!0,payload:H,course:W,sensor:F}}import{getServiceUrlsForEnv as M$}from"@timeback/core";var S8=R("handlers:activity:attempts");async function F$($,J){let Z=[$,J].join("_");return`caliper_${await S2(Z)}`}function Y0($,J){return $.find((Z)=>Z.scoreDate===J)}function Q0($){let J=0;for(let Z of $){let H=Z.metadata?.attempt;if(typeof H==="number"&&H>J)J=H}return J}function G0($){let J=$.metadata;return typeof J?.attempt==="number"&&J.attempt>=1?J.attempt:1}async function O$($,J,Z,K){let H;try{H=await $.oneroster.assessmentResults.listAll({where:{status:"active","assessmentLineItem.sourcedId":J,"student.sourcedId":Z}})}catch{return S8.debug("No existing results found (line item may not exist yet)",{lineItemId:J}),1}if(H.length===0)return 1;let W=Y0(H,K);if(W){let O=G0(W);return S8.debug("Retry detected, reusing attempt number",{lineItemId:J,timebackId:Z,endedAt:K,attempt:O}),O}let F=Q0(H),_=F+1;return S8.debug("New attempt computed",{lineItemId:J,timebackId:Z,endedAt:K,maxAttempt:F,nextAttempt:_}),_}var x$=R("handlers:activity:completion");async function w$($){let{client:J,courseId:Z,timebackId:K,pctComplete:H,appName:W}=$;if(H!==100)return;let F=D$(Z),_=`timeback_sdk_${await S2(`mastery-completion_${Z}`)}`,O=`timeback_sdk_${await S2(`mastery-completion_${Z}_${K}`)}`;try{let w=!1;try{await J.oneroster.assessmentLineItems(_).get(),w=!0}catch{}if(!w)await J.oneroster.assessmentLineItems.create({sourcedId:_,title:`${W}: Complete`,status:"active",course:{sourcedId:F.course},componentResource:{sourcedId:F.componentResource},resultValueMin:0,resultValueMax:100,metadata:{appName:W}});let j=new Date().toISOString();await J.oneroster.assessmentResults.upsert(O,{status:"active",assessmentLineItem:{sourcedId:_},student:{sourcedId:K},score:100,scoreDate:j,scoreStatus:"fully graded",metadata:{isMasteryCompletion:!0,completedAt:j,appName:W}}),x$.debug("Created mastery completion entry",{courseId:Z,timebackId:K,lineItemId:_,resultId:O})}catch(w){let j=w instanceof Error?w.message:"Unknown error";x$.error("Failed to create mastery completion entry",{courseId:Z,timebackId:K,lineItemId:_,error:j})}}import{aggregateActivityMetrics as B0}from"@timeback/core/utils";var A2=R("handlers:activity:progress");function _0($,J){let Z=u(J),K=$.overrides?.[Z]?.metadata?.metrics,H=$.metadata?.metrics;return K?.totalLessons??H?.totalLessons}function F0($,J){let Z=$/J*100;return Math.min(100,Math.max(0,Math.round(Z)))}async function U$($){let{client:J,courseId:Z,timebackId:K,payload:H,course:W,env:F}=$;if(H.pctComplete!==void 0)return;let _=H.metrics.masteredUnits;if(typeof _!=="number"||_<=0)return;let O=_0(W,F);if(!O||O<=0){A2.debug("Skipping progress computation: totalLessons not configured",{courseId:Z});return}let w;try{w=(await J.edubridge.enrollments.list({userId:K})).find((N)=>N.course.id===Z)?.id}catch(z){let N=z instanceof Error?z.message:"Unknown error";A2.warn("Failed to fetch enrollments for progress computation",{courseId:Z,timebackId:K,error:N});return}if(!w){A2.warn("Skipping progress computation: enrollment not found for student/course",{courseId:Z,timebackId:K});return}let j=0;try{let z=await J.edubridge.analytics.getEnrollmentFacts({enrollmentId:w});j=B0(z).masteredUnits}catch(z){let N=z instanceof Error?z.message:"Unknown error";A2.warn("Failed to fetch enrollment facts for progress computation",{courseId:Z,timebackId:K,enrollmentId:w,error:N});return}let A=!0;try{if((await J.edubridge.analytics.getWeeklyFacts({studentId:K,weekDate:H.endedAt})).some((I)=>{if(I.activityId!==H.id)return!1;if(I.enrollmentId&&I.enrollmentId===w)return!0;if(I.courseId&&I.courseId===Z)return!0;return!1}))A=!1}catch(z){let N=z instanceof Error?z.message:"Unknown error";A2.warn("Failed to fetch weekly facts for retry-safe progress computation",{courseId:Z,timebackId:K,enrollmentId:w,activityId:H.id,error:N}),A=!1}let C=j+(A?_:0),q=F0(C,O);return A2.debug("Computed pctComplete",{courseId:Z,timebackId:K,enrollmentId:w,historicalMasteredUnits:j,currentMasteredUnits:_,shouldIncludeCurrentMasteredUnits:A,totalMastered:C,totalLessons:O,pctComplete:q}),{pctComplete:q}}var E8=R("handlers:activity:submit"),O0={computeProgress:U$,maybeWriteCompletionEntry:w$};function L$($,J){return $.timebackId??G2({email:$.email,client:J})}async function n2($,J,Z=O0){let K=u($.env),{userInfo:H,payload:W,course:F,sensor:_,preview:O=!1,runId:w}=J,j=F.ids?.[K];if(!j)throw new K2(F,K);let A=$.getClient(),C=await L$(H,A),q=W;if(W.pctComplete===void 0){let y2=await Z.computeProgress({client:A,courseId:j,timebackId:C,payload:W,course:F,env:$.env});if(y2)q={...W,pctComplete:y2.pctComplete}}let z;if(!O){let y2=h8(_,q.course,q.id),FJ=await F$(y2,j);z=await O$(A,FJ,C,q.endedAt)}let I=M$(K).oneroster,r=Y$({sensor:_,timebackId:C,email:H.email,payload:q,process:q.process,course:F,appName:$.appConfig.name,apiEnv:K,onerosterBaseUrl:I,attempt:z,runId:w}),H2=$.hooks?.beforeActivitySend,v2=H2?await H2(r):r,p=v2??r;if(O||v2===null)return{success:!0,preview:!0,sensor:p.sensor,actor:p.actor,object:p.object,event:p.event};return await A.caliper.events.send(p.sensor,[p.event]),await Z.maybeWriteCompletionEntry({client:A,courseId:j,timebackId:p.timebackId,pctComplete:p.payload.pctComplete,appName:p.appName}),E8.debug("Recorded completion",{courseSelector:W.course,activityId:W.id}),{success:!0}}async function j$($,J){let Z=u($.env),{userInfo:K,payload:H,course:W,sensor:F,runId:_}=J;if(!W.ids?.[Z])throw new K2(W,Z);let w=$.getClient(),j=await L$(K,w),C=M$(Z).oneroster,q=i2({sensor:F,timebackId:j,email:K.email,payload:H,course:W,appName:$.appConfig.name,apiEnv:Z,onerosterBaseUrl:C,runId:_}),z=$.hooks?.beforeTimeSpentSend,N=z?await z(q):q,I=N??q;if(N===null){E8.debug("Hook skipped time-spent send",{activityId:H.id});return}await w.caliper.events.send(I.sensor,[I.event]),E8.debug("Sent time-spent event",{activityId:H.id,elapsedMs:H.elapsedMs})}var E2=R("handlers:activity:submit");async function z2($,J){if($.mode==="custom"){let K=await $.getEmail(J);return K?{email:K}:void 0}let Z=await $.getUser(J);return Z?{email:Z.email,timebackId:Z.id}:void 0}function r2($){return async(J)=>{let Z=await z2($.identity,J);if(!Z)return M("UNAUTHORIZED","Unauthorized",401);let K=_$(await J.json(),$.appConfig,$.env);if(!K.ok)return K.response;let{payload:H,course:W,sensor:F}=K,_={id:H.id,name:H.name,course:H.course,process:H.process,endedAt:H.endedAt,metrics:H.metrics,pctComplete:H.pctComplete};try{if((await n2({env:$.env,api:$.api,appConfig:$.appConfig,getClient:$.getClient,hooks:$.hooks},{userInfo:Z,payload:_,course:W,sensor:F,preview:!1,runId:H.runId})).preview)return P({preview:!0});return E2.debug("Submitted activity",{runId:H.runId,activityId:H.id}),new Response(null,{status:204})}catch(O){if(O instanceof d)return E2.warn("Failed to resolve Timeback user",{code:O.code}),M("USER_RESOLUTION_FAILED","Unable to resolve Timeback identity",B2(O));if(O instanceof K2)return E2.warn("Course not synced",{course:O.course,env:O.env}),M("MISSING_SYNCED_COURSE_ID",O.message,503);if(O instanceof a2)return E2.error("Invalid sensor URL",{sensor:O.sensor}),M("INVALID_SENSOR_URL",O.message,500);let w=O instanceof Error?O.message:"Unknown error";return E2.error("Failed to submit activity",{error:w}),M("INTERNAL_ERROR",w,502)}}}var P2=R("handlers:activity:heartbeat"),t2=new Map,D0=300000;function w0(){let $=Date.now();for(let[J,Z]of t2)if($-Z>D0)t2.delete(J)}function U0($){return w0(),t2.has($)}function V$($){t2.set($,Date.now())}function e2($){return async(J)=>{let Z=await z2($.identity,J);if(!Z)return M("UNAUTHORIZED","Unauthorized",401);let K=B$(await J.json(),$.appConfig,$.env);if(!K.ok)return K.response;let{payload:H,course:W,sensor:F}=K,_=new Date(H.startedAt).getTime(),O=`${H.runId}:${_}`;if(U0(O))return P2.debug("Duplicate heartbeat, skipping",{runId:H.runId,windowKey:O}),P({duplicate:!0});let w=u($.env);if(!W.ids?.[w]){let C=new K2(W,w);return P2.warn("Course not synced",{course:H.course,env:w}),M("MISSING_SYNCED_COURSE_ID",C.message,503)}let A=$.getClient();try{let C=Z.timebackId??await G2({email:Z.email,client:A}),z=x0(w).oneroster,N=i2({sensor:F,timebackId:C,email:Z.email,payload:H,course:W,appName:$.appConfig.name,apiEnv:w,onerosterBaseUrl:z,runId:H.runId}),I=$.hooks?.beforeTimeSpentSend,r=I?await I(N):N,H2=r??N;if(r===null)return V$(O),P2.debug("Hook skipped heartbeat send",{runId:H.runId}),new Response(null,{status:204});return await A.caliper.events.send(H2.sensor,[H2.event]),V$(O),P2.debug("Sent heartbeat",{runId:H.runId,activityId:H.id,elapsedMs:H.elapsedMs}),new Response(null,{status:204})}catch(C){if(C instanceof d)return P2.warn("Failed to resolve Timeback user",{code:C.code}),M("USER_RESOLUTION_FAILED","Unable to resolve Timeback identity",B2(C));let q=C instanceof Error?C.message:"Unknown error";return P2.error("Failed to send heartbeat",{error:q}),M("INTERNAL_ERROR",q,502)}}}async function I$($,J,Z){if(Z.mode!=="sso")return M2.warn("SSO not configured"),P({error:"SSO not configured"},400);return await T$({req:$,env:J,clientId:Z.clientId,issuer:Z.issuer,redirectUri:Z.redirectUri,buildState:Z.buildState})}async function M0($,J,Z,K,H,W,F){try{let _=W.issuer??k$(H),O=N$(J,W.redirectUri);M2.debug("Exchanging auth code for tokens",{issuer:_,clientId:W.clientId});let w=await q$({issuer:_,clientId:W.clientId,clientSecret:W.clientSecret,code:$,redirectUri:O}),j=await C$({issuer:_,accessToken:w.access_token}),A=typeof j.identities==="string"?JSON.parse(j.identities):j.identities;M2.debug("SSO completed, resolving Timeback user",{user:{...j,identities:A}});let C=await _2({env:H,apiCredentials:F.credentials,userInfo:j,client:F.getClient()});M2.debug("Timeback user resolved",{timebackId:C.id});let q={user:C,idp:{tokens:w,userInfo:j},state:Z,req:K,redirect:$8,json:P};return W.onCallbackSuccess(q)}catch(_){let O=_ instanceof Error?_:Error("Unknown error"),w=_ instanceof d?_.code:"token_exchange_failed";if(M2.error("SSO callback failed",{error:O.message,errorCode:w}),W.onCallbackError)return W.onCallbackError(A$(O,w,Z,K));if(_ instanceof d)return P({error:O.message},B2(_));return P({error:O.message},500)}}async function b$($,J,Z,K){if(Z.mode!=="sso")return M2.warn("SSO not configured"),P({error:"SSO not configured"},400);let{url:H,code:W,errorParam:F,state:_}=R$($);if(F)return z$(F,H,_,$,Z.onCallbackError);if(!W)return P$(_,$,Z.onCallbackError);return await M0(W,H,_,$,J,Z,K)}function J8($){let{env:J,identity:Z}=$;return(K)=>I$(K,J,Z)}function Z8($){let{env:J,identity:Z,api:K}=$;return(H)=>b$(H,J,Z,K)}function K8(){return()=>$8("/")}var h$=($)=>{return async(J)=>{return await $.getClient().powerpath.assessments.getAssessmentProgress({student:J.student,lesson:J.lesson,attempt:J.attempt})}};var S$=($)=>{return async(J)=>{return(await $.getClient().powerpath.assessments.getAttempts({student:J.student,lesson:J.lesson})).attempts.map((K)=>({attempt:K.attempt??void 0,score:K.score,startedAt:K.startedAt??void 0,completedAt:K.completedAt??void 0,scoreStatus:K.scoreStatus}))}};var E$=($)=>{return async(J)=>{let Z=$.getClient().powerpath.assessments,K=await Z.getAssessmentProgress({student:J.student,lesson:J.lesson}),H;if(K.lessonType!=="powerpath-100"&&K.finalized!==!0){try{H=await Z.finalStudentAssessmentResponse({student:J.student,lesson:J.lesson})}catch{}K=await Z.getAssessmentProgress({student:J.student,lesson:J.lesson})}let W=K.lessonType==="powerpath-100"?!0:K.finalized===!0;return{...H??{},score:K.score??0,totalQuestions:K.totalQuestions,correctQuestions:K.correctQuestions,accuracy:K.accuracy,finalized:W}}};function v$($){let J=$.metadata?.questionCount;return typeof J==="number"?J:void 0}function v8($){return{id:$.id,title:$.title,difficulty:$.difficulty,content:$.content?{rawXml:$.content.rawXml}:void 0,index:$.index,url:$.url,humanApproved:$.humanApproved,response:$.response,responses:$.responses,correct:$.correct,result:$.result,resultId:$.resultId,learningObjectives:$.learningObjectives}}function y$($,J){if(!J)return{lessonId:$,lessonType:"quiz",score:0,seenQuestions:0,finalized:!1};return{lessonId:$,lessonType:J.lessonType,attempt:J.attempt,score:J.score??0,questionCount:J.totalQuestions,seenQuestions:J.lessonType==="powerpath-100"?J.seenQuestions.length:0,finalized:J.lessonType==="powerpath-100"?!1:J.finalized}}function f$($){let J=$.questions,Z=J.filter((K)=>K.response!==void 0).map((K)=>K.id);return{questions:J.map(v8),answeredIds:Z,score:$.score??0,finalized:$.finalized,complete:$.finalized}}function L0($){if($.lessonType==="powerpath-100")return $.responseResult.isCorrect;return!1}function j0($){if($.lessonType==="powerpath-100")return $.powerpathScore;return 0}function g$($){let J=j0($);return{correct:L0($),score:J,complete:$.lessonType==="powerpath-100"&&J>=100,questionResult:$.questionResult}}function d$($,J){return Array.from(new Set($.map((Z)=>Z.ids?.[J]).filter((Z)=>Boolean(Z))))}function m$($){return String($.sourcedId??"")}var l$=($)=>{return async(J={})=>{let Z=$.getClient(),K=u($.env),H;if(J.course){let _=U2($.appConfig.courses,J.course).ids?.[K];H=_?[_]:[]}else H=d$($.appConfig.courses,K);let W=[];for(let F of H){let _=await Z.oneroster.courses(F).components({where:{status:"active"}}),O=y8(_);for(let w of O){let j=m$(w);if(!j)continue;let A=await Z.oneroster.courses.componentResources({where:{"courseComponent.sourcedId":j,status:"active"}}),C=y8(A);for(let q of C){if(!q.sourcedId)continue;let z=q.metadata??{},N=v$(q);W.push({id:q.sourcedId,name:q.title??q.sourcedId,type:z.lessonType??"quiz",courseId:F,questionCount:N,metadata:z})}}}return W}};var u$=($)=>{return async(J)=>{let Z=$.getClient().powerpath.assessments;if(J.lessonType!=="powerpath-100"){let H=await Z.getAssessmentProgress({student:J.student,lesson:J.lesson});if(H.lessonType==="powerpath-100")throw Error(`Expected quiz progress but got powerpath-100 for lesson ${J.lesson}`);return f$(H)}let K=await Z.getNextQuestion({student:J.student,lesson:J.lesson});return v8(K.question)}};var V0=R("lessons:start"),c$=($)=>{return async(J)=>{let Z=$.getClient().powerpath.assessments,K=J.lesson,H=J.student,W=await Z.getAssessmentProgress({student:H,lesson:K});if(J.forceNew){if(W.lessonType!=="powerpath-100"&&W.finalized!==!0)try{await Z.finalStudentAssessmentResponse({student:H,lesson:K})}catch{}try{await Z.createNewAttempt({student:H,lesson:K}),W=await Z.getAssessmentProgress({student:H,lesson:K})}catch(F){V0.warn("Failed to create new lesson attempt",{lessonId:K,error:F})}}else if(W.lessonType!=="powerpath-100"&&W.finalized!==!0&&(W.questions?.length??0)===0)try{await Z.createNewAttempt({student:H,lesson:K}),W=await Z.getAssessmentProgress({student:H,lesson:K})}catch{}return y$(K,W)}};var p$=($)=>{return async(J)=>{let K=await $.getClient().powerpath.assessments.updateStudentQuestionResponse({student:J.student,lesson:J.lesson,question:J.question,responses:{RESPONSE:J.response}});return g$(K)}};function m($){return{list:l$($),start:c$($),next:u$($),submit:p$($),complete:E$($),attempts:S$($),attemptDetails:h$($)}}async function a($,J){let Z=await z2($.identity,J);if(!Z)return null;if(Z.timebackId)return Z.timebackId;return await G2({email:Z.email,client:$.getClient()})}async function a$($,J){let Z=await z2($.identity,J);return Boolean(Z)}var k0=R("handlers:lessons");function c($,J){if($ instanceof d)return M("USER_RESOLUTION_FAILED","Unable to resolve Timeback identity",B2($));let Z=$ instanceof Error?$.message:"Unknown error";return k0.error(J,{error:Z}),M("INTERNAL_ERROR",Z,500)}import*as i from"zod";var q0=i.object({course:w2.optional()}).partial(),C0=i.object({lessonId:E,forceNew:i.boolean().optional()}),A0=i.object({lessonId:E,lessonType:E.optional()}),z0=i.object({lessonId:E,questionId:E,response:E}),P0=i.object({lessonId:E}),T0=i.object({lessonId:E}),R0=i.object({lessonId:E,attempt:i.number().int().positive()});async function N0($){try{let J=await $.json();if(!J||typeof J!=="object"||Array.isArray(J))return null;return J}catch{return null}}async function L2($,J){let Z=await N0($);if(!Z)return{ok:!1,response:M("INVALID_PAYLOAD","Invalid JSON body",400)};let K=J.safeParse(Z);if(!K.success)return{ok:!1,response:M("INVALID_PAYLOAD","Invalid payload",400,{details:K.error.flatten()})};return{ok:!0,payload:K.data}}async function i$($){return await L2($,q0)}async function s$($){return await L2($,C0)}async function o$($){return await L2($,A0)}async function n$($){return await L2($,z0)}async function r$($){return await L2($,P0)}async function t$($){return await L2($,T0)}async function e$($){return await L2($,R0)}function H8($){let J=m($);return async(Z)=>{try{let K=await e$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.attemptDetails({lesson:K.payload.lessonId,attempt:K.payload.attempt,student:H});return P(W)}catch(K){return c(K,"Failed to fetch lesson attempt details")}}}function X8($){let J=m($);return async(Z)=>{try{let K=await t$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.attempts({lesson:K.payload.lessonId,student:H});return P({attempts:W})}catch(K){return c(K,"Failed to list lesson attempts")}}}function W8($){let J=m($);return async(Z)=>{try{let K=await r$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.complete({lesson:K.payload.lessonId,student:H});return P(W)}catch(K){return c(K,"Failed to complete lesson")}}}function Y8($){let J=m($);return async(Z)=>{try{if(!await a$($,Z))return M("UNAUTHORIZED","Unauthorized",401);let K=await i$(Z);if(!K.ok)return K.response;let H=await J.list({course:K.payload.course});return P({lessons:H})}catch(K){return c(K,"Failed to list lessons")}}}function Q8($){let J=m($);return async(Z)=>{try{let K=await o$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.next({lesson:K.payload.lessonId,lessonType:K.payload.lessonType,student:H});return P(W)}catch(K){return c(K,"Failed to fetch next lesson question")}}}function G8($){let J=m($);return async(Z)=>{try{let K=await s$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.start({lesson:K.payload.lessonId,student:H,forceNew:K.payload.forceNew});return P(W)}catch(K){return c(K,"Failed to start lesson")}}}function B8($){let J=m($);return async(Z)=>{try{let K=await n$(Z);if(!K.ok)return K.response;let H=await a($,Z);if(!H)return M("UNAUTHORIZED","Unauthorized",401);let W=await J.submit({lesson:K.payload.lessonId,question:K.payload.questionId,response:K.payload.response,student:H});return P(W)}catch(K){return c(K,"Failed to submit lesson answer")}}}function $J($,J){let Z=new Map;for(let K of $){let H=K.ids?.[J];if(H)Z.set(H,K)}return Z}function JJ($,J){return $.map((Z)=>{let K=J.get(Z.course.id);return{id:Z.course.id,code:K?.courseCode??Z.course.id,name:Z.course.title}})}function ZJ($){return $.map((J)=>J.metadata?.goals).find(Boolean)}function KJ($){let J=new Date(Date.UTC($.getUTCFullYear(),$.getUTCMonth(),$.getUTCDate())),Z=new Date(Date.UTC($.getUTCFullYear(),$.getUTCMonth(),$.getUTCDate(),23,59,59,999));return{start:J,end:Z}}function f8($){return Object.values($).reduce((J,Z)=>{return J+Object.values(Z).reduce((K,H)=>{return K+(H.activityMetrics?.xpEarned??0)},0)},0)}async function _8($,J,Z,K){let H=await $.edubridge.enrollments.list({userId:J.id}),W=$J(Z.courses,K),F=JJ(H,W),_=ZJ(H),{start:O,end:w}=KJ(new Date),[j,A]=await Promise.all([$.edubridge.analytics.getActivity({studentId:J.id,startDate:O.toISOString(),endDate:w.toISOString()}),$.edubridge.analytics.getActivity({studentId:J.id,startDate:"2000-01-01",endDate:w.toISOString()})]);return{id:J.id,email:J.email,name:J.name,school:J.school,grade:J.grade,courses:F.length?F:void 0,goals:_,xp:{today:f8(j),all:f8(A)}}}var g8=R("handlers:user");async function I0($,J){if($.mode==="custom"){let K=await $.getEmail(J);if(!K)return;return{sub:K,email:K}}let Z=await $.getUser(J);if(!Z)return;return{sub:Z.id,email:Z.email}}function b0($){if(g8.warn("Timeback user resolution failed",{code:$.code}),$.code==="timeback_user_ambiguous")return M("USER_AMBIGUOUS","Timeback user resolution ambiguous",409);if($.code==="timeback_user_not_found")return M("USER_NOT_FOUND","Timeback user not found",404);return M("USER_RESOLUTION_FAILED",$.message,502)}function F8($){return async(J)=>{try{let Z=await I0($.identity,J);if(!Z)return M("UNAUTHORIZED","Unauthorized",401);let K=u($.env),H=$.getClient();try{let W=await _2({env:$.env,apiCredentials:$.api,userInfo:Z,client:H}),F=await _8(H,W,$.appConfig,K);return P(F)}catch(W){if(W instanceof d)return b0(W);let F=W instanceof Error?W.message:"Unknown error";return g8.error("Failed to build user profile",{error:F}),M("INTERNAL_ERROR",F,502)}}catch(Z){let K=Z instanceof Error?Z.message:"Unknown error";return g8.error("Unhandled error in user handler",{error:K}),M("INTERNAL_ERROR",K,500)}}}var d8=R("handlers:user:verify");async function h0($,J){if($.mode==="custom"){let K=await $.getEmail(J);if(!K)return;return{sub:K,email:K}}let Z=await $.getUser(J);if(!Z)return;return{sub:Z.id,email:Z.email}}function O8($){return async(J)=>{try{let Z=await h0($.identity,J);if(!Z)return M("UNAUTHORIZED","Unauthorized",401);let K=$.getClient();try{let H=await _2({env:$.env,apiCredentials:$.api,userInfo:Z,client:K});return P({verified:!0,timebackId:H.id})}catch(H){if(H instanceof d){if(d8.warn("Timeback user resolution failed",{code:H.code}),H.code==="timeback_user_ambiguous")return M("USER_AMBIGUOUS","Timeback user resolution ambiguous",409);if(H.code==="timeback_user_not_found")return P({verified:!1});return M("USER_RESOLUTION_FAILED",H.message,502)}let W=H instanceof Error?H.message:"Unknown error";return d8.error("Failed to verify user",{error:W}),M("INTERNAL_ERROR",W,502)}}catch(Z){let K=Z instanceof Error?Z.message:"Unknown error";return d8.error("Unhandled error in verify handler",{error:K}),M("INTERNAL_ERROR",K,500)}}}import*as T from"zod";var S0=T.object({email:T.email(),timebackId:T.string().optional()}),E0=T.object({id:E,name:E,course:w2}),v0=T.object({totalQuestions:T.number().int().nonnegative().optional(),correctQuestions:T.number().int().nonnegative().optional(),xpEarned:T.number(),masteredUnits:T.number().int().nonnegative().optional(),pctComplete:T.number().min(0).max(100).optional()}).superRefine(o2),y0=T.object({startedAt:T.union([T.iso.datetime(),T.date()]).optional(),endedAt:T.union([T.iso.datetime(),T.date()]).optional(),activeMs:T.number().int().nonnegative().optional(),inactiveMs:T.number().int().nonnegative().optional()}),f0=T.uuid().optional(),HJ=T.object({user:S0,activity:E0,metrics:v0,time:y0.optional(),runId:f0});var XJ=R("activity:record");class WJ extends Error{code="VALIDATION_ERROR";details;constructor($,J){super($);this.name="ActivityRecordValidationError",this.details=J}}class m8 extends Error{code="COURSE_ERROR";constructor($){super($);this.name="ActivityRecordCourseError"}}function g0($){let J=$.time?.endedAt?typeof $.time.endedAt==="string"?$.time.endedAt:$.time.endedAt.toISOString():new Date().toISOString();return{id:$.activity.id,name:$.activity.name,course:$.activity.course,endedAt:J,metrics:{totalQuestions:$.metrics.totalQuestions,correctQuestions:$.metrics.correctQuestions,xpEarned:$.metrics.xpEarned,masteredUnits:$.metrics.masteredUnits},pctComplete:$.metrics.pctComplete}}function d0($,J){let Z=$.time,K=Z.activeMs??0,H=Z.inactiveMs??0,W;if(Z.startedAt)W=typeof Z.startedAt==="string"?Z.startedAt:Z.startedAt.toISOString();else if(Z.activeMs!==void 0||Z.inactiveMs!==void 0){let F=new Date(J),_=K+H;W=new Date(F.getTime()-_).toISOString()}else W=J;return{id:$.activity.id,name:$.activity.name,course:$.activity.course,startedAt:W,endedAt:J,elapsedMs:K,pausedMs:H}}function m0($,J,Z){let K;try{K=U2($.courses,J)}catch(W){if(W instanceof Q2)throw new m8(W.code==="unknown_course"?`Unknown course: ${JSON.stringify(J)}`:"Ambiguous course selector in timeback.config.json");throw W}let H=h2($,K,Z);if(!H)throw new m8(`Course "${JSON.stringify(J)}" has no sensor configured.`);return{course:K,sensor:H}}var l0={recordCompletion:n2,sendTimeSpent:j$};function l8($,J=l0){return async(Z)=>{let K=HJ.safeParse(Z);if(!K.success)throw XJ.warn("Invalid record input",{error:K.error.flatten()}),new WJ("Invalid activity record input",K.error.flatten());let H=K.data,{course:W,sensor:F}=m0($.appConfig,H.activity.course,$.env),_=g0(H),O={env:$.env,api:$.api,appConfig:$.appConfig,getClient:$.getClient,hooks:$.hooks};if(await J.recordCompletion(O,{userInfo:{email:H.user.email,timebackId:H.user.timebackId},payload:_,course:W,sensor:F,preview:!1,runId:H.runId}),H.time){let w=d0(H,_.endedAt);await J.sendTimeSpent(O,{userInfo:{email:H.user.email,timebackId:H.user.timebackId},payload:w,course:W,sensor:F,runId:H.runId})}XJ.debug("Recorded activity",{activityId:H.activity.id,hasTime:!!H.time})}}var x8=R("user:verify");function u8($){return async(J)=>{x8.debug("Verifying user by email");let Z=$.getClient();try{let K=await G2({email:J,client:Z});return x8.debug("User verified",{timebackId:K}),{verified:!0,timebackId:K}}catch(K){if(K instanceof d){if(K.code==="timeback_user_not_found")return x8.debug("User not found in Timeback"),{verified:!1};throw K}let H=K instanceof Error?K.message:"Unknown error";throw x8.error("Failed to verify user",{error:H}),K}}}var c8=R("user:getProfile");function p8($){return async(J)=>{c8.debug("Building user profile by email");let Z=$.getClient(),K=u($.env);try{let H=await _2({env:$.env,apiCredentials:$.api,userInfo:{sub:J,email:J},client:Z}),W=await _8(Z,H,$.appConfig,K);return c8.debug("User profile built",{userId:W.id}),W}catch(H){if(H instanceof d)throw H;let W=H instanceof Error?H.message:"Unknown error";throw c8.error("Failed to build user profile",{error:W}),H}}}async function c0($){let{loadConfig:J}=await import("./chunk-zy9f17gs.js");return await J($)}function p0($){return $.map((J)=>{if(J.grade!==void 0)return J;if(J.courseCode)return J;throw Error(`Invalid course config: missing both grade and courseCode for subject "${J.subject}"`)})}async function BJ($){if(!globalThis.process?.versions?.node&&!globalThis.Bun)throw Error("createTimeback() requires Node.js or Bun — it reads timeback.config.json from the filesystem. "+"For edge runtimes (Cloudflare Workers, Vercel Edge, etc.), use createTimebackIdentity() from '@timeback/sdk' instead.");YJ({logger:$.logger,logLevel:$.logLevel});let J=QJ($.env),Z=await c0({configPath:$.configPath});if(!Z.success)throw Error(`Failed to load timeback config: ${Z.error}`);let K=Z.config,H,W=()=>{if(!H)H=new u0({env:u(J),auth:{clientId:$.api.clientId,clientSecret:$.api.clientSecret}});return H},F=$.hooks,_=(j,A)=>GJ(j,F,A),O={env:J,identity:$.identity,appConfig:{name:K.name,sensor:K.sensor,launchUrl:K.launchUrl,courses:p0(K.courses)},api:$.api,getClient:W,hooks:F},w={env:J,identity:$.identity,api:{credentials:$.api,getClient:W}};return{config:$,handle:{activity:{heartbeat:_("activity.heartbeat",e2(O)),submit:_("activity.submit",r2(O))},identity:{signIn:_("identity.signIn",J8(w)),callback:_("identity.callback",Z8(w)),signOut:K8()},lessons:{list:_("lessons.list",Y8(O)),start:_("lessons.start",G8(O)),next:_("lessons.next",Q8(O)),submit:_("lessons.submit",B8(O)),complete:_("lessons.complete",W8(O)),attempts:_("lessons.attempts",X8(O)),attemptDetails:_("lessons.attemptDetails",H8(O))},user:{me:_("user.me",F8(O)),verify:_("user.verify",O8(O))}},activity:{record:l8({...O})},lessons:m({...O}),user:{verify:u8({...O}),getProfile:p8({...O})},get api(){return W()},close(){if(H)H.close(),H=void 0}}}import{TimebackClient as xH}from"@timeback/core";import{ApiError as wH,ForbiddenError as UH,isApiError as MH,NotFoundError as LH,UnauthorizedError as jH,ValidationError as VH}from"@timeback/core";export{i0 as toNativeHandler,MH as isApiError,_J as createTimebackIdentity,BJ as createTimeback,VH as ValidationError,jH as UnauthorizedError,xH as TimebackClient,a0 as ROUTES,LH as NotFoundError,UH as ForbiddenError,wH as ApiError};