oro-sdk 5.6.0 → 5.6.1-dev1.0

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.Refill,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationIds: [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 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 const emailConfirmed = !!skipEmailValidation\n\n const signupRequest: IdentityCreateRequest = {\n practiceUuid: practice.uuid,\n email: email.toLowerCase(),\n emailConfirmed,\n password: hashedPassword,\n publicKey: this.toolbox.encodeToBase64(this.rsa.public()),\n recoveryPassword,\n tosAndCpAcceptance,\n tokenData,\n subscription,\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","Refill","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","emailConfirmed","signupRequest","practiceUuid","toLowerCase","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","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":"y6UAOA,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,mBAAiB6P,OAC3BxD,aAAcC,eAAaC,sBAC3BK,gBAAiB,CAACgD,EAAWpG,OAEjC,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,EAAU2I,mBAC1CzH,EACA,CAAE/H,SAAUN,mBAAiBkM,IAAKrC,eAAgB7B,EAAe+H,aACjE,GACH,QAJ0B,MAAvBC,WAK2BA,EAAwBpF,OAAS,IAAClI,UAAA,MAAA,OAAAA,UACjCyE,EAAU8I,YAClC5H,EACA2H,EAAwB,GAAGE,UAC9B,QAC2E,OAJxEC,SAIA/H,GAAYA,EAAWO,IAAgBD,EAAe,mBAAkBhG,UACtEiI,GAAwBiF,EAAYO,EAAiBhJ,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,wECzOCQ,QAA+B,gCAkBpD,cAAA,OAAAC,eAlBM,WACHlJ,EACAhE,GAAgC,YAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAT,SAEbyE,EAAUiE,YAAW,OACpCkF,EAAiB,GAAEC,YACC,OAAA,iBAAA7N,UAAA,MAAV,OAALiH,UAAKjH,SAEiCyE,EAAUmE,YAAYkF,mBAAmB7G,EAAMtB,YAAc,CAAC,kBAAmB,GAAI,CAC5H/H,SAAUN,mBAAiBoM,aAC3BvC,eAAgB1G,EAAO0G,iBACzB,cAEiC,GAAGe,QAAU,GAC5C0F,EAAe7J,KAAKkD,GAAM,QAAAjH,SAAA,MAAA,QAAA,yBAG3B4N,GAAc,QAAA,UAAA,qDC0CZG,cAgBT,WACYC,EACDC,EACArF,EACAnC,EACAwF,EACAvH,EACAM,EACAkJ,EACAC,EACCC,GATAC,aAAAL,EACDK,kBAAAJ,EACAI,iBAAAzF,EACAyF,iBAAA5H,EACA4H,kBAAApC,EACAoC,oBAAA3J,EACA2J,mBAAArJ,EACAqJ,oBAAAH,EACAG,qBAAAF,EACCE,4BAAAD,EAxBJC,aAGF,GACEA,0BAEJ,GAEIA,oBAEJ,GAiBJ,kBAm8CC,OAn8CDC,EAGa/F,WAAU,WAAA,kBAAhB,aAAA,6BAAA,OAAA,sBAAA,OACH8F,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,OAsB5B,OApBDX,KAAKY,IAAM,IAAIC,YACTC,EAAad,KAAKY,cAElBG,EAAqBf,KAAKL,QAAQqB,aAAaC,eAAeX,GAC9DY,EAAmBH,EAAmBI,4BAA4BL,GAElEM,EAAiBpB,KAAKL,QAAQ0B,mBAAmBrB,KAAKL,QAAQ0B,mBAAmBf,IAEjFgB,IAAmBX,EAEnBY,EAAuC,CACzCC,aAAcjB,EAAS9H,KACvB4H,MAAOA,EAAMoB,cACbH,eAAAA,EACAhB,SAAUc,EACVM,UAAW1B,KAAKL,QAAQgC,eAAe3B,KAAKY,cAC5CM,iBAAAA,EACAV,mBAAAA,EACAC,UAAAA,EACAC,aAAAA,GACHxN,SAEsB8M,KAAK5H,YAAYwJ,eAAeL,GAAc,OASpE,OATK9J,UAEOoK,gBAELC,EAAoB9B,KAAKL,QAAQqB,aAAaC,eAAexJ,EAASoK,eAC1EE,eAAeC,QACXrR,EAA2B8G,EAAS7G,IACpCkR,EAAkBX,4BAA4BL,uBAI/CrJ,GAAQ,QAAA,UAAA,+BAClB,OAAA,wBAAA,gCA3CkB,GA6CnBwI,EAKagC,aAAY,WAAA,kBAAlB,WAAmBpH,GAAmB,6BAAA,OAAA,sBAAA,OACE,OAA3CmF,KAAK5H,YAAYwC,UAAU,CAAEC,YAAAA,IAAczG,SACtB4L,KAAK5H,YAAY2C,SAAQ,OAAlC,yBACLiF,KAAK5H,YAAY8J,sBAAsBC,IAAK,CAC/Cb,gBAAgB,KAClB,OAAA,UAAA,+BACL,OAAA,YAAA,gCANwB,GAQzBrB,EAUamC,OAAM,WAAA,kBAAZ,WAAaZ,EAAoBnB,EAAeC,EAAkB+B,GAAY,UAAA,6BAAA,OAAA,sBAAA,OAOhF,OANKjB,EAAiBpB,KAAKL,QAAQ0B,mBAAmBrB,KAAKL,QAAQ0B,mBAAmBf,IACjFgC,EAAiC,CACnCd,aAAAA,EACAnB,MAAOA,EAAMoB,cACbnB,SAAUc,EACViB,IAAAA,GACH3N,SAEKsL,KAAK5H,YAAYmK,UAAUD,GAAa,OAAA,OAAA5N,SACtBsL,KAAK5H,YAAY2C,SAAQ,OAAK,OAAhDyH,SAA6CL,IAAGzN,SAGhDsL,KAAKyC,8BAA8BD,EAAUlC,GAAS,OAAA,OAAA5L,UAC/CsL,KAAK5H,YAAYC,YAAYmK,GAAS,QAAA,iCAAA,QAAA,UAAA,+BACtD,OAAA,kBAAA,gCAfkB,GAiBnBvC,EAIayC,cAAa,WAAA,kBAAnB,aAAA,cAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAtI,SACe4F,KAAK5H,YAAY2C,SAAQ,OACmC,OADxEnK,SAAuCuR,IACvCQ,EAAkBZ,eAAea,QAAQjS,EAA2BC,IAAIwJ,SACnD4F,KAAK5H,YAAYC,YAAYzH,GAAG,OAAe,IAApEiS,SAAuDhB,gBAExCc,GAAevI,SAAA,MAAA,MAAQvJ,EAAwB,OAE9DiS,EAAqB9C,KAAKL,QAAQqB,aAAaC,eAAe4B,GAChE/B,EAAagC,EAAmBC,4BAA4BJ,GAChE3C,KAAKY,IAAMZ,KAAKL,QAAQkB,UAAUmC,QAAQlC,GAAW,QAAA,UAAA,+BACxD,OAAA,WAAA,gCAVyB,GAY1Bb,EAOOgD,0BAAA,SAA0BpO,GAC7B,IAAKmL,KAAKY,IAKN,MAJIZ,KAAKD,wBACLC,KAAKD,uBAAuB,IAAIlP,GAG9B,IAAIA,EAGd,IAAMqS,EAAY,IAAIlD,KAAKL,QAAQqB,aAKnC,MAAO,CAAEmC,cAHaD,EAAUE,2BAA2BvO,GAGnCwO,aAFHrD,KAAKL,QAAQgC,eAAe3B,KAAKY,IAAI0C,eAAeJ,EAAUK,UAKvFtD,EAOOuD,wBAAA,gBAA0BH,IAAAA,aAAcF,IAAAA,cAC3C,IAAKnD,KAAKY,IAKN,MAJIZ,KAAKD,wBACLC,KAAKD,uBAAuB,IAAIlP,GAG9B,IAAIA,EAGd,IAAMqS,EAAYlD,KAAKY,IAAIzC,qBAAqBkF,GAGhD,OAFsBrD,KAAKL,QAAQqB,aAAagC,QAAQE,GAAWO,2BAA2BN,IAKlGlD,EAGayD,QAAO,WAAA,kBAAb,aAAA,6BAAA,OAAA,sBAAA,OAMD,OALF1D,KAAKY,SAAMnM,EACXuL,KAAK2D,QAAU,GACf3D,KAAK5H,YAAYwC,UAAU,CACvBC,iBAAapG,EACbqG,kBAAcrG,IAChBmP,SACI5D,KAAK5H,YAAYyL,aAAY,OAAA,UAAA,+BACtC,OAAA,WAAA,gCARmB,GAUpB5D,EAmBanJ,gBAAe,WAAA,kBAArB,WACHE,EACAb,EACAN,EACAsB,EAIAC,EACAC,GAA+D,6BAAA,OAAA,sBAAA,OADpC,YAA3BD,IAAAA,GAAuB,GAGlB4I,KAAKY,KAAGzE,SAAA,MAAA,MAAQtL,EAAwB,OAAA,yBACtCiG,EACHE,EACAb,EACAN,EACAmK,KACAA,KAAKL,QAAQlH,OACbtB,EACAC,EACAC,IACH,OAAA,UAAA,+BACJ,OAAA,sBAAA,gCAtB2B,GAwB5B4I,EAUavB,aAAY,WAAA,kBAAlB,WACHvI,EACAyI,EACAxH,EACAC,GAA+D,6BAAA,OAAA,sBAAA,OADpC,YAA3BD,IAAAA,GAAuB,GAGlB4I,KAAKY,KAAGkD,SAAA,MAAA,MAAQjT,EAAwB,OAAA,yBACtC6N,GAAavI,EAASyI,EAAyBoB,KAAM5I,EAAaC,IAAW,OAAA,UAAA,+BACvF,OAAA,kBAAA,gCARwB,GAUzB4I,EAIa8D,wBAAuB,WAAA,kBAA7B,aAAA,IAAAC,WAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAzG,SACgByC,KAAK3F,YAAW,OAAzB,OAANC,SAAMiD,SAE6CnK,QAAQC,IAC3DiH,EAAOrI,eAAG,kBACN,WAAO2G,GAAY,6BAAA,OAAA,sBAAA,OAAA,OAAAqL,SACTC,EAAK3J,YACNkF,mBACG7G,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,OACrCwN,KAAK/G,sBACAP,WAAS2C,yBAET5H,MAAK,WAAA,OAAM2Q,MAAM,iDACX,WAAA,OAAMpQ,QAAQC,MAAM,kCAA+B,OAAA,UAAA,+BACjE,OAAA,WAAA,gCAtCmC,GAwCpCgM,EAMahH,cAAa,WAAA,kBAAnB,WAAoB5I,EAAqBgU,GAAqB,cAAA,6BAAA,OAAA,sBAAA,OAAA,GAC5DrE,KAAKY,KAAG0D,SAAA,MAAA,MAAQzT,EAAwB,OAAA,IAGzCwT,GAAcC,SAAA,MAAA,OAAAA,SACsBtE,KAAK5H,YAAYC,YAAYgM,GAAe,OAChFE,EAASvE,KAAKL,QAAQ6E,wBAD4D9C,WACpB4C,UAAA,MAAA,OAE9DC,EAASvE,KAAKY,aAAY,QAG1B6D,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,oBAAqBsC,YAAUgE,2BAC3B,CACI/L,eAAgBxF,EAAEwF,eAClBF,MAAOtF,EAAEsF,OAEb2L,4BAGf,QAAAG,IAAAJ,UAAA,MAAA,QAAA,OAAAA,UAIXtE,KAAKzF,YAAYuK,cAAcL,EAAgBJ,GAAe,QAAA,UAAA,+BACvE,OAAA,cAAA,gCAzCyB,GA2C1BpE,EAOa3H,aAAY,WAAA,kBAAlB,WAAmByM,EAAmBzN,EAAmBuB,GAAuB,YAAA,6BAAA,OAAA,sBAAA,OAAA,GAC9EmH,KAAKY,KAAGoE,SAAA,MAAA,MAAQnU,EAAwB,OAAA,OAAAmU,SAEzBhF,KAAKiF,uBAAuB3N,EAAauB,GAAiB,OAAK,OAA/EqM,SAA4E3B,MAAGyB,SAC/ChF,KAAK5H,YAAYC,YAAY0M,GAAY,OAO5E,OANGI,EAAmBnF,KAAKL,QAAQ6E,wBAD2C9C,WAG3E0D,EAAyBvE,YAAUwE,4BAA4BH,EAAQC,GACvEG,EAA+B,CAC/BC,gBAAiBH,EACjBL,YAAaA,GAChBC,UACKhF,KAAKzF,YAAYiL,aAAalO,EAAagO,EAASzM,GAAiB,QAAA,UAAA,+BAC9E,OAAA,gBAAA,gCAbwB,GAezBoH,EAUawF,kBAAiB,WAAA,kBAAvB,WACHnO,EACAoO,EACA5M,EACAD,EACA8M,EACAC,8EAAyE,YAAzEA,IAAAA,EAA4C,CAAEjK,qBAAqB,IAE9DqE,KAAKY,KAAGiF,SAAA,MAAA,MAAQhV,EAAwB,OAAA,OAAAgV,SAEd7F,KAAKiF,uBAAuB3N,EAAauB,GAAiB,OAG5C,OADzCsK,GAFApC,UAEmCqC,2BAA2BsC,GAAQG,KAC/C9E,EAAkB8E,UAC1B7F,KAAK5H,YAAY2C,SAAQ,QAc3C,OAd2C8K,YAAE1D,IAAG0D,MAA7CC,aADAC,OAA0C3C,6DAiBvCpD,KAAKJ,aAAaoG,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,GAiC9B3F,EAUamG,4BAA2B,WAAA,kBAAjC,WACH9O,EACAhI,EACAwJ,EACAD,EACA8M,EACAC,8EAAyE,YAAzEA,IAAAA,EAA4C,CAAEjK,qBAAqB,IAE9DqE,KAAKY,KAAGyF,SAAA,MAAA,MAAQxV,EAAwB,OAAA,OAAAwV,SAEdrG,KAAKiF,uBAAuB3N,EAAauB,GAAiB,OACR,OAD3DwN,KAAlBtF,SACkCsF,KAAiCC,WAAUD,UAAO/W,EAAKiX,cAAa,QAC7D,OAD6DF,YAAAA,oBAAtGlD,OAAmChC,4CAA2BkF,KACvCtF,EAAkBsF,UAC1BrG,KAAK5H,YAAY2C,SAAQ,QAiB3C,OAjB2CsL,YAAElE,IAAGkE,KACnC/W,EAAKM,KAAIyW,KACL/W,EAAKkX,aAAYH,KACzB/W,EAAKmX,KAAIJ,MAHfP,YACAY,cACAF,kBACAC,WAJAV,OAA0C3C,6DAoBvCpD,KAAKJ,aAAaoG,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,GAmCxC3F,EAYa2G,iCAAgC,WAAA,kBAAtC,WACHtP,EACAhI,EACAwJ,EACAwC,EACAzC,EACA8M,EACAC,oEAGC,YAHDA,IAAAA,EAAuE,CACnEnK,kBAAkB,EAClBE,qBAAqB,IAGpBqE,KAAKY,KAAGiG,SAAA,MAAA,MAAQhW,EAAwB,OAI3B,OAJ2BgW,KAEtC7G,KAAI6G,KACPvP,EAAWuP,KACPP,WAAUO,SAAOvX,EAAKiX,cAAa,OAMtC,OANsCM,YAAAA,oBAAAA,KACvC,CACI/N,eAAAA,EACAvJ,SAAUN,mBAAiBoM,aAC3BC,aAAAA,EACAF,YAAa9L,EAAKqX,MACrBE,UAEkB7G,KAAK5H,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,GAiC7C7G,EAYa8G,eAAc,WAAA,kBAApB,WACHzP,EACAhI,EACA0X,EACAC,EACApO,EACA8M,EACAC,gFAGC,YAHDA,IAAAA,EAAuE,CACnEnK,kBAAkB,EAClBE,qBAAqB,IAGpBqE,KAAKY,KAAGsG,SAAA,MAAA,MAAQrW,EAAwB,OAAA,OAAAqW,SAEdlH,KAAKiF,uBAAuB3N,EAAauB,GAAiB,OAQxF,GAPGsK,GADApC,UACmCqC,2BAA2B9T,GAC9DyW,EAAuBhF,EAAmBqC,2BAA2B6D,GAErE3B,EAA8B,CAC9BhW,KAAM6T,EACN8C,eAAgBe,EAChBb,gBAAiBJ,IAEjBH,EAAQnK,kBAAgByL,UAAA,MAAA,yBACjBlH,KAAKJ,aAAaoG,iBAAiB1O,EAAagO,EAASzM,EAAkB8M,EAAkBC,IAAQ,QAAA,yBACpG5F,KAAKzF,YAAYyL,iBAAiB1O,EAAagO,EAASzM,EAAkB8M,IAAiB,QAAA,UAAA,+BAC1G,OAAA,wBAAA,gCA1B0B,GA4B3B1F,EAUa/E,oBAAmB,WAAA,kBAAzB,WACH5D,EACAhI,EACA2W,EACAE,EACAP,0EAIC,gBAJDA,IAAAA,EAA8F,CAC1FnK,kBAAkB,EAClBC,cAAc,EACdC,qBAAqB,IACxBwL,SAEoBnH,KAAKzF,YAAY6M,mBAAmB9P,EAAa2O,GAAe,OAAzE,GAARoB,SACCzB,EAAQlK,gBAAgB2L,EAASxN,OAAS,IAACsN,SAAA,MAC+B,OAA3EnT,QAAQiE,oBAAoBqP,KAAKC,UAAUtB,uCACpCoB,EAAS,GAAGlI,UAAQ,OAAA,OAAAgI,UAGjBnH,KAAK+G,eACPzP,EACAhI,EACA2W,EACAE,OACA1R,EAEAmR,EAAQlK,cAAgB2L,EAASxN,OAAS,EAAIwN,EAAS,GAAGlI,cAAW1K,EACrEmR,UACI,SAAC7R,GAEL,MADAC,QAAQC,oCAAoCqT,KAAKC,UAAUtB,WAAwBlS,GAC7EA,KACR,QAAA,gCACJoL,UAAQ,QAAA,UAAA,+BACjB,OAAA,oBAAA,gCA/B+B,GAiChCc,EAYa6G,gBAAe,WAAA,kBAArB,WACHxP,EACAhI,EACA0X,EACAC,EACApO,EACA8M,EACAC,gFAGC,YAHDA,IAAAA,EAAuE,CACnEnK,kBAAkB,EAClBE,qBAAqB,IAGpBqE,KAAKY,KAAG4G,SAAA,MAAA,MAAQ3W,EAAwB,OAAA,OAAA2W,SACdxH,KAAKiF,uBAAuB3N,EAAauB,GAAiB,OAQxF,GAPGsK,GADApC,UACmCI,4BAA4B7R,GAC/DyW,EAAuBhF,EAAmBqC,2BAA2B6D,GAErE3B,EAA8B,CAC9BhW,KAAM6T,EACN8C,eAAgBe,EAChBb,gBAAiBJ,IAEjBH,EAAQnK,kBAAgB+L,UAAA,MAAA,yBACjBxH,KAAKJ,aAAaoG,iBAAiB1O,EAAagO,EAASzM,EAAkB8M,EAAkBC,IAAQ,QAAA,yBACpG5F,KAAKzF,YAAYyL,iBAAiB1O,EAAagO,EAASzM,EAAkB8M,IAAiB,QAAA,UAAA,+BAC1G,OAAA,wBAAA,gCAzB2B,GA2B5B1F,EAWaf,YAAW,WAAA,kBAAjB,WAA2B5H,EAAmB6H,EAAgBtG,GAAuB,MAAA,6BAAA,OAAA,sBAAA,OAAA,GACnFmH,KAAKY,KAAG6G,SAAA,MAAA,MAAQ5W,EAAwB,OAAA,OAAA4W,SAEMrU,QAAQC,IAAI,CAC3D2M,KAAKzF,YAAYmN,eAAepQ,EAAa6H,EAAUtG,GACvDmH,KAAKiF,uBAAuB3N,EAAauB,KAC3C,OAHuC,0BAGvC8O,aAEwBlE,gCAA4CnU,OAAK,OAAA,UAAA,+BAC9E,OAAA,gBAAA,gCATuB,GAUxB2Q,EAOa2H,aAAY,WAAA,kBAAlB,WAAmBtQ,EAAmB6H,EAAgBtG,GAAuB,MAAA,6BAAA,OAAA,sBAAA,OAAA,GAC3EmH,KAAKY,KAAGiH,SAAA,MAAA,MAAQhX,EAAwB,OAAA,OAAAgX,SAEMzU,QAAQC,IAAI,CAC3D2M,KAAKzF,YAAYmN,eAAepQ,EAAa6H,EAAUtG,GACvDmH,KAAKiF,uBAAuB3N,EAAauB,KAC3C,OAHuC,0BAGvCiP,aAEwB/E,iCAA6CzT,OAAK,OAAA,UAAA,+BAC/E,OAAA,gBAAA,gCATwB,GAWzB2Q,EAUa5F,UAAS,WAAA,kBAAf,WAAgBjI,GAAiC,gBAAA,6BAAA,OAAA,sBAAA,OAAA,GAC/C4N,KAAKY,KAAGmH,SAAA,MAAA,MAAQlX,EAAwB,OAG7C,GADImX,EAAeV,KAAKC,UAAUnV,IAE9B4N,KAAKE,qBAAqB8H,IAAaD,SAAA,MAAA,yBAAS/H,KAAKE,qBAAqB8H,IAAa,OAAA,OAAAD,SAG5D/H,KAAKiI,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,UACkB1I,GAAgCW,KAAM5N,GAAO,QAArE2L,SAAegK,UAAA,MAAA,QAAA,OAAAA,UAEU/H,KAAKzF,YAAYgO,YAAW,QAArDxK,SAAuDzD,OAAM,QAAA,OAAAyN,UAEnCjK,GAAcC,EAAiBiC,KAAKY,KAAI,QAGnB,OADnDZ,KAAKE,qBAAqB8H,GAFpBQ,SAGNxU,QAAQyU,KAAK,yDACND,GAAe,QAAA,GAGrBpW,GAAM2V,UAAA,MAAA,MAAQ9W,EAAkB,QAAA,OAAA8W,UAEA/H,KAAKzF,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,GAAI5I,KAAKY,MACnE/G,OAAS,IAACkO,UAAA,MAE+B,OAD3D/T,QAAQyU,KAAK,iEACbzI,KAAKE,qBAAqB8H,GAAgBW,oBACnC3I,KAAKE,qBAAqB8H,IAAa,QAAA,yBAI3C,IAAE,QAAA,UAAA,+BACZ,OAAA,YAAA,gCAjDqB,GAmDtB/H,EAKMgI,eAAc,WAAA,kBAApB,aAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAY,SACkB7I,KAAK5H,YAAY2C,SAAQ,OAAA,gCAAE+N,MAAMC,MAAM,MAAG,OAAA,UAAA,+BAC3D,OAAA,WAAA,gCAFmB,GAIpB9I,EAOMgF,uBAAsB,WAAA,kBAA5B,WAA6B3N,EAAqBuB,GAAyB,UAAA,6BAAA,OAAA,sBAAA,OAAA,GAClEmH,KAAKY,KAAGoI,SAAA,MAAA,MAAQnY,EAAwB,OAEqC,IACnE,KADXgN,EAAQmC,KAAK2D,QAAQsF,WAAU,SAAC/D,GAAM,OAAKA,EAAO5N,cAAgBA,OACtD0R,UAAA,MAAA,OAAAA,SACiBhJ,KAAKzF,YAAY2O,iBAAiB5R,EAAauB,GAAiB,OAIlD,OAFvCqM,EAASlF,KAAKY,IAAIzC,4BAFyEgL,cAG3FC,EAAUpJ,KAAKL,QAAQqB,aAAagC,QAAQkC,GAChDlF,KAAK2D,QAAQjO,KAAK,CAAE4B,YAAAA,EAAa8R,QAAAA,sBAC1BA,GAAO,QAAA,yBAEPpJ,KAAK2D,QAAQ9F,GAAOuL,SAAO,QAAA,UAAA,+BAEzC,OAAA,cAAA,gCAd2B,GAgB5BnJ,EASaoJ,qCAAoC,WAAA,kBAA1C,WACHvQ,EACAvJ,EACAqW,oEAA4D,gBAA5DA,IAAAA,EAAqC,CAAE0D,cAAc,sBAE9CtJ,KAAKuJ,6BAA6BzQ,EAAgBvJ,EAAUqW,IAAQ,OAAA,UAAA,+BAC9E,OAAA,gBAAA,gCANgD,GAQjD3F,EAQauJ,4BAA2B,WAAA,kBAAjC,WACH1Q,EACA8M,oEAA4D,gBAA5DA,IAAAA,EAAqC,CAAE0D,cAAc,sBAE9CtJ,KAAKuJ,6BAA6BzQ,EAAgB7J,mBAAiB2M,QAASgK,IAAQ,OAAA,UAAA,+BAC9F,OAAA,cAAA,gCALuC,GAKvC3F,EAEasJ,wCAA4B,kBAAlC,WACJzQ,EACAvJ,EACAqW,yFAA4D,gBAA5DA,IAAAA,EAAqC,CAAE0D,cAAc,IAAOG,SAEzCzJ,KAAK3F,UAAU,CAAEvB,eAAAA,IAAiB,OAAjDwB,SACA9I,EAAuD,GAAEkY,yBAAA,QAAA,6BAAA,OAAA,sBAAA,OAC/C,OAAL9Q,UAAK+Q,SACWC,EAAK7K,mBACtBnG,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,EAAK7K,mBACPnG,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,EAAM1K,SAAQ4K,SACZH,EAAK1K,YAAmCtG,EAAMtB,YAAcuS,EAAM1K,UAAS,OAAA,OAAA4K,+BAHvFlR,sBACAvB,iBACA6H,cACA7P,YAAI,OAAA,UAAA,0BAEX,mBAAA,qCACJ,QACDkC,OAAoBA,UAAuB,QAAA,UAAA,yBAAAgO,IAvC7BlF,GAAM,OAAA,iBAAAmP,UAAA,MAAA,mCAAA,OAAAA,SAAA,MAAA,QAAA,yBAyCjBjY,GAAY,QAAA,UAAA,+BACtB,OAAA,gBAAA,mCAEDyO,EAKa+J,wBAAuB,WAAA,kBAA7B,WAA8BC,GAAY,YAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAC,SACxBlK,KAAK3F,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,UAGtClK,KAAKjB,mBACPzH,EACA,CACI/H,SAAUN,mBAAiBC,SAC3BoM,aAAcC,eAAaC,wBAE/B,EACAyO,GACH,QAM+B,OAf9BI,SAUJ,GAAGlL,SAAQ+K,KAGTrR,EAAgBqR,KAChB5S,EAAW4S,KACDG,EAAsBH,UACpBlK,KAAKd,YAAmC5H,EAAa+S,GAAuB,QAAA,OAAAH,+BAHxFrR,sBACAvB,iBACA6H,cACA7P,YAAI,QAAA,UAAA,+BAEX,OAAA,YAAA,gCA/BmC,GAiCpC2Q,EAMaqK,sBAAqB,WAAA,kBAA3B,WAA4BxR,GAAoB,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAyR,SAChCvK,KAAK3F,UAAU,CAAEvB,eAAAA,IAAiB,OAA3C,GAEY,KAFlBwB,UAEOT,QAAY0Q,SAAA,MAAA,MACbnZ,EAAyB,OAAA,yBAG5BkJ,EAAO,IAAE,OAAA,UAAA,+BACnB,OAAA,YAAA,gCARiC,GAUlC2F,EAKauK,yBAAwB,WAAA,kBAA9B,WAA+B1R,GAAoB,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA2R,SAClCzK,KAAKsK,sBAAsBxR,GAAe,OAAnD,KAALF,YAEOA,EAAMC,kBAAgB4R,SAAA,MAAA,OAAAA,SAClBzK,KAAK5H,YAAYC,YAAYO,EAAMC,kBAAiB,OAAA,iCAAA,OAAA,8BAE1DpE,GAAS,QAAA,UAAA,+BAEvB,OAAA,YAAA,gCARoC,GAUrCwL,EAUalB,mBAAkB,WAAA,kBAAxB,WACHzH,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,eAAgBtJ,KAAKG,eAAewK,IAAYC,SAAA,MAAA,yBAAS5K,KAAKG,eAAewK,IAAY,OAAA,yBAE/F3K,KAAKzF,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,EAAK5L,YACzB5H,EACAuS,EAAMC,SAAS3D,gBACftN,GACH,OACDgR,EAAMC,cACCD,EAAMC,iBAEZ,OAAA,yBAEED,GAAK,OAAA,UAAA,0BACf,mBAAA,qCACHpW,MAAK,SAAC4T,GAAQ,OAAMyD,EAAK3K,eAAewK,GAAetD,SAC3D,OAAA,UAAA,+BACL,OAAA,oBAAA,gCAjC8B,GAmC/BpH,EAOa8K,2BAA0B,WAAA,kBAAhC,WACHtT,EACAnI,EACA6P,GAAiB,QAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA6L,SAEUhL,KAAK3F,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,yBACJhL,KAAK+G,eACRzP,EACAhI,EACA,CACIC,SAAUN,mBAAiBC,SAC3BoM,aAAcC,eAAaC,uBAE/B,QACA/G,EACA0K,IACH,QAAA,MAEKjO,EAAc,QAAA,UAAA,+BAE3B,OAAA,gBAAA,gCAxBsC,GA0BvC+O,EAOaiL,qBAAoB,WAAA,kBAA1B,WACHzT,EACA0T,EACAhM,GAAiB,QAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAiM,SAEUpL,KAAK3F,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,yBACJpL,KAAK+G,eACRzP,EACA6T,EACA,CACI5b,SAAUN,mBAAiB8M,WAC3BX,YAAa,oBAEjB,QACA3G,EACA0K,IACH,QAAA,MAEKjO,EAAc,QAAA,UAAA,+BAE3B,OAAA,gBAAA,gCAxBgC,GA0BjC+O,EAKaqL,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,SAEtCvL,KAAKjB,mBAAmBzH,EAAalF,GAAQ,EAAOwG,EAAMC,iBAAkB,CAAEyQ,cAAc,IAAO,OAMzE,OAP9Be,SAEJ,GAAGlL,SAAQoM,KAGT1S,EAAgB0S,KAChBjU,EAAWiU,KACDlB,EAAsBkB,UACpBvL,KAAKd,YAAe5H,EAAa+S,GAAuB,QAAA,OAAAkB,+BAHpE1S,sBACAvB,iBACA6H,cACA7P,YAAI,QAAA,UAAA,+BAEX,OAAA,cAAA,gCAf4B,GAiB7B2Q,EAKauL,+BAA8B,WAAA,kBAApC,WAAqC1S,GAAsB,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA2S,SAC1CzL,KAAKsK,sBAAsBxR,GAAe,OAAnD,GAALF,UAEI6S,SAAA,MAAA,MAAQza,EAAY,OAAA,yBAEvBgP,KAAKsL,iBAAiC1S,EAAO,CAChDrJ,SAAUN,mBAAiB8M,WAC3BX,YAAa,sBACf,OAAA,UAAA,+BACL,OAAA,YAAA,gCAT0C,GAW3C6E,EAKayL,kBAAiB,WAAA,kBAAvB,WAAwBjU,GAA0B,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAkU,SAChC3L,KAAK3F,YAAW,OAA4D,GAA3FzB,SAAiCuR,MAAK,SAACC,GAAO,OAAKA,EAAQvR,mBAAqBpB,EAAS7G,OAErF+a,SAAA,MAAA,MAAQ3a,EAAY,OAAA,yBAEvBgP,KAAKsL,iBAAiC1S,EAAO,CAChDrJ,SAAUN,mBAAiB8M,WAC3BX,YAAa,sBACf,OAAA,UAAA,+BACL,OAAA,YAAA,gCAT6B,GAW9B6E,EAKa2L,6BAA4B,WAAA,kBAAlC,WAAmC9S,GAAsB,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA+S,SACxC7L,KAAKsK,sBAAsBxR,GAAe,OAAnD,GAALF,UAEIiT,SAAA,MAAA,MAAQ7a,EAAY,OAAA,yBAEvBgP,KAAKsL,iBAA+B1S,EAAO,CAC9CrJ,SAAUN,mBAAiB6c,SAC3B1Q,YAAa,sBACf,OAAA,UAAA,+BACL,OAAA,YAAA,gCATwC,GAWzC6E,EAKa8L,gBAAe,WAAA,kBAArB,WAAsBtU,GAA0B,MAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAuU,SAC9BhM,KAAK3F,YAAW,OAA4D,GAA3FzB,SAAiCuR,MAAK,SAACC,GAAO,OAAKA,EAAQvR,mBAAqBpB,EAAS7G,OAErFob,SAAA,MAAA,MAAQhb,EAAY,OAAA,yBAEvBgP,KAAKsL,iBAAiB1S,EAAO,CAChCrJ,SAAUN,mBAAiB6c,SAC3B1Q,YAAa,sBACf,OAAA,UAAA,+BACL,OAAA,YAAA,gCAT2B,GAW5B6E,EAUagM,yBAAwB,WAAA,kBAA9B,WAA+BzK,GAAkB,WAAA,6BAAA,OAAA,sBAAA,OACtC,OADsC0K,KAC7C9Y,QAAO8Y,SACHlM,KAAK3F,YAAW,OAgBlB,OAhBkB6R,YAAEja,KAAI,SAAC2G,GAAK,OAC/BuT,EAAKpN,mBACDnG,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,GAuBrCyN,EAKaqM,kCAAiC,WAAA,kBAAvC,WACHxT,EACA0I,GAAoB,eAAA,6BAAA,OAAA,sBAAA,OAAA,OAAA+K,SAEAvM,KAAKsK,sBAAsBxR,GAAe,OAAnD,GAALF,UACI2T,SAAA,MAAA,8BAAS9X,GAAS,OAAA,OAAA8X,SAGlBvM,KAAKzF,YAAYkF,mBACnB7G,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+B9CvB,EAMa2M,2BAA0B,WAAA,kBAAhC,WACH9T,EACA8M,+EAGc,gBAHdA,IAAAA,EAAqC,CAAE0D,cAAc,IAAOuD,KAGrDzZ,QAAOyZ,SACH7M,KAAK3F,UAAU,CAAEvB,eAAAA,IAAiB,OAwBhC,OAxBgC+T,YACpC5a,KAAI,SAAC2G,GAAK,OACPkU,EAAK/N,mBACDnG,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,EAAK5N,YACDtG,EAAMtB,YACNhE,EAAE6L,SACFvG,EAAMC,4BAMzBrG,8BAzBMa,oBA0BbI,MAAK,SAACnE,GAAI,OAAKA,EAAKkD,WAAM,OAAA,UAAA,+BAC/B,OAAA,cAAA,gCAhCsC,GAkCvCyN,EAKa8M,4BAA2B,WAAA,kBAAjC,WAAkCjU,GAAoB,6BAAA,OAAA,sBAAA,OAAA,yBAClDkH,KAAKgN,wBACR,CACIzd,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa0R,eAE/B,EACAnU,IACH,OAAA,UAAA,+BACJ,OAAA,YAAA,gCATuC,GAWxCmH,EAKaiN,sBAAqB,WAAA,kBAA3B,WAA4BpU,GAAoB,6BAAA,OAAA,sBAAA,OAAA,yBAC5CkH,KAAKgN,wBACR,CACIzd,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa4R,SAE/B,EACArU,IACH,OAAA,UAAA,+BACJ,OAAA,YAAA,gCATiC,GAWlCmH,EAKamN,yBAAwB,WAAA,kBAA9B,WAA+BtU,GAAoB,6BAAA,OAAA,sBAAA,OAAA,yBAC/CkH,KAAKgN,wBACR,CACIzd,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa8R,gBAE/B,EACAvU,IACH,OAAA,UAAA,+BACJ,OAAA,YAAA,gCAToC,GAWrCmH,EAMaqN,8BAA6B,WAAA,kBAAnC,WAAoCxU,EAAsByU,GAAqB,6BAAA,OAAA,sBAAA,OAAA,yBAC3EvN,KAAKgN,wBACR,CACIzd,SAAUN,mBAAiBoM,aAC3BC,aAAcC,eAAa8R,cAC3BE,gBAAAA,IAEJ,EACAzU,IACH,OAAA,UAAA,+BACJ,OAAA,cAAA,gCAVyC,GAY1CmH,EASa+M,wBAAuB,WAAA,kBAA7B,WACHQ,EACA9C,EACA5R,GAAoB,WAAA,6BAAA,OAAA,sBAAA,OAEN,OAFM2U,KAEbra,QAAOqa,SACHzN,KAAK3F,UAAU,CAAEvB,eAAAA,IAAiB,OAoBhC,OApBgC2U,YACpCxb,KAAI,SAAC2G,GAAK,OACP8U,EAAK3O,mBACDnG,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,GAkCpCyN,EAQa0N,uCAAsC,WAAA,kBAA5C,WACH/c,EACA6I,EACAE,EACAiU,GAAiB,QAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAC,SAEkB7N,KAAK5H,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,IAEQrN,EAAad,KAAKL,QAAQ0O,kBAAkBP,EAAgBF,GAChE5N,KAAKY,IAAMZ,KAAKL,QAAQkB,UAAUmC,QAAQlC,GAC5C,MAAOxN,GACLU,QAAQC,MAAMX,GACjB,OAAA,UAAA,+BACJ,OAAA,kBAAA,gCA3BkD,GA6BnD2M,EAMawC,8BAA6B,WAAA,kBAAnC,WAAoC7R,EAAU0P,GAAgB,cAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAgO,SAC5CtO,KAAK5H,YAAYC,YAAYzH,GAAG,OAEjD+R,GAFAlL,UAE2ByJ,iBAC3B4B,EAAqB9C,KAAKL,QAAQqB,aAAaC,eAAeX,GAC9DQ,EAAagC,EAAmBC,4BAA4BJ,GAE5DlL,EAASoK,gBAELC,EAAoB9B,KAAKL,QAAQqB,aAAaC,eAAexJ,EAASoK,eAC1EE,eAAeC,QACXrR,EAA2BC,GAC3BkR,EAAkBX,4BAA4BL,KAItDd,KAAKY,IAAMZ,KAAKL,QAAQkB,UAAUmC,QAAQlC,GAAW,OAAA,UAAA,+BACxD,OAAA,cAAA,gCAjByC,GAmB1Cb,EAMasO,+BAA8B,WAAA,kBAApC,WAAqC3d,EAAUsG,GAAiB,UAAA,6BAAA,OAAA,sBAAA,OAAA,OAAAsX,SACtCxO,KAAK5H,YAAYC,YAAYzH,GAAG,OAAzD+R,SAA2DrJ,kBAC3DwJ,EAAqB9C,KAAKL,QAAQqB,aAAaC,eAAe/J,GAC9D4J,EAAagC,EAAmBC,4BAA4BJ,GAChE3C,KAAKY,IAAMZ,KAAKL,QAAQkB,UAAUmC,QAAQlC,GAAW,OAAA,UAAA,+BACxD,OAAA,cAAA,gCAL0C,GAO3Cb,EAQavG,wBAAuB,WAAA,kBAA7B,WACH9I,EACA6I,EACAE,EACAiU,GAAiB,QAAA,6BAAA,OAAA,sBAAA,OAAA,GAEZ5N,KAAKY,KAAG6N,SAAA,MAAA,MAAQ5d,EAAwB,OAS5C,OARG6d,EAA0B1O,KAAKL,QAAQgP,sBACvClV,EACAE,EACAqG,KAAKY,cACLgN,GAEAgB,EAAgB,CAChBnV,0BAA2BiV,GAC9BD,SAEYzO,KAAK5H,YAAY8J,eAAetR,EAAIge,GAAc,OAAA,iCAAA,OAAA,UAAA,+BAClE,OAAA,kBAAA,gCAlBmC,GAoBpC3O,EAWa4O,eAAc,WAAA,kBAApB,WAAqBje,EAAUke,EAAqBC,GAAoB,UAAA,6BAAA,OAAA,sBAAA,OAAA,GACtE/O,KAAKY,KAAGoO,SAAA,MAAA,MAAQne,EAAwB,OAgB5C,OAdGkQ,EAAqBf,KAAKL,QAAQqB,aAAaC,eAAe6N,GAC9DG,EAAkBlO,EAAmBI,4BAA4BnB,KAAKY,eACtEmO,IACAA,EAAc/O,KAAKL,QAAQ0B,mBAAmBrB,KAAKL,QAAQ0B,mBAAmB0N,KAGlFD,EAAc9O,KAAKL,QAAQ0B,mBAAmBrB,KAAKL,QAAQ0B,mBAAmByN,IAE1EF,EAAgB,CAChBtO,SAAU,CACNyO,YAAAA,EACAD,YAAAA,GAEJ5N,iBAAkB+N,GACrBD,SAEYhP,KAAK5H,YAAY8J,eAAetR,EAAIge,GAAc,OAAA,iCAAA,QAAA,UAAA,+BAClE,OAAA,gBAAA,gCApB0B,GAsB3B3O,EAQM1G,gBAAe,WAAA,kBAArB,WAAsB3I,EAAUsG,EAAmBI,GAAiB,YAAA,6BAAA,OAAA,sBAAA,OAAA,GAC3D0I,KAAKY,KAAGsO,SAAA,MAAA,MAAQre,EAAwB,OAIc,OAFvDkQ,EAAqBf,KAAKL,QAAQqB,aAAaC,eAAe/J,GAC9DiY,EAAmBpO,EAAmBI,4BAA4BnB,KAAKY,eACvEgO,EAAgB,CAAEtV,kBAAmB6V,GAAkBD,SAC7BlP,KAAK5H,YAAY8J,eAAetR,EAAIge,GAAc,OAA3D,OAAfQ,SAAeF,UAEflP,KAAK9E,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,oCC/gDZC,cAGT,WAAoBC,EAAaC,EAAwBzb,GAArCkM,SAAAsP,EAAqCtP,YAAAlM,EACrDkM,KAAKwP,IAAM,IAAIC,eAAa,CAAEC,QAAS,CAAEC,mBAAoBJ,KAChE,kBAkDA,OAlDAtP,EAEM2P,YAAA,SAAYC,GAQf,IAAQ/b,EAAoB+b,EAApB/b,OAAWxE,IAASugB,MAE5B,OAAO7P,KAAKwP,IAAIM,KACT9P,KAAKsP,+CACRhgB,EACA,CACIygB,OAAQ,CAAEjc,aAAQA,EAAAA,EAAUkM,KAAKlM,WAG5CmM,EAEM+P,WAAA,SACHH,EASAlJ,GAEA,IAAQ7S,EAAoB+b,EAApB/b,OAAWxE,IAASugB,MAExBvK,EAAUtF,KAAKwP,IAAIM,KAChB9P,KAAKsP,yBACRhgB,EACA,CACIygB,OAAQ,CAAEjc,aAAQA,EAAAA,EAAUkM,KAAKlM,UAUzC,OANI6S,IACArB,EAAUA,EAAQ7R,MAAK,SAACwc,GAAM,OAC1BA,EAAO7d,QAAO,SAAC8d,GAAK,OAAKA,EAAMvJ,OAASA,SAIzCrB,0jBClCF,SACT3F,EACAwQ,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACA3Q,GAEA,MASI4Q,EACA,CACIR,cAAAA,EACAC,aAAAA,EACAC,aAAAA,EACAC,cAAAA,EACAC,gBAAAA,EACAC,eAAAA,EACAC,gBAAAA,EACAC,iBAAAA,GAEJ3Q,GAgBJ,OAbe,IAAIL,GACfC,IAvBAiR,gBAGAC,eACAC,eACAC,gBAJAC,kBACAC,iBAIAC,kBACAC,iBAyBApR,gGVkCJpL,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,mBAAiB6P,OAC/BnK,QAAS,CACL6e,uCAAwC,CACpC5e,KAAM,OAEV6e,uCAAwC,CACpC7e,KAAM,QAIlBie,eAAgB,CACZO,MAAO,6BACP3hB,KAAM,QACN4hB,QAAQ,EACRC,aAAa,EACbC,aAActkB,mBAAiB6P,OAC/BnK,QAAS,CACL+e,uCAAwC,CACpC9e,KAAM,OAEV+e,uCAAwC,CACpC/e,KAAM,QAIlBgf,YAAa,CACTniB,KAAM,yBACN2hB,MAAO,uDACPG,aAActkB,mBAAiB6P,OAC/B+U,aAAc,iBAElBC,WAAY,CACRriB,KAAM,gBACN2hB,MAAO,UACPG,aAActkB,mBAAiB6P,WAK/ChL,OAAQ,KACRpC,gBAAAA,8PNnEJqiB,EACAzkB,EACAC,GAKA,IAAMC,EAASR,EAAqBO,GAE9BY,EAAMmX,KAAKoL,MAAMpL,KAAKC,UAAUjY,IA0BtC,OAxBIykB,EAAMtkB,UAAYU,EAAIG,OAAUd,gBAChCW,EAAIG,OAAUd,cAAkBkB,OAASqjB,EAAMtkB,UAC/CskB,EAAMrkB,WAAaS,EAAIG,OAAUd,iBACjCW,EAAIG,OAAUd,eAAmBkB,OAASqjB,EAAMrkB,WAChDqkB,EAAMpkB,QAAUQ,EAAIG,OAAUd,cAC9BW,EAAIG,OAAUd,YAAgBkB,OAASqjB,EAAMpkB,QAC7CokB,EAAMnkB,MAAQO,EAAIG,OAAUd,YAC5BW,EAAIG,OAAUd,UAAckB,OAASqjB,EAAMnkB,MAC3CmkB,EAAMlkB,OAASM,EAAIG,OAAUd,aAC7BW,EAAIG,OAAUd,WAAekB,OAASqjB,EAAMlkB,OAC5CkkB,EAAMjkB,KAAOK,EAAIG,OAAUd,WAC3BW,EAAIG,OAAUd,SAAakB,OAASqjB,EAAMjkB,KAC1CikB,EAAMhkB,MACFI,EAAIG,OAAUd,SACdW,EAAIG,OAAUd,SAAakB,OAASqjB,EAAMhkB,IACnCI,EAAIG,OAAUd,QAErBW,EAAIG,OAAUd,QAAYkB,OAASqjB,EAAMhkB,IAGzCI,EAAIG,OAAUd,SAAe,CAAEiC,KAAM,OAAQf,OAAQqjB,EAAMhkB,MAI5DI,oBUtFW"}
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 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 const emailConfirmed = !!skipEmailValidation\n\n const signupRequest: IdentityCreateRequest = {\n practiceUuid: practice.uuid,\n email: email.toLowerCase(),\n emailConfirmed,\n password: hashedPassword,\n publicKey: this.toolbox.encodeToBase64(this.rsa.public()),\n recoveryPassword,\n tosAndCpAcceptance,\n tokenData,\n subscription,\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","emailConfirmed","signupRequest","practiceUuid","toLowerCase","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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"}