oro-sdk 5.5.1 → 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 },\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 }\n )\n .catch((err) => {\n console.error('[SDK: prescription refill request] Some errors happened during refill data upload', err)\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(lockboxUuid!, { category: MetadataCategory.Raw, consultationId: consultRequest.uuidParent }, false)\n if (rawConsultationManifest && rawConsultationManifest.length > 0) {\n let rawConsultation = await oroClient.getJsonData<WorkflowData>(lockboxUuid!, rawConsultationManifest[0].dataUuid)\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(\n '[SDK: prescription refill request] parent consultation\\'s raw data not found',\n )\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\n } catch (err) {\n console.error(`[SDK] Error occured during prescription refill request: ${err}, retrying... Retries remaining: ${retry}`)\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 ): 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)\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 ): 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)\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 } = { withNotification: false }\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 } = { withNotification: false }\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)\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 } = { withNotification: false, forceReplace: false }\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 { withNotification: options.withNotification }\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 } = { withNotification: false }\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)\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(\n lockboxUuid,\n filter,\n false,\n grant.lockboxOwnerUuid,\n { forceRefresh: true }\n )\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 }\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","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","_context13","author","encryptedPrivateMeta","lockboxDataStore","publicMetadata","Message","privateMetadata","createMessageAttachmentData","_context14","Uint8Array","arrayBuffer","lastModified","size","fileName","type","createConsultationAttachmentData","options","_context15","createBytesData","createJsonData","meta","privateMeta","_context16","forceReplace","_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":"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"}
1
+ {"version":3,"file":"oro-sdk.cjs.production.min.js","sources":["../src/helpers/client.ts","../src/models/error.ts","../src/helpers/workflow.ts","../src/helpers/consult.ts","../src/helpers/patient-registration.ts","../src/helpers/vault-grants.ts","../src/helpers/prescription-refill.ts","../src/sdk-revision/client.ts","../src/client.ts","../src/services/external/clinia.ts","../src/index.ts"],"sourcesContent":["import {\n PopulatedWorkflowData,\n MetadataCategory,\n SelectedAnswersData,\n} from 'oro-sdk-apis'\nimport { PersonalInformations } from '../models/client'\n\nconst personalMetaToPrefix = {\n [MetadataCategory.Personal]: 'you',\n [MetadataCategory.ChildPersonal]: 'child',\n [MetadataCategory.OtherPersonal]: 'other',\n}\n\n/**\n * This function extract PersonalInformations from data input object coming from workflow\n * @param data extracted from WorkflowData\n * @returns PersonalInformations of a patient\n */\nexport function identificationToPersonalInformations(\n data: any,\n category:\n | MetadataCategory.Personal\n | MetadataCategory.ChildPersonal\n | MetadataCategory.OtherPersonal\n): PersonalInformations {\n const prefix = personalMetaToPrefix[category]\n\n return {\n birthday: data[`${prefix}Birthday`],\n firstname: data[`${prefix}Firstname`],\n gender: data[`${prefix}Gender`],\n name: data[`${prefix}Name`],\n phone: data[`${prefix}Phone`],\n zip: data[`${prefix}Zip`],\n hid: data[`${prefix}HID`] ?? data[`${prefix}ID`], // This is done for backward compatibility (historically youID was used)\n pharmacy: data[`${prefix}Pharmacy`],\n address: data[`${prefix}Address`],\n }\n}\n\nexport function toActualObject(data: PopulatedWorkflowData) {\n const ret: any = {}\n\n Object.entries(data.fields).forEach(([key, field]) => {\n ret[key] = field.displayedAnswer ? field.displayedAnswer : field.answer\n })\n\n return ret\n}\n\n/**\n * This function update a PopulatedWorkflowData with PersonalInformations\n * @param infos the personal informations\n * @param data the PopulatedWorkflowData\n * @returns an updated PopulatedWorkflowData\n */\nexport function updatePersonalIntoPopulatedWorkflowData(\n infos: PersonalInformations,\n data: PopulatedWorkflowData,\n category:\n | MetadataCategory.Personal\n | MetadataCategory.ChildPersonal\n | MetadataCategory.OtherPersonal\n) {\n const prefix = personalMetaToPrefix[category]\n\n const ret = JSON.parse(JSON.stringify(data)) // deep copy PopulatedWorkflowData\n\n if (infos.birthday && ret.fields[`${prefix}Birthday`])\n ret.fields[`${prefix}Birthday`].answer = infos.birthday\n if (infos.firstname && ret.fields[`${prefix}Firstname`])\n ret.fields[`${prefix}Firstname`].answer = infos.firstname\n if (infos.gender && ret.fields[`${prefix}Gender`])\n ret.fields[`${prefix}Gender`].answer = infos.gender\n if (infos.name && ret.fields[`${prefix}Name`])\n ret.fields[`${prefix}Name`].answer = infos.name\n if (infos.phone && ret.fields[`${prefix}Phone`])\n ret.fields[`${prefix}Phone`].answer = infos.phone\n if (infos.zip && ret.fields[`${prefix}Zip`])\n ret.fields[`${prefix}Zip`].answer = infos.zip\n if (infos.hid) {\n if (ret.fields[`${prefix}HID`]) {\n ret.fields[`${prefix}HID`].answer = infos.hid\n } else if (ret.fields[`${prefix}ID`]) {\n // This is done for backward compatibility (historically youID was used)\n ret.fields[`${prefix}ID`].answer = infos.hid\n } else {\n // If does not exist create it\n ret.fields[`${prefix}HID`] = { kind: 'text', answer: infos.hid }\n }\n }\n\n return ret\n}\n\n/**\n * This function extract an ISO 3166-1 alpha-2 country and subdivision code from data input object coming from workflow\n * @param answers answers from the WorkflowData\n * @returns an ISO 3166 alpha-2 code or undefined\n */\nexport function extractISOLocalityForConsult(\n answers?: SelectedAnswersData\n): string | undefined {\n if (!answers) {\n return undefined\n }\n\n const arrAnswersWithLocality = answers\n .flatMap((currentAnswerPage) => {\n const arrCountryFields = Object.keys(currentAnswerPage)\n .filter(\n (workflowFieldName) =>\n workflowFieldName.indexOf('Country') !== -1\n )\n .flat()\n const arrProvinceFields = Object.keys(currentAnswerPage)\n .filter(\n (workflowFieldName) =>\n workflowFieldName.indexOf('Province') !== -1\n )\n .flat()\n const arrConsultLocalFields = Object.keys(currentAnswerPage)\n .filter(\n (workflowFieldName) =>\n workflowFieldName.indexOf('Locality') !== -1\n )\n .flat()\n //returning the actual selected values, skipping if their IDs are more complex than a string\n return [\n ...arrCountryFields.map(\n (currentFieldName) =>\n (typeof currentAnswerPage[currentFieldName] === 'string'\n ? currentAnswerPage[currentFieldName]\n : undefined) as string\n ),\n ...arrProvinceFields.map(\n (currentFieldName) =>\n (typeof currentAnswerPage[currentFieldName] === 'string'\n ? currentAnswerPage[currentFieldName]\n : undefined) as string\n ),\n ...arrConsultLocalFields.map(\n (currentFieldName) =>\n (typeof currentAnswerPage[currentFieldName] === 'string'\n ? currentAnswerPage[currentFieldName]\n : undefined) as string\n ),\n ]\n })\n .filter((item) => item !== undefined)\n\n const arrSelectedLocality = arrAnswersWithLocality.filter(\n (currentSelectedLocality) =>\n currentSelectedLocality.startsWith('isoLocalityConsult')\n )\n if (!arrSelectedLocality || arrSelectedLocality.length === 0) {\n console.log('no locality found in ' + arrSelectedLocality)\n return undefined\n }\n //to allow enforcing of an order, we will allow the following pattern in the isoLocalityConsult field name\n // isoLocalityConsult-QC-CA and isoLocalityConsult_1-QC-CA\n // or generally: isoLocalityConsult-<isoValue> or isoLocalityConsult_<priority>-<isoValue>\n const allowedLocalityPatterns = /isoLocalityConsult(?:_(?<indexPriority>\\d*))?-(?<isoValue>[a-zA-Z0-9]{2}-[a-zA-Z0-9]{1,3})/\n const finalLocality = arrSelectedLocality.reduce<string | undefined>(\n (finalLocality, currentSelectedLocality) => {\n const extractedSelected = allowedLocalityPatterns.exec(\n currentSelectedLocality\n )\n const [, indexSelectedPriority, isoSelectedValue] =\n extractedSelected ?? []\n if (!finalLocality) {\n return isoSelectedValue\n }\n\n const extractedFinal = allowedLocalityPatterns.exec(finalLocality)\n const [, indexFinalPriority, isoFinalValue] = extractedFinal ?? []\n //we only keep the old value if there's priority used\n // and the new value is of lower priority\n if (\n !indexSelectedPriority ||\n (indexFinalPriority &&\n indexFinalPriority > indexSelectedPriority)\n ) {\n return isoFinalValue\n }\n\n return isoSelectedValue\n },\n undefined\n )\n\n console.log('Picking locality ' + finalLocality)\n return finalLocality\n}\n\nconst sessionPrivateKeyPrefix = 'sess-pkey'\nexport function sessionStorePrivateKeyName(id: string): string {\n return sessionPrivateKeyPrefix + id\n}\n","export class IncompleteAuthentication extends Error { }\nexport class MissingGrant extends Error { }\nexport class MissingGrantFilter extends Error { }\nexport class MissingLockbox extends Error { }\nexport class MissingLockboxOwner extends Error { }\nexport class AssociatedLockboxNotFound extends Error { }\nexport class WorkflowAnswersMissingError extends Error { }\n","import { getMany } from 'idb-keyval'\nimport { WorkflowAnswersMissingError } from '../models'\nimport {\n MetadataCategory,\n PopulatedWorkflowData,\n PopulatedWorkflowField,\n QuestionData,\n SelectedAnswerData,\n SelectedAnswersData,\n WorkflowData,\n WorkflowPageData,\n WorkflowUploadedImage,\n} from 'oro-sdk-apis'\n\nexport async function filterTriggeredAnsweredWithKind(\n workflowData: WorkflowData,\n kind:\n | 'text'\n | 'text-area'\n | 'text-select-group'\n | 'date'\n | 'number'\n | 'images'\n | 'images-alias'\n | 'body-parts'\n | 'pharmacy-picker'\n | 'online-pharmacy-picker'\n | 'hair-selector-women'\n | 'hair-selector-men'\n | 'hair-loss-stage'\n | 'hair-loss-frontal'\n): Promise<SelectedAnswerData[]> {\n if (!workflowData.selectedAnswers) throw WorkflowAnswersMissingError\n // Flattens the list of answered questions\n let flattenedAnswers = flattenSelectedAnswers(workflowData.selectedAnswers)\n // Generates a list of applicable questions\n let triggeredQuestionsWithKind = Object.fromEntries(\n workflowData.pages\n .map((a) => {\n return Object.entries(a.questions).filter(\n ([_, question]) => isTriggered(question.triggers || [], flattenedAnswers) && question.kind === kind\n )\n })\n .flat()\n )\n\n const samePageAnswers = workflowData.selectedAnswers.reduce((prev, cur) => {\n return { ...prev, ...cur }\n }, {})\n\n const res = Object.keys(triggeredQuestionsWithKind).map((questionFieldName) => {\n return samePageAnswers[questionFieldName]\n })\n\n return res\n}\n\n/**\n * Filters and Populates the `selectedAnswers` from the workflow by\n * Cross-referencing the `MetaCategory` of the answer's respective question\n * Populates the fields labels and values that are of radio, dropdown and checkbox types\n *\n * @param workflowData\n * @param category\n * @returns An array of record key, value pairs\n */\nexport async function getWorkflowDataByCategory(\n workflowData: WorkflowData,\n category: MetadataCategory\n): Promise<PopulatedWorkflowData> {\n if (!workflowData.selectedAnswers) throw WorkflowAnswersMissingError\n\n // Flattens the list of answered questions\n let flattenedAnswers = flattenSelectedAnswers(workflowData.selectedAnswers)\n // Generates a list of applicable questions\n let triggeredQuestions = Object.fromEntries(\n workflowData.pages\n .map((a) => {\n return Object.entries(a.questions).filter(([_, question]) =>\n isTriggered(question.triggers || [], flattenedAnswers)\n )\n })\n .flat()\n )\n\n const fields: Record<string, PopulatedWorkflowField> = {}\n\n // Generates the answers of the specified category and adds the appropriate values if any are missing\n return Promise.all(\n workflowData.selectedAnswers\n .map((e) => Object.entries(e))\n .flat()\n .filter(([k, v]) => triggeredQuestions[k] && triggeredQuestions[k]['metaCategory'] === category)\n .map(([k, v]) => {\n return populateWorkflowField(triggeredQuestions[k], v).then((populatedValue) => {\n fields[k] = populatedValue\n })\n })\n )\n .then(() => {\n const ret: PopulatedWorkflowData = {\n workflowCreatedAt: workflowData.createdAt,\n workflowId: workflowData.id,\n locale: workflowData.locale,\n fields,\n }\n return ret\n })\n .catch((err) => {\n console.error(`Error while extracting ${category} data from workflow`, err)\n throw err\n })\n}\n\nexport async function getImagesFromIndexDb(answer: SelectedAnswerData): Promise<WorkflowUploadedImage[]> {\n return await getMany<WorkflowUploadedImage>((answer as any[]).map((v) => v.id ?? v) as string[])\n}\n\n/**\n * (If applicable) Based on the question kind, and the answer type this function will add and replace the appropriate fields to the\n * field values if they are radio, dropdown and checkbox fields\n *\n *\n * @param question\n * @param answerValue\n * @returns\n */\nasync function populateWorkflowField(\n question: QuestionData,\n answerValue: SelectedAnswerData\n): Promise<PopulatedWorkflowField> {\n let answer: any\n let displayedAnswer: string | string[] | undefined = undefined\n switch (question.kind) {\n case 'text-select-group':\n if (question.answers) {\n displayedAnswer = `${answerValue[0]} ${question.answers[answerValue[1] as string].text}`\n }\n answer = answerValue\n break\n case 'radio':\n case 'radio-card':\n case 'select':\n if (question.answers) {\n displayedAnswer = question.answers[answerValue as string].text\n }\n\n answer = answerValue\n break\n case 'multiple':\n case 'checkbox-group':\n displayedAnswer = (answerValue as string[]).map((value) => {\n if (question.answers) {\n return question.answers[value].text\n }\n\n throw new WorkflowAnswersMissingError()\n })\n\n answer = answerValue\n break\n case 'images':\n answer = await getImagesFromIndexDb(answerValue).then((images) =>\n images.map((image) => {\n const { name, imageData } = image\n\n return { name, imageData }\n })\n )\n break\n default:\n answer = answerValue\n }\n\n return Promise.resolve({\n answer,\n displayedAnswer,\n kind: question.kind,\n })\n}\n\n/**\n * Determine if a question is triggered by some answers\n *\n * We use the following logical combinations of rules:\n *\n * #### Single string\n *\n * ```\n * // Required: rule1\n * rules: rule1\n * ```\n *\n * #### Array of strings (AND is applied between statements):\n *\n * ```\n * // Required: rule1 AND rule2\n * rules: [ rule1, rule2 ]\n * ```\n *\n * #### Array of arrays of strings (OR is applied between inner arrays. AND is applied between inner arrays statements)\n *\n * ```\n * // Required: rule1 OR rule2\n * rules: [\n * [ rule1 ],\n * [ rule2 ]\n * ]\n *\n * // Required: rule1 OR (rule2 AND rule3)\n * rules: [\n * [ rule1 ],\n * [ rule2, rule3 ]\n * ]\n *\n * // THIS IS FORBIDDEN\n * rules: [\n * rule1, // <-- THIS IS FORBIDDEN. Instead use [ rule1 ]\n * [ rule2, rule3 ]\n * ]\n * ```\n *\n * @param triggers the triggering rules\n * @param answers the answers to check againts triggering rules\n * @returns `true` if triggers are verified against ansers. Otherwise, returns `false`.\n * @throws an Error if triggers typing is wrong\n */\nexport function isTriggered(triggers: string[][] | string[] | string, answers: string[]): boolean {\n // is triggers contained in answers\n if (typeof triggers === 'string') {\n return answers.includes(triggers)\n }\n\n if (Array.isArray(triggers)) {\n // rule combination kind: rule1 OR (rule2 AND rule3)\n if (Array.isArray(triggers[0])) {\n return (triggers as string[][]).some((subSetTriggers) =>\n subSetTriggers.every((trigger) => answers.includes(trigger))\n )\n } else {\n // rule combination kind: rule1 AND rule2\n return (triggers as string[]).every((trigger) => answers.includes(trigger))\n }\n }\n\n throw Error('[isTriggered] triggers is not typed well')\n}\n\nexport function flattenSelectedAnswers(answers: SelectedAnswersData) {\n const linearAnswers: SelectedAnswerData[] = []\n\n for (const answer of answers) {\n linearAnswers.push(...Object.values(answer))\n }\n\n return linearAnswers.flat(1)\n}\n\n/**\n * This function helps you to get a valid workflow selectedAnswers structure\n * @param workflow the workflow data to use to initialize selectedAnswers\n * @param useDefault use workflow default values or not (this is used to avoid having unset values to appear in summaries)\n * @returns a valid selectedAnswers structure\n */\nexport function getInitialisedSelectedAnswers(workflow: WorkflowData, useDefault: boolean = true) {\n return workflow.pages.map((page) => {\n const ret: any = {}\n for (const [id, question] of Object.entries(page.questions)) {\n if (question.kind === 'body-parts') {\n ret[id] = useDefault ? [] : undefined\n } else {\n ret[id] = useDefault && question.defaultValue ? question.defaultValue : undefined\n }\n }\n return ret\n })\n}\n\nexport function fillWorkflowFromPopulatedWorkflow(workflow: WorkflowData, populatedWorkflow: PopulatedWorkflowData) {\n const filledWorkflow = JSON.parse(JSON.stringify(workflow))\n\n if (!filledWorkflow.selectedAnswers) {\n filledWorkflow.selectedAnswers = getInitialisedSelectedAnswers(filledWorkflow, false)\n }\n\n filledWorkflow.pages.forEach((page: WorkflowPageData, pageIdx: number) => {\n const ret: any = {}\n for (const [id] of Object.entries(page.questions)) {\n if (populatedWorkflow.fields[id]) {\n if (filledWorkflow.selectedAnswers)\n filledWorkflow.selectedAnswers[pageIdx][id] = populatedWorkflow.fields[id].answer as\n | string\n | string[]\n }\n }\n })\n\n return filledWorkflow\n}\n","import { Consult, ConsultRequest } from 'oro-sdk-apis'\nimport { OroClient } from '..'\n\n/**\n * Creates a consultation if one has not been created and fails to be retrieved by the payment intent\n * @param consult\n * @param oroClient\n * @returns the consult Uuid\n */\nexport async function getOrCreatePatientConsultationUuid(\n consult: ConsultRequest,\n oroClient: OroClient\n): Promise<Consult> {\n let payment = await oroClient.practiceClient.practiceGetPayment(\n consult.uuidPractice,\n consult.idStripeInvoiceOrPaymentIntent\n )\n if (payment && payment.uuidConsult) {\n return oroClient.consultClient.getConsultByUUID(payment.uuidConsult).catch((err) => {\n console.error('Error while retrieving consult', err)\n throw err\n })\n } else {\n return await oroClient.consultClient.consultCreate(consult).catch((err) => {\n console.error('Error while creating consult', err)\n throw err\n })\n }\n}\n","import {\n Consult,\n ConsultationImageMeta,\n ConsultationMeta,\n ConsultRequest,\n DocumentType,\n IdentityResponse,\n IndexKey,\n MedicalMeta,\n MedicalStatus,\n MetadataCategory,\n PersonalMeta,\n PopulatedWorkflowData,\n Practitioner,\n PreferenceMeta,\n RawConsultationMeta,\n Term,\n Terms,\n Uuid,\n VaultIndex,\n WorkflowData,\n} from 'oro-sdk-apis'\nimport {\n filterTriggeredAnsweredWithKind,\n getImagesFromIndexDb,\n getWorkflowDataByCategory,\n identificationToPersonalInformations,\n OroClient,\n RegisterPatientOutput,\n toActualObject,\n} from '..'\nimport { getOrCreatePatientConsultationUuid } from './consult'\n\nconst MAX_RETRIES = 15\n\n/**\n * Completes a registration for a user retrying the complete flow a maximum of 15 times\n *\n * @description The order of importance when registering:\n * Creates a consultation if none exist\n * Retrieves or create's a lockbox if none exist\n * Grants the lockbox (if new) to all practitioners in the practice\n * Stores or fetches the patient data (without images)\n * Indexes the lockbox to the consult for all practitioners (done after inserting since index can be rebuilt from grants)\n * Stores the image data - done last since the majority of failure cases occur here\n * Creates the recovery payloads if they don't exist\n *\n * @param patientUuid\n * @param consultRequest\n * @param workflow\n * @param oroClient\n * @param masterKey\n * @param recoveryQA\n * @param indexSearch create search index for the consultation if true\n * @param onProgress callback that is called whenever a new step of patient registration is executed. Note: progress ranges from 0 to 1, and descriptionKey is a description of the progress as a key so the app would use it to translate the description\n * @returns the successful registration\n */\nexport async function registerPatient(\n patientUuid: Uuid,\n consultRequest: ConsultRequest,\n workflow: WorkflowData,\n oroClient: OroClient,\n masterKey?: Uuid,\n recoveryQA?: {\n recoverySecurityQuestions: string[]\n recoverySecurityAnswers: string[]\n },\n indexSearch: boolean = true,\n onProgress?: (\n progress: number,\n descriptionKey: string,\n extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }\n ) => void\n): Promise<RegisterPatientOutput> {\n let consult: Consult | undefined = undefined\n let lockboxUuid: Uuid | undefined = undefined\n let practitionerAdmin: Uuid | undefined = undefined\n let retry = MAX_RETRIES\n let identity: IdentityResponse | undefined = undefined\n let errorsThrown: Error[] = []\n const stepsTotalNum = 9\n let currentStep: number\n\n for (; retry > 0; retry--) {\n try {\n currentStep = 0\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'retrieve_practitioners')\n\n // Wait a bit each retry (we also want the first one to wait)\n await new Promise((resolve) => setTimeout(resolve, 2000))\n\n // Retrieving practitioners\n if (!practitionerAdmin)\n practitionerAdmin = (await oroClient.practiceClient.practiceGetFromUuid(consultRequest.uuidPractice))\n .uuidAdmin\n\n let practitioners: Practitioner[] = await oroClient.practiceClient\n .practiceGetPractitioners(consultRequest.uuidPractice)\n .catch((err) => {\n console.log(`Error retrieving practitioners`, err)\n return []\n })\n\n // Creating consult\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_consult')\n\n if (!consult) {\n consult = await getOrCreatePatientConsultationUuid(consultRequest, oroClient)\n }\n\n // Creating lockbox\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_lockbox')\n\n if (!lockboxUuid) lockboxUuid = await getOrCreatePatientLockbox(oroClient)\n\n if (!identity) identity = await oroClient.guardClient.identityGet(patientUuid)\n\n await oroClient.grantLockbox(practitionerAdmin, lockboxUuid).catch((err) => {\n console.error(`Error while granting lockbox to practitioner admin ${practitionerAdmin}`, err)\n // if we cannot grant to the admin, then the registration will fail\n errorsThrown.push(err)\n })\n\n // Patient Grant to practice\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'grant_patient')\n\n let grantPromises = practitioners\n .filter((practitioner) => practitioner.uuid !== practitionerAdmin)\n .map(async (practitioner) => {\n return oroClient.grantLockbox(practitioner.uuid, lockboxUuid!).catch((err) => {\n console.error(`Error while granting lockbox to practitioner`, err)\n // Acceptable to continue as admin has already been granted, but we should still retry until the last retry remains\n if (retry <= 1) return\n errorsThrown.push(err)\n })\n })\n\n const consultIndex: VaultIndex = {\n [IndexKey.ConsultationLockbox]: [\n {\n grant: {\n lockboxUuid,\n lockboxOwnerUuid: patientUuid,\n },\n consultationId: consult.uuid,\n },\n ],\n }\n\n // the index will identify in which lockbox a consultation resides\n let consultIndexPromises = practitioners.map(async (practitioner) => {\n return oroClient.vaultIndexAdd(consultIndex, practitioner.uuid).catch((err) => {\n console.error(\n `[SDK: registration] Error while adding to the practitioner's index ${practitioner.uuid}`,\n err\n )\n // Acceptable to continue as the index can be rebuilt, but we should still retry until the last retry remains\n if (retry <= 1) return\n else errorsThrown.push(err)\n })\n })\n\n await storeImageAliases(\n consult.uuid,\n lockboxUuid,\n workflow,\n oroClient,\n onProgress\n ? {\n onProgress,\n currentStep,\n stepsTotalNum,\n }\n : undefined\n ).catch((err) => {\n console.error('[SDK: registration] Some errors happened during image upload', err)\n // Acceptable to continue as images can be requested during the consultation, but we should still retry until the last retry remains\n if (retry <= 1) return\n else errorsThrown.push(err)\n })\n ++currentStep\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'store_patient_data')\n\n await storePatientData(\n consult.uuid,\n consultRequest.isoLanguageRequired,\n lockboxUuid,\n workflow,\n oroClient\n ).catch((err) => {\n console.error('[SDK: registration] Some errors happened during patient data upload', err)\n errorsThrown.push(err)\n })\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'set_masterkey')\n\n if (masterKey && !identity?.recoveryMasterKey) {\n // generate and store recovery payload and updates the identity\n identity = await oroClient.updateMasterKey(patientUuid, masterKey, lockboxUuid).catch((err) => {\n console.error(`[SDK: registration] Error while updating master key`, err)\n /// it's acceptable to continue registration (return old identity)\n if (retry <= 1) return\n errorsThrown.push(err)\n return identity\n })\n } else {\n // we did not set the master key so we do not return it\n masterKey = undefined\n }\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'set_security_questions')\n\n if (recoveryQA && !identity?.recoverySecurityQuestions)\n // Patient security question recovery threshold is 2 answers and updates the identity\n identity = await oroClient\n .updateSecurityQuestions(\n patientUuid,\n recoveryQA.recoverySecurityQuestions,\n recoveryQA.recoverySecurityAnswers,\n 2\n )\n .catch((err) => {\n console.error(`[SDK: registration] Error while updating security questions`, err)\n /// it's acceptable to continue registration (return old identity)\n if (retry <= 1) return\n errorsThrown.push(err)\n return identity\n })\n\n await Promise.all([...grantPromises, ...consultIndexPromises])\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'search_indexing')\n\n if (indexSearch) {\n await buildConsultSearchIndex(consult, workflow, oroClient).catch((err) => {\n console.error(\n '[SDK: registration] personal information not found or another error occured during search indexing',\n err\n )\n if (retry <= 1) return // this statement is to avoid failing the registration due to the failure in search indexing the consult, this practically implements a soft retry\n errorsThrown.push(err)\n })\n }\n\n if (errorsThrown.length > 0) throw errorsThrown\n\n // Deem the consultation as ready\n await oroClient.consultClient.updateConsultByUUID(consult.uuid, {\n statusMedical: MedicalStatus.New,\n })\n\n // if we got through the complete flow, the registration succeeded\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'success')\n\n break\n } catch (err) {\n console.error(`[SDK] Error occured during registration: ${err}, retrying... Retries remaining: ${retry}`)\n errorsThrown = []\n continue\n }\n }\n\n if (retry <= 0) {\n console.error('[SDK] registration failed: MAX_RETRIES reached')\n throw 'RegistrationFailed'\n }\n\n console.log('Successfully Registered')\n await oroClient.cleanIndex()\n return {\n masterKey,\n consultationId: consult!.uuid,\n lockboxUuid: lockboxUuid!,\n }\n}\n\n/**\n * Creates a new lockbox for the patient if they do not have any, otherwise, use the first (and only one)\n * @param oroClient\n * @returns the lockbox Uuid\n */\nasync function getOrCreatePatientLockbox(oroClient: OroClient): Promise<Uuid> {\n let grants = await oroClient.getGrants()\n if (grants.length > 0) {\n console.log('The grant has already been created, skipping lockbox create step')\n return grants[0].lockboxUuid!\n } else {\n let lockboxResponse = await oroClient.vaultClient.lockboxCreate().catch((err) => {\n console.error('Error while creating lockbox', err)\n throw err\n })\n // Since the creation of a lockbox will change the scope of a user, we will force refresh the tokens\n let tokens = await oroClient.guardClient.authRefresh()\n await oroClient.guardClient.setTokens({ accessToken: tokens.accessToken, refreshToken: tokens.refreshToken })\n await oroClient.guardClient.whoAmI(true)\n\n return lockboxResponse.lockboxUuid\n }\n}\n\n/**\n * Store all patient related information into his/her lockbox\n * @param consultationId The consultation id\n * @param isoLanguage the prefered language of communication (ISO 639-3 https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes)\n * @param lockboxUuid the lockbox uuid to store data in\n * @param workflow the workflow used to extract informations\n * @param oroClient an oroClient instance\n * @returns\n */\nasync function storePatientData(\n consultationId: Uuid,\n isoLanguage: string,\n lockboxUuid: Uuid,\n workflow: WorkflowData,\n oroClient: OroClient\n): Promise<(Uuid | void)[]> {\n // Create and store registration data\n return Promise.all([\n // Storing Raw data first\n oroClient.getOrInsertJsonData<RawConsultationMeta>(\n lockboxUuid,\n workflow,\n {\n category: MetadataCategory.Raw,\n contentType: 'application/json',\n consultationId,\n },\n {}\n ),\n getWorkflowDataByCategory(workflow, MetadataCategory.Consultation).then((data) =>\n oroClient.getOrInsertJsonData<ConsultationMeta>(\n lockboxUuid,\n data,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationId, // TODO: deprecated. Will finally only be in privateMetadata\n },\n { consultationId },\n { withNotification: true, forceReplace: false, updateMedicalStatus: false }\n // the only data that needs to include an email notification\n )\n ),\n getWorkflowDataByCategory(workflow, MetadataCategory.Medical).then((data) =>\n oroClient.getOrInsertJsonData<MedicalMeta>(\n lockboxUuid,\n data,\n {\n category: MetadataCategory.Medical,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationIds: [consultationId!],\n },\n {}\n )\n ),\n extractAndStorePersonalWorkflowData(\n workflow,\n lockboxUuid,\n consultationId,\n MetadataCategory.Personal,\n oroClient\n ),\n extractAndStorePersonalWorkflowData(\n workflow,\n lockboxUuid,\n consultationId,\n MetadataCategory.ChildPersonal,\n oroClient\n ),\n extractAndStorePersonalWorkflowData(\n workflow,\n lockboxUuid,\n consultationId,\n MetadataCategory.OtherPersonal,\n oroClient\n ),\n oroClient.getOrInsertJsonData<PreferenceMeta>(\n lockboxUuid,\n { isoLanguage },\n {\n category: MetadataCategory.Preference,\n contentType: 'application/json',\n },\n {}\n ),\n ]).then((dataUuids) => dataUuids.flat())\n}\n\nasync function storeImageAliases(\n consultationId: Uuid,\n lockboxUuid: Uuid,\n workflow: WorkflowData,\n oroClient: OroClient,\n progress?: {\n currentStep: number\n stepsTotalNum: number\n onProgress: (\n progress: number,\n descriptionKey: string,\n extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }\n ) => void\n }\n): Promise<(Uuid | void)[]> {\n const images = await getImagesFromIndexDb((await filterTriggeredAnsweredWithKind(workflow, 'images-alias')).flat())\n\n const nonNullImages = images.filter((img) => !!img)\n\n if (images.length !== nonNullImages.length) {\n console.error('[SDK] Some images have not been found, they have been skipped.')\n }\n\n let storedImagesNum = 0\n let totalImagesNum = nonNullImages.length\n if (progress)\n progress.onProgress(progress.currentStep / progress.stepsTotalNum, 'store_images', {\n storedImagesNum,\n totalImagesNum,\n })\n\n let promises = nonNullImages.map((image) => {\n return oroClient\n .getOrInsertJsonData<ConsultationImageMeta>(\n lockboxUuid,\n image,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.ImageAlias,\n consultationId,\n idbId: image.idbId as string,\n },\n {}\n )\n .then(() => {\n if (progress) {\n ++storedImagesNum\n let progressStepValue =\n Math.round(\n ((progress.currentStep + 1) / progress.stepsTotalNum -\n progress.currentStep / progress.stepsTotalNum) *\n 100\n ) / 100\n progress.onProgress(\n progress.currentStep / progress.stepsTotalNum +\n progressStepValue * (storedImagesNum / totalImagesNum),\n 'store_images',\n {\n storedImagesNum,\n totalImagesNum,\n }\n )\n }\n })\n })\n return Promise.all(promises)\n}\n\n/**\n * Extracts the workflow MetadataCategory for Personal, ChildPersonal and OtherPersonal\n * then stores it in the vault\n *\n * @param workflow\n * @param lockboxUuid\n * @param category\n * @returns The data uuid\n */\nexport async function extractAndStorePersonalWorkflowData(\n workflow: WorkflowData,\n lockboxUuid: Uuid,\n consultationId: Uuid,\n category: MetadataCategory.Personal | MetadataCategory.ChildPersonal | MetadataCategory.OtherPersonal,\n oroClient: OroClient\n): Promise<Uuid | void> {\n return getWorkflowDataByCategory(workflow, category as unknown as MetadataCategory).then((data) => {\n if (Object.keys(data.fields).length === 0) return\n return oroClient.getOrInsertJsonData<PersonalMeta>(\n lockboxUuid,\n data,\n {\n category,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationIds: [consultationId],\n },\n {}\n )\n })\n}\n\n/**\n * Given workflow data, it populates it with Personal, ChildPersonal, and OtherPersonal workflow data\n * @param workflow\n */\nexport async function extractPersonalInfoFromWorkflowData(workflow: WorkflowData): Promise<{\n personalInfoPopulatedWfData: PopulatedWorkflowData\n childPersonalInfoPopulatedWfData: PopulatedWorkflowData\n otherPersonalInfoPopulatedWfData: PopulatedWorkflowData\n}> {\n return Promise.all([\n getWorkflowDataByCategory(workflow, MetadataCategory.Personal),\n getWorkflowDataByCategory(workflow, MetadataCategory.ChildPersonal),\n getWorkflowDataByCategory(workflow, MetadataCategory.OtherPersonal),\n ]).then(([personalInfoPopulatedWfData, childPersonalInfoPopulatedWfData, otherPersonalInfoPopulatedWfData]) => {\n return {\n personalInfoPopulatedWfData,\n childPersonalInfoPopulatedWfData,\n otherPersonalInfoPopulatedWfData,\n }\n })\n}\n\n/**\n * Creates the search index for the first name, last name, and the short id of the given consultation\n * @param consult the consultation to be search indexed\n * @param workflow the workflow data\n * @param oroClient\n */\nexport async function buildConsultSearchIndex(consult: Consult, workflow: WorkflowData, oroClient: OroClient) {\n let terms: Terms = [\n <Term>{\n kind: 'consult-shortid',\n value: consult.shortId,\n },\n ]\n\n const { personalInfoPopulatedWfData, childPersonalInfoPopulatedWfData, otherPersonalInfoPopulatedWfData } =\n await extractPersonalInfoFromWorkflowData(workflow)\n\n const personalInfo = identificationToPersonalInformations(\n toActualObject(personalInfoPopulatedWfData),\n MetadataCategory.Personal\n )\n const childPersonalInfo = identificationToPersonalInformations(\n toActualObject(childPersonalInfoPopulatedWfData),\n MetadataCategory.ChildPersonal\n )\n const otherPersonalInfo = identificationToPersonalInformations(\n toActualObject(otherPersonalInfoPopulatedWfData),\n MetadataCategory.OtherPersonal\n )\n\n terms.push(\n <Term>{\n kind: 'first-name',\n value: personalInfo.firstname,\n },\n <Term>{\n kind: 'last-name',\n value: personalInfo.name,\n }\n )\n\n if (childPersonalInfo.firstname && childPersonalInfo.name) {\n terms.push(\n <Term>{\n kind: 'first-name',\n value: childPersonalInfo.firstname,\n },\n <Term>{\n kind: 'last-name',\n value: childPersonalInfo.name,\n }\n )\n }\n\n if (otherPersonalInfo.firstname && otherPersonalInfo.name) {\n terms.push(\n <Term>{\n kind: 'first-name',\n value: otherPersonalInfo.firstname,\n },\n <Term>{\n kind: 'last-name',\n value: otherPersonalInfo.name,\n }\n )\n }\n\n await oroClient.searchClient.index(consult.uuid, terms)\n}\n","import { CryptoRSA, uuidParse} from \"oro-toolbox\"\nimport { EncryptedIndexEntry, Grant, IndexConsultLockbox } from \"oro-sdk-apis\"\n\n/**\n * Decrypts and returns the encrypted grants\n * If something went wrong during decryption, that grant will be removed from the list\n *\n * @param encryptedGrants: an array of encrypted grants\n * @param rsaKey: the rsa key used to decrypt the encrypted grants\n * @returns an array of grants\n */\nexport function decryptGrants(encryptedGrants: Grant[], rsaKey: CryptoRSA): Grant[] {\n return encryptedGrants\n .map(grant => {\n if (grant.encryptedLockbox && !grant.lockboxUuid) {\n try {\n grant.lockboxUuid = uuidParse(\n rsaKey.base64DecryptToBytes(grant.encryptedLockbox)\n )\n } catch (e) {\n console.error('[sdk:index] The grant could not be decrypted or was not a valid UUID: ', e)\n }\n }\n return grant\n })\n .filter(grant => grant.lockboxUuid)\n}\n\n/**\n * Decrypts the encrypted consult lockboxes and returns their grants\n * If something went wrong during decryption, that grant will be removed from the list\n *\n * @param encryptedConsultLockboxes: an array of encrypted entries\n * @param rsaKey: the rsa key used to decrypt the encrypted entries\n * @returns an array of grants\n */\nexport function decryptConsultLockboxGrants(encryptedConsultLockboxes: EncryptedIndexEntry[], rsaKey: CryptoRSA): Grant[] {\n return encryptedConsultLockboxes\n .map(encryptedConsultLockboxes => {\n try {\n return [true, (rsaKey.base64DecryptToJson(\n encryptedConsultLockboxes.encryptedIndexEntry\n ) as IndexConsultLockbox).grant]\n } catch(e) {\n console.error('[sdk:index] The consult lockbox grant could not be decrypted: ', e)\n return [false, undefined] // if decryption fails, we want to ignore the grant but not fail the call\n }\n })\n .filter(grantsTuple => grantsTuple[0])\n .map(grantTuples => grantTuples[1] as Grant)\n}","import {\n Consult,\n ConsultRequest,\n DocumentType,\n MedicalStatus,\n MetadataCategory,\n PlaceData,\n SelectedAnswersData,\n Uuid,\n WorkflowData,\n} from 'oro-sdk-apis'\nimport { buildConsultSearchIndex, OroClient } from '..'\nimport { getOrCreatePatientConsultationUuid } from './consult'\n\nconst MAX_RETRIES = 15\n/**\n * Placeholder while the workflow interpreter for the refill flows is complete\n *\n * Creates a fake workflow in which the workflow data will reside\n *\n * @todo deprecate this function when using workflows and populating them from the app\n *\n * @param isTreatmentWorking the value from the `is treatment working` question\n * @param hasSideEffects the value from the `does the treatment have side effects` question\n * @param deliveryAddress the provided delivery address\n * @param pharmacy\n * @returns a workflow\n */\nexport function getRefillAnswersAsWorkflow(\n isTreatmentWorking: string,\n hasSideEffects: string,\n deliveryAddress?: string,\n pharmacy?: PlaceData\n): WorkflowData {\n let selectedAnswers: SelectedAnswersData = [\n {\n ['isTreatmentWorking']: isTreatmentWorking,\n ['hasSideEffects']: hasSideEffects,\n },\n ]\n\n // appends the delivery address to the first page of the answers if provided\n if (deliveryAddress) selectedAnswers[0] = { ...selectedAnswers[0], ['deliveryAddress']: deliveryAddress }\n\n // appends the pharmacy to the first page of the answers if provided\n if (pharmacy) selectedAnswers[0] = { ...selectedAnswers[0], ['pharmacy']: JSON.stringify(pharmacy) }\n\n return {\n id: '32573a20-6f1d-49be-9ad3-b87c58074979',\n createdAt: '2022-10-03T00:00:00.000Z',\n culDeSacs: [],\n hidePlanRules: [],\n pages: [\n {\n title: 'Prescription Refill',\n groups: [\n {\n type: 'field-group',\n fieldsAndGroups: [\n {\n type: 'field',\n id: 'isTreatmentWorking',\n },\n {\n type: 'field',\n id: 'hasSideEffects',\n },\n {\n type: 'field',\n id: 'youPharmacy',\n },\n {\n type: 'field',\n id: 'youAddress',\n },\n ],\n },\n ],\n questions: {\n isTreatmentWorking: {\n label: 'Is the treatment working for you?',\n kind: 'radio',\n inline: true,\n inlineLabel: false,\n metaCategory: MetadataCategory.Refill,\n answers: {\n '73bec6eb-0310-4787-af3c-ac9c291737b2': {\n text: 'Yes',\n },\n 'e193951f-986f-4db3-bede-903045a1804a': {\n text: 'No',\n },\n },\n },\n hasSideEffects: {\n label: 'Are there any side effects',\n kind: 'radio',\n inline: true,\n inlineLabel: false,\n metaCategory: MetadataCategory.Refill,\n answers: {\n '1b87ad22-d316-4fac-9c7f-8f4ccb841aed': {\n text: 'Yes',\n },\n 'ab7f5a41-c351-4f5d-a568-e38f9f200e9a': {\n text: 'No',\n },\n },\n },\n youPharmacy: {\n kind: 'online-pharmacy-picker',\n label: 'Which pharmacy do you want the prescription sent to?',\n metaCategory: MetadataCategory.Refill,\n summaryLabel: 'Your pharmacy',\n },\n youAddress: {\n kind: 'place-address',\n label: 'Address',\n metaCategory: MetadataCategory.Refill,\n },\n },\n },\n ],\n locale: 'en',\n selectedAnswers,\n }\n}\n\n/**\n * Complete refill flow, creates a consult, stores refill data and updates consultation status\n * @param consultRequest\n * @param populatedRefillWorkflow the refill workflow data\n * @param oroClient\n */\nexport async function createRefill(\n consultRequest: ConsultRequest,\n populatedRefillWorkflow: WorkflowData,\n oroClient: OroClient,\n indexSearch: boolean = true,\n onProgress?: (\n progress: number,\n descriptionKey: string,\n extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }\n ) => void\n): Promise<Consult> {\n let retry = MAX_RETRIES\n let errorsThrown: Error[] = []\n let newConsult: Consult | undefined = undefined\n let lockboxUuid: Uuid | undefined\n const stepsTotalNum = 6\n let currentStep: number\n\n for (; retry > 0; retry--) {\n try {\n currentStep = 0\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_consult')\n // Creating refill consult\n newConsult = await getOrCreatePatientConsultationUuid(consultRequest, oroClient)\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'get_patient_grant')\n if (!lockboxUuid) lockboxUuid = (await oroClient.getGrants())[0].lockboxUuid\n\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'store_patient_data')\n await oroClient\n .getOrInsertJsonData(\n lockboxUuid!,\n populatedRefillWorkflow,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n consultationId: newConsult.uuid,\n },\n {},\n { withNotification: true, forceReplace: false, updateMedicalStatus: true }\n )\n .catch((err) => {\n console.error(\n '[SDK: prescription refill request] Some errors happened during refill data upload',\n err\n )\n errorsThrown.push(err)\n })\n\n if (indexSearch) {\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'fetching_parent_workflow_data')\n // raw workflow from parent consultation (contains first and last name of patient)\n let rawConsultationManifest = await oroClient.getLockboxManifest(\n lockboxUuid!,\n { category: MetadataCategory.Raw, consultationId: consultRequest.uuidParent },\n false\n )\n if (rawConsultationManifest && rawConsultationManifest.length > 0) {\n let rawConsultation = await oroClient.getJsonData<WorkflowData>(\n lockboxUuid!,\n rawConsultationManifest[0].dataUuid\n )\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'search_indexing')\n await buildConsultSearchIndex(newConsult, rawConsultation, oroClient).catch((err) => {\n console.error(\n '[SDK: prescription refill request] personal information not found or another error occured during search indexing',\n err\n )\n if (retry <= 1) return // this statement is to avoid failing the registration due to the failure in search indexing the consult, this practically implements a soft retry\n errorsThrown.push(err)\n })\n } else {\n console.error(\"[SDK: prescription refill request] parent consultation's raw data not found\")\n errorsThrown.push(Error('RawData Not Found'))\n }\n }\n\n if (errorsThrown.length > 0) throw errorsThrown\n\n // Deem the consultation as ready\n await oroClient.consultClient.updateConsultByUUID(newConsult.uuid, {\n statusMedical: MedicalStatus.New,\n })\n\n // if we got through the complete flow, the registration succeeded\n if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'success')\n\n await oroClient.cleanIndex()\n break\n } catch (err) {\n console.error(\n `[SDK] Error occured during prescription refill request: ${err}, retrying... Retries remaining: ${retry}`\n )\n errorsThrown = []\n continue\n }\n }\n if (retry <= 0) {\n console.error('[SDK] prescription refill request failed: MAX_RETRIES reached')\n throw 'RegistrationFailed'\n }\n\n if (!newConsult) {\n console.error('[SDK] prescription refill request failed: MAX_RETRIES reached')\n throw 'RegistrationFailed'\n }\n\n console.log('Successfully Created refill')\n return newConsult\n}\n","import { IndexKey, Grant, IndexConsultLockbox, MetadataCategory, VaultIndex } from 'oro-sdk-apis'\nimport { OroClient, Uuid } from '..'\n\n/**\n * @name filterGrantsWithLockboxMetadata\n * @description searches for the existance of a consult uuid in each granted lockbox\n * @param oroClient\n * @param filter: the consult uuid\n * @returns the grants containing the consult uuid\n */\nexport async function filterGrantsWithLockboxMetadata(\n oroClient: OroClient,\n filter: { consultationId: Uuid },\n): Promise<Grant[]> {\n let grants = await oroClient.getGrants()\n let filteredGrants = []\n for (let grant of grants) {\n // Fetches in each lockbox the existance of a given consult id\n let consultationIdExistsInMetadata = await oroClient.vaultClient.lockboxMetadataGet(grant.lockboxUuid!, ['consultationId'], [], {\n category: MetadataCategory.Consultation,\n consultationId: filter.consultationId\n })\n // If there are entries in the metadata, it means that the consult exists in the lockbox\n if (consultationIdExistsInMetadata[0].length >= 0)\n filteredGrants.push(grant)\n }\n\n return filteredGrants\n}\n","import {\n AllRoleType,\n AuthTokenRequest,\n Consult,\n ConsultRequest,\n ConsultService,\n DataCreateResponse,\n DiagnosisService,\n Document,\n DocumentType,\n EncryptedIndexEntry,\n EncryptedVaultIndex,\n Grant,\n GuardService,\n IdentityCreateRequest,\n IdentityResponse,\n IndexConsultLockbox,\n IndexKey,\n LocalizedData,\n LockboxDataRequest,\n LockboxGrantRequest,\n LockboxManifest,\n ManifestEntry,\n Meta,\n Metadata,\n MetadataCategory,\n OtherRoleType,\n PersonalMeta,\n PopulatedWorkflowData,\n Practice,\n PracticeService,\n PractitionnerRoleType,\n PreferenceMeta,\n RecoveryMeta,\n RoleBasedScopes,\n SearchService,\n SecretShard,\n 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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"}