oro-sdk 3.13.0 → 3.16.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/patient-registration.ts","../src/helpers/vault-grants.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 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 {\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 '..'\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 * @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): 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\n for (; retry > 0; retry--) {\n try {\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 (!consult) {\n consult = await getOrCreatePatientConsultationUuid(consultRequest, oroClient)\n }\n\n // Creating lockbox\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 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(consult.uuid, lockboxUuid, workflow, oroClient).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\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 (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 (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\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 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 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 */\nasync function getOrCreatePatientConsultationUuid(consult: ConsultRequest, oroClient: OroClient): 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\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(undefined, true)\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 return (\n await oroClient.vaultClient.lockboxCreate().catch((err) => {\n console.error('Error while creating lockbox', err)\n throw err\n })\n ).lockboxUuid\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 )\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): 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 promises = nonNullImages.map((image) => {\n return oroClient.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 })\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}","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 { IndexKey, Grant, IndexConsultLockbox, MetadataCategory, VaultIndex } from 'oro-sdk-apis'\nimport { OroClient, Uuid } from '..'\n\n/**\n * @name filterGrantsWithLockboxMetadata\n * @description searches for the applied filters in the vault index\n * @param oroClient\n * @param filter: the metadata filter applied to each the lockboxes\n * @param vaultIndex: the index to which the filter will be applied\n * @param forceRefresh\n * @returns the filtered grants\n */\nexport async function filterGrantsWithLockboxMetadata(\n oroClient: OroClient,\n filter?: { consultationId: Uuid },\n vaultIndex?: VaultIndex,\n forceRefresh = false\n): Promise<Grant[]> {\n if (!vaultIndex || forceRefresh) {\n vaultIndex = await buildLegacyVaultIndex(oroClient)\n }\n if (vaultIndex[IndexKey.Consultation] && filter) {\n let indexConsults = (vaultIndex[IndexKey.Consultation] ?? [])\n .filter((consultGrant: { consultationId: Uuid }) => consultGrant.consultationId === filter.consultationId)\n .map((consultGrant: { consultationId: Uuid; grant: Grant }) => consultGrant.grant as Grant)\n return indexConsults as Grant[]\n } else {\n // No grants exist and the index has already been built\n return []\n }\n}\n\n/** Finds all grants for the logged user\n * requests a list of unique consultation ids for each lockbox the user has access to\n * builds and sets the index of consultations\n * @param oroClient\n * @returns the constructed vaultIndex\n */\nexport async function buildLegacyVaultIndex(oroClient: OroClient): Promise<VaultIndex> {\n let grants = await oroClient.getGrants()\n let consultGrants: IndexConsultLockbox[] = []\n for (let grant of grants) {\n let consults = (\n await oroClient.vaultClient.lockboxMetadataGet(grant.lockboxUuid!, ['consultationId'], [], {\n category: MetadataCategory.Consultation,\n })\n )[0] as Uuid[]\n\n consultGrants = [\n ...consultGrants,\n ...consults.map((consult: any) => ({\n ...consult,\n grant: {\n lockboxOwnerUuid: grant.lockboxOwnerUuid,\n lockboxUuid: grant.lockboxUuid,\n },\n })),\n ]\n }\n\n let vaultIndex = {\n [IndexKey.Consultation]: consultGrants,\n }\n oroClient.setVaultIndex(vaultIndex)\n console.info('[sdk:index] Successfully Built Vault Index')\n return vaultIndex\n}\n","import {\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 PersonalMeta,\n PopulatedWorkflowData,\n Practice,\n PracticeService,\n PreferenceMeta,\n RecoveryMeta,\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 { decryptConsultLockboxGrants, decryptGrants, registerPatient, sessionStorePrivateKeyName } from './helpers'\nimport {\n AssociatedLockboxNotFound,\n IncompleteAuthentication,\n LocalEncryptedData,\n MissingGrant,\n MissingLockbox,\n MissingLockboxOwner,\n RecoveryData,\n RegisterPatientOutput,\n UserPreference,\n} from './models'\nimport { buildLegacyVaultIndex, 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.vaultIndex = undefined\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 * @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 ): Promise<RegisterPatientOutput> {\n if (!this.rsa) throw IncompleteAuthentication\n return registerPatient(patientUuid, consult, workflow, this, this.toolbox.uuid(), recoveryQA, indexSearch)\n }\n\n /**\n * Builds the vault index for the logged user\n *\n * Steps:\n * 1. Retrieves, decrypts and sets the lockbox IndexSnapshot\n * 2. Retrieves, decrypts and adds all other index entries starting at the snapshot timestamp\n * 3. Updates the IndexSnapshot if changed\n * @deprecated\n * @returns the latest vault index\n */\n public async buildVaultIndex(forceRefresh: boolean = false) {\n if (!this.vaultIndex || forceRefresh) await buildLegacyVaultIndex(this)\n }\n\n /**\n * Setter for the vault index\n * @param index\n */\n public setVaultIndex(index: VaultIndex) {\n this.vaultIndex = index\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 //// DEPRECATED : REMOVE ME : BEGIN ///////////////////////////////////////////\n case IndexKey.Consultation:\n encryptedIndex[key] = (entries[key] as IndexConsultLockbox[])\n .map((e) => ({\n ...e,\n uniqueHash: this.toolbox.hashStringToBase64(\n JSON.stringify({\n consultationId: e.consultationId,\n grant: e.grant,\n })\n ),\n }))\n .filter(\n (e) =>\n !this.vaultIndex ||\n !this.vaultIndex[IndexKey.Consultation]?.find((v) => v.uniqueHash === e.uniqueHash)\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 //// DEPRECATED : REMOVE ME : END ///////////////////////////////////////////\n }\n }\n await this.vaultClient.vaultIndexPut(encryptedIndex, indexOwnerUuid)\n }\n\n /**\n * adds or updates the index snapshot for the logged user\n * @param index\n */\n public async indexSnapshotAdd(index: VaultIndex) {\n if (!this.rsa) throw IncompleteAuthentication\n let rsaPub: Uint8Array = this.rsa.public()\n\n let cleanedIndex: VaultIndex = {\n [IndexKey.Consultation]: index[IndexKey.Consultation]\n ?.filter((c) => c)\n .map((c) => {\n return {\n grant: c.grant,\n consultationId: c.consultationId,\n }\n }),\n }\n\n // the data of the snapshot should not contain the `IndexEntry` data\n // (will create conflicts while updating)\n let encryptedIndexEntry = CryptoRSA.jsonWithPubEncryptToBase64(cleanedIndex, rsaPub)\n\n // The encryptedIndexEntry can have the uuid and timstamp (for updating)\n let encryptedIndex: EncryptedIndexEntry = {\n uuid: index.uuid,\n timestamp: index.timestamp,\n encryptedIndexEntry,\n }\n this.vaultClient.vaultIndexSnapshotPut(encryptedIndex)\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 * @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 ): 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 )\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 * @returns the data uuid\n */\n public async createJsonData<T = Meta>(\n lockboxUuid: Uuid,\n data: any,\n meta?: T,\n privateMeta?: { [val: string]: any },\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.jsonEncryptToBase64Payload(data)\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload(privateMeta)\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 * 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 * @returns the data uuid\n */\n public async getOrInsertJsonData<M = Metadata>(\n lockboxUuid: Uuid,\n data: any,\n publicMetadata: M,\n privateMetadata: Metadata,\n forceReplace: boolean = false\n ): Promise<Uuid> {\n let manifest = await this.vaultClient.lockboxManifestGet(lockboxUuid, publicMetadata)\n if (!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 forceReplace && manifest.length > 0 ? manifest[0].dataUuid : undefined // if forceReplace and data already exist, then replace data. Otherwise insert it\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 * @returns the data uuid\n */\n public async createBytesData<T = Meta>(\n lockboxUuid: Uuid,\n data: Uint8Array,\n meta: T,\n privateMeta: { [val: string]: any },\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid\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\n return this.tellerClient.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 }, forceRefresh: boolean = false): Promise<Grant[]> {\n if (!this.rsa) throw IncompleteAuthentication\n\n let filterString = JSON.stringify(filter)\n // retrieves cached grants\n // Note: if filters is set to empty, it will be stored in the `undefined` key\n if (!forceRefresh && this.cachedMetadataGrants[filterString]) return this.cachedMetadataGrants[filterString]\n\n // if there is a filter to apply, then the grant can be retrieved from the vault index, otherwise, all grants are fetched\n // Note: will work only if the filter being applied is exclusively a consult id\n const grantsByConsultLockbox = filter\n ? 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 : undefined\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[JSON.stringify(filter)] = decryptedConsults\n return this.cachedMetadataGrants[filterString]\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, this.vaultIndex, forceRefresh)\n } else {\n encryptedGrants = (await this.vaultClient.grantsGet()).grants\n }\n\n const decryptedGrants = await decryptGrants(encryptedGrants, this.rsa)\n // sets the cached grant\n this.cachedMetadataGrants[filterString] = decryptedGrants\n return decryptedGrants\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 forceRefresh = false\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n return this.getMetaCategoryFromConsultId(consultationId, category, forceRefresh)\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 forceRefresh = false\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n return this.getMetaCategoryFromConsultId(consultationId, MetadataCategory.Medical, forceRefresh)\n }\n\n private async getMetaCategoryFromConsultId(\n consultationId: Uuid,\n category: MetadataCategory,\n 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 forceRefresh\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 forceRefresh\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 forceRefresh: boolean = false\n ): Promise<LockboxManifest> {\n let manifestKey = JSON.stringify({\n lockboxUuid,\n filter,\n expandPrivateMetadata,\n lockboxOwnerUuid,\n })\n if (!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\n filter,\n false,\n grant.lockboxOwnerUuid,\n 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, forceRefresh: boolean = false): Promise<Consult[]> {\n return Promise.all(\n (await this.getGrants(undefined, forceRefresh)).map((grant) =>\n this.getLockboxManifest(\n grant.lockboxUuid!,\n {\n category: MetadataCategory.Consultation,\n documentType: DocumentType.PopulatedWorkflowData,\n },\n true,\n undefined,\n forceRefresh\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 forceRefresh: boolean = 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 }, forceRefresh))\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 forceRefresh\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 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 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","MissingLockbox","MissingLockboxOwner","AssociatedLockboxNotFound","WorkflowAnswersMissingError","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","_context2","triggeredQuestions","Promise","all","e","k","populateWorkflowField","then","populatedValue","workflowCreatedAt","createdAt","workflowId","locale","err","console","error","getImagesFromIndexDb","_context3","getMany","v","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","registerPatient","patientUuid","consultRequest","oroClient","masterKey","recoveryQA","indexSearch","consult","lockboxUuid","practitionerAdmin","retry","identity","errorsThrown","setTimeout","practiceClient","practiceGetFromUuid","uuidPractice","uuidAdmin","practiceGetPractitioners","log","practitioners","getOrCreatePatientConsultationUuid","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","consultClient","updateConsultByUUID","statusMedical","MedicalStatus","New","cleanIndex","_context5","practiceGetPayment","idStripeInvoiceOrPaymentIntent","payment","uuidConsult","getConsultByUUID","consultCreate","_context6","getGrants","grants","vaultClient","lockboxCreate","isoLanguage","getOrInsertJsonData","Raw","contentType","Consultation","documentType","DocumentType","PopulatedWorkflowData","Medical","consultationIds","extractAndStorePersonalWorkflowData","Preference","dataUuids","_context8","nonNullImages","img","promises","ImageAlias","idbId","extractPersonalInfoFromWorkflowData","personalInfoPopulatedWfData","childPersonalInfoPopulatedWfData","otherPersonalInfoPopulatedWfData","terms","shortId","_context11","_yield$extractPersona","personalInfo","childPersonalInfo","otherPersonalInfo","searchClient","index","decryptGrants","encryptedGrants","rsaKey","encryptedLockbox","uuidParse","base64DecryptToBytes","decryptConsultLockboxGrants","encryptedConsultLockboxes","base64DecryptToJson","encryptedIndexEntry","grantsTuple","grantTuples","filterGrantsWithLockboxMetadata","vaultIndex","forceRefresh","buildLegacyVaultIndex","indexConsults","consultGrant","consultGrants","_loop","lockboxMetadataGet","_iterator","setVaultIndex","info","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","accessToken","setTokens","whoAmI","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","refreshToken","authLogout","_context7","buildVaultIndex","forceUpdateIndexEntries","_context10","_context9","_this","consults","alert","indexOwnerUuid","rsaPub","decodeFromBase64","encryptedIndex","_i","uniqueHash","timestamp","jsonWithPubEncryptToBase64","_this2","JSON","stringify","_this2$vaultIndex$Ind","find","vaultIndexPut","indexSnapshotAdd","_context12","_index$IndexKey$Consu","c","vaultIndexSnapshotPut","granteeUuid","_context13","getCachedSecretCryptor","secret","granteePublicKey","granteeEncryptedSecret","bytesWithPubEncryptToBase64","request","encryptedSecret","lockboxGrant","createMessageData","message","previousDataUuid","_context14","author","encryptedPrivateMeta","lockboxDataStore","publicMetadata","Message","privateMetadata","createMessageAttachmentData","_context15","Uint8Array","arrayBuffer","lastModified","size","fileName","type","createConsultationAttachmentData","_context16","createBytesData","createJsonData","meta","privateMeta","_context17","forceReplace","_context18","lockboxManifestGet","manifest","dataUuid","_context19","getJsonData","_context20","lockboxDataGet","_yield$Promise$all","getBytesData","_context21","_yield$Promise$all2","_context22","filterString","vaultIndexGet","decryptedConsults","grantsByConsultLockbox","grantsGet","decryptedGrants","_context23","findIndex","lockboxSecretGet","sharedSecret","cryptor","getPersonalInformationsFromConsultId","getMetaCategoryFromConsultId","getMedicalDataFromConsultId","_context28","_context27","_this3","getLockboxManifest","entry","metadata","_context26","getPersonalInformations","userId","_context29","lockbox","identificationDataUuid","getGrantFromConsultId","_context30","getIdentityFromConsultId","_context31","expandPrivateMetadata","manifestKey","_context33","_context32","_this4","createPersonalInformations","_context34","_yield$this$getGrants","createUserPreference","preference","_context35","_yield$this$getGrants2","getDataFromGrant","_context36","getUserPreferenceFromConsultId","_context37","getUserPreference","_context38","getRecoveryDataFromConsultId","_context39","Recovery","getRecoveryData","_context40","getAssignedConsultations","_context42","_this5","_context41","promise","getPastConsultationsFromConsultId","_context44","consultationsInLockbox","consultId","_context43","_this6","getPatientConsultationData","_context45","_this7","getPatientPrescriptionsList","getPatientDocumentsList","Prescription","getPatientResultsList","Result","getPatientTreatmentPlans","TreatmentPlan","getPatientTreatmentPlanByUuid","treatmentPlanId","filters","_context51","_this8","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","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/patient-registration.ts","../src/helpers/vault-grants.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 {\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 '..'\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 * @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): 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\n for (; retry > 0; retry--) {\n try {\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 (!consult) {\n consult = await getOrCreatePatientConsultationUuid(consultRequest, oroClient)\n }\n\n // Creating lockbox\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 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(consult.uuid, lockboxUuid, workflow, oroClient).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\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 (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 (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\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 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 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 */\nasync function getOrCreatePatientConsultationUuid(consult: ConsultRequest, oroClient: OroClient): 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\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 return (\n await oroClient.vaultClient.lockboxCreate().catch((err) => {\n console.error('Error while creating lockbox', err)\n throw err\n })\n ).lockboxUuid\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 )\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): 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 promises = nonNullImages.map((image) => {\n return oroClient.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 })\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}","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 { 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 { decryptConsultLockboxGrants, decryptGrants, registerPatient, sessionStorePrivateKeyName } 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 * @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 ): Promise<RegisterPatientOutput> {\n if (!this.rsa) throw IncompleteAuthentication\n return registerPatient(patientUuid, consult, workflow, this, this.toolbox.uuid(), recoveryQA, indexSearch)\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 * @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 ): 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 )\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 * @returns the data uuid\n */\n public async createJsonData<T = Meta>(\n lockboxUuid: Uuid,\n data: any,\n meta?: T,\n privateMeta?: { [val: string]: any },\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.jsonEncryptToBase64Payload(data)\n let encryptedPrivateMeta = symmetricEncryptor.jsonEncryptToBase64Payload(privateMeta)\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 * 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 * @returns the data uuid\n */\n public async getOrInsertJsonData<M = Metadata>(\n lockboxUuid: Uuid,\n data: any,\n publicMetadata: M,\n privateMetadata: Metadata,\n forceReplace: boolean = false\n ): Promise<Uuid> {\n let manifest = await this.vaultClient.lockboxManifestGet(lockboxUuid, publicMetadata)\n if (!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 forceReplace && manifest.length > 0 ? manifest[0].dataUuid : undefined // if forceReplace and data already exist, then replace data. Otherwise insert it\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 * @returns the data uuid\n */\n public async createBytesData<T = Meta>(\n lockboxUuid: Uuid,\n data: Uint8Array,\n meta: T,\n privateMeta: { [val: string]: any },\n lockboxOwnerUuid?: Uuid,\n previousDataUuid?: Uuid\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\n return this.tellerClient.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\n if ([OtherRoleType.Patient, OtherRoleType.User].every(requiredRole => currentAccountRole.includes(requiredRole))) {\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)\n 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 forceRefresh = false\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n return this.getMetaCategoryFromConsultId(consultationId, category, forceRefresh)\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 forceRefresh = false\n ): Promise<LocalizedData<PopulatedWorkflowData>[]> {\n return this.getMetaCategoryFromConsultId(consultationId, MetadataCategory.Medical, forceRefresh)\n }\n\n private async getMetaCategoryFromConsultId(\n consultationId: Uuid,\n category: MetadataCategory,\n 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 forceRefresh\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 forceRefresh\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 forceRefresh: boolean = false\n ): Promise<LockboxManifest> {\n let manifestKey = JSON.stringify({\n lockboxUuid,\n filter,\n expandPrivateMetadata,\n lockboxOwnerUuid,\n })\n if (!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\n filter,\n false,\n grant.lockboxOwnerUuid,\n 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 forceRefresh: boolean = 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 forceRefresh\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 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 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","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","_context2","triggeredQuestions","Promise","all","e","k","populateWorkflowField","then","populatedValue","workflowCreatedAt","createdAt","workflowId","locale","err","console","error","getImagesFromIndexDb","_context3","getMany","v","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","registerPatient","patientUuid","consultRequest","oroClient","masterKey","recoveryQA","indexSearch","consult","lockboxUuid","practitionerAdmin","retry","identity","errorsThrown","setTimeout","practiceClient","practiceGetFromUuid","uuidPractice","uuidAdmin","practiceGetPractitioners","log","practitioners","getOrCreatePatientConsultationUuid","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","consultClient","updateConsultByUUID","statusMedical","MedicalStatus","New","cleanIndex","_context5","practiceGetPayment","idStripeInvoiceOrPaymentIntent","payment","uuidConsult","getConsultByUUID","consultCreate","_context6","getGrants","grants","vaultClient","lockboxCreate","isoLanguage","getOrInsertJsonData","Raw","contentType","Consultation","documentType","DocumentType","PopulatedWorkflowData","Medical","consultationIds","extractAndStorePersonalWorkflowData","Preference","dataUuids","_context8","nonNullImages","img","promises","ImageAlias","idbId","extractPersonalInfoFromWorkflowData","personalInfoPopulatedWfData","childPersonalInfoPopulatedWfData","otherPersonalInfoPopulatedWfData","terms","shortId","_context11","_yield$extractPersona","personalInfo","childPersonalInfo","otherPersonalInfo","searchClient","index","decryptGrants","encryptedGrants","rsaKey","encryptedLockbox","uuidParse","base64DecryptToBytes","decryptConsultLockboxGrants","encryptedConsultLockboxes","base64DecryptToJson","encryptedIndexEntry","grantsTuple","grantTuples","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","accessToken","setTokens","whoAmI","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","refreshToken","authLogout","_context7","forceUpdateIndexEntries","_context9","_this","consults","alert","indexOwnerUuid","_context10","rsaPub","decodeFromBase64","encryptedIndex","_i","uniqueHash","timestamp","jsonWithPubEncryptToBase64","vaultIndexPut","granteeUuid","getCachedSecretCryptor","secret","granteePublicKey","granteeEncryptedSecret","bytesWithPubEncryptToBase64","request","encryptedSecret","lockboxGrant","createMessageData","message","previousDataUuid","_context12","author","encryptedPrivateMeta","lockboxDataStore","publicMetadata","Message","privateMetadata","createMessageAttachmentData","_context13","Uint8Array","arrayBuffer","lastModified","size","fileName","type","createConsultationAttachmentData","_context14","createBytesData","createJsonData","meta","privateMeta","_context15","forceReplace","_context16","lockboxManifestGet","manifest","JSON","stringify","dataUuid","_context17","getJsonData","_context18","lockboxDataGet","_yield$Promise$all","getBytesData","_context19","_yield$Promise$all2","_context20","filterString","getAccountRole","currentAccountRole","OtherRoleType","Patient","User","requiredRole","grantsGet","decryptedGrants","info","vaultIndexGet","decryptedConsults","grantsByConsultLockbox","_context21","scope","split","_context22","findIndex","lockboxSecretGet","sharedSecret","cryptor","getPersonalInformationsFromConsultId","forceRefresh","getMetaCategoryFromConsultId","getMedicalDataFromConsultId","_context27","_loop","_context26","_this2","getLockboxManifest","entry","metadata","_context25","getPersonalInformations","userId","_context28","find","lockbox","identificationDataUuid","getGrantFromConsultId","_context29","getIdentityFromConsultId","_context30","expandPrivateMetadata","manifestKey","_context32","_context31","_this3","createPersonalInformations","_context33","_yield$this$getGrants","createUserPreference","preference","_context34","_yield$this$getGrants2","getDataFromGrant","_context35","getUserPreferenceFromConsultId","_context36","getUserPreference","_context37","getRecoveryDataFromConsultId","_context38","Recovery","getRecoveryData","_context39","getAssignedConsultations","_context41","_this4","_context40","promise","getPastConsultationsFromConsultId","_context43","consultationsInLockbox","consultId","_context42","_this5","getPatientConsultationData","_context44","_this6","getPatientPrescriptionsList","getPatientDocumentsList","Prescription","getPatientResultsList","Result","getPatientTreatmentPlans","TreatmentPlan","getPatientTreatmentPlanByUuid","treatmentPlanId","filters","_context50","_this7","recoverPrivateKeyFromSecurityQuestions","threshold","_context51","answeredShards","shard","indexOfQuestion","indexOf","securityQuestion","item","securityAnswer","reconstructSecret","_context52","recoverPrivateKeyFromMasterKey","_context53","_context54","securityQuestionPayload","breakSecretIntoShards","updateRequest","updatePassword","newPassword","oldPassword","_context55","passwordPayload","_context56","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","infos"],"mappings":"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"}