oro-sdk 5.10.0 → 5.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1 @@
1
- {"version":3,"file":"oro-sdk.cjs.production.min.js","sources":["../src/helpers/client.ts","../src/models/error.ts","../src/helpers/workflow.ts","../src/helpers/consult.ts","../src/helpers/patient-registration.ts","../src/helpers/vault-grants.ts","../src/helpers/prescription-refill.ts","../src/sdk-revision/client.ts","../src/client.ts","../src/services/external/clinia.ts","../src/index.ts"],"sourcesContent":["import {\n PopulatedWorkflowData,\n MetadataCategory,\n SelectedAnswersData,\n} from 'oro-sdk-apis'\nimport { PersonalInformations } from '../models/client'\n\nconst personalMetaToPrefix = {\n [MetadataCategory.Personal]: 'you',\n [MetadataCategory.ChildPersonal]: 'child',\n [MetadataCategory.OtherPersonal]: 'other',\n}\n\n/**\n * This function extract PersonalInformations from data input object coming from workflow\n * @param data extracted from WorkflowData\n * @returns PersonalInformations of a patient\n */\nexport function identificationToPersonalInformations(\n data: any,\n category:\n | MetadataCategory.Personal\n | MetadataCategory.ChildPersonal\n | MetadataCategory.OtherPersonal\n): PersonalInformations {\n const prefix = personalMetaToPrefix[category]\n\n return {\n birthday: data[`${prefix}Birthday`],\n firstname: data[`${prefix}Firstname`],\n gender: data[`${prefix}Gender`],\n name: data[`${prefix}Name`],\n phone: data[`${prefix}Phone`],\n zip: data[`${prefix}Zip`],\n hid: data[`${prefix}HID`] ?? data[`${prefix}ID`], // This is done for backward compatibility (historically youID was used)\n pharmacy: data[`${prefix}Pharmacy`],\n address: data[`${prefix}Address`],\n }\n}\n\nexport function toActualObject(data: PopulatedWorkflowData) {\n const ret: any = {}\n\n Object.entries(data.fields).forEach(([key, field]) => {\n ret[key] = field.displayedAnswer ? field.displayedAnswer : field.answer\n })\n\n return ret\n}\n\n/**\n * This function update a PopulatedWorkflowData with PersonalInformations\n * @param infos the personal informations\n * @param data the PopulatedWorkflowData\n * @returns an updated PopulatedWorkflowData\n */\nexport function updatePersonalIntoPopulatedWorkflowData(\n infos: PersonalInformations,\n data: PopulatedWorkflowData,\n category:\n | MetadataCategory.Personal\n | MetadataCategory.ChildPersonal\n | MetadataCategory.OtherPersonal\n) {\n const prefix = personalMetaToPrefix[category]\n\n const ret = JSON.parse(JSON.stringify(data)) // deep copy PopulatedWorkflowData\n\n if (infos.birthday && ret.fields[`${prefix}Birthday`])\n ret.fields[`${prefix}Birthday`].answer = infos.birthday\n if (infos.firstname && ret.fields[`${prefix}Firstname`])\n ret.fields[`${prefix}Firstname`].answer = infos.firstname\n if (infos.gender && ret.fields[`${prefix}Gender`])\n ret.fields[`${prefix}Gender`].answer = infos.gender\n if (infos.name && ret.fields[`${prefix}Name`])\n ret.fields[`${prefix}Name`].answer = infos.name\n if (infos.phone && ret.fields[`${prefix}Phone`])\n ret.fields[`${prefix}Phone`].answer = infos.phone\n if (infos.zip && ret.fields[`${prefix}Zip`])\n ret.fields[`${prefix}Zip`].answer = infos.zip\n if (infos.hid) {\n if (ret.fields[`${prefix}HID`]) {\n ret.fields[`${prefix}HID`].answer = infos.hid\n } else if (ret.fields[`${prefix}ID`]) {\n // This is done for backward compatibility (historically youID was used)\n ret.fields[`${prefix}ID`].answer = infos.hid\n } else {\n // If does not exist create it\n ret.fields[`${prefix}HID`] = { kind: 'text', answer: infos.hid }\n }\n }\n\n return ret\n}\n\n/**\n * This function extract an ISO 3166-1 alpha-2 country and subdivision code from data input object coming from workflow\n * @param answers answers from the WorkflowData\n * @returns an ISO 3166 alpha-2 code or undefined\n */\nexport function extractISOLocalityForConsult(\n answers?: SelectedAnswersData\n): string | undefined {\n if (!answers) {\n return undefined\n }\n\n const arrAnswersWithLocality = answers\n .flatMap((currentAnswerPage) => {\n const arrCountryFields = Object.keys(currentAnswerPage)\n .filter(\n (workflowFieldName) =>\n workflowFieldName.indexOf('Country') !== -1\n )\n .flat()\n const arrProvinceFields = Object.keys(currentAnswerPage)\n .filter(\n (workflowFieldName) =>\n workflowFieldName.indexOf('Province') !== -1\n )\n .flat()\n const arrConsultLocalFields = Object.keys(currentAnswerPage)\n .filter(\n (workflowFieldName) =>\n workflowFieldName.indexOf('Locality') !== -1\n )\n .flat()\n //returning the actual selected values, skipping if their IDs are more complex than a string\n return [\n ...arrCountryFields.map(\n (currentFieldName) =>\n (typeof currentAnswerPage[currentFieldName] === 'string'\n ? currentAnswerPage[currentFieldName]\n : undefined) as string\n ),\n ...arrProvinceFields.map(\n (currentFieldName) =>\n (typeof currentAnswerPage[currentFieldName] === 'string'\n ? currentAnswerPage[currentFieldName]\n : undefined) as string\n ),\n ...arrConsultLocalFields.map(\n (currentFieldName) =>\n (typeof currentAnswerPage[currentFieldName] === 'string'\n ? currentAnswerPage[currentFieldName]\n : undefined) as string\n ),\n ]\n })\n .filter((item) => item !== undefined)\n\n const arrSelectedLocality = arrAnswersWithLocality.filter(\n (currentSelectedLocality) =>\n currentSelectedLocality.startsWith('isoLocalityConsult')\n )\n if (!arrSelectedLocality || arrSelectedLocality.length === 0) {\n console.log('no locality found in ' + arrSelectedLocality)\n return undefined\n }\n //to allow enforcing of an order, we will allow the following pattern in the isoLocalityConsult field name\n // isoLocalityConsult-QC-CA and isoLocalityConsult_1-QC-CA\n // or generally: isoLocalityConsult-<isoValue> or isoLocalityConsult_<priority>-<isoValue>\n const allowedLocalityPatterns = /isoLocalityConsult(?:_(?<indexPriority>\\d*))?-(?<isoValue>[a-zA-Z0-9]{2}-[a-zA-Z0-9]{1,3})/\n const finalLocality = arrSelectedLocality.reduce<string | undefined>(\n (finalLocality, currentSelectedLocality) => {\n const extractedSelected = allowedLocalityPatterns.exec(\n currentSelectedLocality\n )\n const [, indexSelectedPriority, isoSelectedValue] =\n extractedSelected ?? []\n if (!finalLocality) {\n return isoSelectedValue\n }\n\n const extractedFinal = allowedLocalityPatterns.exec(finalLocality)\n const [, indexFinalPriority, isoFinalValue] = extractedFinal ?? []\n //we only keep the old value if there's priority used\n // and the new value is of lower priority\n if (\n !indexSelectedPriority ||\n (indexFinalPriority &&\n indexFinalPriority > indexSelectedPriority)\n ) {\n return isoFinalValue\n }\n\n return isoSelectedValue\n },\n undefined\n )\n\n console.log('Picking locality ' + finalLocality)\n return finalLocality\n}\n\nconst sessionPrivateKeyPrefix = 'sess-pkey'\nexport function sessionStorePrivateKeyName(id: string): string {\n return sessionPrivateKeyPrefix + id\n}\n","export class IncompleteAuthentication extends Error { }\nexport class MissingGrant extends Error { }\nexport class MissingGrantFilter extends Error { }\nexport class MissingLockbox extends Error { }\nexport class MissingLockboxOwner extends Error { }\nexport class AssociatedLockboxNotFound extends Error { }\nexport class WorkflowAnswersMissingError extends Error { }\n","import { getMany } from 'idb-keyval'\nimport { WorkflowAnswersMissingError } from '../models'\nimport {\n MetadataCategory,\n PopulatedWorkflowData,\n PopulatedWorkflowField,\n QuestionData,\n SelectedAnswerData,\n SelectedAnswersData,\n WorkflowData,\n WorkflowPageData,\n WorkflowUploadedImage,\n} from 'oro-sdk-apis'\n\nexport async function filterTriggeredAnsweredWithKind(\n workflowData: WorkflowData,\n kind:\n | 'text'\n | 'text-area'\n | 'text-select-group'\n | 'date'\n | 'number'\n | 'images'\n | 'images-alias'\n | 'body-parts'\n | 'pharmacy-picker'\n | 'online-pharmacy-picker'\n | 'hair-selector-women'\n | 'hair-selector-men'\n | 'hair-loss-stage'\n | 'hair-loss-frontal'\n): Promise<SelectedAnswerData[]> {\n if (!workflowData.selectedAnswers) throw WorkflowAnswersMissingError\n // Flattens the list of answered questions\n let flattenedAnswers = flattenSelectedAnswers(workflowData.selectedAnswers)\n // Generates a list of applicable questions\n let triggeredQuestionsWithKind = Object.fromEntries(\n workflowData.pages\n .map((a) => {\n return Object.entries(a.questions).filter(\n ([_, question]) => isTriggered(question.triggers || [], flattenedAnswers) && question.kind === kind\n )\n })\n .flat()\n )\n\n const samePageAnswers = workflowData.selectedAnswers.reduce((prev, cur) => {\n return { ...prev, ...cur }\n }, {})\n\n const res = Object.keys(triggeredQuestionsWithKind).map((questionFieldName) => {\n return samePageAnswers[questionFieldName]\n })\n\n return res\n}\n\n/**\n * Filters and Populates the `selectedAnswers` from the workflow by\n * Cross-referencing the `MetaCategory` of the answer's respective question\n * Populates the fields labels and values that are of radio, dropdown and checkbox types\n *\n * @param workflowData\n * @param category\n * @returns An array of record key, value pairs\n */\nexport async function getWorkflowDataByCategory(\n workflowData: WorkflowData,\n category: MetadataCategory\n): Promise<PopulatedWorkflowData> {\n if (!workflowData.selectedAnswers) throw WorkflowAnswersMissingError\n\n // Flattens the list of answered questions\n let flattenedAnswers = flattenSelectedAnswers(workflowData.selectedAnswers)\n // Generates a list of applicable questions\n let triggeredQuestions = Object.fromEntries(\n workflowData.pages\n .map((a) => {\n return Object.entries(a.questions).filter(([_, question]) =>\n isTriggered(question.triggers || [], flattenedAnswers)\n )\n })\n .flat()\n )\n\n const fields: Record<string, PopulatedWorkflowField> = {}\n\n // Generates the answers of the specified category and adds the appropriate values if any are missing\n return Promise.all(\n workflowData.selectedAnswers\n .map((e) => Object.entries(e))\n .flat()\n .filter(([k, v]) => triggeredQuestions[k] && triggeredQuestions[k]['metaCategory'] === category)\n .map(([k, v]) => {\n return populateWorkflowField(triggeredQuestions[k], v).then((populatedValue) => {\n fields[k] = populatedValue\n })\n })\n )\n .then(() => {\n const ret: PopulatedWorkflowData = {\n workflowCreatedAt: workflowData.createdAt,\n workflowId: workflowData.id,\n locale: workflowData.locale,\n fields,\n }\n return ret\n })\n .catch((err) => {\n console.error(`Error while extracting ${category} data from workflow`, err)\n throw err\n })\n}\n\nexport async function getImagesFromIndexDb(answer: SelectedAnswerData): Promise<WorkflowUploadedImage[]> {\n return await getMany<WorkflowUploadedImage>((answer as any[]).map((v) => v.id ?? v) as string[])\n}\n\n/**\n * (If applicable) Based on the question kind, and the answer type this function will add and replace the appropriate fields to the\n * field values if they are radio, dropdown and checkbox fields\n *\n *\n * @param question\n * @param answerValue\n * @returns\n */\nasync function populateWorkflowField(\n question: QuestionData,\n answerValue: SelectedAnswerData\n): Promise<PopulatedWorkflowField> {\n let answer: any\n let displayedAnswer: string | string[] | undefined = undefined\n switch (question.kind) {\n case 'text-select-group':\n if (question.answers) {\n displayedAnswer = `${answerValue[0]} ${question.answers[answerValue[1] as string].text}`\n }\n answer = answerValue\n break\n case 'radio':\n case 'radio-card':\n case 'select':\n if (question.answers) {\n displayedAnswer = question.answers[answerValue as string].text\n }\n\n answer = answerValue\n break\n case 'multiple':\n case 'checkbox-group':\n displayedAnswer = (answerValue as string[]).map((value) => {\n if (question.answers) {\n return question.answers[value].text\n }\n\n throw new WorkflowAnswersMissingError()\n })\n\n answer = answerValue\n break\n case 'images':\n answer = await getImagesFromIndexDb(answerValue).then((images) =>\n images.map((image) => {\n const { name, imageData } = image\n\n return { name, imageData }\n })\n )\n break\n default:\n answer = answerValue\n }\n\n return Promise.resolve({\n answer,\n displayedAnswer,\n kind: question.kind,\n })\n}\n\n/**\n * Determine if a question is triggered by some answers\n *\n * We use the following logical combinations of rules:\n *\n * #### Single string\n *\n * ```\n * // Required: rule1\n * rules: rule1\n * ```\n *\n * #### Array of strings (AND is applied between statements):\n *\n * ```\n * // Required: rule1 AND rule2\n * rules: [ rule1, rule2 ]\n * ```\n *\n * #### Array of arrays of strings (OR is applied between inner arrays. AND is applied between inner arrays statements)\n *\n * ```\n * // Required: rule1 OR rule2\n * rules: [\n * [ rule1 ],\n * [ rule2 ]\n * ]\n *\n * // Required: rule1 OR (rule2 AND rule3)\n * rules: [\n * [ rule1 ],\n * [ rule2, rule3 ]\n * ]\n *\n * // THIS IS FORBIDDEN\n * rules: [\n * rule1, // <-- THIS IS FORBIDDEN. Instead use [ rule1 ]\n * [ rule2, rule3 ]\n * ]\n * ```\n *\n * @param triggers the triggering rules\n * @param answers the answers to check againts triggering rules\n * @returns `true` if triggers are verified against ansers. Otherwise, returns `false`.\n * @throws an Error if triggers typing is wrong\n */\nexport function isTriggered(triggers: string[][] | string[] | string, answers: string[]): boolean {\n // is triggers contained in answers\n if (typeof triggers === 'string') {\n return answers.includes(triggers)\n }\n\n if (Array.isArray(triggers)) {\n // rule combination kind: rule1 OR (rule2 AND rule3)\n if (Array.isArray(triggers[0])) {\n return (triggers as string[][]).some((subSetTriggers) =>\n subSetTriggers.every((trigger) => answers.includes(trigger))\n )\n } else {\n // rule combination kind: rule1 AND rule2\n return (triggers as string[]).every((trigger) => answers.includes(trigger))\n }\n }\n\n throw Error('[isTriggered] triggers is not typed well')\n}\n\nexport function flattenSelectedAnswers(answers: SelectedAnswersData) {\n const linearAnswers: SelectedAnswerData[] = []\n\n for (const answer of answers) {\n linearAnswers.push(...Object.values(answer))\n }\n\n return linearAnswers.flat(1)\n}\n\n/**\n * This function helps you to get a valid workflow selectedAnswers structure\n * @param workflow the workflow data to use to initialize selectedAnswers\n * @param useDefault use workflow default values or not (this is used to avoid having unset values to appear in summaries)\n * @returns a valid selectedAnswers structure\n */\nexport function getInitialisedSelectedAnswers(workflow: WorkflowData, useDefault: boolean = true) {\n return workflow.pages.map((page) => {\n const ret: any = {}\n for (const [id, question] of Object.entries(page.questions)) {\n if (question.kind === 'body-parts') {\n ret[id] = useDefault ? [] : undefined\n } else {\n ret[id] = useDefault && question.defaultValue ? question.defaultValue : undefined\n }\n }\n return ret\n })\n}\n\nexport function fillWorkflowFromPopulatedWorkflow(workflow: WorkflowData, populatedWorkflow: PopulatedWorkflowData) {\n const filledWorkflow = JSON.parse(JSON.stringify(workflow))\n\n if (!filledWorkflow.selectedAnswers) {\n filledWorkflow.selectedAnswers = getInitialisedSelectedAnswers(filledWorkflow, false)\n }\n\n filledWorkflow.pages.forEach((page: WorkflowPageData, pageIdx: number) => {\n const ret: any = {}\n for (const [id] of Object.entries(page.questions)) {\n if (populatedWorkflow.fields[id]) {\n if (filledWorkflow.selectedAnswers)\n filledWorkflow.selectedAnswers[pageIdx][id] = populatedWorkflow.fields[id].answer as\n | string\n | string[]\n }\n }\n })\n\n return filledWorkflow\n}\n","import { Consult, ConsultRequest } from 'oro-sdk-apis'\nimport { OroClient } from '..'\n\n/**\n * Creates a consultation if one has not been created and fails to be retrieved by the payment intent\n * @param consult\n * @param oroClient\n * @returns the consult Uuid\n */\nexport async function getOrCreatePatientConsultationUuid(\n consult: ConsultRequest,\n oroClient: OroClient\n): Promise<Consult> {\n let payment = await oroClient.practiceClient.practiceGetPayment(\n consult.uuidPractice,\n consult.idStripeInvoiceOrPaymentIntent\n )\n if (payment && payment.uuidConsult) {\n return oroClient.consultClient.getConsultByUUID(payment.uuidConsult).catch((err) => {\n console.error('Error while retrieving consult', err)\n throw err\n })\n } else {\n return await oroClient.consultClient.consultCreate(consult).catch((err) => {\n console.error('Error while creating consult', err)\n throw err\n })\n }\n}\n","import {\n Consult,\n ConsultationImageMeta,\n ConsultationMeta,\n ConsultRequest,\n DocumentType,\n IdentityResponse,\n IndexKey,\n MedicalMeta,\n MedicalStatus,\n MetadataCategory,\n PersonalMeta,\n PopulatedWorkflowData,\n Practitioner,\n PreferenceMeta,\n RawConsultationMeta,\n Term,\n Terms,\n Uuid,\n VaultIndex,\n WorkflowData,\n} from 'oro-sdk-apis'\nimport {\n filterTriggeredAnsweredWithKind,\n getImagesFromIndexDb,\n getWorkflowDataByCategory,\n identificationToPersonalInformations,\n OroClient,\n RegisterPatientOutput,\n toActualObject,\n} from '..'\nimport { getOrCreatePatientConsultationUuid } from './consult'\n\nconst MAX_RETRIES = 15\n\n/**\n * Completes a registration for a user retrying the complete flow a maximum of 15 times\n *\n * @description The order of importance when registering:\n * Creates a consultation if none exist\n * Retrieves or create's a lockbox if none exist\n * Grants the lockbox (if new) to all practitioners in the practice\n * Stores or fetches the patient data (without images)\n * Indexes the lockbox to the consult for all practitioners (done after inserting since index can be rebuilt from grants)\n * Stores the image data - done last since the majority of failure cases occur here\n * Creates the recovery payloads if they don't exist\n *\n * @param patientUuid\n * @param consultRequest\n * @param workflow\n * @param oroClient\n * @param masterKey\n * @param recoveryQA\n * @param indexSearch create search index for the consultation if true\n * @param onProgress callback that is called whenever a new step of patient registration is executed. Note: progress ranges from 0 to 1, and descriptionKey is a description of the progress as a key so the app would use it to translate the description\n * @returns the successful registration\n */\nexport async function registerPatient(\n patientUuid: Uuid,\n consultRequest: ConsultRequest,\n workflow: WorkflowData,\n oroClient: OroClient,\n masterKey?: Uuid,\n recoveryQA?: {\n recoverySecurityQuestions: string[]\n recoverySecurityAnswers: string[]\n },\n indexSearch: boolean = true,\n onProgress?: (\n progress: number,\n descriptionKey: string,\n extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }\n ) => void\n): Promise<RegisterPatientOutput> {\n let consult: Consult | undefined = undefined\n let lockboxUuid: Uuid | undefined = undefined\n let practitionerAdmin: Uuid | undefined = undefined\n let retry = MAX_RETRIES\n let identity: IdentityResponse | undefined = undefined\n let errorsThrown: Error[] = []\n const stepsTotalNum = 9\n let currentStep: number\n\n for (; retry > 0; retry--) {\n try {\n currentStep = 0\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'retrieve_practitioners')\n\n // Wait a bit each retry (we also want the first one to wait)\n await new Promise((resolve) => setTimeout(resolve, 2000))\n\n // Retrieving practitioners\n if (!practitionerAdmin)\n practitionerAdmin = (await oroClient.practiceClient.practiceGetFromUuid(consultRequest.uuidPractice))\n .uuidAdmin\n\n let practitioners: Practitioner[] = await oroClient.practiceClient\n .practiceGetPractitioners(consultRequest.uuidPractice)\n .catch((err) => {\n console.log(`Error retrieving practitioners`, err)\n return []\n })\n\n // Creating consult\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_consult')\n\n if (!consult) {\n consult = await getOrCreatePatientConsultationUuid(consultRequest, oroClient)\n }\n\n // Creating lockbox\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_lockbox')\n\n if (!lockboxUuid) lockboxUuid = await getOrCreatePatientLockbox(oroClient)\n\n if (!identity) identity = await oroClient.guardClient.identityGet(patientUuid)\n\n await oroClient.grantLockbox(practitionerAdmin, lockboxUuid).catch((err) => {\n console.error(`Error while granting lockbox to practitioner admin ${practitionerAdmin}`, err)\n // if we cannot grant to the admin, then the registration will fail\n errorsThrown.push(err)\n })\n\n // Patient Grant to practice\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'grant_patient')\n\n let grantPromises = practitioners\n .filter((practitioner) => practitioner.uuid !== practitionerAdmin)\n .map(async (practitioner) => {\n return oroClient.grantLockbox(practitioner.uuid, lockboxUuid!).catch((err) => {\n console.error(`Error while granting lockbox to practitioner`, err)\n // Acceptable to continue as admin has already been granted, but we should still retry until the last retry remains\n if (retry <= 1) return\n errorsThrown.push(err)\n })\n })\n\n const consultIndex: VaultIndex = {\n [IndexKey.ConsultationLockbox]: [\n {\n grant: {\n lockboxUuid,\n lockboxOwnerUuid: patientUuid,\n },\n consultationId: consult.uuid,\n },\n ],\n }\n\n // the index will identify in which lockbox a consultation resides\n let consultIndexPromises = practitioners.map(async (practitioner) => {\n return oroClient.vaultIndexAdd(consultIndex, practitioner.uuid).catch((err) => {\n console.error(\n `[SDK: registration] Error while adding to the practitioner's index ${practitioner.uuid}`,\n err\n )\n // Acceptable to continue as the index can be rebuilt, but we should still retry until the last retry remains\n if (retry <= 1) return\n else errorsThrown.push(err)\n })\n })\n\n await storeImageAliases(\n consult.uuid,\n lockboxUuid,\n workflow,\n oroClient,\n onProgress\n ? {\n onProgress,\n currentStep,\n stepsTotalNum,\n }\n : undefined\n ).catch((err) => {\n console.error('[SDK: registration] Some errors happened during image upload', err)\n // Acceptable to continue as images can be requested during the consultation, but we should still retry until the last retry remains\n if (retry <= 1) return\n else errorsThrown.push(err)\n })\n ++currentStep\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'store_patient_data')\n\n await storePatientData(\n consult.uuid,\n consultRequest.isoLanguageRequired,\n lockboxUuid,\n workflow,\n oroClient\n ).catch((err) => {\n console.error('[SDK: registration] Some errors happened during patient data upload', err)\n errorsThrown.push(err)\n })\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'set_masterkey')\n\n if (masterKey && !identity?.recoveryMasterKey) {\n // generate and store recovery payload and updates the identity\n identity = await oroClient.updateMasterKey(patientUuid, masterKey, lockboxUuid).catch((err) => {\n console.error(`[SDK: registration] Error while updating master key`, err)\n /// it's acceptable to continue registration (return old identity)\n if (retry <= 1) return\n errorsThrown.push(err)\n return identity\n })\n } else {\n // we did not set the master key so we do not return it\n masterKey = undefined\n }\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'set_security_questions')\n\n if (recoveryQA && !identity?.recoverySecurityQuestions)\n // Patient security question recovery threshold is 2 answers and updates the identity\n identity = await oroClient\n .updateSecurityQuestions(\n patientUuid,\n recoveryQA.recoverySecurityQuestions,\n recoveryQA.recoverySecurityAnswers,\n 2\n )\n .catch((err) => {\n console.error(`[SDK: registration] Error while updating security questions`, err)\n /// it's acceptable to continue registration (return old identity)\n if (retry <= 1) return\n errorsThrown.push(err)\n return identity\n })\n\n await Promise.all([...grantPromises, ...consultIndexPromises])\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'search_indexing')\n\n if (indexSearch) {\n await buildConsultSearchIndex(consult, workflow, oroClient).catch((err) => {\n console.error(\n '[SDK: registration] personal information not found or another error occured during search indexing',\n err\n )\n if (retry <= 1) return // this statement is to avoid failing the registration due to the failure in search indexing the consult, this practically implements a soft retry\n errorsThrown.push(err)\n })\n }\n\n if (errorsThrown.length > 0) throw errorsThrown\n\n // Deem the consultation as ready\n await oroClient.consultClient.updateConsultByUUID(consult.uuid, {\n statusMedical: MedicalStatus.New,\n })\n\n // if we got through the complete flow, the registration succeeded\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'success')\n\n break\n } catch (err) {\n console.error(`[SDK] Error occured during registration: ${err}, retrying... Retries remaining: ${retry}`)\n errorsThrown = []\n continue\n }\n }\n\n if (retry <= 0) {\n console.error('[SDK] registration failed: MAX_RETRIES reached')\n throw 'RegistrationFailed'\n }\n\n console.log('Successfully Registered')\n await oroClient.cleanIndex()\n return {\n masterKey,\n consultationId: consult!.uuid,\n lockboxUuid: lockboxUuid!,\n }\n}\n\n/**\n * Creates a new lockbox for the patient if they do not have any, otherwise, use the first (and only one)\n * @param oroClient\n * @returns the lockbox Uuid\n */\nasync function getOrCreatePatientLockbox(oroClient: OroClient): Promise<Uuid> {\n let grants = await oroClient.getGrants()\n if (grants.length > 0) {\n console.log('The grant has already been created, skipping lockbox create step')\n return grants[0].lockboxUuid!\n } else {\n let lockboxResponse = await oroClient.vaultClient.lockboxCreate().catch((err) => {\n console.error('Error while creating lockbox', err)\n throw err\n })\n // Since the creation of a lockbox will change the scope of a user, we will force refresh the tokens\n let tokens = await oroClient.guardClient.authRefresh()\n await oroClient.guardClient.setTokens({ accessToken: tokens.accessToken, refreshToken: tokens.refreshToken })\n await oroClient.guardClient.whoAmI(true)\n\n return lockboxResponse.lockboxUuid\n }\n}\n\n/**\n * Store all patient related information into his/her lockbox\n * @param consultationId The consultation id\n * @param isoLanguage the prefered language of communication (ISO 639-3 https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes)\n * @param lockboxUuid the lockbox uuid to store data in\n * @param workflow the workflow used to extract informations\n * @param oroClient an oroClient instance\n * @returns\n */\nasync function storePatientData(\n consultationId: Uuid,\n isoLanguage: string,\n lockboxUuid: Uuid,\n workflow: WorkflowData,\n oroClient: OroClient\n): Promise<(Uuid | void)[]> {\n // Create and store registration data\n return Promise.all([\n // Storing Raw data first\n oroClient.getOrInsertJsonData<RawConsultationMeta>(\n lockboxUuid,\n workflow,\n {\n category: MetadataCategory.Raw,\n contentType: 'application/json',\n consultationId,\n },\n {}\n ),\n getWorkflowDataByCategory(workflow, MetadataCategory.Consultation).then((data) =>\n oroClient.getOrInsertJsonData<ConsultationMeta>(\n lockboxUuid,\n data,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationId, // TODO: deprecated. Will finally only be in privateMetadata\n },\n { consultationId },\n { withNotification: true, forceReplace: false, updateMedicalStatus: false }\n // the only data that needs to include an email notification\n )\n ),\n getWorkflowDataByCategory(workflow, MetadataCategory.Medical).then((data) =>\n oroClient.getOrInsertJsonData<MedicalMeta>(\n lockboxUuid,\n data,\n {\n category: MetadataCategory.Medical,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationIds: [consultationId!],\n },\n {}\n )\n ),\n extractAndStorePersonalWorkflowData(\n workflow,\n lockboxUuid,\n consultationId,\n MetadataCategory.Personal,\n oroClient\n ),\n extractAndStorePersonalWorkflowData(\n workflow,\n lockboxUuid,\n consultationId,\n MetadataCategory.ChildPersonal,\n oroClient\n ),\n extractAndStorePersonalWorkflowData(\n workflow,\n lockboxUuid,\n consultationId,\n MetadataCategory.OtherPersonal,\n oroClient\n ),\n oroClient.getOrInsertJsonData<PreferenceMeta>(\n lockboxUuid,\n { isoLanguage },\n {\n category: MetadataCategory.Preference,\n contentType: 'application/json',\n },\n {}\n ),\n ]).then((dataUuids) => dataUuids.flat())\n}\n\nasync function storeImageAliases(\n consultationId: Uuid,\n lockboxUuid: Uuid,\n workflow: WorkflowData,\n oroClient: OroClient,\n progress?: {\n currentStep: number\n stepsTotalNum: number\n onProgress: (\n progress: number,\n descriptionKey: string,\n extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }\n ) => void\n }\n): Promise<(Uuid | void)[]> {\n const images = await getImagesFromIndexDb((await filterTriggeredAnsweredWithKind(workflow, 'images-alias')).flat())\n\n const nonNullImages = images.filter((img) => !!img)\n\n if (images.length !== nonNullImages.length) {\n console.error('[SDK] Some images have not been found, they have been skipped.')\n }\n\n let storedImagesNum = 0\n let totalImagesNum = nonNullImages.length\n if (progress)\n progress.onProgress(progress.currentStep / progress.stepsTotalNum, 'store_images', {\n storedImagesNum,\n totalImagesNum,\n })\n\n let promises = nonNullImages.map((image) => {\n return oroClient\n .getOrInsertJsonData<ConsultationImageMeta>(\n lockboxUuid,\n image,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.ImageAlias,\n consultationId,\n idbId: image.idbId as string,\n },\n {}\n )\n .then(() => {\n if (progress) {\n ++storedImagesNum\n let progressStepValue =\n Math.round(\n ((progress.currentStep + 1) / progress.stepsTotalNum -\n progress.currentStep / progress.stepsTotalNum) *\n 100\n ) / 100\n progress.onProgress(\n progress.currentStep / progress.stepsTotalNum +\n progressStepValue * (storedImagesNum / totalImagesNum),\n 'store_images',\n {\n storedImagesNum,\n totalImagesNum,\n }\n )\n }\n })\n })\n return Promise.all(promises)\n}\n\n/**\n * Extracts the workflow MetadataCategory for Personal, ChildPersonal and OtherPersonal\n * then stores it in the vault\n *\n * @param workflow\n * @param lockboxUuid\n * @param category\n * @returns The data uuid\n */\nexport async function extractAndStorePersonalWorkflowData(\n workflow: WorkflowData,\n lockboxUuid: Uuid,\n consultationId: Uuid,\n category: MetadataCategory.Personal | MetadataCategory.ChildPersonal | MetadataCategory.OtherPersonal,\n oroClient: OroClient\n): Promise<Uuid | void> {\n return getWorkflowDataByCategory(workflow, category as unknown as MetadataCategory).then((data) => {\n if (Object.keys(data.fields).length === 0) return\n return oroClient.getOrInsertJsonData<PersonalMeta>(\n lockboxUuid,\n data,\n {\n category,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationIds: [consultationId],\n },\n {}\n )\n })\n}\n\n/**\n * Given workflow data, it populates it with Personal, ChildPersonal, and OtherPersonal workflow data\n * @param workflow\n */\nexport async function extractPersonalInfoFromWorkflowData(workflow: WorkflowData): Promise<{\n personalInfoPopulatedWfData: PopulatedWorkflowData\n childPersonalInfoPopulatedWfData: PopulatedWorkflowData\n otherPersonalInfoPopulatedWfData: PopulatedWorkflowData\n}> {\n return Promise.all([\n getWorkflowDataByCategory(workflow, MetadataCategory.Personal),\n getWorkflowDataByCategory(workflow, MetadataCategory.ChildPersonal),\n getWorkflowDataByCategory(workflow, MetadataCategory.OtherPersonal),\n ]).then(([personalInfoPopulatedWfData, childPersonalInfoPopulatedWfData, otherPersonalInfoPopulatedWfData]) => {\n return {\n personalInfoPopulatedWfData,\n childPersonalInfoPopulatedWfData,\n otherPersonalInfoPopulatedWfData,\n }\n })\n}\n\n/**\n * Creates the search index for the first name, last name, and the short id of the given consultation\n * @param consult the consultation to be search indexed\n * @param workflow the workflow data\n * @param oroClient\n */\nexport async function buildConsultSearchIndex(consult: Consult, workflow: WorkflowData, oroClient: OroClient) {\n let terms: Terms = [\n <Term>{\n kind: 'consult-shortid',\n value: consult.shortId,\n },\n ]\n\n const { personalInfoPopulatedWfData, childPersonalInfoPopulatedWfData, otherPersonalInfoPopulatedWfData } =\n await extractPersonalInfoFromWorkflowData(workflow)\n\n const personalInfo = identificationToPersonalInformations(\n toActualObject(personalInfoPopulatedWfData),\n MetadataCategory.Personal\n )\n const childPersonalInfo = identificationToPersonalInformations(\n toActualObject(childPersonalInfoPopulatedWfData),\n MetadataCategory.ChildPersonal\n )\n const otherPersonalInfo = identificationToPersonalInformations(\n toActualObject(otherPersonalInfoPopulatedWfData),\n MetadataCategory.OtherPersonal\n )\n\n terms.push(\n <Term>{\n kind: 'first-name',\n value: personalInfo.firstname,\n },\n <Term>{\n kind: 'last-name',\n value: personalInfo.name,\n }\n )\n\n if (childPersonalInfo.firstname && childPersonalInfo.name) {\n terms.push(\n <Term>{\n kind: 'first-name',\n value: childPersonalInfo.firstname,\n },\n <Term>{\n kind: 'last-name',\n value: childPersonalInfo.name,\n }\n )\n }\n\n if (otherPersonalInfo.firstname && otherPersonalInfo.name) {\n terms.push(\n <Term>{\n kind: 'first-name',\n value: otherPersonalInfo.firstname,\n },\n <Term>{\n kind: 'last-name',\n value: otherPersonalInfo.name,\n }\n )\n }\n\n await oroClient.searchClient.index(consult.uuid, terms)\n}\n","import { CryptoRSA, uuidParse} from \"oro-toolbox\"\nimport { EncryptedIndexEntry, Grant, IndexConsultLockbox } from \"oro-sdk-apis\"\n\n/**\n * Decrypts and returns the encrypted grants\n * If something went wrong during decryption, that grant will be removed from the list\n *\n * @param encryptedGrants: an array of encrypted grants\n * @param rsaKey: the rsa key used to decrypt the encrypted grants\n * @returns an array of grants\n */\nexport function decryptGrants(encryptedGrants: Grant[], rsaKey: CryptoRSA): Grant[] {\n return encryptedGrants\n .map(grant => {\n if (grant.encryptedLockbox && !grant.lockboxUuid) {\n try {\n grant.lockboxUuid = uuidParse(\n rsaKey.base64DecryptToBytes(grant.encryptedLockbox)\n )\n } catch (e) {\n console.error('[sdk:index] The grant could not be decrypted or was not a valid UUID: ', e)\n }\n }\n return grant\n })\n .filter(grant => grant.lockboxUuid)\n}\n\n/**\n * Decrypts the encrypted consult lockboxes and returns their grants\n * If something went wrong during decryption, that grant will be removed from the list\n *\n * @param encryptedConsultLockboxes: an array of encrypted entries\n * @param rsaKey: the rsa key used to decrypt the encrypted entries\n * @returns an array of grants\n */\nexport function decryptConsultLockboxGrants(encryptedConsultLockboxes: EncryptedIndexEntry[], rsaKey: CryptoRSA): Grant[] {\n return encryptedConsultLockboxes\n .map(encryptedConsultLockboxes => {\n try {\n return [true, (rsaKey.base64DecryptToJson(\n encryptedConsultLockboxes.encryptedIndexEntry\n ) as IndexConsultLockbox).grant]\n } catch(e) {\n console.error('[sdk:index] The consult lockbox grant could not be decrypted: ', e)\n return [false, undefined] // if decryption fails, we want to ignore the grant but not fail the call\n }\n })\n .filter(grantsTuple => grantsTuple[0])\n .map(grantTuples => grantTuples[1] as Grant)\n}","import {\n Consult,\n ConsultRequest,\n DocumentType,\n MedicalStatus,\n MetadataCategory,\n PlaceData,\n SelectedAnswersData,\n Uuid,\n WorkflowData,\n} from 'oro-sdk-apis'\nimport { buildConsultSearchIndex, OroClient } from '..'\nimport { getOrCreatePatientConsultationUuid } from './consult'\n\nconst MAX_RETRIES = 15\n/**\n * Placeholder while the workflow interpreter for the refill flows is complete\n *\n * Creates a fake workflow in which the workflow data will reside\n *\n * @todo deprecate this function when using workflows and populating them from the app\n *\n * @param isTreatmentWorking the value from the `is treatment working` question\n * @param hasSideEffects the value from the `does the treatment have side effects` question\n * @param deliveryAddress the provided delivery address\n * @param pharmacy\n * @returns a workflow\n */\nexport function getRefillAnswersAsWorkflow(\n isTreatmentWorking: string,\n hasSideEffects: string,\n deliveryAddress?: string,\n pharmacy?: PlaceData\n): WorkflowData {\n let selectedAnswers: SelectedAnswersData = [\n {\n ['isTreatmentWorking']: isTreatmentWorking,\n ['hasSideEffects']: hasSideEffects,\n },\n ]\n\n // appends the delivery address to the first page of the answers if provided\n if (deliveryAddress) selectedAnswers[0] = { ...selectedAnswers[0], ['deliveryAddress']: deliveryAddress }\n\n // appends the pharmacy to the first page of the answers if provided\n if (pharmacy) selectedAnswers[0] = { ...selectedAnswers[0], ['pharmacy']: JSON.stringify(pharmacy) }\n\n return {\n id: '32573a20-6f1d-49be-9ad3-b87c58074979',\n createdAt: '2022-10-03T00:00:00.000Z',\n culDeSacs: [],\n hidePlanRules: [],\n pages: [\n {\n title: 'Prescription Refill',\n groups: [\n {\n type: 'field-group',\n fieldsAndGroups: [\n {\n type: 'field',\n id: 'isTreatmentWorking',\n },\n {\n type: 'field',\n id: 'hasSideEffects',\n },\n {\n type: 'field',\n id: 'youPharmacy',\n },\n {\n type: 'field',\n id: 'youAddress',\n },\n ],\n },\n ],\n questions: {\n isTreatmentWorking: {\n label: 'Is the treatment working for you?',\n kind: 'radio',\n inline: true,\n inlineLabel: false,\n metaCategory: MetadataCategory.Refill,\n answers: {\n '73bec6eb-0310-4787-af3c-ac9c291737b2': {\n text: 'Yes',\n },\n 'e193951f-986f-4db3-bede-903045a1804a': {\n text: 'No',\n },\n },\n },\n hasSideEffects: {\n label: 'Are there any side effects',\n kind: 'radio',\n inline: true,\n inlineLabel: false,\n metaCategory: MetadataCategory.Refill,\n answers: {\n '1b87ad22-d316-4fac-9c7f-8f4ccb841aed': {\n text: 'Yes',\n },\n 'ab7f5a41-c351-4f5d-a568-e38f9f200e9a': {\n text: 'No',\n },\n },\n },\n youPharmacy: {\n kind: 'online-pharmacy-picker',\n label: 'Which pharmacy do you want the prescription sent to?',\n metaCategory: MetadataCategory.Refill,\n summaryLabel: 'Your pharmacy',\n },\n youAddress: {\n kind: 'place-address',\n label: 'Address',\n metaCategory: MetadataCategory.Refill,\n },\n },\n },\n ],\n locale: 'en',\n selectedAnswers,\n }\n}\n\n/**\n * Complete refill flow, creates a consult, stores refill data and updates consultation status\n * @param consultRequest\n * @param populatedRefillWorkflow the refill workflow data\n * @param oroClient\n */\nexport async function createRefill(\n consultRequest: ConsultRequest,\n populatedRefillWorkflow: WorkflowData,\n oroClient: OroClient,\n indexSearch: boolean = true,\n onProgress?: (\n progress: number,\n descriptionKey: string,\n extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }\n ) => void\n): Promise<Consult> {\n let retry = MAX_RETRIES\n let errorsThrown: Error[] = []\n let newConsult: Consult | undefined = undefined\n let lockboxUuid: Uuid | undefined\n const stepsTotalNum = 6\n let currentStep: number\n\n for (; retry > 0; retry--) {\n try {\n currentStep = 0\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_consult')\n // Creating refill consult\n newConsult = await getOrCreatePatientConsultationUuid(consultRequest, oroClient)\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'get_patient_grant')\n if (!lockboxUuid) lockboxUuid = (await oroClient.getGrants())[0].lockboxUuid\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'store_patient_data')\n await oroClient\n .getOrInsertJsonData(\n lockboxUuid!,\n populatedRefillWorkflow,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationId: newConsult.uuid,\n },\n {},\n { withNotification: true, forceReplace: false, updateMedicalStatus: true }\n )\n .catch((err) => {\n console.error(\n '[SDK: prescription refill request] Some errors happened during refill data upload',\n err\n )\n errorsThrown.push(err)\n })\n\n if (indexSearch) {\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'fetching_parent_workflow_data')\n // raw workflow from parent consultation (contains first and last name of patient)\n let rawConsultationManifest = await oroClient.getLockboxManifest(\n lockboxUuid!,\n { category: MetadataCategory.Raw, consultationId: consultRequest.uuidParent },\n false\n )\n if (rawConsultationManifest && rawConsultationManifest.length > 0) {\n let rawConsultation = await oroClient.getJsonData<WorkflowData>(\n lockboxUuid!,\n rawConsultationManifest[0].dataUuid\n )\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'search_indexing')\n await buildConsultSearchIndex(newConsult, rawConsultation, oroClient).catch((err) => {\n console.error(\n '[SDK: prescription refill request] personal information not found or another error occured during search indexing',\n err\n )\n if (retry <= 1) return // this statement is to avoid failing the registration due to the failure in search indexing the consult, this practically implements a soft retry\n errorsThrown.push(err)\n })\n } else {\n console.error(\"[SDK: prescription refill request] parent consultation's raw data not found\")\n errorsThrown.push(Error('RawData Not Found'))\n }\n }\n\n if (errorsThrown.length > 0) throw errorsThrown\n\n // Deem the consultation as ready\n await oroClient.consultClient.updateConsultByUUID(newConsult.uuid, {\n statusMedical: MedicalStatus.New,\n })\n\n // if we got through the complete flow, the registration succeeded\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'success')\n\n await oroClient.cleanIndex()\n break\n } catch (err) {\n console.error(\n `[SDK] Error occured during prescription refill request: ${err}, retrying... Retries remaining: ${retry}`\n )\n errorsThrown = []\n continue\n }\n }\n if (retry <= 0) {\n console.error('[SDK] prescription refill request failed: MAX_RETRIES reached')\n throw 'RegistrationFailed'\n }\n\n if (!newConsult) {\n console.error('[SDK] prescription refill request failed: MAX_RETRIES reached')\n throw 'RegistrationFailed'\n }\n\n console.log('Successfully Created refill')\n return newConsult\n}\n","import { IndexKey, Grant, IndexConsultLockbox, MetadataCategory, VaultIndex } from 'oro-sdk-apis'\nimport { OroClient, Uuid } from '..'\n\n/**\n * @name filterGrantsWithLockboxMetadata\n * @description searches for the existance of a consult uuid in each granted lockbox\n * @param oroClient\n * @param filter: the consult uuid\n * @returns the grants containing the consult uuid\n */\nexport async function filterGrantsWithLockboxMetadata(\n oroClient: OroClient,\n filter: { consultationId: Uuid },\n): Promise<Grant[]> {\n let grants = await oroClient.getGrants()\n let filteredGrants = []\n for (let grant of grants) {\n // Fetches in each lockbox the existance of a given consult id\n let consultationIdExistsInMetadata = await oroClient.vaultClient.lockboxMetadataGet(grant.lockboxUuid!, ['consultationId'], [], {\n category: MetadataCategory.Consultation,\n consultationId: filter.consultationId\n })\n // If there are entries in the metadata, it means that the consult exists in the lockbox\n if (consultationIdExistsInMetadata[0].length >= 0)\n filteredGrants.push(grant)\n }\n\n return filteredGrants\n}\n","import {\n AllRoleType,\n AuthTokenRequest,\n Consult,\n ConsultRequest,\n ConsultService,\n DataCreateResponse,\n DiagnosisService,\n Document,\n DocumentType,\n EncryptedIndexEntry,\n EncryptedVaultIndex,\n Grant,\n GuardService,\n IdentityCreateRequest,\n IdentityResponse,\n IndexConsultLockbox,\n IndexKey,\n LocalizedData,\n LockboxDataRequest,\n LockboxGrantRequest,\n LockboxManifest,\n ManifestEntry,\n Meta,\n Metadata,\n MetadataCategory,\n OtherRoleType,\n PersonalMeta,\n PopulatedWorkflowData,\n Practice,\n PracticeService,\n PractitionnerRoleType,\n PreferenceMeta,\n RecoveryMeta,\n RoleBasedScopes,\n SearchService,\n SecretShard,\n SubscriptionAcceptanceRequest,\n TellerService,\n TokenData,\n TosAndCpAcceptanceRequest,\n Uuid,\n VaultIndex,\n VaultService,\n WorkflowData,\n WorkflowService,\n} from 'oro-sdk-apis'\nimport * as OroToolbox from 'oro-toolbox'\nimport { CryptoRSA } from 'oro-toolbox'\nimport {\n createRefill,\n decryptConsultLockboxGrants,\n decryptGrants,\n registerPatient,\n sessionStorePrivateKeyName,\n} from './helpers'\nimport {\n AssociatedLockboxNotFound,\n IncompleteAuthentication,\n LocalEncryptedData,\n MissingGrant,\n MissingGrantFilter,\n MissingLockbox,\n MissingLockboxOwner,\n RecoveryData,\n RegisterPatientOutput,\n UserPreference,\n} from './models'\nimport { filterGrantsWithLockboxMetadata } from './sdk-revision'\n\nexport class OroClient {\n private rsa?: CryptoRSA\n private secrets: {\n lockboxUuid: string\n cryptor: OroToolbox.CryptoChaCha\n }[] = []\n private cachedMetadataGrants: {\n [filter: string]: Grant[]\n } = {}\n\n private cachedManifest: {\n [filter: string]: ManifestEntry[]\n } = {}\n\n private vaultIndex?: VaultIndex\n\n constructor(\n private toolbox: typeof OroToolbox,\n public tellerClient: TellerService,\n public vaultClient: VaultService,\n public guardClient: GuardService,\n public searchClient: SearchService,\n public practiceClient: PracticeService,\n public consultClient: ConsultService,\n public workflowClient: WorkflowService,\n public diagnosisClient: DiagnosisService,\n private authenticationCallback?: (err: Error) => void\n ) {}\n\n /**\n * clears the vaultIndex and cached metadata grants\n */\n public async cleanIndex() {\n this.cachedMetadataGrants = {}\n this.cachedManifest = {}\n }\n\n /**\n * Generates an RSA key pair and password payload (rsa private key encrypted with the password)\n * Calls Guard to sign up with the email address, password, practice, legal and token data\n *\n * @param email\n * @param password\n * @param practice\n * @param legal\n * @param tokenData\n * @returns\n */\n public async signUp(\n email: string,\n password: string,\n practice: Practice,\n tosAndCpAcceptance: TosAndCpAcceptanceRequest,\n tokenData?: TokenData,\n subscription?: boolean,\n skipEmailValidation?: boolean\n ): Promise<IdentityResponse> {\n this.rsa = new CryptoRSA()\n const privateKey = this.rsa.private()\n\n const symmetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(password)\n const recoveryPassword = symmetricEncryptor.bytesEncryptToBase64Payload(privateKey)\n\n const hashedPassword = this.toolbox.hashStringToBase64(this.toolbox.hashStringToBase64(password))\n\n email = email.toLowerCase()\n const emailConfirmed = !!skipEmailValidation\n const subscriptionAcceptance = subscription ? ({ email } as SubscriptionAcceptanceRequest) : undefined\n\n const signupRequest: IdentityCreateRequest = {\n practiceUuid: practice.uuid,\n email,\n emailConfirmed,\n password: hashedPassword,\n publicKey: this.toolbox.encodeToBase64(this.rsa.public()),\n recoveryPassword,\n tosAndCpAcceptance,\n tokenData,\n subscriptionAcceptance,\n }\n\n const identity = await this.guardClient.identityCreate(signupRequest)\n\n if (identity.recoveryLogin) {\n //Ensure we can recover from a page reload\n let symetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(identity.recoveryLogin)\n sessionStorage.setItem(\n sessionStorePrivateKeyName(identity.id),\n symetricEncryptor.bytesEncryptToBase64Payload(privateKey)\n )\n }\n\n return identity\n }\n\n /**\n * Parse the given accessToken claims by calling guard whoami and update theidentity to set it's emailConfirmed flag\n * @param accessToken\n * @returns The identity related to confirmedEmail\n */\n public async confirmEmail(accessToken: string): Promise<IdentityResponse> {\n this.guardClient.setTokens({ accessToken })\n const claims = await this.guardClient.whoAmI()\n return this.guardClient.identityUpdate(claims.sub, {\n emailConfirmed: true,\n })\n }\n\n /**\n * Calls Guard to sign in with the email address, password and one time password (if MFA is enabled)\n * Then recover's the rsa private key from the recovery payload\n *\n * @param practiceUuid\n * @param email\n * @param password\n * @param otp\n * @returns the user identity\n */\n public async signIn(practiceUuid: Uuid, email: string, password: string, otp?: string): Promise<IdentityResponse> {\n const hashedPassword = this.toolbox.hashStringToBase64(this.toolbox.hashStringToBase64(password))\n const tokenRequest: AuthTokenRequest = {\n practiceUuid,\n email: email.toLowerCase(),\n password: hashedPassword,\n otp,\n }\n\n await this.guardClient.authToken(tokenRequest)\n const userUuid = (await this.guardClient.whoAmI()).sub\n\n // Updates the rsa key to the one generated on the backend\n await this.recoverPrivateKeyFromPassword(userUuid, password)\n return await this.guardClient.identityGet(userUuid)\n }\n\n /**\n * Will attempt to recover an existing login session and set back\n * the private key in scope\n */\n public async resumeSession() {\n const id = (await this.guardClient.whoAmI()).sub\n const recoveryPayload = sessionStorage.getItem(sessionStorePrivateKeyName(id))\n const recoveryKey = (await this.guardClient.identityGet(id)).recoveryLogin\n\n if (!recoveryKey || !recoveryPayload) throw IncompleteAuthentication\n\n const symmetricDecryptor = this.toolbox.CryptoChaCha.fromPassphrase(recoveryKey)\n let privateKey = symmetricDecryptor.base64PayloadDecryptToBytes(recoveryPayload)\n this.rsa = this.toolbox.CryptoRSA.fromKey(privateKey)\n }\n\n /**\n * This function let's you encrypt locally an Object\n * @param value the Object to encrypt\n * @returns a LocalEncryptedData Object\n * @throws IncompleteAuthentication if rsa is not set\n * @calls authenticationCallback if rsa is not set\n */\n public localEncryptToJsonPayload(value: any): LocalEncryptedData {\n if (!this.rsa) {\n if (this.authenticationCallback) {\n this.authenticationCallback(new IncompleteAuthentication())\n }\n\n throw new IncompleteAuthentication()\n }\n\n const chaChaKey = new this.toolbox.CryptoChaCha()\n\n const encryptedData = chaChaKey.jsonEncryptToBase64Payload(value)\n const encryptedKey = this.toolbox.encodeToBase64(this.rsa.encryptToBytes(chaChaKey.key()))\n\n return { encryptedData, encryptedKey }\n }\n\n /**\n * This function let's you decrypt a LocalEncryptedData object\n * @param value a LocalEncryptedData object\n * @returns a decrypted Object\n * @throws IncompleteAuthentication if rsa is not set\n * @calls authenticationCallback if rsa is not set\n */\n public localDecryptJsonPayload({ encryptedKey, encryptedData }: LocalEncryptedData): any {\n if (!this.rsa) {\n if (this.authenticationCallback) {\n this.authenticationCallback(new IncompleteAuthentication())\n }\n\n throw new IncompleteAuthentication()\n }\n\n const chaChaKey = this.rsa.base64DecryptToBytes(encryptedKey)\n const decryptedData = this.toolbox.CryptoChaCha.fromKey(chaChaKey).base64PayloadDecryptToJson(encryptedData)\n\n return decryptedData\n }\n\n /**\n * Effectively kills your \"session\"\n */\n public async signOut() {\n this.rsa = undefined\n this.secrets = []\n this.guardClient.setTokens({\n accessToken: undefined,\n refreshToken: undefined,\n })\n await this.guardClient.authLogout()\n }\n\n /**\n * @name registerPatient\n * @description The complete flow to register a patient\n *\n * Steps:\n * 1. Create a consult (checks if payment has been done)\n * 2. Creates a lockbox\n * 3. Grants lockbox access to all practice personnel\n * 4. Creates secure identification, medical, onboarding data\n * 5. Generates and stores the rsa key pair and recovery payloads\n *\n * @param patientUuid\n * @param consult\n * @param workflow\n * @param recoveryQA\n * @param indexSearch create search index for the consultation if true\n * @param onProgress callback that is called whenever a new step of patient registration is executed. Note: progress ranges from 0 to 1, and descriptionKey is a description of the progress as a key so the app would use it to translate the description\n * @returns\n */\n public async registerPatient(\n patientUuid: Uuid,\n consult: ConsultRequest,\n workflow: WorkflowData,\n recoveryQA?: {\n recoverySecurityQuestions: string[]\n recoverySecurityAnswers: string[]\n },\n indexSearch: boolean = true,\n onProgress?: (progress: number, descriptionKey: string) => void\n ): Promise<RegisterPatientOutput> {\n if (!this.rsa) throw IncompleteAuthentication\n return registerPatient(\n patientUuid,\n consult,\n workflow,\n this,\n this.toolbox.uuid(),\n recoveryQA,\n indexSearch,\n onProgress\n )\n }\n\n /**\n * Creates and stores all relevant refill data\n * - New consultation is created\n * - Stores refill workflow data in the lockbox\n * - Updates the consult to new\n *\n * @param consult\n * @param populatedRefillWorkflow\n * @returns\n */\n public async createRefill(\n consult: ConsultRequest,\n populatedRefillWorkflow: WorkflowData,\n indexSearch: boolean = true,\n onProgress?: (progress: number, descriptionKey: string) => void\n ): Promise<Consult> {\n if (!this.rsa) throw IncompleteAuthentication\n return createRefill(consult, populatedRefillWorkflow, this, indexSearch, onProgress)\n }\n\n /**\n * Fetches all grants, and consultations that exist in each lockbox\n * Then updates the index for the current user with the lockbox consult relationship\n */\n public async forceUpdateIndexEntries() {\n let grants = await this.getGrants()\n\n let indexConsultLockbox: IndexConsultLockbox[] = await Promise.all(\n grants.map(\n async (grant: Grant) =>\n await this.vaultClient\n .lockboxMetadataGet(\n grant.lockboxUuid!,\n ['consultationId'],\n [],\n { category: MetadataCategory.Consultation },\n grant.lockboxOwnerUuid\n )\n .then((consults) => {\n try {\n return consults[0].map((consult: any) => {\n return {\n ...consult,\n grant: {\n lockboxOwnerUuid: grant.lockboxOwnerUuid,\n lockboxUuid: grant.lockboxUuid,\n },\n }\n })\n } catch (e) {\n // No consultations in lockbox or index could not be created\n return []\n }\n })\n .catch(() => [])\n )\n ).then((consults) => consults.flat())\n this.vaultIndexAdd({\n [IndexKey.Consultation]: indexConsultLockbox,\n })\n .then(() => alert('The Index was successfully updated!'))\n .catch(() => console.error('The index failed to update!'))\n }\n\n /**\n * Generates, encrypts and adds entries to vault index for a given index owner\n *\n * @param entries\n * @param indexOwnerUuid\n */\n public async vaultIndexAdd(entries: VaultIndex, indexOwnerUuid?: Uuid) {\n if (!this.rsa) throw IncompleteAuthentication\n\n let rsaPub: Uint8Array\n if (indexOwnerUuid) {\n let base64IndexOwnerPubKey = (await this.guardClient.identityGet(indexOwnerUuid)).publicKey\n rsaPub = this.toolbox.decodeFromBase64(base64IndexOwnerPubKey)\n } else {\n rsaPub = this.rsa.public()\n }\n\n let encryptedIndex: EncryptedVaultIndex = {}\n\n for (let keyString of Object.keys(entries)) {\n let key = keyString as keyof VaultIndex\n switch (key) {\n case IndexKey.ConsultationLockbox:\n encryptedIndex[key] = (entries[key] as IndexConsultLockbox[])\n .map((e) => ({\n ...e,\n uniqueHash: e.consultationId,\n }))\n .map(\n (e: IndexConsultLockbox) =>\n ({\n uuid: e.uuid,\n timestamp: e.timestamp,\n uniqueHash: e.uniqueHash,\n encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(\n {\n consultationId: e.consultationId,\n grant: e.grant,\n },\n rsaPub\n ),\n } as EncryptedIndexEntry)\n )\n break\n }\n }\n await this.vaultClient.vaultIndexPut(encryptedIndex, indexOwnerUuid)\n }\n\n /**\n * @name grantLockbox\n * @description Grants a lockbox by retrieving the shared secret of the lockbox and encrypting it with the grantees public key\n * @param granteeUuid\n * @param lockboxUuid\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n */\n public async grantLockbox(granteeUuid: Uuid, lockboxUuid: Uuid, lockboxOwnerUuid?: Uuid) {\n if (!this.rsa) throw IncompleteAuthentication\n\n let secret = (await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)).key()\n let base64GranteePublicKey = (await this.guardClient.identityGet(granteeUuid)).publicKey\n let granteePublicKey = this.toolbox.decodeFromBase64(base64GranteePublicKey)\n\n let granteeEncryptedSecret = CryptoRSA.bytesWithPubEncryptToBase64(secret, granteePublicKey)\n let request: LockboxGrantRequest = {\n encryptedSecret: granteeEncryptedSecret,\n granteeUuid: granteeUuid,\n }\n await this.vaultClient.lockboxGrant(lockboxUuid, request, lockboxOwnerUuid)\n }\n\n /**\n * @name createMessageData\n * @description Creates a Base64 encrypted Payload to send and store in the vault from a message string\n * @param lockboxUuid\n * @param message\n * @param consultationId the consultation for which this message is sent\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing file, specify the previous data uuid\n * @returns the data uuid\n */\n public async createMessageData(\n lockboxUuid: Uuid,\n message: string,\n consultationId: string,\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { updateMedicalStatus: boolean } = { updateMedicalStatus: true }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)\n\n let encryptedData = symmetricEncryptor.jsonEncryptToBase64Payload(message)\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload({\n author: (await this.guardClient.whoAmI()).sub,\n })\n\n let meta = {\n consultationId,\n category: MetadataCategory.Consultation,\n documentType: DocumentType.Message,\n contentType: 'text/plain',\n }\n\n let request: LockboxDataRequest = {\n data: encryptedData,\n publicMetadata: meta,\n privateMetadata: encryptedPrivateMeta,\n }\n\n return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid, options)\n }\n\n /**\n * @name createMessageAttachmentData\n * @description Creates a Base64 encrypted Payload to send and store in the vault from a file\n * @param lockboxUuid\n * @param data the file stored\n * @param consultationId the consultation for which this message is sent\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing file, specify the previous data uuid\n * @returns the data uuid\n */\n public async createMessageAttachmentData(\n lockboxUuid: Uuid,\n data: File,\n consultationId: string,\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { updateMedicalStatus: boolean } = { updateMedicalStatus: true }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)\n let encryptedData = symmetricEncryptor.bytesEncryptToBase64Payload(new Uint8Array(await data.arrayBuffer()))\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload({\n author: (await this.guardClient.whoAmI()).sub,\n fileName: data.name,\n lastModified: data.lastModified,\n size: data.size,\n })\n\n let meta = {\n consultationId,\n category: MetadataCategory.Consultation,\n documentType: DocumentType.Message,\n contentType: data.type,\n }\n\n let request: LockboxDataRequest = {\n data: encryptedData,\n publicMetadata: meta,\n privateMetadata: encryptedPrivateMeta,\n }\n\n return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid, options)\n }\n\n /**\n * @name createAttachmentData\n * @description Creates a Base64 encrypted Payload to send and store in the vault from a file\n * @param lockboxUuid\n * @param data the file stored\n * @param consultationId the consultation for which this message is sent\n * @param category the category for the attachment data\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing file, specify the previous data uuid\n * @param withNotification if the insertion of data requires notification\n * @returns the data uuid\n */\n public async createConsultationAttachmentData(\n lockboxUuid: Uuid,\n data: File,\n consultationId: string,\n documentType: DocumentType,\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { withNotification: boolean; updateMedicalStatus: boolean } = {\n withNotification: false,\n updateMedicalStatus: false,\n }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n\n return this.createBytesData<Meta | any>(\n lockboxUuid,\n new Uint8Array(await data.arrayBuffer()),\n {\n consultationId,\n category: MetadataCategory.Consultation,\n documentType,\n contentType: data.type,\n },\n {\n author: (await this.guardClient.whoAmI()).sub,\n fileName: data.name,\n },\n lockboxOwnerUuid,\n previousDataUuid,\n options\n )\n }\n\n /**\n * @name createJsonData\n * @description Creates a Base64 encrypted Payload to send and store in the vault. With the data input as a JSON\n * @param lockboxUuid\n * @param data\n * @param meta\n * @param privateMeta the metadata that will be secured in the vault\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing data, specify the previous data uuid\n * @param options if the insertion of data requires email notification\n * @returns the data uuid\n */\n public async createJsonData<T extends Metadata>(\n lockboxUuid: Uuid,\n data: any,\n meta?: T,\n privateMeta?: { [val: string]: any },\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { withNotification: boolean; updateMedicalStatus: boolean } = {\n withNotification: false,\n updateMedicalStatus: false,\n }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)\n let encryptedData = symmetricEncryptor.jsonEncryptToBase64Payload(data)\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload(privateMeta)\n\n let request: LockboxDataRequest = {\n data: encryptedData,\n publicMetadata: meta,\n privateMetadata: encryptedPrivateMeta,\n }\n if (options.withNotification)\n return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid, options)\n else return this.vaultClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)\n }\n\n /**\n * Get or upsert a data in lockbox\n * @param lockboxUuid the lockbox uuid\n * @param data the data to insert\n * @param publicMetadata the public Metadata\n * @param privateMetadata the private Metadata\n * @param forceReplace set true when the insertion of data requires to replace the data when it exists already\n * @param options if the insertion of data requires email notification\n * @returns the data uuid\n */\n public async getOrInsertJsonData<M extends Metadata>(\n lockboxUuid: Uuid,\n data: any,\n publicMetadata: M,\n privateMetadata: Metadata,\n options: { withNotification: boolean; forceReplace: boolean; updateMedicalStatus: boolean } = {\n withNotification: false,\n forceReplace: false,\n updateMedicalStatus: false,\n }\n ): Promise<Uuid> {\n let manifest = await this.vaultClient.lockboxManifestGet(lockboxUuid, publicMetadata)\n if (!options.forceReplace && manifest.length > 0) {\n console.log(`The data for ${JSON.stringify(publicMetadata)} already exist`)\n return manifest[0].dataUuid\n } else\n return (\n await this.createJsonData<M>(\n lockboxUuid,\n data,\n publicMetadata,\n privateMetadata,\n undefined,\n // if forceReplace and data already exist, then replace data. Otherwise insert it\n options.forceReplace && manifest.length > 0 ? manifest[0].dataUuid : undefined,\n options\n ).catch((err) => {\n console.error(`Error while upserting data ${JSON.stringify(publicMetadata)} data`, err)\n throw err\n })\n ).dataUuid\n }\n\n /**\n * @name createBytesData\n * @description Creates a Base64 encrypted Payload to send and store in the vault. With the data input as a Bytes\n * @param lockboxUuid\n * @param data\n * @param meta\n * @param privateMeta the metadata that will be secured in the vault\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing data, specify the previous data uuid\n * @param withNotification if the insertion of data requires notification\n * @returns the data uuid\n */\n public async createBytesData<T extends Metadata>(\n lockboxUuid: Uuid,\n data: Uint8Array,\n meta: T,\n privateMeta: { [val: string]: any },\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { withNotification: boolean; updateMedicalStatus: boolean } = {\n withNotification: false,\n updateMedicalStatus: false,\n }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n let symmetricEncryptor = await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)\n let encryptedData = symmetricEncryptor.bytesEncryptToBase64Payload(data)\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload(privateMeta)\n\n let request: LockboxDataRequest = {\n data: encryptedData,\n publicMetadata: meta,\n privateMetadata: encryptedPrivateMeta,\n }\n if (options.withNotification)\n return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid, options)\n else return this.vaultClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)\n }\n\n /**\n * @name getJsonData\n * @description Fetches and decrypts the lockbox data with the cached shared secret.\n * Decrypts the data to a valid JSON object. If this is impossible, the call to the WASM binary will fail\n *\n * @type T is the generic type specifying the return type object of the function\n * @param lockboxUuid\n * @param dataUuid\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @returns the data specified by the generic type <T>\n */\n public async getJsonData<T = any>(lockboxUuid: Uuid, dataUuid: Uuid, lockboxOwnerUuid?: Uuid): Promise<T> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let [encryptedPayload, symmetricDecryptor] = await Promise.all([\n this.vaultClient.lockboxDataGet(lockboxUuid, dataUuid, lockboxOwnerUuid),\n this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid),\n ])\n\n return symmetricDecryptor.base64PayloadDecryptToJson(encryptedPayload.data)\n }\n /**\n * @description Fetches and decrypts the lockbox data with the cached shared secret.\n * @param lockboxUuid\n * @param dataUuid\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @returns the bytes data\n */\n public async getBytesData(lockboxUuid: Uuid, dataUuid: Uuid, lockboxOwnerUuid?: Uuid): Promise<Uint8Array> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let [encryptedPayload, symmetricDecryptor] = await Promise.all([\n this.vaultClient.lockboxDataGet(lockboxUuid, dataUuid, lockboxOwnerUuid),\n this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid),\n ])\n\n return symmetricDecryptor.base64PayloadDecryptToBytes(encryptedPayload.data)\n }\n\n /**\n * @name getGrants\n * @description Get all lockboxes granted to user with the applied filter\n * @note this function returns cached grants and will not update unless the page is refreshed\n * @todo some versions of lockboxes do not make use of lockbox metadata\n * in this case, all lockboxes need to be filtered one-by-one to find the correct one\n * Remove if this is no longer the case\n * @param filter: the consultationId in which the grant exists\n * @returns decrypted lockboxes granted to user\n */\n public async getGrants(filter?: { consultationId: Uuid }): Promise<Grant[]> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let filterString = JSON.stringify(filter)\n // retrieves cached grants\n if (this.cachedMetadataGrants[filterString]) return this.cachedMetadataGrants[filterString]\n\n // We're using the account role to determine the way a grant is accessed\n let currentAccountRole = await this.getAccountRole()\n if (currentAccountRole.length === 1 && currentAccountRole[0] === OtherRoleType.User) return []\n\n if (\n [OtherRoleType.Patient, OtherRoleType.User].every((requiredRole) =>\n currentAccountRole.includes(requiredRole)\n )\n ) {\n let encryptedGrants\n // if there are no grants with the applied filter from index, attempt for naive filter with backwards compatibility\n if (filter) {\n encryptedGrants = await filterGrantsWithLockboxMetadata(this, filter)\n } else {\n encryptedGrants = (await this.vaultClient.grantsGet()).grants\n }\n const decryptedGrants = await decryptGrants(encryptedGrants, this.rsa)\n // sets the cached grant\n this.cachedMetadataGrants[filterString] = decryptedGrants\n console.info('[sdk:grant] Found grant for patient')\n return decryptedGrants\n }\n // if not a patient, then a practitioner is trying to retrieve a grant, it **Must** contain a filter, otherwise too many grants are possible\n if (!filter) throw MissingGrantFilter\n // Note: will work only if the filter being applied is exclusively a consult id\n const grantsByConsultLockbox = await this.vaultClient\n .vaultIndexGet([IndexKey.ConsultationLockbox], [filter.consultationId])\n .then((res) => res[IndexKey.ConsultationLockbox])\n .catch((e) => {\n console.error(e)\n return []\n })\n\n const decryptedConsults = decryptConsultLockboxGrants(grantsByConsultLockbox ?? [], this.rsa)\n if (decryptedConsults.length > 0) {\n console.info('[sdk:index] Grants found in user`s constant time secure index')\n this.cachedMetadataGrants[filterString] = decryptedConsults\n return this.cachedMetadataGrants[filterString]\n }\n\n // if we have no valid grants, then return nothing\n return []\n }\n\n /**\n * Fetches the role of the account that is logged in\n *\n * @returns the role based scopes defined by the whoami\n */\n async getAccountRole(): Promise<RoleBasedScopes[]> {\n return (await this.guardClient.whoAmI()).scope.split(' ') as RoleBasedScopes[]\n }\n\n /**\n * @name getCachedSecretCryptor\n * @description Retrieves the cached lockbox secret or fetches the secret from vault, then creates the symmetric cryptor and stores it in memory\n * @param lockboxUuid\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @returns\n */\n async getCachedSecretCryptor(lockboxUuid: string, lockboxOwnerUuid?: string): Promise<OroToolbox.CryptoChaCha> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let index = this.secrets.findIndex((secret) => secret.lockboxUuid === lockboxUuid)\n if (index === -1) {\n let encryptedSecret = (await this.vaultClient.lockboxSecretGet(lockboxUuid, lockboxOwnerUuid)).sharedSecret\n\n let secret = this.rsa.base64DecryptToBytes(encryptedSecret)\n let cryptor = this.toolbox.CryptoChaCha.fromKey(secret)\n this.secrets.push({ lockboxUuid, cryptor })\n return cryptor\n } else {\n return this.secrets[index].cryptor\n }\n }\n\n /**\n * Retrieves the patient personal information associated to the `consultationId`\n * The `consultationId` only helps to retrieve the patient lockboxes\n * Note: it is possible to have several personal informations data\n * @param consultationId The consultation Id\n * @param category The personal MetadataCategory to fetch\n * @param forceRefresh force data refresh (default to false)\n * @returns the personal data\n */\n public async getPersonalInformationsFromConsultId(\n consultationId: Uuid,\n category: MetadataCategory.Personal | MetadataCategory.ChildPersonal | MetadataCategory.OtherPersonal,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n return this.getMetaCategoryFromConsultId(consultationId, category, options)\n }\n\n /**\n * Retrieves the patient medical data associated to the `consultationId`\n * The `consultationId` only helps to retrieve the patient lockboxes\n * Note: it is possible to have several medical data\n * @param consultationId The consultation Id\n * @param forceRefresh force data refresh (default to false)\n * @returns the medical data\n */\n public async getMedicalDataFromConsultId(\n consultationId: Uuid,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n return this.getMetaCategoryFromConsultId(consultationId, MetadataCategory.Medical, options)\n }\n\n private async getMetaCategoryFromConsultId(\n consultationId: Uuid,\n category: MetadataCategory,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n let grants = await this.getGrants({ consultationId })\n let workflowData: LocalizedData<PopulatedWorkflowData>[] = []\n for (let grant of grants) {\n let manifest = await this.getLockboxManifest(\n grant.lockboxUuid!,\n {\n category,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationIds: [consultationId],\n },\n true,\n grant.lockboxOwnerUuid,\n options\n )\n\n // TODO: find another solution for backwards compatibility (those without the metadata consultationIds)\n if (manifest.length === 0) {\n manifest = (\n await this.getLockboxManifest(\n grant.lockboxUuid!,\n {\n category,\n documentType: DocumentType.PopulatedWorkflowData,\n // backward compatiblility with TonTest\n },\n true,\n grant.lockboxOwnerUuid,\n options\n )\n ).filter((entry) => !entry.metadata.consultationIds) // Keep only entries without associated consultationIds\n }\n let data = await Promise.all(\n manifest.map(async (entry) => {\n return {\n lockboxOwnerUuid: grant.lockboxOwnerUuid,\n lockboxUuid: grant.lockboxUuid!,\n dataUuid: entry.dataUuid,\n data: await this.getJsonData<PopulatedWorkflowData>(grant.lockboxUuid!, entry.dataUuid),\n }\n })\n )\n workflowData = { ...workflowData, ...data }\n }\n return workflowData\n }\n\n /**\n * @description retrieves the personal information stored in the first owned lockbox\n * @param userId The user Id\n * @returns the personal data\n */\n public async getPersonalInformations(userId: Uuid): Promise<LocalizedData<PopulatedWorkflowData>> {\n const grant = (await this.getGrants()).find((lockbox) => lockbox.lockboxOwnerUuid === userId)\n\n if (!grant) {\n throw MissingGrant\n }\n\n const { lockboxUuid, lockboxOwnerUuid } = grant\n\n if (!lockboxUuid) throw MissingLockbox\n\n if (!lockboxOwnerUuid) throw MissingLockboxOwner\n\n const identificationDataUuid = (\n await this.getLockboxManifest(\n lockboxUuid,\n {\n category: MetadataCategory.Personal,\n documentType: DocumentType.PopulatedWorkflowData,\n },\n false,\n userId\n )\n )[0].dataUuid\n\n return {\n lockboxOwnerUuid,\n lockboxUuid,\n dataUuid: identificationDataUuid,\n data: await this.getJsonData<PopulatedWorkflowData>(lockboxUuid, identificationDataUuid),\n }\n }\n\n /**\n * Retrieves the grant associated to a consultationId\n * @note returns the first grant only\n * @param consultationId The consultationId\n * @returns the grant\n */\n public async getGrantFromConsultId(consultationId: Uuid): Promise<Grant | undefined> {\n let grants = await this.getGrants({ consultationId })\n\n if (grants.length === 0) {\n throw AssociatedLockboxNotFound\n }\n\n return grants[0]\n }\n\n /**\n * retrieves the identity associated to the `consultationId`\n * @param consultationId The consultation Id\n * @returns the identity\n */\n public async getIdentityFromConsultId(consultationId: Uuid): Promise<IdentityResponse | undefined> {\n const grant = await this.getGrantFromConsultId(consultationId)\n\n if (grant && grant.lockboxOwnerUuid) {\n return await this.guardClient.identityGet(grant.lockboxOwnerUuid)\n } else {\n return undefined\n }\n }\n\n /**\n * retrieves the lockbox manifest for a given lockbox and add's its private metadata\n * @note the lockbox manifest will retrieved the cached manifest first unless force refresh is enabled\n * @param lockboxUuid\n * @param filter\n * @param expandPrivateMetadata\n * @param lockboxOwnerUuid\n * @param forceRefresh\n * @returns the lockbox manifest\n */\n public async getLockboxManifest(\n lockboxUuid: Uuid,\n filter: Metadata,\n expandPrivateMetadata: boolean,\n lockboxOwnerUuid?: Uuid,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<LockboxManifest> {\n let manifestKey = JSON.stringify({\n lockboxUuid,\n filter,\n expandPrivateMetadata,\n lockboxOwnerUuid,\n })\n if (!options.forceRefresh && this.cachedManifest[manifestKey]) return this.cachedManifest[manifestKey]\n\n return this.vaultClient.lockboxManifestGet(lockboxUuid, filter, lockboxOwnerUuid).then((manifest) => {\n return Promise.all(\n manifest.map(async (entry) => {\n if (expandPrivateMetadata && entry.metadata.privateMetadata) {\n let privateMeta = await this.getJsonData<Metadata>(\n lockboxUuid!,\n entry.metadata.privateMetadata,\n lockboxOwnerUuid\n )\n entry.metadata = {\n ...entry.metadata,\n ...privateMeta,\n }\n }\n return entry\n })\n ).then((manifest) => (this.cachedManifest[manifestKey] = manifest))\n })\n }\n\n /**\n * @description Create or update the personal information and store it in the first owned lockbox\n * @param identity The identity to use\n * @param data The personal data to store\n * @param dataUuid (optional) The dataUuid to update\n * @returns\n */\n public async createPersonalInformations(\n identity: IdentityResponse,\n data: PopulatedWorkflowData,\n dataUuid?: string\n ): Promise<DataCreateResponse> {\n const lockboxUuid = (await this.getGrants()).find(\n (lockbox) => lockbox.lockboxOwnerUuid === identity.id\n )?.lockboxUuid\n\n if (lockboxUuid) {\n return this.createJsonData<PersonalMeta>(\n lockboxUuid,\n data,\n {\n category: MetadataCategory.Personal,\n documentType: DocumentType.PopulatedWorkflowData,\n },\n {},\n undefined,\n dataUuid\n )\n } else {\n throw MissingLockbox\n }\n }\n\n /**\n * Create or update user Preference\n * @param identity\n * @param preference\n * @param dataUuid\n * @returns\n */\n public async createUserPreference(\n identity: IdentityResponse,\n preference: UserPreference,\n dataUuid?: string\n ): Promise<DataCreateResponse> {\n const lockboxUuid = (await this.getGrants()).find(\n (lockbox) => lockbox.lockboxOwnerUuid === identity.id\n )?.lockboxUuid\n\n if (lockboxUuid) {\n return this.createJsonData<PreferenceMeta>(\n lockboxUuid,\n preference,\n {\n category: MetadataCategory.Preference,\n contentType: 'application/json',\n },\n {},\n undefined,\n dataUuid\n )\n } else {\n throw MissingLockbox\n }\n }\n\n /**\n * retrieves the user preference from a grant\n * @param grant The grant\n * @returns the user preference\n */\n public async getDataFromGrant<T = any>(grant: Grant, filter: Metadata): Promise<LocalizedData<T>> {\n const { lockboxUuid, lockboxOwnerUuid } = grant\n\n if (!lockboxUuid) throw MissingLockbox\n if (!lockboxOwnerUuid) throw MissingLockboxOwner\n const identificationDataUuid = (\n await this.getLockboxManifest(lockboxUuid, filter, false, grant.lockboxOwnerUuid, { forceRefresh: true })\n )[0].dataUuid\n\n return {\n lockboxOwnerUuid,\n lockboxUuid,\n dataUuid: identificationDataUuid,\n data: await this.getJsonData<T>(lockboxUuid, identificationDataUuid),\n }\n }\n\n /**\n * retrieves the user preference from a consultation id\n * @param consultationId The related consultationId\n * @returns the user preference\n */\n public async getUserPreferenceFromConsultId(consultationId: string): Promise<LocalizedData<UserPreference>> {\n const grant = await this.getGrantFromConsultId(consultationId)\n\n if (!grant) throw MissingGrant\n\n return this.getDataFromGrant<UserPreference>(grant, {\n category: MetadataCategory.Preference,\n contentType: 'application/json',\n })\n }\n\n /**\n * retrieves the user preference stored in the first owned lockbox from identity\n * @param identity The identity to use\n * @returns the user preference\n */\n public async getUserPreference(identity: IdentityResponse): Promise<LocalizedData<UserPreference>> {\n const grant = (await this.getGrants()).find((lockbox) => lockbox.lockboxOwnerUuid === identity.id)\n\n if (!grant) throw MissingGrant\n\n return this.getDataFromGrant<UserPreference>(grant, {\n category: MetadataCategory.Preference,\n contentType: 'application/json',\n })\n }\n\n /**\n * retrieves the user preference from a consultation id\n * @param consultationId The related consultationId\n * @returns the user preference\n */\n public async getRecoveryDataFromConsultId(consultationId: string): Promise<LocalizedData<RecoveryData>> {\n const grant = await this.getGrantFromConsultId(consultationId)\n\n if (!grant) throw MissingGrant\n\n return this.getDataFromGrant<RecoveryData>(grant, {\n category: MetadataCategory.Recovery,\n contentType: 'application/json',\n })\n }\n\n /**\n * retrieves the user preference stored in the first owned lockbox from identity\n * @param identity The identity to use\n * @returns the user preference\n */\n public async getRecoveryData(identity: IdentityResponse): Promise<LocalizedData<RecoveryData>> {\n const grant = (await this.getGrants()).find((lockbox) => lockbox.lockboxOwnerUuid === identity.id)\n\n if (!grant) throw MissingGrant\n\n return this.getDataFromGrant(grant, {\n category: MetadataCategory.Recovery,\n contentType: 'application/json',\n })\n }\n\n /**\n * @name getAssignedConsultations\n * @description finds all assigned or owned consultations for the logged user\n * Steps:\n * - Retrieves all granted lockboxes given to the logged user\n * - for each lockbox, find all consultation ids\n * - for each consultation id, retrieve the consult information\n * @param practiceUuid the uuid of the practice to look consult into\n * @returns the list of consults\n */\n public async getAssignedConsultations(practiceUuid: Uuid): Promise<Consult[]> {\n return Promise.all(\n (await this.getGrants()).map((grant) =>\n this.getLockboxManifest(\n grant.lockboxUuid!,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n },\n true,\n undefined\n ).then((manifest) =>\n Promise.all(\n manifest.map(\n async (entry) =>\n await this.consultClient.getConsultByUUID(entry.metadata.consultationId, practiceUuid)\n )\n ).then((promise) => promise.flat())\n )\n )\n ).then((consults) => consults.flat())\n }\n\n /**\n * Gets the past consultations of the patient as well as his relatives if any\n * @param consultationId any consultation uuid from which we will fetch all the other consultations of the same patient as the owner of this consultation id\n * @param practiceUuid\n */\n public async getPastConsultationsFromConsultId(\n consultationId: string,\n practiceUuid: string\n ): Promise<Consult[] | undefined> {\n const grant = await this.getGrantFromConsultId(consultationId)\n if (!grant) return undefined\n\n let consultationsInLockbox: string[] = (\n await this.vaultClient.lockboxMetadataGet(\n grant.lockboxUuid!,\n ['consultationId'],\n ['consultationId'],\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n },\n grant.lockboxOwnerUuid\n )\n )\n .flat()\n .map((metadata: { consultationId: string }) => metadata.consultationId)\n\n if (consultationsInLockbox.length == 0) return []\n\n return await Promise.all(\n consultationsInLockbox.map(async (consultId: string) => {\n return await this.consultClient.getConsultByUUID(consultId, practiceUuid)\n })\n )\n }\n\n /**\n * @name getPatientConsultationData\n * @description retrieves the consultation data\n * @param consultationId\n * @returns\n */\n public async getPatientConsultationData(\n consultationId: Uuid,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<PopulatedWorkflowData[]> {\n //TODO: make use of getPatientDocumentsList instead of doing it manually here\n return Promise.all(\n (await this.getGrants({ consultationId }))\n .map((grant) =>\n this.getLockboxManifest(\n grant.lockboxUuid!,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationId, //since we want to update the cached manifest (if another consult data exists)\n },\n true,\n grant.lockboxOwnerUuid,\n options\n ).then((manifest) =>\n Promise.all(\n manifest.map((e) =>\n this.getJsonData<PopulatedWorkflowData>(\n grant.lockboxUuid!,\n e.dataUuid,\n grant.lockboxOwnerUuid\n )\n )\n )\n )\n )\n .flat()\n ).then((data) => data.flat())\n }\n\n /**\n * This function returns the patient prescriptions\n * @param consultationId\n * @returns\n */\n public async getPatientPrescriptionsList(consultationId: Uuid): Promise<Document[]> {\n return this.getPatientDocumentsList(\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.Prescription,\n },\n true,\n consultationId\n )\n }\n\n /**\n * This function returns the patient results\n * @param consultationId\n * @returns\n */\n public async getPatientResultsList(consultationId: Uuid): Promise<Document[]> {\n return this.getPatientDocumentsList(\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.Result,\n },\n true,\n consultationId\n )\n }\n\n /**\n * returns the patient treatment plan options\n * @param consultationId\n * @returns Document[] corresponding to the patient treatment plan options\n */\n public async getPatientTreatmentPlans(consultationId: Uuid): Promise<Document[]> {\n return this.getPatientDocumentsList(\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.TreatmentPlan,\n },\n true,\n consultationId\n )\n }\n\n /**\n * returns a specific patient treatment plan option\n * @param consultationId\n * @param treatmentPlanId\n * @returns\n */\n public async getPatientTreatmentPlanByUuid(consultationId: Uuid, treatmentPlanId: Uuid): Promise<Document[]> {\n return this.getPatientDocumentsList(\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.TreatmentPlan,\n treatmentPlanId,\n },\n true,\n consultationId\n )\n }\n\n /**\n * @name getPatientDocumentsList\n * @description applies the provided filter to the vault to only find those documents\n * @param filters the applied filters (e.g. type of documents)\n * @param expandPrivateMetadata whether or not, the private metadata needs to be retrieved\n * (more computationally expensive)\n * @param consultationId\n * @returns the filtered document list\n */\n public async getPatientDocumentsList(\n filters: Object,\n expandPrivateMetadata: boolean,\n consultationId: Uuid\n ): Promise<Document[]> {\n return Promise.all(\n (await this.getGrants({ consultationId }))\n .map((grant) =>\n this.getLockboxManifest(\n grant.lockboxUuid!,\n { ...filters, consultationId },\n expandPrivateMetadata,\n grant.lockboxOwnerUuid,\n { forceRefresh: true }\n ).then((manifest) =>\n Promise.all(\n manifest.map(async (entry): Promise<Document> => {\n return {\n lockboxOwnerUuid: grant.lockboxOwnerUuid,\n lockboxUuid: grant.lockboxUuid!,\n ...entry,\n }\n })\n )\n )\n )\n .flat()\n ).then((data) => data.flat())\n }\n\n /****************************************************************************************************************\n * RECOVERY *\n ****************************************************************************************************************/\n\n /**\n * @name recoverPrivateKeyFromSecurityQuestions\n * @description Recovers and sets the rsa private key from the answered security questions\n * @param id\n * @param recoverySecurityQuestions\n * @param recoverySecurityAnswers\n * @param threshold the number of answers needed to recover the key\n */\n public async recoverPrivateKeyFromSecurityQuestions(\n id: Uuid,\n recoverySecurityQuestions: string[],\n recoverySecurityAnswers: string[],\n threshold: number\n ) {\n let shards: SecretShard[] = (await this.guardClient.identityGet(id)).recoverySecurityQuestions!\n let answeredShards = shards\n .filter((shard: any) => {\n // filters all answered security questions\n let indexOfQuestion = recoverySecurityQuestions.indexOf(shard.securityQuestion)\n if (indexOfQuestion === -1) return false\n return recoverySecurityAnswers[indexOfQuestion] && recoverySecurityAnswers[indexOfQuestion] != ''\n })\n .map((item: any) => {\n // appends the security answer to the answered shards\n let index = recoverySecurityQuestions.indexOf(item.securityQuestion)\n item.securityAnswer = recoverySecurityAnswers[index]\n return item\n })\n try {\n // reconstructs the key from the answered security answers\n let privateKey = this.toolbox.reconstructSecret(answeredShards, threshold)\n this.rsa = this.toolbox.CryptoRSA.fromKey(privateKey)\n } catch (e) {\n console.error(e)\n }\n }\n\n /**\n * @name recoverPrivateKeyFromPassword\n * @description Recovers and sets the rsa private key from the password\n * @param id\n * @param password\n */\n public async recoverPrivateKeyFromPassword(id: Uuid, password: string) {\n let identity = await this.guardClient.identityGet(id)\n\n let recoveryPayload = identity.recoveryPassword\n let symmetricDecryptor = this.toolbox.CryptoChaCha.fromPassphrase(password)\n let privateKey = symmetricDecryptor.base64PayloadDecryptToBytes(recoveryPayload)\n\n if (identity.recoveryLogin) {\n //Ensure we can recover from a page reload\n let symetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(identity.recoveryLogin)\n sessionStorage.setItem(\n sessionStorePrivateKeyName(id),\n symetricEncryptor.bytesEncryptToBase64Payload(privateKey)\n )\n }\n\n this.rsa = this.toolbox.CryptoRSA.fromKey(privateKey)\n }\n\n /**\n * @name recoverPrivateKeyFromMasterKey\n * @description Recovers and sets the rsa private key from the master key\n * @param id\n * @param masterKey\n */\n public async recoverPrivateKeyFromMasterKey(id: Uuid, masterKey: string) {\n let recoveryPayload = (await this.guardClient.identityGet(id)).recoveryMasterKey!\n let symmetricDecryptor = this.toolbox.CryptoChaCha.fromPassphrase(masterKey)\n let privateKey = symmetricDecryptor.base64PayloadDecryptToBytes(recoveryPayload)\n this.rsa = this.toolbox.CryptoRSA.fromKey(privateKey)\n }\n\n /**\n * @description Generates and updates the security questions and answers payload using new recovery questions and answers\n * Important: Since the security questions generate a payload for the private key, they will never be stored on the device as they must remain secret!!!\n * @param id\n * @param recoverySecurityQuestions\n * @param recoverySecurityAnswers\n * @param threshold the number of answers needed to rebuild the secret\n */\n public async updateSecurityQuestions(\n id: Uuid,\n recoverySecurityQuestions: string[],\n recoverySecurityAnswers: string[],\n threshold: number\n ) {\n if (!this.rsa) throw IncompleteAuthentication\n let securityQuestionPayload = this.toolbox.breakSecretIntoShards(\n recoverySecurityQuestions,\n recoverySecurityAnswers,\n this.rsa.private(),\n threshold\n )\n let updateRequest = {\n recoverySecurityQuestions: securityQuestionPayload,\n }\n\n return await this.guardClient.identityUpdate(id, updateRequest)\n }\n\n /**\n * @description Generates and stores the payload encrypted payload and updates the password itself (double hash)\n * @important\n * the recovery payload uses a singly hashed password and the password stored is doubly hashed so\n * the stored password cannot derive the decryption key in the payload\n * @note\n * the old password must be provided when not performing an account recovery\n * @param id\n * @param newPassword\n * @param oldPassword\n */\n public async updatePassword(id: Uuid, newPassword: string, oldPassword?: string) {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(newPassword)\n let passwordPayload = symmetricEncryptor.bytesEncryptToBase64Payload(this.rsa.private())\n if (oldPassword) {\n oldPassword = this.toolbox.hashStringToBase64(this.toolbox.hashStringToBase64(oldPassword))\n }\n\n newPassword = this.toolbox.hashStringToBase64(this.toolbox.hashStringToBase64(newPassword))\n\n let updateRequest = {\n password: {\n oldPassword,\n newPassword,\n },\n recoveryPassword: passwordPayload,\n }\n\n return await this.guardClient.identityUpdate(id, updateRequest)\n }\n\n /**\n * @description Generates and stores the master key encrypted payload\n * Important\n * Since the master key is used to generate a payload for the private key, it will never be stored on the device as it must remain secret!\n * @param id\n * @param masterKey\n * @param lockboxUuid\n */\n async updateMasterKey(id: Uuid, masterKey: string, lockboxUuid: Uuid) {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(masterKey)\n let masterKeyPayload = symmetricEncryptor.bytesEncryptToBase64Payload(this.rsa.private())\n let updateRequest = { recoveryMasterKey: masterKeyPayload }\n const updatedIdentity = await this.guardClient.identityUpdate(id, updateRequest)\n\n await this.getOrInsertJsonData<RecoveryMeta>(\n lockboxUuid,\n { masterKey },\n {\n category: MetadataCategory.Recovery,\n contentType: 'application/json',\n },\n {},\n { forceReplace: true, withNotification: false, updateMedicalStatus: false }\n )\n\n return updatedIdentity\n }\n}\n","import { AxiosService, CliniaResponse, FacetFilter, PlaceData } from \"oro-sdk-apis\"\n\nexport class CliniaService {\n private api: AxiosService\n\n constructor(private url: string, apiKey: string, private locale?: string) {\n this.api = new AxiosService({ headers: { 'X-Clinia-API-Key': apiKey } })\n }\n\n public placeSearch(searchOptions: {\n locale?: string\n query?: string\n facetFilters?: FacetFilter[]\n location?: string\n aroundLatLng?: string\n page?: number\n }) {\n const { locale, ...data } = searchOptions\n\n return this.api.post<CliniaResponse<PlaceData>>(\n `${this.url}/search/v1/indexes/health_facility/query`,\n data,\n {\n params: { locale: locale ?? this.locale },\n }\n )\n }\n\n public placeMatch(\n searchOptions: {\n locale?: string\n name?: string\n address?: string\n postalCode?: string\n place?: string\n region?: string\n country?: string\n },\n type?: string\n ) {\n const { locale, ...data } = searchOptions\n\n let request = this.api.post<PlaceData[]>(\n `${this.url}/search/v1/matches`,\n data,\n {\n params: { locale: locale ?? this.locale },\n }\n )\n\n if (type) {\n request = request.then((places) =>\n places.filter((place) => place.type === type)\n )\n }\n\n return request\n }\n}\n","import initApis from 'oro-sdk-apis'\nimport { OroClient } from './client'\nimport * as OroToolboxNamespace from 'oro-toolbox'\n\nexport type OroToolbox = typeof OroToolboxNamespace\n\nexport let wasmPath = 'node_modules/oro-toolbox'\n\n/**\n * This function helps you to initialize and OroClient instance\n * @param toolbox the OroToolbox object\n * @param tellerBaseURL the teller service base URL \n * @param vaultBaseURL the vault service base URL \n * @param guardBaseURL the guard service base URL \n * @param searchbaseURL the search service base URL\n * @param practiceBaseURL the practice service base URL \n * @param consultBaseURL the consult service base URL \n * @param workflowBaseURL the workflow service base URL \n * @param diagnosisBaseURL the diagnosis service base URL \n * @param authenticationCallback (optional) authenticationCallback the authentification callback \n * @returns an instance of OroClient\n */\nconst init = (\n toolbox: OroToolbox,\n tellerBaseURL: string,\n vaultBaseURL: string,\n guardBaseURL: string,\n searchBaseURL: string,\n practiceBaseURL: string,\n consultBaseURL: string,\n workflowBaseURL: string,\n diagnosisBaseURL: string,\n authenticationCallback?: (err: Error) => void\n) => {\n const {\n tellerService,\n practiceService,\n consultService,\n vaultService,\n guardService,\n searchService,\n workflowService,\n diagnosisService,\n } = initApis(\n {\n tellerBaseURL,\n vaultBaseURL,\n guardBaseURL,\n searchBaseURL,\n practiceBaseURL,\n consultBaseURL,\n workflowBaseURL,\n diagnosisBaseURL,\n },\n authenticationCallback\n )\n\n const client = new OroClient(\n toolbox,\n tellerService!,\n vaultService!,\n guardService!,\n searchService!,\n practiceService!,\n consultService!,\n workflowService!,\n diagnosisService!,\n authenticationCallback\n )\n\n return client\n}\n\nexport { OroClient } from './client'\nexport * from 'oro-sdk-apis'\nexport * from './models'\nexport * from './helpers'\nexport * from './services'\nexport { OroToolboxNamespace }\nexport default init\n"],"names":["personalMetaToPrefix","MetadataCategory","Personal","ChildPersonal","OtherPersonal","identificationToPersonalInformations","data","category","prefix","birthday","firstname","gender","name","phone","zip","hid","pharmacy","address","toActualObject","ret","Object","entries","fields","forEach","field","displayedAnswer","answer","sessionStorePrivateKeyName","id","IncompleteAuthentication","_inheritsLoose","Error","MissingGrant","MissingGrantFilter","MissingLockbox","MissingLockboxOwner","AssociatedLockboxNotFound","WorkflowAnswersMissingError","filterTriggeredAnsweredWithKind","_filterTriggeredAnsweredWithKind","workflowData","kind","selectedAnswers","_context","flattenedAnswers","flattenSelectedAnswers","triggeredQuestionsWithKind","fromEntries","pages","map","a","questions","filter","question","isTriggered","triggers","flat","samePageAnswers","reduce","prev","cur","res","keys","questionFieldName","getWorkflowDataByCategory","_getWorkflowDataByCategory","_context2","triggeredQuestions","Promise","all","e","k","populateWorkflowField","then","populatedValue","workflowCreatedAt","createdAt","workflowId","locale","err","console","error","getImagesFromIndexDb","_getImagesFromIndexDb","_context3","getMany","v","_populateWorkflowField","answerValue","undefined","_context4","answers","text","value","images","image","imageData","resolve","includes","Array","isArray","some","subSetTriggers","every","trigger","linearAnswers","push","values","getInitialisedSelectedAnswers","workflow","useDefault","page","defaultValue","getOrCreatePatientConsultationUuid","_getOrCreatePatientConsultationUuid","consult","oroClient","practiceClient","practiceGetPayment","uuidPractice","idStripeInvoiceOrPaymentIntent","payment","uuidConsult","consultClient","getConsultByUUID","consultCreate","registerPatient","_registerPatient","patientUuid","consultRequest","masterKey","recoveryQA","indexSearch","onProgress","lockboxUuid","practitionerAdmin","retry","identity","errorsThrown","stepsTotalNum","currentStep","setTimeout","practiceGetFromUuid","uuidAdmin","practiceGetPractitioners","log","practitioners","getOrCreatePatientLockbox","guardClient","identityGet","grantLockbox","grantPromises","practitioner","uuid","IndexKey","ConsultationLockbox","grant","lockboxOwnerUuid","consultationId","consultIndex","consultIndexPromises","vaultIndexAdd","storeImageAliases","storePatientData","isoLanguageRequired","_identity","recoveryMasterKey","updateMasterKey","_identity2","recoverySecurityQuestions","updateSecurityQuestions","recoverySecurityAnswers","buildConsultSearchIndex","length","updateConsultByUUID","statusMedical","MedicalStatus","New","cleanIndex","_getOrCreatePatientLockbox","_context5","getGrants","grants","vaultClient","lockboxCreate","lockboxResponse","authRefresh","tokens","setTokens","accessToken","refreshToken","whoAmI","_storePatientData","isoLanguage","getOrInsertJsonData","Raw","contentType","Consultation","documentType","DocumentType","PopulatedWorkflowData","withNotification","forceReplace","updateMedicalStatus","Medical","consultationIds","extractAndStorePersonalWorkflowData","Preference","dataUuids","_storeImageAliases","progress","_context7","nonNullImages","img","storedImagesNum","totalImagesNum","promises","ImageAlias","idbId","progressStepValue","Math","round","_extractAndStorePersonalWorkflowData","extractPersonalInfoFromWorkflowData","_extractPersonalInfoFromWorkflowData","personalInfoPopulatedWfData","childPersonalInfoPopulatedWfData","otherPersonalInfoPopulatedWfData","_buildConsultSearchIndex","terms","shortId","_context10","_yield$extractPersona","personalInfo","childPersonalInfo","otherPersonalInfo","searchClient","index","decryptGrants","encryptedGrants","rsaKey","encryptedLockbox","uuidParse","base64DecryptToBytes","decryptConsultLockboxGrants","encryptedConsultLockboxes","base64DecryptToJson","encryptedIndexEntry","grantsTuple","grantTuples","createRefill","_createRefill","populatedRefillWorkflow","newConsult","getLockboxManifest","uuidParent","rawConsultationManifest","getJsonData","dataUuid","rawConsultation","filterGrantsWithLockboxMetadata","_filterGrantsWithLockboxMetadata","filteredGrants","_iterator","lockboxMetadataGet","OroClient","toolbox","tellerClient","workflowClient","diagnosisClient","authenticationCallback","this","_proto","cachedMetadataGrants","cachedManifest","signUp","email","password","practice","tosAndCpAcceptance","tokenData","subscription","skipEmailValidation","rsa","CryptoRSA","privateKey","symmetricEncryptor","CryptoChaCha","fromPassphrase","recoveryPassword","bytesEncryptToBase64Payload","hashedPassword","hashStringToBase64","toLowerCase","subscriptionAcceptance","signupRequest","practiceUuid","emailConfirmed","publicKey","encodeToBase64","identityCreate","recoveryLogin","symetricEncryptor","sessionStorage","setItem","confirmEmail","identityUpdate","sub","signIn","otp","tokenRequest","authToken","userUuid","recoverPrivateKeyFromPassword","resumeSession","recoveryPayload","getItem","recoveryKey","symmetricDecryptor","base64PayloadDecryptToBytes","fromKey","localEncryptToJsonPayload","chaChaKey","encryptedData","jsonEncryptToBase64Payload","encryptedKey","encryptToBytes","key","localDecryptJsonPayload","base64PayloadDecryptToJson","signOut","secrets","_context6","authLogout","_context8","forceUpdateIndexEntries","_this$vaultIndexAdd","_context9","_this","consults","alert","indexOwnerUuid","_context11","rsaPub","decodeFromBase64","encryptedIndex","_i","uniqueHash","timestamp","jsonWithPubEncryptToBase64","vaultIndexPut","granteeUuid","_context12","getCachedSecretCryptor","secret","granteePublicKey","granteeEncryptedSecret","bytesWithPubEncryptToBase64","request","encryptedSecret","lockboxGrant","createMessageData","message","previousDataUuid","options","_context13","author","encryptedPrivateMeta","lockboxDataStore","publicMetadata","Message","privateMetadata","createMessageAttachmentData","_context14","Uint8Array","arrayBuffer","lastModified","size","fileName","type","createConsultationAttachmentData","_context15","createBytesData","createJsonData","meta","privateMeta","_context16","_context17","lockboxManifestGet","manifest","JSON","stringify","_context18","_context19","lockboxDataGet","_yield$Promise$all","getBytesData","_context20","_yield$Promise$all2","_context21","filterString","getAccountRole","currentAccountRole","OtherRoleType","User","Patient","requiredRole","grantsGet","decryptedGrants","info","vaultIndexGet","decryptedConsults","grantsByConsultLockbox","_context22","scope","split","_context23","findIndex","lockboxSecretGet","sharedSecret","cryptor","getPersonalInformationsFromConsultId","forceRefresh","getMetaCategoryFromConsultId","getMedicalDataFromConsultId","_context28","_loop","_context27","_this2","entry","metadata","_context26","getPersonalInformations","userId","_context29","find","lockbox","identificationDataUuid","getGrantFromConsultId","_context30","getIdentityFromConsultId","_context31","expandPrivateMetadata","manifestKey","_context33","_context32","_this3","createPersonalInformations","_context34","_yield$this$getGrants","createUserPreference","preference","_context35","_yield$this$getGrants2","getDataFromGrant","_context36","getUserPreferenceFromConsultId","_context37","getUserPreference","_context38","getRecoveryDataFromConsultId","_context39","Recovery","getRecoveryData","_context40","getAssignedConsultations","_context42","_this4","_context41","promise","getPastConsultationsFromConsultId","_context44","consultationsInLockbox","consultId","_context43","_this5","getPatientConsultationData","_context45","_this6","getPatientPrescriptionsList","getPatientDocumentsList","Prescription","getPatientResultsList","Result","getPatientTreatmentPlans","TreatmentPlan","getPatientTreatmentPlanByUuid","treatmentPlanId","filters","_context51","_this7","recoverPrivateKeyFromSecurityQuestions","threshold","_context52","answeredShards","shard","indexOfQuestion","indexOf","securityQuestion","item","securityAnswer","reconstructSecret","_context53","recoverPrivateKeyFromMasterKey","_context54","_context55","securityQuestionPayload","breakSecretIntoShards","updateRequest","updatePassword","newPassword","oldPassword","_context56","passwordPayload","_context57","masterKeyPayload","updatedIdentity","CliniaService","url","apiKey","api","AxiosService","headers","X-Clinia-API-Key","placeSearch","searchOptions","post","params","placeMatch","places","place","tellerBaseURL","vaultBaseURL","guardBaseURL","searchBaseURL","practiceBaseURL","consultBaseURL","workflowBaseURL","diagnosisBaseURL","initApis","tellerService","vaultService","guardService","searchService","practiceService","consultService","workflowService","diagnosisService","arrSelectedLocality","flatMap","currentAnswerPage","arrCountryFields","workflowFieldName","arrProvinceFields","arrConsultLocalFields","currentFieldName","currentSelectedLocality","startsWith","allowedLocalityPatterns","indexPriority","isoValue","finalLocality","extractedSelected","exec","indexSelectedPriority","isoSelectedValue","extractedFinal","indexFinalPriority","populatedWorkflow","filledWorkflow","parse","pageIdx","isTreatmentWorking","hasSideEffects","deliveryAddress","culDeSacs","hidePlanRules","title","groups","fieldsAndGroups","label","inline","inlineLabel","metaCategory","Refill","73bec6eb-0310-4787-af3c-ac9c291737b2","e193951f-986f-4db3-bede-903045a1804a","1b87ad22-d316-4fac-9c7f-8f4ccb841aed","ab7f5a41-c351-4f5d-a568-e38f9f200e9a","youPharmacy","summaryLabel","youAddress","infos"],"mappings":"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"}
1
+ {"version":3,"file":"oro-sdk.cjs.production.min.js","sources":["../src/helpers/client.ts","../src/models/error.ts","../src/helpers/workflow.ts","../src/helpers/consult.ts","../src/helpers/patient-registration.ts","../src/helpers/vault-grants.ts","../src/helpers/prescription-refill.ts","../src/sdk-revision/client.ts","../src/client.ts","../src/services/external/clinia.ts","../src/index.ts"],"sourcesContent":["import {\n PopulatedWorkflowData,\n MetadataCategory,\n SelectedAnswersData,\n} from 'oro-sdk-apis'\nimport { PersonalInformations } from '../models/client'\n\nconst personalMetaToPrefix = {\n [MetadataCategory.Personal]: 'you',\n [MetadataCategory.ChildPersonal]: 'child',\n [MetadataCategory.OtherPersonal]: 'other',\n}\n\n/**\n * This function extract PersonalInformations from data input object coming from workflow\n * @param data extracted from WorkflowData\n * @returns PersonalInformations of a patient\n */\nexport function identificationToPersonalInformations(\n data: any,\n category:\n | MetadataCategory.Personal\n | MetadataCategory.ChildPersonal\n | MetadataCategory.OtherPersonal\n): PersonalInformations {\n const prefix = personalMetaToPrefix[category]\n\n return {\n birthday: data[`${prefix}Birthday`],\n firstname: data[`${prefix}Firstname`],\n gender: data[`${prefix}Gender`],\n name: data[`${prefix}Name`],\n phone: data[`${prefix}Phone`],\n zip: data[`${prefix}Zip`],\n hid: data[`${prefix}HID`] ?? data[`${prefix}ID`], // This is done for backward compatibility (historically youID was used)\n pharmacy: data[`${prefix}Pharmacy`],\n address: data[`${prefix}Address`],\n }\n}\n\nexport function toActualObject(data: PopulatedWorkflowData) {\n const ret: any = {}\n\n Object.entries(data.fields).forEach(([key, field]) => {\n ret[key] = field.displayedAnswer ? field.displayedAnswer : field.answer\n })\n\n return ret\n}\n\n/**\n * This function update a PopulatedWorkflowData with PersonalInformations\n * @param infos the personal informations\n * @param data the PopulatedWorkflowData\n * @returns an updated PopulatedWorkflowData\n */\nexport function updatePersonalIntoPopulatedWorkflowData(\n infos: PersonalInformations,\n data: PopulatedWorkflowData,\n category:\n | MetadataCategory.Personal\n | MetadataCategory.ChildPersonal\n | MetadataCategory.OtherPersonal\n) {\n const prefix = personalMetaToPrefix[category]\n\n const ret = JSON.parse(JSON.stringify(data)) // deep copy PopulatedWorkflowData\n\n if (infos.birthday && ret.fields[`${prefix}Birthday`])\n ret.fields[`${prefix}Birthday`].answer = infos.birthday\n if (infos.firstname && ret.fields[`${prefix}Firstname`])\n ret.fields[`${prefix}Firstname`].answer = infos.firstname\n if (infos.gender && ret.fields[`${prefix}Gender`])\n ret.fields[`${prefix}Gender`].answer = infos.gender\n if (infos.name && ret.fields[`${prefix}Name`])\n ret.fields[`${prefix}Name`].answer = infos.name\n if (infos.phone && ret.fields[`${prefix}Phone`])\n ret.fields[`${prefix}Phone`].answer = infos.phone\n if (infos.zip && ret.fields[`${prefix}Zip`])\n ret.fields[`${prefix}Zip`].answer = infos.zip\n if (infos.hid) {\n if (ret.fields[`${prefix}HID`]) {\n ret.fields[`${prefix}HID`].answer = infos.hid\n } else if (ret.fields[`${prefix}ID`]) {\n // This is done for backward compatibility (historically youID was used)\n ret.fields[`${prefix}ID`].answer = infos.hid\n } else {\n // If does not exist create it\n ret.fields[`${prefix}HID`] = { kind: 'text', answer: infos.hid }\n }\n }\n\n return ret\n}\n\n/**\n * This function extract an ISO 3166-1 alpha-2 country and subdivision code from data input object coming from workflow\n * @param answers answers from the WorkflowData\n * @returns an ISO 3166 alpha-2 code or undefined\n */\nexport function extractISOLocalityForConsult(\n answers?: SelectedAnswersData\n): string | undefined {\n if (!answers) {\n return undefined\n }\n\n const arrAnswersWithLocality = answers\n .flatMap((currentAnswerPage) => {\n const arrCountryFields = Object.keys(currentAnswerPage)\n .filter(\n (workflowFieldName) =>\n workflowFieldName.indexOf('Country') !== -1\n )\n .flat()\n const arrProvinceFields = Object.keys(currentAnswerPage)\n .filter(\n (workflowFieldName) =>\n workflowFieldName.indexOf('Province') !== -1\n )\n .flat()\n const arrConsultLocalFields = Object.keys(currentAnswerPage)\n .filter(\n (workflowFieldName) =>\n workflowFieldName.indexOf('Locality') !== -1\n )\n .flat()\n //returning the actual selected values, skipping if their IDs are more complex than a string\n return [\n ...arrCountryFields.map(\n (currentFieldName) =>\n (typeof currentAnswerPage[currentFieldName] === 'string'\n ? currentAnswerPage[currentFieldName]\n : undefined) as string\n ),\n ...arrProvinceFields.map(\n (currentFieldName) =>\n (typeof currentAnswerPage[currentFieldName] === 'string'\n ? currentAnswerPage[currentFieldName]\n : undefined) as string\n ),\n ...arrConsultLocalFields.map(\n (currentFieldName) =>\n (typeof currentAnswerPage[currentFieldName] === 'string'\n ? currentAnswerPage[currentFieldName]\n : undefined) as string\n ),\n ]\n })\n .filter((item) => item !== undefined)\n\n const arrSelectedLocality = arrAnswersWithLocality.filter(\n (currentSelectedLocality) =>\n currentSelectedLocality.startsWith('isoLocalityConsult')\n )\n if (!arrSelectedLocality || arrSelectedLocality.length === 0) {\n console.log('no locality found in ' + arrSelectedLocality)\n return undefined\n }\n //to allow enforcing of an order, we will allow the following pattern in the isoLocalityConsult field name\n // isoLocalityConsult-QC-CA and isoLocalityConsult_1-QC-CA\n // or generally: isoLocalityConsult-<isoValue> or isoLocalityConsult_<priority>-<isoValue>\n const allowedLocalityPatterns = /isoLocalityConsult(?:_(?<indexPriority>\\d*))?-(?<isoValue>[a-zA-Z0-9]{2}-[a-zA-Z0-9]{1,3})/\n const finalLocality = arrSelectedLocality.reduce<string | undefined>(\n (finalLocality, currentSelectedLocality) => {\n const extractedSelected = allowedLocalityPatterns.exec(\n currentSelectedLocality\n )\n const [, indexSelectedPriority, isoSelectedValue] =\n extractedSelected ?? []\n if (!finalLocality) {\n return isoSelectedValue\n }\n\n const extractedFinal = allowedLocalityPatterns.exec(finalLocality)\n const [, indexFinalPriority, isoFinalValue] = extractedFinal ?? []\n //we only keep the old value if there's priority used\n // and the new value is of lower priority\n if (\n !indexSelectedPriority ||\n (indexFinalPriority &&\n indexFinalPriority > indexSelectedPriority)\n ) {\n return isoFinalValue\n }\n\n return isoSelectedValue\n },\n undefined\n )\n\n console.log('Picking locality ' + finalLocality)\n return finalLocality\n}\n\nconst sessionPrivateKeyPrefix = 'sess-pkey'\nexport function sessionStorePrivateKeyName(id: string): string {\n return sessionPrivateKeyPrefix + id\n}\n","export class IncompleteAuthentication extends Error { }\nexport class MissingGrant extends Error { }\nexport class MissingGrantFilter extends Error { }\nexport class MissingLockbox extends Error { }\nexport class MissingLockboxOwner extends Error { }\nexport class AssociatedLockboxNotFound extends Error { }\nexport class WorkflowAnswersMissingError extends Error { }\n","import { getMany } from 'idb-keyval'\nimport { WorkflowAnswersMissingError } from '../models'\nimport {\n MetadataCategory,\n PopulatedWorkflowData,\n PopulatedWorkflowField,\n QuestionData,\n SelectedAnswerData,\n SelectedAnswersData,\n WorkflowData,\n WorkflowPageData,\n WorkflowUploadedImage,\n} from 'oro-sdk-apis'\n\nexport async function filterTriggeredAnsweredWithKind(\n workflowData: WorkflowData,\n kind:\n | 'text'\n | 'text-area'\n | 'text-select-group'\n | 'date'\n | 'number'\n | 'images'\n | 'images-alias'\n | 'body-parts'\n | 'pharmacy-picker'\n | 'online-pharmacy-picker'\n | 'hair-selector-women'\n | 'hair-selector-men'\n | 'hair-loss-stage'\n | 'hair-loss-frontal'\n): Promise<SelectedAnswerData[]> {\n if (!workflowData.selectedAnswers) throw WorkflowAnswersMissingError\n // Flattens the list of answered questions\n let flattenedAnswers = flattenSelectedAnswers(workflowData.selectedAnswers)\n // Generates a list of applicable questions\n let triggeredQuestionsWithKind = Object.fromEntries(\n workflowData.pages\n .map((a) => {\n return Object.entries(a.questions).filter(\n ([_, question]) => isTriggered(question.triggers || [], flattenedAnswers) && question.kind === kind\n )\n })\n .flat()\n )\n\n const samePageAnswers = workflowData.selectedAnswers.reduce((prev, cur) => {\n return { ...prev, ...cur }\n }, {})\n\n const res = Object.keys(triggeredQuestionsWithKind).map((questionFieldName) => {\n return samePageAnswers[questionFieldName]\n })\n\n return res\n}\n\n/**\n * Filters and Populates the `selectedAnswers` from the workflow by\n * Cross-referencing the `MetaCategory` of the answer's respective question\n * Populates the fields labels and values that are of radio, dropdown and checkbox types\n *\n * @param workflowData\n * @param category\n * @returns An array of record key, value pairs\n */\nexport async function getWorkflowDataByCategory(\n workflowData: WorkflowData,\n category: MetadataCategory\n): Promise<PopulatedWorkflowData> {\n if (!workflowData.selectedAnswers) throw WorkflowAnswersMissingError\n\n // Flattens the list of answered questions\n let flattenedAnswers = flattenSelectedAnswers(workflowData.selectedAnswers)\n // Generates a list of applicable questions\n let triggeredQuestions = Object.fromEntries(\n workflowData.pages\n .map((a) => {\n return Object.entries(a.questions).filter(([_, question]) =>\n isTriggered(question.triggers || [], flattenedAnswers)\n )\n })\n .flat()\n )\n\n const fields: Record<string, PopulatedWorkflowField> = {}\n\n // Generates the answers of the specified category and adds the appropriate values if any are missing\n return Promise.all(\n workflowData.selectedAnswers\n .map((e) => Object.entries(e))\n .flat()\n .filter(([k, v]) => triggeredQuestions[k] && triggeredQuestions[k]['metaCategory'] === category)\n .map(([k, v]) => {\n return populateWorkflowField(triggeredQuestions[k], v).then((populatedValue) => {\n fields[k] = populatedValue\n })\n })\n )\n .then(() => {\n const ret: PopulatedWorkflowData = {\n workflowCreatedAt: workflowData.createdAt,\n workflowId: workflowData.id,\n locale: workflowData.locale,\n fields,\n }\n return ret\n })\n .catch((err) => {\n console.error(`Error while extracting ${category} data from workflow`, err)\n throw err\n })\n}\n\nexport async function getImagesFromIndexDb(answer: SelectedAnswerData): Promise<WorkflowUploadedImage[]> {\n return await getMany<WorkflowUploadedImage>((answer as any[]).map((v) => v.id ?? v) as string[])\n}\n\n/**\n * (If applicable) Based on the question kind, and the answer type this function will add and replace the appropriate fields to the\n * field values if they are radio, dropdown and checkbox fields\n *\n *\n * @param question\n * @param answerValue\n * @returns\n */\nasync function populateWorkflowField(\n question: QuestionData,\n answerValue: SelectedAnswerData\n): Promise<PopulatedWorkflowField> {\n let answer: any\n let displayedAnswer: string | string[] | undefined = undefined\n switch (question.kind) {\n case 'text-select-group':\n if (question.answers) {\n displayedAnswer = `${answerValue[0]} ${question.answers[answerValue[1] as string].text}`\n }\n answer = answerValue\n break\n case 'radio':\n case 'radio-card':\n case 'select':\n if (question.answers) {\n displayedAnswer = question.answers[answerValue as string].text\n }\n\n answer = answerValue\n break\n case 'multiple':\n case 'checkbox-group':\n displayedAnswer = (answerValue as string[]).map((value) => {\n if (question.answers) {\n return question.answers[value].text\n }\n\n throw new WorkflowAnswersMissingError()\n })\n\n answer = answerValue\n break\n case 'images':\n answer = await getImagesFromIndexDb(answerValue).then((images) =>\n images.map((image) => {\n const { name, imageData } = image\n\n return { name, imageData }\n })\n )\n break\n default:\n answer = answerValue\n }\n\n return Promise.resolve({\n answer,\n displayedAnswer,\n kind: question.kind,\n })\n}\n\n/**\n * Determine if a question is triggered by some answers\n *\n * We use the following logical combinations of rules:\n *\n * #### Single string\n *\n * ```\n * // Required: rule1\n * rules: rule1\n * ```\n *\n * #### Array of strings (AND is applied between statements):\n *\n * ```\n * // Required: rule1 AND rule2\n * rules: [ rule1, rule2 ]\n * ```\n *\n * #### Array of arrays of strings (OR is applied between inner arrays. AND is applied between inner arrays statements)\n *\n * ```\n * // Required: rule1 OR rule2\n * rules: [\n * [ rule1 ],\n * [ rule2 ]\n * ]\n *\n * // Required: rule1 OR (rule2 AND rule3)\n * rules: [\n * [ rule1 ],\n * [ rule2, rule3 ]\n * ]\n *\n * // THIS IS FORBIDDEN\n * rules: [\n * rule1, // <-- THIS IS FORBIDDEN. Instead use [ rule1 ]\n * [ rule2, rule3 ]\n * ]\n * ```\n *\n * @param triggers the triggering rules\n * @param answers the answers to check againts triggering rules\n * @returns `true` if triggers are verified against ansers. Otherwise, returns `false`.\n * @throws an Error if triggers typing is wrong\n */\nexport function isTriggered(triggers: string[][] | string[] | string, answers: string[]): boolean {\n // is triggers contained in answers\n if (typeof triggers === 'string') {\n return answers.includes(triggers)\n }\n\n if (Array.isArray(triggers)) {\n // rule combination kind: rule1 OR (rule2 AND rule3)\n if (Array.isArray(triggers[0])) {\n return (triggers as string[][]).some((subSetTriggers) =>\n subSetTriggers.every((trigger) => answers.includes(trigger))\n )\n } else {\n // rule combination kind: rule1 AND rule2\n return (triggers as string[]).every((trigger) => answers.includes(trigger))\n }\n }\n\n throw Error('[isTriggered] triggers is not typed well')\n}\n\nexport function flattenSelectedAnswers(answers: SelectedAnswersData) {\n const linearAnswers: SelectedAnswerData[] = []\n\n for (const answer of answers) {\n linearAnswers.push(...Object.values(answer))\n }\n\n return linearAnswers.flat(1)\n}\n\n/**\n * This function helps you to get a valid workflow selectedAnswers structure\n * @param workflow the workflow data to use to initialize selectedAnswers\n * @param useDefault use workflow default values or not (this is used to avoid having unset values to appear in summaries)\n * @returns a valid selectedAnswers structure\n */\nexport function getInitialisedSelectedAnswers(workflow: WorkflowData, useDefault: boolean = true) {\n return workflow.pages.map((page) => {\n const ret: any = {}\n for (const [id, question] of Object.entries(page.questions)) {\n if (question.kind === 'body-parts') {\n ret[id] = useDefault ? [] : undefined\n } else {\n ret[id] = useDefault && question.defaultValue ? question.defaultValue : undefined\n }\n }\n return ret\n })\n}\n\nexport function fillWorkflowFromPopulatedWorkflow(workflow: WorkflowData, populatedWorkflow: PopulatedWorkflowData) {\n const filledWorkflow = JSON.parse(JSON.stringify(workflow))\n\n if (!filledWorkflow.selectedAnswers) {\n filledWorkflow.selectedAnswers = getInitialisedSelectedAnswers(filledWorkflow, false)\n }\n\n filledWorkflow.pages.forEach((page: WorkflowPageData, pageIdx: number) => {\n const ret: any = {}\n for (const [id] of Object.entries(page.questions)) {\n if (populatedWorkflow.fields[id]) {\n if (filledWorkflow.selectedAnswers)\n filledWorkflow.selectedAnswers[pageIdx][id] = populatedWorkflow.fields[id].answer as\n | string\n | string[]\n }\n }\n })\n\n return filledWorkflow\n}\n","import { Consult, ConsultRequest } from 'oro-sdk-apis'\nimport { OroClient } from '..'\n\n/**\n * Creates a consultation if one has not been created and fails to be retrieved by the payment intent\n * @param consult\n * @param oroClient\n * @returns the consult Uuid\n */\nexport async function getOrCreatePatientConsultationUuid(\n consult: ConsultRequest,\n oroClient: OroClient\n): Promise<Consult> {\n let payment = await oroClient.practiceClient.practiceGetPayment(\n consult.uuidPractice,\n consult.idStripeInvoiceOrPaymentIntent\n )\n if (payment && payment.uuidConsult) {\n return oroClient.consultClient.getConsultByUUID(payment.uuidConsult).catch((err) => {\n console.error('Error while retrieving consult', err)\n throw err\n })\n } else {\n return await oroClient.consultClient.consultCreate(consult).catch((err) => {\n console.error('Error while creating consult', err)\n throw err\n })\n }\n}\n","import {\n Consult,\n ConsultationImageMeta,\n ConsultationMeta,\n ConsultRequest,\n DocumentType,\n IdentityResponse,\n IndexKey,\n MedicalMeta,\n MedicalStatus,\n MetadataCategory,\n PersonalMeta,\n PopulatedWorkflowData,\n Practitioner,\n PreferenceMeta,\n RawConsultationMeta,\n Term,\n Terms,\n Uuid,\n VaultIndex,\n WorkflowData,\n} from 'oro-sdk-apis'\nimport {\n filterTriggeredAnsweredWithKind,\n getImagesFromIndexDb,\n getWorkflowDataByCategory,\n identificationToPersonalInformations,\n OroClient,\n RegisterPatientOutput,\n toActualObject,\n} from '..'\nimport { getOrCreatePatientConsultationUuid } from './consult'\n\nconst MAX_RETRIES = 15\n\n/**\n * Completes a registration for a user retrying the complete flow a maximum of 15 times\n *\n * @description The order of importance when registering:\n * Creates a consultation if none exist\n * Retrieves or create's a lockbox if none exist\n * Grants the lockbox (if new) to all practitioners in the practice\n * Stores or fetches the patient data (without images)\n * Indexes the lockbox to the consult for all practitioners (done after inserting since index can be rebuilt from grants)\n * Stores the image data - done last since the majority of failure cases occur here\n * Creates the recovery payloads if they don't exist\n *\n * @param patientUuid\n * @param consultRequest\n * @param workflow\n * @param oroClient\n * @param masterKey\n * @param recoveryQA\n * @param indexSearch create search index for the consultation if true\n * @param onProgress callback that is called whenever a new step of patient registration is executed. Note: progress ranges from 0 to 1, and descriptionKey is a description of the progress as a key so the app would use it to translate the description\n * @returns the successful registration\n */\nexport async function registerPatient(\n patientUuid: Uuid,\n consultRequest: ConsultRequest,\n workflow: WorkflowData,\n oroClient: OroClient,\n masterKey?: Uuid,\n recoveryQA?: {\n recoverySecurityQuestions: string[]\n recoverySecurityAnswers: string[]\n },\n indexSearch: boolean = true,\n onProgress?: (\n progress: number,\n descriptionKey: string,\n extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }\n ) => void\n): Promise<RegisterPatientOutput> {\n let consult: Consult | undefined = undefined\n let lockboxUuid: Uuid | undefined = undefined\n let practitionerAdmin: Uuid | undefined = undefined\n let retry = MAX_RETRIES\n let identity: IdentityResponse | undefined = undefined\n let errorsThrown: Error[] = []\n const stepsTotalNum = 9\n let currentStep: number\n\n for (; retry > 0; retry--) {\n try {\n currentStep = 0\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'retrieve_practitioners')\n\n // Wait a bit each retry (we also want the first one to wait)\n await new Promise((resolve) => setTimeout(resolve, 2000))\n\n // Retrieving practitioners\n if (!practitionerAdmin)\n practitionerAdmin = (await oroClient.practiceClient.practiceGetFromUuid(consultRequest.uuidPractice))\n .uuidAdmin\n\n let practitioners: Practitioner[] = await oroClient.practiceClient\n .practiceGetPractitioners(consultRequest.uuidPractice)\n .catch((err) => {\n console.log(`Error retrieving practitioners`, err)\n return []\n })\n\n // Creating consult\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_consult')\n\n if (!consult) {\n consult = await getOrCreatePatientConsultationUuid(consultRequest, oroClient)\n }\n\n // Creating lockbox\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_lockbox')\n\n if (!lockboxUuid) lockboxUuid = await getOrCreatePatientLockbox(oroClient)\n\n if (!identity) identity = await oroClient.guardClient.identityGet(patientUuid)\n\n await oroClient.grantLockbox(practitionerAdmin, lockboxUuid).catch((err) => {\n console.error(`Error while granting lockbox to practitioner admin ${practitionerAdmin}`, err)\n // if we cannot grant to the admin, then the registration will fail\n errorsThrown.push(err)\n })\n\n // Patient Grant to practice\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'grant_patient')\n\n let grantPromises = practitioners\n .filter((practitioner) => practitioner.uuid !== practitionerAdmin)\n .map(async (practitioner) => {\n return oroClient.grantLockbox(practitioner.uuid, lockboxUuid!).catch((err) => {\n console.error(`Error while granting lockbox to practitioner`, err)\n // Acceptable to continue as admin has already been granted, but we should still retry until the last retry remains\n if (retry <= 1) return\n errorsThrown.push(err)\n })\n })\n\n const consultIndex: VaultIndex = {\n [IndexKey.ConsultationLockbox]: [\n {\n grant: {\n lockboxUuid,\n lockboxOwnerUuid: patientUuid,\n },\n consultationId: consult.uuid,\n },\n ],\n }\n\n // the index will identify in which lockbox a consultation resides\n let consultIndexPromises = practitioners.map(async (practitioner) => {\n return oroClient.vaultIndexAdd(consultIndex, practitioner.uuid).catch((err) => {\n console.error(\n `[SDK: registration] Error while adding to the practitioner's index ${practitioner.uuid}`,\n err\n )\n // Acceptable to continue as the index can be rebuilt, but we should still retry until the last retry remains\n if (retry <= 1) return\n else errorsThrown.push(err)\n })\n })\n\n await storeImageAliases(\n consult.uuid,\n lockboxUuid,\n workflow,\n oroClient,\n onProgress\n ? {\n onProgress,\n currentStep,\n stepsTotalNum,\n }\n : undefined\n ).catch((err) => {\n console.error('[SDK: registration] Some errors happened during image upload', err)\n // Acceptable to continue as images can be requested during the consultation, but we should still retry until the last retry remains\n if (retry <= 1) return\n else errorsThrown.push(err)\n })\n ++currentStep\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'store_patient_data')\n\n await storePatientData(\n consult.uuid,\n consultRequest.isoLanguageRequired,\n lockboxUuid,\n workflow,\n oroClient\n ).catch((err) => {\n console.error('[SDK: registration] Some errors happened during patient data upload', err)\n errorsThrown.push(err)\n })\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'set_masterkey')\n\n if (masterKey && !identity?.recoveryMasterKey) {\n // generate and store recovery payload and updates the identity\n identity = await oroClient.updateMasterKey(patientUuid, masterKey, lockboxUuid).catch((err) => {\n console.error(`[SDK: registration] Error while updating master key`, err)\n /// it's acceptable to continue registration (return old identity)\n if (retry <= 1) return\n errorsThrown.push(err)\n return identity\n })\n } else {\n // we did not set the master key so we do not return it\n masterKey = undefined\n }\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'set_security_questions')\n\n if (recoveryQA && !identity?.recoverySecurityQuestions)\n // Patient security question recovery threshold is 2 answers and updates the identity\n identity = await oroClient\n .updateSecurityQuestions(\n patientUuid,\n recoveryQA.recoverySecurityQuestions,\n recoveryQA.recoverySecurityAnswers,\n 2\n )\n .catch((err) => {\n console.error(`[SDK: registration] Error while updating security questions`, err)\n /// it's acceptable to continue registration (return old identity)\n if (retry <= 1) return\n errorsThrown.push(err)\n return identity\n })\n\n await Promise.all([...grantPromises, ...consultIndexPromises])\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'search_indexing')\n\n if (indexSearch) {\n await buildConsultSearchIndex(consult, workflow, oroClient).catch((err) => {\n console.error(\n '[SDK: registration] personal information not found or another error occured during search indexing',\n err\n )\n if (retry <= 1) return // this statement is to avoid failing the registration due to the failure in search indexing the consult, this practically implements a soft retry\n errorsThrown.push(err)\n })\n }\n\n if (errorsThrown.length > 0) throw errorsThrown\n\n // Deem the consultation as ready\n await oroClient.consultClient.updateConsultByUUID(consult.uuid, {\n statusMedical: MedicalStatus.New,\n })\n\n // if we got through the complete flow, the registration succeeded\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'success')\n\n break\n } catch (err) {\n console.error(`[SDK] Error occured during registration: ${err}, retrying... Retries remaining: ${retry}`)\n errorsThrown = []\n continue\n }\n }\n\n if (retry <= 0) {\n console.error('[SDK] registration failed: MAX_RETRIES reached')\n throw 'RegistrationFailed'\n }\n\n console.log('Successfully Registered')\n await oroClient.cleanIndex()\n return {\n masterKey,\n consultationId: consult!.uuid,\n lockboxUuid: lockboxUuid!,\n }\n}\n\n/**\n * Creates a new lockbox for the patient if they do not have any, otherwise, use the first (and only one)\n * @param oroClient\n * @returns the lockbox Uuid\n */\nasync function getOrCreatePatientLockbox(oroClient: OroClient): Promise<Uuid> {\n let grants = await oroClient.getGrants()\n if (grants.length > 0) {\n console.log('The grant has already been created, skipping lockbox create step')\n return grants[0].lockboxUuid!\n } else {\n let lockboxResponse = await oroClient.vaultClient.lockboxCreate().catch((err) => {\n console.error('Error while creating lockbox', err)\n throw err\n })\n // Since the creation of a lockbox will change the scope of a user, we will force refresh the tokens\n let tokens = await oroClient.guardClient.authRefresh()\n await oroClient.guardClient.setTokens({ accessToken: tokens.accessToken, refreshToken: tokens.refreshToken })\n await oroClient.guardClient.whoAmI(true)\n\n return lockboxResponse.lockboxUuid\n }\n}\n\n/**\n * Store all patient related information into his/her lockbox\n * @param consultationId The consultation id\n * @param isoLanguage the prefered language of communication (ISO 639-3 https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes)\n * @param lockboxUuid the lockbox uuid to store data in\n * @param workflow the workflow used to extract informations\n * @param oroClient an oroClient instance\n * @returns\n */\nasync function storePatientData(\n consultationId: Uuid,\n isoLanguage: string,\n lockboxUuid: Uuid,\n workflow: WorkflowData,\n oroClient: OroClient\n): Promise<(Uuid | void)[]> {\n // Create and store registration data\n return Promise.all([\n // Storing Raw data first\n oroClient.getOrInsertJsonData<RawConsultationMeta>(\n lockboxUuid,\n workflow,\n {\n category: MetadataCategory.Raw,\n contentType: 'application/json',\n consultationId,\n },\n {}\n ),\n getWorkflowDataByCategory(workflow, MetadataCategory.Consultation).then((data) =>\n oroClient.getOrInsertJsonData<ConsultationMeta>(\n lockboxUuid,\n data,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationId, // TODO: deprecated. Will finally only be in privateMetadata\n },\n { consultationId },\n { withNotification: true, forceReplace: false, updateMedicalStatus: false }\n // the only data that needs to include an email notification\n )\n ),\n getWorkflowDataByCategory(workflow, MetadataCategory.Medical).then((data) =>\n oroClient.getOrInsertJsonData<MedicalMeta>(\n lockboxUuid,\n data,\n {\n category: MetadataCategory.Medical,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationIds: [consultationId!],\n },\n {}\n )\n ),\n extractAndStorePersonalWorkflowData(\n workflow,\n lockboxUuid,\n consultationId,\n MetadataCategory.Personal,\n oroClient\n ),\n extractAndStorePersonalWorkflowData(\n workflow,\n lockboxUuid,\n consultationId,\n MetadataCategory.ChildPersonal,\n oroClient\n ),\n extractAndStorePersonalWorkflowData(\n workflow,\n lockboxUuid,\n consultationId,\n MetadataCategory.OtherPersonal,\n oroClient\n ),\n oroClient.getOrInsertJsonData<PreferenceMeta>(\n lockboxUuid,\n { isoLanguage },\n {\n category: MetadataCategory.Preference,\n contentType: 'application/json',\n },\n {}\n ),\n ]).then((dataUuids) => dataUuids.flat())\n}\n\nasync function storeImageAliases(\n consultationId: Uuid,\n lockboxUuid: Uuid,\n workflow: WorkflowData,\n oroClient: OroClient,\n progress?: {\n currentStep: number\n stepsTotalNum: number\n onProgress: (\n progress: number,\n descriptionKey: string,\n extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }\n ) => void\n }\n): Promise<(Uuid | void)[]> {\n const images = await getImagesFromIndexDb((await filterTriggeredAnsweredWithKind(workflow, 'images-alias')).flat())\n\n const nonNullImages = images.filter((img) => !!img)\n\n if (images.length !== nonNullImages.length) {\n console.error('[SDK] Some images have not been found, they have been skipped.')\n }\n\n let storedImagesNum = 0\n let totalImagesNum = nonNullImages.length\n if (progress)\n progress.onProgress(progress.currentStep / progress.stepsTotalNum, 'store_images', {\n storedImagesNum,\n totalImagesNum,\n })\n\n let promises = nonNullImages.map((image) => {\n return oroClient\n .getOrInsertJsonData<ConsultationImageMeta>(\n lockboxUuid,\n image,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.ImageAlias,\n consultationId,\n idbId: image.idbId as string,\n },\n {}\n )\n .then(() => {\n if (progress) {\n ++storedImagesNum\n let progressStepValue =\n Math.round(\n ((progress.currentStep + 1) / progress.stepsTotalNum -\n progress.currentStep / progress.stepsTotalNum) *\n 100\n ) / 100\n progress.onProgress(\n progress.currentStep / progress.stepsTotalNum +\n progressStepValue * (storedImagesNum / totalImagesNum),\n 'store_images',\n {\n storedImagesNum,\n totalImagesNum,\n }\n )\n }\n })\n })\n return Promise.all(promises)\n}\n\n/**\n * Extracts the workflow MetadataCategory for Personal, ChildPersonal and OtherPersonal\n * then stores it in the vault\n *\n * @param workflow\n * @param lockboxUuid\n * @param category\n * @returns The data uuid\n */\nexport async function extractAndStorePersonalWorkflowData(\n workflow: WorkflowData,\n lockboxUuid: Uuid,\n consultationId: Uuid,\n category: MetadataCategory.Personal | MetadataCategory.ChildPersonal | MetadataCategory.OtherPersonal,\n oroClient: OroClient\n): Promise<Uuid | void> {\n return getWorkflowDataByCategory(workflow, category as unknown as MetadataCategory).then((data) => {\n if (Object.keys(data.fields).length === 0) return\n return oroClient.getOrInsertJsonData<PersonalMeta>(\n lockboxUuid,\n data,\n {\n category,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationIds: [consultationId],\n },\n {}\n )\n })\n}\n\n/**\n * Given workflow data, it populates it with Personal, ChildPersonal, and OtherPersonal workflow data\n * @param workflow\n */\nexport async function extractPersonalInfoFromWorkflowData(workflow: WorkflowData): Promise<{\n personalInfoPopulatedWfData: PopulatedWorkflowData\n childPersonalInfoPopulatedWfData: PopulatedWorkflowData\n otherPersonalInfoPopulatedWfData: PopulatedWorkflowData\n}> {\n return Promise.all([\n getWorkflowDataByCategory(workflow, MetadataCategory.Personal),\n getWorkflowDataByCategory(workflow, MetadataCategory.ChildPersonal),\n getWorkflowDataByCategory(workflow, MetadataCategory.OtherPersonal),\n ]).then(([personalInfoPopulatedWfData, childPersonalInfoPopulatedWfData, otherPersonalInfoPopulatedWfData]) => {\n return {\n personalInfoPopulatedWfData,\n childPersonalInfoPopulatedWfData,\n otherPersonalInfoPopulatedWfData,\n }\n })\n}\n\n/**\n * Creates the search index for the first name, last name, and the short id of the given consultation\n * @param consult the consultation to be search indexed\n * @param workflow the workflow data\n * @param oroClient\n */\nexport async function buildConsultSearchIndex(consult: Consult, workflow: WorkflowData, oroClient: OroClient) {\n let terms: Terms = [\n <Term>{\n kind: 'consult-shortid',\n value: consult.shortId,\n },\n ]\n\n const { personalInfoPopulatedWfData, childPersonalInfoPopulatedWfData, otherPersonalInfoPopulatedWfData } =\n await extractPersonalInfoFromWorkflowData(workflow)\n\n const personalInfo = identificationToPersonalInformations(\n toActualObject(personalInfoPopulatedWfData),\n MetadataCategory.Personal\n )\n const childPersonalInfo = identificationToPersonalInformations(\n toActualObject(childPersonalInfoPopulatedWfData),\n MetadataCategory.ChildPersonal\n )\n const otherPersonalInfo = identificationToPersonalInformations(\n toActualObject(otherPersonalInfoPopulatedWfData),\n MetadataCategory.OtherPersonal\n )\n\n terms.push(\n <Term>{\n kind: 'first-name',\n value: personalInfo.firstname,\n },\n <Term>{\n kind: 'last-name',\n value: personalInfo.name,\n }\n )\n\n if (childPersonalInfo.firstname && childPersonalInfo.name) {\n terms.push(\n <Term>{\n kind: 'first-name',\n value: childPersonalInfo.firstname,\n },\n <Term>{\n kind: 'last-name',\n value: childPersonalInfo.name,\n }\n )\n }\n\n if (otherPersonalInfo.firstname && otherPersonalInfo.name) {\n terms.push(\n <Term>{\n kind: 'first-name',\n value: otherPersonalInfo.firstname,\n },\n <Term>{\n kind: 'last-name',\n value: otherPersonalInfo.name,\n }\n )\n }\n\n await oroClient.searchClient.index(consult.uuid, terms)\n}\n","import { CryptoRSA, uuidParse} from \"oro-toolbox\"\nimport { EncryptedIndexEntry, Grant, IndexConsultLockbox } from \"oro-sdk-apis\"\n\n/**\n * Decrypts and returns the encrypted grants\n * If something went wrong during decryption, that grant will be removed from the list\n *\n * @param encryptedGrants: an array of encrypted grants\n * @param rsaKey: the rsa key used to decrypt the encrypted grants\n * @returns an array of grants\n */\nexport function decryptGrants(encryptedGrants: Grant[], rsaKey: CryptoRSA): Grant[] {\n return encryptedGrants\n .map(grant => {\n if (grant.encryptedLockbox && !grant.lockboxUuid) {\n try {\n grant.lockboxUuid = uuidParse(\n rsaKey.base64DecryptToBytes(grant.encryptedLockbox)\n )\n } catch (e) {\n console.error('[sdk:index] The grant could not be decrypted or was not a valid UUID: ', e)\n }\n }\n return grant\n })\n .filter(grant => grant.lockboxUuid)\n}\n\n/**\n * Decrypts the encrypted consult lockboxes and returns their grants\n * If something went wrong during decryption, that grant will be removed from the list\n *\n * @param encryptedConsultLockboxes: an array of encrypted entries\n * @param rsaKey: the rsa key used to decrypt the encrypted entries\n * @returns an array of grants\n */\nexport function decryptConsultLockboxGrants(encryptedConsultLockboxes: EncryptedIndexEntry[], rsaKey: CryptoRSA): Grant[] {\n return encryptedConsultLockboxes\n .map(encryptedConsultLockboxes => {\n try {\n return [true, (rsaKey.base64DecryptToJson(\n encryptedConsultLockboxes.encryptedIndexEntry\n ) as IndexConsultLockbox).grant]\n } catch(e) {\n console.error('[sdk:index] The consult lockbox grant could not be decrypted: ', e)\n return [false, undefined] // if decryption fails, we want to ignore the grant but not fail the call\n }\n })\n .filter(grantsTuple => grantsTuple[0])\n .map(grantTuples => grantTuples[1] as Grant)\n}","import {\n Consult,\n ConsultRequest,\n DocumentType,\n MedicalStatus,\n MetadataCategory,\n PlaceData,\n SelectedAnswersData,\n Uuid,\n WorkflowData,\n} from 'oro-sdk-apis'\nimport { buildConsultSearchIndex, OroClient } from '..'\nimport { getOrCreatePatientConsultationUuid } from './consult'\n\nconst MAX_RETRIES = 15\n/**\n * Placeholder while the workflow interpreter for the refill flows is complete\n *\n * Creates a fake workflow in which the workflow data will reside\n *\n * @todo deprecate this function when using workflows and populating them from the app\n *\n * @param isTreatmentWorking the value from the `is treatment working` question\n * @param hasSideEffects the value from the `does the treatment have side effects` question\n * @param deliveryAddress the provided delivery address\n * @param pharmacy\n * @returns a workflow\n */\nexport function getRefillAnswersAsWorkflow(\n isTreatmentWorking: string,\n hasSideEffects: string,\n deliveryAddress?: string,\n pharmacy?: PlaceData\n): WorkflowData {\n let selectedAnswers: SelectedAnswersData = [\n {\n ['isTreatmentWorking']: isTreatmentWorking,\n ['hasSideEffects']: hasSideEffects,\n },\n ]\n\n // appends the delivery address to the first page of the answers if provided\n if (deliveryAddress) selectedAnswers[0] = { ...selectedAnswers[0], ['deliveryAddress']: deliveryAddress }\n\n // appends the pharmacy to the first page of the answers if provided\n if (pharmacy) selectedAnswers[0] = { ...selectedAnswers[0], ['pharmacy']: JSON.stringify(pharmacy) }\n\n return {\n id: '32573a20-6f1d-49be-9ad3-b87c58074979',\n createdAt: '2022-10-03T00:00:00.000Z',\n culDeSacs: [],\n hidePlanRules: [],\n pages: [\n {\n title: 'Prescription Refill',\n groups: [\n {\n type: 'field-group',\n fieldsAndGroups: [\n {\n type: 'field',\n id: 'isTreatmentWorking',\n },\n {\n type: 'field',\n id: 'hasSideEffects',\n },\n {\n type: 'field',\n id: 'youPharmacy',\n },\n {\n type: 'field',\n id: 'youAddress',\n },\n ],\n },\n ],\n questions: {\n isTreatmentWorking: {\n label: 'Is the treatment working for you?',\n kind: 'radio',\n inline: true,\n inlineLabel: false,\n metaCategory: MetadataCategory.Refill,\n answers: {\n '73bec6eb-0310-4787-af3c-ac9c291737b2': {\n text: 'Yes',\n },\n 'e193951f-986f-4db3-bede-903045a1804a': {\n text: 'No',\n },\n },\n },\n hasSideEffects: {\n label: 'Are there any side effects',\n kind: 'radio',\n inline: true,\n inlineLabel: false,\n metaCategory: MetadataCategory.Refill,\n answers: {\n '1b87ad22-d316-4fac-9c7f-8f4ccb841aed': {\n text: 'Yes',\n },\n 'ab7f5a41-c351-4f5d-a568-e38f9f200e9a': {\n text: 'No',\n },\n },\n },\n youPharmacy: {\n kind: 'online-pharmacy-picker',\n label: 'Which pharmacy do you want the prescription sent to?',\n metaCategory: MetadataCategory.Refill,\n summaryLabel: 'Your pharmacy',\n },\n youAddress: {\n kind: 'place-address',\n label: 'Address',\n metaCategory: MetadataCategory.Refill,\n },\n },\n },\n ],\n locale: 'en',\n selectedAnswers,\n }\n}\n\n/**\n * Complete refill flow, creates a consult, stores refill data and updates consultation status\n * @param consultRequest\n * @param populatedRefillWorkflow the refill workflow data\n * @param oroClient\n */\nexport async function createRefill(\n consultRequest: ConsultRequest,\n populatedRefillWorkflow: WorkflowData,\n oroClient: OroClient,\n indexSearch: boolean = true,\n onProgress?: (\n progress: number,\n descriptionKey: string,\n extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }\n ) => void\n): Promise<Consult> {\n let retry = MAX_RETRIES\n let errorsThrown: Error[] = []\n let newConsult: Consult | undefined = undefined\n let lockboxUuid: Uuid | undefined\n const stepsTotalNum = 6\n let currentStep: number\n\n for (; retry > 0; retry--) {\n try {\n currentStep = 0\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_consult')\n // Creating refill consult\n newConsult = await getOrCreatePatientConsultationUuid(consultRequest, oroClient)\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'get_patient_grant')\n if (!lockboxUuid) lockboxUuid = (await oroClient.getGrants())[0].lockboxUuid\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'store_patient_data')\n await oroClient\n .getOrInsertJsonData(\n lockboxUuid!,\n populatedRefillWorkflow,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationId: newConsult.uuid,\n },\n {},\n { withNotification: true, forceReplace: false, updateMedicalStatus: true }\n )\n .catch((err) => {\n console.error(\n '[SDK: prescription refill request] Some errors happened during refill data upload',\n err\n )\n errorsThrown.push(err)\n })\n\n if (indexSearch) {\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'fetching_parent_workflow_data')\n // raw workflow from parent consultation (contains first and last name of patient)\n let rawConsultationManifest = await oroClient.getLockboxManifest(\n lockboxUuid!,\n { category: MetadataCategory.Raw, consultationId: consultRequest.uuidParent },\n false\n )\n if (rawConsultationManifest && rawConsultationManifest.length > 0) {\n let rawConsultation = await oroClient.getJsonData<WorkflowData>(\n lockboxUuid!,\n rawConsultationManifest[0].dataUuid\n )\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'search_indexing')\n await buildConsultSearchIndex(newConsult, rawConsultation, oroClient).catch((err) => {\n console.error(\n '[SDK: prescription refill request] personal information not found or another error occured during search indexing',\n err\n )\n if (retry <= 1) return // this statement is to avoid failing the registration due to the failure in search indexing the consult, this practically implements a soft retry\n errorsThrown.push(err)\n })\n } else {\n console.error(\"[SDK: prescription refill request] parent consultation's raw data not found\")\n errorsThrown.push(Error('RawData Not Found'))\n }\n }\n\n if (errorsThrown.length > 0) throw errorsThrown\n\n // Deem the consultation as ready\n await oroClient.consultClient.updateConsultByUUID(newConsult.uuid, {\n statusMedical: MedicalStatus.New,\n })\n\n // if we got through the complete flow, the registration succeeded\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'success')\n\n await oroClient.cleanIndex()\n break\n } catch (err) {\n console.error(\n `[SDK] Error occured during prescription refill request: ${err}, retrying... Retries remaining: ${retry}`\n )\n errorsThrown = []\n continue\n }\n }\n if (retry <= 0) {\n console.error('[SDK] prescription refill request failed: MAX_RETRIES reached')\n throw 'RegistrationFailed'\n }\n\n if (!newConsult) {\n console.error('[SDK] prescription refill request failed: MAX_RETRIES reached')\n throw 'RegistrationFailed'\n }\n\n console.log('Successfully Created refill')\n return newConsult\n}\n","import { IndexKey, Grant, IndexConsultLockbox, MetadataCategory, VaultIndex } from 'oro-sdk-apis'\nimport { OroClient, Uuid } from '..'\n\n/**\n * @name filterGrantsWithLockboxMetadata\n * @description searches for the existance of a consult uuid in each granted lockbox\n * @param oroClient\n * @param filter: the consult uuid\n * @returns the grants containing the consult uuid\n */\nexport async function filterGrantsWithLockboxMetadata(\n oroClient: OroClient,\n filter: { consultationId: Uuid },\n): Promise<Grant[]> {\n let grants = await oroClient.getGrants()\n let filteredGrants = []\n for (let grant of grants) {\n // Fetches in each lockbox the existance of a given consult id\n let consultationIdExistsInMetadata = await oroClient.vaultClient.lockboxMetadataGet(grant.lockboxUuid!, ['consultationId'], [], {\n category: MetadataCategory.Consultation,\n consultationId: filter.consultationId\n })\n // If there are entries in the metadata, it means that the consult exists in the lockbox\n if (consultationIdExistsInMetadata[0].length >= 0)\n filteredGrants.push(grant)\n }\n\n return filteredGrants\n}\n","import {\n AllRoleType,\n AuthTokenRequest,\n Consult,\n ConsultRequest,\n ConsultService,\n DataCreateResponse,\n DiagnosisService,\n Document,\n DocumentType,\n EncryptedIndexEntry,\n EncryptedVaultIndex,\n Grant,\n GuardService,\n IdentityCreateRequest,\n IdentityResponse,\n IndexConsultLockbox,\n IndexKey,\n LocalizedData,\n LockboxDataRequest,\n LockboxGrantRequest,\n LockboxManifest,\n ManifestEntry,\n Meta,\n Metadata,\n MetadataCategory,\n OtherRoleType,\n PersonalMeta,\n PopulatedWorkflowData,\n Practice,\n PracticeService,\n PractitionnerRoleType,\n PreferenceMeta,\n RecoveryMeta,\n RoleBasedScopes,\n SearchService,\n SecretShard,\n SubscriptionAcceptanceRequest,\n TellerService,\n TokenData,\n TosAndCpAcceptanceRequest,\n Uuid,\n VaultIndex,\n VaultService,\n WorkflowData,\n WorkflowService,\n} from 'oro-sdk-apis'\nimport * as OroToolbox from 'oro-toolbox'\nimport { CryptoRSA } from 'oro-toolbox'\nimport {\n createRefill,\n decryptConsultLockboxGrants,\n decryptGrants,\n registerPatient,\n sessionStorePrivateKeyName,\n} from './helpers'\nimport {\n AssociatedLockboxNotFound,\n IncompleteAuthentication,\n LocalEncryptedData,\n MissingGrant,\n MissingGrantFilter,\n MissingLockbox,\n MissingLockboxOwner,\n RecoveryData,\n RegisterPatientOutput,\n UserPreference,\n} from './models'\nimport { filterGrantsWithLockboxMetadata } from './sdk-revision'\n\nexport class OroClient {\n private rsa?: CryptoRSA\n private secrets: {\n lockboxUuid: string\n cryptor: OroToolbox.CryptoChaCha\n }[] = []\n private cachedMetadataGrants: {\n [filter: string]: Grant[]\n } = {}\n\n private cachedManifest: {\n [filter: string]: ManifestEntry[]\n } = {}\n\n private vaultIndex?: VaultIndex\n\n constructor(\n private toolbox: typeof OroToolbox,\n public tellerClient: TellerService,\n public vaultClient: VaultService,\n public guardClient: GuardService,\n public searchClient: SearchService,\n public practiceClient: PracticeService,\n public consultClient: ConsultService,\n public workflowClient: WorkflowService,\n public diagnosisClient: DiagnosisService,\n private authenticationCallback?: (err: Error) => void\n ) {}\n\n /**\n * clears the vaultIndex and cached metadata grants\n */\n public async cleanIndex() {\n this.cachedMetadataGrants = {}\n this.cachedManifest = {}\n }\n\n /**\n * Generates an RSA key pair and password payload (rsa private key encrypted with the password)\n * Calls Guard to sign up with the email address, password, practice, legal and token data\n *\n * @param email\n * @param password\n * @param practice\n * @param legal\n * @param tokenData\n * @returns\n */\n public async signUp(\n email: string,\n password: string,\n practice: Practice,\n tosAndCpAcceptance: TosAndCpAcceptanceRequest,\n tokenData?: TokenData,\n subscription?: boolean,\n skipEmailValidation?: boolean\n ): Promise<IdentityResponse> {\n this.rsa = new CryptoRSA()\n const privateKey = this.rsa.private()\n\n const symmetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(password)\n const recoveryPassword = symmetricEncryptor.bytesEncryptToBase64Payload(privateKey)\n\n const hashedPassword = this.toolbox.hashStringToBase64(this.toolbox.hashStringToBase64(password))\n\n email = email.toLowerCase()\n const emailConfirmed = !!skipEmailValidation\n const subscriptionAcceptance = subscription ? ({ email } as SubscriptionAcceptanceRequest) : undefined\n\n const signupRequest: IdentityCreateRequest = {\n practiceUuid: practice.uuid,\n email,\n emailConfirmed,\n password: hashedPassword,\n publicKey: this.toolbox.encodeToBase64(this.rsa.public()),\n recoveryPassword,\n tosAndCpAcceptance,\n tokenData,\n subscriptionAcceptance,\n }\n\n const identity = await this.guardClient.identityCreate(signupRequest)\n\n if (identity.recoveryLogin) {\n //Ensure we can recover from a page reload\n let symetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(identity.recoveryLogin)\n sessionStorage.setItem(\n sessionStorePrivateKeyName(identity.id),\n symetricEncryptor.bytesEncryptToBase64Payload(privateKey)\n )\n }\n\n return identity\n }\n\n /**\n * Parse the given accessToken claims by calling guard whoami and update theidentity to set it's emailConfirmed flag\n * @param accessToken\n * @returns The identity related to confirmedEmail\n */\n public async confirmEmail(accessToken: string): Promise<IdentityResponse> {\n this.guardClient.setTokens({ accessToken })\n const claims = await this.guardClient.whoAmI()\n return this.guardClient.identityUpdate(claims.sub, {\n emailConfirmed: true,\n })\n }\n\n /**\n * Calls Guard to sign in with the email address, password and one time password (if MFA is enabled)\n * Then recover's the rsa private key from the recovery payload\n *\n * @param practiceUuid\n * @param email\n * @param password\n * @param otp\n * @returns the user identity\n */\n public async signIn(practiceUuid: Uuid, email: string, password: string, otp?: string): Promise<IdentityResponse> {\n const hashedPassword = this.toolbox.hashStringToBase64(this.toolbox.hashStringToBase64(password))\n const tokenRequest: AuthTokenRequest = {\n practiceUuid,\n email: email.toLowerCase(),\n password: hashedPassword,\n otp,\n }\n\n await this.guardClient.authToken(tokenRequest)\n const userUuid = (await this.guardClient.whoAmI()).sub\n\n // Updates the rsa key to the one generated on the backend\n await this.recoverPrivateKeyFromPassword(userUuid, password)\n return await this.guardClient.identityGet(userUuid)\n }\n\n /**\n * Will attempt to recover an existing login session and set back\n * the private key in scope\n */\n public async resumeSession() {\n const id = (await this.guardClient.whoAmI()).sub\n const recoveryPayload = sessionStorage.getItem(sessionStorePrivateKeyName(id))\n const recoveryKey = (await this.guardClient.identityGet(id)).recoveryLogin\n\n if (!recoveryKey || !recoveryPayload) throw IncompleteAuthentication\n\n const symmetricDecryptor = this.toolbox.CryptoChaCha.fromPassphrase(recoveryKey)\n let privateKey = symmetricDecryptor.base64PayloadDecryptToBytes(recoveryPayload)\n this.rsa = this.toolbox.CryptoRSA.fromKey(privateKey)\n }\n\n /**\n * This function let's you encrypt locally an Object\n * @param value the Object to encrypt\n * @returns a LocalEncryptedData Object\n * @throws IncompleteAuthentication if rsa is not set\n * @calls authenticationCallback if rsa is not set\n */\n public localEncryptToJsonPayload(value: any): LocalEncryptedData {\n if (!this.rsa) {\n if (this.authenticationCallback) {\n this.authenticationCallback(new IncompleteAuthentication())\n }\n\n throw new IncompleteAuthentication()\n }\n\n const chaChaKey = new this.toolbox.CryptoChaCha()\n\n const encryptedData = chaChaKey.jsonEncryptToBase64Payload(value)\n const encryptedKey = this.toolbox.encodeToBase64(this.rsa.encryptToBytes(chaChaKey.key()))\n\n return { encryptedData, encryptedKey }\n }\n\n /**\n * This function let's you decrypt a LocalEncryptedData object\n * @param value a LocalEncryptedData object\n * @returns a decrypted Object\n * @throws IncompleteAuthentication if rsa is not set\n * @calls authenticationCallback if rsa is not set\n */\n public localDecryptJsonPayload({ encryptedKey, encryptedData }: LocalEncryptedData): any {\n if (!this.rsa) {\n if (this.authenticationCallback) {\n this.authenticationCallback(new IncompleteAuthentication())\n }\n\n throw new IncompleteAuthentication()\n }\n\n const chaChaKey = this.rsa.base64DecryptToBytes(encryptedKey)\n const decryptedData = this.toolbox.CryptoChaCha.fromKey(chaChaKey).base64PayloadDecryptToJson(encryptedData)\n\n return decryptedData\n }\n\n /**\n * Effectively kills your \"session\"\n */\n public async signOut() {\n this.rsa = undefined\n this.secrets = []\n this.guardClient.setTokens({\n accessToken: undefined,\n refreshToken: undefined,\n })\n await this.guardClient.authLogout()\n }\n\n /**\n * @name registerPatient\n * @description The complete flow to register a patient\n *\n * Steps:\n * 1. Create a consult (checks if payment has been done)\n * 2. Creates a lockbox\n * 3. Grants lockbox access to all practice personnel\n * 4. Creates secure identification, medical, onboarding data\n * 5. Generates and stores the rsa key pair and recovery payloads\n *\n * @param patientUuid\n * @param consult\n * @param workflow\n * @param recoveryQA\n * @param indexSearch create search index for the consultation if true\n * @param onProgress callback that is called whenever a new step of patient registration is executed. Note: progress ranges from 0 to 1, and descriptionKey is a description of the progress as a key so the app would use it to translate the description\n * @returns\n */\n public async registerPatient(\n patientUuid: Uuid,\n consult: ConsultRequest,\n workflow: WorkflowData,\n recoveryQA?: {\n recoverySecurityQuestions: string[]\n recoverySecurityAnswers: string[]\n },\n indexSearch: boolean = true,\n onProgress?: (progress: number, descriptionKey: string) => void\n ): Promise<RegisterPatientOutput> {\n if (!this.rsa) throw IncompleteAuthentication\n return registerPatient(\n patientUuid,\n consult,\n workflow,\n this,\n this.toolbox.uuid(),\n recoveryQA,\n indexSearch,\n onProgress\n )\n }\n\n /**\n * Creates and stores all relevant refill data\n * - New consultation is created\n * - Stores refill workflow data in the lockbox\n * - Updates the consult to new\n *\n * @param consult\n * @param populatedRefillWorkflow\n * @returns\n */\n public async createRefill(\n consult: ConsultRequest,\n populatedRefillWorkflow: WorkflowData,\n indexSearch: boolean = true,\n onProgress?: (progress: number, descriptionKey: string) => void\n ): Promise<Consult> {\n if (!this.rsa) throw IncompleteAuthentication\n return createRefill(consult, populatedRefillWorkflow, this, indexSearch, onProgress)\n }\n\n /**\n * Fetches all grants, and consultations that exist in each lockbox\n * Then updates the index for the current user with the lockbox consult relationship\n */\n public async forceUpdateIndexEntries() {\n let grants = await this.getGrants()\n\n let indexConsultLockbox: IndexConsultLockbox[] = await Promise.all(\n grants.map(\n async (grant: Grant) =>\n await this.vaultClient\n .lockboxMetadataGet(\n grant.lockboxUuid!,\n ['consultationId'],\n [],\n { category: MetadataCategory.Consultation },\n grant.lockboxOwnerUuid\n )\n .then((consults) => {\n try {\n return consults[0].map((consult: any) => {\n return {\n ...consult,\n grant: {\n lockboxOwnerUuid: grant.lockboxOwnerUuid,\n lockboxUuid: grant.lockboxUuid,\n },\n }\n })\n } catch (e) {\n // No consultations in lockbox or index could not be created\n return []\n }\n })\n .catch(() => [])\n )\n ).then((consults) => consults.flat())\n this.vaultIndexAdd({\n [IndexKey.Consultation]: indexConsultLockbox,\n })\n .then(() => alert('The Index was successfully updated!'))\n .catch(() => console.error('The index failed to update!'))\n }\n\n /**\n * Generates, encrypts and adds entries to vault index for a given index owner\n *\n * @param entries\n * @param indexOwnerUuid\n */\n public async vaultIndexAdd(entries: VaultIndex, indexOwnerUuid?: Uuid) {\n if (!this.rsa) throw IncompleteAuthentication\n\n let rsaPub: Uint8Array\n if (indexOwnerUuid) {\n let base64IndexOwnerPubKey = (await this.guardClient.identityGet(indexOwnerUuid)).publicKey\n rsaPub = this.toolbox.decodeFromBase64(base64IndexOwnerPubKey)\n } else {\n rsaPub = this.rsa.public()\n }\n\n let encryptedIndex: EncryptedVaultIndex = {}\n\n for (let keyString of Object.keys(entries)) {\n let key = keyString as keyof VaultIndex\n switch (key) {\n case IndexKey.ConsultationLockbox:\n encryptedIndex[key] = (entries[key] as IndexConsultLockbox[])\n .map((e) => ({\n ...e,\n uniqueHash: e.consultationId,\n }))\n .map(\n (e: IndexConsultLockbox) =>\n ({\n uuid: e.uuid,\n timestamp: e.timestamp,\n uniqueHash: e.uniqueHash,\n encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(\n {\n consultationId: e.consultationId,\n grant: e.grant,\n },\n rsaPub\n ),\n } as EncryptedIndexEntry)\n )\n break\n }\n }\n await this.vaultClient.vaultIndexPut(encryptedIndex, indexOwnerUuid)\n }\n\n /**\n * @name grantLockbox\n * @description Grants a lockbox by retrieving the shared secret of the lockbox and encrypting it with the grantees public key\n * @param granteeUuid\n * @param lockboxUuid\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n */\n public async grantLockbox(granteeUuid: Uuid, lockboxUuid: Uuid, lockboxOwnerUuid?: Uuid) {\n if (!this.rsa) throw IncompleteAuthentication\n\n let secret = (await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)).key()\n let base64GranteePublicKey = (await this.guardClient.identityGet(granteeUuid)).publicKey\n let granteePublicKey = this.toolbox.decodeFromBase64(base64GranteePublicKey)\n\n let granteeEncryptedSecret = CryptoRSA.bytesWithPubEncryptToBase64(secret, granteePublicKey)\n let request: LockboxGrantRequest = {\n encryptedSecret: granteeEncryptedSecret,\n granteeUuid: granteeUuid,\n }\n await this.vaultClient.lockboxGrant(lockboxUuid, request, lockboxOwnerUuid)\n }\n\n /**\n * @name createMessageData\n * @description Creates a Base64 encrypted Payload to send and store in the vault from a message string\n * @param lockboxUuid\n * @param message\n * @param consultationId the consultation for which this message is sent\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing file, specify the previous data uuid\n * @returns the data uuid\n */\n public async createMessageData(\n lockboxUuid: Uuid,\n message: string,\n consultationId: string,\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { updateMedicalStatus: boolean } = { updateMedicalStatus: true }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)\n\n let encryptedData = symmetricEncryptor.jsonEncryptToBase64Payload(message)\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload({\n author: (await this.guardClient.whoAmI()).sub,\n })\n\n let meta = {\n consultationId,\n category: MetadataCategory.Consultation,\n documentType: DocumentType.Message,\n contentType: 'text/plain',\n }\n\n let request: LockboxDataRequest = {\n data: encryptedData,\n publicMetadata: meta,\n privateMetadata: encryptedPrivateMeta,\n }\n\n return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid, options)\n }\n\n /**\n * @name createMessageAttachmentData\n * @description Creates a Base64 encrypted Payload to send and store in the vault from a file\n * @param lockboxUuid\n * @param data the file stored\n * @param consultationId the consultation for which this message is sent\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing file, specify the previous data uuid\n * @returns the data uuid\n */\n public async createMessageAttachmentData(\n lockboxUuid: Uuid,\n data: File,\n consultationId: string,\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { updateMedicalStatus: boolean } = { updateMedicalStatus: true }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)\n let encryptedData = symmetricEncryptor.bytesEncryptToBase64Payload(new Uint8Array(await data.arrayBuffer()))\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload({\n author: (await this.guardClient.whoAmI()).sub,\n fileName: data.name,\n lastModified: data.lastModified,\n size: data.size,\n })\n\n let meta = {\n consultationId,\n category: MetadataCategory.Consultation,\n documentType: DocumentType.Message,\n contentType: data.type,\n }\n\n let request: LockboxDataRequest = {\n data: encryptedData,\n publicMetadata: meta,\n privateMetadata: encryptedPrivateMeta,\n }\n\n return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid, options)\n }\n\n /**\n * @name createAttachmentData\n * @description Creates a Base64 encrypted Payload to send and store in the vault from a file\n * @param lockboxUuid\n * @param data the file stored\n * @param consultationId the consultation for which this message is sent\n * @param category the category for the attachment data\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing file, specify the previous data uuid\n * @param withNotification if the insertion of data requires notification\n * @returns the data uuid\n */\n public async createConsultationAttachmentData(\n lockboxUuid: Uuid,\n data: File,\n consultationId: string,\n documentType: DocumentType,\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { withNotification: boolean; updateMedicalStatus: boolean } = {\n withNotification: false,\n updateMedicalStatus: false,\n }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n\n return this.createBytesData<Meta | any>(\n lockboxUuid,\n new Uint8Array(await data.arrayBuffer()),\n {\n consultationId,\n category: MetadataCategory.Consultation,\n documentType,\n contentType: data.type,\n },\n {\n author: (await this.guardClient.whoAmI()).sub,\n fileName: data.name,\n },\n lockboxOwnerUuid,\n previousDataUuid,\n options\n )\n }\n\n /**\n * @name createJsonData\n * @description Creates a Base64 encrypted Payload to send and store in the vault. With the data input as a JSON\n * @param lockboxUuid\n * @param data\n * @param meta\n * @param privateMeta the metadata that will be secured in the vault\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing data, specify the previous data uuid\n * @param options if the insertion of data requires email notification\n * @returns the data uuid\n */\n public async createJsonData<T extends Metadata>(\n lockboxUuid: Uuid,\n data: any,\n meta?: T,\n privateMeta?: { [val: string]: any },\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { withNotification: boolean; updateMedicalStatus: boolean } = {\n withNotification: false,\n updateMedicalStatus: false,\n }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)\n let encryptedData = symmetricEncryptor.jsonEncryptToBase64Payload(data)\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload(privateMeta)\n\n let request: LockboxDataRequest = {\n data: encryptedData,\n publicMetadata: meta,\n privateMetadata: encryptedPrivateMeta,\n }\n if (options.withNotification)\n return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid, options)\n else return this.vaultClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)\n }\n\n /**\n * Get or upsert a data in lockbox\n * @param lockboxUuid the lockbox uuid\n * @param data the data to insert\n * @param publicMetadata the public Metadata\n * @param privateMetadata the private Metadata\n * @param forceReplace set true when the insertion of data requires to replace the data when it exists already\n * @param options if the insertion of data requires email notification\n * @returns the data uuid\n */\n public async getOrInsertJsonData<M extends Metadata>(\n lockboxUuid: Uuid,\n data: any,\n publicMetadata: M,\n privateMetadata: Metadata,\n options: { withNotification: boolean; forceReplace: boolean; updateMedicalStatus: boolean } = {\n withNotification: false,\n forceReplace: false,\n updateMedicalStatus: false,\n }\n ): Promise<Uuid> {\n let manifest = await this.vaultClient.lockboxManifestGet(lockboxUuid, publicMetadata)\n if (!options.forceReplace && manifest.length > 0) {\n console.log(`The data for ${JSON.stringify(publicMetadata)} already exist`)\n return manifest[0].dataUuid\n } else\n return (\n await this.createJsonData<M>(\n lockboxUuid,\n data,\n publicMetadata,\n privateMetadata,\n undefined,\n // if forceReplace and data already exist, then replace data. Otherwise insert it\n options.forceReplace && manifest.length > 0 ? manifest[0].dataUuid : undefined,\n options\n ).catch((err) => {\n console.error(`Error while upserting data ${JSON.stringify(publicMetadata)} data`, err)\n throw err\n })\n ).dataUuid\n }\n\n /**\n * @name createBytesData\n * @description Creates a Base64 encrypted Payload to send and store in the vault. With the data input as a Bytes\n * @param lockboxUuid\n * @param data\n * @param meta\n * @param privateMeta the metadata that will be secured in the vault\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @param previousDataUuid if it's a revision of existing data, specify the previous data uuid\n * @param withNotification if the insertion of data requires notification\n * @returns the data uuid\n */\n public async createBytesData<T extends Metadata>(\n lockboxUuid: Uuid,\n data: Uint8Array,\n meta: T,\n privateMeta: { [val: string]: any },\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid,\n options: { withNotification: boolean; updateMedicalStatus: boolean } = {\n withNotification: false,\n updateMedicalStatus: false,\n }\n ): Promise<DataCreateResponse> {\n if (!this.rsa) throw IncompleteAuthentication\n let symmetricEncryptor = await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)\n let encryptedData = symmetricEncryptor.bytesEncryptToBase64Payload(data)\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload(privateMeta)\n\n let request: LockboxDataRequest = {\n data: encryptedData,\n publicMetadata: meta,\n privateMetadata: encryptedPrivateMeta,\n }\n if (options.withNotification)\n return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid, options)\n else return this.vaultClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)\n }\n\n /**\n * @name getJsonData\n * @description Fetches and decrypts the lockbox data with the cached shared secret.\n * Decrypts the data to a valid JSON object. If this is impossible, the call to the WASM binary will fail\n *\n * @type T is the generic type specifying the return type object of the function\n * @param lockboxUuid\n * @param dataUuid\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @returns the data specified by the generic type <T>\n */\n public async getJsonData<T = any>(lockboxUuid: Uuid, dataUuid: Uuid, lockboxOwnerUuid?: Uuid): Promise<T> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let [encryptedPayload, symmetricDecryptor] = await Promise.all([\n this.vaultClient.lockboxDataGet(lockboxUuid, dataUuid, lockboxOwnerUuid),\n this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid),\n ])\n\n return symmetricDecryptor.base64PayloadDecryptToJson(encryptedPayload.data)\n }\n /**\n * @description Fetches and decrypts the lockbox data with the cached shared secret.\n * @param lockboxUuid\n * @param dataUuid\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @returns the bytes data\n */\n public async getBytesData(lockboxUuid: Uuid, dataUuid: Uuid, lockboxOwnerUuid?: Uuid): Promise<Uint8Array> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let [encryptedPayload, symmetricDecryptor] = await Promise.all([\n this.vaultClient.lockboxDataGet(lockboxUuid, dataUuid, lockboxOwnerUuid),\n this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid),\n ])\n\n return symmetricDecryptor.base64PayloadDecryptToBytes(encryptedPayload.data)\n }\n\n /**\n * @name getGrants\n * @description Get all lockboxes granted to user with the applied filter\n * @note this function returns cached grants and will not update unless the page is refreshed\n * @todo some versions of lockboxes do not make use of lockbox metadata\n * in this case, all lockboxes need to be filtered one-by-one to find the correct one\n * Remove if this is no longer the case\n * @param filter: the consultationId in which the grant exists\n * @returns decrypted lockboxes granted to user\n */\n public async getGrants(filter?: { consultationId: Uuid }): Promise<Grant[]> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let filterString = JSON.stringify(filter)\n // retrieves cached grants\n if (this.cachedMetadataGrants[filterString]) return this.cachedMetadataGrants[filterString]\n\n // We're using the account role to determine the way a grant is accessed\n let currentAccountRole = await this.getAccountRole()\n if (currentAccountRole.length === 1 && currentAccountRole[0] === OtherRoleType.User) return []\n\n if (\n [OtherRoleType.Patient, OtherRoleType.User].every((requiredRole) =>\n currentAccountRole.includes(requiredRole)\n )\n ) {\n let encryptedGrants\n // if there are no grants with the applied filter from index, attempt for naive filter with backwards compatibility\n if (filter) {\n encryptedGrants = await filterGrantsWithLockboxMetadata(this, filter)\n } else {\n encryptedGrants = (await this.vaultClient.grantsGet()).grants\n }\n const decryptedGrants = await decryptGrants(encryptedGrants, this.rsa)\n // sets the cached grant\n this.cachedMetadataGrants[filterString] = decryptedGrants\n console.info('[sdk:grant] Found grant for patient')\n return decryptedGrants\n }\n // if not a patient, then a practitioner is trying to retrieve a grant, it **Must** contain a filter, otherwise too many grants are possible\n if (!filter) throw MissingGrantFilter\n // Note: will work only if the filter being applied is exclusively a consult id\n const grantsByConsultLockbox = await this.vaultClient\n .vaultIndexGet([IndexKey.ConsultationLockbox], [filter.consultationId])\n .then((res) => res[IndexKey.ConsultationLockbox])\n .catch((e) => {\n console.error(e)\n return []\n })\n\n const decryptedConsults = decryptConsultLockboxGrants(grantsByConsultLockbox ?? [], this.rsa)\n if (decryptedConsults.length > 0) {\n console.info('[sdk:index] Grants found in user`s constant time secure index')\n this.cachedMetadataGrants[filterString] = decryptedConsults\n return this.cachedMetadataGrants[filterString]\n }\n\n // if we have no valid grants, then return nothing\n return []\n }\n\n /**\n * Fetches the role of the account that is logged in\n *\n * @returns the role based scopes defined by the whoami\n */\n async getAccountRole(): Promise<RoleBasedScopes[]> {\n return (await this.guardClient.whoAmI()).scope.split(' ') as RoleBasedScopes[]\n }\n\n /**\n * @name getCachedSecretCryptor\n * @description Retrieves the cached lockbox secret or fetches the secret from vault, then creates the symmetric cryptor and stores it in memory\n * @param lockboxUuid\n * @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)\n * @returns\n */\n async getCachedSecretCryptor(lockboxUuid: string, lockboxOwnerUuid?: string): Promise<OroToolbox.CryptoChaCha> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let index = this.secrets.findIndex((secret) => secret.lockboxUuid === lockboxUuid)\n if (index === -1) {\n let encryptedSecret = (await this.vaultClient.lockboxSecretGet(lockboxUuid, lockboxOwnerUuid)).sharedSecret\n\n let secret = this.rsa.base64DecryptToBytes(encryptedSecret)\n let cryptor = this.toolbox.CryptoChaCha.fromKey(secret)\n this.secrets.push({ lockboxUuid, cryptor })\n return cryptor\n } else {\n return this.secrets[index].cryptor\n }\n }\n\n /**\n * Retrieves the patient personal information associated to the `consultationId`\n * The `consultationId` only helps to retrieve the patient lockboxes\n * Note: it is possible to have several personal informations data\n * @param consultationId The consultation Id\n * @param category The personal MetadataCategory to fetch\n * @param forceRefresh force data refresh (default to false)\n * @returns the personal data\n */\n public async getPersonalInformationsFromConsultId(\n consultationId: Uuid,\n category: MetadataCategory.Personal | MetadataCategory.ChildPersonal | MetadataCategory.OtherPersonal,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n return this.getMetaCategoryFromConsultId(consultationId, category, options)\n }\n\n /**\n * Retrieves the patient medical data associated to the `consultationId`\n * The `consultationId` only helps to retrieve the patient lockboxes\n * Note: it is possible to have several medical data\n * @param consultationId The consultation Id\n * @param forceRefresh force data refresh (default to false)\n * @returns the medical data\n */\n public async getMedicalDataFromConsultId(\n consultationId: Uuid,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n return this.getMetaCategoryFromConsultId(consultationId, MetadataCategory.Medical, options)\n }\n\n private async getMetaCategoryFromConsultId(\n consultationId: Uuid,\n category: MetadataCategory,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n let grants = await this.getGrants({ consultationId })\n let workflowData: LocalizedData<PopulatedWorkflowData>[] = []\n for (let grant of grants) {\n let manifest = await this.getLockboxManifest(\n grant.lockboxUuid!,\n {\n category,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationIds: [consultationId],\n },\n true,\n grant.lockboxOwnerUuid,\n options\n )\n\n // TODO: find another solution for backwards compatibility (those without the metadata consultationIds)\n if (manifest.length === 0) {\n manifest = (\n await this.getLockboxManifest(\n grant.lockboxUuid!,\n {\n category,\n documentType: DocumentType.PopulatedWorkflowData,\n // backward compatiblility with TonTest\n },\n true,\n grant.lockboxOwnerUuid,\n options\n )\n ).filter((entry) => !entry.metadata.consultationIds) // Keep only entries without associated consultationIds\n }\n let data = await Promise.all(\n manifest.map(async (entry) => {\n return {\n lockboxOwnerUuid: grant.lockboxOwnerUuid,\n lockboxUuid: grant.lockboxUuid!,\n dataUuid: entry.dataUuid,\n data: await this.getJsonData<PopulatedWorkflowData>(grant.lockboxUuid!, entry.dataUuid),\n }\n })\n )\n workflowData = { ...workflowData, ...data }\n }\n return workflowData\n }\n\n /**\n * @description retrieves the personal information stored in the first owned lockbox\n * @param userId The user Id\n * @returns the personal data\n */\n public async getPersonalInformations(userId: Uuid): Promise<LocalizedData<PopulatedWorkflowData>> {\n const grant = (await this.getGrants()).find((lockbox) => lockbox.lockboxOwnerUuid === userId)\n\n if (!grant) {\n throw MissingGrant\n }\n\n const { lockboxUuid, lockboxOwnerUuid } = grant\n\n if (!lockboxUuid) throw MissingLockbox\n\n if (!lockboxOwnerUuid) throw MissingLockboxOwner\n\n const identificationDataUuid = (\n await this.getLockboxManifest(\n lockboxUuid,\n {\n category: MetadataCategory.Personal,\n documentType: DocumentType.PopulatedWorkflowData,\n },\n false,\n userId\n )\n )[0].dataUuid\n\n return {\n lockboxOwnerUuid,\n lockboxUuid,\n dataUuid: identificationDataUuid,\n data: await this.getJsonData<PopulatedWorkflowData>(lockboxUuid, identificationDataUuid),\n }\n }\n\n /**\n * Retrieves the grant associated to a consultationId\n * @note returns the first grant only\n * @param consultationId The consultationId\n * @returns the grant\n */\n public async getGrantFromConsultId(consultationId: Uuid): Promise<Grant | undefined> {\n let grants = await this.getGrants({ consultationId })\n\n if (grants.length === 0) {\n throw AssociatedLockboxNotFound\n }\n\n return grants[0]\n }\n\n /**\n * retrieves the identity associated to the `consultationId`\n * @param consultationId The consultation Id\n * @returns the identity\n */\n public async getIdentityFromConsultId(consultationId: Uuid): Promise<IdentityResponse | undefined> {\n const grant = await this.getGrantFromConsultId(consultationId)\n\n if (grant && grant.lockboxOwnerUuid) {\n return await this.guardClient.identityGet(grant.lockboxOwnerUuid)\n } else {\n return undefined\n }\n }\n\n /**\n * retrieves the lockbox manifest for a given lockbox and add's its private metadata\n * @note the lockbox manifest will retrieved the cached manifest first unless force refresh is enabled\n * @param lockboxUuid\n * @param filter\n * @param expandPrivateMetadata\n * @param lockboxOwnerUuid\n * @param forceRefresh\n * @returns the lockbox manifest\n */\n public async getLockboxManifest(\n lockboxUuid: Uuid,\n filter: Metadata,\n expandPrivateMetadata: boolean,\n lockboxOwnerUuid?: Uuid,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<LockboxManifest> {\n let manifestKey = JSON.stringify({\n lockboxUuid,\n filter,\n expandPrivateMetadata,\n lockboxOwnerUuid,\n })\n if (!options.forceRefresh && this.cachedManifest[manifestKey]) return this.cachedManifest[manifestKey]\n\n return this.vaultClient.lockboxManifestGet(lockboxUuid, filter, lockboxOwnerUuid).then((manifest) => {\n return Promise.all(\n manifest.map(async (entry) => {\n if (expandPrivateMetadata && entry.metadata.privateMetadata) {\n let privateMeta = await this.getJsonData<Metadata>(\n lockboxUuid!,\n entry.metadata.privateMetadata,\n lockboxOwnerUuid\n )\n entry.metadata = {\n ...entry.metadata,\n ...privateMeta,\n }\n }\n return entry\n })\n ).then((manifest) => (this.cachedManifest[manifestKey] = manifest))\n })\n }\n\n /**\n * @description Create or update the personal information and store it in the first owned lockbox\n * @param identity The identity to use\n * @param data The personal data to store\n * @param dataUuid (optional) The dataUuid to update\n * @returns\n */\n public async createPersonalInformations(\n identity: IdentityResponse,\n data: PopulatedWorkflowData,\n dataUuid?: string\n ): Promise<DataCreateResponse> {\n const lockboxUuid = (await this.getGrants()).find(\n (lockbox) => lockbox.lockboxOwnerUuid === identity.id\n )?.lockboxUuid\n\n if (lockboxUuid) {\n return this.createJsonData<PersonalMeta>(\n lockboxUuid,\n data,\n {\n category: MetadataCategory.Personal,\n documentType: DocumentType.PopulatedWorkflowData,\n },\n {},\n undefined,\n dataUuid\n )\n } else {\n throw MissingLockbox\n }\n }\n\n /**\n * Create or update user Preference\n * @param identity\n * @param preference\n * @param dataUuid\n * @returns\n */\n public async createUserPreference(\n identity: IdentityResponse,\n preference: UserPreference,\n dataUuid?: string\n ): Promise<DataCreateResponse> {\n const lockboxUuid = (await this.getGrants()).find(\n (lockbox) => lockbox.lockboxOwnerUuid === identity.id\n )?.lockboxUuid\n\n if (lockboxUuid) {\n return this.createJsonData<PreferenceMeta>(\n lockboxUuid,\n preference,\n {\n category: MetadataCategory.Preference,\n contentType: 'application/json',\n },\n {},\n undefined,\n dataUuid\n )\n } else {\n throw MissingLockbox\n }\n }\n\n /**\n * retrieves the user preference from a grant\n * @param grant The grant\n * @returns the user preference\n */\n public async getDataFromGrant<T = any>(grant: Grant, filter: Metadata): Promise<LocalizedData<T>> {\n const { lockboxUuid, lockboxOwnerUuid } = grant\n\n if (!lockboxUuid) throw MissingLockbox\n if (!lockboxOwnerUuid) throw MissingLockboxOwner\n const identificationDataUuid = (\n await this.getLockboxManifest(lockboxUuid, filter, false, grant.lockboxOwnerUuid, { forceRefresh: true })\n )[0].dataUuid\n\n return {\n lockboxOwnerUuid,\n lockboxUuid,\n dataUuid: identificationDataUuid,\n data: await this.getJsonData<T>(lockboxUuid, identificationDataUuid),\n }\n }\n\n /**\n * retrieves the user preference from a consultation id\n * @param consultationId The related consultationId\n * @returns the user preference\n */\n public async getUserPreferenceFromConsultId(consultationId: string): Promise<LocalizedData<UserPreference>> {\n const grant = await this.getGrantFromConsultId(consultationId)\n\n if (!grant) throw MissingGrant\n\n return this.getDataFromGrant<UserPreference>(grant, {\n category: MetadataCategory.Preference,\n contentType: 'application/json',\n })\n }\n\n /**\n * retrieves the user preference stored in the first owned lockbox from identity\n * @param identity The identity to use\n * @returns the user preference\n */\n public async getUserPreference(identity: IdentityResponse): Promise<LocalizedData<UserPreference>> {\n const grant = (await this.getGrants()).find((lockbox) => lockbox.lockboxOwnerUuid === identity.id)\n\n if (!grant) throw MissingGrant\n\n return this.getDataFromGrant<UserPreference>(grant, {\n category: MetadataCategory.Preference,\n contentType: 'application/json',\n })\n }\n\n /**\n * retrieves the user preference from a consultation id\n * @param consultationId The related consultationId\n * @returns the user preference\n */\n public async getRecoveryDataFromConsultId(consultationId: string): Promise<LocalizedData<RecoveryData>> {\n const grant = await this.getGrantFromConsultId(consultationId)\n\n if (!grant) throw MissingGrant\n\n return this.getDataFromGrant<RecoveryData>(grant, {\n category: MetadataCategory.Recovery,\n contentType: 'application/json',\n })\n }\n\n /**\n * retrieves the user preference stored in the first owned lockbox from identity\n * @param identity The identity to use\n * @returns the user preference\n */\n public async getRecoveryData(identity: IdentityResponse): Promise<LocalizedData<RecoveryData>> {\n const grant = (await this.getGrants()).find((lockbox) => lockbox.lockboxOwnerUuid === identity.id)\n\n if (!grant) throw MissingGrant\n\n return this.getDataFromGrant(grant, {\n category: MetadataCategory.Recovery,\n contentType: 'application/json',\n })\n }\n\n /**\n * @name getAssignedConsultations\n * @description finds all assigned or owned consultations for the logged user\n * Steps:\n * - Retrieves all granted lockboxes given to the logged user\n * - for each lockbox, find all consultation ids\n * - for each consultation id, retrieve the consult information\n * @param practiceUuid the uuid of the practice to look consult into\n * @returns the list of consults\n */\n public async getAssignedConsultations(practiceUuid: Uuid): Promise<Consult[]> {\n return Promise.all(\n (await this.getGrants()).map((grant) =>\n this.getLockboxManifest(\n grant.lockboxUuid!,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n },\n true,\n undefined\n ).then((manifest) =>\n Promise.all(\n manifest.map(\n async (entry) =>\n await this.consultClient.getConsultByUUID(entry.metadata.consultationId, practiceUuid)\n )\n ).then((promise) => promise.flat())\n )\n )\n ).then((consults) => consults.flat())\n }\n\n /**\n * Gets the past consultations of the patient as well as his relatives if any\n * @param consultationId any consultation uuid from which we will fetch all the other consultations of the same patient as the owner of this consultation id\n * @param practiceUuid\n */\n public async getPastConsultationsFromConsultId(\n consultationId: string,\n practiceUuid: string\n ): Promise<Consult[] | undefined> {\n const grant = await this.getGrantFromConsultId(consultationId)\n if (!grant) return undefined\n\n let consultationsInLockbox: string[] = (\n await this.vaultClient.lockboxMetadataGet(\n grant.lockboxUuid!,\n ['consultationId'],\n ['consultationId'],\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n },\n grant.lockboxOwnerUuid\n )\n )\n .flat()\n .map((metadata: { consultationId: string }) => metadata.consultationId)\n\n if (consultationsInLockbox.length == 0) return []\n\n return await Promise.all(\n consultationsInLockbox.map(async (consultId: string) => {\n return await this.consultClient.getConsultByUUID(consultId, practiceUuid)\n })\n )\n }\n\n /**\n * @name getPatientConsultationData\n * @description retrieves the consultation data\n * @param consultationId\n * @returns\n */\n public async getPatientConsultationData(\n consultationId: Uuid,\n options: { forceRefresh: boolean } = { forceRefresh: false }\n ): Promise<PopulatedWorkflowData[]> {\n //TODO: make use of getPatientDocumentsList instead of doing it manually here\n return Promise.all(\n (await this.getGrants({ consultationId }))\n .map((grant) =>\n this.getLockboxManifest(\n grant.lockboxUuid!,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationId, //since we want to update the cached manifest (if another consult data exists)\n },\n true,\n grant.lockboxOwnerUuid,\n options\n ).then((manifest) =>\n Promise.all(\n manifest.map((e) =>\n this.getJsonData<PopulatedWorkflowData>(\n grant.lockboxUuid!,\n e.dataUuid,\n grant.lockboxOwnerUuid\n )\n )\n )\n )\n )\n .flat()\n ).then((data) => data.flat())\n }\n\n /**\n * This function returns the patient prescriptions\n * @param consultationId\n * @returns\n */\n public async getPatientPrescriptionsList(consultationId: Uuid): Promise<Document[]> {\n return this.getPatientDocumentsList(\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.Prescription,\n },\n true,\n consultationId\n )\n }\n\n /**\n * This function returns the patient results\n * @param consultationId\n * @returns\n */\n public async getPatientResultsList(consultationId: Uuid): Promise<Document[]> {\n return this.getPatientDocumentsList(\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.Result,\n },\n true,\n consultationId\n )\n }\n\n /**\n * returns the patient treatment plan options\n * @param consultationId\n * @returns Document[] corresponding to the patient treatment plan options\n */\n public async getPatientTreatmentPlans(consultationId: Uuid): Promise<Document[]> {\n return this.getPatientDocumentsList(\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.TreatmentPlan,\n },\n true,\n consultationId\n )\n }\n\n /**\n * returns a specific patient treatment plan option\n * @param consultationId\n * @param treatmentPlanId\n * @returns\n */\n public async getPatientTreatmentPlanByUuid(consultationId: Uuid, treatmentPlanId: Uuid): Promise<Document[]> {\n return this.getPatientDocumentsList(\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.TreatmentPlan,\n treatmentPlanId,\n },\n true,\n consultationId\n )\n }\n\n /**\n * @name getPatientDocumentsList\n * @description applies the provided filter to the vault to only find those documents\n * @param filters the applied filters (e.g. type of documents)\n * @param expandPrivateMetadata whether or not, the private metadata needs to be retrieved\n * (more computationally expensive)\n * @param consultationId\n * @returns the filtered document list\n */\n public async getPatientDocumentsList(\n filters: Object,\n expandPrivateMetadata: boolean,\n consultationId: Uuid\n ): Promise<Document[]> {\n return Promise.all(\n (await this.getGrants({ consultationId }))\n .map((grant) =>\n this.getLockboxManifest(\n grant.lockboxUuid!,\n { ...filters, consultationId },\n expandPrivateMetadata,\n grant.lockboxOwnerUuid,\n { forceRefresh: true }\n ).then((manifest) =>\n Promise.all(\n manifest.map(async (entry): Promise<Document> => {\n return {\n lockboxOwnerUuid: grant.lockboxOwnerUuid,\n lockboxUuid: grant.lockboxUuid!,\n ...entry,\n }\n })\n )\n )\n )\n .flat()\n ).then((data) => data.flat())\n }\n\n /****************************************************************************************************************\n * RECOVERY *\n ****************************************************************************************************************/\n\n /**\n * @name recoverPrivateKeyFromSecurityQuestions\n * @description Recovers and sets the rsa private key from the answered security questions\n * @param id\n * @param recoverySecurityQuestions\n * @param recoverySecurityAnswers\n * @param threshold the number of answers needed to recover the key\n */\n public async recoverPrivateKeyFromSecurityQuestions(\n id: Uuid,\n recoverySecurityQuestions: string[],\n recoverySecurityAnswers: string[],\n threshold: number\n ) {\n let shards: SecretShard[] = (await this.guardClient.identityGet(id)).recoverySecurityQuestions!\n let answeredShards = shards\n .filter((shard: any) => {\n // filters all answered security questions\n let indexOfQuestion = recoverySecurityQuestions.indexOf(shard.securityQuestion)\n if (indexOfQuestion === -1) return false\n return recoverySecurityAnswers[indexOfQuestion] && recoverySecurityAnswers[indexOfQuestion] != ''\n })\n .map((item: any) => {\n // appends the security answer to the answered shards\n let index = recoverySecurityQuestions.indexOf(item.securityQuestion)\n item.securityAnswer = recoverySecurityAnswers[index]\n return item\n })\n try {\n // reconstructs the key from the answered security answers\n let privateKey = this.toolbox.reconstructSecret(answeredShards, threshold)\n this.rsa = this.toolbox.CryptoRSA.fromKey(privateKey)\n } catch (e) {\n console.error(e)\n }\n }\n\n /**\n * @name recoverPrivateKeyFromPassword\n * @description Recovers and sets the rsa private key from the password\n * @param id\n * @param password\n */\n public async recoverPrivateKeyFromPassword(id: Uuid, password: string) {\n let identity = await this.guardClient.identityGet(id)\n\n let recoveryPayload = identity.recoveryPassword\n let symmetricDecryptor = this.toolbox.CryptoChaCha.fromPassphrase(password)\n let privateKey = symmetricDecryptor.base64PayloadDecryptToBytes(recoveryPayload)\n\n if (identity.recoveryLogin) {\n //Ensure we can recover from a page reload\n let symetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(identity.recoveryLogin)\n sessionStorage.setItem(\n sessionStorePrivateKeyName(id),\n symetricEncryptor.bytesEncryptToBase64Payload(privateKey)\n )\n }\n\n this.rsa = this.toolbox.CryptoRSA.fromKey(privateKey)\n }\n\n /**\n * @name recoverPrivateKeyFromMasterKey\n * @description Recovers and sets the rsa private key from the master key\n * @param id\n * @param masterKey\n */\n public async recoverPrivateKeyFromMasterKey(id: Uuid, masterKey: string) {\n let recoveryPayload = (await this.guardClient.identityGet(id)).recoveryMasterKey!\n let symmetricDecryptor = this.toolbox.CryptoChaCha.fromPassphrase(masterKey)\n let privateKey = symmetricDecryptor.base64PayloadDecryptToBytes(recoveryPayload)\n this.rsa = this.toolbox.CryptoRSA.fromKey(privateKey)\n }\n\n /**\n * @description Generates and updates the security questions and answers payload using new recovery questions and answers\n * Important: Since the security questions generate a payload for the private key, they will never be stored on the device as they must remain secret!!!\n * @param id\n * @param recoverySecurityQuestions\n * @param recoverySecurityAnswers\n * @param threshold the number of answers needed to rebuild the secret\n */\n public async updateSecurityQuestions(\n id: Uuid,\n recoverySecurityQuestions: string[],\n recoverySecurityAnswers: string[],\n threshold: number\n ) {\n if (!this.rsa) throw IncompleteAuthentication\n let securityQuestionPayload = this.toolbox.breakSecretIntoShards(\n recoverySecurityQuestions,\n recoverySecurityAnswers,\n this.rsa.private(),\n threshold\n )\n let updateRequest = {\n recoverySecurityQuestions: securityQuestionPayload,\n }\n\n return await this.guardClient.identityUpdate(id, updateRequest)\n }\n\n /**\n * @description Generates and stores the payload encrypted payload and updates the password itself (double hash)\n * @important\n * the recovery payload uses a singly hashed password and the password stored is doubly hashed so\n * the stored password cannot derive the decryption key in the payload\n * @note\n * the old password must be provided when not performing an account recovery\n * @param id\n * @param newPassword\n * @param oldPassword\n */\n public async updatePassword(id: Uuid, newPassword: string, oldPassword?: string) {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(newPassword)\n let passwordPayload = symmetricEncryptor.bytesEncryptToBase64Payload(this.rsa.private())\n if (oldPassword) {\n oldPassword = this.toolbox.hashStringToBase64(this.toolbox.hashStringToBase64(oldPassword))\n }\n\n newPassword = this.toolbox.hashStringToBase64(this.toolbox.hashStringToBase64(newPassword))\n\n let updateRequest = {\n password: {\n oldPassword,\n newPassword,\n },\n recoveryPassword: passwordPayload,\n }\n\n return await this.guardClient.identityUpdate(id, updateRequest)\n }\n\n /**\n * @description Generates and stores the master key encrypted payload\n * Important\n * Since the master key is used to generate a payload for the private key, it will never be stored on the device as it must remain secret!\n * @param id\n * @param masterKey\n * @param lockboxUuid\n */\n async updateMasterKey(id: Uuid, masterKey: string, lockboxUuid: Uuid) {\n if (!this.rsa) throw IncompleteAuthentication\n\n let symmetricEncryptor = this.toolbox.CryptoChaCha.fromPassphrase(masterKey)\n let masterKeyPayload = symmetricEncryptor.bytesEncryptToBase64Payload(this.rsa.private())\n let updateRequest = { recoveryMasterKey: masterKeyPayload }\n const updatedIdentity = await this.guardClient.identityUpdate(id, updateRequest)\n\n await this.getOrInsertJsonData<RecoveryMeta>(\n lockboxUuid,\n { masterKey },\n {\n category: MetadataCategory.Recovery,\n contentType: 'application/json',\n },\n {},\n { forceReplace: true, withNotification: false, updateMedicalStatus: false }\n )\n\n return updatedIdentity\n }\n}\n","import { AxiosService, CliniaResponse, FacetFilter, PlaceData } from \"oro-sdk-apis\"\n\nexport class CliniaService {\n private api: AxiosService\n\n constructor(private url: string, apiKey: string, private locale?: string) {\n this.api = new AxiosService({ headers: { 'X-Clinia-API-Key': apiKey } })\n }\n\n public placeSearch(searchOptions: {\n locale?: string\n query?: string\n facetFilters?: FacetFilter[]\n location?: string\n aroundLatLng?: string\n page?: number\n }) {\n const { locale, ...data } = searchOptions\n\n return this.api.post<CliniaResponse<PlaceData>>(\n `${this.url}/search/v1/indexes/health_facility/query`,\n data,\n {\n params: { locale: locale ?? this.locale },\n }\n )\n }\n\n public placeMatch(\n searchOptions: {\n locale?: string\n name?: string\n address?: string\n postalCode?: string\n place?: string\n region?: string\n country?: string\n },\n type?: string\n ) {\n const { locale, ...data } = searchOptions\n\n let request = this.api.post<PlaceData[]>(\n `${this.url}/search/v1/matches`,\n data,\n {\n params: { locale: locale ?? this.locale },\n }\n )\n\n if (type) {\n request = request.then((places) =>\n places.filter((place) => place.type === type)\n )\n }\n\n return request\n }\n}\n","import initApis from 'oro-sdk-apis'\nimport { OroClient } from './client'\nimport * as OroToolboxNamespace from 'oro-toolbox'\n\nexport type OroToolbox = typeof OroToolboxNamespace\n\nexport let wasmPath = 'node_modules/oro-toolbox'\n\n/**\n * This function helps you to initialize and OroClient instance\n * @param toolbox the OroToolbox object\n * @param tellerBaseURL the teller service base URL \n * @param vaultBaseURL the vault service base URL \n * @param guardBaseURL the guard service base URL \n * @param searchbaseURL the search service base URL\n * @param practiceBaseURL the practice service base URL \n * @param consultBaseURL the consult service base URL \n * @param workflowBaseURL the workflow service base URL \n * @param diagnosisBaseURL the diagnosis service base URL \n * @param authenticationCallback (optional) authenticationCallback the authentification callback \n * @returns an instance of OroClient\n */\nconst init = (\n toolbox: OroToolbox,\n tellerBaseURL: string,\n vaultBaseURL: string,\n guardBaseURL: string,\n searchBaseURL: string,\n practiceBaseURL: string,\n consultBaseURL: string,\n workflowBaseURL: string,\n diagnosisBaseURL: string,\n authenticationCallback?: (err: Error) => void\n) => {\n const {\n tellerService,\n practiceService,\n consultService,\n vaultService,\n guardService,\n searchService,\n workflowService,\n diagnosisService,\n } = initApis(\n {\n tellerBaseURL,\n vaultBaseURL,\n guardBaseURL,\n searchBaseURL,\n practiceBaseURL,\n consultBaseURL,\n workflowBaseURL,\n diagnosisBaseURL,\n },\n authenticationCallback\n )\n\n const client = new OroClient(\n toolbox,\n tellerService!,\n vaultService!,\n guardService!,\n searchService!,\n practiceService!,\n consultService!,\n workflowService!,\n diagnosisService!,\n authenticationCallback\n )\n\n return client\n}\n\nexport { OroClient } from './client'\nexport * from 'oro-sdk-apis'\nexport * from './models'\nexport * from './helpers'\nexport * from './services'\nexport { OroToolboxNamespace }\nexport default init\n"],"names":["personalMetaToPrefix","MetadataCategory","Personal","ChildPersonal","OtherPersonal","identificationToPersonalInformations","data","category","prefix","birthday","firstname","gender","name","phone","zip","hid","pharmacy","address","toActualObject","ret","Object","entries","fields","forEach","field","displayedAnswer","answer","sessionStorePrivateKeyName","id","IncompleteAuthentication","_inheritsLoose","Error","MissingGrant","MissingGrantFilter","MissingLockbox","MissingLockboxOwner","AssociatedLockboxNotFound","WorkflowAnswersMissingError","filterTriggeredAnsweredWithKind","_filterTriggeredAnsweredWithKind","workflowData","kind","selectedAnswers","_context","flattenedAnswers","flattenSelectedAnswers","triggeredQuestionsWithKind","fromEntries","pages","map","a","questions","filter","question","isTriggered","triggers","flat","samePageAnswers","reduce","prev","cur","res","keys","questionFieldName","getWorkflowDataByCategory","_getWorkflowDataByCategory","_context2","triggeredQuestions","Promise","all","e","k","populateWorkflowField","then","populatedValue","workflowCreatedAt","createdAt","workflowId","locale","err","console","error","getImagesFromIndexDb","_getImagesFromIndexDb","_context3","getMany","v","_populateWorkflowField","answerValue","undefined","_context4","answers","text","value","images","image","imageData","resolve","includes","Array","isArray","some","subSetTriggers","every","trigger","linearAnswers","push","values","getInitialisedSelectedAnswers","workflow","useDefault","page","defaultValue","getOrCreatePatientConsultationUuid","_getOrCreatePatientConsultationUuid","consult","oroClient","practiceClient","practiceGetPayment","uuidPractice","idStripeInvoiceOrPaymentIntent","payment","uuidConsult","consultClient","getConsultByUUID","consultCreate","registerPatient","_registerPatient","patientUuid","consultRequest","masterKey","recoveryQA","indexSearch","onProgress","lockboxUuid","practitionerAdmin","retry","identity","errorsThrown","stepsTotalNum","currentStep","setTimeout","practiceGetFromUuid","uuidAdmin","practiceGetPractitioners","log","practitioners","getOrCreatePatientLockbox","guardClient","identityGet","grantLockbox","grantPromises","practitioner","uuid","IndexKey","ConsultationLockbox","grant","lockboxOwnerUuid","consultationId","consultIndex","consultIndexPromises","vaultIndexAdd","storeImageAliases","storePatientData","isoLanguageRequired","_identity","recoveryMasterKey","updateMasterKey","_identity2","recoverySecurityQuestions","updateSecurityQuestions","recoverySecurityAnswers","buildConsultSearchIndex","length","updateConsultByUUID","statusMedical","MedicalStatus","New","cleanIndex","_getOrCreatePatientLockbox","_context5","getGrants","grants","vaultClient","lockboxCreate","lockboxResponse","authRefresh","tokens","setTokens","accessToken","refreshToken","whoAmI","_storePatientData","isoLanguage","getOrInsertJsonData","Raw","contentType","Consultation","documentType","DocumentType","PopulatedWorkflowData","withNotification","forceReplace","updateMedicalStatus","Medical","consultationIds","extractAndStorePersonalWorkflowData","Preference","dataUuids","_storeImageAliases","progress","_context7","nonNullImages","img","storedImagesNum","totalImagesNum","promises","ImageAlias","idbId","progressStepValue","Math","round","_extractAndStorePersonalWorkflowData","extractPersonalInfoFromWorkflowData","_extractPersonalInfoFromWorkflowData","personalInfoPopulatedWfData","childPersonalInfoPopulatedWfData","otherPersonalInfoPopulatedWfData","_buildConsultSearchIndex","terms","shortId","_context10","_yield$extractPersona","personalInfo","childPersonalInfo","otherPersonalInfo","searchClient","index","decryptGrants","encryptedGrants","rsaKey","encryptedLockbox","uuidParse","base64DecryptToBytes","decryptConsultLockboxGrants","encryptedConsultLockboxes","base64DecryptToJson","encryptedIndexEntry","grantsTuple","grantTuples","createRefill","_createRefill","populatedRefillWorkflow","newConsult","getLockboxManifest","uuidParent","rawConsultationManifest","getJsonData","dataUuid","rawConsultation","filterGrantsWithLockboxMetadata","_filterGrantsWithLockboxMetadata","filteredGrants","_iterator","lockboxMetadataGet","OroClient","toolbox","tellerClient","workflowClient","diagnosisClient","authenticationCallback","this","_proto","cachedMetadataGrants","cachedManifest","signUp","email","password","practice","tosAndCpAcceptance","tokenData","subscription","skipEmailValidation","rsa","CryptoRSA","privateKey","symmetricEncryptor","CryptoChaCha","fromPassphrase","recoveryPassword","bytesEncryptToBase64Payload","hashedPassword","hashStringToBase64","toLowerCase","subscriptionAcceptance","signupRequest","practiceUuid","emailConfirmed","publicKey","encodeToBase64","identityCreate","recoveryLogin","symetricEncryptor","sessionStorage","setItem","confirmEmail","identityUpdate","sub","signIn","otp","tokenRequest","authToken","userUuid","recoverPrivateKeyFromPassword","resumeSession","recoveryPayload","getItem","recoveryKey","symmetricDecryptor","base64PayloadDecryptToBytes","fromKey","localEncryptToJsonPayload","chaChaKey","encryptedData","jsonEncryptToBase64Payload","encryptedKey","encryptToBytes","key","localDecryptJsonPayload","base64PayloadDecryptToJson","signOut","secrets","_context6","authLogout","_context8","forceUpdateIndexEntries","_this$vaultIndexAdd","_context9","_this","consults","alert","indexOwnerUuid","_context11","rsaPub","decodeFromBase64","encryptedIndex","_i","uniqueHash","timestamp","jsonWithPubEncryptToBase64","vaultIndexPut","granteeUuid","_context12","getCachedSecretCryptor","secret","granteePublicKey","granteeEncryptedSecret","bytesWithPubEncryptToBase64","request","encryptedSecret","lockboxGrant","createMessageData","message","previousDataUuid","options","_context13","author","encryptedPrivateMeta","lockboxDataStore","publicMetadata","Message","privateMetadata","createMessageAttachmentData","_context14","Uint8Array","arrayBuffer","lastModified","size","fileName","type","createConsultationAttachmentData","_context15","createBytesData","createJsonData","meta","privateMeta","_context16","_context17","lockboxManifestGet","manifest","JSON","stringify","_context18","_context19","lockboxDataGet","_yield$Promise$all","getBytesData","_context20","_yield$Promise$all2","_context21","filterString","getAccountRole","currentAccountRole","OtherRoleType","User","Patient","requiredRole","grantsGet","decryptedGrants","info","vaultIndexGet","decryptedConsults","grantsByConsultLockbox","_context22","scope","split","_context23","findIndex","lockboxSecretGet","sharedSecret","cryptor","getPersonalInformationsFromConsultId","forceRefresh","getMetaCategoryFromConsultId","getMedicalDataFromConsultId","_context28","_loop","_context27","_this2","entry","metadata","_context26","getPersonalInformations","userId","_context29","find","lockbox","identificationDataUuid","getGrantFromConsultId","_context30","getIdentityFromConsultId","_context31","expandPrivateMetadata","manifestKey","_context33","_context32","_this3","createPersonalInformations","_context34","_yield$this$getGrants","createUserPreference","preference","_context35","_yield$this$getGrants2","getDataFromGrant","_context36","getUserPreferenceFromConsultId","_context37","getUserPreference","_context38","getRecoveryDataFromConsultId","_context39","Recovery","getRecoveryData","_context40","getAssignedConsultations","_context42","_this4","_context41","promise","getPastConsultationsFromConsultId","_context44","consultationsInLockbox","consultId","_context43","_this5","getPatientConsultationData","_context45","_this6","getPatientPrescriptionsList","getPatientDocumentsList","Prescription","getPatientResultsList","Result","getPatientTreatmentPlans","TreatmentPlan","getPatientTreatmentPlanByUuid","treatmentPlanId","filters","_context51","_this7","recoverPrivateKeyFromSecurityQuestions","threshold","_context52","answeredShards","shard","indexOfQuestion","indexOf","securityQuestion","item","securityAnswer","reconstructSecret","_context53","recoverPrivateKeyFromMasterKey","_context54","_context55","securityQuestionPayload","breakSecretIntoShards","updateRequest","updatePassword","newPassword","oldPassword","_context56","passwordPayload","_context57","masterKeyPayload","updatedIdentity","CliniaService","url","apiKey","api","AxiosService","headers","X-Clinia-API-Key","placeSearch","searchOptions","post","params","placeMatch","places","place","tellerBaseURL","vaultBaseURL","guardBaseURL","searchBaseURL","practiceBaseURL","consultBaseURL","workflowBaseURL","diagnosisBaseURL","initApis","tellerService","vaultService","guardService","searchService","practiceService","consultService","workflowService","diagnosisService","arrSelectedLocality","flatMap","currentAnswerPage","arrCountryFields","workflowFieldName","arrProvinceFields","arrConsultLocalFields","currentFieldName","currentSelectedLocality","startsWith","allowedLocalityPatterns","indexPriority","isoValue","finalLocality","extractedSelected","exec","indexSelectedPriority","isoSelectedValue","extractedFinal","indexFinalPriority","populatedWorkflow","filledWorkflow","parse","pageIdx","isTreatmentWorking","hasSideEffects","deliveryAddress","culDeSacs","hidePlanRules","title","groups","fieldsAndGroups","label","inline","inlineLabel","metaCategory","Refill","73bec6eb-0310-4787-af3c-ac9c291737b2","e193951f-986f-4db3-bede-903045a1804a","1b87ad22-d316-4fac-9c7f-8f4ccb841aed","ab7f5a41-c351-4f5d-a568-e38f9f200e9a","youPharmacy","summaryLabel","youAddress","infos"],"mappings":"uoVAOA,IAAMA,UACDC,mBAAiBC,UAAW,QAC5BD,mBAAiBE,eAAgB,UACjCF,mBAAiBG,eAAgB,oBAQtBC,EACZC,EACAC,SAKMC,EAASR,EAAqBO,GAEpC,MAAO,CACHE,SAAUH,EAAQE,cAClBE,UAAWJ,EAAQE,eACnBG,OAAQL,EAAQE,YAChBI,KAAMN,EAAQE,UACdK,MAAOP,EAAQE,WACfM,IAAKR,EAAQE,SACbO,aAAKT,EAAQE,YAAgBF,EAAQE,QACrCQ,SAAUV,EAAQE,cAClBS,QAASX,EAAQE,uBAITU,EAAeZ,GAC3B,IAAMa,EAAW,GAMjB,OAJAC,OAAOC,QAAQf,EAAKgB,QAAQC,SAAQ,gBAAOC,OACvCL,QAAWK,EAAMC,gBAAkBD,EAAMC,gBAAkBD,EAAME,UAG9DP,WAqJKQ,EAA2BC,GACvC,MAF4B,YAEKA,MCrMxBC,cAAyB,aAAA,qCAAA,OAAAC,YAAQC,QACjCC,cAAa,aAAA,qCAAA,OAAAF,YAAQC,QACrBE,cAAmB,aAAA,qCAAA,OAAAH,YAAQC,QAC3BG,cAAe,aAAA,qCAAA,OAAAJ,YAAQC,QACvBI,cAAoB,aAAA,qCAAA,OAAAL,YAAQC,QAC5BK,cAA0B,aAAA,qCAAA,OAAAN,YAAQC,QAClCM,cAA4B,aAAA,qCAAA,OAAAP,YAAQC,iBCQ3BO,OAA+B,+BA2CrD,aAFC,OAEDC,cA3CO,WACHC,EACAC,GAcyB,YAAA,6BAAA,OAAA,sBAAA,OAAA,GAEpBD,EAAaE,iBAAeC,SAAA,MAAA,MAAQN,EAA2B,OAoBlE,OAlBEO,EAAmBC,EAAuBL,EAAaE,iBAEvDI,EAA6B1B,OAAO2B,YACpCP,EAAaQ,MACRC,KAAI,SAACC,GACF,OAAO9B,OAAOC,QAAQ6B,EAAEC,WAAWC,QAC/B,gBAAKC,OAAQ,OAAMC,EAAYD,EAASE,UAAY,GAAIX,IAAqBS,EAASZ,OAASA,QAGtGe,QAGHC,EAAkBjB,EAAaE,gBAAgBgB,QAAO,SAACC,EAAMC,GAC/D,YAAYD,EAASC,KACtB,IAEGC,EAAMzC,OAAO0C,KAAKhB,GAA4BG,KAAI,SAACc,GACrD,OAAON,EAAgBM,wBAGpBF,GAAG,OAAA,UAAA,0DAYQG,OAAyB,+BA8C9C,aAAA,OAAAC,cA9CM,WACHzB,EACAjC,GAA0B,UAAA,6BAAA,OAAA,sBAAA,OAAA,GAErBiC,EAAaE,iBAAewB,SAAA,MAAA,MAAQ7B,EAA2B,OAiBpE,OAdIO,EAAmBC,EAAuBL,EAAaE,iBAEvDyB,EAAqB/C,OAAO2B,YAC5BP,EAAaQ,MACRC,KAAI,SAACC,GACF,OAAO9B,OAAOC,QAAQ6B,EAAEC,WAAWC,QAAO,YAAa,OACnDE,OAAqBC,UAAY,GAAIX,SAG5CY,QAGHlC,EAAiD,qBAGhD8C,QAAQC,IACX7B,EAAaE,gBACRO,KAAI,SAACqB,GAAC,OAAKlD,OAAOC,QAAQiD,MAC1Bd,OACAJ,QAAO,gBAAEmB,OAAI,OAAMJ,EAAmBI,IAAMJ,EAAmBI,GAAiB,eAAMhE,KACtF0C,KAAI,gBAAEsB,OACH,OAAOC,EAAsBL,EAAmBI,SAAOE,MAAK,SAACC,GACzDpD,EAAOiD,GAAKG,SAIvBD,MAAK,WAOF,MANmC,CAC/BE,kBAAmBnC,EAAaoC,UAChCC,WAAYrC,EAAaZ,GACzBkD,OAAQtC,EAAasC,OACrBxD,OAAAA,aAID,SAACyD,GAEJ,MADAC,QAAQC,gCAAgC1E,wBAA+BwE,GACjEA,MACR,OAAA,UAAA,0DAGYG,KAAoB,+BAI1C,aAFC,OAEDC,cAJO,WAAoCzD,GAA0B,6BAAA,OAAA,sBAAA,OAAA,OAAA0D,SACpDC,UAAgC3D,EAAiBuB,KAAI,SAACqC,GAAC,MAAA,gBAAKA,EAAE1D,MAAM0D,MAAe,OAAA,iCAAA,OAAA,UAAA,iDACnG,SAWcd,OAAqB,+BAsDpC,aAFC,OAEDe,cAtDA,WACIlC,EACAmC,GAA+B,QAAA,6BAAA,OAAA,sBAAA,OAG3B/D,OAAiDgE,EAASC,KACtDrC,EAASZ,KAAIiD,OACZ,6BAMA,gBACA,qBACA,kBAOA,mBACA,2BAWA,sBAAQ,MAAA,OAvBW,OAHhBrC,EAASsC,UACTlE,EAAqB+D,EAAY,OAAMnC,EAASsC,QAAQH,EAAY,IAAcI,MAEtFlE,EAAS8D,uBAAW,OASA,OAJhBnC,EAASsC,UACTlE,EAAkB4B,EAASsC,QAAQH,GAAuBI,MAG9DlE,EAAS8D,uBAAW,QAYA,OARpB/D,EAAmB+D,EAAyBvC,KAAI,SAAC4C,GAC7C,GAAIxC,EAASsC,QACT,OAAOtC,EAASsC,QAAQE,GAAOD,KAGnC,MAAM,IAAIvD,KAGdX,EAAS8D,uBAAW,QAAA,OAAAE,UAGLR,EAAqBM,GAAaf,MAAK,SAACqB,GAAM,OACzDA,EAAO7C,KAAI,SAAC8C,GAGR,MAAO,CAAEnF,KAFmBmF,EAApBnF,KAEOoF,UAFaD,EAAdC,iBAIrB,QANK,OAANtE,8BAAM,QASNA,EAAS8D,EAAW,QAAA,yBAGrBpB,QAAQ6B,QAAQ,CACnBvE,OAAAA,EACAD,gBAAAA,EACAgB,KAAMY,EAASZ,QACjB,QAAA,UAAA,0DAiDUa,EAAYC,EAA0CoC,GAElE,GAAwB,iBAAbpC,EACP,OAAOoC,EAAQO,SAAS3C,GAG5B,GAAI4C,MAAMC,QAAQ7C,GAEd,OAAI4C,MAAMC,QAAQ7C,EAAS,IACfA,EAAwB8C,MAAK,SAACC,GAAc,OAChDA,EAAeC,OAAM,SAACC,GAAO,OAAKb,EAAQO,SAASM,SAI/CjD,EAAsBgD,OAAM,SAACC,GAAO,OAAKb,EAAQO,SAASM,MAI1E,MAAMzE,MAAM,qDAGAc,EAAuB8C,GAGnC,IAFA,MAAMc,EAAsC,OAEvBd,kBACjBc,EAAcC,WAAdD,EAAsBrF,OAAOuF,iBAGjC,OAAOF,EAAcjD,KAAK,YASdoD,EAA8BC,EAAwBC,GAClE,gBADkEA,IAAAA,GAAsB,GACjFD,EAAS7D,MAAMC,KAAI,SAAC8D,GAEvB,IADA,IAAM5F,EAAW,SACYC,OAAOC,QAAQ0F,EAAK5D,0BAAY,CAAxD,WAAWE,OAERlC,QADkB,eAAlBkC,EAASZ,KACCqE,EAAa,QAAKrB,EAElBqB,GAAczD,EAAS2D,aAAe3D,EAAS2D,kBAAevB,EAGhF,OAAOtE,cCzQO8F,OAAkC,+BAmBvD,aAAA,OAAAC,cAnBM,WACHC,EACAC,GAAoB,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAzE,SAEAyE,EAAUC,eAAeC,mBACzCH,EAAQI,aACRJ,EAAQK,gCACX,OAHU,KAAPC,YAIWA,EAAQC,aAAW/E,SAAA,MAAA,yBACvByE,EAAUO,cAAcC,iBAAiBH,EAAQC,oBAAmB,SAAC3C,GAExE,MADAC,QAAQC,MAAM,iCAAkCF,GAC1CA,MACR,OAAA,OAAApC,SAEWyE,EAAUO,cAAcE,cAAcV,UAAe,SAACpC,GAE/D,MADAC,QAAQC,MAAM,+BAAgCF,GACxCA,KACR,OAAA,iCAAA,QAAA,UAAA,0DC+BY+C,mBAAe,+BA6NrC,aAFC,OAEDC,cA7NO,WACHC,EACAC,EACApB,EACAO,EACAc,EACAC,EAIAC,EACAC,GAIS,oBAAA,6BAAA,OAAA,sBAAA,gBALTD,IAAAA,GAAuB,GAOnBjB,OAA+B1B,EAC/B6C,OAAgC7C,EAChC8C,OAAsC9C,EACtC+C,EA5CY,GA6CZC,OAAyChD,EACzCiD,EAAwB,GACtBC,EAAgB,EAAC,OAAA,KAGhBH,EAAQ,IAAC9C,UAAA,MAAA,OAAAA,gDAAA,kBAAA,6BAAA,OAAA,sBAAA,OAMR,OAJAkD,EAAc,EAEVP,GAAYA,EAAWO,IAAgBD,EAAe,0BAE1DvD,SACM,IAAIhB,SAAQ,SAAC6B,GAAO,OAAK4C,WAAW5C,EAAS,QAAM,OAAA,GAGpDsC,GAAiBnD,SAAA,MAAA,OAAAA,SACSgC,EAAUC,eAAeyB,oBAAoBb,EAAeV,cAAa,OAApGgB,SACKQ,UAAS,OAAA,OAAA3D,UAEwBgC,EAAUC,eAC/C2B,yBAAyBf,EAAeV,qBAClC,SAACxC,GAEJ,OADAC,QAAQiE,qCAAsClE,GACvC,MACT,QAGqE,GARvEmE,SAQAb,GAAYA,EAAWO,IAAgBD,EAAe,kBAErDxB,GAAO/B,UAAA,MAAA,OAAAA,UACQ6B,EAAmCgB,EAAgBb,GAAU,QAA7ED,SAAO,QAIgE,GAAvEkB,GAAYA,EAAWO,IAAgBD,EAAe,kBAErDL,GAAWlD,UAAA,MAAA,OAAAA,UAAsB+D,EAA0B/B,GAAU,QAAxDkB,SAAW,QAAA,GAExBG,GAAQrD,UAAA,MAAA,OAAAA,UAAmBgC,EAAUgC,YAAYC,YAAYrB,GAAY,QAA/DS,SAAQ,QAAA,OAAArD,UAEjBgC,EAAUkC,aAAaf,EAAmBD,UAAmB,SAACvD,GAChEC,QAAQC,4DAA4DsD,EAAqBxD,GAEzF2D,EAAahC,KAAK3B,MACpB,QAuCA,OApCEsD,GAAYA,EAAWO,IAAgBD,EAAe,iBAEtDY,EAAgBL,EACf9F,QAAO,SAACoG,GAAY,OAAKA,EAAaC,OAASlB,KAC/CtF,eAAG,kBAAC,WAAOuG,GAAY,6BAAA,OAAA,sBAAA,OAAA,yBACbpC,EAAUkC,aAAaE,EAAaC,KAAMnB,UAAoB,SAACvD,GAClEC,QAAQC,qDAAsDF,GAE1DyD,GAAS,GACbE,EAAahC,KAAK3B,OACpB,OAAA,UAAA,0BACL,mBAAA,2CAGA2E,WAASC,qBAAsB,CAC5B,CACIC,MAAO,CACHtB,YAAAA,EACAuB,iBAAkB7B,GAEtB8B,eAAgB3C,EAAQsC,OAP9BM,IAaFC,EAAuBd,EAAcjG,eAAG,kBAAC,WAAOuG,GAAY,6BAAA,OAAA,sBAAA,OAAA,yBACrDpC,EAAU6C,cAAcF,EAAcP,EAAaC,aAAY,SAAC1E,GACnEC,QAAQC,4EACkEuE,EAAaC,KACnF1E,GAGAyD,GAAS,GACRE,EAAahC,KAAK3B,OACzB,OAAA,UAAA,0BACL,mBAAA,oCAACK,UAEI8E,EACF/C,EAAQsC,KACRnB,EACAzB,EACAO,EACAiB,EACM,CACIA,WAAAA,EACAO,YAAAA,EACAD,cAAAA,QAEJlD,UACF,SAACV,GACLC,QAAQC,MAAM,+DAAgEF,GAE1EyD,GAAS,GACRE,EAAahC,KAAK3B,MACzB,QAG6E,QAF7E6D,EAEEP,GAAYA,EAAWO,IAAgBD,EAAe,sBAAqBvD,UAEzE+E,EACFhD,EAAQsC,KACRxB,EAAemC,oBACf9B,EACAzB,EACAO,UACI,SAACrC,GACLC,QAAQC,MAAM,sEAAuEF,GACrF2D,EAAahC,KAAK3B,MACpB,QAEwE,GAAtEsD,GAAYA,EAAWO,IAAgBD,EAAe,kBAEtDT,YAAcO,IAAA4B,EAAUC,mBAAiBlF,UAAA,MAAA,OAAAA,UAExBgC,EAAUmD,gBAAgBvC,EAAaE,EAAWI,UAAmB,SAACvD,GAGnF,GAFAC,QAAQC,4DAA6DF,KAEjEyD,GAAS,GAEb,OADAE,EAAahC,KAAK3B,GACX0D,KACT,QANFA,SAAQrD,UAAA,MAAA,QASR8C,OAAYzC,EAAS,QAG0D,GAA/E4C,GAAYA,EAAWO,IAAgBD,EAAe,2BAEtDR,YAAeM,IAAA+B,EAAUC,2BAAyBrF,UAAA,MAAA,OAAAA,UAEjCgC,EACZsD,wBACG1C,EACAG,EAAWsC,0BACXtC,EAAWwC,wBACX,UAEG,SAAC5F,GAGJ,GAFAC,QAAQC,oEAAqEF,KAEzEyD,GAAS,GAEb,OADAE,EAAahC,KAAK3B,GACX0D,KACT,QAbNA,SAAQ,QAAA,OAAArD,UAeNhB,QAAQC,cAAQkF,EAAkBS,IAAsB,QAEc,GAAxE3B,GAAYA,EAAWO,IAAgBD,EAAe,oBAEtDP,GAAWhD,UAAA,MAAA,OAAAA,UACLwF,GAAwBzD,EAASN,EAAUO,UAAiB,SAACrC,GAC/DC,QAAQC,MACJ,qGACAF,GAEAyD,GAAS,GACbE,EAAahC,KAAK3B,MACpB,QAAA,KAGF2D,EAAamC,OAAS,IAACzF,UAAA,MAAA,MAAQsD,EAAY,QAAA,OAAAtD,UAGzCgC,EAAUO,cAAcmD,oBAAoB3D,EAAQsC,KAAM,CAC5DsB,cAAeC,gBAAcC,MAC/B,QAGkE,OAAhE5C,GAAYA,EAAWO,IAAgBD,EAAe,sCAAU,QAAA,UAAA,oCAAA,QAAA,mBAAAjD,UAAA,MAAA,4BAAA,QAAAA,UAAA,MAAA,QAKnD,OALmDA,UAAAA,gBAIpEV,QAAQC,2FAAyFuD,GACjGE,EAAe,2BAAE,QAhLPF,IAAO9C,SAAA,MAAA,QAAA,KAqLrB8C,GAAS,IAAC9C,UAAA,MACqD,MAA/DV,QAAQC,MAAM,kDACR,qBAAoB,QAGQ,OAAtCD,QAAQiE,IAAI,2BAA0BvD,UAChC0B,EAAU8D,aAAY,QAAA,yBACrB,CACHhD,UAAAA,EACA4B,eAAgB3C,EAASsC,KACzBnB,YAAaA,IAChB,QAAA,UAAA,+DACJ,SAOca,KAAyB,+BAmBxC,aAFC,OAEDgC,cAnBA,WAAyC/D,GAAoB,UAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAgE,SACtChE,EAAUiE,YAAW,OAA9B,MAANC,UACOT,OAAS,IAACO,SAAA,MAC8D,OAA/EpG,QAAQiE,IAAI,sFACLqC,EAAO,GAAGhD,aAAY,OAAA,OAAA8C,UAEDhE,EAAUmE,YAAYC,uBAAsB,SAACzG,GAErE,MADAC,QAAQC,MAAM,+BAAgCF,GACxCA,KACR,QAHiB,OAAf0G,SAAeL,UAKAhE,EAAUgC,YAAYsC,cAAa,QAA5C,OAANC,SAAMP,UACJhE,EAAUgC,YAAYwC,UAAU,CAAEC,YAAaF,EAAOE,YAAaC,aAAcH,EAAOG,eAAe,QAAA,OAAAV,UACvGhE,EAAUgC,YAAY2C,QAAO,GAAK,QAAA,yBAEjCN,EAAgBnD,aAAW,QAAA,UAAA,iDAEzC,SAWc6B,aAAgB,+BAAA,aA6E9B,OA7E8B6B,cAA/B,WACIlC,EACAmC,EACA3D,EACAzB,EACAO,GAAoB,6BAAA,OAAA,sBAAA,OAAA,yBAGbhD,QAAQC,IAAI,CAEf+C,EAAU8E,oBACN5D,EACAzB,EACA,CACItG,SAAUN,mBAAiBkM,IAC3BC,YAAa,mBACbtC,eAAAA,GAEJ,IAEJ9F,EAA0B6C,EAAU5G,mBAAiBoM,cAAc5H,MAAK,SAACnE,GAAI,OACzE8G,EAAU8E,oBACN5D,EACAhI,EACA,CACIC,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAaC,sBAC3B1C,eAAAA,GAEJ,CAAEA,eAAAA,GACF,CAAE2C,kBAAkB,EAAMC,cAAc,EAAOC,qBAAqB,OAI5E3I,EAA0B6C,EAAU5G,mBAAiB2M,SAASnI,MAAK,SAACnE,GAAI,OACpE8G,EAAU8E,oBACN5D,EACAhI,EACA,CACIC,SAAUN,mBAAiB2M,QAC3BN,aAAcC,eAAaC,sBAC3BK,gBAAiB,CAAC/C,IAEtB,OAGRgD,EACIjG,EACAyB,EACAwB,EACA7J,mBAAiBC,SACjBkH,GAEJ0F,EACIjG,EACAyB,EACAwB,EACA7J,mBAAiBE,cACjBiH,GAEJ0F,EACIjG,EACAyB,EACAwB,EACA7J,mBAAiBG,cACjBgH,GAEJA,EAAU8E,oBACN5D,EACA,CAAE2D,YAAAA,GACF,CACI1L,SAAUN,mBAAiB8M,WAC3BX,YAAa,oBAEjB,MAEL3H,MAAK,SAACuI,GAAS,OAAKA,EAAUxJ,WAAO,OAAA,UAAA,iDAC3C,SAEc0G,aAAiB,+BAoEhC,aAFC,OAED+C,cApEA,WACInD,EACAxB,EACAzB,EACAO,EACA8F,GAQC,cAAA,6BAAA,OAAA,sBAAA,OAEwC,OAFxCC,KAEoBjI,EAAoBiI,SAAQ7K,EAAgCuE,EAAU,gBAAe,OAAM,OAANsG,YAAE3J,OAAI2J,wBAAA,OAiD9G,OA/CIC,GAFAtH,UAEuB1C,QAAO,SAACiK,GAAG,QAAOA,KAE3CvH,EAAO+E,SAAWuC,EAAcvC,QAChC7F,QAAQC,MAAM,kEAGdqI,EAAkB,EAClBC,EAAiBH,EAAcvC,OAC/BqC,GACAA,EAAS7E,WAAW6E,EAAStE,YAAcsE,EAASvE,cAAe,eAAgB,CAC/E2E,gBAAAA,EACAC,eAAAA,IAGJC,EAAWJ,EAAcnK,KAAI,SAAC8C,GAC9B,OAAOqB,EACF8E,oBACG5D,EACAvC,EACA,CACIxF,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAakB,WAC3B3D,eAAAA,EACA4D,MAAO3H,EAAM2H,OAEjB,IAEHjJ,MAAK,WACF,GAAIyI,EAAU,GACRI,EACF,IAAIK,EACAC,KAAKC,MAGG,MAFFX,EAAStE,YAAc,GAAKsE,EAASvE,cACnCuE,EAAStE,YAAcsE,EAASvE,gBAEpC,IACRuE,EAAS7E,WACL6E,EAAStE,YAAcsE,EAASvE,cAC5BgF,GAAqBL,EAAkBC,GAC3C,eACA,CACID,gBAAAA,EACAC,eAAAA,6BAMjBnJ,QAAQC,IAAImJ,IAAS,QAAA,UAAA,0DAYVV,aAAmC,gCAsBzD,cAFC,OAEDgB,eAtBO,WACHjH,EACAyB,EACAwB,EACAvJ,EACA6G,GAAoB,6BAAA,OAAA,sBAAA,OAAA,yBAEbpD,EAA0B6C,EAAUtG,GAAyCkE,MAAK,SAACnE,GACtF,GAAwC,IAApCc,OAAO0C,KAAKxD,EAAKgB,QAAQuJ,OAC7B,OAAOzD,EAAU8E,oBACb5D,EACAhI,EACA,CACIC,SAAAA,EACA+L,aAAcC,eAAaC,sBAC3BK,gBAAiB,CAAC/C,IAEtB,QAEN,OAAA,UAAA,0DAOgBiE,MAAmC,gCAkBzD,cAFC,OAEDC,eAlBO,WAAmDnH,GAAsB,6BAAA,OAAA,sBAAA,OAAA,yBAKrEzC,QAAQC,IAAI,CACfL,EAA0B6C,EAAU5G,mBAAiBC,UACrD8D,EAA0B6C,EAAU5G,mBAAiBE,eACrD6D,EAA0B6C,EAAU5G,mBAAiBG,iBACtDqE,MAAK,YACJ,MAAO,CACHwJ,iCACAC,sCACAC,2CAEN,OAAA,UAAA,iDASN,SAAsBvD,UAAuB,gCA8D5C,cAAA,OAAAwD,eA9DM,WAAuCjH,EAAkBN,EAAwBO,GAAoB,kBAAA,6BAAA,OAAA,sBAAA,OAMvG,OALGiH,EAAe,CACT,CACF5L,KAAM,kBACNoD,MAAOsB,EAAQmH,UAEtBC,SAGSR,GAAoClH,GAAS,OAkDtD,OAnDoCqH,GACkBM,UADlBN,iCAAkCC,IAAAA,iCAGjEM,EAAepO,EACjBa,IAJI+M,6BAKJhO,mBAAiBC,UAEfwO,EAAoBrO,EACtBa,EAAegN,GACfjO,mBAAiBE,eAEfwO,EAAoBtO,EACtBa,EAAeiN,GACflO,mBAAiBG,eAGrBiO,EAAM3H,KACI,CACFjE,KAAM,aACNoD,MAAO4I,EAAa/N,WAElB,CACF+B,KAAM,YACNoD,MAAO4I,EAAa7N,OAIxB8N,EAAkBhO,WAAagO,EAAkB9N,MACjDyN,EAAM3H,KACI,CACFjE,KAAM,aACNoD,MAAO6I,EAAkBhO,WAEvB,CACF+B,KAAM,YACNoD,MAAO6I,EAAkB9N,OAKjC+N,EAAkBjO,WAAaiO,EAAkB/N,MACjDyN,EAAM3H,KACI,CACFjE,KAAM,aACNoD,MAAO8I,EAAkBjO,WAEvB,CACF+B,KAAM,YACNoD,MAAO8I,EAAkB/N,OAGpC2N,UAEKnH,EAAUwH,aAAaC,MAAM1H,EAAQsC,KAAM4E,GAAM,QAAA,UAAA,0DCvjB3CS,GAAcC,EAA0BC,GACpD,OAAOD,EACF9L,KAAI,SAAA2G,GACD,GAAIA,EAAMqF,mBAAqBrF,EAAMtB,YACjC,IACIsB,EAAMtB,YAAc4G,YAChBF,EAAOG,qBAAqBvF,EAAMqF,mBAExC,MAAO3K,GACLU,QAAQC,MAAM,yEAA0EX,GAGhG,OAAOsF,KAEVxG,QAAO,SAAAwG,GAAK,OAAIA,EAAMtB,wBAWf8G,GAA4BC,EAAkDL,GAC1F,OAAOK,EACFpM,KAAI,SAAAoM,GACD,IACI,MAAO,EAAC,EAAOL,EAAOM,oBAClBD,EAA0BE,qBACJ3F,OAC5B,MAAMtF,GAEJ,OADAU,QAAQC,MAAM,iEAAkEX,GACzE,EAAC,OAAOmB,OAGtBrC,QAAO,SAAAoM,GAAW,OAAIA,EAAY,MAClCvM,KAAI,SAAAwM,GAAW,OAAIA,EAAY,eCqFlBC,cAAY,gCA8GjC,cAAA,OAAAC,eA9GM,WACH1H,EACA2H,EACAxI,EACAgB,EACAC,GAIS,oBAAA,6BAAA,OAAA,sBAAA,gBALTD,IAAAA,GAAuB,GAOnBI,EAnIY,GAoIZE,EAAwB,GACxBmH,OAAkCpK,EAEhCkD,EAAgB,EAAC,OAAA,KAGhBH,EAAQ,IAAC7F,UAAA,MAKR,OALQA,SAERiG,EAAc,EAEVP,GAAYA,EAAWO,IAAgBD,EAAe,kBAC1DhG,UACmBsE,EAAmCgB,EAAgBb,GAAU,QAEF,GAF9EyI,SAEIxH,GAAYA,EAAWO,IAAgBD,EAAe,qBACrDL,GAAW3F,UAAA,MAAA,OAAAA,UAAuByE,EAAUiE,YAAW,QAA1C/C,SAA4C,GAAGA,YAAW,QAEG,OAA3ED,GAAYA,EAAWO,IAAgBD,EAAe,sBAAqBhG,UACzEyE,EACD8E,oBACG5D,EACAsH,EACA,CACIrP,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAaC,sBAC3B1C,eAAgB+F,EAAWpG,MAE/B,GACA,CAAEgD,kBAAkB,EAAMC,cAAc,EAAOC,qBAAqB,WAEjE,SAAC5H,GACJC,QAAQC,MACJ,oFACAF,GAEJ2D,EAAahC,KAAK3B,MACpB,QAAA,IAEFqD,GAAWzF,UAAA,MAEX,OADI0F,GAAYA,EAAWO,IAAgBD,EAAe,iCAC1DhG,UACoCyE,EAAU0I,mBAC1CxH,EACA,CAAE/H,SAAUN,mBAAiBkM,IAAKrC,eAAgB7B,EAAe8H,aACjE,GACH,QAJ0B,MAAvBC,WAK2BA,EAAwBnF,OAAS,IAAClI,UAAA,MAAA,OAAAA,UACjCyE,EAAU6I,YAClC3H,EACA0H,EAAwB,GAAGE,UAC9B,QAC2E,OAJxEC,SAIA9H,GAAYA,EAAWO,IAAgBD,EAAe,mBAAkBhG,UACtEiI,GAAwBiF,EAAYM,EAAiB/I,UAAiB,SAACrC,GACzEC,QAAQC,MACJ,oHACAF,GAEAyD,GAAS,GACbE,EAAahC,KAAK3B,MACpB,QAAApC,UAAA,MAAA,QAEFqC,QAAQC,MAAM,+EACdyD,EAAahC,KAAK3E,MAAM,sBAAqB,QAAA,KAIjD2G,EAAamC,OAAS,IAAClI,UAAA,MAAA,MAAQ+F,EAAY,QAAA,OAAA/F,UAGzCyE,EAAUO,cAAcmD,oBAAoB+E,EAAWpG,KAAM,CAC/DsB,cAAeC,gBAAcC,MAC/B,QAGkE,OAAhE5C,GAAYA,EAAWO,IAAgBD,EAAe,WAAUhG,UAE9DyE,EAAU8D,aAAY,QAAA,4BAAA,QAMX,OANWvI,UAAAA,gBAG5BqC,QAAQC,0GAC8FuD,GAEtGE,EAAe,2BAAE,QA5EPF,IAAO7F,SAAA,MAAA,QAAA,KAgFrB6F,GAAS,IAAC7F,UAAA,MACoE,MAA9EqC,QAAQC,MAAM,iEACR,qBAAoB,QAAA,GAGzB4K,GAAUlN,UAAA,MACmE,MAA9EqC,QAAQC,MAAM,iEACR,qBAAoB,QAGY,OAA1CD,QAAQiE,IAAI,iDACL4G,GAAU,QAAA,UAAA,wECzOCO,QAA+B,gCAkBpD,cAAA,OAAAC,eAlBM,WACHjJ,EACAhE,GAAgC,YAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAT,SAEbyE,EAAUiE,YAAW,OACpCiF,EAAiB,GAAEC,YACC,OAAA,iBAAA5N,UAAA,MAAV,OAALiH,UAAKjH,SAEiCyE,EAAUmE,YAAYiF,mBAAmB5G,EAAMtB,YAAc,CAAC,kBAAmB,GAAI,CAC5H/H,SAAUN,mBAAiBoM,aAC3BvC,eAAgB1G,EAAO0G,iBACzB,cAEiC,GAAGe,QAAU,GAC5CyF,EAAe5J,KAAKkD,GAAM,QAAAjH,SAAA,MAAA,QAAA,yBAG3B2N,GAAc,QAAA,UAAA,qDC2CZG,cAgBT,WACYC,EACDC,EACApF,EACAnC,EACAwF,EACAvH,EACAM,EACAiJ,EACAC,EACCC,GATAC,aAAAL,EACDK,kBAAAJ,EACAI,iBAAAxF,EACAwF,iBAAA3H,EACA2H,kBAAAnC,EACAmC,oBAAA1J,EACA0J,mBAAApJ,EACAoJ,oBAAAH,EACAG,qBAAAF,EACCE,4BAAAD,EAxBJC,aAGF,GACEA,0BAEJ,GAEIA,oBAEJ,GAiBJ,kBAq8CC,OAr8CDC,EAGa9F,WAAU,WAAA,kBAAhB,aAAA,6BAAA,OAAA,sBAAA,OACH6F,KAAKE,qBAAuB,GAC5BF,KAAKG,eAAiB,GAAE,OAAA,UAAA,+BAC3B,OAAA,WAAA,gCAHsB,GAKvBF,EAWaG,OAAM,WAAA,kBAAZ,WACHC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,GAA6B,oBAAA,6BAAA,OAAA,sBAAA,OAwB5B,OAtBDX,KAAKY,IAAM,IAAIC,YACTC,EAAad,KAAKY,cAElBG,EAAqBf,KAAKL,QAAQqB,aAAaC,eAAeX,GAC9DY,EAAmBH,EAAmBI,4BAA4BL,GAElEM,EAAiBpB,KAAKL,QAAQ0B,mBAAmBrB,KAAKL,QAAQ0B,mBAAmBf,IAEvFD,EAAQA,EAAMiB,cAERC,EAAyBb,EAAgB,CAAEL,MAAAA,QAA4C3L,EAEvF8M,EAAuC,CACzCC,aAAclB,EAAS7H,KACvB2H,MAAAA,EACAqB,iBANqBf,EAOrBL,SAAUc,EACVO,UAAW3B,KAAKL,QAAQiC,eAAe5B,KAAKY,cAC5CM,iBAAAA,EACAV,mBAAAA,EACAC,UAAAA,EACAc,uBAAAA,GACHpO,UAEsB6M,KAAK3H,YAAYwJ,eAAeL,GAAc,QASpE,OATK9J,UAEOoK,gBAELC,EAAoB/B,KAAKL,QAAQqB,aAAaC,eAAevJ,EAASoK,eAC1EE,eAAeC,QACXrR,EAA2B8G,EAAS7G,IACpCkR,EAAkBZ,4BAA4BL,uBAI/CpJ,GAAQ,QAAA,UAAA,+BAClB,OAAA,wBAAA,gCA7CkB,GA+CnBuI,EAKaiC,aAAY,WAAA,kBAAlB,WAAmBpH,GAAmB,6BAAA,OAAA,sBAAA,OACE,OAA3CkF,KAAK3H,YAAYwC,UAAU,CAAEC,YAAAA,IAAczG,SACtB2L,KAAK3H,YAAY2C,SAAQ,OAAlC,yBACLgF,KAAK3H,YAAY8J,sBAAsBC,IAAK,CAC/CV,gBAAgB,KAClB,OAAA,UAAA,+BACL,OAAA,YAAA,gCANwB,GAQzBzB,EAUaoC,OAAM,WAAA,kBAAZ,WAAaZ,EAAoBpB,EAAeC,EAAkBgC,GAAY,UAAA,6BAAA,OAAA,sBAAA,OAOhF,OANKlB,EAAiBpB,KAAKL,QAAQ0B,mBAAmBrB,KAAKL,QAAQ0B,mBAAmBf,IACjFiC,EAAiC,CACnCd,aAAAA,EACApB,MAAOA,EAAMiB,cACbhB,SAAUc,EACVkB,IAAAA,GACH3N,SAEKqL,KAAK3H,YAAYmK,UAAUD,GAAa,OAAA,OAAA5N,SACtBqL,KAAK3H,YAAY2C,SAAQ,OAAK,OAAhDyH,SAA6CL,IAAGzN,SAGhDqL,KAAK0C,8BAA8BD,EAAUnC,GAAS,OAAA,OAAA3L,UAC/CqL,KAAK3H,YAAYC,YAAYmK,GAAS,QAAA,iCAAA,QAAA,UAAA,+BACtD,OAAA,kBAAA,gCAfkB,GAiBnBxC,EAIa0C,cAAa,WAAA,kBAAnB,aAAA,cAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAtI,SACe2F,KAAK3H,YAAY2C,SAAQ,OACmC,OADxEnK,SAAuCuR,IACvCQ,EAAkBZ,eAAea,QAAQjS,EAA2BC,IAAIwJ,SACnD2F,KAAK3H,YAAYC,YAAYzH,GAAG,OAAe,IAApEiS,SAAuDhB,gBAExCc,GAAevI,SAAA,MAAA,MAAQvJ,EAAwB,OAE9DiS,EAAqB/C,KAAKL,QAAQqB,aAAaC,eAAe6B,GAChEhC,EAAaiC,EAAmBC,4BAA4BJ,GAChE5C,KAAKY,IAAMZ,KAAKL,QAAQkB,UAAUoC,QAAQnC,GAAW,QAAA,UAAA,+BACxD,OAAA,WAAA,gCAVyB,GAY1Bb,EAOOiD,0BAAA,SAA0BpO,GAC7B,IAAKkL,KAAKY,IAKN,MAJIZ,KAAKD,wBACLC,KAAKD,uBAAuB,IAAIjP,GAG9B,IAAIA,EAGd,IAAMqS,EAAY,IAAInD,KAAKL,QAAQqB,aAKnC,MAAO,CAAEoC,cAHaD,EAAUE,2BAA2BvO,GAGnCwO,aAFHtD,KAAKL,QAAQiC,eAAe5B,KAAKY,IAAI2C,eAAeJ,EAAUK,UAKvFvD,EAOOwD,wBAAA,gBAA0BH,IAAAA,aAAcF,IAAAA,cAC3C,IAAKpD,KAAKY,IAKN,MAJIZ,KAAKD,wBACLC,KAAKD,uBAAuB,IAAIjP,GAG9B,IAAIA,EAGd,IAAMqS,EAAYnD,KAAKY,IAAIxC,qBAAqBkF,GAGhD,OAFsBtD,KAAKL,QAAQqB,aAAaiC,QAAQE,GAAWO,2BAA2BN,IAKlGnD,EAGa0D,QAAO,WAAA,kBAAb,aAAA,6BAAA,OAAA,sBAAA,OAMD,OALF3D,KAAKY,SAAMlM,EACXsL,KAAK4D,QAAU,GACf5D,KAAK3H,YAAYwC,UAAU,CACvBC,iBAAapG,EACbqG,kBAAcrG,IAChBmP,SACI7D,KAAK3H,YAAYyL,aAAY,OAAA,UAAA,+BACtC,OAAA,WAAA,gCARmB,GAUpB7D,EAmBalJ,gBAAe,WAAA,kBAArB,WACHE,EACAb,EACAN,EACAsB,EAIAC,EACAC,GAA+D,6BAAA,OAAA,sBAAA,OADpC,YAA3BD,IAAAA,GAAuB,GAGlB2I,KAAKY,KAAGxE,SAAA,MAAA,MAAQtL,EAAwB,OAAA,yBACtCiG,EACHE,EACAb,EACAN,EACAkK,KACAA,KAAKL,QAAQjH,OACbtB,EACAC,EACAC,IACH,OAAA,UAAA,+BACJ,OAAA,sBAAA,gCAtB2B,GAwB5B2I,EAUatB,aAAY,WAAA,kBAAlB,WACHvI,EACAyI,EACAxH,EACAC,GAA+D,6BAAA,OAAA,sBAAA,OADpC,YAA3BD,IAAAA,GAAuB,GAGlB2I,KAAKY,KAAGmD,SAAA,MAAA,MAAQjT,EAAwB,OAAA,yBACtC6N,GAAavI,EAASyI,EAAyBmB,KAAM3I,EAAaC,IAAW,OAAA,UAAA,+BACvF,OAAA,kBAAA,gCARwB,GAUzB2I,EAIa+D,wBAAuB,WAAA,kBAA7B,aAAA,IAAAC,WAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAzG,SACgBwC,KAAK1F,YAAW,OAAzB,OAANC,SAAMiD,SAE6CnK,QAAQC,IAC3DiH,EAAOrI,eAAG,kBACN,WAAO2G,GAAY,6BAAA,OAAA,sBAAA,OAAA,OAAAqL,SACTC,EAAK3J,YACNiF,mBACG5G,EAAMtB,YACN,CAAC,kBACD,GACA,CAAE/H,SAAUN,mBAAiBoM,cAC7BzC,EAAMC,kBAETpF,MAAK,SAAC0Q,GACH,IACI,OAAOA,EAAS,GAAGlS,KAAI,SAACkE,GACpB,YACOA,GACHyC,MAAO,CACHC,iBAAkBD,EAAMC,iBACxBvB,YAAasB,EAAMtB,kBAIjC,MAAOhE,GAEL,MAAO,cAGR,WAAA,MAAM,MAAG,OAAA,iCAAA,OAAA,UAAA,0BAAA,mBAAA,qCAE9BG,MAAK,SAAC0Q,GAAQ,OAAKA,EAAS3R,UAAO,OACrCuN,KAAK9G,sBACAP,WAAS2C,yBAET5H,MAAK,WAAA,OAAM2Q,MAAM,iDACX,WAAA,OAAMpQ,QAAQC,MAAM,kCAA+B,OAAA,UAAA,+BACjE,OAAA,WAAA,gCAtCmC,GAwCpC+L,EAMa/G,cAAa,WAAA,kBAAnB,WAAoB5I,EAAqBgU,GAAqB,cAAA,6BAAA,OAAA,sBAAA,OAAA,GAC5DtE,KAAKY,KAAG2D,SAAA,MAAA,MAAQzT,EAAwB,OAAA,IAGzCwT,GAAcC,SAAA,MAAA,OAAAA,SACsBvE,KAAK3H,YAAYC,YAAYgM,GAAe,OAChFE,EAASxE,KAAKL,QAAQ8E,wBAD4D9C,WACpB4C,UAAA,MAAA,OAE9DC,EAASxE,KAAKY,aAAY,QAG1B8D,EAAsC,GAAEC,MAEtBtU,OAAO0C,KAAKzC,GAAQ,QAAA,kBAAAiU,UAAA,MACCA,KAAnCf,OACOe,cACF5L,WAASC,0BAAmB,MAAA,QAoBxB,OAnBL8L,EAAelB,GAAQlT,EAAQkT,GAC1BtR,KAAI,SAACqB,GAAC,YACAA,GACHqR,WAAYrR,EAAEwF,oBAEjB7G,KACG,SAACqB,GAAsB,MAClB,CACGmF,KAAMnF,EAAEmF,KACRmM,UAAWtR,EAAEsR,UACbD,WAAYrR,EAAEqR,WACdpG,oBAAqBqC,YAAUiE,2BAC3B,CACI/L,eAAgBxF,EAAEwF,eAClBF,MAAOtF,EAAEsF,OAEb2L,4BAGf,QAAAG,IAAAJ,UAAA,MAAA,QAAA,OAAAA,UAIXvE,KAAKxF,YAAYuK,cAAcL,EAAgBJ,GAAe,QAAA,UAAA,+BACvE,OAAA,cAAA,gCAzCyB,GA2C1BrE,EAOa1H,aAAY,WAAA,kBAAlB,WAAmByM,EAAmBzN,EAAmBuB,GAAuB,YAAA,6BAAA,OAAA,sBAAA,OAAA,GAC9EkH,KAAKY,KAAGqE,SAAA,MAAA,MAAQnU,EAAwB,OAAA,OAAAmU,SAEzBjF,KAAKkF,uBAAuB3N,EAAauB,GAAiB,OAAK,OAA/EqM,SAA4E3B,MAAGyB,SAC/CjF,KAAK3H,YAAYC,YAAY0M,GAAY,OAO5E,OANGI,EAAmBpF,KAAKL,QAAQ8E,wBAD2C9C,WAG3E0D,EAAyBxE,YAAUyE,4BAA4BH,EAAQC,GACvEG,EAA+B,CAC/BC,gBAAiBH,EACjBL,YAAaA,GAChBC,UACKjF,KAAKxF,YAAYiL,aAAalO,EAAagO,EAASzM,GAAiB,QAAA,UAAA,+BAC9E,OAAA,gBAAA,gCAbwB,GAezBmH,EAUayF,kBAAiB,WAAA,kBAAvB,WACHnO,EACAoO,EACA5M,EACAD,EACA8M,EACAC,8EAAyE,YAAzEA,IAAAA,EAA4C,CAAEjK,qBAAqB,IAE9DoE,KAAKY,KAAGkF,SAAA,MAAA,MAAQhV,EAAwB,OAAA,OAAAgV,SAEd9F,KAAKkF,uBAAuB3N,EAAauB,GAAiB,OAG5C,OADzCsK,GAFArC,UAEmCsC,2BAA2BsC,GAAQG,KAC/C/E,EAAkB+E,UAC1B9F,KAAK3H,YAAY2C,SAAQ,QAc3C,OAd2C8K,YAAE1D,IAAG0D,MAA7CC,aADAC,OAA0C3C,6DAiBvCrD,KAAKJ,aAAaqG,iBAAiB1O,EANR,CAC9BhI,KAAM6T,EACN8C,eATO,CACPnN,eAAAA,EACAvJ,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa2K,QAC3B9K,YAAa,cAMb+K,gBAAiBJ,GAG2ClN,EAAkB8M,EAAkBC,IAAQ,QAAA,UAAA,+BAC/G,OAAA,sBAAA,gCA/B6B,GAiC9B5F,EAUaoG,4BAA2B,WAAA,kBAAjC,WACH9O,EACAhI,EACAwJ,EACAD,EACA8M,EACAC,8EAAyE,YAAzEA,IAAAA,EAA4C,CAAEjK,qBAAqB,IAE9DoE,KAAKY,KAAG0F,SAAA,MAAA,MAAQxV,EAAwB,OAAA,OAAAwV,SAEdtG,KAAKkF,uBAAuB3N,EAAauB,GAAiB,OACR,OAD3DwN,KAAlBvF,SACkCuF,KAAiCC,WAAUD,UAAO/W,EAAKiX,cAAa,QAC7D,OAD6DF,YAAAA,oBAAtGlD,OAAmCjC,4CAA2BmF,KACvCvF,EAAkBuF,UAC1BtG,KAAK3H,YAAY2C,SAAQ,QAiB3C,OAjB2CsL,YAAElE,IAAGkE,KACnC/W,EAAKM,KAAIyW,KACL/W,EAAKkX,aAAYH,KACzB/W,EAAKmX,KAAIJ,MAHfP,YACAY,cACAF,kBACAC,WAJAV,OAA0C3C,6DAoBvCrD,KAAKJ,aAAaqG,iBAAiB1O,EANR,CAC9BhI,KAAM6T,EACN8C,eATO,CACPnN,eAAAA,EACAvJ,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa2K,QAC3B9K,YAAa9L,EAAKqX,MAMlBR,gBAAiBJ,GAG2ClN,EAAkB8M,EAAkBC,IAAQ,QAAA,UAAA,+BAC/G,OAAA,sBAAA,gCAjCuC,GAmCxC5F,EAYa4G,iCAAgC,WAAA,kBAAtC,WACHtP,EACAhI,EACAwJ,EACAwC,EACAzC,EACA8M,EACAC,oEAGC,YAHDA,IAAAA,EAAuE,CACnEnK,kBAAkB,EAClBE,qBAAqB,IAGpBoE,KAAKY,KAAGkG,SAAA,MAAA,MAAQhW,EAAwB,OAI3B,OAJ2BgW,KAEtC9G,KAAI8G,KACPvP,EAAWuP,KACPP,WAAUO,SAAOvX,EAAKiX,cAAa,OAMtC,OANsCM,YAAAA,oBAAAA,KACvC,CACI/N,eAAAA,EACAvJ,SAAUN,mBAAiBoM,aAC3BC,aAAAA,EACAF,YAAa9L,EAAKqX,MACrBE,UAEkB9G,KAAK3H,YAAY2C,SAAQ,QAKrC,OALqC8L,YAAE1E,IAAG0E,KACnCvX,EAAKM,KAAIiX,MADnBf,YACAY,eAAQG,KAEZhO,EAAgBgO,MAChBlB,EAAgBkB,MAChBjB,yBAfQkB,iEAAe,QAAA,UAAA,+BAiB9B,OAAA,wBAAA,gCA/B4C,GAiC7C9G,EAYa+G,eAAc,WAAA,kBAApB,WACHzP,EACAhI,EACA0X,EACAC,EACApO,EACA8M,EACAC,gFAGC,YAHDA,IAAAA,EAAuE,CACnEnK,kBAAkB,EAClBE,qBAAqB,IAGpBoE,KAAKY,KAAGuG,SAAA,MAAA,MAAQrW,EAAwB,OAAA,OAAAqW,SAEdnH,KAAKkF,uBAAuB3N,EAAauB,GAAiB,OAQxF,GAPGsK,GADArC,UACmCsC,2BAA2B9T,GAC9DyW,EAAuBjF,EAAmBsC,2BAA2B6D,GAErE3B,EAA8B,CAC9BhW,KAAM6T,EACN8C,eAAgBe,EAChBb,gBAAiBJ,IAEjBH,EAAQnK,kBAAgByL,UAAA,MAAA,yBACjBnH,KAAKJ,aAAaqG,iBAAiB1O,EAAagO,EAASzM,EAAkB8M,EAAkBC,IAAQ,QAAA,yBACpG7F,KAAKxF,YAAYyL,iBAAiB1O,EAAagO,EAASzM,EAAkB8M,IAAiB,QAAA,UAAA,+BAC1G,OAAA,wBAAA,gCA1B0B,GA4B3B3F,EAUa9E,oBAAmB,WAAA,kBAAzB,WACH5D,EACAhI,EACA2W,EACAE,EACAP,0EAIC,gBAJDA,IAAAA,EAA8F,CAC1FnK,kBAAkB,EAClBC,cAAc,EACdC,qBAAqB,IACxBwL,SAEoBpH,KAAKxF,YAAY6M,mBAAmB9P,EAAa2O,GAAe,OAAzE,GAARoB,SACCzB,EAAQlK,gBAAgB2L,EAASxN,OAAS,IAACsN,SAAA,MAC+B,OAA3EnT,QAAQiE,oBAAoBqP,KAAKC,UAAUtB,uCACpCoB,EAAS,GAAGnI,UAAQ,OAAA,OAAAiI,UAGjBpH,KAAKgH,eACPzP,EACAhI,EACA2W,EACAE,OACA1R,EAEAmR,EAAQlK,cAAgB2L,EAASxN,OAAS,EAAIwN,EAAS,GAAGnI,cAAWzK,EACrEmR,UACI,SAAC7R,GAEL,MADAC,QAAQC,oCAAoCqT,KAAKC,UAAUtB,WAAwBlS,GAC7EA,KACR,QAAA,gCACJmL,UAAQ,QAAA,UAAA,+BACjB,OAAA,oBAAA,gCA/B+B,GAiChCc,EAYa8G,gBAAe,WAAA,kBAArB,WACHxP,EACAhI,EACA0X,EACAC,EACApO,EACA8M,EACAC,gFAGC,YAHDA,IAAAA,EAAuE,CACnEnK,kBAAkB,EAClBE,qBAAqB,IAGpBoE,KAAKY,KAAG6G,SAAA,MAAA,MAAQ3W,EAAwB,OAAA,OAAA2W,SACdzH,KAAKkF,uBAAuB3N,EAAauB,GAAiB,OAQxF,GAPGsK,GADArC,UACmCI,4BAA4B5R,GAC/DyW,EAAuBjF,EAAmBsC,2BAA2B6D,GAErE3B,EAA8B,CAC9BhW,KAAM6T,EACN8C,eAAgBe,EAChBb,gBAAiBJ,IAEjBH,EAAQnK,kBAAgB+L,UAAA,MAAA,yBACjBzH,KAAKJ,aAAaqG,iBAAiB1O,EAAagO,EAASzM,EAAkB8M,EAAkBC,IAAQ,QAAA,yBACpG7F,KAAKxF,YAAYyL,iBAAiB1O,EAAagO,EAASzM,EAAkB8M,IAAiB,QAAA,UAAA,+BAC1G,OAAA,wBAAA,gCAzB2B,GA2B5B3F,EAWaf,YAAW,WAAA,kBAAjB,WAA2B3H,EAAmB4H,EAAgBrG,GAAuB,MAAA,6BAAA,OAAA,sBAAA,OAAA,GACnFkH,KAAKY,KAAG8G,SAAA,MAAA,MAAQ5W,EAAwB,OAAA,OAAA4W,SAEMrU,QAAQC,IAAI,CAC3D0M,KAAKxF,YAAYmN,eAAepQ,EAAa4H,EAAUrG,GACvDkH,KAAKkF,uBAAuB3N,EAAauB,KAC3C,OAHuC,0BAGvC8O,aAEwBlE,gCAA4CnU,OAAK,OAAA,UAAA,+BAC9E,OAAA,gBAAA,gCATuB,GAUxB0Q,EAOa4H,aAAY,WAAA,kBAAlB,WAAmBtQ,EAAmB4H,EAAgBrG,GAAuB,MAAA,6BAAA,OAAA,sBAAA,OAAA,GAC3EkH,KAAKY,KAAGkH,SAAA,MAAA,MAAQhX,EAAwB,OAAA,OAAAgX,SAEMzU,QAAQC,IAAI,CAC3D0M,KAAKxF,YAAYmN,eAAepQ,EAAa4H,EAAUrG,GACvDkH,KAAKkF,uBAAuB3N,EAAauB,KAC3C,OAHuC,0BAGvCiP,aAEwB/E,iCAA6CzT,OAAK,OAAA,UAAA,+BAC/E,OAAA,gBAAA,gCATwB,GAWzB0Q,EAUa3F,UAAS,WAAA,kBAAf,WAAgBjI,GAAiC,gBAAA,6BAAA,OAAA,sBAAA,OAAA,GAC/C2N,KAAKY,KAAGoH,SAAA,MAAA,MAAQlX,EAAwB,OAG7C,GADImX,EAAeV,KAAKC,UAAUnV,IAE9B2N,KAAKE,qBAAqB+H,IAAaD,SAAA,MAAA,yBAAShI,KAAKE,qBAAqB+H,IAAa,OAAA,OAAAD,SAG5DhI,KAAKkI,iBAAgB,OAA9B,GACY,KAD9BC,UACmBrO,QAAgBqO,EAAmB,KAAOC,gBAAcC,MAAIL,UAAA,MAAA,yBAAS,IAAE,QAAA,IAG1F,CAACI,gBAAcE,QAASF,gBAAcC,MAAM7S,OAAM,SAAC+S,GAAY,OAC3DJ,EAAmBhT,SAASoT,OAC/BP,UAAA,MAAA,IAIG3V,GAAM2V,UAAA,MAAA,OAAAA,UACkB3I,GAAgCW,KAAM3N,GAAO,QAArE2L,SAAegK,UAAA,MAAA,QAAA,OAAAA,UAEUhI,KAAKxF,YAAYgO,YAAW,QAArDxK,SAAuDzD,OAAM,QAAA,OAAAyN,UAEnCjK,GAAcC,EAAiBgC,KAAKY,KAAI,QAGnB,OADnDZ,KAAKE,qBAAqB+H,GAFpBQ,SAGNxU,QAAQyU,KAAK,yDACND,GAAe,QAAA,GAGrBpW,GAAM2V,UAAA,MAAA,MAAQ9W,EAAkB,QAAA,OAAA8W,UAEAhI,KAAKxF,YACrCmO,cAAc,CAAChQ,WAASC,qBAAsB,CAACvG,EAAO0G,iBACtDrF,MAAK,SAACZ,GAAG,OAAKA,EAAI6F,WAASC,+BACrB,SAACrF,GAEJ,OADAU,QAAQC,MAAMX,GACP,MACT,QAEuF,MAAvFqV,EAAoBvK,UARpBwK,UAQgDA,EAA0B,GAAI7I,KAAKY,MACnE9G,OAAS,IAACkO,UAAA,MAE+B,OAD3D/T,QAAQyU,KAAK,iEACb1I,KAAKE,qBAAqB+H,GAAgBW,oBACnC5I,KAAKE,qBAAqB+H,IAAa,QAAA,yBAI3C,IAAE,QAAA,UAAA,+BACZ,OAAA,YAAA,gCAjDqB,GAmDtBhI,EAKMiI,eAAc,WAAA,kBAApB,aAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAY,SACkB9I,KAAK3H,YAAY2C,SAAQ,OAAA,gCAAE+N,MAAMC,MAAM,MAAG,OAAA,UAAA,+BAC3D,OAAA,WAAA,gCAFmB,GAIpB/I,EAOMiF,uBAAsB,WAAA,kBAA5B,WAA6B3N,EAAqBuB,GAAyB,UAAA,6BAAA,OAAA,sBAAA,OAAA,GAClEkH,KAAKY,KAAGqI,SAAA,MAAA,MAAQnY,EAAwB,OAEqC,IACnE,KADXgN,EAAQkC,KAAK4D,QAAQsF,WAAU,SAAC/D,GAAM,OAAKA,EAAO5N,cAAgBA,OACtD0R,UAAA,MAAA,OAAAA,SACiBjJ,KAAKxF,YAAY2O,iBAAiB5R,EAAauB,GAAiB,OAIlD,OAFvCqM,EAASnF,KAAKY,IAAIxC,4BAFyEgL,cAG3FC,EAAUrJ,KAAKL,QAAQqB,aAAaiC,QAAQkC,GAChDnF,KAAK4D,QAAQjO,KAAK,CAAE4B,YAAAA,EAAa8R,QAAAA,sBAC1BA,GAAO,QAAA,yBAEPrJ,KAAK4D,QAAQ9F,GAAOuL,SAAO,QAAA,UAAA,+BAEzC,OAAA,cAAA,gCAd2B,GAgB5BpJ,EASaqJ,qCAAoC,WAAA,kBAA1C,WACHvQ,EACAvJ,EACAqW,oEAA4D,gBAA5DA,IAAAA,EAAqC,CAAE0D,cAAc,sBAE9CvJ,KAAKwJ,6BAA6BzQ,EAAgBvJ,EAAUqW,IAAQ,OAAA,UAAA,+BAC9E,OAAA,gBAAA,gCANgD,GAQjD5F,EAQawJ,4BAA2B,WAAA,kBAAjC,WACH1Q,EACA8M,oEAA4D,gBAA5DA,IAAAA,EAAqC,CAAE0D,cAAc,sBAE9CvJ,KAAKwJ,6BAA6BzQ,EAAgB7J,mBAAiB2M,QAASgK,IAAQ,OAAA,UAAA,+BAC9F,OAAA,cAAA,gCALuC,GAKvC5F,EAEauJ,wCAA4B,kBAAlC,WACJzQ,EACAvJ,EACAqW,yFAA4D,gBAA5DA,IAAAA,EAAqC,CAAE0D,cAAc,IAAOG,SAEzC1J,KAAK1F,UAAU,CAAEvB,eAAAA,IAAiB,OAAjDwB,SACA9I,EAAuD,GAAEkY,yBAAA,QAAA,6BAAA,OAAA,sBAAA,OAC/C,OAAL9Q,UAAK+Q,SACWC,EAAK9K,mBACtBlG,EAAMtB,YACN,CACI/H,SAAAA,EACA+L,aAAcC,eAAaC,sBAC3BK,gBAAiB,CAAC/C,KAEtB,EACAF,EAAMC,iBACN+M,GACH,OAVW,GAaY,KAbpByB,UAaSxN,QAAY8P,SAAA,MAAA,OAAAA,SAEXC,EAAK9K,mBACPlG,EAAMtB,YACN,CACI/H,SAAAA,EACA+L,aAAcC,eAAaC,wBAG/B,EACA5C,EAAMC,iBACN+M,GACH,OAXLyB,SAYEjV,QAAO,SAACyX,GAAK,OAAMA,EAAMC,SAASjO,mBAAe,OAAA,OAAA8N,UAEtCvW,QAAQC,IACrBgU,EAASpV,eAAG,kBAAC,WAAO4X,GAAK,6BAAA,OAAA,sBAAA,OAIO,OAJPE,KAECnR,EAAMC,iBAAgBkR,KAC3BnR,EAAMtB,YAAYyS,KACrBF,EAAM3K,SAAQ6K,SACZH,EAAK3K,YAAmCrG,EAAMtB,YAAcuS,EAAM3K,UAAS,OAAA,OAAA6K,+BAHvFlR,sBACAvB,iBACA4H,cACA5P,YAAI,OAAA,UAAA,0BAEX,mBAAA,qCACJ,QACDkC,OAAoBA,UAAuB,QAAA,UAAA,yBAAA+N,IAvC7BjF,GAAM,OAAA,iBAAAmP,UAAA,MAAA,mCAAA,OAAAA,SAAA,MAAA,QAAA,yBAyCjBjY,GAAY,QAAA,UAAA,+BACtB,OAAA,gBAAA,mCAEDwO,EAKagK,wBAAuB,WAAA,kBAA7B,WAA8BC,GAAY,YAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAC,SACxBnK,KAAK1F,YAAW,OAAuD,GAAtFzB,SAAiCuR,MAAK,SAACC,GAAO,OAAKA,EAAQvR,mBAAqBoR,MAE5EC,SAAA,MAAA,MACAlZ,EAAY,OAGe,GAAhB6H,EAAqBD,EAArBC,iBAAbvB,EAAkCsB,EAAlCtB,aAEQ4S,SAAA,MAAA,MAAQhZ,EAAc,OAAA,GAEjC2H,GAAgBqR,UAAA,MAAA,MAAQ/Y,EAAmB,QAAA,OAAA+Y,UAGtCnK,KAAKjB,mBACPxH,EACA,CACI/H,SAAUN,mBAAiBC,SAC3BoM,aAAcC,eAAaC,wBAE/B,EACAyO,GACH,QAM+B,OAf9BI,SAUJ,GAAGnL,SAAQgL,KAGTrR,EAAgBqR,KAChB5S,EAAW4S,KACDG,EAAsBH,UACpBnK,KAAKd,YAAmC3H,EAAa+S,GAAuB,QAAA,OAAAH,+BAHxFrR,sBACAvB,iBACA4H,cACA5P,YAAI,QAAA,UAAA,+BAEX,OAAA,YAAA,gCA/BmC,GAiCpC0Q,EAMasK,sBAAqB,WAAA,kBAA3B,WAA4BxR,GAAoB,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAyR,SAChCxK,KAAK1F,UAAU,CAAEvB,eAAAA,IAAiB,OAA3C,GAEY,KAFlBwB,UAEOT,QAAY0Q,SAAA,MAAA,MACbnZ,EAAyB,OAAA,yBAG5BkJ,EAAO,IAAE,OAAA,UAAA,+BACnB,OAAA,YAAA,gCARiC,GAUlC0F,EAKawK,yBAAwB,WAAA,kBAA9B,WAA+B1R,GAAoB,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA2R,SAClC1K,KAAKuK,sBAAsBxR,GAAe,OAAnD,KAALF,YAEOA,EAAMC,kBAAgB4R,SAAA,MAAA,OAAAA,SAClB1K,KAAK3H,YAAYC,YAAYO,EAAMC,kBAAiB,OAAA,iCAAA,OAAA,8BAE1DpE,GAAS,QAAA,UAAA,+BAEvB,OAAA,YAAA,gCARoC,GAUrCuL,EAUalB,mBAAkB,WAAA,kBAAxB,WACHxH,EACAlF,EACAsY,EACA7R,EACA+M,iFAOE,YAPFA,IAAAA,EAAqC,CAAE0D,cAAc,IAEjDqB,EAAcrD,KAAKC,UAAU,CAC7BjQ,YAAAA,EACAlF,OAAAA,EACAsY,sBAAAA,EACA7R,iBAAAA,IAEC+M,EAAQ0D,eAAgBvJ,KAAKG,eAAeyK,IAAYC,SAAA,MAAA,yBAAS7K,KAAKG,eAAeyK,IAAY,OAAA,yBAE/F5K,KAAKxF,YAAY6M,mBAAmB9P,EAAalF,EAAQyG,GAAkBpF,MAAK,SAAC4T,GACpF,OAAOjU,QAAQC,IACXgU,EAASpV,eAAG,kBAAC,WAAO4X,GAAK,6BAAA,OAAA,sBAAA,OAAA,IACjBa,IAAyBb,EAAMC,SAAS3D,iBAAe0E,SAAA,MAAA,OAAAA,SAC/BC,EAAK7L,YACzB3H,EACAuS,EAAMC,SAAS3D,gBACftN,GACH,OACDgR,EAAMC,cACCD,EAAMC,iBAEZ,OAAA,yBAEED,GAAK,OAAA,UAAA,0BACf,mBAAA,qCACHpW,MAAK,SAAC4T,GAAQ,OAAMyD,EAAK5K,eAAeyK,GAAetD,SAC3D,OAAA,UAAA,+BACL,OAAA,oBAAA,gCAjC8B,GAmC/BrH,EAOa+K,2BAA0B,WAAA,kBAAhC,WACHtT,EACAnI,EACA4P,GAAiB,QAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA8L,SAEUjL,KAAK1F,YAAW,OACc,GADd2Q,cAAEb,MACzC,SAACC,GAAO,OAAKA,EAAQvR,mBAAqBpB,EAAS7G,kBAAEoa,SAAA,MAAAA,YAAAA,SAAA,MAAA,OAAAA,KADrCC,EAEjB3T,YAAW,OAFG,KAAXA,SAIS0T,UAAA,MAAA,yBACJjL,KAAKgH,eACRzP,EACAhI,EACA,CACIC,SAAUN,mBAAiBC,SAC3BoM,aAAcC,eAAaC,uBAE/B,QACA/G,EACAyK,IACH,QAAA,MAEKhO,EAAc,QAAA,UAAA,+BAE3B,OAAA,gBAAA,gCAxBsC,GA0BvC8O,EAOakL,qBAAoB,WAAA,kBAA1B,WACHzT,EACA0T,EACAjM,GAAiB,QAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAkM,SAEUrL,KAAK1F,YAAW,OACc,GADd+Q,cAAEjB,MACzC,SAACC,GAAO,OAAKA,EAAQvR,mBAAqBpB,EAAS7G,kBAAEwa,SAAA,MAAAA,YAAAA,SAAA,MAAA,OAAAA,KADrCC,EAEjB/T,YAAW,OAFG,KAAXA,SAIS8T,UAAA,MAAA,yBACJrL,KAAKgH,eACRzP,EACA6T,EACA,CACI5b,SAAUN,mBAAiB8M,WAC3BX,YAAa,oBAEjB,QACA3G,EACAyK,IACH,QAAA,MAEKhO,EAAc,QAAA,UAAA,+BAE3B,OAAA,gBAAA,gCAxBgC,GA0BjC8O,EAKasL,iBAAgB,WAAA,kBAAtB,WAAgC1S,EAAcxG,GAAgB,UAAA,6BAAA,OAAA,sBAAA,OAC5B,GAAhByG,EAAqBD,EAArBC,iBAAbvB,EAAkCsB,EAAlCtB,aAEQiU,SAAA,MAAA,MAAQra,EAAc,OAAA,GACjC2H,GAAgB0S,SAAA,MAAA,MAAQpa,EAAmB,OAAA,OAAAoa,SAEtCxL,KAAKjB,mBAAmBxH,EAAalF,GAAQ,EAAOwG,EAAMC,iBAAkB,CAAEyQ,cAAc,IAAO,OAMzE,OAP9Be,SAEJ,GAAGnL,SAAQqM,KAGT1S,EAAgB0S,KAChBjU,EAAWiU,KACDlB,EAAsBkB,UACpBxL,KAAKd,YAAe3H,EAAa+S,GAAuB,QAAA,OAAAkB,+BAHpE1S,sBACAvB,iBACA4H,cACA5P,YAAI,QAAA,UAAA,+BAEX,OAAA,cAAA,gCAf4B,GAiB7B0Q,EAKawL,+BAA8B,WAAA,kBAApC,WAAqC1S,GAAsB,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA2S,SAC1C1L,KAAKuK,sBAAsBxR,GAAe,OAAnD,GAALF,UAEI6S,SAAA,MAAA,MAAQza,EAAY,OAAA,yBAEvB+O,KAAKuL,iBAAiC1S,EAAO,CAChDrJ,SAAUN,mBAAiB8M,WAC3BX,YAAa,sBACf,OAAA,UAAA,+BACL,OAAA,YAAA,gCAT0C,GAW3C4E,EAKa0L,kBAAiB,WAAA,kBAAvB,WAAwBjU,GAA0B,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAkU,SAChC5L,KAAK1F,YAAW,OAA4D,GAA3FzB,SAAiCuR,MAAK,SAACC,GAAO,OAAKA,EAAQvR,mBAAqBpB,EAAS7G,OAErF+a,SAAA,MAAA,MAAQ3a,EAAY,OAAA,yBAEvB+O,KAAKuL,iBAAiC1S,EAAO,CAChDrJ,SAAUN,mBAAiB8M,WAC3BX,YAAa,sBACf,OAAA,UAAA,+BACL,OAAA,YAAA,gCAT6B,GAW9B4E,EAKa4L,6BAA4B,WAAA,kBAAlC,WAAmC9S,GAAsB,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA+S,SACxC9L,KAAKuK,sBAAsBxR,GAAe,OAAnD,GAALF,UAEIiT,SAAA,MAAA,MAAQ7a,EAAY,OAAA,yBAEvB+O,KAAKuL,iBAA+B1S,EAAO,CAC9CrJ,SAAUN,mBAAiB6c,SAC3B1Q,YAAa,sBACf,OAAA,UAAA,+BACL,OAAA,YAAA,gCATwC,GAWzC4E,EAKa+L,gBAAe,WAAA,kBAArB,WAAsBtU,GAA0B,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAuU,SAC9BjM,KAAK1F,YAAW,OAA4D,GAA3FzB,SAAiCuR,MAAK,SAACC,GAAO,OAAKA,EAAQvR,mBAAqBpB,EAAS7G,OAErFob,SAAA,MAAA,MAAQhb,EAAY,OAAA,yBAEvB+O,KAAKuL,iBAAiB1S,EAAO,CAChCrJ,SAAUN,mBAAiB6c,SAC3B1Q,YAAa,sBACf,OAAA,UAAA,+BACL,OAAA,YAAA,gCAT2B,GAW5B4E,EAUaiM,yBAAwB,WAAA,kBAA9B,WAA+BzK,GAAkB,WAAA,6BAAA,OAAA,sBAAA,OACtC,OADsC0K,KAC7C9Y,QAAO8Y,SACHnM,KAAK1F,YAAW,OAgBlB,OAhBkB6R,YAAEja,KAAI,SAAC2G,GAAK,OAC/BuT,EAAKrN,mBACDlG,EAAMtB,YACN,CACI/H,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAaC,wBAE/B,OACA/G,GACFhB,MAAK,SAAC4T,GAAQ,OACZjU,QAAQC,IACJgU,EAASpV,eAAG,kBACR,WAAO4X,GAAK,6BAAA,OAAA,sBAAA,OAAA,OAAAuC,SACFD,EAAKxV,cAAcC,iBAAiBiT,EAAMC,SAAShR,eAAgB0I,GAAa,OAAA,iCAAA,OAAA,UAAA,0BAAA,mBAAA,qCAEhG/N,MAAK,SAAC4Y,GAAO,OAAKA,EAAQ7Z,uCAhBzBa,oBAmBbI,MAAK,SAAC0Q,GAAQ,OAAKA,EAAS3R,WAAM,OAAA,UAAA,+BACvC,OAAA,YAAA,gCArBoC,GAuBrCwN,EAKasM,kCAAiC,WAAA,kBAAvC,WACHxT,EACA0I,GAAoB,eAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA+K,SAEAxM,KAAKuK,sBAAsBxR,GAAe,OAAnD,GAALF,UACI2T,SAAA,MAAA,8BAAS9X,GAAS,OAAA,OAAA8X,SAGlBxM,KAAKxF,YAAYiF,mBACnB5G,EAAMtB,YACN,CAAC,kBACD,CAAC,kBACD,CACI/H,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAaC,uBAE/B5C,EAAMC,kBACT,OAGqE,GAErC,IAfjC2T,SAYCha,OACAP,KAAI,SAAC6X,GAAoC,OAAKA,EAAShR,mBAEjCe,QAAW0S,UAAA,MAAA,yBAAS,IAAE,QAAA,OAAAA,UAEpCnZ,QAAQC,IACjBmZ,EAAuBva,eAAG,kBAAC,WAAOwa,GAAiB,6BAAA,OAAA,sBAAA,OAAA,OAAAC,SAClCC,EAAKhW,cAAcC,iBAAiB6V,EAAWjL,GAAa,OAAA,iCAAA,OAAA,UAAA,0BAC5E,mBAAA,qCACJ,QAAA,iCAAA,QAAA,UAAA,+BACJ,OAAA,cAAA,gCA7B6C,GA+B9CxB,EAMa4M,2BAA0B,WAAA,kBAAhC,WACH9T,EACA8M,+EAGc,gBAHdA,IAAAA,EAAqC,CAAE0D,cAAc,IAAOuD,KAGrDzZ,QAAOyZ,SACH9M,KAAK1F,UAAU,CAAEvB,eAAAA,IAAiB,OAwBhC,OAxBgC+T,YACpC5a,KAAI,SAAC2G,GAAK,OACPkU,EAAKhO,mBACDlG,EAAMtB,YACN,CACI/H,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAaC,sBAC3B1C,eAAAA,IAEJ,EACAF,EAAMC,iBACN+M,GACFnS,MAAK,SAAC4T,GAAQ,OACZjU,QAAQC,IACJgU,EAASpV,KAAI,SAACqB,GAAC,OACXwZ,EAAK7N,YACDrG,EAAMtB,YACNhE,EAAE4L,SACFtG,EAAMC,4BAMzBrG,8BAzBMa,oBA0BbI,MAAK,SAACnE,GAAI,OAAKA,EAAKkD,WAAM,OAAA,UAAA,+BAC/B,OAAA,cAAA,gCAhCsC,GAkCvCwN,EAKa+M,4BAA2B,WAAA,kBAAjC,WAAkCjU,GAAoB,6BAAA,OAAA,sBAAA,OAAA,yBAClDiH,KAAKiN,wBACR,CACIzd,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa0R,eAE/B,EACAnU,IACH,OAAA,UAAA,+BACJ,OAAA,YAAA,gCATuC,GAWxCkH,EAKakN,sBAAqB,WAAA,kBAA3B,WAA4BpU,GAAoB,6BAAA,OAAA,sBAAA,OAAA,yBAC5CiH,KAAKiN,wBACR,CACIzd,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa4R,SAE/B,EACArU,IACH,OAAA,UAAA,+BACJ,OAAA,YAAA,gCATiC,GAWlCkH,EAKaoN,yBAAwB,WAAA,kBAA9B,WAA+BtU,GAAoB,6BAAA,OAAA,sBAAA,OAAA,yBAC/CiH,KAAKiN,wBACR,CACIzd,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa8R,gBAE/B,EACAvU,IACH,OAAA,UAAA,+BACJ,OAAA,YAAA,gCAToC,GAWrCkH,EAMasN,8BAA6B,WAAA,kBAAnC,WAAoCxU,EAAsByU,GAAqB,6BAAA,OAAA,sBAAA,OAAA,yBAC3ExN,KAAKiN,wBACR,CACIzd,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa8R,cAC3BE,gBAAAA,IAEJ,EACAzU,IACH,OAAA,UAAA,+BACJ,OAAA,cAAA,gCAVyC,GAY1CkH,EASagN,wBAAuB,WAAA,kBAA7B,WACHQ,EACA9C,EACA5R,GAAoB,WAAA,6BAAA,OAAA,sBAAA,OAEN,OAFM2U,KAEbra,QAAOqa,SACH1N,KAAK1F,UAAU,CAAEvB,eAAAA,IAAiB,OAoBhC,OApBgC2U,YACpCxb,KAAI,SAAC2G,GAAK,OACP8U,EAAK5O,mBACDlG,EAAMtB,iBACDkW,GAAS1U,eAAAA,IACd4R,EACA9R,EAAMC,iBACN,CAAEyQ,cAAc,IAClB7V,MAAK,SAAC4T,GAAQ,OACZjU,QAAQC,IACJgU,EAASpV,eAAG,kBAAC,WAAO4X,GAAK,6BAAA,OAAA,sBAAA,OAAA,4BAEjBhR,iBAAkBD,EAAMC,iBACxBvB,YAAasB,EAAMtB,aAChBuS,IAAK,OAAA,UAAA,0BAEf,mBAAA,2CAIZrX,8BArBMa,oBAsBbI,MAAK,SAACnE,GAAI,OAAKA,EAAKkD,WAAM,OAAA,UAAA,+BAC/B,OAAA,gBAAA,gCA5BmC,GAkCpCwN,EAQa2N,uCAAsC,WAAA,kBAA5C,WACH/c,EACA6I,EACAE,EACAiU,GAAiB,QAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAC,SAEkB9N,KAAK3H,YAAYC,YAAYzH,GAAG,OAC/Dkd,SADiErU,0BAEhErH,QAAO,SAAC2b,GAEL,IAAIC,EAAkBvU,EAA0BwU,QAAQF,EAAMG,kBAC9D,OAAyB,IAArBF,GACGrU,EAAwBqU,IAAgE,IAA5CrU,EAAwBqU,MAE9E/b,KAAI,SAACkc,GAEF,IAAItQ,EAAQpE,EAA0BwU,QAAQE,EAAKD,kBAEnD,OADAC,EAAKC,eAAiBzU,EAAwBkE,GACvCsQ,KAEf,IAEQtN,EAAad,KAAKL,QAAQ2O,kBAAkBP,EAAgBF,GAChE7N,KAAKY,IAAMZ,KAAKL,QAAQkB,UAAUoC,QAAQnC,GAC5C,MAAOvN,GACLU,QAAQC,MAAMX,GACjB,OAAA,UAAA,+BACJ,OAAA,kBAAA,gCA3BkD,GA6BnD0M,EAMayC,8BAA6B,WAAA,kBAAnC,WAAoC7R,EAAUyP,GAAgB,cAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAiO,SAC5CvO,KAAK3H,YAAYC,YAAYzH,GAAG,OAEjD+R,GAFAlL,UAE2BwJ,iBAC3B6B,EAAqB/C,KAAKL,QAAQqB,aAAaC,eAAeX,GAC9DQ,EAAaiC,EAAmBC,4BAA4BJ,GAE5DlL,EAASoK,gBAELC,EAAoB/B,KAAKL,QAAQqB,aAAaC,eAAevJ,EAASoK,eAC1EE,eAAeC,QACXrR,EAA2BC,GAC3BkR,EAAkBZ,4BAA4BL,KAItDd,KAAKY,IAAMZ,KAAKL,QAAQkB,UAAUoC,QAAQnC,GAAW,OAAA,UAAA,+BACxD,OAAA,cAAA,gCAjByC,GAmB1Cb,EAMauO,+BAA8B,WAAA,kBAApC,WAAqC3d,EAAUsG,GAAiB,UAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAsX,SACtCzO,KAAK3H,YAAYC,YAAYzH,GAAG,OAAzD+R,SAA2DrJ,kBAC3DwJ,EAAqB/C,KAAKL,QAAQqB,aAAaC,eAAe9J,GAC9D2J,EAAaiC,EAAmBC,4BAA4BJ,GAChE5C,KAAKY,IAAMZ,KAAKL,QAAQkB,UAAUoC,QAAQnC,GAAW,OAAA,UAAA,+BACxD,OAAA,cAAA,gCAL0C,GAO3Cb,EAQatG,wBAAuB,WAAA,kBAA7B,WACH9I,EACA6I,EACAE,EACAiU,GAAiB,QAAA,6BAAA,OAAA,sBAAA,OAAA,GAEZ7N,KAAKY,KAAG8N,SAAA,MAAA,MAAQ5d,EAAwB,OAS5C,OARG6d,EAA0B3O,KAAKL,QAAQiP,sBACvClV,EACAE,EACAoG,KAAKY,cACLiN,GAEAgB,EAAgB,CAChBnV,0BAA2BiV,GAC9BD,SAEY1O,KAAK3H,YAAY8J,eAAetR,EAAIge,GAAc,OAAA,iCAAA,OAAA,UAAA,+BAClE,OAAA,kBAAA,gCAlBmC,GAoBpC5O,EAWa6O,eAAc,WAAA,kBAApB,WAAqBje,EAAUke,EAAqBC,GAAoB,UAAA,6BAAA,OAAA,sBAAA,OAAA,GACtEhP,KAAKY,KAAGqO,SAAA,MAAA,MAAQne,EAAwB,OAgB5C,OAdGiQ,EAAqBf,KAAKL,QAAQqB,aAAaC,eAAe8N,GAC9DG,EAAkBnO,EAAmBI,4BAA4BnB,KAAKY,eACtEoO,IACAA,EAAchP,KAAKL,QAAQ0B,mBAAmBrB,KAAKL,QAAQ0B,mBAAmB2N,KAGlFD,EAAc/O,KAAKL,QAAQ0B,mBAAmBrB,KAAKL,QAAQ0B,mBAAmB0N,IAE1EF,EAAgB,CAChBvO,SAAU,CACN0O,YAAAA,EACAD,YAAAA,GAEJ7N,iBAAkBgO,GACrBD,SAEYjP,KAAK3H,YAAY8J,eAAetR,EAAIge,GAAc,OAAA,iCAAA,QAAA,UAAA,+BAClE,OAAA,gBAAA,gCApB0B,GAsB3B5O,EAQMzG,gBAAe,WAAA,kBAArB,WAAsB3I,EAAUsG,EAAmBI,GAAiB,YAAA,6BAAA,OAAA,sBAAA,OAAA,GAC3DyI,KAAKY,KAAGuO,SAAA,MAAA,MAAQre,EAAwB,OAIc,OAFvDiQ,EAAqBf,KAAKL,QAAQqB,aAAaC,eAAe9J,GAC9DiY,EAAmBrO,EAAmBI,4BAA4BnB,KAAKY,eACvEiO,EAAgB,CAAEtV,kBAAmB6V,GAAkBD,SAC7BnP,KAAK3H,YAAY8J,eAAetR,EAAIge,GAAc,OAA3D,OAAfQ,SAAeF,UAEfnP,KAAK7E,oBACP5D,EACA,CAAEJ,UAAAA,GACF,CACI3H,SAAUN,mBAAiB6c,SAC3B1Q,YAAa,oBAEjB,GACA,CAAEM,cAAc,EAAMD,kBAAkB,EAAOE,qBAAqB,IACvE,QAAA,yBAEMyT,GAAe,QAAA,UAAA,+BACzB,OAAA,gBAAA,gCApBoB,oCClhDZC,cAGT,WAAoBC,EAAaC,EAAwBzb,GAArCiM,SAAAuP,EAAqCvP,YAAAjM,EACrDiM,KAAKyP,IAAM,IAAIC,eAAa,CAAEC,QAAS,CAAEC,mBAAoBJ,KAChE,kBAkDA,OAlDAvP,EAEM4P,YAAA,SAAYC,GAQf,IAAQ/b,EAAoB+b,EAApB/b,OAAWxE,IAASugB,MAE5B,OAAO9P,KAAKyP,IAAIM,KACT/P,KAAKuP,+CACRhgB,EACA,CACIygB,OAAQ,CAAEjc,aAAQA,EAAAA,EAAUiM,KAAKjM,WAG5CkM,EAEMgQ,WAAA,SACHH,EASAlJ,GAEA,IAAQ7S,EAAoB+b,EAApB/b,OAAWxE,IAASugB,MAExBvK,EAAUvF,KAAKyP,IAAIM,KAChB/P,KAAKuP,yBACRhgB,EACA,CACIygB,OAAQ,CAAEjc,aAAQA,EAAAA,EAAUiM,KAAKjM,UAUzC,OANI6S,IACArB,EAAUA,EAAQ7R,MAAK,SAACwc,GAAM,OAC1BA,EAAO7d,QAAO,SAAC8d,GAAK,OAAKA,EAAMvJ,OAASA,SAIzCrB,0jBClCF,SACT5F,EACAyQ,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACA5Q,GAEA,MASI6Q,EACA,CACIR,cAAAA,EACAC,aAAAA,EACAC,aAAAA,EACAC,cAAAA,EACAC,gBAAAA,EACAC,eAAAA,EACAC,gBAAAA,EACAC,iBAAAA,GAEJ5Q,GAgBJ,OAbe,IAAIL,GACfC,IAvBAkR,gBAGAC,eACAC,eACAC,gBAJAC,kBACAC,iBAIAC,kBACAC,iBAyBArR,gGVkCJnL,GAEA,GAAKA,EAAL,CAIA,IA4CMyc,EA5CyBzc,EAC1B0c,SAAQ,SAACC,GACN,IAAMC,EAAmBnhB,OAAO0C,KAAKwe,GAChClf,QACG,SAACof,GAAiB,OAC4B,IAA1CA,EAAkBvD,QAAQ,cAEjCzb,OACCif,EAAoBrhB,OAAO0C,KAAKwe,GACjClf,QACG,SAACof,GAAiB,OAC6B,IAA3CA,EAAkBvD,QAAQ,eAEjCzb,OACCkf,EAAwBthB,OAAO0C,KAAKwe,GACrClf,QACG,SAACof,GAAiB,OAC6B,IAA3CA,EAAkBvD,QAAQ,eAEjCzb,OAEL,gBACO+e,EAAiBtf,KAChB,SAAC0f,GAAgB,MACmC,iBAAxCL,EAAkBK,GACpBL,EAAkBK,QAClBld,KAEXgd,EAAkBxf,KACjB,SAAC0f,GAAgB,MACmC,iBAAxCL,EAAkBK,GACpBL,EAAkBK,QAClBld,KAEXid,EAAsBzf,KACrB,SAAC0f,GAAgB,MACmC,iBAAxCL,EAAkBK,GACpBL,EAAkBK,QAClBld,SAIrBrC,QAAO,SAAC+b,GAAI,YAAc1Z,IAAT0Z,KAE6B/b,QAC/C,SAACwf,GAAuB,OACpBA,EAAwBC,WAAW,yBAE3C,GAAKT,GAAsD,IAA/BA,EAAoBvX,OAAhD,CAOA,IAAMiY,IAA0B,yEAA4FC,gBAAAC,aACtHC,EAAgBb,EAAoB1e,QACtC,SAACuf,EAAeL,GACZ,IAAMM,EAAoBJ,EAAwBK,KAC9CP,WAGAM,EAAAA,EAAqB,GADhBE,OAAuBC,OAEhC,IAAKJ,EACD,OAAOI,EAGX,IAAMC,EAAiBR,EAAwBK,KAAKF,WACNK,EAAAA,EAAkB,GAAvDC,OAGT,OACKH,GACAG,GACGA,EAAqBH,OAKtBC,SAEX5d,GAIJ,OADAT,QAAQiE,IAAI,oBAAsBga,GAC3BA,EApCHje,QAAQiE,IAAI,wBAA0BmZ,uGE0HIvb,EAAwB2c,GACtE,IAAMC,EAAiBnL,KAAKoL,MAAMpL,KAAKC,UAAU1R,IAkBjD,OAhBK4c,EAAe/gB,kBAChB+gB,EAAe/gB,gBAAkBkE,EAA8B6c,GAAgB,IAGnFA,EAAezgB,MAAMzB,SAAQ,SAACwF,EAAwB4c,GAElD,cAAmBviB,OAAOC,QAAQ0F,EAAK5D,0BAAY,CAA9C,IAAOvB,UACJ4hB,EAAkBliB,OAAOM,IACrB6hB,EAAe/gB,kBACf+gB,EAAe/gB,gBAAgBihB,GAAS/hB,GAAM4hB,EAAkBliB,OAAOM,GAAIF,YAOpF+hB,wLI7QX,SACIG,EACAC,EACAC,EACA9iB,aAEI0B,EAAuC,SAEd,mBAAGkhB,IACP,eAAGC,MAU5B,OALIC,IAAiBphB,EAAgB,QAAUA,EAAgB,WAAsB,gBAAGohB,OAGpF9iB,IAAU0B,EAAgB,QAAUA,EAAgB,WAAe,SAAG4V,KAAKC,UAAUvX,QAElF,CACHY,GAAI,uCACJgD,UAAW,2BACXmf,UAAW,GACXC,cAAe,GACfhhB,MAAO,CACH,CACIihB,MAAO,sBACPC,OAAQ,CACJ,CACIvM,KAAM,cACNwM,gBAAiB,CACb,CACIxM,KAAM,QACN/V,GAAI,sBAER,CACI+V,KAAM,QACN/V,GAAI,kBAER,CACI+V,KAAM,QACN/V,GAAI,eAER,CACI+V,KAAM,QACN/V,GAAI,iBAKpBuB,UAAW,CACPygB,mBAAoB,CAChBQ,MAAO,oCACP3hB,KAAM,QACN4hB,QAAQ,EACRC,aAAa,EACbC,aAActkB,mBAAiBukB,OAC/B7e,QAAS,CACL8e,uCAAwC,CACpC7e,KAAM,OAEV8e,uCAAwC,CACpC9e,KAAM,QAIlBie,eAAgB,CACZO,MAAO,6BACP3hB,KAAM,QACN4hB,QAAQ,EACRC,aAAa,EACbC,aAActkB,mBAAiBukB,OAC/B7e,QAAS,CACLgf,uCAAwC,CACpC/e,KAAM,OAEVgf,uCAAwC,CACpChf,KAAM,QAIlBif,YAAa,CACTpiB,KAAM,yBACN2hB,MAAO,uDACPG,aAActkB,mBAAiBukB,OAC/BM,aAAc,iBAElBC,WAAY,CACRtiB,KAAM,gBACN2hB,MAAO,UACPG,aAActkB,mBAAiBukB,WAK/C1f,OAAQ,KACRpC,gBAAAA,8PNnEJsiB,EACA1kB,EACAC,GAKA,IAAMC,EAASR,EAAqBO,GAE9BY,EAAMmX,KAAKoL,MAAMpL,KAAKC,UAAUjY,IA0BtC,OAxBI0kB,EAAMvkB,UAAYU,EAAIG,OAAUd,gBAChCW,EAAIG,OAAUd,cAAkBkB,OAASsjB,EAAMvkB,UAC/CukB,EAAMtkB,WAAaS,EAAIG,OAAUd,iBACjCW,EAAIG,OAAUd,eAAmBkB,OAASsjB,EAAMtkB,WAChDskB,EAAMrkB,QAAUQ,EAAIG,OAAUd,cAC9BW,EAAIG,OAAUd,YAAgBkB,OAASsjB,EAAMrkB,QAC7CqkB,EAAMpkB,MAAQO,EAAIG,OAAUd,YAC5BW,EAAIG,OAAUd,UAAckB,OAASsjB,EAAMpkB,MAC3CokB,EAAMnkB,OAASM,EAAIG,OAAUd,aAC7BW,EAAIG,OAAUd,WAAekB,OAASsjB,EAAMnkB,OAC5CmkB,EAAMlkB,KAAOK,EAAIG,OAAUd,WAC3BW,EAAIG,OAAUd,SAAakB,OAASsjB,EAAMlkB,KAC1CkkB,EAAMjkB,MACFI,EAAIG,OAAUd,SACdW,EAAIG,OAAUd,SAAakB,OAASsjB,EAAMjkB,IACnCI,EAAIG,OAAUd,QAErBW,EAAIG,OAAUd,QAAYkB,OAASsjB,EAAMjkB,IAGzCI,EAAIG,OAAUd,SAAe,CAAEiC,KAAM,OAAQf,OAAQsjB,EAAMjkB,MAI5DI,oBUtFW"}