From a305328d66d670126e33992b44c24df472cd8e56 Mon Sep 17 00:00:00 2001 From: Curtis Upshall Date: Tue, 16 Jan 2024 09:08:07 -0800 Subject: [PATCH 1/3] SIMSBIOHUB-428: Apply Security to Different Features (#227) * Updated endpoints and service and repo methods to support applying security to selected features. * Refactored the frontend to support selecting features, applying security rules, and to see already applied security rules. --- api/package-lock.json | 1562 ++++++++++------- .../paths/administrative/security/apply.ts | 131 -- .../{category/index.ts => categories.ts} | 35 +- .../administrative/security/category/fetch.ts | 120 -- .../paths/administrative/security/fetch.ts | 116 -- .../paths/administrative/security/remove.ts | 116 -- .../security/{index.ts => rules.ts} | 40 +- .../security/submission/{submissionId}.ts | 214 +++ .../repositories/security-repository.test.ts | 119 +- api/src/repositories/security-repository.ts | 134 +- api/src/services/security-service.test.ts | 121 +- api/src/services/security-service.ts | 95 +- .../components/security/ManageSecurity.tsx | 15 +- .../components/security/SecuritiesDialog.tsx | 53 +- .../security/SecurityRuleActionCard.tsx | 34 +- .../components/security/SecurityRuleCard.tsx | 19 +- .../components/security/SecurityRuleForm.tsx | 214 ++- .../components/security/UnsecureDialog.tsx | 65 - app/src/constants/i18n.ts | 16 +- app/src/contexts/submissionContext.tsx | 15 +- .../submissions/AdminSubmissionPage.tsx | 66 +- .../components/SubmissionDataGrid.tsx | 163 ++ .../SubmissionDataGrid/SubmissionDataGrid.tsx | 14 +- .../useSubmissionDataGridColumns.tsx | 11 +- ...Header.tsx => SubmissionHeaderToolbar.tsx} | 67 +- app/src/hooks/api/useSecurityApi.ts | 86 +- .../interfaces/useSecurityApi.interface.ts | 35 + 27 files changed, 2022 insertions(+), 1654 deletions(-) delete mode 100644 api/src/paths/administrative/security/apply.ts rename api/src/paths/administrative/security/{category/index.ts => categories.ts} (70%) delete mode 100644 api/src/paths/administrative/security/category/fetch.ts delete mode 100644 api/src/paths/administrative/security/fetch.ts delete mode 100644 api/src/paths/administrative/security/remove.ts rename api/src/paths/administrative/security/{index.ts => rules.ts} (71%) create mode 100644 api/src/paths/administrative/security/submission/{submissionId}.ts delete mode 100644 app/src/components/security/UnsecureDialog.tsx create mode 100644 app/src/features/submissions/components/SubmissionDataGrid.tsx rename app/src/features/submissions/components/{SubmissionHeader.tsx => SubmissionHeaderToolbar.tsx} (58%) diff --git a/api/package-lock.json b/api/package-lock.json index 06b241c08..e15f9c164 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -4,6 +4,12 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, "@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -24,74 +30,122 @@ } }, "@babel/compat-data": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", - "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "dev": true }, "@babel/core": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", - "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", "dev": true, "requires": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helpers": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "dependencies": { "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "requires": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" } }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, "@babel/generator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz", - "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "requires": { - "@babel/types": "^7.22.5", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" } }, "@babel/helper-compilation-targets": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", - "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", - "browserslist": "^4.21.3", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "dependencies": { "lru-cache": { @@ -104,9 +158,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true }, "yallist": { @@ -118,19 +172,19 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true }, "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { @@ -143,28 +197,25 @@ } }, "@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.15" } }, "@babel/helper-module-transforms": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", - "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" } }, "@babel/helper-simple-access": { @@ -177,51 +228,51 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", - "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "requires": { "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true }, "@babel/helpers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz", - "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", + "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", "dev": true, "requires": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" } }, "@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "dependencies": { @@ -269,60 +320,144 @@ } }, "@babel/parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", - "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "dev": true }, "@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "dependencies": { "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "@babel/highlight": "^7.22.5" + "color-convert": "^1.9.0" } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true } } }, "@babel/traverse": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz", - "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5", - "debug": "^4.1.0", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "dependencies": { "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "@babel/highlight": "^7.22.5" + "color-name": "1.1.3" } }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -332,13 +467,13 @@ } }, "@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -382,9 +517,9 @@ } }, "@elastic/transport": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@elastic/transport/-/transport-8.3.2.tgz", - "integrity": "sha512-ZiBYRVPj6pwYW99fueyNU4notDf7ZPs7Ix+4T1btIJsKJmeaORIItIfs+0O7KV4vV+DcvyMhkY1FXQx7kQOODw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@elastic/transport/-/transport-8.4.0.tgz", + "integrity": "sha512-Yb3fDa7yGD0ca3uMbL64M3vM1cE5h5uHmBcTjkdB4VpCasRNKSd09iDpwqX8zX1tbBtxcaKYLceKthWvPeIxTw==", "requires": { "debug": "^4.3.4", "hpagent": "^1.0.0", @@ -462,6 +597,11 @@ } } }, + "@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==" + }, "@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -598,9 +738,9 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true }, "@jridgewell/set-array": { @@ -616,21 +756,13 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - } + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@nodelib/fs.scandir": { @@ -813,9 +945,9 @@ "dev": true }, "@types/glob-stream": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@types/glob-stream/-/glob-stream-8.0.0.tgz", - "integrity": "sha512-fxTWwdQmX9LWSHD7ZLlv3BHR992mKcVcDnT/2v+l/QZZo7TfDdyasqlSYVzOnMGWhRbrWeWkbj/mgezFjKynhw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@types/glob-stream/-/glob-stream-8.0.2.tgz", + "integrity": "sha512-kyuRfGE+yiSJWzSO3t74rXxdZNdYfLcllO0IUha4eX1fl40pm9L02Q/TEc3mykTLjoWz4STBNwYnUWdFu3I0DA==", "dev": true, "requires": { "@types/node": "*", @@ -835,9 +967,9 @@ } }, "@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "@types/json5": { @@ -865,8 +997,7 @@ "@types/mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", - "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==", - "dev": true + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" }, "@types/mocha": { "version": "9.0.0", @@ -906,15 +1037,15 @@ } }, "@types/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-O397rnSS9iQI4OirieAtsDqvCj4+3eY1J+EPdNTKuHuRWIfUoGyzX294o8C4KJYaLqgSrd2o60c5EqCU8Zv02g==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-2.3.3.tgz", + "integrity": "sha512-Yll76ZHikRFCyz/pffKGjrCwe/le2CDwOP5F210KQo27kpRE46U2rDnzikNlVn6/ezH3Mhn46bJMTfeVTtcYMg==", "dev": true }, "@types/qs": { - "version": "6.9.10", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", - "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==" + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==" }, "@types/range-parser": { "version": "1.2.7", @@ -944,18 +1075,6 @@ "requires": { "@types/mime": "*", "@types/node": "*" - }, - "dependencies": { - "@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" - }, - "@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==" - } } }, "@types/sinon": { @@ -978,15 +1097,15 @@ } }, "@types/sinonjs__fake-timers": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", - "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", "dev": true }, "@types/streamx": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/streamx/-/streamx-2.9.1.tgz", - "integrity": "sha512-9bywzhouyedmci7WCIPFwJ8zASDnxt2gaVUy52X0p0Tt085IJSAEP0L6j4SSNeDMSLzpYu6cPz0GrJZ7kPJ6Bg==", + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/@types/streamx/-/streamx-2.9.5.tgz", + "integrity": "sha512-IHYsa6jYrck8VEdSwpY141FTTf6D7boPeMq9jy4qazNrFMA4VbRz/sw5LSsfR7jwdDcx0QKWkUexZvsWBC2eIQ==", "dev": true, "requires": { "@types/node": "*" @@ -1003,14 +1122,14 @@ } }, "@types/triple-beam": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz", - "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" }, "@types/undertaker": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@types/undertaker/-/undertaker-1.2.8.tgz", - "integrity": "sha512-gW3PRqCHYpo45XFQHJBhch7L6hytPsIe0QeLujlnFsjHPnXLhJcPdN6a9368d7aIQgH2I/dUTPFBlGeSNA3qOg==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@types/undertaker/-/undertaker-1.2.11.tgz", + "integrity": "sha512-j1Z0V2ByRHr8ZK7eOeGq0LGkkdthNFW0uAZGY22iRkNQNL9/vAV0yFPr1QN3FM/peY5bxs9P+1f0PYJTQVa5iA==", "dev": true, "requires": { "@types/node": "*", @@ -1019,9 +1138,9 @@ } }, "@types/undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha512-Z4TYuEKn9+RbNVk1Ll2SS4x1JeLHecolIbM/a8gveaHsW0Hr+RQMraZACwTO2VD7JvepgA6UO1A1VrbktQrIbQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/undertaker-registry/-/undertaker-registry-1.0.4.tgz", + "integrity": "sha512-tW77pHh2TU4uebWXWeEM5laiw8BuJ7pyJYDh6xenOs75nhny2kVgwYbegJ4BoLMYsIrXaBpKYaPdYO3/udG+hg==", "dev": true }, "@types/uuid": { @@ -1031,9 +1150,9 @@ "dev": true }, "@types/vinyl": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.7.tgz", - "integrity": "sha512-4UqPv+2567NhMQuMLdKAyK4yzrfCqwaTt6bLhHEs8PFcxbHILsrxaY63n4wgE/BRLDWDQeI+WcTmkXKExh9hQg==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.11.tgz", + "integrity": "sha512-vPXzCLmRp74e9LsP8oltnWKTH+jBwt86WgRUb4Pc9Lf3pkMVGyvIo2gm9bODeGfCay2DBB/hAWDuvf07JcK4rw==", "dev": true, "requires": { "@types/expect": "^1.20.4", @@ -1041,9 +1160,9 @@ } }, "@types/vinyl-fs": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/vinyl-fs/-/vinyl-fs-3.0.2.tgz", - "integrity": "sha512-ctNcmmzbMIKooXjRkyyUCOu2Z4AyqibL+RhXoF3pb7K7j+ezItnakmpm31LymkYHSIM5ey0tjIFzTvFOTSBCGw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/vinyl-fs/-/vinyl-fs-3.0.5.tgz", + "integrity": "sha512-ckYz9giHgV6U10RFuf9WsDQ3X86EFougapxHmmoxLK7e6ICQqO8CE+4V/3lBN148V5N1pb4nQMmMjyScleVsig==", "dev": true, "requires": { "@types/glob-stream": "*", @@ -1083,9 +1202,9 @@ } }, "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -1166,9 +1285,9 @@ } }, "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -1226,9 +1345,9 @@ "dev": true }, "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true }, "adler-32": { @@ -1490,6 +1609,21 @@ "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true }, + "arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -1648,33 +1782,14 @@ "is-descriptor": "^1.0.0" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } } } @@ -1698,16 +1813,6 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -1774,15 +1879,15 @@ "dev": true }, "browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" } }, "buffer": { @@ -1817,11 +1922,12 @@ "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" }, "busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", "requires": { - "streamsearch": "^1.1.0" + "dicer": "0.2.5", + "readable-stream": "1.1.x" } }, "bytes": { @@ -1879,9 +1985,9 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, "caniuse-lite": { - "version": "1.0.30001503", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz", - "integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==", + "version": "1.0.30001576", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", + "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", "dev": true }, "cfb": { @@ -1943,10 +2049,13 @@ } }, "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "requires": { + "get-func-name": "^2.0.2" + } }, "chokidar": { "version": "3.5.3", @@ -2184,9 +2293,9 @@ "dev": true }, "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", "dev": true }, "concat-map": { @@ -2475,12 +2584,24 @@ "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", "dev": true }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, "define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "requires": { + "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } @@ -2495,33 +2616,14 @@ "isobject": "^3.0.1" }, "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } } } @@ -2565,13 +2667,6 @@ "requires": { "readable-stream": "1.1.x", "streamsearch": "0.1.2" - }, - "dependencies": { - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==" - } } }, "diff": { @@ -2684,9 +2779,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.431", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.431.tgz", - "integrity": "sha512-m232JTVmCawA2vG+1azVxhKZ9Sv1Q//xxNv5PkP5rWxGgQE8c3CiZFrh8Xnp+d1NmNxlu3QQrGIfdeW5TtXX5w==", + "version": "1.4.628", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.628.tgz", + "integrity": "sha512-2k7t5PHvLsufpP6Zwk0nof62yLOsCf032wZx7/q0mv8gwlXjhcxI3lz6f0jBr0GrnWKcm3burXzI3t5IrcdUxw==", "dev": true }, "emoji-regex": { @@ -2714,12 +2809,13 @@ } }, "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, "requires": { - "ansi-colors": "^4.1.1" + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" } }, "error-ex": { @@ -2740,25 +2836,26 @@ } }, "es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dev": true, "requires": { "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", + "hasown": "^2.0.0", "internal-slot": "^1.0.5", "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", @@ -2766,30 +2863,113 @@ "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", + "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" + "which-typed-array": "^1.1.13" + }, + "dependencies": { + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true + }, + "which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + } } }, "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", "dev": true, "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + } } }, "es-to-primitive": { @@ -2987,9 +3167,9 @@ } }, "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -3361,33 +3541,14 @@ "is-extendable": "^0.1.0" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } } } @@ -3421,9 +3582,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -3480,13 +3641,6 @@ "flat-cache": "^3.0.4" } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3697,19 +3851,20 @@ "dev": true }, "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "requires": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" } }, "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "flush-write-stream": { @@ -3760,9 +3915,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==" }, "for-each": { "version": "0.3.3", @@ -3848,9 +4003,9 @@ "dev": true }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, @@ -3860,15 +4015,15 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" } }, "functional-red-black-tree": { @@ -3895,9 +4050,9 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true }, "get-intrinsic": { @@ -4187,7 +4342,6 @@ "dev": true, "optional": true, "requires": { - "bindings": "^1.5.0", "nan": "^2.12.1" } }, @@ -4351,9 +4505,9 @@ } }, "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -4671,12 +4825,32 @@ "dev": true }, "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dev": true, "requires": { - "get-intrinsic": "^1.1.1" + "get-intrinsic": "^1.2.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + } } }, "has-proto": { @@ -4767,6 +4941,21 @@ } } }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + } + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -4825,9 +5014,9 @@ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true }, "ignore-by-default": { @@ -4892,14 +5081,34 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", "dev": true, "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", "side-channel": "^1.0.4" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + } } }, "interpret": { @@ -4929,23 +5138,12 @@ } }, "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "hasown": "^2.0.0" } }, "is-arguments": { @@ -5013,31 +5211,20 @@ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" }, "is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "requires": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "hasown": "^2.0.0" } }, "is-date-object": { @@ -5050,22 +5237,13 @@ } }, "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } }, "is-dir": { @@ -5288,9 +5466,9 @@ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true }, "istanbul-lib-hook": { @@ -5315,9 +5493,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -5348,13 +5526,13 @@ } }, "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "requires": { "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", + "make-dir": "^4.0.0", "supports-color": "^7.1.0" }, "dependencies": { @@ -5364,6 +5542,33 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "requires": { + "semver": "^7.5.3" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5372,6 +5577,12 @@ "requires": { "has-flag": "^4.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, @@ -5395,9 +5606,9 @@ } }, "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -5447,6 +5658,12 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -5499,9 +5716,9 @@ "dev": true }, "just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", "dev": true }, "jwa": { @@ -5535,6 +5752,15 @@ "safe-buffer": "^5.0.1" } }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -5789,25 +6015,32 @@ } }, "logform": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", - "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", "requires": { - "@colors/colors": "1.5.0", + "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" + }, + "dependencies": { + "@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==" + } } }, "loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "requires": { - "get-func-name": "^2.0.0" + "get-func-name": "^2.0.1" } }, "lru-cache": { @@ -5845,9 +6078,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -6383,17 +6616,6 @@ "on-finished": "^2.3.0", "type-is": "^1.6.4", "xtend": "^4.0.0" - }, - "dependencies": { - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" - } - } } }, "mute-stdout": { @@ -6408,9 +6630,9 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", "optional": true }, "nanoid": { @@ -6462,61 +6684,41 @@ "dev": true }, "nise": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", - "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.7.tgz", + "integrity": "sha512-wWtNUhkT7k58uvWTB/Gy26eA/EJKtPZFVAhEilN5UYVmmGRYOURbejRUyKm0Uu9XVEW7K5nBOZfR8VMB4QR2RQ==", "dev": true, "requires": { - "@sinonjs/commons": "^2.0.0", - "@sinonjs/fake-timers": "^10.0.2", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/text-encoding": "^0.7.2", + "just-extend": "^6.2.0", + "path-to-regexp": "^6.2.1" }, "dependencies": { "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.1.0.tgz", - "integrity": "sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==", + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", "dev": true, "requires": { "@sinonjs/commons": "^3.0.0" - }, - "dependencies": { - "@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - } } }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "requires": { - "isarray": "0.0.1" - } + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true } } }, @@ -6535,9 +6737,9 @@ } }, "node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "nodemon": { @@ -6958,15 +7160,34 @@ } }, "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" + }, + "dependencies": { + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + } } }, "object.defaults": { @@ -7173,17 +7394,17 @@ "integrity": "sha512-/Yvsd2D7miYB4HLJ3hOOS0+vnowQpaT75FsHzr/y5M9P4q9bwa7RcbW2YdH6KZBn8ceLbKGnHxMZ1CHliGHUFw==" }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" } }, "ordered-read-streams": { @@ -7440,9 +7661,9 @@ } }, "pg-connection-string": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.0.tgz", - "integrity": "sha512-x14ibktcwlHKoHxx9X3uTVW9zIGR41ZB6QNhHb21OPNdCCO3NaRnpJuwKIQSR4u+Yqjx4HCvy7Hh7VSy1U4dGg==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" }, "pg-int8": { "version": "1.0.1", @@ -7450,9 +7671,9 @@ "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" }, "pg-pool": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.0.tgz", - "integrity": "sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==" + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==" }, "pg-protocol": { "version": "1.6.0", @@ -7716,9 +7937,9 @@ } }, "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" }, "qs": { "version": "6.10.4", @@ -7884,14 +8105,14 @@ } }, "regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "set-function-name": "^2.0.0" } }, "regexpp": { @@ -8089,6 +8310,26 @@ "queue-microtask": "^1.2.2" } }, + "safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -8104,14 +8345,45 @@ } }, "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", "is-regex": "^1.1.4" + }, + "dependencies": { + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + } } }, "safe-stable-stringify": { @@ -8215,6 +8487,29 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + } + }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -8427,33 +8722,14 @@ "is-descriptor": "^1.0.0" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } } } @@ -8586,9 +8862,9 @@ } }, "spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", "dev": true }, "split-string": { @@ -8672,15 +8948,15 @@ "dev": true }, "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.2.tgz", + "integrity": "sha512-rV4Bovi9xx0BFzOb/X0B2GqoIjvqPCttZdu0Wgtx2Dxkj7ETyWl9gmqJ4EutWRLvtZWm8dxE+InQZX1IryZn/w==", "dev": true }, "streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==" }, "string-width": { "version": "4.2.3", @@ -8703,47 +8979,47 @@ } }, "string.prototype.padend": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz", - "integrity": "sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.5.tgz", + "integrity": "sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" } }, "string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" } }, "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" } }, "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" } }, "string_decoder": { @@ -8811,9 +9087,9 @@ } }, "swagger-ui-dist": { - "version": "5.10.5", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.10.5.tgz", - "integrity": "sha512-Uv8E7hV/nXALQKgW86X1i58gl1O6DFg+Uq54sDwhYqucBBxj/47dLNw872TNILNlOTuPA6dRvUMGQdmlpaX8qQ==" + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.0.tgz", + "integrity": "sha512-j0PIATqQSEFGOLmiJOJZj1X1Jt6bFIur3JpY7+ghliUnfZs0fpWDdHEkn9q7QUlBtKbkn6TepvSxTqnE8l3s0A==" }, "swagger-ui-express": { "version": "4.3.0", @@ -9042,9 +9318,9 @@ } }, "triple-beam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==" }, "ts-log": { "version": "2.2.5", @@ -9106,9 +9382,9 @@ }, "dependencies": { "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true }, "diff": { @@ -9126,9 +9402,9 @@ } }, "tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "optional": true, "requires": { @@ -9158,9 +9434,9 @@ } }, "tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "tsutils": { "version": "3.21.0", @@ -9245,6 +9521,42 @@ "mime-types": "~2.1.24" } }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, "typed-array-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", @@ -9332,11 +9644,11 @@ "dev": true }, "undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "version": "5.28.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", + "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", "requires": { - "busboy": "^1.6.0" + "@fastify/busboy": "^2.0.0" } }, "union-value": { @@ -9413,9 +9725,9 @@ "dev": true }, "update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "requires": { "escalade": "^3.1.1", @@ -9486,9 +9798,9 @@ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", "dev": true }, "v8flags": { @@ -9743,9 +10055,9 @@ } }, "winston-transport": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", - "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", + "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", "requires": { "logform": "^2.3.2", "readable-stream": "^3.6.0", @@ -9782,12 +10094,6 @@ "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==" }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, "workerpool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", diff --git a/api/src/paths/administrative/security/apply.ts b/api/src/paths/administrative/security/apply.ts deleted file mode 100644 index bb4284d96..000000000 --- a/api/src/paths/administrative/security/apply.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { RequestHandler } from 'express'; -import { Operation } from 'express-openapi'; -import { SYSTEM_ROLE } from '../../../constants/roles'; -import { getDBConnection } from '../../../database/db'; -import { authorizeRequestHandler } from '../../../request-handlers/security/authorization'; -import { SecurityService } from '../../../services/security-service'; -import { getLogger } from '../../../utils/logger'; - -const defaultLog = getLogger('paths/administrative/security/apply'); - -export const POST: Operation = [ - authorizeRequestHandler(() => { - return { - and: [ - { - validSystemRoles: [SYSTEM_ROLE.SYSTEM_ADMIN], - discriminator: 'SystemRole' - } - ] - }; - }), - applySecurityRulesToSubmissionFeatures() -]; - -POST.apiDoc = { - description: - 'Applies security rules to a list of submission features. A flag can also be passed to make application of security rules override existing ones or add new ones to the existing list of security rules per submission feature.', - tags: ['security'], - security: [ - { - Bearer: [] - } - ], - requestBody: { - description: 'Payload of submission features and rules to apply.', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - override: { - type: 'boolean', - nullable: true - }, - features: { - type: 'array', - items: { - type: 'number' - }, - minItems: 1 - }, - rules: { - type: 'array', - items: { - type: 'number' - } - } - } - } - } - } - }, - responses: { - 200: { - description: 'Features.', - content: { - 'application/json': { - schema: { - type: 'array', - items: { - type: 'object', - properties: { - submission_feature_security_id: { - type: 'number' - }, - submission_feature_id: { - type: 'number' - }, - security_rule_id: { - type: 'number' - } - } - } - } - } - } - }, - 400: { - $ref: '#/components/responses/400' - }, - 401: { - $ref: '#/components/responses/401' - }, - 403: { - $ref: '#/components/responses/403' - }, - 500: { - $ref: '#/components/responses/500' - }, - default: { - $ref: '#/components/responses/default' - } - } -}; - -export function applySecurityRulesToSubmissionFeatures(): RequestHandler { - return async (req, res) => { - const connection = getDBConnection(req['keycloak_token']); - const service = new SecurityService(connection); - - try { - await connection.open(); - - const data = await service.applySecurityRulesToSubmissionFeatures( - req.body.features, - req.body.rules || [], - Boolean(req.body.override) - ); - - await connection.commit(); - - return res.status(200).json(data); - } catch (error) { - defaultLog.error({ label: 'applySecurityRulesToSubmissionFeatures', message: 'error', error }); - await connection.rollback(); - throw error; - } finally { - connection.release(); - } - }; -} diff --git a/api/src/paths/administrative/security/category/index.ts b/api/src/paths/administrative/security/categories.ts similarity index 70% rename from api/src/paths/administrative/security/category/index.ts rename to api/src/paths/administrative/security/categories.ts index 83dfe7083..9f05d19ba 100644 --- a/api/src/paths/administrative/security/category/index.ts +++ b/api/src/paths/administrative/security/categories.ts @@ -1,12 +1,12 @@ import { RequestHandler } from 'express'; import { Operation } from 'express-openapi'; -import { SYSTEM_ROLE } from '../../../../constants/roles'; -import { getDBConnection } from '../../../../database/db'; -import { authorizeRequestHandler } from '../../../../request-handlers/security/authorization'; -import { SecurityService } from '../../../../services/security-service'; -import { getLogger } from '../../../../utils/logger'; +import { SYSTEM_ROLE } from '../../../constants/roles'; +import { getDBConnection } from '../../../database/db'; +import { authorizeRequestHandler } from '../../../request-handlers/security/authorization'; +import { SecurityService } from '../../../services/security-service'; +import { getLogger } from '../../../utils/logger'; -const defaultLog = getLogger('paths/administrative/security/category'); +const defaultLog = getLogger('paths/administrative/security/categories'); export const GET: Operation = [ authorizeRequestHandler(() => { @@ -23,7 +23,8 @@ export const GET: Operation = [ ]; GET.apiDoc = { - description: 'Get all active security categories.', + description: + 'Get all active security rules with their associated categories. A security category is active if it has not been end-dated.', tags: ['security'], security: [ { @@ -39,9 +40,21 @@ GET.apiDoc = { type: 'array', items: { type: 'object', + required: [ + 'security_category_id', + 'name', + 'description', + 'record_effective_date', + 'record_end_date', + 'create_date', + 'create_user', + 'update_date', + 'update_user', + 'revision_count' + ], properties: { security_category_id: { - type: 'number' + type: 'integer' }, name: { type: 'string' @@ -60,7 +73,7 @@ GET.apiDoc = { type: 'string' }, create_user: { - type: 'string' + type: 'integer' }, update_date: { type: 'string', @@ -71,7 +84,7 @@ GET.apiDoc = { nullable: true }, revision_count: { - type: 'number' + type: 'integer' } } } @@ -111,7 +124,7 @@ export function getActiveSecurityCategories(): RequestHandler { return res.status(200).json(data); } catch (error) { - defaultLog.error({ label: 'getActiveSecurityRules', message: 'error', error }); + defaultLog.error({ label: 'getActiveSecurityCategories', message: 'error', error }); await connection.rollback(); throw error; } finally { diff --git a/api/src/paths/administrative/security/category/fetch.ts b/api/src/paths/administrative/security/category/fetch.ts deleted file mode 100644 index 14c4e58b0..000000000 --- a/api/src/paths/administrative/security/category/fetch.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { RequestHandler } from 'express'; -import { Operation } from 'express-openapi'; -import { SYSTEM_ROLE } from '../../../../constants/roles'; -import { getDBConnection } from '../../../../database/db'; -import { authorizeRequestHandler } from '../../../../request-handlers/security/authorization'; -import { SecurityService } from '../../../../services/security-service'; -import { getLogger } from '../../../../utils/logger'; - -const defaultLog = getLogger('paths/administrative/security/category'); - -export const GET: Operation = [ - authorizeRequestHandler(() => { - return { - and: [ - { - validSystemRoles: [SYSTEM_ROLE.SYSTEM_ADMIN], - discriminator: 'SystemRole' - } - ] - }; - }), - getActiveSecurityCategories() -]; - -GET.apiDoc = { - description: 'Get all active security categories.', - tags: ['security'], - security: [ - { - Bearer: [] - } - ], - responses: { - 200: { - description: 'Security Categories.', - content: { - 'application/json': { - schema: { - type: 'array', - items: { - type: 'object', - properties: { - security_rule_id: { - type: 'number' - }, - name: { - type: 'string' - }, - description: { - type: 'string' - }, - record_effective_date: { - type: 'string' - }, - record_end_date: { - type: 'string', - nullable: true - }, - security_category_id: { - type: 'number' - }, - category_name: { - type: 'string' - }, - category_description: { - type: 'string' - }, - category_record_effective_date: { - type: 'string' - }, - category_record_end_date: { - type: 'string', - nullable: true - } - } - } - } - } - } - }, - 400: { - $ref: '#/components/responses/400' - }, - 401: { - $ref: '#/components/responses/401' - }, - 403: { - $ref: '#/components/responses/403' - }, - 500: { - $ref: '#/components/responses/500' - }, - default: { - $ref: '#/components/responses/default' - } - } -}; - -export function getActiveSecurityCategories(): RequestHandler { - return async (req, res) => { - const connection = getDBConnection(req['keycloak_token']); - const service = new SecurityService(connection); - - try { - await connection.open(); - - const data = await service.getActiveRulesAndCategories(); - - await connection.commit(); - - return res.status(200).json(data); - } catch (error) { - defaultLog.error({ label: 'getActiveSecurityRules', message: 'error', error }); - await connection.rollback(); - throw error; - } finally { - connection.release(); - } - }; -} diff --git a/api/src/paths/administrative/security/fetch.ts b/api/src/paths/administrative/security/fetch.ts deleted file mode 100644 index c3a90831b..000000000 --- a/api/src/paths/administrative/security/fetch.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { RequestHandler } from 'express'; -import { Operation } from 'express-openapi'; -import { SYSTEM_ROLE } from '../../../constants/roles'; -import { getDBConnection } from '../../../database/db'; -import { authorizeRequestHandler } from '../../../request-handlers/security/authorization'; -import { SecurityService } from '../../../services/security-service'; -import { getLogger } from '../../../utils/logger'; - -const defaultLog = getLogger('paths/administrative/security/fetch'); - -export const POST: Operation = [ - authorizeRequestHandler(() => { - return { - and: [ - { - validSystemRoles: [SYSTEM_ROLE.SYSTEM_ADMIN], - discriminator: 'SystemRole' - } - ] - }; - }), - getSecurityRulesForSubmissionFeatures() -]; - -POST.apiDoc = { - description: '', - tags: ['security'], - security: [ - { - Bearer: [] - } - ], - requestBody: { - description: 'Payload of submission features ids.', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - features: { - type: 'array', - items: { - type: 'number' - }, - minItems: 1 - } - } - } - } - } - }, - responses: { - 200: { - description: 'Features.', - content: { - 'application/json': { - schema: { - type: 'array', - items: { - type: 'object', - properties: { - submission_feature_security_id: { - type: 'number' - }, - submission_feature_id: { - type: 'number' - }, - security_rule_id: { - type: 'number' - } - } - } - } - } - } - }, - 400: { - $ref: '#/components/responses/400' - }, - 401: { - $ref: '#/components/responses/401' - }, - 403: { - $ref: '#/components/responses/403' - }, - 500: { - $ref: '#/components/responses/500' - }, - default: { - $ref: '#/components/responses/default' - } - } -}; - -export function getSecurityRulesForSubmissionFeatures(): RequestHandler { - return async (req, res) => { - const connection = getDBConnection(req['keycloak_token']); - const service = new SecurityService(connection); - - try { - await connection.open(); - - const data = await service.getSecurityRulesForSubmissionFeatures(req.body.features); - - await connection.commit(); - - return res.status(200).json(data); - } catch (error) { - defaultLog.error({ label: 'getSecurityRulesForSubmissionFeatures', message: 'error', error }); - await connection.rollback(); - throw error; - } finally { - connection.release(); - } - }; -} diff --git a/api/src/paths/administrative/security/remove.ts b/api/src/paths/administrative/security/remove.ts deleted file mode 100644 index 680e758fb..000000000 --- a/api/src/paths/administrative/security/remove.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { RequestHandler } from 'express'; -import { Operation } from 'express-openapi'; -import { SYSTEM_ROLE } from '../../../constants/roles'; -import { getDBConnection } from '../../../database/db'; -import { authorizeRequestHandler } from '../../../request-handlers/security/authorization'; -import { SecurityService } from '../../../services/security-service'; -import { getLogger } from '../../../utils/logger'; - -const defaultLog = getLogger('paths/administrative/security/remove'); - -export const POST: Operation = [ - authorizeRequestHandler(() => { - return { - and: [ - { - validSystemRoles: [SYSTEM_ROLE.SYSTEM_ADMIN], - discriminator: 'SystemRole' - } - ] - }; - }), - removeSecurityRulesFromSubmissionFeatures() -]; - -POST.apiDoc = { - description: 'Remove Security for given submission features', - tags: ['security'], - security: [ - { - Bearer: [] - } - ], - requestBody: { - description: 'Unsecure object.', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - features: { - type: 'array', - items: { - type: 'number' - }, - minItems: 1 - } - } - } - } - } - }, - responses: { - 200: { - description: 'Features.', - content: { - 'application/json': { - schema: { - type: 'array', - items: { - type: 'object', - properties: { - submission_feature_security_id: { - type: 'number' - }, - submission_feature_id: { - type: 'number' - }, - security_rule_id: { - type: 'number' - } - } - } - } - } - } - }, - 400: { - $ref: '#/components/responses/400' - }, - 401: { - $ref: '#/components/responses/401' - }, - 403: { - $ref: '#/components/responses/403' - }, - 500: { - $ref: '#/components/responses/500' - }, - default: { - $ref: '#/components/responses/default' - } - } -}; - -export function removeSecurityRulesFromSubmissionFeatures(): RequestHandler { - return async (req, res) => { - const connection = getDBConnection(req['keycloak_token']); - const service = new SecurityService(connection); - - try { - await connection.open(); - - const data = await service.removeSecurityRulesFromSubmissionFeatures(req.body.features); - - await connection.commit(); - - return res.status(200).json(data); - } catch (error) { - defaultLog.error({ label: 'removeSecurityRulesFromSubmissionFeatures', message: 'error', error }); - await connection.rollback(); - throw error; - } finally { - connection.release(); - } - }; -} diff --git a/api/src/paths/administrative/security/index.ts b/api/src/paths/administrative/security/rules.ts similarity index 71% rename from api/src/paths/administrative/security/index.ts rename to api/src/paths/administrative/security/rules.ts index 7a90e61b4..1b99aab7e 100644 --- a/api/src/paths/administrative/security/index.ts +++ b/api/src/paths/administrative/security/rules.ts @@ -6,7 +6,7 @@ import { authorizeRequestHandler } from '../../../request-handlers/security/auth import { SecurityService } from '../../../services/security-service'; import { getLogger } from '../../../utils/logger'; -const defaultLog = getLogger('paths/administrative/security'); +const defaultLog = getLogger('paths/administrative/security/rules'); export const GET: Operation = [ authorizeRequestHandler(() => { @@ -23,7 +23,8 @@ export const GET: Operation = [ ]; GET.apiDoc = { - description: 'Get all active security rules.', + description: + 'Get all active security rules, with their respective categories. A security rule is active if it has not been end-dated.', tags: ['security'], security: [ { @@ -32,16 +33,27 @@ GET.apiDoc = { ], responses: { 200: { - description: 'Security Rules.', + description: 'Security rules with category.', content: { 'application/json': { schema: { type: 'array', items: { type: 'object', + required: [ + 'security_rule_id', + 'name', + 'description', + 'record_effective_date', + 'record_end_date', + 'category_name', + 'category_description', + 'category_record_effective_date', + 'category_record_end_date' + ], properties: { security_rule_id: { - type: 'number' + type: 'integer' }, name: { type: 'string' @@ -56,22 +68,18 @@ GET.apiDoc = { type: 'string', nullable: true }, - create_date: { + category_name: { type: 'string' }, - create_user: { - type: 'number' + category_description: { + type: 'string' }, - update_date: { - type: 'string', - nullable: true + category_record_effective_date: { + type: 'string' }, - update_user: { - type: 'number', + category_record_end_date: { + type: 'string', nullable: true - }, - revision_count: { - type: 'number' } } } @@ -105,7 +113,7 @@ export function getActiveSecurityRules(): RequestHandler { try { await connection.open(); - const data = await service.getActiveSecurityRules(); + const data = await service.getActiveRulesAndCategories(); await connection.commit(); diff --git a/api/src/paths/administrative/security/submission/{submissionId}.ts b/api/src/paths/administrative/security/submission/{submissionId}.ts new file mode 100644 index 000000000..d19a2a57e --- /dev/null +++ b/api/src/paths/administrative/security/submission/{submissionId}.ts @@ -0,0 +1,214 @@ +import { RequestHandler } from 'express'; +import { Operation } from 'express-openapi'; +import { SYSTEM_ROLE } from '../../../../constants/roles'; +import { getDBConnection } from '../../../../database/db'; +import { authorizeRequestHandler } from '../../../../request-handlers/security/authorization'; +import { SecurityService } from '../../../../services/security-service'; +import { getLogger } from '../../../../utils/logger'; + +const defaultLog = getLogger('paths/administrative/security/submission/{submissionId}'); + +export const GET: Operation = [ + authorizeRequestHandler(() => { + return { + and: [ + { + validSystemRoles: [SYSTEM_ROLE.SYSTEM_ADMIN], + discriminator: 'SystemRole' + } + ] + }; + }), + getAllSecurityRulesForSubmissionFeatures() +]; + +GET.apiDoc = { + description: '', + tags: ['security'], + security: [ + { + Bearer: [] + } + ], + parameters: [ + { + description: 'Submission ID', + in: 'path', + name: 'submissionId', + schema: { + type: 'integer', + minimum: 1 + }, + required: true + } + ], + responses: { + 200: { + description: 'Set of all security rules applied to all features belonging to the given submission.', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + required: ['submission_feature_security_id', 'submission_feature_id', 'security_rule_id'], + properties: { + submission_feature_security_id: { + type: 'integer' + }, + submission_feature_id: { + type: 'integer' + }, + security_rule_id: { + type: 'integer' + } + } + } + } + } + } + }, + 400: { + $ref: '#/components/responses/400' + }, + 401: { + $ref: '#/components/responses/401' + }, + 403: { + $ref: '#/components/responses/403' + }, + 500: { + $ref: '#/components/responses/500' + }, + default: { + $ref: '#/components/responses/default' + } + } +}; + +export function getAllSecurityRulesForSubmissionFeatures(): RequestHandler { + return async (req, res) => { + const connection = getDBConnection(req['keycloak_token']); + const securityService = new SecurityService(connection); + + try { + await connection.open(); + + const submissionId = Number(req.params.submissionId); + const data = await securityService.getAllSecurityRulesForSubmission(submissionId); + + await connection.commit(); + + return res.status(200).json(data); + } catch (error) { + defaultLog.error({ label: 'getAllSecurityRulesForSubmissionFeatures', message: 'error', error }); + await connection.rollback(); + throw error; + } finally { + connection.release(); + } + }; +} + +export const PATCH: Operation = [ + authorizeRequestHandler(() => { + return { + and: [ + { + validSystemRoles: [SYSTEM_ROLE.SYSTEM_ADMIN], + discriminator: 'SystemRole' + } + ] + }; + }), + patchSecurityRulesOnSubmissionFeatures() +]; + +PATCH.apiDoc = { + description: 'Applies security rules to a list of submission features.', + tags: ['security'], + security: [ + { + Bearer: [] + } + ], + requestBody: { + description: 'Payload of submission features and rules to apply.', + content: { + 'application/json': { + schema: { + type: 'object', + required: ['submissionFeatureIds', 'applyRuleIds', 'removeRuleIds'], + properties: { + submissionFeatureIds: { + type: 'array', + items: { + type: 'integer' + }, + minItems: 1 + }, + applyRuleIds: { + type: 'array', + items: { + type: 'integer' + } + }, + removeRuleIds: { + type: 'array', + items: { + type: 'integer' + } + } + } + } + } + } + }, + responses: { + 204: { + description: 'Successfully applied and/or removed security rules.' + }, + 400: { + $ref: '#/components/responses/400' + }, + 401: { + $ref: '#/components/responses/401' + }, + 403: { + $ref: '#/components/responses/403' + }, + 500: { + $ref: '#/components/responses/500' + }, + default: { + $ref: '#/components/responses/default' + } + } +}; + +export function patchSecurityRulesOnSubmissionFeatures(): RequestHandler { + return async (req, res) => { + const connection = getDBConnection(req['keycloak_token']); + const service = new SecurityService(connection); + + const submissionFeatureIds: number[] = req.body.submissionFeatureIds; + const applyRuleIds: number[] = req.body.applyRuleIds; + const removeRuleIds: number[] = req.body.removeRuleIds; + + try { + await connection.open(); + + await service.patchSecurityRulesOnSubmissionFeatures(submissionFeatureIds, applyRuleIds, removeRuleIds); + + await connection.commit(); + + return res.status(204).send(); + } catch (error) { + defaultLog.error({ label: 'patchSecurityRulesOnSubmissionFeatures', message: 'error', error }); + await connection.rollback(); + throw error; + } finally { + connection.release(); + } + }; +} diff --git a/api/src/repositories/security-repository.test.ts b/api/src/repositories/security-repository.test.ts index 2d1d151ca..bfd0bb35b 100644 --- a/api/src/repositories/security-repository.test.ts +++ b/api/src/repositories/security-repository.test.ts @@ -304,34 +304,6 @@ describe('SecurityRepository', () => { }); describe('applySecurityRulesToSubmissionFeatures', () => { - it('returns early with an empty dataset', async () => { - const mockQueryResponse = { - rowCount: 1, - rows: [ - { - submission_feature_security_id: 1, - submission_feature_id: 1, - security_rule_id: 1, - record_effective_date: '', - record_end_date: null, - create_date: 1, - create_user: 1, - update_date: 1, - update_user: 1, - revision_count: 1 - } - ] - } as any as Promise>; - - const mockDBConnection = getMockDBConnection({ - sql: () => mockQueryResponse - }); - - const repo = new SecurityRepository(mockDBConnection); - const response = await repo.applySecurityRulesToSubmissionFeatures([], []); - expect(response.length).to.equal(0); - }); - it('should succeed with valid data', async () => { const mockQueryResponse = { rowCount: 1, @@ -421,10 +393,10 @@ describe('SecurityRepository', () => { }); }); - describe('removeSecurityRulesFromSubmissionFeatures', () => { + describe('removeAllSecurityRulesFromSubmissionFeatures', () => { it('should succeed with valid data', async () => { const mockQueryResponse = { - rowCount: 1, + rowCount: 3, rows: [ { submission_feature_security_id: 1, @@ -466,41 +438,13 @@ describe('SecurityRepository', () => { } as any as Promise>; const mockDBConnection = getMockDBConnection({ - sql: () => mockQueryResponse + knex: () => mockQueryResponse }); const repo = new SecurityRepository(mockDBConnection); - const response = await repo.removeSecurityRulesFromSubmissionFeatures([1, 2]); + const response = await repo.removeAllSecurityRulesFromSubmissionFeatures([1, 2]); expect(response.length).to.equal(3); }); - - it('should return nothing with an empty ', async () => { - const mockQueryResponse = { - rowCount: 1, - rows: [ - { - submission_feature_security_id: 1, - submission_feature_id: 1, - security_rule_id: 1, - record_effective_date: '', - record_end_date: null, - create_date: 1, - create_user: 1, - update_date: 1, - update_user: 1, - revision_count: 1 - } - ] - } as any as Promise>; - - const mockDBConnection = getMockDBConnection({ - sql: () => mockQueryResponse - }); - - const repo = new SecurityRepository(mockDBConnection); - const response = await repo.removeSecurityRulesFromSubmissionFeatures([]); - expect(response.length).to.equal(0); - }); }); describe('getSecurityRulesForSubmissionFeatures', () => { @@ -548,63 +492,12 @@ describe('SecurityRepository', () => { } as any as Promise>; const mockDBConnection = getMockDBConnection({ - sql: () => mockQueryResponse + knex: () => mockQueryResponse }); const repo = new SecurityRepository(mockDBConnection); const response = await repo.getSecurityRulesForSubmissionFeatures([1, 2]); expect(response.length).to.equal(3); - }), - it('should leave early with no features', async () => { - const mockQueryResponse = { - rowCount: 1, - rows: [ - { - submission_feature_security_id: 1, - submission_feature_id: 1, - security_rule_id: 1, - record_effective_date: '', - record_end_date: null, - create_date: 1, - create_user: 1, - update_date: 1, - update_user: 1, - revision_count: 1 - }, - { - submission_feature_security_id: 2, - submission_feature_id: 1, - security_rule_id: 2, - record_effective_date: '', - record_end_date: null, - create_date: 1, - create_user: 1, - update_date: 1, - update_user: 1, - revision_count: 1 - }, - { - submission_feature_security_id: 3, - submission_feature_id: 2, - security_rule_id: 1, - record_effective_date: '', - record_end_date: null, - create_date: 1, - create_user: 1, - update_date: 1, - update_user: 1, - revision_count: 1 - } - ] - } as any as Promise>; - - const mockDBConnection = getMockDBConnection({ - sql: () => mockQueryResponse - }); - - const repo = new SecurityRepository(mockDBConnection); - const response = await repo.getSecurityRulesForSubmissionFeatures([]); - expect(response.length).to.equal(0); - }); + }); }); }); diff --git a/api/src/repositories/security-repository.ts b/api/src/repositories/security-repository.ts index a454c45a4..eb885e5c1 100644 --- a/api/src/repositories/security-repository.ts +++ b/api/src/repositories/security-repository.ts @@ -1,5 +1,6 @@ import SQL from 'sql-template-strings'; import { z } from 'zod'; +import { getKnex } from '../database/db'; import { ApiExecuteSQLError } from '../errors/api-error'; import { getLogger } from '../utils/logger'; import { BaseRepository } from './base-repository'; @@ -287,7 +288,8 @@ export class SecurityRepository extends BaseRepository { } /** - * Get all active security categories + * Get all active security categories. A security category is active if it has not been + * end-dated. * * @return {*} {Promise} * @memberof SecurityRepository @@ -302,7 +304,8 @@ export class SecurityRepository extends BaseRepository { } /** - * Get active security rules with associated categories + * Gets a list of all active security rules with associated categories. A security rule is + * active if it has not been end-dated. * * @return {*} {Promise} * @memberof SecurityRepository @@ -330,7 +333,8 @@ export class SecurityRepository extends BaseRepository { } /** - * Gets a list of all active security rules + * Gets a list of all active security rules. A security rule is active if it has not + * been end-dated. * * @return {*} {Promise} * @memberof SecurityRepository @@ -345,32 +349,33 @@ export class SecurityRepository extends BaseRepository { } /** - * Gets a list of all active security rules + * Attaches all of the given security rules to the given submission features. * - * @return {*} {Promise} + * @param {number[]} submissionFeatureIds + * @param {number[]} securityRuleIds + * @return {*} {Promise} * @memberof SecurityRepository */ async applySecurityRulesToSubmissionFeatures( - features: number[], - rules: number[] + submissionFeatureIds: number[], + securityRuleIds: number[] ): Promise { - if (!rules.length || !features.length) { - // no rules to apply, leave early - return []; - } + defaultLog.debug({ label: 'applySecurityRulesToSubmissionFeatures', submissionFeatureIds, securityRuleIds }); - const final = features.flatMap((item) => { - return rules.flatMap((rule) => `(${item}, ${rule}, 'NOW()')`); + const queryValues = submissionFeatureIds.flatMap((submissionFeatureId) => { + return securityRuleIds.flatMap((securityRuleId) => `(${submissionFeatureId}, ${securityRuleId}, 'NOW()')`); }); const insertSQL = SQL` - INSERT INTO submission_feature_security (submission_feature_id, security_rule_id, record_effective_date) - VALUES `; - insertSQL.append(final.join(', ')); + INSERT INTO + submission_feature_security (submission_feature_id, security_rule_id, record_effective_date) + VALUES `; + + insertSQL.append(queryValues.join(', ')); insertSQL.append(` - ON CONFLICT (submission_feature_id, security_rule_id) - DO NOTHING - RETURNING *;`); + ON CONFLICT (submission_feature_id, security_rule_id) + DO NOTHING + RETURNING *;`); const response = await this.connection.sql(insertSQL, SubmissionFeatureSecurityRecord); return response.rows; @@ -379,43 +384,90 @@ export class SecurityRepository extends BaseRepository { /** * Removes all security rules for a given set of submission features * - * @param {number[]} features + * @param {number[]} submissionFeatureIds * @return {*} {Promise} * @memberof SecurityRepository */ - async removeSecurityRulesFromSubmissionFeatures(features: number[]): Promise { - if (!features.length) { - // no features, return early - return []; - } - const deleteSQL = SQL` - DELETE FROM submission_feature_security WHERE submission_feature_id IN (`; + async removeAllSecurityRulesFromSubmissionFeatures( + submissionFeatureIds: number[] + ): Promise { + const queryBuilder = getKnex() + .queryBuilder() + .delete() + .from('submission_feature_security') + .whereIn('submission_feature_id', submissionFeatureIds) + .returning('*'); + + const response = await this.connection.knex(queryBuilder, SubmissionFeatureSecurityRecord); + + return response.rows; + } + + /** + * Removes the given security rules for a given set of given submission features. + * + * @param {number[]} submissionFeatureIds + * @param {number[]} removeRuleIds + * @return {*} {Promise} + * @memberof SecurityRepository + */ + async removeSecurityRulesFromSubmissionFeatures( + submissionFeatureIds: number[], + removeRuleIds: number[] + ): Promise { + defaultLog.debug({ label: 'removeSecurityRulesFromSubmissionFeatures', submissionFeatureIds, removeRuleIds }); + + const queryBuilder = getKnex() + .queryBuilder() + .delete() + .fromRaw('submission_feature_security sfs') + .whereIn('sfs.submission_feature_id', submissionFeatureIds) + .and.whereIn('sfs.security_rule_id', removeRuleIds) + .returning('*'); + + const response = await this.connection.knex(queryBuilder, SubmissionFeatureSecurityRecord); - deleteSQL.append(features.join(', ')); - deleteSQL.append(`) RETURNING *;`); - const response = await this.connection.sql(deleteSQL, SubmissionFeatureSecurityRecord); return response.rows; } /** * Gets Submission Feature Security Records for a given set of submission features * - * @param {number[]} features + * @param {number[]} submissionFeatureIds * @return {*} {Promise} * @memberof SecurityRepository */ - async getSecurityRulesForSubmissionFeatures(features: number[]): Promise { - if (!features.length) { - // no features, return early - return []; - } - const sql = SQL` - SELECT * FROM submission_feature_security WHERE submission_feature_id IN (`; + async getSecurityRulesForSubmissionFeatures( + submissionFeatureIds: number[] + ): Promise { + const queryBuilder = getKnex() + .queryBuilder() + .select('*') + .from('submission_feature_security') + .whereIn('submission_feature_id', submissionFeatureIds); + + const response = await this.connection.knex(queryBuilder, SubmissionFeatureSecurityRecord); + + return response.rows; + } + + /** + * Gets Submission Feature Security Records for a given set of submission features + * + * @param {number} submissionId + * @return {*} {Promise} + * @memberof SecurityRepository + */ + async getAllSecurityRulesForSubmission(submissionId: number): Promise { + const queryBuilder = getKnex() + .select('*') + .from('submission_feature_security') + .whereIn('submission_feature_id', (subQuery) => { + return subQuery.select('submission_feature_id').from('submission_feature').where('submission_id', submissionId); + }); - sql.append(features.join(', ')); - sql.append(`);`); + const response = await this.connection.knex(queryBuilder, SubmissionFeatureSecurityRecord); - const response = await this.connection.sql(sql, SubmissionFeatureSecurityRecord); return response.rows; } } diff --git a/api/src/services/security-service.test.ts b/api/src/services/security-service.test.ts index 667b48eb7..2859818a9 100644 --- a/api/src/services/security-service.test.ts +++ b/api/src/services/security-service.test.ts @@ -561,7 +561,7 @@ describe('SecurityService', () => { }); }); - describe('applySecurityRulesToSubmissionFeatures', () => { + describe('patchSecurityRulesOnSubmissionFeatures', () => { afterEach(() => { sinon.restore(); }); @@ -570,40 +570,78 @@ describe('SecurityService', () => { const mockDBConnection = getMockDBConnection(); const service = new SecurityService(mockDBConnection); - const removeFunction = sinon - .stub(SecurityService.prototype, 'removeSecurityRulesFromSubmissionFeatures') + const removeStub = sinon + .stub(SecurityRepository.prototype, 'removeSecurityRulesFromSubmissionFeatures') .resolves([]); - const applySecurity = sinon.stub(SecurityService.prototype, 'applySecurityRulesToSubmissionFeatures').resolves([ - { - submission_feature_security_id: 1, - submission_feature_id: 1, - security_rule_id: 1, - record_effective_date: '', - record_end_date: null, - create_date: '', - create_user: 1, - update_date: '', - update_user: 1, - revision_count: 1 - } - ]); - const response = await service.applySecurityRulesToSubmissionFeatures([1], [1]); + const applyStub = sinon.stub(SecurityRepository.prototype, 'applySecurityRulesToSubmissionFeatures').resolves([]); - expect(removeFunction).to.not.be.called; - expect(applySecurity).to.be.calledOnce; - expect(response.length).to.be.greaterThan(0); + await service.patchSecurityRulesOnSubmissionFeatures([1, 2, 3], [4, 5], [6, 7]); + + expect(removeStub).to.be.calledWith([1, 2, 3], [6, 7]); + expect(applyStub).to.be.calledWith([1, 2, 3], [4, 5]); + }); + + it('should succeed when no submissionFeatureIds are called', async () => { + const mockDBConnection = getMockDBConnection(); + const service = new SecurityService(mockDBConnection); + + const removeStub = sinon + .stub(SecurityRepository.prototype, 'removeSecurityRulesFromSubmissionFeatures') + .resolves([]); + + const applyStub = sinon.stub(SecurityRepository.prototype, 'applySecurityRulesToSubmissionFeatures').resolves([]); + + await service.patchSecurityRulesOnSubmissionFeatures([], [4, 5], [6, 7]); + + expect(removeStub).to.not.be.called; + expect(applyStub).to.not.be.called; + }); + + it('should succeed when no remove rule IDs are called', async () => { + const mockDBConnection = getMockDBConnection(); + const service = new SecurityService(mockDBConnection); + + const removeStub = sinon + .stub(SecurityRepository.prototype, 'removeSecurityRulesFromSubmissionFeatures') + .resolves([]); + + const applyStub = sinon.stub(SecurityRepository.prototype, 'applySecurityRulesToSubmissionFeatures').resolves([]); + + await service.patchSecurityRulesOnSubmissionFeatures([1, 2, 3], [4, 5], []); + + expect(removeStub).to.not.be.called; + expect(applyStub).to.be.calledWith([1, 2, 3], [4, 5]); }); - it('should succeed with override called', async () => { + it('should succeed when no apply rule IDs are called', async () => { const mockDBConnection = getMockDBConnection(); const service = new SecurityService(mockDBConnection); - const removeFunction = sinon + const removeStub = sinon .stub(SecurityRepository.prototype, 'removeSecurityRulesFromSubmissionFeatures') .resolves([]); - const applySecurity = sinon - .stub(SecurityRepository.prototype, 'applySecurityRulesToSubmissionFeatures') + + const applyStub = sinon.stub(SecurityRepository.prototype, 'applySecurityRulesToSubmissionFeatures').resolves([]); + + await service.patchSecurityRulesOnSubmissionFeatures([1, 2, 3], [], [6, 7]); + + expect(applyStub).to.not.be.called; + expect(removeStub).to.be.calledWith([1, 2, 3], [6, 7]); + }); + }); + + describe('removeSecurityRulesFromSubmissionFeatures', () => { + afterEach(() => { + sinon.restore(); + }); + + it('should succeed at removing a list of security rules', async () => { + const mockDBConnection = getMockDBConnection(); + const service = new SecurityService(mockDBConnection); + + const removeSecurityStub = sinon + .stub(SecurityRepository.prototype, 'removeSecurityRulesFromSubmissionFeatures') .resolves([ { submission_feature_security_id: 1, @@ -618,25 +656,19 @@ describe('SecurityService', () => { revision_count: 1 } ]); - const response = await service.applySecurityRulesToSubmissionFeatures([1], [1], true); - expect(removeFunction).to.be.calledOnce; - expect(applySecurity).to.be.calledOnce; - expect(response.length).to.be.greaterThan(0); - }); - }); + const response = await service.removeSecurityRulesFromSubmissionFeatures([1, 2, 3], [4, 5]); - describe('removeSecurityRulesFromSubmissionFeatures', () => { - afterEach(() => { - sinon.restore(); + expect(removeSecurityStub).to.be.calledOnce; + expect(response.length).to.be.greaterThan(0); }); - it('removeSecurityRulesFromSubmissionFeatures', async () => { + it('should succeed at removing all rules when no array is given', async () => { const mockDBConnection = getMockDBConnection(); const service = new SecurityService(mockDBConnection); - const applySecurity = sinon - .stub(SecurityRepository.prototype, 'removeSecurityRulesFromSubmissionFeatures') + const removeSecurityStub = sinon + .stub(SecurityRepository.prototype, 'removeAllSecurityRulesFromSubmissionFeatures') .resolves([ { submission_feature_security_id: 1, @@ -651,12 +683,23 @@ describe('SecurityService', () => { revision_count: 1 } ]); - const response = await service.removeSecurityRulesFromSubmissionFeatures([1]); - expect(applySecurity).to.be.calledOnce; + const response = await service.removeSecurityRulesFromSubmissionFeatures([1, 2, 3]); + + expect(removeSecurityStub).to.be.calledOnce; expect(response.length).to.be.greaterThan(0); }); + + it('should return an empty array if no submission feature IDs have been given', async () => { + const mockDBConnection = getMockDBConnection(); + const service = new SecurityService(mockDBConnection); + + const response = await service.removeSecurityRulesFromSubmissionFeatures([]); + + expect(response).to.eql([]); + }); }); + describe('getSecurityRulesForSubmissionFeatures', () => { afterEach(() => { sinon.restore(); diff --git a/api/src/services/security-service.ts b/api/src/services/security-service.ts index 82f0cdb57..58543af34 100644 --- a/api/src/services/security-service.ts +++ b/api/src/services/security-service.ts @@ -330,53 +330,94 @@ export class SecurityService extends DBService { } /** - * Applies all given security rules to the given set of submission feature ids. - * This process is additive unless the override flag is set to `true`. - * If the override is set to `true` all security rules for the given set of features will be removed. - * Then the new security rules will be applied as normal. + * Patches security rules that are applied or removed to the given set of submission features. If a + * particular rule happens to belong to both `applyRuleIds` and `removeRuleIds`, it will always be + * added. * - * @param {number[]} features - * @param {number[]} rules - * @param {boolean} - * @return {*} {Promise} + * @param {number[]} submissionFeatureIds IDs of the submission features whose security will be updated. + * @param {number[]} applyRuleIds IDs of the rules which will be applied after the patch operation + * @param {number[]} removeRuleIds IDs of the rules which will be removed after the patch operation + * @return {*} {Promise} * @memberof SecurityService */ - async applySecurityRulesToSubmissionFeatures( - features: number[], - rules: number[], - override = false - ): Promise { - if (override) { - // we want to override any security rules present and can achieve this by remove everything first - await this.securityRepository.removeSecurityRulesFromSubmissionFeatures(features); + async patchSecurityRulesOnSubmissionFeatures( + submissionFeatureIds: number[], + applyRuleIds: number[], + removeRuleIds: number[] + ): Promise { + defaultLog.debug({ label: 'patchSecurityRulesOnSubmissionFeatures', applyRuleIds, removeRuleIds }); + + if (!submissionFeatureIds.length) { + return; } - return this.securityRepository.applySecurityRulesToSubmissionFeatures(features, rules); + if (removeRuleIds.length > 0) { + await this.securityRepository.removeSecurityRulesFromSubmissionFeatures(submissionFeatureIds, removeRuleIds); + } + + if (applyRuleIds.length > 0) { + await this.securityRepository.applySecurityRulesToSubmissionFeatures(submissionFeatureIds, applyRuleIds); + } } /** - * Removes all security rules for the given set of submission feature ids + * Removes the given security rules from the given set of submission feature ids. If + * no security rules ID is provided, all security rules will be removed for the given set + * of subission features. + * + * @param {number[]} submissionFeatureIds + * @param {number[]} [removeRuleIds] * * @return {*} {Promise} * @memberof SecurityService */ - async removeSecurityRulesFromSubmissionFeatures(features: number[]): Promise { - return this.securityRepository.removeSecurityRulesFromSubmissionFeatures(features); + async removeSecurityRulesFromSubmissionFeatures( + submissionFeatureIds: number[], + removeRuleIds?: number[] + ): Promise { + if (!submissionFeatureIds.length) { + return []; + } + + if (!removeRuleIds) { + return this.securityRepository.removeAllSecurityRulesFromSubmissionFeatures(submissionFeatureIds); + } + + return this.securityRepository.removeSecurityRulesFromSubmissionFeatures(submissionFeatureIds, removeRuleIds); } /** * Gets Submission Feature Security Records for a given set of submission feature ids * - * @param {number[]} features + * @param {number[]} submissionFeatureIds + * @return {*} {Promise} + * @memberof SecurityService + */ + async getSecurityRulesForSubmissionFeatures( + submissionFeatureIds: number[] + ): Promise { + if (!submissionFeatureIds.length) { + // no features, return early + return []; + } + + return this.securityRepository.getSecurityRulesForSubmissionFeatures(submissionFeatureIds); + } + + /** + * Gets all Security Records for all featues belonging to the given submission. + * + * @param {number} submissionId * @return {*} {Promise} * @memberof SecurityService */ - async getSecurityRulesForSubmissionFeatures(features: number[]): Promise { - return this.securityRepository.getSecurityRulesForSubmissionFeatures(features); + async getAllSecurityRulesForSubmission(submissionId: number): Promise { + return this.securityRepository.getAllSecurityRulesForSubmission(submissionId); } /** - * Gets a list of all active security rules + * Gets a list of all active security rules. A security rule is active if it has not + * been end-dated. * * @return {*} {Promise} * @memberof SecurityService @@ -386,7 +427,8 @@ export class SecurityService extends DBService { } /** - * Gets a list of all active security rules with associated categories + * Gets a list of all active security rules with associated categories. A security rule is + * active if it has not been end-dated. * * @return {*} {Promise} * @memberof SecurityService @@ -396,7 +438,8 @@ export class SecurityService extends DBService { } /** - * Gets a list of all active security categories + * Gets a list of all active security categories. A security category is active if it has + * not been end-dated. * * @return {*} {Promise} * @memberof SecurityService diff --git a/app/src/components/security/ManageSecurity.tsx b/app/src/components/security/ManageSecurity.tsx index 392f6c787..7a03da310 100644 --- a/app/src/components/security/ManageSecurity.tsx +++ b/app/src/components/security/ManageSecurity.tsx @@ -1,13 +1,13 @@ import { mdiSecurity } from '@mdi/js'; import Icon from '@mdi/react'; import { Button } from '@mui/material'; +import { GridRowSelectionModel } from '@mui/x-data-grid'; import { useSubmissionContext } from 'hooks/useContext'; import { useState } from 'react'; import SecuritiesDialog from './SecuritiesDialog'; -import UnsecureDialog from './UnsecureDialog'; interface IManageSecurityProps { - features: number[]; + submissionFeatureIds: GridRowSelectionModel; onClose: () => void; } @@ -16,27 +16,18 @@ const ManageSecurity = (props: IManageSecurityProps) => { const hasSecurity = Boolean(submissionFeaturesAppliedRulesDataLoader.data?.length); - const [isUnsecureDialogOpen, setIsUnsecuredDialogOpen] = useState(false); const [isSecuritiesDialogOpen, setIsSecuritiesDialogOpen] = useState(false); return ( <> { props.onClose(); setIsSecuritiesDialogOpen(false); }} /> - { - props.onClose(); - setIsUnsecuredDialogOpen(false); - }} - /> + )} ); }; diff --git a/app/src/components/security/SecurityRuleCard.tsx b/app/src/components/security/SecurityRuleCard.tsx index 05f5fb7c3..3ca9d5f25 100644 --- a/app/src/components/security/SecurityRuleCard.tsx +++ b/app/src/components/security/SecurityRuleCard.tsx @@ -1,10 +1,14 @@ import { Box, Typography } from '@mui/material'; +import { Stack } from '@mui/system'; -interface ISecurityRuleCardProps { +export interface ISecurityRuleCardProps { + key?: string | number; title: string; category: string; - subtitle: string; + description: string; + featureMembers?: string[]; } + const SecurityRuleCard = (props: ISecurityRuleCardProps) => { return ( @@ -35,8 +39,17 @@ const SecurityRuleCard = (props: ISecurityRuleCardProps) => { overflow: 'hidden', textOverflow: 'ellipsis' }}> - {props.subtitle} + {props.description} + {props.featureMembers && props.featureMembers?.length && ( + + {props.featureMembers.map((featureMember) => ( + + {featureMember} + + ))} + + )} ); }; diff --git a/app/src/components/security/SecurityRuleForm.tsx b/app/src/components/security/SecurityRuleForm.tsx index 81fdc084b..b3d9250e3 100644 --- a/app/src/components/security/SecurityRuleForm.tsx +++ b/app/src/components/security/SecurityRuleForm.tsx @@ -5,50 +5,138 @@ import Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete'; import Box from '@mui/material/Box'; import TextField from '@mui/material/TextField'; import { useFormikContext } from 'formik'; -import { ISecurityRuleAndCategory } from 'hooks/api/useSecurityApi'; +import { ISecurityRuleAndCategory, ISubmissionFeatureSecurityRecord } from 'hooks/api/useSecurityApi'; import { useSubmissionContext } from 'hooks/useContext'; -import { useState } from 'react'; +import { IPatchFeatureSecurityRules } from 'interfaces/useSecurityApi.interface'; +import { useMemo, useState } from 'react'; import { TransitionGroup } from 'react-transition-group'; -import { alphabetizeObjects } from 'utils/Utils'; -import yup from 'utils/YupSchema'; +import { alphabetizeObjects, pluralize as p } from 'utils/Utils'; import SecurityRuleActionCard from './SecurityRuleActionCard'; import SecurityRuleCard from './SecurityRuleCard'; -export interface ISecurityRuleFormProps { - features: number[]; +interface IAppliedSecurityRuleGroup { + securityRule: ISecurityRuleAndCategory; + submissionFeatureIds: number[]; + appliedFeatureGroups: { displayName: string; numFeatures: number }[]; } -export interface ISecurityRuleFormikProps { - rules: ISecurityRuleAndCategory[]; -} - -export const SecurityRuleFormYupSchema = yup.object().shape({ - rules: yup.array(yup.object()) -}); - -const SecurityRuleForm = (props: ISecurityRuleFormProps) => { - const { handleSubmit, values, setFieldValue } = useFormikContext(); +const SecurityRuleForm = () => { + const formikProps = useFormikContext(); const [searchText, setSearchText] = useState(''); const submissionContext = useSubmissionContext(); - // List of all potential security rules - const securityRules = submissionContext.allSecurityRulesStaticListDataLoader.data || []; + const { + allSecurityRulesStaticListDataLoader, + submissionFeaturesAppliedRulesDataLoader, + submissionFeatureGroupsDataLoader + } = submissionContext; + + // List all potential security rules + const allSecurityRules = useMemo(() => { + return allSecurityRulesStaticListDataLoader.data ?? []; + }, [allSecurityRulesStaticListDataLoader.data]); + + const initialAppliedSecurityRules = useMemo(() => { + return submissionFeaturesAppliedRulesDataLoader.data ?? []; + }, [submissionFeaturesAppliedRulesDataLoader.data]); - const hasNoSecuritySelected = !values.rules.length; + /** + * An aggregate of all security rules that have been applied to one or more of the *selected* features, + * in addition to all of the features IDs and features types (with counts) that belong to each rule. + */ + const groupedAppliedSecurityRules: IAppliedSecurityRuleGroup[] = useMemo(() => { + return ( + initialAppliedSecurityRules + // Filter out any security records that don't pertain to the selected. + .filter((securityRecord) => + formikProps.initialValues.submissionFeatureIds.includes(securityRecord.submission_feature_id) + ) - const handleAdd = (selected: ISecurityRuleAndCategory) => { - setFieldValue(`rules[${values.rules.length}]`, selected); + // Group security records by rule, including associated feature IDs and feature type counts. + .reduce((ruleGroups: IAppliedSecurityRuleGroup[], securityRecord: ISubmissionFeatureSecurityRecord) => { + const ruleGroupIndex = ruleGroups.findIndex( + (ruleGroup) => ruleGroup.securityRule.security_rule_id === securityRecord.security_rule_id + ); + + const featureGroupDisplayName = + (submissionFeatureGroupsDataLoader.data ?? []).find((featureGroup) => { + return featureGroup.features.some( + (feature) => feature.submission_feature_id === securityRecord.submission_feature_id + ); + })?.feature_type_display_name ?? 'Other'; + + if (ruleGroupIndex === -1) { + const securityRule = allSecurityRules.find( + (securityRule) => securityRule.security_rule_id === securityRecord.security_rule_id + ); + if (securityRule) { + ruleGroups.push({ + securityRule, + submissionFeatureIds: [securityRecord.submission_feature_id], + appliedFeatureGroups: [{ displayName: featureGroupDisplayName, numFeatures: 1 }] + }); + } + } else { + ruleGroups[ruleGroupIndex].submissionFeatureIds.push(securityRecord.submission_feature_id); + + const featureGroupIndex = ruleGroups[ruleGroupIndex].appliedFeatureGroups.findIndex((featureGroup) => { + return featureGroup.displayName === featureGroupDisplayName; + }); + + if (featureGroupIndex === -1) { + ruleGroups[ruleGroupIndex].appliedFeatureGroups.push({ + displayName: featureGroupDisplayName, + numFeatures: 1 + }); + } else { + ruleGroups[ruleGroupIndex].appliedFeatureGroups[featureGroupIndex].numFeatures++; + } + } + + return ruleGroups; + }, []) + ); + }, [initialAppliedSecurityRules, submissionFeatureGroupsDataLoader.data]); + + const toggleStageApply = (securityRule: ISecurityRuleAndCategory) => { + if ( + formikProps.values.stagedForApply.some( + (applyingRule) => applyingRule.security_rule_id === securityRule.security_rule_id + ) + ) { + formikProps.setFieldValue( + 'stagedForApply', + formikProps.values.stagedForApply.filter((value) => value.security_rule_id !== securityRule.security_rule_id) + ); + } else { + formikProps.setFieldValue('stagedForApply', [...formikProps.values.stagedForApply, securityRule]); + } }; - const handleRemove = (idToRemove: number) => { - const formData = values.rules; - const filteredData = formData.filter((item) => item.security_rule_id !== idToRemove); - setFieldValue('rules', filteredData); + const toggleStageRemove = (securityRule: ISecurityRuleAndCategory) => { + if ( + formikProps.values.stagedForRemove.some( + (removingRule) => removingRule.security_rule_id === securityRule.security_rule_id + ) + ) { + formikProps.setFieldValue( + 'stagedForRemove', + formikProps.values.stagedForRemove.filter((value) => value.security_rule_id !== securityRule.security_rule_id) + ); + } else { + formikProps.setFieldValue('stagedForRemove', [...formikProps.values.stagedForRemove, securityRule]); + } }; + const applyRulesAvailableSortedOptions = useMemo(() => { + return alphabetizeObjects(allSecurityRules, 'name'); + }, [allSecurityRules]); + + const hasNoSecuritySelected = !initialAppliedSecurityRules.length; + return ( -
+ { }}> Specify reasons why this information should be secured. + + + Add Security Rules + { const searchFilter = createFilterOptions({ ignoreCase: true, matchFrom: 'any', stringify: (option) => option.name + option.category_name }); - const unselectedOptions = options.filter( - (item) => !values.rules.some((existing) => existing.security_rule_id === item.security_rule_id) - ); - return searchFilter(unselectedOptions, state); + + const selectableOptions = options.filter((securityRule) => { + return !formikProps.values.stagedForApply.some( + (applyingRule) => applyingRule.security_rule_id === securityRule.security_rule_id + ); + }); + + return searchFilter(selectableOptions, state); }} getOptionLabel={(option) => option.name} isOptionEqualToValue={(option, value) => option.security_rule_id === value.security_rule_id} @@ -90,14 +187,14 @@ const SecurityRuleForm = (props: ISecurityRuleFormProps) => { }} onChange={(_, option) => { if (option) { - handleAdd(option); + toggleStageApply(option); } }} renderInput={(params) => ( { ); }} /> - - {values.rules.map((rule: ISecurityRuleAndCategory) => { + + + {formikProps.values.stagedForApply.map((applyingRule) => { + return ( + + toggleStageApply(applyingRule)} + /> + + ); + })} + + + + Manage Existing Security + + These rules have already been applied to one or more of the selected features. + + + + {groupedAppliedSecurityRules.map((group: IAppliedSecurityRuleGroup) => { + const cardAction = formikProps.values.stagedForRemove.some( + (removingRule) => removingRule.security_rule_id === group.securityRule.security_rule_id + ) + ? 'remove' + : 'persist'; + return ( - + + `${p(featureGroup.numFeatures, featureGroup.displayName)} (${featureGroup.numFeatures})` + )} + onRemove={() => toggleStageRemove(group.securityRule)} /> ); diff --git a/app/src/components/security/UnsecureDialog.tsx b/app/src/components/security/UnsecureDialog.tsx deleted file mode 100644 index d70ddb53f..000000000 --- a/app/src/components/security/UnsecureDialog.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { Alert, AlertTitle, Typography } from '@mui/material'; -import YesNoDialog from 'components/dialog/YesNoDialog'; -import { ApplySecurityRulesI18N } from 'constants/i18n'; -import { useApi } from 'hooks/useApi'; -import { useDialogContext } from 'hooks/useContext'; - -interface IUnsecureDialogProps { - features: number[]; - open: boolean; - onClose: () => void; -} -const UnsecureDialog = (props: IUnsecureDialogProps) => { - const api = useApi(); - const dialogContext = useDialogContext(); - - const handleRemove = async () => { - try { - await api.security.removeSecurityRulesFromSubmissionFeatures(props.features); - dialogContext.setSnackbar({ - snackbarMessage: ( - - {ApplySecurityRulesI18N.unApplySecurityRulesSuccess(props.features.length)} - - ), - open: true - }); - } catch (error) { - // Close yes-no dialog - dialogContext.setYesNoDialog({ open: false }); - - // Show error dialog - dialogContext.setErrorDialog({ - onOk: () => dialogContext.setErrorDialog({ open: false }), - onClose: () => dialogContext.setErrorDialog({ open: false }), - dialogTitle: ApplySecurityRulesI18N.unapplySecurityRulesErrorTitle, - dialogText: ApplySecurityRulesI18N.unapplySecurityRulesErrorText, - open: true - }); - } finally { - props.onClose(); - } - }; - - return ( - handleRemove()} - onNo={props.onClose} - onClose={() => {}} - dialogTitle="Unsecure all records?" - dialogText="Are you sure you want to unsecure all records in this submission?" - dialogContent={ - - Open access to all records - All users will have unrestricted access to records that have been included in this submission. - - } - yesButtonProps={{ color: 'error' }} - yesButtonLabel="UNSECURE" - noButtonLabel="CANCEL" - /> - ); -}; - -export default UnsecureDialog; diff --git a/app/src/constants/i18n.ts b/app/src/constants/i18n.ts index b0374e5ad..58f3e7a01 100644 --- a/app/src/constants/i18n.ts +++ b/app/src/constants/i18n.ts @@ -26,15 +26,15 @@ export const DeleteSystemUserI18N = { }; export const ApplySecurityRulesI18N = { - applySecuritySuccess: (ruleCount: number, featureCount: number) => { - if (ruleCount === 0) { - return `Successfully removed all security rules for ${featureCount} ${p(featureCount, 'feature')}.`; - } + applySecuritySuccess: (numApplied: number, numRemoved: number, featureCount: number) => { + const appliedRemoved = [ + numApplied > 0 && `applied ${numApplied} ${p(numApplied, 'security rule')}`, + numRemoved > 0 && `removed ${numRemoved} ${p(numRemoved, 'security rule')}` + ] + .filter(Boolean) + .join(' and '); - return `Successfully applied ${ruleCount} ${p(ruleCount, 'security rule')} to ${featureCount} ${p( - featureCount, - 'feature' - )}.`; + return `Successfully ${appliedRemoved} for ${featureCount} ${p(featureCount, 'feature')}.`; }, applySecurityRulesErrorTitle: 'Error Applying Security', diff --git a/app/src/contexts/submissionContext.tsx b/app/src/contexts/submissionContext.tsx index 36f8122ba..9b0587ef0 100644 --- a/app/src/contexts/submissionContext.tsx +++ b/app/src/contexts/submissionContext.tsx @@ -57,13 +57,13 @@ export const SubmissionContext = React.createContext = (props) => { const api = useApi(); - // Stores the static list of all security rules that could be applied to a submission feature - const allSecurityRulesStaticListDataLoader = useDataLoader(api.security.getActiveSecurityRulesAndCategories); + // Retrieves the static list of all security rules that could be applied to a submission feature + const allSecurityRulesStaticListDataLoader = useDataLoader(api.security.getActiveSecurityRulesWithCategories); - // Stores the submission record, including security metadata + // Retrieves the submission record, including security metadata const submissionRecordDataLoader = useDataLoader(api.submissions.getSubmissionRecordWithSecurity); - // Stores the list of all features for the given submission + // Retrieves the list of all features for the given submission const submissionFeatureGroupsDataLoader = useDataLoader(api.submissions.getSubmissionFeatureGroups); // The collection of all feature IDs belonging to this submission @@ -82,9 +82,12 @@ export const SubmissionContextProvider: React.FC = (pro // eslint-disable-next-line react-hooks/exhaustive-deps }, [submissionFeatureGroupsDataLoader.data]); - // Stores the list of all security rules applied to the given features + /** + * Stores the list of pivot values representing all security rules that apply to all the feaures belonging + * to the current submission. + */ const submissionFeaturesAppliedRulesDataLoader = useDataLoader(() => { - return api.security.getSecurityRulesForSubmissionFeatures(allSubmissionFeatureIds); + return api.security.getAllSecurityRulesForSubmission(submissionId); }); const urlParams = useParams(); diff --git a/app/src/features/submissions/AdminSubmissionPage.tsx b/app/src/features/submissions/AdminSubmissionPage.tsx index fe20dbc36..53da28015 100644 --- a/app/src/features/submissions/AdminSubmissionPage.tsx +++ b/app/src/features/submissions/AdminSubmissionPage.tsx @@ -1,10 +1,41 @@ +import { Skeleton } from '@mui/material'; import Box from '@mui/material/Box'; import Container from '@mui/material/Container'; import Stack from '@mui/material/Stack'; -import SubmissionHeader from 'features/submissions/components/SubmissionHeader'; +import { GridRowSelectionModel } from '@mui/x-data-grid'; +import BaseHeader from 'components/layout/header/BaseHeader'; +import SubmissionHeaderToolbar from 'features/submissions/components/SubmissionHeaderToolbar'; import { useSubmissionContext } from 'hooks/useContext'; import { IGetSubmissionGroupedFeatureResponse } from 'interfaces/useSubmissionsApi.interface'; +import { useState } from 'react'; import SubmissionDataGrid from './components/SubmissionDataGrid/SubmissionDataGrid'; +import SubmissionHeaderSecurityStatus from './components/SubmissionHeaderSecurityStatus'; + +type GroupedSubmissionFeatureSelection = Record< + IGetSubmissionGroupedFeatureResponse['feature_type_name'], + GridRowSelectionModel +>; + +const SubmissionHeader = (props: { submissionFeatureIds: GridRowSelectionModel }) => { + const submissionContext = useSubmissionContext(); + const submission = submissionContext.submissionRecordDataLoader.data; + + if (!submission) { + return <>; + } + + return ( + + {submission ? : } + + } + buttonJSX={} + /> + ); +}; /** * AdminSubmissionPage component for reviewing submissions. @@ -12,11 +43,31 @@ import SubmissionDataGrid from './components/SubmissionDataGrid/SubmissionDataGr * @return {*} */ const AdminSubmissionPage = () => { + const [groupedSubmissionFeatureSelection, setGroupedSubmissionFeatureSelection] = + useState({}); + const submissionContext = useSubmissionContext(); const { submissionFeatureGroupsDataLoader } = submissionContext; const submissionFeatureGroups = submissionFeatureGroupsDataLoader.data || []; + const onRowSelectionModelChange = ( + featureTypeName: IGetSubmissionGroupedFeatureResponse['feature_type_name'], + rowSelectionModel: GridRowSelectionModel + ) => { + setGroupedSubmissionFeatureSelection((prev) => ({ + ...prev, + [featureTypeName]: rowSelectionModel + })); + }; + + const submissionFeatureIds: GridRowSelectionModel = Object.values(groupedSubmissionFeatureSelection).reduce( + (acc: GridRowSelectionModel, featureIds: GridRowSelectionModel) => { + return acc.concat(featureIds); + }, + [] + ); + const allSubmissionFeatureIds = submissionFeatureGroups.reduce( (acc: number[], submissionFeatureGroup: IGetSubmissionGroupedFeatureResponse) => { return acc.concat(submissionFeatureGroup.features.map((feature) => feature.submission_feature_id)); @@ -26,16 +77,23 @@ const AdminSubmissionPage = () => { return ( <> - + {submissionFeatureGroups.map((submissionFeatureGroup) => { + const featureTypeName = submissionFeatureGroup.feature_type_name; + const rowSelectionModel = groupedSubmissionFeatureSelection[submissionFeatureGroup.feature_type_name]; + return ( - + onRowSelectionModelChange(featureTypeName, model)} + rowSelectionModel={rowSelectionModel} /> ); diff --git a/app/src/features/submissions/components/SubmissionDataGrid.tsx b/app/src/features/submissions/components/SubmissionDataGrid.tsx new file mode 100644 index 000000000..4cfcfb0cd --- /dev/null +++ b/app/src/features/submissions/components/SubmissionDataGrid.tsx @@ -0,0 +1,163 @@ +import { mdiLock, mdiLockOpenOutline } from '@mdi/js'; +import Icon from '@mdi/react'; +import { Divider, Paper, Stack, Toolbar } from '@mui/material'; +import Typography from '@mui/material/Typography'; +import { Box } from '@mui/system'; +import { + DataGrid, + GridColDef, + GridInputRowSelectionModel, + GridRenderCellParams, + GridRowSelectionModel, + GridValueGetterParams +} from '@mui/x-data-grid'; +import { useCodesContext } from 'hooks/useContext'; +import { IFeatureTypeProperties } from 'interfaces/useCodesApi.interface'; +import { SubmissionFeatureRecordWithTypeAndSecurity } from 'interfaces/useSubmissionsApi.interface'; + +export interface ISubmissionDataGridProps { + feature_type_display_name: string; + feature_type_name: string; + submissionFeatures: SubmissionFeatureRecordWithTypeAndSecurity[]; + rowSelectionModel: GridInputRowSelectionModel; + onRowSelectionModelChange: (rowSelectionModel: GridRowSelectionModel) => void; +} + +/** + * SubmissionDataGrid component for displaying submission data. + * + * @param {ISubmissionDataGridProps} props + * @return {*} + */ +export const SubmissionDataGrid = (props: ISubmissionDataGridProps) => { + const codesContext = useCodesContext(); + const { submissionFeatures, feature_type_display_name, feature_type_name } = props; + + const featureTypesWithProperties = codesContext.codesDataLoader.data?.feature_type_with_properties; + + const featureTypeWithProperties = + featureTypesWithProperties?.find((item) => item.feature_type['name'] === feature_type_name) + ?.feature_type_properties || []; + + const fieldColumns = featureTypeWithProperties.map((featureType: IFeatureTypeProperties) => { + return { + field: featureType.name, + headerName: featureType.display_name, + flex: 1, + disableColumnMenu: true, + valueGetter: (params: GridValueGetterParams) => params.row.data[featureType.name] ?? null, + renderCell: (params: GridRenderCellParams) => { + return ( + + {String(params.value)} + + ); + } + }; + }); + + const columns: GridColDef[] = [ + { + field: 'submission_feature_security_ids', + headerName: 'Security', + flex: 0, + disableColumnMenu: true, + width: 160, + renderCell: (params) => { + if (params.value.length > 0) { + return ( + + + + Secured + + + ); + } + return ( + + + + Unsecured + + + ); + } + }, + { + field: 'submission_feature_id', + headerName: 'ID', + flex: 0, + disableColumnMenu: true, + width: 100 + }, + { + field: 'parent_submission_feature_id', + headerName: 'Parent ID', + flex: 0, + disableColumnMenu: true, + width: 120 + }, + ...fieldColumns + ]; + + return ( + + + + {`${feature_type_display_name} Records`} + + ({submissionFeatures.length}) + + + + + + + row.submission_feature_id} + autoHeight + rows={submissionFeatures} + columns={columns} + pageSizeOptions={[5]} + editMode="row" + rowSelectionModel={props.rowSelectionModel} + onRowSelectionModelChange={props.onRowSelectionModelChange} + disableRowSelectionOnClick + disableColumnSelector + disableColumnMenu + sortingOrder={['asc', 'desc']} + initialState={{ + sorting: { sortModel: [{ field: 'submission_feature_id', sort: 'asc' }] }, + pagination: { + paginationModel: { + pageSize: 10 + } + } + }} + sx={{ + '& .MuiDataGrid-columnHeaderTitle': { + fontWeight: 700, + textTransform: 'uppercase', + color: 'text.secondary' + } + }} + /> + + + ); +}; + +export default SubmissionDataGrid; diff --git a/app/src/features/submissions/components/SubmissionDataGrid/SubmissionDataGrid.tsx b/app/src/features/submissions/components/SubmissionDataGrid/SubmissionDataGrid.tsx index db02b536d..64f81fc22 100644 --- a/app/src/features/submissions/components/SubmissionDataGrid/SubmissionDataGrid.tsx +++ b/app/src/features/submissions/components/SubmissionDataGrid/SubmissionDataGrid.tsx @@ -1,9 +1,8 @@ import { Divider, Paper, Toolbar } from '@mui/material'; import Typography from '@mui/material/Typography'; import { Box } from '@mui/system'; -import { DataGrid, GridRowSelectionModel } from '@mui/x-data-grid'; +import { DataGrid, GridInputRowSelectionModel, GridRowSelectionModel } from '@mui/x-data-grid'; import { SubmissionFeatureRecordWithTypeAndSecurity } from 'interfaces/useSubmissionsApi.interface'; -import React, { useState } from 'react'; import { pluralize } from 'utils/Utils'; import useSubmissionDataGridColumns from './useSubmissionDataGridColumns'; @@ -11,6 +10,8 @@ export interface ISubmissionDataGridProps { feature_type_display_name: string; feature_type_name: string; submissionFeatures: SubmissionFeatureRecordWithTypeAndSecurity[]; + rowSelectionModel: GridInputRowSelectionModel; + onRowSelectionModelChange: (rowSelectionModel: GridRowSelectionModel) => void; } /** @@ -24,8 +25,6 @@ export const SubmissionDataGrid = (props: ISubmissionDataGridProps) => { const columns = useSubmissionDataGridColumns(feature_type_name); - const [rowSelectionModel, setRowSelectionModel] = useState([]); - return ( @@ -40,6 +39,7 @@ export const SubmissionDataGrid = (props: ISubmissionDataGridProps) => { row.submission_feature_id} autoHeight @@ -47,10 +47,8 @@ export const SubmissionDataGrid = (props: ISubmissionDataGridProps) => { columns={columns} pageSizeOptions={[5]} editMode="row" - rowSelectionModel={rowSelectionModel} - onRowSelectionModelChange={(model) => { - setRowSelectionModel(model); - }} + rowSelectionModel={props.rowSelectionModel} + onRowSelectionModelChange={props.onRowSelectionModelChange} disableRowSelectionOnClick disableColumnSelector disableColumnMenu diff --git a/app/src/features/submissions/components/SubmissionDataGrid/useSubmissionDataGridColumns.tsx b/app/src/features/submissions/components/SubmissionDataGrid/useSubmissionDataGridColumns.tsx index 35bc61f62..47bd927a9 100644 --- a/app/src/features/submissions/components/SubmissionDataGrid/useSubmissionDataGridColumns.tsx +++ b/app/src/features/submissions/components/SubmissionDataGrid/useSubmissionDataGridColumns.tsx @@ -1,13 +1,12 @@ import { mdiLock, mdiLockOpenOutline } from '@mdi/js'; import Icon from '@mdi/react'; -import { Button, Stack } from '@mui/material'; +import { Button, Stack, Typography } from '@mui/material'; import { Box } from '@mui/system'; import { GridColDef, GridRenderCellParams, GridValueGetterParams } from '@mui/x-data-grid'; import { useApi } from 'hooks/useApi'; import { useCodesContext } from 'hooks/useContext'; import useDownload from 'hooks/useDownload'; import { IFeatureTypeProperties } from 'interfaces/useCodesApi.interface'; -import React from 'react'; /** * Hook to generate columns for SubmissionDataGrid @@ -84,7 +83,9 @@ const useSubmissionDataGridColumns = (featureTypeName: string): GridColDef[] => return ( - SECURED + + Secured + ); } @@ -97,7 +98,9 @@ const useSubmissionDataGridColumns = (featureTypeName: string): GridColDef[] => color: 'text.secondary' }}> - UNSECURED + + Unsecured + ); } diff --git a/app/src/features/submissions/components/SubmissionHeader.tsx b/app/src/features/submissions/components/SubmissionHeaderToolbar.tsx similarity index 58% rename from app/src/features/submissions/components/SubmissionHeader.tsx rename to app/src/features/submissions/components/SubmissionHeaderToolbar.tsx index 190985a8f..6d0c2453a 100644 --- a/app/src/features/submissions/components/SubmissionHeader.tsx +++ b/app/src/features/submissions/components/SubmissionHeaderToolbar.tsx @@ -1,24 +1,23 @@ import { mdiArrowRight } from '@mdi/js'; import Icon from '@mdi/react'; -import CircularProgress from '@mui/material/CircularProgress'; import Stack from '@mui/material/Stack'; -import BaseHeader from 'components/layout/header/BaseHeader'; +import { GridRowSelectionModel } from '@mui/x-data-grid'; import ManageSecurity from 'components/security/ManageSecurity'; import CompleteSecurityReviewButton from 'features/submissions/components/PublishSecurityReview/CompleteSecurityReviewButton'; -import SubmissionHeaderSecurityStatus from 'features/submissions/components/SubmissionHeaderSecurityStatus'; import { useApi } from 'hooks/useApi'; import { useDialogContext, useSubmissionContext } from 'hooks/useContext'; import PublishSecurityReviewButton from './PublishSecurityReview/PublishSecurityReviewButton'; -export interface ISubmissionHeaderProps { - selectedFeatures: number[]; + +export interface ISubmissionHeaderToolbarProps { + submissionFeatureIds: GridRowSelectionModel; } /** - * Submission header for admin single-submission view. + * Submission header toolbar for admin single-submission view. * * @return {*} */ -const SubmissionHeader = (props: ISubmissionHeaderProps) => { +const SubmissionHeaderToolbar = (props: ISubmissionHeaderToolbarProps) => { const submissionContext = useSubmissionContext(); const dialogContext = useDialogContext(); const api = useApi(); @@ -26,7 +25,7 @@ const SubmissionHeader = (props: ISubmissionHeaderProps) => { const submissionRecordDataLoader = submissionContext.submissionRecordDataLoader; if (!submissionRecordDataLoader.data) { - return ; + return <>; } const submission = submissionRecordDataLoader.data; @@ -76,38 +75,28 @@ const SubmissionHeader = (props: ISubmissionHeaderProps) => { }; return ( - - - - } - buttonJSX={ - - { - submissionRecordDataLoader.refresh(submissionContext.submissionId); - submissionContext.submissionFeatureGroupsDataLoader.refresh(submissionContext.submissionId); - }} - /> + + { + submissionRecordDataLoader.refresh(submissionContext.submissionId); + submissionContext.submissionFeatureGroupsDataLoader.refresh(submissionContext.submissionId); + }} + /> - - {submission.publish_timestamp == null && } - - - } - /> + + {submission.publish_timestamp == null && } + + ); }; -export default SubmissionHeader; +export default SubmissionHeaderToolbar; diff --git a/app/src/hooks/api/useSecurityApi.ts b/app/src/hooks/api/useSecurityApi.ts index 1c294f0c1..5698a68c9 100644 --- a/app/src/hooks/api/useSecurityApi.ts +++ b/app/src/hooks/api/useSecurityApi.ts @@ -1,5 +1,9 @@ import { AxiosInstance } from 'axios'; -import { IListPersecutionHarmResponse, ISecureDataAccessRequestForm } from 'interfaces/useSecurityApi.interface'; +import { + IListPersecutionHarmResponse, + IPatchFeatureSecurityRules, + ISecureDataAccessRequestForm +} from 'interfaces/useSecurityApi.interface'; export interface ISecurityRule { security_rule_id: number; @@ -86,79 +90,48 @@ const useSecurityApi = (axios: AxiosInstance) => { return data; }; - const getActiveSecurityRules = async (): Promise => { - const { data } = await axios.get('api/administrative/security'); - return data; - }; - - const getActiveSecurityRulesAndCategories = async (): Promise => { - const { data } = await axios.get('api/administrative/security/category/fetch'); - return data; - }; - - const addSecurityRule = async (newRule: { - name: string; - description: string; - record_effective_date: string; - record_end_date?: string; - }): Promise => { - await axios.post('api/administrative/security', {}); - // new item id - return 1; - }; - /** - * Applies all of the given security rule IDs to all of the given submission feature IDs. If the - * `override` parameter is supplied as `true`, then all rules for these submission features will - * be replaced with the incoming set. Otherwise, the union of the existing rules and supplied - * rules will be applied to these features (deafult behaviour). - * - * @param {number[]} submissionFeatureIds - * @param {number[]} ruleIds - * @return {*} {Promise} + * Gets a list of all active security rules with associated categories. A security rule is + * active if it has not been end-dated. */ - const applySecurityRulesToSubmissionFeatures = async ( - submissionFeatureIds: number[], - ruleIds: number[], - override = false - ): Promise => { - const { data } = await axios.post('api/administrative/security/apply', { - override, - features: submissionFeatureIds, - rules: ruleIds - }); + const getActiveSecurityRulesWithCategories = async (): Promise => { + const { data } = await axios.get('api/administrative/security/rules'); return data; }; /** - * Removes all of the security rules for the given submission feature IDs, rendering them unsecure. - * - * @deprecated Use `applySecurityRulesToSubmissionFeatures(submissionFeatureIds, [], true)` + * Patches security rules that are applied or removed to the given set of submission features. If + * a particular rule happens to belong to both `applyRuleIds` and `removeRuleIds`, it will always + * be added. * * @param {number[]} submissionFeatureIds + * @param {number[]} ruleIds * @return {*} {Promise} */ - const removeSecurityRulesFromSubmissionFeatures = async (submissionFeatureIds: number[]): Promise => { - const { data } = await axios.post('api/administrative/security/remove', { - features: submissionFeatureIds + const patchSecurityRulesOnSubmissionFeatures = async ( + submissionId: number, + featureSecurityRulesPatch: IPatchFeatureSecurityRules + ): Promise => { + const { data } = await axios.patch(`api/administrative/security/submission/${submissionId}`, { + applyRuleIds: featureSecurityRulesPatch.stagedForApply.map((rule) => rule.security_rule_id), + removeRuleIds: featureSecurityRulesPatch.stagedForRemove.map((rule) => rule.security_rule_id), + submissionFeatureIds: featureSecurityRulesPatch.submissionFeatureIds }); return data; }; /** - * Retrieves the list of all security rule IDs associated with the list of given submission feature IDs + * Retrieves the list of all security rule IDs associated with the features belonging to the given submission. * * @param {number[]} features * @return {*} {Promise} */ - const getSecurityRulesForSubmissionFeatures = async ( - features: number[] + const getAllSecurityRulesForSubmission = async ( + submissionId: number ): Promise => { - const { data } = await axios.post('api/administrative/security/fetch', { - features - }); + const { data } = await axios.get(`api/administrative/security/submission/${submissionId}`); return data; }; @@ -167,12 +140,9 @@ const useSecurityApi = (axios: AxiosInstance) => { sendSecureArtifactAccessRequest, listPersecutionHarmRules, applySecurityReasonsToArtifacts, - getActiveSecurityRules, - addSecurityRule, - applySecurityRulesToSubmissionFeatures, - removeSecurityRulesFromSubmissionFeatures, - getSecurityRulesForSubmissionFeatures, - getActiveSecurityRulesAndCategories + patchSecurityRulesOnSubmissionFeatures, + getAllSecurityRulesForSubmission, + getActiveSecurityRulesWithCategories }; }; diff --git a/app/src/interfaces/useSecurityApi.interface.ts b/app/src/interfaces/useSecurityApi.interface.ts index 2a2aee2e2..4b3420db0 100644 --- a/app/src/interfaces/useSecurityApi.interface.ts +++ b/app/src/interfaces/useSecurityApi.interface.ts @@ -1,3 +1,6 @@ +import { GridRowSelectionModel } from '@mui/x-data-grid'; +import { ISecurityRuleAndCategory } from 'hooks/api/useSecurityApi'; + export interface ISecureDataAccessRequestForm { fullName: string; emailAddress: string; @@ -28,3 +31,35 @@ export interface IPersecutionHarmRule { name: string; description: string | null; } + +/** + * Represents a patch request made to apply security; + * + * @export + * @interface IPatchFeatureSecurityRules + */ +export interface IPatchFeatureSecurityRules { + /** + * The array of submission feature IDs whose security rules will be mutated + * + * @type {number[]} + * @memberof IPatchFeatureSecurityRules + */ + submissionFeatureIds: number[] | GridRowSelectionModel; + /** + * The array of the security rules that will be applied to all of the given features. + * Note that it is possible that a particular rule ID may also belong to `stagedForRemove`. + * + * @type {number[]} + * @memberof IPatchFeatureSecurityRules + */ + stagedForApply: ISecurityRuleAndCategory[]; + /** + * The array of the security rules that will be removed from all of the given features. + * Note that it is possible that a particular rule ID may also belong to `stagedForApply`. + * + * @type {number[]} + * @memberof IPatchFeatureSecurityRules + */ + stagedForRemove: ISecurityRuleAndCategory[]; +} From 8ea20360217c84f97b4927155f208819b9f4c9e7 Mon Sep 17 00:00:00 2001 From: Alfred Rosenthal Date: Tue, 16 Jan 2024 11:23:33 -0800 Subject: [PATCH 2/3] fixed type checking --- .../SubmissionDataGrid/useSubmissionDataGridColumns.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/features/submissions/components/SubmissionDataGrid/useSubmissionDataGridColumns.tsx b/app/src/features/submissions/components/SubmissionDataGrid/useSubmissionDataGridColumns.tsx index 203ada0a6..67f3c8bbd 100644 --- a/app/src/features/submissions/components/SubmissionDataGrid/useSubmissionDataGridColumns.tsx +++ b/app/src/features/submissions/components/SubmissionDataGrid/useSubmissionDataGridColumns.tsx @@ -22,7 +22,7 @@ const useSubmissionDataGridColumns = (featureTypeName: string): GridColDef[] => const featureTypesWithProperties = codesContext.codesDataLoader.data?.feature_type_with_properties; const featureTypeWithProperties = - featureTypesWithProperties?.find((item) => item.feature_type['name'] === featureTypeName) + featureTypesWithProperties?.find((item) => item.feature_type.feature_type_name === featureTypeName) ?.feature_type_properties ?? []; const fieldColumns = featureTypeWithProperties.map((featureType: FeaturePropertyCode) => { From 54cf8f4161450100d9cdbdcde3a50d0b208054fe Mon Sep 17 00:00:00 2001 From: Alfred Rosenthal Date: Tue, 16 Jan 2024 11:39:58 -0800 Subject: [PATCH 3/3] fixed import issue --- .../submissions/components/SubmissionDataGrid.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/features/submissions/components/SubmissionDataGrid.tsx b/app/src/features/submissions/components/SubmissionDataGrid.tsx index 4cfcfb0cd..b697dd4c2 100644 --- a/app/src/features/submissions/components/SubmissionDataGrid.tsx +++ b/app/src/features/submissions/components/SubmissionDataGrid.tsx @@ -12,7 +12,7 @@ import { GridValueGetterParams } from '@mui/x-data-grid'; import { useCodesContext } from 'hooks/useContext'; -import { IFeatureTypeProperties } from 'interfaces/useCodesApi.interface'; +import { FeaturePropertyCode } from 'interfaces/useCodesApi.interface'; import { SubmissionFeatureRecordWithTypeAndSecurity } from 'interfaces/useSubmissionsApi.interface'; export interface ISubmissionDataGridProps { @@ -39,13 +39,13 @@ export const SubmissionDataGrid = (props: ISubmissionDataGridProps) => { featureTypesWithProperties?.find((item) => item.feature_type['name'] === feature_type_name) ?.feature_type_properties || []; - const fieldColumns = featureTypeWithProperties.map((featureType: IFeatureTypeProperties) => { + const fieldColumns = featureTypeWithProperties.map((featureType: FeaturePropertyCode) => { return { - field: featureType.name, - headerName: featureType.display_name, + field: featureType.feature_property_type_name, + headerName: featureType.feature_property_display_name, flex: 1, disableColumnMenu: true, - valueGetter: (params: GridValueGetterParams) => params.row.data[featureType.name] ?? null, + valueGetter: (params: GridValueGetterParams) => params.row.data[featureType.feature_property_type_name] ?? null, renderCell: (params: GridRenderCellParams) => { return (