{"version":3,"file":"CG9XueNZ.mjs","names":["b64u"],"sources":["../../../../../../../node_modules/txstate-utils/lib-esm/object/omit.js","../../../../../../../node_modules/txstate-utils/lib-esm/array/comparators.js","../../../../../../../node_modules/txstate-utils/lib-esm/array/sortby.js","../../../../../../../node_modules/txstate-utils/lib-esm/array/toarray.js","../../../../../../../node_modules/txstate-utils/lib-esm/async.js","../../../../../../../node_modules/jose/dist/webapi/lib/buffer_utils.js","../../../../../../../node_modules/jose/dist/webapi/util/errors.js","../../../../../../../node_modules/jose/dist/webapi/util/base64url.js","../../../../../../../node_modules/jose/dist/webapi/lib/validate.js","../../../../../../../node_modules/jose/dist/webapi/util/decode_jwt.js","../../../../../../../node_modules/@txstate-mws/sveltekit-utils/dist/unifiedauth.js","../../../../../../../node_modules/@txstate-mws/sveltekit-utils/dist/api.js","../../../../../../src/lib/api.ts"],"sourcesContent":["export function omit(obj, ...props) {\n    const ret = { ...obj };\n    for (const prop of props)\n        delete ret[prop];\n    return ret;\n}\n","export const comparators = {\n    boolean: (a, b) => Number(a) - Number(b),\n    string: (a, b) => a.localeCompare(b),\n    number: (a, b) => a - b,\n    object: (a, b) => a - b\n};\n","import { comparators } from './comparators.js';\nimport { extractors } from './extractors.js';\n/**\n * Sort array by a specific property or transformation\n *\n * May also provide an array of properties or transformations to provide tiebreakers.\n *\n * Follow any property or transformation with a `true` argument if you want a descending sort.\n *\n * Comparison algorithm is chosen automatically and supports strings, numbers, and\n * dates.\n *\n * undefined or null will always sort to the bottom. If you want them to sort to the top, you\n * can .reverse() the output array and invert your descending booleans.\n *\n * Examples:\n *\n * simple sort by a property\n * sortby(myarray, 'myproperty')\n *\n * simple descending sort\n * sortby(myarray, 'myproperty', true)\n *\n * sort with a tiebreaker property\n * sortby(myarray, 'myproperty', 'mynextproperty')\n *\n * sort descending with a tiebreaker\n * sortby(myarray, 'myproperty', true, 'mynextproperty')\n *\n * sort with a descending tiebreaker\n * sortby(myarray, 'myproperty', 'mynextproperty', true)\n *\n * sort with a transformation\n * sortby(myarray, itm => itm.count - 100)\n */\nexport function sortby(collection, ...args) {\n    const extractorlist = [];\n    const descending = [];\n    for (const arg of args) {\n        if (arg === true) {\n            descending[descending.length - 1] = true;\n        }\n        else if (arg !== false) {\n            extractorlist.push(arg);\n            descending.push(false);\n        }\n    }\n    const sortMap = new Map();\n    for (const itm of collection)\n        sortMap.set(itm, []);\n    const compares = [];\n    for (const extract of extractorlist) {\n        let comparechosen;\n        const handleval = function (val, itm) {\n            const t = typeof val;\n            if (t !== 'undefined') {\n                if (!comparechosen) {\n                    compares.push(comparators[t]);\n                    comparechosen = t;\n                }\n                else if (comparechosen !== t) {\n                    compares[compares.length - 1] = comparators.number;\n                }\n            }\n            sortMap.get(itm).push(val);\n        };\n        const extractor = extractors[typeof extract](extract);\n        for (const itm of collection) {\n            handleval(extractor(itm) ?? undefined, itm);\n        }\n    }\n    return collection.sort((a, b) => {\n        const avals = sortMap.get(a);\n        const bvals = sortMap.get(b);\n        for (let i = 0; i < compares.length; i++) {\n            const aval = avals[i];\n            const bval = bvals[i];\n            const desc = (descending[i] ? -1 : 1);\n            if (aval == null) {\n                if (bval == null)\n                    continue;\n                return 1;\n            }\n            if (bval == null)\n                return -1;\n            const cmp = compares[i](aval, bval);\n            if (cmp !== 0)\n                return cmp * desc;\n        }\n        return 0;\n    });\n}\n","export function toArray(val) {\n    val ??= [];\n    return Array.isArray(val) ? val : [val];\n}\n","/**\n * works like Array.filter but expects a Promise<boolean> from each element\n * instead of a synchronous boolean\n *\n * Uses Promise.all; if you need an in-flight limit, use filterConcurrent\n * instead\n */\nexport async function filterAsync(items, callback) {\n    const bools = await Promise.all(items.map(callback));\n    return items.filter((_, index) => bools[index]);\n}\n/**\n * works like Array.some but expects a Promise<boolean> from each element\n * instead of a synchronous boolean\n *\n * Uses Promise.all; if you need an in-flight limit, use someConcurrent\n * instead\n */\nexport async function someAsync(items, callback) {\n    const bools = await Promise.all(items.map(callback));\n    return items.some((_, index) => bools[index]);\n}\nexport async function rescue(promise, defaultValueOrOptions) {\n    if (typeof defaultValueOrOptions !== 'object' || (!('condition' in defaultValueOrOptions) && !('defaultValue' in defaultValueOrOptions))) {\n        defaultValueOrOptions = { defaultValue: defaultValueOrOptions };\n    }\n    try {\n        return await promise;\n    }\n    catch (e) {\n        if (!defaultValueOrOptions.condition || defaultValueOrOptions.condition(e)) {\n            await defaultValueOrOptions.logRescue?.(e);\n            return defaultValueOrOptions.defaultValue;\n        }\n        throw e;\n    }\n}\n","const encoder = new TextEncoder(), decoder = new TextDecoder(), strictDecoder = new TextDecoder(\"utf-8\", { fatal: !0 }), MAX_INT32 = 2 ** 32;\nfunction concat(...buffers) {\n  const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);\n  let i = 0;\n  for (const buffer of buffers)\n    buf.set(buffer, i), i += buffer.length;\n  return buf;\n}\nfunction writeUInt32BE(buf, value, offset) {\n  if (value < 0 || value >= MAX_INT32)\n    throw new RangeError(`value must be >= 0 and <= ${MAX_INT32 - 1}. Received ${value}`);\n  buf.set([value >>> 24, value >>> 16, value >>> 8, value & 255], offset);\n}\nfunction uint64be(value) {\n  const high = Math.floor(value / MAX_INT32), low = value % MAX_INT32, buf = new Uint8Array(8);\n  return writeUInt32BE(buf, high, 0), writeUInt32BE(buf, low, 4), buf;\n}\nfunction uint32be(value) {\n  const buf = new Uint8Array(4);\n  return writeUInt32BE(buf, value), buf;\n}\nconst NON_ASCII = /[^\\x00-\\x7f]/;\nfunction encode(string) {\n  if (typeof string == \"string\" && string.length >= 128) {\n    if (NON_ASCII.test(string))\n      throw new TypeError(\"non-ASCII string encountered in encode()\");\n    return encoder.encode(string);\n  }\n  const bytes = new Uint8Array(string.length);\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code > 127)\n      throw new TypeError(\"non-ASCII string encountered in encode()\");\n    bytes[i] = code;\n  }\n  return bytes;\n}\nfunction encodeBase64(input, url = !1) {\n  if (Uint8Array.prototype.toBase64)\n    return input.toBase64({ alphabet: url ? \"base64url\" : \"base64\", omitPadding: url });\n  const CHUNK_SIZE = 32768, arr = [];\n  for (let i = 0; i < input.length; i += CHUNK_SIZE)\n    arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));\n  const encoded = btoa(arr.join(\"\"));\n  return url ? encoded.replace(/=/g, \"\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\") : encoded;\n}\nfunction decodeBase64(encoded, url = !1) {\n  if (Uint8Array.fromBase64)\n    return Uint8Array.fromBase64(encoded, { alphabet: url ? \"base64url\" : \"base64\" });\n  if (url) {\n    if (encoded.includes(\"+\") || encoded.includes(\"/\"))\n      throw new TypeError(\"Invalid base64url\");\n    encoded = encoded.replace(/-/g, \"+\").replace(/_/g, \"/\");\n  }\n  const binary = atob(encoded), bytes = new Uint8Array(binary.length);\n  for (let i = 0; i < binary.length; i++)\n    bytes[i] = binary.charCodeAt(i);\n  return bytes;\n}\nasync function digest(algorithm, data) {\n  const subtleDigest = `SHA-${algorithm.slice(-3)}`;\n  return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));\n}\nexport {\n  concat,\n  decodeBase64,\n  decoder,\n  digest,\n  encode,\n  encodeBase64,\n  encoder,\n  strictDecoder,\n  uint32be,\n  uint64be\n};\n","class JOSEError extends Error {\n  static code = \"ERR_JOSE_GENERIC\";\n  code = \"ERR_JOSE_GENERIC\";\n  constructor(message, options) {\n    super(message, options), this.name = this.constructor.name, Error.captureStackTrace?.(this, this.constructor);\n  }\n}\nclass JWTClaimValidationFailed extends JOSEError {\n  static code = \"ERR_JWT_CLAIM_VALIDATION_FAILED\";\n  code = \"ERR_JWT_CLAIM_VALIDATION_FAILED\";\n  claim;\n  reason;\n  payload;\n  constructor(message, payload, claim = \"unspecified\", reason = \"unspecified\") {\n    super(message, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;\n  }\n}\nclass JWTExpired extends JOSEError {\n  static code = \"ERR_JWT_EXPIRED\";\n  code = \"ERR_JWT_EXPIRED\";\n  claim;\n  reason;\n  payload;\n  constructor(message, payload, claim = \"unspecified\", reason = \"unspecified\") {\n    super(message, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;\n  }\n}\nclass JOSEAlgNotAllowed extends JOSEError {\n  static code = \"ERR_JOSE_ALG_NOT_ALLOWED\";\n  code = \"ERR_JOSE_ALG_NOT_ALLOWED\";\n}\nclass JOSENotSupported extends JOSEError {\n  static code = \"ERR_JOSE_NOT_SUPPORTED\";\n  code = \"ERR_JOSE_NOT_SUPPORTED\";\n}\nclass JWEDecryptionFailed extends JOSEError {\n  static code = \"ERR_JWE_DECRYPTION_FAILED\";\n  code = \"ERR_JWE_DECRYPTION_FAILED\";\n  constructor(message = \"decryption operation failed\", options) {\n    super(message, options);\n  }\n}\nclass JWEInvalid extends JOSEError {\n  static code = \"ERR_JWE_INVALID\";\n  code = \"ERR_JWE_INVALID\";\n}\nclass JWSInvalid extends JOSEError {\n  static code = \"ERR_JWS_INVALID\";\n  code = \"ERR_JWS_INVALID\";\n}\nclass JWTInvalid extends JOSEError {\n  static code = \"ERR_JWT_INVALID\";\n  code = \"ERR_JWT_INVALID\";\n}\nclass JWKInvalid extends JOSEError {\n  static code = \"ERR_JWK_INVALID\";\n  code = \"ERR_JWK_INVALID\";\n}\nclass JWKSInvalid extends JOSEError {\n  static code = \"ERR_JWKS_INVALID\";\n  code = \"ERR_JWKS_INVALID\";\n}\nclass JWKSNoMatchingKey extends JOSEError {\n  static code = \"ERR_JWKS_NO_MATCHING_KEY\";\n  code = \"ERR_JWKS_NO_MATCHING_KEY\";\n  constructor(message = \"no applicable key found in the JSON Web Key Set\", options) {\n    super(message, options);\n  }\n}\nclass JWKSMultipleMatchingKeys extends JOSEError {\n  [Symbol.asyncIterator] = async function* () {\n  };\n  static code = \"ERR_JWKS_MULTIPLE_MATCHING_KEYS\";\n  code = \"ERR_JWKS_MULTIPLE_MATCHING_KEYS\";\n  constructor(message = \"multiple matching keys found in the JSON Web Key Set\", options) {\n    super(message, options);\n  }\n}\nclass JWKSTimeout extends JOSEError {\n  static code = \"ERR_JWKS_TIMEOUT\";\n  code = \"ERR_JWKS_TIMEOUT\";\n  constructor(message = \"request timed out\", options) {\n    super(message, options);\n  }\n}\nclass JWSSignatureVerificationFailed extends JOSEError {\n  static code = \"ERR_JWS_SIGNATURE_VERIFICATION_FAILED\";\n  code = \"ERR_JWS_SIGNATURE_VERIFICATION_FAILED\";\n  constructor(message = \"signature verification failed\", options) {\n    super(message, options);\n  }\n}\nexport {\n  JOSEAlgNotAllowed,\n  JOSEError,\n  JOSENotSupported,\n  JWEDecryptionFailed,\n  JWEInvalid,\n  JWKInvalid,\n  JWKSInvalid,\n  JWKSMultipleMatchingKeys,\n  JWKSNoMatchingKey,\n  JWKSTimeout,\n  JWSInvalid,\n  JWSSignatureVerificationFailed,\n  JWTClaimValidationFailed,\n  JWTExpired,\n  JWTInvalid\n};\n","import { encoder, decoder, encodeBase64, decodeBase64 } from \"../lib/buffer_utils.js\";\nconst invalid = \"The input to be decoded is not correctly encoded.\";\nfunction decode(input) {\n  try {\n    return decodeBase64(typeof input == \"string\" ? input : decoder.decode(input), !0);\n  } catch (cause) {\n    throw new TypeError(invalid, { cause });\n  }\n}\nfunction encode(input) {\n  return encodeBase64(typeof input == \"string\" ? encoder.encode(input) : input, !0);\n}\nexport {\n  decode,\n  encode\n};\n","import { JOSENotSupported, JWSInvalid } from \"../util/errors.js\";\nimport { decode } from \"../util/base64url.js\";\nimport { encode, strictDecoder } from \"./buffer_utils.js\";\nfunction assertUint8Array(input, label) {\n  if (!(input instanceof Uint8Array))\n    throw new TypeError(`${label} must be an instance of Uint8Array`);\n}\nfunction isObject(input) {\n  if (typeof input != \"object\" || input === null || Object.prototype.toString.call(input) !== \"[object Object]\")\n    return !1;\n  const prototype = Object.getPrototypeOf(input);\n  return prototype === null || Object.getPrototypeOf(prototype) === null;\n}\nfunction isJwkSet(input) {\n  return isObject(input) && Array.isArray(input.keys) && Array.from(input.keys).every(isObject);\n}\nfunction isDisjoint(...headers) {\n  const parameters = /* @__PURE__ */ new Set();\n  for (const header of headers)\n    if (header)\n      for (const parameter of Object.keys(header)) {\n        if (parameters.has(parameter))\n          return !1;\n        parameters.add(parameter);\n      }\n  return !0;\n}\nfunction assertNotSet(value, name) {\n  if (value !== void 0)\n    throw new TypeError(`${name} can only be called once`);\n}\nfunction decodeBase64url(value, label, ErrorClass) {\n  try {\n    return decode(value);\n  } catch {\n    throw new ErrorClass(`Failed to base64url decode the ${label}`);\n  }\n}\nfunction encodeBase64url(value, label, ErrorClass) {\n  try {\n    return encode(value);\n  } catch {\n    throw new ErrorClass(`The ${label} is not a valid base64url string`);\n  }\n}\nfunction parseJoseHeader(b64, ErrorClass, message) {\n  let parsed;\n  try {\n    parsed = JSON.parse(strictDecoder.decode(decode(b64)));\n  } catch {\n    throw new ErrorClass(message);\n  }\n  if (!isObject(parsed))\n    throw new ErrorClass(message);\n  return parsed;\n}\nconst JWS_RECOGNIZED = { __proto__: null, b64: !0 }, JWE_RECOGNIZED = { __proto__: null };\nfunction validateAlgorithms(option, algorithms) {\n  if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s != \"string\")))\n    throw new TypeError(`\"${option}\" option must be an array of strings`);\n  return algorithms === void 0 ? void 0 : new Set(algorithms);\n}\nfunction validateCritDuplicates(Err, protectedHeader) {\n  const { crit } = protectedHeader ?? {};\n  if (Array.isArray(crit) && new Set(crit).size !== crit.length)\n    throw new Err('\"crit\" (Critical) Header Parameter MUST NOT contain duplicate values');\n}\nfunction validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {\n  if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0)\n    throw new Err('\"crit\" (Critical) Header Parameter MUST be integrity protected');\n  if (!protectedHeader || protectedHeader.crit === void 0)\n    return [];\n  if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input != \"string\" || input.length === 0))\n    throw new Err('\"crit\" (Critical) Header Parameter MUST be an array of non-empty strings when present');\n  const recognized = recognizedOption === void 0 ? recognizedDefault : { __proto__: null, ...recognizedOption, ...recognizedDefault };\n  for (const parameter of protectedHeader.crit) {\n    if (!(parameter in recognized))\n      throw new JOSENotSupported(`Extension Header Parameter \"${parameter}\" is not recognized`);\n    if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === void 0)\n      throw new Err(`Extension Header Parameter \"${parameter}\" is missing`);\n    if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === void 0))\n      throw new Err(`Extension Header Parameter \"${parameter}\" MUST be integrity protected`);\n  }\n  return protectedHeader.crit;\n}\nfunction validateB64(protectedHeader, extensions) {\n  if (extensions.includes(\"b64\")) {\n    const b64 = protectedHeader.b64;\n    if (typeof b64 != \"boolean\")\n      throw new JWSInvalid('The \"b64\" (base64url-encode payload) Header Parameter must be a boolean');\n    return b64;\n  }\n  return !0;\n}\nfunction serializeJoseHeader(Err, header) {\n  let serialized, parsed;\n  try {\n    serialized = JSON.stringify(header), parsed = JSON.parse(serialized);\n  } catch (cause) {\n    throw new Err(\"JOSE Header is not valid JSON\", { cause });\n  }\n  if (!isObject(parsed))\n    throw new Err(\"JOSE Header is not a JSON object\");\n  return [parsed, serialized];\n}\nexport {\n  JWE_RECOGNIZED,\n  JWS_RECOGNIZED,\n  assertNotSet,\n  assertUint8Array,\n  decodeBase64url,\n  encodeBase64url,\n  isDisjoint,\n  isJwkSet,\n  isObject,\n  parseJoseHeader,\n  serializeJoseHeader,\n  validateAlgorithms,\n  validateB64,\n  validateCrit,\n  validateCritDuplicates\n};\n","import { decode as b64u } from \"./base64url.js\";\nimport { strictDecoder } from \"../lib/buffer_utils.js\";\nimport { isObject } from \"../lib/validate.js\";\nimport { JWTInvalid } from \"./errors.js\";\nfunction decodeJwt(jwt) {\n  if (typeof jwt != \"string\")\n    throw new JWTInvalid(\"JWTs must use Compact JWS serialization, JWT must be a string\");\n  const { 1: payload, length } = jwt.split(\".\");\n  if (length === 5)\n    throw new JWTInvalid(\"Only JWTs using Compact JWS serialization can be decoded\");\n  if (length !== 3)\n    throw new JWTInvalid(\"Invalid JWT\");\n  if (!payload)\n    throw new JWTInvalid(\"JWTs must contain a payload\");\n  let decoded;\n  try {\n    decoded = b64u(payload);\n  } catch {\n    throw new JWTInvalid(\"Failed to base64url decode the payload\");\n  }\n  let result;\n  try {\n    result = JSON.parse(strictDecoder.decode(decoded));\n  } catch {\n    throw new JWTInvalid(\"Failed to parse the decoded payload as JSON\");\n  }\n  if (!isObject(result))\n    throw new JWTInvalid(\"Invalid JWT Claims Set\");\n  return result;\n}\nexport {\n  decodeJwt\n};\n","import { redirect } from '@sveltejs/kit';\nimport { isBlank, Cache } from 'txstate-utils';\nimport { decodeJwt } from 'jose';\nimport { invalidateAll } from '$app/navigation';\nconst mayImpersonateAnyCache = new Cache(async (token, api) => {\n    const authUrl = new URL(api.authRedirect);\n    const mayImpersonateUrl = new URL('/mayImpersonate', authUrl.origin);\n    try {\n        const resp = await fetch(mayImpersonateUrl, {\n            method: 'POST',\n            headers: {\n                'Authorization': `Bearer ${token}`,\n                'Content-Type': 'application/json'\n            },\n            body: JSON.stringify({})\n        });\n        if (!resp.ok)\n            return false;\n        const { authorized } = await resp.json();\n        return !!authorized;\n    }\n    catch {\n        return false;\n    }\n});\nconst mayImpersonateNetidCache = new Cache(async ({ token, netid }, api) => {\n    const authUrl = new URL(api.authRedirect);\n    const mayImpersonateUrl = new URL('/mayImpersonate', authUrl.origin);\n    try {\n        const resp = await fetch(mayImpersonateUrl, {\n            method: 'POST',\n            headers: {\n                'Authorization': `Bearer ${token}`,\n                'Content-Type': 'application/json'\n            },\n            body: JSON.stringify({ netid })\n        });\n        if (!resp.ok)\n            return false;\n        const { authorized } = await resp.json();\n        return !!authorized;\n    }\n    catch {\n        return false;\n    }\n});\nexport const unifiedAuth = {\n    /**\n     * Your root +layout.ts' load function should call this method to ensure that it\n     * handles authentication from Unified Auth. By default it will redirect unauthenticated\n     * users to Unified Auth without a screen flash.\n     *\n     * If you set allowUnauthenticated: true and wait for the API to send a 401, there\n     * will often be a screen flash.\n     */\n    async handle(api, input, opts) {\n        const unifiedJwt = input.url.searchParams.get('unifiedJwt') ?? undefined;\n        await api.init(unifiedJwt);\n        if (unifiedJwt) {\n            let redirectUrl = input.url.searchParams.get('requestedUrl') ?? undefined;\n            if (!redirectUrl) {\n                const currentUrl = new URL(input.url);\n                currentUrl.searchParams.delete('unifiedJwt');\n                redirectUrl = currentUrl.toString();\n            }\n            throw redirect(302, redirectUrl);\n        }\n        window.addEventListener('pageshow', (event) => {\n            if (event.persisted && isBlank(sessionStorage.getItem('token'))) {\n                api.token = undefined;\n                invalidateAll();\n            }\n        });\n        if (!opts?.allowUnauthenticated)\n            this.requireAuth(api, input);\n    },\n    loginRedirect(api, currentUrl) {\n        const loginRedirect = new URL(api.authRedirect);\n        loginRedirect.searchParams.set('requestedUrl', currentUrl);\n        return loginRedirect;\n    },\n    logout(api) {\n        if (isBlank(api.token))\n            return;\n        // If impersonating, use the original token for logout\n        const originalToken = sessionStorage.getItem('originalToken');\n        const token = originalToken ?? api.token;\n        const authRedirect = new URL(api.authRedirect);\n        authRedirect.pathname = [...authRedirect.pathname.split('/').slice(0, -1), 'logout'].join('/');\n        authRedirect.searchParams.set('unifiedJwt', token);\n        api.token = undefined;\n        sessionStorage.removeItem('token');\n        sessionStorage.removeItem('originalToken');\n        location.href = authRedirect.toString();\n    },\n    requireAuth(api, input) {\n        if (!api.token) {\n            throw redirect(302, this.loginRedirect(api, input.url.toString()));\n        }\n    },\n    /**\n     * Start impersonating a user. This will store the current token and replace it with\n     * an impersonation token obtained from Unified Auth.\n     *\n     * The impersonation token will expire in 1 hour.\n     */\n    async impersonate(api, netid) {\n        if (isBlank(api.token))\n            throw new Error('Must be authenticated to impersonate.');\n        // Store original token before impersonating\n        const originalToken = api.token;\n        sessionStorage.setItem('originalToken', originalToken);\n        // Get impersonation token from unified-auth\n        const authUrl = new URL(api.authRedirect);\n        const impersonateUrl = new URL('/impersonate', authUrl.origin);\n        const resp = await fetch(impersonateUrl, {\n            method: 'POST',\n            headers: {\n                'Authorization': `Bearer ${originalToken}`,\n                'Content-Type': 'application/json'\n            },\n            body: JSON.stringify({ netid })\n        });\n        if (!resp.ok) {\n            const error = await resp.text();\n            throw new Error(`Failed to impersonate: ${error}`);\n        }\n        const { token } = await resp.json();\n        // Replace current token with impersonation token\n        api.token = token;\n        sessionStorage.setItem('token', token);\n    },\n    /**\n     * Exit impersonation and restore the original token.\n     */\n    exitImpersonation(api) {\n        const originalToken = sessionStorage.getItem('originalToken');\n        if (!originalToken) {\n            throw new Error('No original token found. Not currently impersonating.');\n        }\n        api.token = originalToken;\n        sessionStorage.setItem('token', originalToken);\n        sessionStorage.removeItem('originalToken');\n    },\n    /**\n     * Check if the current token is an impersonation token.\n     * Returns { isImpersonating: false } if not impersonating.\n     * Returns { isImpersonating: true, impersonatedUser: string, impersonatedBy: string } if impersonating.\n     */\n    getImpersonationStatus(api) {\n        if (isBlank(api.token))\n            return { isImpersonating: false };\n        try {\n            const payload = decodeJwt(api.token);\n            if (payload.act && payload.act.sub) {\n                return {\n                    isImpersonating: true,\n                    impersonatedUser: payload.sub,\n                    impersonatedBy: payload.act.sub\n                };\n            }\n        }\n        catch (e) {\n            // Invalid token, treat as not impersonating\n        }\n        return { isImpersonating: false };\n    },\n    /**\n     * Check if the current user is authorized to impersonate anyone.\n     * Results are cached to avoid repeated requests.\n     *\n     * @param api The API instance\n     * @returns A promise that resolves to true if authorized to impersonate, false otherwise\n     */\n    async mayImpersonateAny(api) {\n        if (isBlank(api.token))\n            return false;\n        return await mayImpersonateAnyCache.get(api.token, api);\n    },\n    /**\n     * Check if the current user is authorized to impersonate a specific user.\n     * Results are cached to avoid repeated requests.\n     *\n     * @param api The API instance\n     * @param netid The netid to check authorization for\n     * @returns A promise that resolves to true if authorized, false otherwise\n     */\n    async mayImpersonate(api, netid) {\n        if (isBlank(api.token))\n            return false;\n        return await mayImpersonateNetidCache.get({ token: api.token, netid }, api);\n    }\n};\n","import { toasts } from '@txstate-mws/svelte-components';\nimport { error } from '@sveltejs/kit';\nimport { get } from 'svelte/store';\nimport { isNotBlank, isNull, omit, pick, rescue, toArray } from 'txstate-utils';\nimport { page } from '$app/stores';\nimport { afterNavigate } from '$app/navigation';\nimport { unifiedAuth } from './unifiedauth.js';\n/**\n * Provided for convenience in case you are not using APIBase but still want to record navigations\n *\n * If you are using or extending APIBase, call `api.recordNavigations` instead.\n *\n * Must be called from a svelte component. Should usually be your root +layout.svelte.\n */\nexport function recordNavigations(callback) {\n    let timer = 0;\n    let from;\n    afterNavigate(navigation => {\n        // save off the navigation.from in case we're debouncing a redirect\n        if (timer === 0)\n            from = navigation.from;\n        clearTimeout(timer); // we are debouncing because sometimes afterNavigate gets called twice\n        timer = setTimeout(() => {\n            callback({ eventType: 'sveltekit-utils-navigation', screen: (from ?? navigation.to)?.route.id, target: navigation.to?.url.pathname, action: 'navigation', additionalProperties: { fullPageLoad: String(!from) } });\n            timer = 0;\n        }, 10);\n    });\n}\n/**\n * A non-mutating function that will replace all File objects in the variables with an APIUploadInfo\n * object, and put the original File object into the files array so it can be appended to the multipart\n * upload.\n *\n * When I say non-mutating, I mean it will not modify the original variables object. It will mutate the\n * files parameter, which should be passed an empty array.\n */\nfunction replaceFiles(variables, files) {\n    let newVariables;\n    for (const key in variables) {\n        const val = variables[key];\n        if (val instanceof File) {\n            files.push(val);\n            newVariables ??= Array.isArray(variables) ? [...variables] : { ...variables };\n            newVariables[key] = { _type: 'APIUploadInfo', multipartIndex: files.length - 1, name: val.name, mime: val.type, size: val.size };\n        }\n        else if (val instanceof Object) {\n            const newVal = replaceFiles(val, files);\n            if (newVal !== val) {\n                newVariables ??= Array.isArray(variables) ? [...variables] : { ...variables };\n                newVariables[key] = newVal;\n            }\n        }\n    }\n    return newVariables ?? variables;\n}\nexport class APIBase {\n    apiBase;\n    authRedirect;\n    loginRedirect;\n    token;\n    fetch;\n    ready;\n    readyPromise;\n    constructor(apiBase, authRedirect, loginRedirect = unifiedAuth.loginRedirect) {\n        this.apiBase = apiBase;\n        this.authRedirect = authRedirect;\n        this.loginRedirect = loginRedirect;\n        this.readyPromise = new Promise(resolve => { this.ready = resolve; });\n    }\n    async init(token, fetch) {\n        this.fetch = fetch ?? this.fetch;\n        if (token) {\n            this.token = token;\n            sessionStorage.setItem('token', token);\n        }\n        else {\n            this.token ??= sessionStorage.getItem('token') ?? undefined;\n        }\n        if (typeof document !== 'undefined') {\n            document.addEventListener(\"visibilitychange\", () => {\n                if (document.visibilityState === \"hidden\") {\n                    this.sendBatchedAnalytics().catch(console.error);\n                }\n            });\n        }\n        this.ready();\n    }\n    stringifyQuery(query) {\n        if (query == null)\n            return '';\n        if (typeof query === 'string')\n            return query.startsWith('?') ? query : '?' + query;\n        const p = new URLSearchParams();\n        for (const [key, val] of Object.entries(query)) {\n            for (const v of toArray(val))\n                p.append(key, String(v));\n        }\n        return '?' + p.toString();\n    }\n    async request(path, method, opts) {\n        await this.readyPromise;\n        try {\n            const resp = await this.fetch(this.apiBase + path + this.stringifyQuery(opts?.query), {\n                method,\n                keepalive: opts?.keepalive,\n                headers: {\n                    Authorization: `Bearer ${this.token ?? ''}`,\n                    Accept: 'application/json',\n                    ...(opts?.body ? { 'Content-Type': 'application/json' } : {})\n                },\n                body: opts?.body ? JSON.stringify(opts.body) : undefined\n            });\n            const contentType = resp.headers.get(\"content-type\");\n            const isJsonResponse = contentType && contentType.indexOf(\"application/json\") !== -1;\n            if (!resp.ok && !(resp.status === 422 && opts?.inlineValidation)) {\n                if (resp.status === 401) {\n                    location.href = this.loginRedirect(this, location.href).toString();\n                    throw error(401);\n                }\n                else {\n                    const body = (isJsonResponse ? (await rescue(resp.json())) : await rescue(resp.text())) ?? resp.statusText;\n                    let message = '';\n                    if (typeof body === 'string')\n                        message = body;\n                    else if (body.message)\n                        message = body.message;\n                    else if (body[0]?.message)\n                        message = body[0].message;\n                    throw error(resp.status, message);\n                }\n            }\n            return ((isJsonResponse) ? await resp.json() : await resp.text());\n        }\n        catch (e) {\n            toasts.add(e.body?.message ?? e.message);\n            throw e;\n        }\n    }\n    async uploadWithProgress(path, formData, progress) {\n        await this.readyPromise;\n        try {\n            return await new Promise((resolve, reject) => {\n                try {\n                    progress({ loaded: 0, total: 0, ratio: 0 });\n                    const request = new XMLHttpRequest();\n                    request.open('POST', this.apiBase + path);\n                    if (this.token)\n                        request.setRequestHeader('Authorization', `Bearer ${this.token}`);\n                    request.setRequestHeader('Accept', 'application/json');\n                    request.upload.addEventListener('progress', e => progress({ ...pick(e, 'loaded', 'total'), ratio: e.lengthComputable ? e.loaded / e.total : 0.1 }));\n                    // request finished\n                    request.addEventListener('load', e => {\n                        if (request.status >= 400)\n                            reject(new Error(request.responseText));\n                        else {\n                            try {\n                                resolve(JSON.parse(request.responseText));\n                            }\n                            catch (e) {\n                                reject(e);\n                            }\n                        }\n                    });\n                    request.addEventListener('abort', e => reject(new Error('Upload aborted.')));\n                    request.addEventListener('error', e => reject(new Error('An error occurred during transfer. Upload not completed.')));\n                    request.send(formData);\n                }\n                catch (e) {\n                    reject(e);\n                }\n            });\n        }\n        finally {\n            progress(undefined);\n        }\n    }\n    async get(path, query) {\n        return await this.request(path, 'GET', { query });\n    }\n    /**\n     * Remember to use validatedPost when the user is interacting with a form. That way they\n     * will get inline errors.\n     */\n    async post(path, body, query) {\n        return await this.request(path, 'POST', { body, query });\n    }\n    /**\n     * Remember to use validatedPut when the user is interacting with a form. That way they\n     * will get inline errors.\n     */\n    async put(path, body, query) {\n        return await this.request(path, 'PUT', { body, query });\n    }\n    /**\n     * Remember to use validatedPatch when the user is interacting with a form. That way they\n     * will get inline errors.\n     */\n    async patch(path, body, query) {\n        return await this.request(path, 'PATCH', { body, query });\n    }\n    /**\n     * Use this method when the user is interacting with a form. You should expect a ValidatedResponse,\n     * e.g. { success: false, messages: [{ type: 'error', message: 'That name is already taken.', path: 'name' }] }\n     */\n    async validatedPost(path, body, query) {\n        return await this.request(path, 'POST', { body, query, inlineValidation: true });\n    }\n    /**\n     * Use this method when the user is interacting with a form. You should expect a ValidatedResponse,\n     * e.g. { success: false, messages: [{ type: 'error', message: 'That name is already taken.', path: 'name' }] }\n     */\n    async validatedPut(path, body, query) {\n        return await this.request(path, 'PUT', { body, query, inlineValidation: true });\n    }\n    /**\n     * Use this method when the user is interacting with a form. You should expect a ValidatedResponse,\n     * e.g. { success: false, messages: [{ type: 'error', message: 'That name is already taken.', path: 'name' }] }\n     */\n    async validatedPatch(path, body, query) {\n        return await this.request(path, 'PATCH', { body, query, inlineValidation: true });\n    }\n    /**\n     * Sending a JSON body with an HTTP DELETE is not recommended\n     */\n    async delete(path, query, body) {\n        return await this.request(path, 'DELETE', { body, query });\n    }\n    async graphql(query, variables, querySignature) {\n        const gqlresponse = await this.request('/graphql', 'POST', { body: {\n                query,\n                variables,\n                extensions: {\n                    querySignature\n                }\n            } });\n        if (gqlresponse.errors?.length) {\n            toasts.add(gqlresponse.errors[0].message);\n            throw new Error(JSON.stringify(gqlresponse.errors));\n        }\n        return gqlresponse.data;\n    }\n    /**\n     * This is a special graphql request method that allows you to upload files. It will\n     * find all the File objects in the variables and replace them with an APIUploadInfo object.\n     *\n     * Then it will send a multipart/form-data request instead of a standard JSON body, and all\n     * the file data will be included in later parts.\n     */\n    async graphqlWithUploads(query, variables, options) {\n        const files = [];\n        variables = replaceFiles(variables, files);\n        // If we are only validating, we don't need to upload files\n        const omitUploads = options?.omitUploads != null ? options.omitUploads : !!variables.validateOnly;\n        if (omitUploads || !files.length)\n            return this.graphql(query, variables, options?.querySignature);\n        const form = new FormData();\n        form.set('body', JSON.stringify({\n            query,\n            variables,\n            extensions: {\n                querySignature: options?.querySignature\n            }\n        }));\n        for (let i = 0; i < files.length; i++)\n            form.set(`file${i}`, files[i]);\n        const gqlresponse = await this.uploadWithProgress('/graphql', form, options?.progress ?? (() => { }));\n        if (gqlresponse.errors?.length) {\n            toasts.add(gqlresponse.errors[0].message);\n            throw new Error(JSON.stringify(gqlresponse.errors));\n        }\n        return gqlresponse.data;\n    }\n    lastAnalyticsSent = new Date().getTime();\n    analyticsQueue = [];\n    analyticsTimer;\n    recordInteraction(evt) {\n        evt.screen ??= get(page).route.id;\n        this.analyticsQueue.push(evt);\n        clearTimeout(this.analyticsTimer);\n        // If the last analytics was sent more than 2 seconds ago, send immediately\n        if (new Date().getTime() - this.lastAnalyticsSent > 2000)\n            this.sendBatchedAnalytics().catch(console.error);\n        // Otherwise, collect more analytics for up to 2 seconds\n        else\n            this.analyticsTimer = setTimeout(() => this.sendBatchedAnalytics().catch(console.error), 2000);\n    }\n    async sendBatchedAnalytics() {\n        const events = [...this.analyticsQueue];\n        this.analyticsQueue.length = 0;\n        if (events.length) {\n            this.lastAnalyticsSent = new Date().getTime();\n            // keepalive true means the request will not be cancelled even if the user navigates away\n            await this.request('/analytics', 'POST', { body: events, keepalive: true });\n        }\n    }\n    /**\n     * Due to the mechanics of sveltekit, this function cannot be fully automatic and must\n     * be called in your global +layout.svelte\n     */\n    recordNavigations() {\n        recordNavigations(this.recordInteraction.bind(this));\n    }\n    /**\n     * This function is used to convert MutationMessageType[] that comes from our standard\n     * graphql servers into the Feedback[] type expected by svelte-forms.\n     *\n     * It will also remove a prefix from the arg property if you pass one in. This is useful\n     * because your graphql service should always be creating paths relative to the mutation's\n     * argument root, but the UI may not care how that's done.\n     *\n     * For example, consider the difference between `{ updateUser(id: ID!, name: String!, email: String!) {...} }`\n     * and `{ updateUser(id: ID!, user: UserInfo!) {...} }`. The first one should be sending back messages\n     * with `arg` like `name` or `email`, while the second one should be sending back messages with `arg`\n     * like `user.name` or `user.email` - because any user of the GraphQL API should expect that format after\n     * seeing the mutation signature.\n     *\n     * If your UI form for editing the user uses paths like `name` and `email`, you can pass `user` as the\n     * prefix to the second example and this function will remove it from the `arg` property when it creates\n     * the `path` property.\n     */\n    messageForDialog(messages, prefix) {\n        return messages.map(m => {\n            return { ...omit(m, 'arg'), path: isNull(m.arg) ? null : isNotBlank(prefix) ? m.arg.replace(RegExp('^' + prefix + '\\\\.'), '') : m.arg };\n        });\n    }\n    mutationForDialog(resp, { prefix, dataName } = {}) {\n        return { success: resp.success, messages: this.messageForDialog(resp.messages, prefix), data: (dataName ? resp[dataName] : undefined) };\n    }\n}\n","import { PUBLIC_API_BASE, PUBLIC_AUTH_REDIRECT } from '$env/static/public'\nimport { type BaseOutcomeTypeCreate, type Organization, type Degree, type DegreeCreate, type DegreeUpdate, type Goal, type GoalCreate, type Initiative, type InitiativeCreate, type OutcomeType, type OrganizationPatch, type OrganizationUpdate, type OrganizationCreate, type OrganizationValidatedResponse, type OrganizationTemplate, type Assessment, type AssessmentTask, type AssessmentListFilters, type AssessmentPatch, type AssessmentValidatedResponse, type OutcomeCreate, type MethodCreate, type OutcomeValidatedResponse, type MethodValidatedResponse, type OutcomePatch, type AuditForm, type AssessmentAudit, type MethodPatch, type Category, type AssessmentActionBody, type AssessmentActivity, type AuditValidatedResponse, type Audit, type Access, type BaseOutcomeTypeUpdate, type OrganizationAllowedDestination, type Competency, type Component, type AssessmentReport, type AssessmentReportFilters, type AuditAssessmentPhase, type AuditFormQuestionGroup, type AuditFormValidatedResponse, type AuditFormQuestionBody } from '@shared'\nimport type { ValidatedResponse, QueryWithValidateFlag } from '@txstate-mws/fastify-shared'\nimport { APIBase, type APIBaseQueryPayload } from '@txstate-mws/sveltekit-utils'\nimport { isEmpty, sortby, toQuery } from 'txstate-utils'\n\nconst orgTypeSorter: Record<string, Record<string, number>> = {\n  Academic: {\n    College: 0,\n    Department: 2,\n    Program: 4\n  },\n  Administrative: {\n    Division: 1,\n    Unit: 3,\n    Department: 5\n  }\n}\n\nclass API extends APIBase {\n  stringifyQuery (query: undefined | APIBaseQueryPayload) {\n    return isEmpty(query) ? '' : '?' + toQuery(query)\n  }\n\n  async getAccess () {\n    return await this.get<Access>('/access')\n  }\n\n  //\n  // DEGREES\n  //\n  async getDegrees () {\n    return await this.get<Degree[]>('/degrees')\n  }\n\n  async getDegree (id: string) {\n    return await this.get<Degree>('/degrees/' + id)\n  }\n\n  async upsertDegree (degree: DegreeCreate, { validate, name }: QueryWithValidateFlag & { name?: string }) {\n    return name == null\n      ? await this.validatedPost<ValidatedResponse & { degree?: Degree }>('/degrees', degree, { validate })\n      : await this.validatedPut<ValidatedResponse & { degree?: Degree }>('/degrees/' + name, degree, { validate })\n  }\n\n  async createDegree (degree: DegreeCreate, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPost<ValidatedResponse & { degree: Degree }>('/degrees', degree, { validate })\n  }\n\n  async updateDegree (degree: DegreeUpdate, { validate, name }: QueryWithValidateFlag & { name: string }) {\n    return await this.validatedPut<ValidatedResponse & { degree: Degree }>('/degrees/' + encodeURIComponent(degree.name), { name, enabled: degree.enabled }, { validate })\n  }\n\n  async toggleDegree (degree: DegreeUpdate, enabled: boolean) {\n    return await this.validatedPatch<ValidatedResponse & { degree: Degree }>('/degrees/' + encodeURIComponent(degree.name) + `?enabled=${enabled}`, {})\n  }\n\n  async deleteDegree (degree: Degree) {\n    return await this.delete<ValidatedResponse & { degree?: Degree }>('/degrees/' + encodeURIComponent(degree.name))\n  }\n\n  //\n  // GOALS\n  //\n  async getGoals () {\n    return await this.get<Goal[]>('/goals')\n  }\n\n  async getGoal (id: string) {\n    return await this.get<Goal>('/goal/' + id)\n  }\n\n  async patchGoalOrder (id: string, beforeId: string) {\n    return await this.validatedPatch<ValidatedResponse & { goal: Goal }>('/goals/' + encodeURIComponent(id) + `?orderBefore_id=${beforeId}`)\n  }\n\n  async upsertGoal (goal: GoalCreate, { validate, description }: QueryWithValidateFlag & { description?: string }) {\n    return description == null\n      ? await this.validatedPost<ValidatedResponse & { goal?: Goal }>('/goals', goal, { validate })\n      : await this.validatedPut<ValidatedResponse & { goal?: Goal }>('/goals/' + encodeURIComponent(description), goal, { validate })\n  }\n\n  async createGoal (goal: GoalCreate, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPost<ValidatedResponse & { goal: Goal }>('/goals', goal, { validate })\n  }\n\n  // async updateGoal (goal: GoalUpdate, { validate, _id }: QueryWithValidateFlag & { _id: string }) {\n  //   return await this.validatedPut<ValidatedResponse & { goal: Goal }>('/goals/' + encodeURIComponent(goal.description), { _id, enabled: goal.enabled }, { validate })\n  // }\n\n  // PUT endpoint: /goals/{goal_id}/initiatives/{initiative_id}\n  async updateGoal (goal: Goal, { validate }: QueryWithValidateFlag) {\n    if (goal._id) {\n      return await this.validatedPut<ValidatedResponse & { goal: Goal }>('/goals/' + encodeURIComponent(goal._id), { ...goal }, { validate })\n    }\n  }\n\n  async toggleGoal (goal: Goal, enabled: boolean) {\n    return await this.validatedPut<ValidatedResponse & { goal: Goal }>('/goals/' + encodeURIComponent(goal._id), { description: goal.description, enabled })\n  }\n\n  // DELERTE /goals/{_id}\n  async deleteGoal (goal: Goal) {\n    if (goal._id) {\n      return await this.delete<ValidatedResponse & { goal?: Goal }>('/goals/' + encodeURIComponent(goal._id))\n    }\n  }\n\n  //\n  // Initiatives\n  //\n\n  // GET endpoint: /goals/{goal_id}/initiatives\n  async getInitiatives (id: string) {\n    // endpoint: /goals/{goal_id}/initiatives\n    return await this.get<Initiative[]>('/goals/' + id + '/initiatives')\n  }\n\n  // POST endpoint: /goals/{goal_id}/initiatives\n\n  // eslint-disable-next-line @typescript-eslint/naming-convention\n  async postInitiative (initiative: InitiativeCreate, { validate, goal_id }: QueryWithValidateFlag & { goal_id: string }) {\n    return await this.validatedPost<ValidatedResponse & { initiative: Initiative }>(`/goals/${goal_id}/initiatives`, initiative, { validate })\n  }\n\n  // PUT endpoint: /goals/{goal_id}/initiatives/{initiative_id}\n  async putInitiative (initiative: Initiative, { validate, _id }: QueryWithValidateFlag & { _id: string }) {\n    return await this.validatedPut<ValidatedResponse & { initiative: Initiative }>('/goals/' + encodeURIComponent(initiative.goal_id) + '/initiatives/' + encodeURIComponent(_id), { ...initiative }, { validate })\n  }\n\n  // PATCH (for toggle) endpoint: /goals/{goal_id}/initiatives/{initiative_id}\n  async patchInitiative (initiative: Initiative, enabled: boolean) {\n    if (initiative.goal_id) {\n      return await this.patch<ValidatedResponse & { initiative?: Initiative }>('/goals/' + encodeURIComponent(initiative.goal_id) + `/initiatives/${initiative._id}?enabled=${enabled}`)\n    }\n  }\n\n  async patchInitiativeOrder (goalId: string, id: string, beforeId: string) {\n    return await this.validatedPatch<ValidatedResponse & { initiative: Initiative }>('/goals/' + encodeURIComponent(goalId) + `/initiatives/${id}?orderBefore_id=${beforeId}`)\n  }\n\n  // DELETE endpoint: /goals/{goal_id}/initiatives/{initiative_id}\n  async deleteInitiative (initiative: Initiative) {\n    if (initiative.goal_id) {\n      return await this.delete<ValidatedResponse & { initiative?: Initiative }>('/goals/' + encodeURIComponent(initiative.goal_id) + '/initiatives/' + encodeURIComponent(initiative._id))\n    }\n  }\n\n  //\n  // Outcome Types\n  //\n\n  // GET\n  async getOutcomeTypes () {\n    return await this.get<OutcomeType[]>('/outcometypes')\n  }\n\n  // PATCH for toggle\n  async patchOutcomeTypes (name: string, enabled: boolean) {\n    return await this.patch<ValidatedResponse & { outcomeType?: OutcomeType }>('/outcometypes/' + encodeURIComponent(name) + `?enabled=${enabled}`)\n  }\n\n  async deleteOutcomeTypes (name: string) {\n    return await this.delete<ValidatedResponse & { outcomeType?: OutcomeType }>('/outcometypes/' + encodeURIComponent(name))\n  }\n\n  async postOutcomeTypes (outcomeType: BaseOutcomeTypeCreate, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPost<ValidatedResponse & { outcomeType?: OutcomeType }>('/outcometypes', outcomeType, { validate })\n  }\n\n  async putOutcomeTypes (outcomeType: BaseOutcomeTypeUpdate, { validate, name }: QueryWithValidateFlag & { name: string }) {\n    return await this.validatedPut<ValidatedResponse & { outcomeType: OutcomeType }>('/outcometypes/' + encodeURIComponent(name), { ...outcomeType }, { validate })\n  }\n\n\n  //\n  // Orgs\n  //\n\n  async getOrgTemplate (filterRoute: string) {\n    return await this.get<OrganizationTemplate>(`/templates/organizations${filterRoute}`)\n  }\n\n  async getOrgs (filterRoute: string) {\n    const response = await this.get<Organization[]>(`/organizations${filterRoute}`)\n    return response\n  }\n\n  collectOrgs (orgs: Organization[]): Organization[] {\n    const children = orgs.flatMap(o => o.childOrganizations ?? [])\n    if (children.length) return [...orgs, ...this.collectOrgs(orgs.flatMap(o => o.childOrganizations ?? []))]\n    return orgs\n  }\n\n  async getAllOrgs () {\n    const orgs = await this.get<Organization[]>('/organizations')\n    return sortby(this.collectOrgs(orgs), o => orgTypeSorter[o.classification][o.type])\n  }\n\n  async getOrgList () {\n    const orgs = await this.get<Organization[]>('/organizations')\n    return orgs\n  }\n\n  async getDestinations (filterRoute: string) {\n    const response = await this.get<OrganizationAllowedDestination[]>(`/destinations/organizations${filterRoute}`)\n    return response\n  }\n\n  // using this for enable/disable for the moment\n  async putOrg (org: OrganizationUpdate, filterRoute: string, { validate, name }: QueryWithValidateFlag & { name?: string }) {\n    const orgName = name || org.name\n    return await this.validatedPut<OrganizationValidatedResponse>(`/organizations${filterRoute}/${encodeURIComponent(orgName)}`, { ...org }, { validate })\n  }\n\n  async postOrg (org: OrganizationCreate, url: string, { validate }: QueryWithValidateFlag) {\n    // const path = url.replace('/academic/', '').replace(/%20/g, ' ')\n    // const endpoint = (encodeURIComponent(path))\n    return await this.validatedPost<OrganizationValidatedResponse>(`/organizations${url}`, org, { validate })\n  }\n\n\n  async organizationPatch (data: OrganizationPatch, Route: string, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPatch<ValidatedResponse>(`/organizations${Route}`, data, { validate })\n  }\n\n  //  PATCH (for toggle) endpoint using query string: /organizations/{classification}/{filterRoute}?enabled={true/false}. Empty body used for fastify.\n  async toggleOrg (name: string, Route: string, enabled: boolean) {\n    return await this.validatedPatch<ValidatedResponse & { organization?: OrganizationPatch }>(`/organizations${Route}/${encodeURIComponent(name)}?enabled=${enabled}`, {})\n  }\n\n  // Dashboards\n  async getTasks (filters: AssessmentListFilters) {\n    return await this.get<AssessmentTask[]>('/assessments', filters as APIBaseQueryPayload)\n  }\n\n  async getYears () {\n    return await this.get<{ openingYear: number, year: string }[]>('/assessments/years')\n  }\n\n  // Assessments / Data Entry\n  async getAssessment (referenceId: string) {\n    return await this.get<Assessment>(`/assessments/${referenceId}`)\n  }\n\n  async saveAssessment (referenceId: string, payload: AssessmentPatch, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPatch<AssessmentValidatedResponse>(`/assessments/${referenceId}`, payload, { validate })\n  }\n\n  async createOutcome (referenceId: string, payload: OutcomeCreate, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPost<OutcomeValidatedResponse>(`/assessments/${referenceId}/outcomes`, payload, { validate })\n  }\n\n  async saveOutcome (outcomeId: string, payload: OutcomePatch, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPatch(`/outcomes/${outcomeId}`, payload, { validate })\n  }\n\n  async deleteOutcome (outcomeId: string) {\n    return await this.delete(`/outcomes/${outcomeId}`)\n  }\n\n  async createMethod (outcomeId: string, payload: MethodCreate, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPost<MethodValidatedResponse>(`/outcomes/${outcomeId}/methods`, payload, { validate })\n  }\n\n  async deleteMethod (methodId: string) {\n    return await this.delete(`/methods/${methodId}`)\n  }\n\n  async saveMethod (methodId: string, payload: MethodPatch, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPatch<MethodValidatedResponse>(`/methods/${methodId}`, payload, { validate })\n  }\n\n  async assessmentAction (referenceId: string, phase: 'outcomes' | 'results', stage: string, action: 'submit' | 'return', { validate }: QueryWithValidateFlag, body: AssessmentActionBody) {\n    return await this.validatedPost<AssessmentValidatedResponse>(`/assessments/${referenceId}/${phase}/${stage}/${action}`, body ?? {}, { validate })\n  }\n\n  // Audits\n  // audit form details by outcometype\n  async getOutcomeTypeAuditForms (outcomeTypeId: string, phase: string) {\n    return await this.get<AuditForm>(`/auditform/${outcomeTypeId}/${phase}`)\n  }\n\n  async enableAuditFormQuestion (auditFormId: string, questionGroupName: AuditFormQuestionGroup, questionId: string, enabled: boolean, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPatch<AuditFormValidatedResponse>(`/auditform/${auditFormId}/${encodeURIComponent(questionGroupName as string)}/${questionId}?enabled=${enabled}&validate=${validate}`)\n  }\n\n  async postAuditFormQuestion (auditFormId: string, questionGroupName: AuditFormQuestionGroup, body: AuditFormQuestionBody, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPost<AuditFormValidatedResponse>(`/auditform/${auditFormId}/${encodeURIComponent(questionGroupName as string)}?validate=${validate}`, body)\n  }\n\n  async putAuditFormQuestion (auditFormId: string, questionGroupName: AuditFormQuestionGroup, questionId: string, body: AuditFormQuestionBody, { validate }: QueryWithValidateFlag) {\n    return await this.validatedPut<AuditFormValidatedResponse>(`/auditform/${auditFormId}/${encodeURIComponent(questionGroupName as string)}/${questionId}?validate=${validate}`, body)\n  }\n\n  async deleteAuditFormQuestion (auditFormId: string, questionGroupName: AuditFormQuestionGroup, questionId: string) {\n    return await this.delete<AuditFormValidatedResponse>(`/auditform/${auditFormId}/${encodeURIComponent(questionGroupName as string)}/${questionId}`)\n  }\n\n  // audit form details by assessment\n  async getAuditForms (referenceId: string, phase: string) {\n    return await this.get<AuditForm>(`/assessments/${referenceId}/audit/${phase}`)\n  }\n\n  // Assessments / Activity Log\n  async getActivityLog (referenceId: string) {\n    return await this.get<AssessmentActivity[]>(`/assessments/${referenceId}/activities`)\n  }\n\n  async patchAuditAnswers (referenceId: string, phase: string, payload: Audit) {\n    return await this.validatedPatch<AuditValidatedResponse>(`/assessments/${referenceId}/audit/${phase}`, payload)\n  }\n\n  // Reports\n  async getAssessmentReport (filters: AssessmentReportFilters) {\n    return await this.get<AssessmentReport[]>('/assessments/reports', filters as APIBaseQueryPayload)\n  }\n}\n\nexport const api = new API(PUBLIC_API_BASE, PUBLIC_AUTH_REDIRECT)\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11],"mappings":"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"}