diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fa5451ce..4cb14e854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,27 @@ ## 1.7.0 Release candidate +### Migration notes +In order to make the upgrade easier, there are a couple of steps that need to be performed which will make the codebase ready for the upgrade: +- Run this command from the root of the countryconfig repository ```curl https://raw.githubusercontent.com/opencrvs/opencrvs-countryconfig/configurable-roles/src/upgrade-to-1_7.ts | npx ts-node -T --cwd ./src``` + + It will remove `roles.csv` and generate a `roles.ts` file. It will also update the corresponding role column in `default-employees.csv` & `prod-employees.csv` while adding the corresponding translations in `client.csv`. The employee files are only used when seeding new environments, if you already have a v1.6.x of OpenCRVS deployed, the data in the environment will automatically get migrated after deploying the upgrade. The changes in these two files are made to keep the roles in sync with your previously deployed environments, if any. +- After pulling in the v1.7.0 changes reject the changes incoming to `roles.ts`, `default-employees.csv` & `prod-employees.csv` files as we used the script above to auto-generate them. + + The `roles.ts` file now defines all the roles available in the system. New roles can be added & existing roles can be customized by giving them different scopes. + + *N.B. The default roles generated in the `roles.ts` file during migration should not be removed to maintain backwards compatibility* + ### Breaking changes - `INFORMANT_SIGNATURE` & `INFORMANT_SIGNATURE_REQUIRED` are now deprecated - Existing implementations relying on database-stored SVGs need to be updated to use the new configuration-based approach. A migration needs to be run (defined in [migration](https://github.com/opencrvs/opencrvs-core/pull/7813/files#diff-e5472dec87399bb9f73f75ec379ceb6a32ca135bc01dd8d0eb8f7d7aaa0bc0b1)), and default certificate templates must be created for each event type, following the convention `${event}-certificate` as the certificate template ID. +- **Roles** The previous `roles.csv` file has been deprecated. It will get removed once you run `yarn upgrade:code` command after pulling in the v1.7 changes. The command automatically generates a `roles.json` file which can be used as a baseline to configure the roles as per your requirements. ### New features - Update the translations for System user add/edit form, `Last name` to `User's surname` and `First name` to `User's first name` to make them less confusing for system users [#6830](https://github.com/opencrvs/opencrvs-core/issues/6830) +- **User scopes** Introduce granular scopes to grant specific permissions to a particular role. The specifics about the introduced scopes can be found here: *Link to scopes description file* - **Refactored certificate handling:** SVGs are no longer stored in the database; streamlined configurations now include certificate details, and clients request SVGs directly via URLs. - Add constant.humanName to allow countries to have custom ordering on their full name e.g. start with `lastName` or `firstName` [#6830](https://github.com/opencrvs/opencrvs-core/issues/6830) diff --git a/package.json b/package.json index 5a6e1c4ff..101fec91b 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,8 @@ "@typescript-eslint/parser": "^5.60.1", "cypress-xpath": "^2.0.1", "eslint": "^8.43.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^4.2.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", "husky": "1.0.0-rc.13", "inquirer": "^9.2.12", "js-yaml": "^4.1.0", @@ -55,7 +55,7 @@ "node-ssh": "^13.2.0", "nodemon": "^2.0.22", "pino-pretty": "^11.0.0", - "prettier": "^2.8.8", + "prettier": "^3.4.2", "react-intl": "^6.4.3", "vitest": "^2.1.2" }, @@ -64,7 +64,7 @@ "@hapi/boom": "^9.1.1", "@hapi/hapi": "^20.0.1", "@hapi/inert": "^6.0.3", - "@opencrvs/toolkit": "0.0.19-events-ml", + "@opencrvs/toolkit": "0.0.22-scopes", "@types/chalk": "^2.2.0", "@types/csv2json": "^1.4.0", "@types/fhir": "^0.0.30", @@ -73,7 +73,7 @@ "@types/hapi__hapi": "^20.0.0", "@types/jwt-decode": "^2.2.1", "@types/lodash": "^4.14.117", - "@types/node": "^10.12.5", + "@types/node": "^18.19.1", "@types/node-fetch": "^2.6.2", "@types/nodemailer": "^6.4.14", "app-module-path": "^2.2.0", diff --git a/src/api/certificates/handler.ts b/src/api/certificates/handler.ts index 8929c55c7..7f15b64f6 100644 --- a/src/api/certificates/handler.ts +++ b/src/api/certificates/handler.ts @@ -9,6 +9,7 @@ * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ +import { Event } from '@countryconfig/form/types/types' import { Request, ResponseToolkit } from '@hapi/hapi' type FontFamilyTypes = { @@ -43,7 +44,7 @@ export async function certificateHandler(request: Request, h: ResponseToolkit) { const certificateConfigs: ICertificateConfigData[] = [ { id: 'birth-certificate', - event: 'birth', + event: Event.Birth, label: { id: 'certificates.birth.certificate', defaultMessage: 'Birth Certificate', @@ -67,7 +68,7 @@ export async function certificateHandler(request: Request, h: ResponseToolkit) { }, { id: 'birth-certificate-certified-copy', - event: 'birth', + event: Event.Birth, label: { id: 'certificates.birth.certificate.copy', defaultMessage: 'Birth Certificate certified copy', @@ -92,7 +93,7 @@ export async function certificateHandler(request: Request, h: ResponseToolkit) { }, { id: 'death-certificate', - event: 'death', + event: Event.Death, label: { id: 'certificates.death.certificate', defaultMessage: 'Death Certificate', @@ -116,7 +117,7 @@ export async function certificateHandler(request: Request, h: ResponseToolkit) { }, { id: 'death-certificate-certified-copy', - event: 'death', + event: Event.Death, label: { id: 'certificates.death.certificate.copy', defaultMessage: 'Death Certificate certified copy', @@ -141,7 +142,7 @@ export async function certificateHandler(request: Request, h: ResponseToolkit) { }, { id: 'marriage-certificate', - event: 'marriage', + event: Event.Marriage, label: { id: 'certificates.marriage.certificate', defaultMessage: 'Marriage Certificate', @@ -165,7 +166,7 @@ export async function certificateHandler(request: Request, h: ResponseToolkit) { }, { id: 'marriage-certificate-certified-copy', - event: 'marriage', + event: Event.Marriage, label: { id: 'certificates.marriage.certificate.copy', defaultMessage: 'Marriage Certificate certified copy', diff --git a/src/data-seeding/employees/source/default-employees.csv b/src/data-seeding/employees/source/default-employees.csv index 1888c3a03..f3cc79280 100644 --- a/src/data-seeding/employees/source/default-employees.csv +++ b/src/data-seeding/employees/source/default-employees.csv @@ -1,12 +1,12 @@ -primaryOfficeId,givenNames,familyName,systemRole,role,mobile,username,email,password -CRVS_OFFICE_JWMRGwDBXK,Kalusha,Bwalya,FIELD_AGENT,Social Worker,+260911111111,k.bwalya,kalushabwalya17@gmail.com,test -CRVS_OFFICE_JWMRGwDBXK,Felix,Katongo,REGISTRATION_AGENT,Registration Agent,+260922222222,f.katongo,kalushabwalya17+@gmail.com,test -CRVS_OFFICE_JWMRGwDBXK,Kennedy,Mweene,LOCAL_REGISTRAR,Local Registrar,+260933333333,k.mweene,kalushabwalya1.7@gmail.com,test -CRVS_OFFICE_JWMRGwDBXK,Emmanuel,Mayuka,LOCAL_SYSTEM_ADMIN,Local System Admin,+260921681112,e.mayuka,kalushabwalya.17@gmail.com,test -CRVS_OFFICE_2OKicPQMNI,Jonathan,Campbell,NATIONAL_SYSTEM_ADMIN,National System Admin,+260921111111,j.campbell,kalushabwaly.a17@gmail.com,test -CRVS_OFFICE_okQp4uKCz0,Patrick,Gondwe,FIELD_AGENT,Local Leader,+260912121212,p.gondwe,kalushabwal.ya17@gmail.com,test -CRVS_OFFICE_okQp4uKCz0,Joshua,Mutale,REGISTRATION_AGENT,Registration Agent,+260923232323,j.mutale,kalushabwa.lya17@gmail.com,test -CRVS_OFFICE_okQp4uKCz0,Derrick,Bulaya,LOCAL_REGISTRAR,Local Registrar,+260934343434,d.bulaya,kalushabw.alya17@gmail.com,test -CRVS_OFFICE_okQp4uKCz0,Alex,Ngonga,LOCAL_SYSTEM_ADMIN,Local System Admin,+260978787878,a.ngonga,kalushab.walya17@gmail.com,test -CRVS_OFFICE_2OKicPQMNI,Edgar,Kazembe,PERFORMANCE_MANAGEMENT,Performance Manager,+260977777777,e.kazembe,kalusha.bwalya17@gmail.com,test -CRVS_OFFICE_2OKicPQMNI,Joseph,Musonda,NATIONAL_REGISTRAR,National Registrar,+260915151515,j.musonda,kalush.abwalya17@gmail.com,test +primaryOfficeId,givenNames,familyName,role,mobile,username,email,password +CRVS_OFFICE_JWMRGwDBXK,Kalusha,Bwalya,SOCIAL_WORKER,+260911111111,k.bwalya,kalushabwalya17@gmail.com,test +CRVS_OFFICE_JWMRGwDBXK,Felix,Katongo,REGISTRATION_AGENT,+260922222222,f.katongo,kalushabwalya17+@gmail.com,test +CRVS_OFFICE_JWMRGwDBXK,Kennedy,Mweene,LOCAL_REGISTRAR,+260933333333,k.mweene,kalushabwalya1.7@gmail.com,test +CRVS_OFFICE_JWMRGwDBXK,Emmanuel,Mayuka,LOCAL_SYSTEM_ADMIN,+260921681112,e.mayuka,kalushabwalya.17@gmail.com,test +CRVS_OFFICE_2OKicPQMNI,Jonathan,Campbell,NATIONAL_SYSTEM_ADMIN,+260921111111,j.campbell,kalushabwaly.a17@gmail.com,test +CRVS_OFFICE_okQp4uKCz0,Patrick,Gondwe,LOCAL_LEADER,+260912121212,p.gondwe,kalushabwal.ya17@gmail.com,test +CRVS_OFFICE_okQp4uKCz0,Joshua,Mutale,REGISTRATION_AGENT,+260923232323,j.mutale,kalushabwa.lya17@gmail.com,test +CRVS_OFFICE_okQp4uKCz0,Derrick,Bulaya,LOCAL_REGISTRAR,+260934343434,d.bulaya,kalushabw.alya17@gmail.com,test +CRVS_OFFICE_okQp4uKCz0,Alex,Ngonga,LOCAL_SYSTEM_ADMIN,+260978787878,a.ngonga,kalushab.walya17@gmail.com,test +CRVS_OFFICE_2OKicPQMNI,Edgar,Kazembe,PERFORMANCE_MANAGER,+260977777777,e.kazembe,kalusha.bwalya17@gmail.com,test +CRVS_OFFICE_2OKicPQMNI,Joseph,Musonda,NATIONAL_REGISTRAR,+260915151515,j.musonda,kalush.abwalya17@gmail.com,test diff --git a/src/data-seeding/roles/handler.ts b/src/data-seeding/roles/handler.ts index 4a611c563..b0de93462 100644 --- a/src/data-seeding/roles/handler.ts +++ b/src/data-seeding/roles/handler.ts @@ -8,34 +8,18 @@ * * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ -import { readCSVToJSON } from '@countryconfig/utils' +import { PRODUCTION, QA_ENV } from '@countryconfig/constants' +import { roles } from './roles' import { Request, ResponseToolkit } from '@hapi/hapi' -import { RoleSchema, Role } from './validator' export async function rolesHandler(_: Request, h: ResponseToolkit) { - const rawRoles: unknown[] = await readCSVToJSON( - './src/data-seeding/roles/source/roles.csv' - ) - const roles = RoleSchema.parse(rawRoles) - .map(({ systemRole, ...rest }) => { + if (!PRODUCTION || QA_ENV) { + return roles.map((role) => { return { - systemRole, - labels: Object.entries(rest).map( - ([key, value]: [Exclude, string]) => ({ - lang: key.split('_')[1], - label: value - }) - ) + ...role, + scopes: [...role.scopes, 'demo'] } }) - .reduce< - Record }>> - >((acc, role) => { - if (!acc[role.systemRole]) { - acc[role.systemRole] = [] - } - acc[role.systemRole].push({ labels: role.labels }) - return acc - }, {}) + } return h.response(roles) } diff --git a/src/data-seeding/roles/roles.ts b/src/data-seeding/roles/roles.ts new file mode 100644 index 000000000..ed7ee7f15 --- /dev/null +++ b/src/data-seeding/roles/roles.ts @@ -0,0 +1,244 @@ +import { SCOPES, Scope } from '@opencrvs/toolkit/scopes' +import { MessageDescriptor } from 'react-intl' + +type Role = { + id: string + label: MessageDescriptor + scopes: Scope[] +} + +export const roles: Role[] = [ + { + id: 'FIELD_AGENT', + label: { + defaultMessage: 'Field Agent', + description: 'Name for user role Field Agent', + id: 'userRole.fieldAgent' + }, + scopes: [ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_SUBMIT_INCOMPLETE, + SCOPES.RECORD_SUBMIT_FOR_REVIEW, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ] + }, + { + id: 'POLICE_OFFICER', + label: { + defaultMessage: 'Police Officer', + description: 'Name for user role Police Officer', + id: 'userRole.policeOfficer' + }, + scopes: [ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_SUBMIT_INCOMPLETE, + SCOPES.RECORD_SUBMIT_FOR_REVIEW, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ] + }, + { + id: 'SOCIAL_WORKER', + label: { + defaultMessage: 'Social Worker', + description: 'Name for user role Social Worker', + id: 'userRole.socialWorker' + }, + scopes: [ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_SUBMIT_INCOMPLETE, + SCOPES.RECORD_SUBMIT_FOR_REVIEW, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ] + }, + { + id: 'HEALTHCARE_WORKER', + label: { + defaultMessage: 'Healthcare Worker', + description: 'Name for user role Healthcare Worker', + id: 'userRole.healthcareWorker' + }, + scopes: [ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_SUBMIT_INCOMPLETE, + SCOPES.RECORD_SUBMIT_FOR_REVIEW, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ] + }, + { + id: 'LOCAL_LEADER', + label: { + defaultMessage: 'Local Leader', + description: 'Name for user role Local Leader', + id: 'userRole.localLeader' + }, + scopes: [ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_SUBMIT_INCOMPLETE, + SCOPES.RECORD_SUBMIT_FOR_REVIEW, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ] + }, + { + id: 'REGISTRATION_AGENT', + label: { + defaultMessage: 'Registration Agent', + description: 'Name for user role Registration Agent', + id: 'userRole.registrationAgent' + }, + scopes: [ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_DECLARATION_EDIT, + SCOPES.RECORD_SUBMIT_FOR_APPROVAL, + SCOPES.RECORD_SUBMIT_FOR_UPDATES, + SCOPES.RECORD_DECLARATION_ARCHIVE, + SCOPES.RECORD_DECLARATION_REINSTATE, + SCOPES.RECORD_REGISTRATION_REQUEST_CORRECTION, + SCOPES.RECORD_PRINT_RECORDS_SUPPORTING_DOCUMENTS, + SCOPES.RECORD_EXPORT_RECORDS, + SCOPES.RECORD_PRINT_ISSUE_CERTIFIED_COPIES, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.ORGANISATION_READ_LOCATIONS_MY_OFFICE, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ] + }, + { + id: 'LOCAL_REGISTRAR', + label: { + defaultMessage: 'Local Registrar', + description: 'Name for user role Local Registrar', + id: 'userRole.localRegistrar' + }, + scopes: [ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_DECLARATION_EDIT, + SCOPES.RECORD_SUBMIT_FOR_UPDATES, + SCOPES.RECORD_REVIEW_DUPLICATES, + SCOPES.RECORD_DECLARATION_ARCHIVE, + SCOPES.RECORD_DECLARATION_REINSTATE, + SCOPES.REGISTER, + SCOPES.RECORD_REGISTRATION_CORRECT, + SCOPES.RECORD_PRINT_RECORDS_SUPPORTING_DOCUMENTS, + SCOPES.RECORD_EXPORT_RECORDS, + SCOPES.RECORD_UNASSIGN_OTHERS, + SCOPES.RECORD_PRINT_ISSUE_CERTIFIED_COPIES, + SCOPES.RECORD_CONFIRM_REGISTRATION, + SCOPES.RECORD_REJECT_REGISTRATION, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PROFILE_ELECTRONIC_SIGNATURE, + SCOPES.ORGANISATION_READ_LOCATIONS_MY_OFFICE, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ] + }, + { + id: 'LOCAL_SYSTEM_ADMIN', + label: { + defaultMessage: 'Local System Admin', + description: 'Name for user role Local System Admin', + id: 'userRole.localSystemAdmin' + }, + scopes: [ + SCOPES.USER_READ_MY_OFFICE, + SCOPES.USER_CREATE_MY_JURISDICTION, + SCOPES.ORGANISATION_READ_LOCATIONS_MY_JURISDICTION, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PERFORMANCE_EXPORT_VITAL_STATISTICS + ] + }, + { + id: 'NATIONAL_SYSTEM_ADMIN', + label: { + defaultMessage: 'National System Admin', + description: 'Name for user role National System Admin', + id: 'userRole.nationalSystemAdmin' + }, + scopes: [ + SCOPES.USER_CREATE, + SCOPES.USER_READ, + SCOPES.USER_UPDATE, + SCOPES.ORGANISATION_READ_LOCATIONS, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PERFORMANCE_EXPORT_VITAL_STATISTICS, + SCOPES.CONFIG_UPDATE_ALL + ] + }, + { + id: 'PERFORMANCE_MANAGER', + label: { + defaultMessage: 'Performance Manager', + description: 'Name for user role Performance Manager', + id: 'userRole.performanceManager' + }, + scopes: [ + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PERFORMANCE_EXPORT_VITAL_STATISTICS + ] + }, + { + id: 'NATIONAL_REGISTRAR', + label: { + defaultMessage: 'National Registrar', + description: 'Name for user role National Registrar', + id: 'userRole.nationalRegistrar' + }, + scopes: [ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_DECLARATION_EDIT, + SCOPES.RECORD_SUBMIT_FOR_UPDATES, + SCOPES.RECORD_REVIEW_DUPLICATES, + SCOPES.RECORD_DECLARATION_ARCHIVE, + SCOPES.RECORD_DECLARATION_REINSTATE, + SCOPES.REGISTER, + SCOPES.RECORD_REGISTRATION_CORRECT, + SCOPES.RECORD_PRINT_RECORDS_SUPPORTING_DOCUMENTS, + SCOPES.RECORD_EXPORT_RECORDS, + SCOPES.RECORD_UNASSIGN_OTHERS, + SCOPES.RECORD_PRINT_ISSUE_CERTIFIED_COPIES, + SCOPES.RECORD_CONFIRM_REGISTRATION, + SCOPES.RECORD_REJECT_REGISTRATION, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PERFORMANCE_EXPORT_VITAL_STATISTICS, + SCOPES.PROFILE_ELECTRONIC_SIGNATURE, + SCOPES.ORGANISATION_READ_LOCATIONS_MY_OFFICE, + SCOPES.USER_READ_MY_OFFICE, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ] + } +] diff --git a/src/data-seeding/roles/source/roles.csv b/src/data-seeding/roles/source/roles.csv deleted file mode 100644 index 0606409b2..000000000 --- a/src/data-seeding/roles/source/roles.csv +++ /dev/null @@ -1,12 +0,0 @@ -systemRole,label_en,label_fr -FIELD_AGENT,Field Agent,Agent de terrain -FIELD_AGENT,Police Officer,Officier de police -FIELD_AGENT,Social Worker,Travailleur social -FIELD_AGENT,Healthcare Worker,Personnel de santé -FIELD_AGENT,Local Leader,Leader local -REGISTRATION_AGENT,Registration Agent,Agent d'enregistrement -LOCAL_REGISTRAR,Local Registrar,Registraire local -LOCAL_SYSTEM_ADMIN,Local System Admin,Administrateur système local -NATIONAL_SYSTEM_ADMIN,National System Admin,Administrateur système national -PERFORMANCE_MANAGEMENT,Performance Manager,Gestion des performances -NATIONAL_REGISTRAR,National Registrar,Registraire national diff --git a/src/data-seeding/roles/validator.ts b/src/data-seeding/roles/validator.ts deleted file mode 100644 index 02c2d9c01..000000000 --- a/src/data-seeding/roles/validator.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * OpenCRVS is also distributed under the terms of the Civil Registration - * & Healthcare Disclaimer located at http://opencrvs.org/license. - * - * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. - */ -import { TypeOf, z } from 'zod' - -export type Role = TypeOf[number] - -export const RoleSchema = z.array( - z.object({ - systemRole: z.enum([ - 'FIELD_AGENT', - 'REGISTRATION_AGENT', - 'LOCAL_REGISTRAR', - 'LOCAL_SYSTEM_ADMIN', - 'NATIONAL_SYSTEM_ADMIN', - 'PERFORMANCE_MANAGEMENT', - 'NATIONAL_REGISTRAR' - ]), - label_en: z.string(), - label_fr: z.string() - }) -) diff --git a/src/index.ts b/src/index.ts index de3527e12..5cdc0486e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -497,6 +497,7 @@ export async function createServer() { path: '/roles', handler: rolesHandler, options: { + auth: false, tags: ['api', 'user-roles'], description: 'Returns user roles metadata' } diff --git a/src/translations/client.csv b/src/translations/client.csv index 18e29f1f8..aaf5796ad 100644 --- a/src/translations/client.csv +++ b/src/translations/client.csv @@ -2272,6 +2272,17 @@ user.profile.roleType,Title for roleType field,Role,Rôle/Type user.profile.sectionTitle.audit,Title for audit section,History,Historique user.profile.startDate,Title for startDate field,Start date,Date de début user.profile.userName,Title for userName field,Username,Nom d'utilisateur +userRole.fieldAgent,Name for user role Field Agent,Field Agent,Agent de terrain +userRole.healthcareWorker,Name for user role Healthcare Worker,Healthcare Worker,Personnel de santé +userRole.localLeader,Name for user role Local Leader,Local Leader,Leader local +userRole.localRegistrar,Name for user role Local Registrar,Local Registrar,Registraire local +userRole.localSystemAdmin,Name for user role Local System Admin,Local System Admin,Administrateur système local +userRole.nationalRegistrar,Name for user role National Registrar,National Registrar,Registraire national +userRole.nationalSystemAdmin,Name for user role National System Admin,National System Admin,Administrateur système national +userRole.performanceManager,Name for user role Performance Manager,Performance Manager,Gestion des performances +userRole.policeOfficer,Name for user role Police Officer,Police Officer,Officier de police +userRole.registrationAgent,Name for user role Registration Agent,Registration Agent,Agent d'enregistrement +userRole.socialWorker,Name for user role Social Worker,Social Worker,Travailleur social userSetup.complete.instruction,Instruction for the setup complete,Login to your account with your username and newly created password,Connectez-vous maintenant à votre compte avec votre nom d'utilisateur et votre mot de passe nouvellement créé. userSetup.complete.title,Title for the setup complete page,Account setup complete,Configuration du compte terminée userSetup.instruction,User setup review page instruction,Check the details below to confirm your account details are correct,Vérifiez les détails ci-dessous pour confirmer que les détails de votre compte sont corrects. et faites les changements nécessaires pour confirmer que les détails de votre compte sont corrects. diff --git a/src/upgrade-to-1_7.ts b/src/upgrade-to-1_7.ts new file mode 100644 index 000000000..0e780488e --- /dev/null +++ b/src/upgrade-to-1_7.ts @@ -0,0 +1,367 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ +import { createReadStream, rmdirSync, writeFileSync } from 'fs' +import { camelCase, snakeCase } from 'lodash' +import { join } from 'path' +import { logger } from './logger' +import { stringify } from 'csv-stringify/sync' +import fs from 'fs' +import csv2json from 'csv2json' +import { inspect } from 'util' +import { format, resolveConfig } from 'prettier' + +/* + * inlining these two functions to not + * trigger envalid when running the script + */ +async function writeJSONToCSV( + filename: string, + data: Array> +) { + const csv = stringify(data, { + header: true + }) + return fs.promises.writeFile(filename, csv, 'utf8') +} + +async function readCSVToJSON(filename: string) { + return new Promise((resolve, reject) => { + const chunks: string[] = [] + createReadStream(filename) + .on('error', reject) + .pipe( + csv2json({ + separator: ',' + }) + ) + .on('data', (chunk) => chunks.push(chunk)) + .on('error', reject) + .on('end', () => { + resolve(JSON.parse(chunks.join(''))) + }) + }) +} + +const DEFAULT_ROLE_SCOPES_PRE_1_7 = { + FIELD_AGENT: `[ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_SUBMIT_INCOMPLETE, + SCOPES.RECORD_SUBMIT_FOR_REVIEW, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ]`, + REGISTRATION_AGENT: `[ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_DECLARATION_EDIT, + SCOPES.RECORD_SUBMIT_FOR_APPROVAL, + SCOPES.RECORD_SUBMIT_FOR_UPDATES, + SCOPES.RECORD_DECLARATION_ARCHIVE, + SCOPES.RECORD_DECLARATION_REINSTATE, + SCOPES.RECORD_REGISTRATION_REQUEST_CORRECTION, + SCOPES.RECORD_PRINT_RECORDS_SUPPORTING_DOCUMENTS, + SCOPES.RECORD_EXPORT_RECORDS, + SCOPES.RECORD_PRINT_ISSUE_CERTIFIED_COPIES, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.ORGANISATION_READ_LOCATIONS_MY_OFFICE, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ]`, + LOCAL_REGISTRAR: `[ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_DECLARATION_EDIT, + SCOPES.RECORD_SUBMIT_FOR_UPDATES, + SCOPES.RECORD_REVIEW_DUPLICATES, + SCOPES.RECORD_DECLARATION_ARCHIVE, + SCOPES.RECORD_DECLARATION_REINSTATE, + SCOPES.REGISTER, + SCOPES.RECORD_REGISTRATION_CORRECT, + SCOPES.RECORD_PRINT_RECORDS_SUPPORTING_DOCUMENTS, + SCOPES.RECORD_EXPORT_RECORDS, + SCOPES.RECORD_UNASSIGN_OTHERS, + SCOPES.RECORD_PRINT_ISSUE_CERTIFIED_COPIES, + SCOPES.RECORD_CONFIRM_REGISTRATION, + SCOPES.RECORD_REJECT_REGISTRATION, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PROFILE_ELECTRONIC_SIGNATURE, + SCOPES.ORGANISATION_READ_LOCATIONS_MY_OFFICE, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ]`, + LOCAL_SYSTEM_ADMIN: `[ + SCOPES.USER_READ_MY_OFFICE, + SCOPES.USER_CREATE_MY_JURISDICTION, + SCOPES.ORGANISATION_READ_LOCATIONS_MY_JURISDICTION, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PERFORMANCE_EXPORT_VITAL_STATISTICS + ]`, + NATIONAL_SYSTEM_ADMIN: `[ + SCOPES.USER_CREATE, + SCOPES.USER_READ, + SCOPES.USER_UPDATE, + SCOPES.ORGANISATION_READ_LOCATIONS, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PERFORMANCE_EXPORT_VITAL_STATISTICS, + SCOPES.CONFIG_UPDATE_ALL + ]`, + PERFORMANCE_MANAGEMENT: `[ + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PERFORMANCE_EXPORT_VITAL_STATISTICS + ]`, + NATIONAL_REGISTRAR: `[ + SCOPES.RECORD_DECLARE_BIRTH, + SCOPES.RECORD_DECLARE_DEATH, + SCOPES.RECORD_DECLARE_MARRIAGE, + SCOPES.RECORD_DECLARATION_EDIT, + SCOPES.RECORD_SUBMIT_FOR_UPDATES, + SCOPES.RECORD_REVIEW_DUPLICATES, + SCOPES.RECORD_DECLARATION_ARCHIVE, + SCOPES.RECORD_DECLARATION_REINSTATE, + SCOPES.REGISTER, + SCOPES.RECORD_REGISTRATION_CORRECT, + SCOPES.RECORD_PRINT_RECORDS_SUPPORTING_DOCUMENTS, + SCOPES.RECORD_EXPORT_RECORDS, + SCOPES.RECORD_UNASSIGN_OTHERS, + SCOPES.RECORD_PRINT_ISSUE_CERTIFIED_COPIES, + SCOPES.RECORD_CONFIRM_REGISTRATION, + SCOPES.RECORD_REJECT_REGISTRATION, + SCOPES.PERFORMANCE_READ, + SCOPES.PERFORMANCE_READ_DASHBOARDS, + SCOPES.PERFORMANCE_EXPORT_VITAL_STATISTICS, + SCOPES.PROFILE_ELECTRONIC_SIGNATURE, + SCOPES.ORGANISATION_READ_LOCATIONS_MY_OFFICE, + SCOPES.USER_READ_MY_OFFICE, + SCOPES.SEARCH_BIRTH, + SCOPES.SEARCH_DEATH, + SCOPES.SEARCH_MARRIAGE + ]` +} as const + +const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom') + +class FormattedScopes { + scopes: string + constructor(scopes: string) { + this.scopes = scopes + } + [customInspectSymbol]() { + return this.scopes + } +} + +async function main() { + await upgradeRolesDefinitions() +} + +async function upgradeRolesDefinitions() { + const roles = await readCSVToJSON( + join(__dirname, './src/data-seeding/roles/source/roles.csv') + ).catch((err) => { + if (err.code === 'ENOENT') { + logger.warn( + 'data-seeding/roles/source/roles.csv does not exist in the codebase. Looks like this codebase has been upgraded already.' + ) + } + + process.exit(1) + }) + + const rolesWithGeneratedIds = roles.map((role) => ({ + id: snakeCase(role.label_en).toUpperCase(), + label: { + defaultMessage: role.label_en, + description: `Name for user role ${role.label_en}`, + id: `userRole.${camelCase(role.label_en)}` + }, + oldLabels: Object.fromEntries( + Object.keys(role) + .filter((key) => key.startsWith('label_')) + .map((key) => [key.split('_')[1], role[key]]) + ), + systemRole: role.systemRole, + scopes: + DEFAULT_ROLE_SCOPES_PRE_1_7[ + role.systemRole as keyof typeof DEFAULT_ROLE_SCOPES_PRE_1_7 + ] + })) + + /* + * Add language items to src/translations/client.csv + */ + const copy = await readCSVToJSON( + join(__dirname, './src/translations/client.csv') + ) + + rolesWithGeneratedIds.forEach((role) => { + if (copy.find((item) => item.id === role.label.id)) { + logger.warn( + `Skipping role ${role.id} as it already exists in the client.csv` + ) + return + } + const copyItem = { + id: role.label.id, + description: role.label.description, + ...role.oldLabels + } + logger.info( + `Adding language items for role ${role.id}: ${JSON.stringify(copyItem)}` + ) + copy.push(copyItem) + }) + + /* + * Fix role references in default-employees.csv & prod-employees.csv from "National System Admin" to "NATIONAL_SYSTEM_ADMIN" + */ + + const defaultEmployees = await readCSVToJSON( + join(__dirname, './src/data-seeding/employees/source/default-employees.csv') + ) + + const defaultEmployeesWithRoles = defaultEmployees.map( + ({ systemRole, ...employee }) => { + if (!systemRole) { + logger.warn( + `Skipping employee "${employee.givenNames} ${employee.familyName}" as it already seems to have been migrated` + ) + return employee + } + const role = rolesWithGeneratedIds.find( + (role) => role.oldLabels.en === employee.role + ) + if (!role) { + logger.error(`Role with id ${employee.role} not found in roles.csv`) + process.exit(1) + } + return { + ...employee, + role: role.id + } + } + ) + + let prodEmployeesWithRoles = null + + try { + const prodEmployees = await readCSVToJSON( + join(__dirname, './src/data-seeding/employees/source/prod-employees.csv') + ) + + prodEmployeesWithRoles = prodEmployees.map( + ({ systemRole, ...employee }) => { + if (!systemRole) { + logger.warn( + `Skipping employee "${employee.givenNames} ${employee.familyName}" as it already seems to have been migrated` + ) + return employee + } + const role = rolesWithGeneratedIds.find( + (role) => role.oldLabels.en === employee.role + ) + if (!role) { + logger.error(`Role with id ${employee.role} not found in roles.csv`) + process.exit(1) + } + return { + ...employee, + role: role.id + } + } + ) + } catch (err) { + if (err.code === 'ENOENT') { + logger.warn( + './src/data-seeding/employees/source/prod-employees.csv does not exist in the codebase. Skipping' + ) + } + } + + /* + * Create the new "roles.ts" file with the updated roles and new format + */ + + const rolesWithoutDeprecatedFields = rolesWithGeneratedIds.map((role) => { + const { oldLabels, systemRole, ...rest } = role + return rest + }) + + const formattedRoles = rolesWithoutDeprecatedFields.map((role) => { + return { + ...role, + scopes: new FormattedScopes(role.scopes) + } + }) + + /* + * Persist changes + */ + logger.info('Creating roles file') + writeFileSync( + join(__dirname, './src/data-seeding/roles/roles.ts'), + await format( + ` + import { SCOPES, Scope } from '@opencrvs/toolkit/scopes' + import { MessageDescriptor } from 'react-intl' + + type Role = { + id: string + label: MessageDescriptor + scopes: Scope[] + } + + export const roles: Role[] = ${inspect(formattedRoles, { depth: null })} + `, + { + ...(await resolveConfig(__dirname)), + parser: 'babel-ts' + } + ) + ) + + logger.info('Updating copy file') + await writeJSONToCSV(join(__dirname, './src/translations/client.csv'), copy) + + logger.info('Updating default employees file') + await writeJSONToCSV( + join( + __dirname, + './src/data-seeding/employees/source/default-employees.csv' + ), + defaultEmployeesWithRoles + ) + if (prodEmployeesWithRoles) { + logger.info('Updating prod employees file') + await writeJSONToCSV( + join(__dirname, './src/data-seeding/employees/source/prod-employees.csv'), + prodEmployeesWithRoles + ) + } + + logger.info('Removing old roles file') + rmdirSync(join(__dirname, './src/data-seeding/roles/source'), { + recursive: true + }) +} + +main() diff --git a/src/utils/index.ts b/src/utils/index.ts index 941eeda1a..aedbb968a 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -22,8 +22,7 @@ export const CHILD_CODE = 'child-details' export const DECEASED_CODE = 'deceased-details' export const OPENCRVS_SPECIFICATION_URL = 'http://opencrvs.org/specs/' import { join } from 'path' -import { promisify } from 'util' -import { stringify, Options } from 'csv-stringify' +import { stringify } from 'csv-stringify/sync' export interface ILocation { id?: string @@ -164,12 +163,11 @@ export async function updateResourceInHearth(resource: fhir.ResourceBase) { return res.text() } -const csvStringify = promisify>, Options>(stringify) export async function writeJSONToCSV( filename: string, data: Array> ) { - const csv = await csvStringify(data, { + const csv = stringify(data, { header: true }) return fs.promises.writeFile(filename, csv, 'utf8') diff --git a/tsconfig.json b/tsconfig.json index 12cb72786..34a6186db 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ "module": "Node16", "outDir": "build/dist", "sourceMap": true, + "resolveJsonModule": true, "moduleResolution": "node16", "rootDir": ".", "lib": ["esnext.asynciterable", "es6", "es2017", "es2019", "es2022"], diff --git a/yarn.lock b/yarn.lock index feca1ff26..42a37ad16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -790,16 +790,21 @@ dependencies: "@octokit/openapi-types" "^18.0.0" -"@opencrvs/toolkit@0.0.19-events-ml": - version "0.0.19-events-ml" - resolved "https://registry.yarnpkg.com/@opencrvs/toolkit/-/toolkit-0.0.19-events-ml.tgz#d93a4ed889908be0f0fd8a88b60640c807d74554" - integrity sha512-16TISLgkYpyrUUVpHtDqLjPhyPT21zPenGrj4UKKKjXt6J55t/y7Te6XXKK5jqsT0+i+VKlx2vVg3/BnSapVZA== +"@opencrvs/toolkit@0.0.22-scopes": + version "0.0.22-scopes" + resolved "https://registry.yarnpkg.com/@opencrvs/toolkit/-/toolkit-0.0.22-scopes.tgz#282e577cb6c12226472f113d8753c7fbe1b150e7" + integrity sha512-VLJSgOuoR10SJPVY9EumbeMqQyuRJRNhMoUEA7O4CafGnj3PsYbawNF44qb5VLe3eJ4uEwAPnZXVBU7BGWRz9w== dependencies: "@trpc/client" "^11.0.0-rc.648" "@trpc/server" "^11.0.0-rc.532" ajv "^8.17.1" superjson "1.9.0-0" +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== + "@rollup/rollup-android-arm-eabi@4.24.0": version "4.24.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54" @@ -1153,10 +1158,12 @@ dependencies: undici-types "~5.25.1" -"@types/node@^10.12.5": - version "10.17.60" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" - integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== +"@types/node@^18.19.1": + version "18.19.68" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.68.tgz#f4f10d9927a7eaf3568c46a6d739cc0967ccb701" + integrity sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw== + dependencies: + undici-types "~5.26.4" "@types/node@^20.9.0": version "20.11.5" @@ -2299,17 +2306,18 @@ escape-string-regexp@^5.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== -eslint-config-prettier@^8.8.0: - version "8.8.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" - integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== -eslint-plugin-prettier@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" - integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== +eslint-plugin-prettier@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz#d1c8f972d8f60e414c25465c163d16f209411f95" + integrity sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw== dependencies: prettier-linter-helpers "^1.0.0" + synckit "^0.9.1" eslint-scope@^5.1.1: version "5.1.1" @@ -4240,10 +4248,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.8.8: - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +prettier@^3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f" + integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ== pretty-format@^23.6.0: version "23.6.0" @@ -4986,6 +4994,14 @@ symbol-observable@^1.1.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +synckit@^0.9.1: + version "0.9.2" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62" + integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -5111,7 +5127,7 @@ tsconfig-paths@^3.8.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@2: +tslib@2, tslib@^2.6.2: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==