From 839e31b7391cb880e983e727f7f628e9cf54dc68 Mon Sep 17 00:00:00 2001 From: Matheus Benachio Date: Tue, 3 May 2022 07:38:00 -0300 Subject: [PATCH] feat: added initial files --- .editorconfig | 12 + .github/main-screenshot.png | Bin 0 -> 303840 bytes .github/workflows/tests.yml | 28 + .gitignore | 28 + .npmrc | 2 + .vscode/extensions.json | 10 + .vscode/settings.json | 53 + LICENSE | 2 +- README.md | 36 + data.json | 4 + package-lock.json | 38360 ++++++++++++++++ package.json | 66 + packages/tcore-api/.eslintignore | 11 + packages/tcore-api/.eslintrc.js | 30 + packages/tcore-api/.prettierrc | 11 + packages/tcore-api/jest.config.js | 6 + packages/tcore-api/nodemon.json | 5 + packages/tcore-api/package.json | 71 + .../src/Controllers/APIController.ts | 216 + packages/tcore-api/src/Controllers/Action.ts | 142 + .../tcore-api/src/Controllers/Analysis.ts | 122 + .../src/Controllers/Device/Device.test.ts | 36 + .../src/Controllers/Device/Device.ts | 201 + .../Controllers/DeviceData/DeviceData.test.ts | 64 + .../src/Controllers/DeviceData/DeviceData.ts | 170 + packages/tcore-api/src/Controllers/File.ts | 33 + .../tcore-api/src/Controllers/Hardware.ts | 70 + packages/tcore-api/src/Controllers/Logs.ts | 48 + packages/tcore-api/src/Controllers/Plugins.ts | 299 + .../tcore-api/src/Controllers/Settings.ts | 47 + .../tcore-api/src/Controllers/Statistic.ts | 24 + packages/tcore-api/src/Controllers/Summary.ts | 24 + packages/tcore-api/src/Controllers/System.ts | 46 + packages/tcore-api/src/Controllers/Tag.ts | 33 + packages/tcore-api/src/Helpers/CPU.ts | 42 + packages/tcore-api/src/Helpers/Download.ts | 55 + packages/tcore-api/src/Helpers/Files.ts | 35 + packages/tcore-api/src/Helpers/Platform.ts | 63 + packages/tcore-api/src/Helpers/Tar/Tar.ts | 44 + packages/tcore-api/src/Helpers/Yaml.ts | 30 + packages/tcore-api/src/Helpers/Zip.ts | 14 + packages/tcore-api/src/Helpers/log.ts | 81 + .../tcore-api/src/Helpers/removeNullValues.ts | 14 + packages/tcore-api/src/Helpers/shutdown.ts | 64 + packages/tcore-api/src/Helpers/splitColon.ts | 9 + packages/tcore-api/src/Plugins/Host.ts | 111 + packages/tcore-api/src/Plugins/Install.ts | 281 + .../tcore-api/src/Plugins/Module/Module.ts | 142 + .../src/Plugins/Plugin/Plugin.test.ts | 281 + .../tcore-api/src/Plugins/Plugin/Plugin.ts | 225 + packages/tcore-api/src/Plugins/PluginID.ts | 9 + .../tcore-api/src/Plugins/PluginPackage.ts | 16 + packages/tcore-api/src/Plugins/Uninstall.ts | 69 + .../src/Plugins/Validator/Validator.ts | 57 + .../tcore-api/src/Plugins/Worker/Worker.ts | 250 + .../Plugins/__mocks__/plugin1/package.json | 10 + .../src/Plugins/__mocks__/plugin10/index.js | 15 + .../Plugins/__mocks__/plugin10/package.json | 11 + .../src/Plugins/__mocks__/plugin11/index.js | 8 + .../Plugins/__mocks__/plugin11/package.json | 11 + .../src/Plugins/__mocks__/plugin12/index.js | 5 + .../Plugins/__mocks__/plugin12/package.json | 11 + .../Plugins/__mocks__/plugin2/package.json | 11 + .../src/Plugins/__mocks__/plugin3/README.md | 1 + .../Plugins/__mocks__/plugin3/package.json | 11 + .../src/Plugins/__mocks__/plugin4/index.js | 2 + .../Plugins/__mocks__/plugin4/package.json | 11 + .../src/Plugins/__mocks__/plugin5/index.js | 1 + .../Plugins/__mocks__/plugin5/package.json | 11 + .../src/Plugins/__mocks__/plugin6/index.js | 7 + .../Plugins/__mocks__/plugin6/package.json | 11 + .../src/Plugins/__mocks__/plugin7/index.js | 7 + .../Plugins/__mocks__/plugin7/package.json | 11 + .../Plugins/__mocks__/plugin8/package.json | 11 + .../src/Plugins/__mocks__/plugin9/index.js | 7 + .../Plugins/__mocks__/plugin9/package.json | 11 + .../src/Plugins/executePluginRequest.ts | 104 + .../src/Plugins/invokeDatabaseFunction.ts | 14 + .../src/Plugins/invokeFilesystemFunction.ts | 14 + packages/tcore-api/src/Services/Action.ts | 283 + packages/tcore-api/src/Services/Analysis.ts | 97 + .../src/Services/AnalysisCodeExecution.ts | 109 + packages/tcore-api/src/Services/Device.ts | 171 + .../Services/DeviceData/DeviceData.test.ts | 977 + .../src/Services/DeviceData/DeviceData.ts | 341 + packages/tcore-api/src/Services/File.ts | 77 + packages/tcore-api/src/Services/FilePicker.ts | 104 + packages/tcore-api/src/Services/Hardware.ts | 198 + .../tcore-api/src/Services/LiveInspector.ts | 73 + packages/tcore-api/src/Services/Logs.ts | 33 + .../Services/PayloadParserCodeExecution.ts | 71 + packages/tcore-api/src/Services/Plugins.ts | 292 + .../tcore-api/src/Services/PluginsStorage.ts | 37 + packages/tcore-api/src/Services/Settings.ts | 139 + packages/tcore-api/src/Services/Statistic.ts | 27 + packages/tcore-api/src/Services/Summary.ts | 11 + packages/tcore-api/src/Services/System.ts | 16 + packages/tcore-api/src/Services/Tag.ts | 11 + packages/tcore-api/src/Socket/SocketServer.ts | 71 + packages/tcore-api/src/index.ts | 24 + packages/tcore-api/src/server.ts | 184 + packages/tcore-api/tsconfig.json | 30 + packages/tcore-cli/.eslintignore | 11 + packages/tcore-cli/.eslintrc.js | 30 + packages/tcore-cli/.prettierrc | 11 + packages/tcore-cli/jest.config.js | 6 + packages/tcore-cli/package.json | 47 + packages/tcore-cli/src/Commands/Logs.ts | 40 + packages/tcore-cli/src/Commands/Restart.ts | 38 + packages/tcore-cli/src/Commands/Start.ts | 107 + packages/tcore-cli/src/Commands/Status.ts | 24 + packages/tcore-cli/src/Commands/Stop.ts | 30 + packages/tcore-cli/src/Helpers/Log.ts | 14 + packages/tcore-cli/src/Helpers/PM2.ts | 87 + packages/tcore-cli/src/PluginCLI.ts | 57 + packages/tcore-cli/src/Scripts/StartPM2Dev.ts | 10 + packages/tcore-cli/src/index.ts | 63 + packages/tcore-cli/tsconfig.json | 29 + packages/tcore-console/.eslintignore | 4 + packages/tcore-console/.eslintrc.js | 110 + packages/tcore-console/.prettierrc | 12 + packages/tcore-console/assets/icons/apple.svg | 1 + packages/tcore-console/assets/icons/ban.svg | 1 + packages/tcore-console/assets/icons/bars.svg | 1 + .../assets/icons/battery-full.svg | 1 + packages/tcore-console/assets/icons/bolt.svg | 1 + packages/tcore-console/assets/icons/brush.svg | 1 + .../tcore-console/assets/icons/bucket.svg | 1 + .../tcore-console/assets/icons/bullhorn.svg | 1 + .../tcore-console/assets/icons/caret-down.svg | 1 + .../assets/icons/caret-right.svg | 1 + .../tcore-console/assets/icons/caret-up.svg | 1 + .../assets/icons/certificate.svg | 1 + packages/tcore-console/assets/icons/check.svg | 1 + .../assets/icons/chevron-left.svg | 1 + .../assets/icons/chevron-right.svg | 1 + .../tcore-console/assets/icons/circle.svg | 1 + packages/tcore-console/assets/icons/clock.svg | 1 + packages/tcore-console/assets/icons/cloud.svg | 1 + packages/tcore-console/assets/icons/code.svg | 1 + packages/tcore-console/assets/icons/cog.svg | 1 + .../assets/icons/comment-dots.svg | 1 + .../tcore-console/assets/icons/connector.svg | 1 + packages/tcore-console/assets/icons/copy.svg | 1 + packages/tcore-console/assets/icons/cube.svg | 1 + packages/tcore-console/assets/icons/cubes.svg | 1 + .../assets/icons/database-double.svg | 11 + .../tcore-console/assets/icons/database.svg | 1 + .../tcore-console/assets/icons/desktop.svg | 1 + .../assets/icons/device-union.svg | 1 + .../tcore-console/assets/icons/device.svg | 1 + .../tcore-console/assets/icons/dice-d20.svg | 1 + .../tcore-console/assets/icons/download.svg | 1 + .../tcore-console/assets/icons/ellipsis-v.svg | 1 + .../tcore-console/assets/icons/envelope.svg | 1 + .../assets/icons/exclamation-circle.svg | 1 + .../assets/icons/exclamation-triangle.svg | 1 + .../assets/icons/external-link-alt.svg | 1 + packages/tcore-console/assets/icons/eye.svg | 1 + .../tcore-console/assets/icons/file-alt.svg | 1 + .../assets/icons/file-import.svg | 1 + .../tcore-console/assets/icons/folder.svg | 1 + .../tcore-console/assets/icons/github.svg | 1 + .../assets/icons/globe-americas.svg | 1 + packages/tcore-console/assets/icons/globe.svg | 1 + .../assets/icons/grip-horizontal.svg | 1 + .../tcore-console/assets/icons/hashtag.svg | 1 + packages/tcore-console/assets/icons/hdd.svg | 1 + packages/tcore-console/assets/icons/home.svg | 1 + packages/tcore-console/assets/icons/image.svg | 1 + packages/tcore-console/assets/icons/io.svg | 1 + packages/tcore-console/assets/icons/key.svg | 1 + packages/tcore-console/assets/icons/link.svg | 1 + packages/tcore-console/assets/icons/linux.svg | 1 + packages/tcore-console/assets/icons/list.svg | 1 + packages/tcore-console/assets/icons/lock.svg | 1 + .../tcore-console/assets/icons/markdown.svg | 1 + .../tcore-console/assets/icons/memory.svg | 1 + .../tcore-console/assets/icons/microchip.svg | 1 + packages/tcore-console/assets/icons/minus.svg | 1 + .../tcore-console/assets/icons/mountain.svg | 1 + .../assets/icons/network-wired.svg | 1 + packages/tcore-console/assets/icons/pause.svg | 1 + .../tcore-console/assets/icons/pencil-alt.svg | 1 + packages/tcore-console/assets/icons/play.svg | 1 + .../assets/icons/plus-circle.svg | 1 + packages/tcore-console/assets/icons/plus.svg | 1 + .../assets/icons/puzzle-piece.svg | 1 + .../assets/icons/question-circle.svg | 1 + .../assets/icons/raspberry-pi.svg | 1 + packages/tcore-console/assets/icons/redo.svg | 1 + packages/tcore-console/assets/icons/save.svg | 1 + .../tcore-console/assets/icons/scroll.svg | 1 + .../tcore-console/assets/icons/search.svg | 1 + .../tcore-console/assets/icons/shapes.svg | 1 + .../assets/icons/sign-out-alt.svg | 1 + .../tcore-console/assets/icons/snowflake.svg | 1 + .../tcore-console/assets/icons/spinner.svg | 1 + packages/tcore-console/assets/icons/star.svg | 1 + .../tcore-console/assets/icons/stopwatch.svg | 1 + packages/tcore-console/assets/icons/store.svg | 1 + .../tcore-console/assets/icons/sync-alt.svg | 1 + packages/tcore-console/assets/icons/tag.svg | 1 + packages/tcore-console/assets/icons/tcore.svg | 13 + .../assets/icons/temperature-high.svg | 1 + .../tcore-console/assets/icons/th-large.svg | 1 + packages/tcore-console/assets/icons/times.svg | 1 + .../tcore-console/assets/icons/trash-alt.svg | 1 + .../tcore-console/assets/icons/user-alt.svg | 1 + packages/tcore-console/assets/icons/wifi.svg | 1 + .../assets/icons/window-maximize.svg | 1 + .../tcore-console/assets/icons/windows.svg | 1 + .../tcore-console/assets/images/favicon.png | Bin 0 -> 405683 bytes .../assets/images/logo-black.svg | 41 + .../assets/images/logo-white.svg | 41 + .../tcore-console/assets/images/retention.gif | Bin 0 -> 59159 bytes packages/tcore-console/esbuild/build.js | 46 + packages/tcore-console/esbuild/buildPath.js | 6 + .../tcore-console/esbuild/generateIndex.js | 27 + packages/tcore-console/esbuild/icon.js | 39 + packages/tcore-console/esbuild/svgr.js | 17 + packages/tcore-console/index.d.ts | 1 + packages/tcore-console/jest.config.js | 14 + packages/tcore-console/package.json | 84 + packages/tcore-console/react-shim.js | 5 + packages/tcore-console/src/App.tsx | 77 + .../Components/Accordion/Accordion.style.ts | 80 + .../Components/Accordion/Accordion.test.tsx | 97 + .../src/Components/Accordion/Accordion.tsx | 105 + .../Common/ActionFields/ActionFields.tsx | 182 + .../ActionTypePicker.style.ts | 43 + .../ActionTypePicker/ActionTypePicker.tsx | 138 + .../Common/DeviceRadio/DeviceRadio.style.tsx | 48 + .../Action/Common/DeviceRadio/DeviceRadio.tsx | 117 + .../Action/Common/HttpHeaders/HttpHeaders.tsx | 94 + .../Common/ModalAddAction/ModalAddAction.tsx | 132 + .../MultipleAnalysis/MultipleAnalysis.tsx | 68 + .../Action/Common/TypeRadio/TypeRadio.tsx | 70 + .../Action/Edit/ActionEdit.test.tsx | 9 + .../src/Components/Action/Edit/ActionEdit.tsx | 345 + .../Action/Edit/ActionTab/ActionTab.style.tsx | 48 + .../Action/Edit/ActionTab/ActionTab.tsx | 196 + .../Action/Edit/MoreTab/MoreTab.tsx | 133 + .../Action/Helpers/normalizeType.ts | 36 + .../Action/Helpers/validateOption.ts | 26 + .../src/Components/Action/List/ActionList.tsx | 104 + .../Common/AnalysisPicker/AnalysisPicker.tsx | 74 + .../Common/AutomateTip/AutomateTip.style.ts | 37 + .../Common/AutomateTip/AutomateTip.tsx | 37 + .../ModalAddAnalysis/ModalAddAnalysis.tsx | 106 + .../Common/SaveAndRun/SaveAndRun.style.ts | 14 + .../Analysis/Common/SaveAndRun/SaveAndRun.tsx | 42 + .../Analysis/Edit/AnalysisEdit.test.tsx | 10 + .../Components/Analysis/Edit/AnalysisEdit.tsx | 273 + .../Edit/AnalysisTab/AnalysisTab.style.ts | 45 + .../Analysis/Edit/AnalysisTab/AnalysisTab.tsx | 112 + .../Analysis/Edit/EnvVarsTab/EnvVarsTab.tsx | 104 + .../Analysis/Edit/MoreTab/MoreTab.tsx | 132 + .../Components/Analysis/List/AnalysisList.tsx | 77 + .../BooleanStatus/BooleanStatus.test.tsx | 19 + .../BooleanStatus/BooleanStatus.tsx | 26 + .../DataRetention/DataRetention.style.ts | 88 + .../Common/DataRetention/DataRetention.tsx | 145 + .../ModalEmptyDevice/ModalEmptyDevice.tsx | 54 + .../VariablesTable/VariablesTable.style.ts | 129 + .../Common/VariablesTable/VariablesTable.tsx | 419 + .../Bucket/Edit/BucketEdit.test.tsx | 9 + .../src/Components/Bucket/Edit/BucketEdit.tsx | 206 + .../GeneralInformationTab.tsx | 81 + .../ModalEditGroup/ModalEditGroup.style.tsx | 13 + .../Edit/ModalEditGroup/ModalEditGroup.tsx | 68 + .../ModalEditLocation/ModalEditLocation.tsx | 88 + .../ModalEditMetadata.style.tsx | 9 + .../ModalEditMetadata/ModalEditMetadata.tsx | 75 + .../Edit/ModalEditValue/ModalEditValue.tsx | 108 + .../Bucket/Edit/MoreTab/MoreTab.tsx | 106 + .../Edit/VariablesTab/VariablesTab.style.ts | 11 + .../Bucket/Edit/VariablesTab/VariablesTab.tsx | 91 + .../Bucket/Helpers/joinDataRetention.ts | 12 + .../Bucket/Helpers/separateDataRetention.ts | 27 + .../src/Components/Bucket/List/BucketList.tsx | 65 + .../ButtonDataAmount.style.ts | 23 + .../ButtonDataAmount/ButtonDataAmount.tsx | 62 + .../src/Components/Button/Button.style.ts | 138 + .../src/Components/Button/Button.test.tsx | 41 + .../src/Components/Button/Button.tsx | 53 + .../src/Components/Button/Button.types.ts | 11 + .../Components/Capitalize/Capitalize.style.ts | 5 + .../src/Components/Capitalize/Capitalize.tsx | 18 + .../src/Components/Checkbox/Checkbox.style.ts | 17 + .../src/Components/Checkbox/Checkbox.tsx | 23 + .../src/Components/Col/Col.style.tsx | 73 + .../src/Components/Col/Col.test.tsx | 24 + .../tcore-console/src/Components/Col/Col.tsx | 24 + .../src/Components/Console/Console.style.ts | 35 + .../src/Components/Console/Console.tsx | 89 + .../src/Components/CopyButton/CopyButton.tsx | 63 + .../Device/Common/DeviceInputOutput.tsx | 41 + .../Common/DevicePicker/DevicePicker.tsx | 70 + .../DeviceTypePicker.style.ts | 43 + .../DeviceTypePicker/DeviceTypePicker.tsx | 112 + .../LiveInspector/LiveInspector.style.tsx | 112 + .../Common/LiveInspector/LiveInspector.tsx | 230 + .../LiveInspector/LiveInspector.types.ts | 9 + .../Common/LiveInspector/LiveInspectorRow.tsx | 62 + .../Common/ModalAddDevice/ModalAddDevice.tsx | 124 + .../PayloadParser/PayloadParser.style.ts | 62 + .../Common/PayloadParser/PayloadParser.tsx | 63 + .../Common/TokenTable/TokenTable.style.ts | 39 + .../Device/Common/TokenTable/TokenTable.tsx | 176 + .../ConfigParametersTab.tsx | 147 + .../Device/Edit/DeviceEdit.test.tsx | 10 + .../src/Components/Device/Edit/DeviceEdit.tsx | 437 + .../Edit/EncoderStack/EncoderStack.style.ts | 121 + .../Device/Edit/EncoderStack/EncoderStack.tsx | 216 + .../EncoderStack/ModalAddEncoder.style.tsx | 64 + .../Edit/EncoderStack/ModalAddEncoder.tsx | 87 + .../GeneralInformationTab.tsx | 133 + .../LiveInspectorTab/LiveInspectorTab.tsx | 66 + .../Device/Edit/MoreTab/MoreTab.tsx | 123 + .../Helpers/normalizeConfigParameters.ts | 27 + .../src/Components/Device/List/DeviceList.tsx | 107 + .../src/Components/EditPage/EditPage.style.ts | 14 + .../src/Components/EditPage/EditPage.tsx | 249 + .../EmptyMessage/EmptyMessage.style.ts | 32 + .../Components/EmptyMessage/EmptyMessage.tsx | 28 + .../ErrorMessage/ErrorMessage.style.ts | 11 + .../Components/ErrorMessage/ErrorMessage.tsx | 10 + .../Components/FileSelect/FileSelect.style.ts | 49 + .../src/Components/FileSelect/FileSelect.tsx | 128 + .../src/Components/FlexRow/FlexRow.style.ts | 19 + .../src/Components/FlexRow/FlexRow.test.tsx | 7 + .../src/Components/FlexRow/FlexRow.tsx | 19 + .../src/Components/Footer/Footer.style.tsx | 21 + .../src/Components/Footer/Footer.test.tsx | 12 + .../src/Components/Footer/Footer.tsx | 22 + .../FormDivision/FormDivision.style.ts | 38 + .../FormDivision/FormDivision.test.tsx | 39 + .../Components/FormDivision/FormDivision.tsx | 50 + .../Components/FormGroup/FormGroup.style.ts | 35 + .../Components/FormGroup/FormGroup.test.tsx | 43 + .../src/Components/FormGroup/FormGroup.tsx | 66 + .../Home/ComputerUsage/ComputerUsage.style.ts | 88 + .../Home/ComputerUsage/ComputerUsage.tsx | 80 + .../src/Components/Home/Home.style.ts | 84 + .../src/Components/Home/Home.test.tsx | 32 + .../src/Components/Home/Home.tsx | 146 + .../Components/Home/Network/Network.style.ts | 73 + .../src/Components/Home/Network/Network.tsx | 43 + .../OperatingSystem/OperatingSystem.style.ts | 45 + .../Home/OperatingSystem/OperatingSystem.tsx | 83 + .../Home/RequestChart/RequestChart.style.ts | 31 + .../Home/RequestChart/RequestChart.tsx | 198 + .../Components/Home/Statistics/Statistics.tsx | 105 + .../Components/Home/Summary/Summary.style.ts | 52 + .../src/Components/Home/Summary/Summary.tsx | 62 + .../src/Components/Icon/Icon.style.tsx | 45 + .../src/Components/Icon/Icon.test.tsx | 34 + .../src/Components/Icon/Icon.tsx | 54 + .../src/Components/Icon/Icon.types.ts | 197 + .../Components/IconRadio/IconRadio.style.ts | 58 + .../Components/IconRadio/IconRadio.test.tsx | 63 + .../src/Components/IconRadio/IconRadio.tsx | 60 + .../Components/IconRadio/IconRadio.types.ts | 32 + .../src/Components/InnerNav/InnerNav.style.ts | 60 + .../src/Components/InnerNav/InnerNav.test.tsx | 36 + .../src/Components/InnerNav/InnerNav.tsx | 67 + .../src/Components/Input/Input.style.ts | 11 + .../src/Components/Input/Input.test.tsx | 44 + .../src/Components/Input/Input.tsx | 30 + .../src/Components/InputList/InputList.tsx | 85 + .../InputRadio/InputRadio.style.tsx | 52 + .../src/Components/InputRadio/InputRadio.tsx | 51 + .../src/Components/Link/Link.style.ts | 22 + .../src/Components/Link/Link.test.tsx | 20 + .../src/Components/Link/Link.tsx | 39 + .../src/Components/ListPage/ListPage.style.ts | 17 + .../src/Components/ListPage/ListPage.tsx | 165 + .../src/Components/Loading/Loading.style.ts | 33 + .../src/Components/Loading/Loading.test.tsx | 7 + .../src/Components/Loading/Loading.tsx | 16 + .../src/Components/Logs/Logs.style.ts | 67 + .../src/Components/Logs/Logs.tsx | 181 + .../Components/MainScreen/MainScreen.style.ts | 20 + .../src/Components/MainScreen/MainScreen.tsx | 37 + .../src/Components/Markdown/Markdown.style.ts | 64 + .../src/Components/Markdown/Markdown.tsx | 54 + .../src/Components/Modal/Modal.style.ts | 91 + .../src/Components/Modal/Modal.tsx | 228 + .../ModalFileSelect/ModalFileSelect.style.ts | 92 + .../ModalFileSelect/ModalFileSelect.tsx | 304 + .../ModalFileSelect/ModalFileSelect.types.ts | 22 + .../ModalListConfiguration.style.ts | 29 + .../ModalListConfiguration.tsx | 96 + .../src/Components/Navbar/Navbar.style.tsx | 87 + .../src/Components/Navbar/Navbar.tsx | 68 + .../src/Components/OptionList/OptionList.tsx | 102 + .../OptionsPicker/OptionsPicker.style.ts | 78 + .../OptionsPicker/OptionsPicker.test.tsx | 53 + .../OptionsPicker/OptionsPicker.tsx | 290 + .../PaginatedTable/PaginatedTable.style.ts | 150 + .../PaginatedTable/PaginatedTable.tsx | 316 + .../PaginatedTable/PaginatedTable.types.ts | 60 + .../Components/Pagination/Pagination.style.ts | 87 + .../src/Components/Pagination/Pagination.tsx | 130 + .../PluginImage/PluginImage.style.ts | 28 + .../Components/PluginImage/PluginImage.tsx | 45 + .../Common/ClassTypes/ClassTypes.style.ts | 58 + .../Plugins/Common/ClassTypes/ClassTypes.tsx | 70 + .../MainInformation/MainInformation.style.ts | 23 + .../MainInformation/MainInformation.tsx | 73 + .../ModalInstallPlugin.style.ts | 112 + .../ModalInstallPlugin/ModalInstallPlugin.tsx | 149 + .../ModalUninstallPlugin.tsx | 102 + .../Common/ModuleSetup/ModuleSetup.style.tsx | 15 + .../Common/ModuleSetup/ModuleSetup.tsx | 136 + .../Common/ModuleStatus/ModuleStatus.style.ts | 77 + .../Common/ModuleStatus/ModuleStatus.tsx | 104 + .../Common/Permissions/Permissions.style.ts | 58 + .../Common/Permissions/Permissions.tsx | 71 + .../Common/Platforms/Platforms.style.ts | 58 + .../Plugins/Common/Platforms/Platforms.tsx | 69 + .../PluginConfigFields.style.ts | 30 + .../PluginConfigFields/PluginConfigFields.tsx | 329 + .../Common/Publisher/Publisher.style.ts | 73 + .../Plugins/Common/Publisher/Publisher.tsx | 109 + .../Common/Resources/Resources.style.ts | 22 + .../Plugins/Common/Resources/Resources.tsx | 54 + .../Plugins/Common/Status/Status.style.ts | 61 + .../Plugins/Common/Status/Status.tsx | 73 + .../Plugins/Edit/Buttons/Buttons.style.ts | 33 + .../Plugins/Edit/Buttons/Buttons.tsx | 104 + .../Plugins/Edit/IFrameTab/IFrameTab.style.ts | 12 + .../Plugins/Edit/IFrameTab/IFrameTab.tsx | 15 + .../Components/Plugins/Edit/PluginEdit.tsx | 259 + .../Edit/SettingsTab/SettingsTab.style.ts | 131 + .../Plugins/Edit/SettingsTab/SettingsTab.tsx | 226 + .../ProgramFieldset/ProgramFieldset.style.tsx | 41 + .../ProgramFieldset/ProgramFieldset.tsx | 74 + .../RelativeDate/RelativeDate.style.ts | 15 + .../RelativeDate/RelativeDate.test.tsx | 60 + .../Components/RelativeDate/RelativeDate.tsx | 63 + .../ResourceLinkField.style.ts | 29 + .../ResourceLinkField/ResourceLinkField.tsx | 34 + .../src/Components/Row/Row.style.tsx | 8 + .../tcore-console/src/Components/Row/Row.tsx | 19 + .../RowManipulator/RowManipulator.style.ts | 52 + .../RowManipulator/RowManipulator.tsx | 83 + .../RowManipulatorTable.style.ts | 58 + .../RowManipulatorTable.tsx | 114 + .../RowManipulatorTable.types.ts | 27 + .../src/Components/Select/Select.style.ts | 9 + .../src/Components/Select/Select.test.tsx | 22 + .../src/Components/Select/Select.tsx | 68 + .../Common/ModalChanges/ModalChanges.tsx | 42 + .../GeneralInformationTab.tsx | 149 + .../Settings/Edit/Settings.style.ts | 5 + .../src/Components/Settings/Edit/Settings.tsx | 152 + .../InstalLocalPluginButton.style.ts | 15 + .../InstalLocalPluginButton.tsx | 74 + .../src/Components/Sidebar/Item.test.tsx | 33 + .../src/Components/Sidebar/Item.tsx | 88 + .../PluginButton/PluginButton.style.ts | 177 + .../Sidebar/PluginButton/PluginButton.tsx | 140 + .../src/Components/Sidebar/Sidebar.style.ts | 129 + .../src/Components/Sidebar/Sidebar.test.tsx | 58 + .../src/Components/Sidebar/Sidebar.tsx | 194 + .../SimpleTable/SimpleTable.style.ts | 108 + .../Components/SimpleTable/SimpleTable.tsx | 151 + .../SimpleTable/SimpleTable.types.ts | 27 + .../Components/Styles/FormControlStyles.ts | 55 + .../src/Components/Styles/GlobalStyles.ts | 74 + .../src/Components/Switch/Switch.style.tsx | 102 + .../src/Components/Switch/Switch.test.tsx | 46 + .../src/Components/Switch/Switch.tsx | 87 + .../src/Components/Switch/Switch.types.ts | 7 + .../src/Components/Tabs/Tabs.style.ts | 81 + .../src/Components/Tabs/Tabs.tsx | 74 + .../src/Components/Tabs/Tabs.types.ts | 6 + .../src/Components/Tags/Tags.test.tsx | 50 + .../src/Components/Tags/Tags.tsx | 103 + .../src/Components/Tags/TagsTab.tsx | 51 + .../src/Components/Tooltip/Tooltip.style.tsx | 85 + .../src/Components/Tooltip/Tooltip.tsx | 99 + .../src/Components/Tooltip/TooltipPopup.tsx | 172 + .../TooltipText/TooltipText.style.ts | 30 + .../Components/TooltipText/TooltipText.tsx | 48 + .../VariableCondition.style.ts | 45 + .../VariableCondition/VariableCondition.tsx | 106 + .../src/Helpers/__mocks__/useApiRequest.ts | 11 + .../src/Helpers/copyToClipboard.ts | 17 + .../tcore-console/src/Helpers/download.ts | 27 + .../src/Helpers/findConfigField.ts | 19 + .../tcore-console/src/Helpers/formatBytes.ts | 16 + .../src/Helpers/formatDataAmount.ts | 21 + .../src/Helpers/getDateTimeObject.ts | 20 + .../src/Helpers/getDeviceTypeName.ts | 14 + .../src/Helpers/isConfigFieldVisible.ts | 82 + .../tcore-console/src/Helpers/isNumber.ts | 11 + .../tcore-console/src/Helpers/localStorage.ts | 82 + .../src/Helpers/normalizeTags.ts | 25 + .../src/Helpers/removeEmptyKeys.ts | 9 + .../src/Helpers/setDocumentTitle.ts | 10 + .../src/Helpers/useApiRequest.ts | 29 + .../tcore-console/src/Helpers/useDarkMode.ts | 29 + .../src/Helpers/useForceUpdate.ts | 11 + .../src/Helpers/validateConfigFields.ts | 64 + .../src/Helpers/validateStringField.ts | 10 + .../src/Helpers/validateStringListField.ts | 15 + .../src/Requests/createAction/createAction.ts | 12 + .../src/Requests/createAnalysis.ts | 14 + .../src/Requests/createDevice.ts | 12 + .../src/Requests/createDeviceToken.ts | 21 + .../src/Requests/deleteAction.ts | 10 + .../src/Requests/deleteAnalysis.ts | 10 + .../src/Requests/deleteBucketVariables.ts | 11 + .../src/Requests/deleteDevice.ts | 10 + .../src/Requests/deleteDeviceData.ts | 11 + .../src/Requests/deleteDeviceToken.ts | 10 + .../src/Requests/disablePlugin.ts | 10 + .../Requests/editAction/editAction.test.ts | 18 + .../src/Requests/editAction/editAction.ts | 10 + .../src/Requests/editAnalysis.ts | 10 + .../tcore-console/src/Requests/editDevice.ts | 10 + .../src/Requests/editDeviceData.ts | 11 + .../src/Requests/editPluginSettings.ts | 10 + .../src/Requests/editSettings.ts | 10 + .../src/Requests/enablePlugin.ts | 10 + .../src/Requests/getActionList.ts | 25 + .../src/Requests/getAnalysisInfo.ts | 13 + .../src/Requests/getAnalysisList.ts | 25 + .../src/Requests/getDeviceData.ts | 34 + .../src/Requests/getDeviceDataAmount.ts | 12 + .../src/Requests/getDeviceInfo.ts | 13 + .../src/Requests/getDeviceList.ts | 25 + .../src/Requests/installPlugin.ts | 11 + .../tcore-console/src/Requests/runAnalysis.ts | 11 + .../src/Requests/setDeviceParams.ts | 13 + .../src/Requests/startPluginModule.ts | 10 + .../src/Requests/stopPluginModule.ts | 10 + .../src/Requests/uninstallPlugin.ts | 10 + packages/tcore-console/src/System/Socket.ts | 17 + packages/tcore-console/src/System/Store.ts | 11 + .../src/System/__mocks__/Socket.ts | 5 + .../tcore-console/src/ThemeUpdateContext.tsx | 10 + packages/tcore-console/src/Validation/Name.ts | 5 + packages/tcore-console/src/Validation/Tags.ts | 5 + .../src/Validation/buildZodError.ts | 25 + packages/tcore-console/src/index.ts | 72 + packages/tcore-console/src/theme.ts | 78 + packages/tcore-console/tsconfig-tsc.json | 31 + packages/tcore-console/tsconfig.json | 25 + packages/tcore-console/types/index.d.ts | 23 + packages/tcore-console/types/styled.d.ts | 62 + packages/tcore-console/utils/setup-jest.tsx | 4 + packages/tcore-console/utils/test-utils.tsx | 44 + packages/tcore-sdk/.eslintignore | 10 + packages/tcore-sdk/.eslintrc.js | 31 + packages/tcore-sdk/.prettierrc | 11 + packages/tcore-sdk/README.md | 1 + packages/tcore-sdk/jest.config.js | 6 + packages/tcore-sdk/package.json | 83 + packages/tcore-sdk/src/Bin/Bin.ts | 226 + .../tcore-sdk/src/Lib/APIBridge/APIBridge.ts | 84 + .../ActionTriggerModule.ts | 28 + .../Lib/ActionTypeModule/ActionTypeModule.ts | 20 + packages/tcore-sdk/src/Lib/Core/Core.test.ts | 279 + packages/tcore-sdk/src/Lib/Core/Core.ts | 285 + .../src/Lib/DatabaseModule/DatabaseModule.ts | 471 + .../Lib/FileSystemModule/FileSystemModule.ts | 26 + packages/tcore-sdk/src/Lib/Helpers/Helpers.ts | 101 + .../PayloadDecoderModule.ts | 20 + .../PayloadEncoderModule.ts | 19 + .../src/Lib/PluginStorage/PluginStorage.ts | 39 + .../src/Lib/ServiceModule/ServiceModule.ts | 13 + .../src/Lib/TCoreModule/TCoreModule.ts | 179 + packages/tcore-sdk/src/Lib/index.ts | 23 + packages/tcore-sdk/src/Shared/ResourceID.ts | 29 + packages/tcore-sdk/src/Types/Action.types.ts | 153 + .../tcore-sdk/src/Types/Analysis.types.ts | 149 + .../src/Types/Common/Common.types.test.ts | 335 + .../src/Types/Common/Common.types.ts | 86 + .../tcore-sdk/src/Types/Common/Icon.types.ts | 106 + .../tcore-sdk/src/Types/Connector.types.ts | 42 + .../DatabaseModule/DatabaseModule.types.ts | 116 + .../src/Types/Device/Device.types.test.ts | 343 + .../src/Types/Device/Device.types.ts | 242 + .../Types/DeviceData/DeviceData.types.test.ts | 561 + .../src/Types/DeviceData/DeviceData.types.ts | 241 + .../tcore-sdk/src/Types/GraphqlAPI.types.ts | 12 + .../tcore-sdk/src/Types/Hardware.types.ts | 38 + packages/tcore-sdk/src/Types/Helpers.ts | 35 + .../src/Types/Helpers/createQueryOrderBy.ts | 23 + .../src/Types/Helpers/parseRelativeDate.ts | 73 + .../src/Types/Helpers/preprocessBoolean.ts | 19 + .../src/Types/Helpers/preprocessNumber.ts | 8 + .../src/Types/Helpers/preprocessObject.ts | 18 + .../src/Types/Helpers/removeNullValues.ts | 14 + .../src/Types/LiveInspector.types.ts | 30 + packages/tcore-sdk/src/Types/Log.types.ts | 27 + packages/tcore-sdk/src/Types/Network.types.ts | 76 + packages/tcore-sdk/src/Types/Plugin.types.ts | 536 + packages/tcore-sdk/src/Types/ResourceID.ts | 29 + .../src/Types/Settings/Settings.types.test.ts | 15 + .../src/Types/Settings/Settings.types.ts | 29 + packages/tcore-sdk/src/Types/Socket.types.ts | 21 + .../tcore-sdk/src/Types/Statistic.types.ts | 18 + packages/tcore-sdk/src/Types/Summary.types.ts | 9 + packages/tcore-sdk/src/Types/Tag.types.ts | 10 + packages/tcore-sdk/src/Types/index.ts | 18 + packages/tcore-sdk/tsconfig.json | 31 + packages/tcore-sdk/types.d.ts | 1 + packages/tcore-sdk/types.js | 1 + packages/tcore-shared/.eslintignore | 10 + packages/tcore-shared/.eslintrc.js | 31 + packages/tcore-shared/.prettierrc | 11 + packages/tcore-shared/README.md | 1 + packages/tcore-shared/jest.config.js | 6 + packages/tcore-shared/package.json | 13 + .../src/Plugin/flattenConfigFields.ts | 33 + packages/tcore-shared/src/System/System.ts | 16 + packages/tcore-shared/src/index.ts | 3 + packages/tcore-shared/tsconfig.json | 31 + 623 files changed, 74908 insertions(+), 1 deletion(-) create mode 100644 .editorconfig create mode 100644 .github/main-screenshot.png create mode 100644 .github/workflows/tests.yml create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100644 data.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 packages/tcore-api/.eslintignore create mode 100644 packages/tcore-api/.eslintrc.js create mode 100644 packages/tcore-api/.prettierrc create mode 100644 packages/tcore-api/jest.config.js create mode 100644 packages/tcore-api/nodemon.json create mode 100644 packages/tcore-api/package.json create mode 100644 packages/tcore-api/src/Controllers/APIController.ts create mode 100644 packages/tcore-api/src/Controllers/Action.ts create mode 100644 packages/tcore-api/src/Controllers/Analysis.ts create mode 100644 packages/tcore-api/src/Controllers/Device/Device.test.ts create mode 100644 packages/tcore-api/src/Controllers/Device/Device.ts create mode 100644 packages/tcore-api/src/Controllers/DeviceData/DeviceData.test.ts create mode 100644 packages/tcore-api/src/Controllers/DeviceData/DeviceData.ts create mode 100644 packages/tcore-api/src/Controllers/File.ts create mode 100644 packages/tcore-api/src/Controllers/Hardware.ts create mode 100644 packages/tcore-api/src/Controllers/Logs.ts create mode 100644 packages/tcore-api/src/Controllers/Plugins.ts create mode 100644 packages/tcore-api/src/Controllers/Settings.ts create mode 100644 packages/tcore-api/src/Controllers/Statistic.ts create mode 100644 packages/tcore-api/src/Controllers/Summary.ts create mode 100644 packages/tcore-api/src/Controllers/System.ts create mode 100644 packages/tcore-api/src/Controllers/Tag.ts create mode 100644 packages/tcore-api/src/Helpers/CPU.ts create mode 100644 packages/tcore-api/src/Helpers/Download.ts create mode 100644 packages/tcore-api/src/Helpers/Files.ts create mode 100644 packages/tcore-api/src/Helpers/Platform.ts create mode 100644 packages/tcore-api/src/Helpers/Tar/Tar.ts create mode 100644 packages/tcore-api/src/Helpers/Yaml.ts create mode 100644 packages/tcore-api/src/Helpers/Zip.ts create mode 100644 packages/tcore-api/src/Helpers/log.ts create mode 100644 packages/tcore-api/src/Helpers/removeNullValues.ts create mode 100644 packages/tcore-api/src/Helpers/shutdown.ts create mode 100644 packages/tcore-api/src/Helpers/splitColon.ts create mode 100644 packages/tcore-api/src/Plugins/Host.ts create mode 100644 packages/tcore-api/src/Plugins/Install.ts create mode 100644 packages/tcore-api/src/Plugins/Module/Module.ts create mode 100644 packages/tcore-api/src/Plugins/Plugin/Plugin.test.ts create mode 100644 packages/tcore-api/src/Plugins/Plugin/Plugin.ts create mode 100644 packages/tcore-api/src/Plugins/PluginID.ts create mode 100644 packages/tcore-api/src/Plugins/PluginPackage.ts create mode 100644 packages/tcore-api/src/Plugins/Uninstall.ts create mode 100644 packages/tcore-api/src/Plugins/Validator/Validator.ts create mode 100644 packages/tcore-api/src/Plugins/Worker/Worker.ts create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin1/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin10/index.js create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin10/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin11/index.js create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin11/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin12/index.js create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin12/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin2/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin3/README.md create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin3/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin4/index.js create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin4/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin5/index.js create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin5/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin6/index.js create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin6/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin7/index.js create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin7/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin8/package.json create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin9/index.js create mode 100644 packages/tcore-api/src/Plugins/__mocks__/plugin9/package.json create mode 100644 packages/tcore-api/src/Plugins/executePluginRequest.ts create mode 100644 packages/tcore-api/src/Plugins/invokeDatabaseFunction.ts create mode 100644 packages/tcore-api/src/Plugins/invokeFilesystemFunction.ts create mode 100644 packages/tcore-api/src/Services/Action.ts create mode 100644 packages/tcore-api/src/Services/Analysis.ts create mode 100644 packages/tcore-api/src/Services/AnalysisCodeExecution.ts create mode 100644 packages/tcore-api/src/Services/Device.ts create mode 100644 packages/tcore-api/src/Services/DeviceData/DeviceData.test.ts create mode 100644 packages/tcore-api/src/Services/DeviceData/DeviceData.ts create mode 100644 packages/tcore-api/src/Services/File.ts create mode 100644 packages/tcore-api/src/Services/FilePicker.ts create mode 100644 packages/tcore-api/src/Services/Hardware.ts create mode 100644 packages/tcore-api/src/Services/LiveInspector.ts create mode 100644 packages/tcore-api/src/Services/Logs.ts create mode 100644 packages/tcore-api/src/Services/PayloadParserCodeExecution.ts create mode 100644 packages/tcore-api/src/Services/Plugins.ts create mode 100644 packages/tcore-api/src/Services/PluginsStorage.ts create mode 100644 packages/tcore-api/src/Services/Settings.ts create mode 100644 packages/tcore-api/src/Services/Statistic.ts create mode 100644 packages/tcore-api/src/Services/Summary.ts create mode 100644 packages/tcore-api/src/Services/System.ts create mode 100644 packages/tcore-api/src/Services/Tag.ts create mode 100644 packages/tcore-api/src/Socket/SocketServer.ts create mode 100644 packages/tcore-api/src/index.ts create mode 100644 packages/tcore-api/src/server.ts create mode 100644 packages/tcore-api/tsconfig.json create mode 100644 packages/tcore-cli/.eslintignore create mode 100644 packages/tcore-cli/.eslintrc.js create mode 100644 packages/tcore-cli/.prettierrc create mode 100644 packages/tcore-cli/jest.config.js create mode 100644 packages/tcore-cli/package.json create mode 100644 packages/tcore-cli/src/Commands/Logs.ts create mode 100644 packages/tcore-cli/src/Commands/Restart.ts create mode 100644 packages/tcore-cli/src/Commands/Start.ts create mode 100644 packages/tcore-cli/src/Commands/Status.ts create mode 100644 packages/tcore-cli/src/Commands/Stop.ts create mode 100644 packages/tcore-cli/src/Helpers/Log.ts create mode 100644 packages/tcore-cli/src/Helpers/PM2.ts create mode 100644 packages/tcore-cli/src/PluginCLI.ts create mode 100644 packages/tcore-cli/src/Scripts/StartPM2Dev.ts create mode 100644 packages/tcore-cli/src/index.ts create mode 100644 packages/tcore-cli/tsconfig.json create mode 100644 packages/tcore-console/.eslintignore create mode 100644 packages/tcore-console/.eslintrc.js create mode 100644 packages/tcore-console/.prettierrc create mode 100644 packages/tcore-console/assets/icons/apple.svg create mode 100644 packages/tcore-console/assets/icons/ban.svg create mode 100644 packages/tcore-console/assets/icons/bars.svg create mode 100644 packages/tcore-console/assets/icons/battery-full.svg create mode 100644 packages/tcore-console/assets/icons/bolt.svg create mode 100644 packages/tcore-console/assets/icons/brush.svg create mode 100644 packages/tcore-console/assets/icons/bucket.svg create mode 100644 packages/tcore-console/assets/icons/bullhorn.svg create mode 100644 packages/tcore-console/assets/icons/caret-down.svg create mode 100644 packages/tcore-console/assets/icons/caret-right.svg create mode 100644 packages/tcore-console/assets/icons/caret-up.svg create mode 100644 packages/tcore-console/assets/icons/certificate.svg create mode 100644 packages/tcore-console/assets/icons/check.svg create mode 100644 packages/tcore-console/assets/icons/chevron-left.svg create mode 100644 packages/tcore-console/assets/icons/chevron-right.svg create mode 100644 packages/tcore-console/assets/icons/circle.svg create mode 100644 packages/tcore-console/assets/icons/clock.svg create mode 100644 packages/tcore-console/assets/icons/cloud.svg create mode 100644 packages/tcore-console/assets/icons/code.svg create mode 100644 packages/tcore-console/assets/icons/cog.svg create mode 100644 packages/tcore-console/assets/icons/comment-dots.svg create mode 100644 packages/tcore-console/assets/icons/connector.svg create mode 100644 packages/tcore-console/assets/icons/copy.svg create mode 100644 packages/tcore-console/assets/icons/cube.svg create mode 100644 packages/tcore-console/assets/icons/cubes.svg create mode 100644 packages/tcore-console/assets/icons/database-double.svg create mode 100644 packages/tcore-console/assets/icons/database.svg create mode 100644 packages/tcore-console/assets/icons/desktop.svg create mode 100644 packages/tcore-console/assets/icons/device-union.svg create mode 100644 packages/tcore-console/assets/icons/device.svg create mode 100644 packages/tcore-console/assets/icons/dice-d20.svg create mode 100644 packages/tcore-console/assets/icons/download.svg create mode 100644 packages/tcore-console/assets/icons/ellipsis-v.svg create mode 100644 packages/tcore-console/assets/icons/envelope.svg create mode 100644 packages/tcore-console/assets/icons/exclamation-circle.svg create mode 100644 packages/tcore-console/assets/icons/exclamation-triangle.svg create mode 100644 packages/tcore-console/assets/icons/external-link-alt.svg create mode 100644 packages/tcore-console/assets/icons/eye.svg create mode 100644 packages/tcore-console/assets/icons/file-alt.svg create mode 100644 packages/tcore-console/assets/icons/file-import.svg create mode 100644 packages/tcore-console/assets/icons/folder.svg create mode 100644 packages/tcore-console/assets/icons/github.svg create mode 100644 packages/tcore-console/assets/icons/globe-americas.svg create mode 100644 packages/tcore-console/assets/icons/globe.svg create mode 100644 packages/tcore-console/assets/icons/grip-horizontal.svg create mode 100644 packages/tcore-console/assets/icons/hashtag.svg create mode 100644 packages/tcore-console/assets/icons/hdd.svg create mode 100644 packages/tcore-console/assets/icons/home.svg create mode 100644 packages/tcore-console/assets/icons/image.svg create mode 100644 packages/tcore-console/assets/icons/io.svg create mode 100644 packages/tcore-console/assets/icons/key.svg create mode 100644 packages/tcore-console/assets/icons/link.svg create mode 100644 packages/tcore-console/assets/icons/linux.svg create mode 100644 packages/tcore-console/assets/icons/list.svg create mode 100644 packages/tcore-console/assets/icons/lock.svg create mode 100644 packages/tcore-console/assets/icons/markdown.svg create mode 100644 packages/tcore-console/assets/icons/memory.svg create mode 100644 packages/tcore-console/assets/icons/microchip.svg create mode 100644 packages/tcore-console/assets/icons/minus.svg create mode 100644 packages/tcore-console/assets/icons/mountain.svg create mode 100644 packages/tcore-console/assets/icons/network-wired.svg create mode 100644 packages/tcore-console/assets/icons/pause.svg create mode 100644 packages/tcore-console/assets/icons/pencil-alt.svg create mode 100644 packages/tcore-console/assets/icons/play.svg create mode 100644 packages/tcore-console/assets/icons/plus-circle.svg create mode 100644 packages/tcore-console/assets/icons/plus.svg create mode 100644 packages/tcore-console/assets/icons/puzzle-piece.svg create mode 100644 packages/tcore-console/assets/icons/question-circle.svg create mode 100644 packages/tcore-console/assets/icons/raspberry-pi.svg create mode 100644 packages/tcore-console/assets/icons/redo.svg create mode 100644 packages/tcore-console/assets/icons/save.svg create mode 100644 packages/tcore-console/assets/icons/scroll.svg create mode 100644 packages/tcore-console/assets/icons/search.svg create mode 100644 packages/tcore-console/assets/icons/shapes.svg create mode 100644 packages/tcore-console/assets/icons/sign-out-alt.svg create mode 100644 packages/tcore-console/assets/icons/snowflake.svg create mode 100644 packages/tcore-console/assets/icons/spinner.svg create mode 100644 packages/tcore-console/assets/icons/star.svg create mode 100644 packages/tcore-console/assets/icons/stopwatch.svg create mode 100644 packages/tcore-console/assets/icons/store.svg create mode 100644 packages/tcore-console/assets/icons/sync-alt.svg create mode 100644 packages/tcore-console/assets/icons/tag.svg create mode 100644 packages/tcore-console/assets/icons/tcore.svg create mode 100644 packages/tcore-console/assets/icons/temperature-high.svg create mode 100644 packages/tcore-console/assets/icons/th-large.svg create mode 100644 packages/tcore-console/assets/icons/times.svg create mode 100644 packages/tcore-console/assets/icons/trash-alt.svg create mode 100644 packages/tcore-console/assets/icons/user-alt.svg create mode 100644 packages/tcore-console/assets/icons/wifi.svg create mode 100644 packages/tcore-console/assets/icons/window-maximize.svg create mode 100644 packages/tcore-console/assets/icons/windows.svg create mode 100644 packages/tcore-console/assets/images/favicon.png create mode 100644 packages/tcore-console/assets/images/logo-black.svg create mode 100644 packages/tcore-console/assets/images/logo-white.svg create mode 100644 packages/tcore-console/assets/images/retention.gif create mode 100644 packages/tcore-console/esbuild/build.js create mode 100644 packages/tcore-console/esbuild/buildPath.js create mode 100644 packages/tcore-console/esbuild/generateIndex.js create mode 100644 packages/tcore-console/esbuild/icon.js create mode 100644 packages/tcore-console/esbuild/svgr.js create mode 100644 packages/tcore-console/index.d.ts create mode 100644 packages/tcore-console/jest.config.js create mode 100644 packages/tcore-console/package.json create mode 100644 packages/tcore-console/react-shim.js create mode 100644 packages/tcore-console/src/App.tsx create mode 100644 packages/tcore-console/src/Components/Accordion/Accordion.style.ts create mode 100644 packages/tcore-console/src/Components/Accordion/Accordion.test.tsx create mode 100644 packages/tcore-console/src/Components/Accordion/Accordion.tsx create mode 100644 packages/tcore-console/src/Components/Action/Common/ActionFields/ActionFields.tsx create mode 100644 packages/tcore-console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.style.ts create mode 100644 packages/tcore-console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.tsx create mode 100644 packages/tcore-console/src/Components/Action/Common/DeviceRadio/DeviceRadio.style.tsx create mode 100644 packages/tcore-console/src/Components/Action/Common/DeviceRadio/DeviceRadio.tsx create mode 100644 packages/tcore-console/src/Components/Action/Common/HttpHeaders/HttpHeaders.tsx create mode 100644 packages/tcore-console/src/Components/Action/Common/ModalAddAction/ModalAddAction.tsx create mode 100644 packages/tcore-console/src/Components/Action/Common/MultipleAnalysis/MultipleAnalysis.tsx create mode 100644 packages/tcore-console/src/Components/Action/Common/TypeRadio/TypeRadio.tsx create mode 100644 packages/tcore-console/src/Components/Action/Edit/ActionEdit.test.tsx create mode 100644 packages/tcore-console/src/Components/Action/Edit/ActionEdit.tsx create mode 100644 packages/tcore-console/src/Components/Action/Edit/ActionTab/ActionTab.style.tsx create mode 100644 packages/tcore-console/src/Components/Action/Edit/ActionTab/ActionTab.tsx create mode 100644 packages/tcore-console/src/Components/Action/Edit/MoreTab/MoreTab.tsx create mode 100644 packages/tcore-console/src/Components/Action/Helpers/normalizeType.ts create mode 100644 packages/tcore-console/src/Components/Action/Helpers/validateOption.ts create mode 100644 packages/tcore-console/src/Components/Action/List/ActionList.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/Common/AnalysisPicker/AnalysisPicker.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/Common/AutomateTip/AutomateTip.style.ts create mode 100644 packages/tcore-console/src/Components/Analysis/Common/AutomateTip/AutomateTip.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/Common/ModalAddAnalysis/ModalAddAnalysis.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/Common/SaveAndRun/SaveAndRun.style.ts create mode 100644 packages/tcore-console/src/Components/Analysis/Common/SaveAndRun/SaveAndRun.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/Edit/AnalysisEdit.test.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/Edit/AnalysisEdit.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/Edit/AnalysisTab/AnalysisTab.style.ts create mode 100644 packages/tcore-console/src/Components/Analysis/Edit/AnalysisTab/AnalysisTab.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/Edit/EnvVarsTab/EnvVarsTab.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/Edit/MoreTab/MoreTab.tsx create mode 100644 packages/tcore-console/src/Components/Analysis/List/AnalysisList.tsx create mode 100644 packages/tcore-console/src/Components/BooleanStatus/BooleanStatus.test.tsx create mode 100644 packages/tcore-console/src/Components/BooleanStatus/BooleanStatus.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Common/DataRetention/DataRetention.style.ts create mode 100644 packages/tcore-console/src/Components/Bucket/Common/DataRetention/DataRetention.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Common/ModalEmptyDevice/ModalEmptyDevice.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Common/VariablesTable/VariablesTable.style.ts create mode 100644 packages/tcore-console/src/Components/Bucket/Common/VariablesTable/VariablesTable.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/BucketEdit.test.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/BucketEdit.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/GeneralInformationTab/GeneralInformationTab.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/ModalEditGroup/ModalEditGroup.style.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/ModalEditGroup/ModalEditGroup.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/ModalEditLocation/ModalEditLocation.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/ModalEditMetadata/ModalEditMetadata.style.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/ModalEditMetadata/ModalEditMetadata.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/ModalEditValue/ModalEditValue.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/MoreTab/MoreTab.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/VariablesTab/VariablesTab.style.ts create mode 100644 packages/tcore-console/src/Components/Bucket/Edit/VariablesTab/VariablesTab.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/Helpers/joinDataRetention.ts create mode 100644 packages/tcore-console/src/Components/Bucket/Helpers/separateDataRetention.ts create mode 100644 packages/tcore-console/src/Components/Bucket/List/BucketList.tsx create mode 100644 packages/tcore-console/src/Components/Bucket/List/ButtonDataAmount/ButtonDataAmount.style.ts create mode 100644 packages/tcore-console/src/Components/Bucket/List/ButtonDataAmount/ButtonDataAmount.tsx create mode 100644 packages/tcore-console/src/Components/Button/Button.style.ts create mode 100644 packages/tcore-console/src/Components/Button/Button.test.tsx create mode 100644 packages/tcore-console/src/Components/Button/Button.tsx create mode 100644 packages/tcore-console/src/Components/Button/Button.types.ts create mode 100644 packages/tcore-console/src/Components/Capitalize/Capitalize.style.ts create mode 100644 packages/tcore-console/src/Components/Capitalize/Capitalize.tsx create mode 100644 packages/tcore-console/src/Components/Checkbox/Checkbox.style.ts create mode 100644 packages/tcore-console/src/Components/Checkbox/Checkbox.tsx create mode 100644 packages/tcore-console/src/Components/Col/Col.style.tsx create mode 100644 packages/tcore-console/src/Components/Col/Col.test.tsx create mode 100644 packages/tcore-console/src/Components/Col/Col.tsx create mode 100644 packages/tcore-console/src/Components/Console/Console.style.ts create mode 100644 packages/tcore-console/src/Components/Console/Console.tsx create mode 100644 packages/tcore-console/src/Components/CopyButton/CopyButton.tsx create mode 100644 packages/tcore-console/src/Components/Device/Common/DeviceInputOutput.tsx create mode 100644 packages/tcore-console/src/Components/Device/Common/DevicePicker/DevicePicker.tsx create mode 100644 packages/tcore-console/src/Components/Device/Common/DeviceTypePicker/DeviceTypePicker.style.ts create mode 100644 packages/tcore-console/src/Components/Device/Common/DeviceTypePicker/DeviceTypePicker.tsx create mode 100644 packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.style.tsx create mode 100644 packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.tsx create mode 100644 packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.types.ts create mode 100644 packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspectorRow.tsx create mode 100644 packages/tcore-console/src/Components/Device/Common/ModalAddDevice/ModalAddDevice.tsx create mode 100644 packages/tcore-console/src/Components/Device/Common/PayloadParser/PayloadParser.style.ts create mode 100644 packages/tcore-console/src/Components/Device/Common/PayloadParser/PayloadParser.tsx create mode 100644 packages/tcore-console/src/Components/Device/Common/TokenTable/TokenTable.style.ts create mode 100644 packages/tcore-console/src/Components/Device/Common/TokenTable/TokenTable.tsx create mode 100644 packages/tcore-console/src/Components/Device/Edit/ConfigParametersTab/ConfigParametersTab.tsx create mode 100644 packages/tcore-console/src/Components/Device/Edit/DeviceEdit.test.tsx create mode 100644 packages/tcore-console/src/Components/Device/Edit/DeviceEdit.tsx create mode 100644 packages/tcore-console/src/Components/Device/Edit/EncoderStack/EncoderStack.style.ts create mode 100644 packages/tcore-console/src/Components/Device/Edit/EncoderStack/EncoderStack.tsx create mode 100644 packages/tcore-console/src/Components/Device/Edit/EncoderStack/ModalAddEncoder.style.tsx create mode 100644 packages/tcore-console/src/Components/Device/Edit/EncoderStack/ModalAddEncoder.tsx create mode 100644 packages/tcore-console/src/Components/Device/Edit/GeneralInformationTab/GeneralInformationTab.tsx create mode 100644 packages/tcore-console/src/Components/Device/Edit/LiveInspectorTab/LiveInspectorTab.tsx create mode 100644 packages/tcore-console/src/Components/Device/Edit/MoreTab/MoreTab.tsx create mode 100644 packages/tcore-console/src/Components/Device/Helpers/normalizeConfigParameters.ts create mode 100644 packages/tcore-console/src/Components/Device/List/DeviceList.tsx create mode 100644 packages/tcore-console/src/Components/EditPage/EditPage.style.ts create mode 100644 packages/tcore-console/src/Components/EditPage/EditPage.tsx create mode 100644 packages/tcore-console/src/Components/EmptyMessage/EmptyMessage.style.ts create mode 100644 packages/tcore-console/src/Components/EmptyMessage/EmptyMessage.tsx create mode 100644 packages/tcore-console/src/Components/ErrorMessage/ErrorMessage.style.ts create mode 100644 packages/tcore-console/src/Components/ErrorMessage/ErrorMessage.tsx create mode 100644 packages/tcore-console/src/Components/FileSelect/FileSelect.style.ts create mode 100644 packages/tcore-console/src/Components/FileSelect/FileSelect.tsx create mode 100644 packages/tcore-console/src/Components/FlexRow/FlexRow.style.ts create mode 100644 packages/tcore-console/src/Components/FlexRow/FlexRow.test.tsx create mode 100644 packages/tcore-console/src/Components/FlexRow/FlexRow.tsx create mode 100644 packages/tcore-console/src/Components/Footer/Footer.style.tsx create mode 100644 packages/tcore-console/src/Components/Footer/Footer.test.tsx create mode 100644 packages/tcore-console/src/Components/Footer/Footer.tsx create mode 100644 packages/tcore-console/src/Components/FormDivision/FormDivision.style.ts create mode 100644 packages/tcore-console/src/Components/FormDivision/FormDivision.test.tsx create mode 100644 packages/tcore-console/src/Components/FormDivision/FormDivision.tsx create mode 100644 packages/tcore-console/src/Components/FormGroup/FormGroup.style.ts create mode 100644 packages/tcore-console/src/Components/FormGroup/FormGroup.test.tsx create mode 100644 packages/tcore-console/src/Components/FormGroup/FormGroup.tsx create mode 100644 packages/tcore-console/src/Components/Home/ComputerUsage/ComputerUsage.style.ts create mode 100644 packages/tcore-console/src/Components/Home/ComputerUsage/ComputerUsage.tsx create mode 100644 packages/tcore-console/src/Components/Home/Home.style.ts create mode 100644 packages/tcore-console/src/Components/Home/Home.test.tsx create mode 100644 packages/tcore-console/src/Components/Home/Home.tsx create mode 100644 packages/tcore-console/src/Components/Home/Network/Network.style.ts create mode 100644 packages/tcore-console/src/Components/Home/Network/Network.tsx create mode 100644 packages/tcore-console/src/Components/Home/OperatingSystem/OperatingSystem.style.ts create mode 100644 packages/tcore-console/src/Components/Home/OperatingSystem/OperatingSystem.tsx create mode 100644 packages/tcore-console/src/Components/Home/RequestChart/RequestChart.style.ts create mode 100644 packages/tcore-console/src/Components/Home/RequestChart/RequestChart.tsx create mode 100644 packages/tcore-console/src/Components/Home/Statistics/Statistics.tsx create mode 100644 packages/tcore-console/src/Components/Home/Summary/Summary.style.ts create mode 100644 packages/tcore-console/src/Components/Home/Summary/Summary.tsx create mode 100644 packages/tcore-console/src/Components/Icon/Icon.style.tsx create mode 100644 packages/tcore-console/src/Components/Icon/Icon.test.tsx create mode 100644 packages/tcore-console/src/Components/Icon/Icon.tsx create mode 100644 packages/tcore-console/src/Components/Icon/Icon.types.ts create mode 100644 packages/tcore-console/src/Components/IconRadio/IconRadio.style.ts create mode 100644 packages/tcore-console/src/Components/IconRadio/IconRadio.test.tsx create mode 100644 packages/tcore-console/src/Components/IconRadio/IconRadio.tsx create mode 100644 packages/tcore-console/src/Components/IconRadio/IconRadio.types.ts create mode 100644 packages/tcore-console/src/Components/InnerNav/InnerNav.style.ts create mode 100644 packages/tcore-console/src/Components/InnerNav/InnerNav.test.tsx create mode 100644 packages/tcore-console/src/Components/InnerNav/InnerNav.tsx create mode 100644 packages/tcore-console/src/Components/Input/Input.style.ts create mode 100644 packages/tcore-console/src/Components/Input/Input.test.tsx create mode 100644 packages/tcore-console/src/Components/Input/Input.tsx create mode 100644 packages/tcore-console/src/Components/InputList/InputList.tsx create mode 100644 packages/tcore-console/src/Components/InputRadio/InputRadio.style.tsx create mode 100644 packages/tcore-console/src/Components/InputRadio/InputRadio.tsx create mode 100644 packages/tcore-console/src/Components/Link/Link.style.ts create mode 100644 packages/tcore-console/src/Components/Link/Link.test.tsx create mode 100644 packages/tcore-console/src/Components/Link/Link.tsx create mode 100644 packages/tcore-console/src/Components/ListPage/ListPage.style.ts create mode 100644 packages/tcore-console/src/Components/ListPage/ListPage.tsx create mode 100644 packages/tcore-console/src/Components/Loading/Loading.style.ts create mode 100644 packages/tcore-console/src/Components/Loading/Loading.test.tsx create mode 100644 packages/tcore-console/src/Components/Loading/Loading.tsx create mode 100644 packages/tcore-console/src/Components/Logs/Logs.style.ts create mode 100644 packages/tcore-console/src/Components/Logs/Logs.tsx create mode 100644 packages/tcore-console/src/Components/MainScreen/MainScreen.style.ts create mode 100644 packages/tcore-console/src/Components/MainScreen/MainScreen.tsx create mode 100644 packages/tcore-console/src/Components/Markdown/Markdown.style.ts create mode 100644 packages/tcore-console/src/Components/Markdown/Markdown.tsx create mode 100644 packages/tcore-console/src/Components/Modal/Modal.style.ts create mode 100644 packages/tcore-console/src/Components/Modal/Modal.tsx create mode 100644 packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.style.ts create mode 100644 packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.tsx create mode 100644 packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.types.ts create mode 100644 packages/tcore-console/src/Components/ModalListConfiguration/ModalListConfiguration.style.ts create mode 100644 packages/tcore-console/src/Components/ModalListConfiguration/ModalListConfiguration.tsx create mode 100644 packages/tcore-console/src/Components/Navbar/Navbar.style.tsx create mode 100644 packages/tcore-console/src/Components/Navbar/Navbar.tsx create mode 100644 packages/tcore-console/src/Components/OptionList/OptionList.tsx create mode 100644 packages/tcore-console/src/Components/OptionsPicker/OptionsPicker.style.ts create mode 100644 packages/tcore-console/src/Components/OptionsPicker/OptionsPicker.test.tsx create mode 100644 packages/tcore-console/src/Components/OptionsPicker/OptionsPicker.tsx create mode 100644 packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.style.ts create mode 100644 packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.tsx create mode 100644 packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.types.ts create mode 100644 packages/tcore-console/src/Components/Pagination/Pagination.style.ts create mode 100644 packages/tcore-console/src/Components/Pagination/Pagination.tsx create mode 100644 packages/tcore-console/src/Components/PluginImage/PluginImage.style.ts create mode 100644 packages/tcore-console/src/Components/PluginImage/PluginImage.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/ClassTypes/ClassTypes.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/ClassTypes/ClassTypes.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/MainInformation/MainInformation.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/MainInformation/MainInformation.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/ModalUninstallPlugin/ModalUninstallPlugin.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/ModuleSetup/ModuleSetup.style.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/ModuleSetup/ModuleSetup.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/ModuleStatus/ModuleStatus.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/ModuleStatus/ModuleStatus.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Permissions/Permissions.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Permissions/Permissions.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Platforms/Platforms.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Platforms/Platforms.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/PluginConfigFields/PluginConfigFields.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/PluginConfigFields/PluginConfigFields.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Publisher/Publisher.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Publisher/Publisher.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Resources/Resources.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Resources/Resources.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Status/Status.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Common/Status/Status.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Edit/Buttons/Buttons.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Edit/Buttons/Buttons.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Edit/IFrameTab/IFrameTab.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Edit/IFrameTab/IFrameTab.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Edit/PluginEdit.tsx create mode 100644 packages/tcore-console/src/Components/Plugins/Edit/SettingsTab/SettingsTab.style.ts create mode 100644 packages/tcore-console/src/Components/Plugins/Edit/SettingsTab/SettingsTab.tsx create mode 100644 packages/tcore-console/src/Components/ProgramFieldset/ProgramFieldset.style.tsx create mode 100644 packages/tcore-console/src/Components/ProgramFieldset/ProgramFieldset.tsx create mode 100644 packages/tcore-console/src/Components/RelativeDate/RelativeDate.style.ts create mode 100644 packages/tcore-console/src/Components/RelativeDate/RelativeDate.test.tsx create mode 100644 packages/tcore-console/src/Components/RelativeDate/RelativeDate.tsx create mode 100644 packages/tcore-console/src/Components/ResourceLinkField/ResourceLinkField.style.ts create mode 100644 packages/tcore-console/src/Components/ResourceLinkField/ResourceLinkField.tsx create mode 100644 packages/tcore-console/src/Components/Row/Row.style.tsx create mode 100644 packages/tcore-console/src/Components/Row/Row.tsx create mode 100644 packages/tcore-console/src/Components/RowManipulator/RowManipulator.style.ts create mode 100644 packages/tcore-console/src/Components/RowManipulator/RowManipulator.tsx create mode 100644 packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.style.ts create mode 100644 packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.tsx create mode 100644 packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.types.ts create mode 100644 packages/tcore-console/src/Components/Select/Select.style.ts create mode 100644 packages/tcore-console/src/Components/Select/Select.test.tsx create mode 100644 packages/tcore-console/src/Components/Select/Select.tsx create mode 100644 packages/tcore-console/src/Components/Settings/Common/ModalChanges/ModalChanges.tsx create mode 100644 packages/tcore-console/src/Components/Settings/Edit/GeneralInformationTab/GeneralInformationTab.tsx create mode 100644 packages/tcore-console/src/Components/Settings/Edit/Settings.style.ts create mode 100644 packages/tcore-console/src/Components/Settings/Edit/Settings.tsx create mode 100644 packages/tcore-console/src/Components/Sidebar/InstalLocalPluginButton/InstalLocalPluginButton.style.ts create mode 100644 packages/tcore-console/src/Components/Sidebar/InstalLocalPluginButton/InstalLocalPluginButton.tsx create mode 100644 packages/tcore-console/src/Components/Sidebar/Item.test.tsx create mode 100644 packages/tcore-console/src/Components/Sidebar/Item.tsx create mode 100644 packages/tcore-console/src/Components/Sidebar/PluginButton/PluginButton.style.ts create mode 100644 packages/tcore-console/src/Components/Sidebar/PluginButton/PluginButton.tsx create mode 100644 packages/tcore-console/src/Components/Sidebar/Sidebar.style.ts create mode 100644 packages/tcore-console/src/Components/Sidebar/Sidebar.test.tsx create mode 100644 packages/tcore-console/src/Components/Sidebar/Sidebar.tsx create mode 100644 packages/tcore-console/src/Components/SimpleTable/SimpleTable.style.ts create mode 100644 packages/tcore-console/src/Components/SimpleTable/SimpleTable.tsx create mode 100644 packages/tcore-console/src/Components/SimpleTable/SimpleTable.types.ts create mode 100644 packages/tcore-console/src/Components/Styles/FormControlStyles.ts create mode 100644 packages/tcore-console/src/Components/Styles/GlobalStyles.ts create mode 100644 packages/tcore-console/src/Components/Switch/Switch.style.tsx create mode 100644 packages/tcore-console/src/Components/Switch/Switch.test.tsx create mode 100644 packages/tcore-console/src/Components/Switch/Switch.tsx create mode 100644 packages/tcore-console/src/Components/Switch/Switch.types.ts create mode 100644 packages/tcore-console/src/Components/Tabs/Tabs.style.ts create mode 100644 packages/tcore-console/src/Components/Tabs/Tabs.tsx create mode 100644 packages/tcore-console/src/Components/Tabs/Tabs.types.ts create mode 100644 packages/tcore-console/src/Components/Tags/Tags.test.tsx create mode 100644 packages/tcore-console/src/Components/Tags/Tags.tsx create mode 100644 packages/tcore-console/src/Components/Tags/TagsTab.tsx create mode 100644 packages/tcore-console/src/Components/Tooltip/Tooltip.style.tsx create mode 100644 packages/tcore-console/src/Components/Tooltip/Tooltip.tsx create mode 100644 packages/tcore-console/src/Components/Tooltip/TooltipPopup.tsx create mode 100644 packages/tcore-console/src/Components/TooltipText/TooltipText.style.ts create mode 100644 packages/tcore-console/src/Components/TooltipText/TooltipText.tsx create mode 100644 packages/tcore-console/src/Components/VariableCondition/VariableCondition.style.ts create mode 100644 packages/tcore-console/src/Components/VariableCondition/VariableCondition.tsx create mode 100644 packages/tcore-console/src/Helpers/__mocks__/useApiRequest.ts create mode 100644 packages/tcore-console/src/Helpers/copyToClipboard.ts create mode 100644 packages/tcore-console/src/Helpers/download.ts create mode 100644 packages/tcore-console/src/Helpers/findConfigField.ts create mode 100644 packages/tcore-console/src/Helpers/formatBytes.ts create mode 100644 packages/tcore-console/src/Helpers/formatDataAmount.ts create mode 100644 packages/tcore-console/src/Helpers/getDateTimeObject.ts create mode 100644 packages/tcore-console/src/Helpers/getDeviceTypeName.ts create mode 100644 packages/tcore-console/src/Helpers/isConfigFieldVisible.ts create mode 100644 packages/tcore-console/src/Helpers/isNumber.ts create mode 100644 packages/tcore-console/src/Helpers/localStorage.ts create mode 100644 packages/tcore-console/src/Helpers/normalizeTags.ts create mode 100644 packages/tcore-console/src/Helpers/removeEmptyKeys.ts create mode 100644 packages/tcore-console/src/Helpers/setDocumentTitle.ts create mode 100644 packages/tcore-console/src/Helpers/useApiRequest.ts create mode 100644 packages/tcore-console/src/Helpers/useDarkMode.ts create mode 100644 packages/tcore-console/src/Helpers/useForceUpdate.ts create mode 100644 packages/tcore-console/src/Helpers/validateConfigFields.ts create mode 100644 packages/tcore-console/src/Helpers/validateStringField.ts create mode 100644 packages/tcore-console/src/Helpers/validateStringListField.ts create mode 100644 packages/tcore-console/src/Requests/createAction/createAction.ts create mode 100644 packages/tcore-console/src/Requests/createAnalysis.ts create mode 100644 packages/tcore-console/src/Requests/createDevice.ts create mode 100644 packages/tcore-console/src/Requests/createDeviceToken.ts create mode 100644 packages/tcore-console/src/Requests/deleteAction.ts create mode 100644 packages/tcore-console/src/Requests/deleteAnalysis.ts create mode 100644 packages/tcore-console/src/Requests/deleteBucketVariables.ts create mode 100644 packages/tcore-console/src/Requests/deleteDevice.ts create mode 100644 packages/tcore-console/src/Requests/deleteDeviceData.ts create mode 100644 packages/tcore-console/src/Requests/deleteDeviceToken.ts create mode 100644 packages/tcore-console/src/Requests/disablePlugin.ts create mode 100644 packages/tcore-console/src/Requests/editAction/editAction.test.ts create mode 100644 packages/tcore-console/src/Requests/editAction/editAction.ts create mode 100644 packages/tcore-console/src/Requests/editAnalysis.ts create mode 100644 packages/tcore-console/src/Requests/editDevice.ts create mode 100644 packages/tcore-console/src/Requests/editDeviceData.ts create mode 100644 packages/tcore-console/src/Requests/editPluginSettings.ts create mode 100644 packages/tcore-console/src/Requests/editSettings.ts create mode 100644 packages/tcore-console/src/Requests/enablePlugin.ts create mode 100644 packages/tcore-console/src/Requests/getActionList.ts create mode 100644 packages/tcore-console/src/Requests/getAnalysisInfo.ts create mode 100644 packages/tcore-console/src/Requests/getAnalysisList.ts create mode 100644 packages/tcore-console/src/Requests/getDeviceData.ts create mode 100644 packages/tcore-console/src/Requests/getDeviceDataAmount.ts create mode 100644 packages/tcore-console/src/Requests/getDeviceInfo.ts create mode 100644 packages/tcore-console/src/Requests/getDeviceList.ts create mode 100644 packages/tcore-console/src/Requests/installPlugin.ts create mode 100644 packages/tcore-console/src/Requests/runAnalysis.ts create mode 100644 packages/tcore-console/src/Requests/setDeviceParams.ts create mode 100644 packages/tcore-console/src/Requests/startPluginModule.ts create mode 100644 packages/tcore-console/src/Requests/stopPluginModule.ts create mode 100644 packages/tcore-console/src/Requests/uninstallPlugin.ts create mode 100644 packages/tcore-console/src/System/Socket.ts create mode 100644 packages/tcore-console/src/System/Store.ts create mode 100644 packages/tcore-console/src/System/__mocks__/Socket.ts create mode 100644 packages/tcore-console/src/ThemeUpdateContext.tsx create mode 100644 packages/tcore-console/src/Validation/Name.ts create mode 100644 packages/tcore-console/src/Validation/Tags.ts create mode 100644 packages/tcore-console/src/Validation/buildZodError.ts create mode 100644 packages/tcore-console/src/index.ts create mode 100644 packages/tcore-console/src/theme.ts create mode 100644 packages/tcore-console/tsconfig-tsc.json create mode 100644 packages/tcore-console/tsconfig.json create mode 100644 packages/tcore-console/types/index.d.ts create mode 100644 packages/tcore-console/types/styled.d.ts create mode 100644 packages/tcore-console/utils/setup-jest.tsx create mode 100644 packages/tcore-console/utils/test-utils.tsx create mode 100644 packages/tcore-sdk/.eslintignore create mode 100644 packages/tcore-sdk/.eslintrc.js create mode 100644 packages/tcore-sdk/.prettierrc create mode 100644 packages/tcore-sdk/README.md create mode 100644 packages/tcore-sdk/jest.config.js create mode 100644 packages/tcore-sdk/package.json create mode 100644 packages/tcore-sdk/src/Bin/Bin.ts create mode 100644 packages/tcore-sdk/src/Lib/APIBridge/APIBridge.ts create mode 100644 packages/tcore-sdk/src/Lib/ActionTriggerModule/ActionTriggerModule.ts create mode 100644 packages/tcore-sdk/src/Lib/ActionTypeModule/ActionTypeModule.ts create mode 100644 packages/tcore-sdk/src/Lib/Core/Core.test.ts create mode 100644 packages/tcore-sdk/src/Lib/Core/Core.ts create mode 100644 packages/tcore-sdk/src/Lib/DatabaseModule/DatabaseModule.ts create mode 100644 packages/tcore-sdk/src/Lib/FileSystemModule/FileSystemModule.ts create mode 100644 packages/tcore-sdk/src/Lib/Helpers/Helpers.ts create mode 100644 packages/tcore-sdk/src/Lib/PayloadDecoderModule/PayloadDecoderModule.ts create mode 100644 packages/tcore-sdk/src/Lib/PayloadEncoderModule/PayloadEncoderModule.ts create mode 100644 packages/tcore-sdk/src/Lib/PluginStorage/PluginStorage.ts create mode 100644 packages/tcore-sdk/src/Lib/ServiceModule/ServiceModule.ts create mode 100644 packages/tcore-sdk/src/Lib/TCoreModule/TCoreModule.ts create mode 100644 packages/tcore-sdk/src/Lib/index.ts create mode 100644 packages/tcore-sdk/src/Shared/ResourceID.ts create mode 100644 packages/tcore-sdk/src/Types/Action.types.ts create mode 100644 packages/tcore-sdk/src/Types/Analysis.types.ts create mode 100644 packages/tcore-sdk/src/Types/Common/Common.types.test.ts create mode 100644 packages/tcore-sdk/src/Types/Common/Common.types.ts create mode 100644 packages/tcore-sdk/src/Types/Common/Icon.types.ts create mode 100644 packages/tcore-sdk/src/Types/Connector.types.ts create mode 100644 packages/tcore-sdk/src/Types/DatabaseModule/DatabaseModule.types.ts create mode 100644 packages/tcore-sdk/src/Types/Device/Device.types.test.ts create mode 100644 packages/tcore-sdk/src/Types/Device/Device.types.ts create mode 100644 packages/tcore-sdk/src/Types/DeviceData/DeviceData.types.test.ts create mode 100644 packages/tcore-sdk/src/Types/DeviceData/DeviceData.types.ts create mode 100644 packages/tcore-sdk/src/Types/GraphqlAPI.types.ts create mode 100644 packages/tcore-sdk/src/Types/Hardware.types.ts create mode 100644 packages/tcore-sdk/src/Types/Helpers.ts create mode 100644 packages/tcore-sdk/src/Types/Helpers/createQueryOrderBy.ts create mode 100644 packages/tcore-sdk/src/Types/Helpers/parseRelativeDate.ts create mode 100644 packages/tcore-sdk/src/Types/Helpers/preprocessBoolean.ts create mode 100644 packages/tcore-sdk/src/Types/Helpers/preprocessNumber.ts create mode 100644 packages/tcore-sdk/src/Types/Helpers/preprocessObject.ts create mode 100644 packages/tcore-sdk/src/Types/Helpers/removeNullValues.ts create mode 100644 packages/tcore-sdk/src/Types/LiveInspector.types.ts create mode 100644 packages/tcore-sdk/src/Types/Log.types.ts create mode 100644 packages/tcore-sdk/src/Types/Network.types.ts create mode 100644 packages/tcore-sdk/src/Types/Plugin.types.ts create mode 100644 packages/tcore-sdk/src/Types/ResourceID.ts create mode 100644 packages/tcore-sdk/src/Types/Settings/Settings.types.test.ts create mode 100644 packages/tcore-sdk/src/Types/Settings/Settings.types.ts create mode 100644 packages/tcore-sdk/src/Types/Socket.types.ts create mode 100644 packages/tcore-sdk/src/Types/Statistic.types.ts create mode 100644 packages/tcore-sdk/src/Types/Summary.types.ts create mode 100644 packages/tcore-sdk/src/Types/Tag.types.ts create mode 100644 packages/tcore-sdk/src/Types/index.ts create mode 100644 packages/tcore-sdk/tsconfig.json create mode 100644 packages/tcore-sdk/types.d.ts create mode 100644 packages/tcore-sdk/types.js create mode 100644 packages/tcore-shared/.eslintignore create mode 100644 packages/tcore-shared/.eslintrc.js create mode 100644 packages/tcore-shared/.prettierrc create mode 100644 packages/tcore-shared/README.md create mode 100644 packages/tcore-shared/jest.config.js create mode 100644 packages/tcore-shared/package.json create mode 100644 packages/tcore-shared/src/Plugin/flattenConfigFields.ts create mode 100644 packages/tcore-shared/src/System/System.ts create mode 100644 packages/tcore-shared/src/index.ts create mode 100644 packages/tcore-shared/tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..5760be58 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/main-screenshot.png b/.github/main-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..317e5a69803b9cb730011c405828dd69211381d8 GIT binary patch literal 303840 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 gs{D|30^&^rz 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 + TagoCore in action +

+ +[TagoCore](https://tagocore.com) is a distribution of the `TCore - OSS` repository with TagoIO-specific customizations released under a copyright license of [TagoIO](https://tago.io). + +[TagoCore](https://tagocore.com) is a free, fast, and open-source IoT platform for edge computing that you can use to parse, and analyze the data from your devices! + +TagoCore is updated monthly with new features and bug fixes. You can download it for Windows, macOS, and Linux on [TagoCore's website](https://tagocore.com/#download). + +## Contributing + +There are many ways in which you can participate in this project, for example: + +* [Submit bugs and feature requests](https://github.com/tago-io/tcore/issues), and help us verify as they are checked in +* Review [source code changes](https://github.com/tago-io/tcore/pulls) + +## Feedback + +* Ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/tcore) +* Upvote [popular feature requests](https://github.com/tago-io/tcore/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) +* [File an issue](https://github.com/tago-io/tcore/issues) + +## License + +Copyright (c) Tago LLC. All rights reserved. + +Licensed under the [MIT](LICENSE) license. diff --git a/data.json b/data.json new file mode 100644 index 00000000..53b1a57e --- /dev/null +++ b/data.json @@ -0,0 +1,4 @@ +{ + "slug": "tcore", + "name": "TCore" +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..57d98c56 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,38360 @@ +{ + "name": "@tago-io/tcore", + "version": "0.3.3", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@tago-io/tcore", + "version": "0.3.3", + "license": "MIT", + "workspaces": [ + "packages/tcore-sdk", + "packages/tcore-shared", + "packages/tcore-console", + "packages/tcore-api", + "packages/tcore-cli" + ], + "dependencies": { + "js-yaml": "4.1.0" + }, + "bin": { + "tcore": "packages/tcore-cli/build/index.js" + }, + "devDependencies": { + "@commitlint/cli": "15.0.0", + "@commitlint/config-conventional": "15.0.0", + "@types/js-yaml": "4.0.3", + "aws-sdk": "2.1087.0", + "axios": "0.24.0", + "chalk": "4.1.2", + "concurrently": "7.1.0", + "husky": "7.0.4", + "lerna": "^4.0.0", + "luxon": "2.3.1", + "npm-run-all": "4.1.5", + "ora": "5.4.1", + "typescript": "4.4.3" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@antv/adjust": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.2.5.tgz", + "integrity": "sha512-MfWZOkD9CqXRES6MBGRNe27Q577a72EIwyMnE29wIlPliFvJfWwsrONddpGU7lilMpVKecS3WAzOoip3RfPTRQ==", + "dependencies": { + "@antv/util": "~2.0.0", + "tslib": "^1.10.0" + } + }, + "node_modules/@antv/adjust/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@antv/attr": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.3.3.tgz", + "integrity": "sha512-7iSSRhYzZ7pYXZKTL1ECGhTdKVHPQx1Vj7yYVTAiyLMsWsLUAoMf0m6dT6msTs0SdrXHRbjzXavVXxRj/wZZJA==", + "dependencies": { + "@antv/color-util": "^2.0.1", + "@antv/util": "~2.0.0", + "tslib": "^1.10.0" + } + }, + "node_modules/@antv/attr/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@antv/color-util": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@antv/color-util/-/color-util-2.0.6.tgz", + "integrity": "sha512-KnPEaAH+XNJMjax9U35W67nzPI+QQ2x27pYlzmSIWrbj4/k8PGrARXfzDTjwoozHJY8qG62Z+Ww6Alhu2FctXQ==", + "dependencies": { + "@antv/util": "^2.0.9", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/component": { + "version": "0.8.27", + "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.8.27.tgz", + "integrity": "sha512-FY9fgUBjEuWxQ4w7VbcMSwFr7pqnRf1/F1ja1weoEpNndKBlStNYWhXTx4p5uMJVLvMpXoFPqan7RzyP8rel6Q==", + "dependencies": { + "@antv/color-util": "^2.0.3", + "@antv/dom-util": "~2.0.1", + "@antv/g-base": "^0.5.9", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "~2.0.7", + "@antv/scale": "~0.3.1", + "@antv/util": "~2.0.0", + "fecha": "~4.2.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/coord": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.3.1.tgz", + "integrity": "sha512-rFE94C8Xzbx4xmZnHh2AnlB3Qm1n5x0VT3OROy257IH6Rm4cuzv1+tZaUBATviwZd99S+rOY9telw/+6C9GbRw==", + "dependencies": { + "@antv/matrix-util": "^3.1.0-beta.2", + "@antv/util": "~2.0.12", + "tslib": "^2.1.0" + } + }, + "node_modules/@antv/dom-util": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@antv/dom-util/-/dom-util-2.0.4.tgz", + "integrity": "sha512-2shXUl504fKwt82T3GkuT4Uoc6p9qjCKnJ8gXGLSW4T1W37dqf9AV28aCfoVPHp2BUXpSsB+PAJX2rG/jLHsLQ==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/event-emitter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@antv/event-emitter/-/event-emitter-0.1.3.tgz", + "integrity": "sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==" + }, + "node_modules/@antv/g-base": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/@antv/g-base/-/g-base-0.5.11.tgz", + "integrity": "sha512-10Hkq7XksVCqxZZrPkd6HTU9tb/+2meCVEMy/edhS4I/sokhcgC9m3fQP5bE8rA3EVKwELE7MJHZ98BEpVFqvQ==", + "dependencies": { + "@antv/event-emitter": "^0.1.1", + "@antv/g-math": "^0.1.6", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "~2.0.5", + "@antv/util": "~2.0.13", + "@types/d3-timer": "^2.0.0", + "d3-ease": "^1.0.5", + "d3-interpolate": "^1.3.2", + "d3-timer": "^1.0.9", + "detect-browser": "^5.1.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g-canvas": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-0.5.12.tgz", + "integrity": "sha512-iJ/muwwqCCNONVlPIzv/7OL5iLguaKRj2BxNMytUO3TWwamM+kHkiyYEOkS0dPn9h/hBsHYlLUluSVz2Fp6/bw==", + "dependencies": { + "@antv/g-base": "^0.5.3", + "@antv/g-math": "^0.1.6", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "~2.0.5", + "@antv/util": "~2.0.0", + "gl-matrix": "^3.0.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g-math": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@antv/g-math/-/g-math-0.1.7.tgz", + "integrity": "sha512-xGyXaloD1ynfp7gS4VuV+MjSptZIwHvLHr8ekXJSFAeWPYLu84yOW2wOZHDdp1bzDAIuRv6xDBW58YGHrWsFcA==", + "dependencies": { + "@antv/util": "~2.0.0", + "gl-matrix": "^3.0.0" + } + }, + "node_modules/@antv/g-svg": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@antv/g-svg/-/g-svg-0.5.6.tgz", + "integrity": "sha512-Xve1EUGk4HMbl2nq4ozR4QLh6GyoZ8Xw/+9kHYI4B5P2lIUQU95MuRsaLFfW5NNpZDx85ZeH97tqEmC9L96E7A==", + "dependencies": { + "@antv/g-base": "^0.5.3", + "@antv/g-math": "^0.1.6", + "@antv/util": "~2.0.0", + "detect-browser": "^5.0.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g2": { + "version": "4.1.23", + "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-4.1.23.tgz", + "integrity": "sha512-xteff5XFXb4pdI/+9qeuKKqk3jnyecoTPX/hnarmHPnAWkyXL0K1wfFSvNPUxqtn+0FMYyL8VNIdIaGUestVOA==", + "dependencies": { + "@antv/adjust": "^0.2.1", + "@antv/attr": "^0.3.1", + "@antv/color-util": "^2.0.2", + "@antv/component": "^0.8.7", + "@antv/coord": "^0.3.0", + "@antv/dom-util": "^2.0.2", + "@antv/event-emitter": "~0.1.0", + "@antv/g-base": "~0.5.6", + "@antv/g-canvas": "~0.5.10", + "@antv/g-svg": "~0.5.6", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "^2.0.3", + "@antv/scale": "^0.3.7", + "@antv/util": "~2.0.5", + "tslib": "^2.0.0" + } + }, + "node_modules/@antv/matrix-util": { + "version": "3.1.0-beta.3", + "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.1.0-beta.3.tgz", + "integrity": "sha512-W2R6Za3A6CmG51Y/4jZUM/tFgYSq7vTqJL1VD9dKrvwxS4sE0ZcXINtkp55CdyBwJ6Cwm8pfoRpnD4FnHahN0A==", + "dependencies": { + "@antv/util": "^2.0.9", + "gl-matrix": "^3.4.3", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/path-util": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", + "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", + "dependencies": { + "@antv/matrix-util": "^3.0.4", + "@antv/util": "^2.0.9", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/path-util/node_modules/@antv/matrix-util": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", + "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", + "dependencies": { + "@antv/util": "^2.0.9", + "gl-matrix": "^3.3.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/scale": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.3.17.tgz", + "integrity": "sha512-YjPYG2Lbhou2cnle4MTlsq45dUVjP5tiGG/pYNIerE1sSBqFnC0/7tf9ZWp5OaHZH/qHNX8IfKeQdWHZDR4kDw==", + "dependencies": { + "@antv/util": "~2.0.3", + "fecha": "~4.2.0", + "tslib": "^2.0.0" + } + }, + "node_modules/@antv/util": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.17.tgz", + "integrity": "sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==", + "dependencies": { + "csstype": "^3.0.8", + "tslib": "^2.0.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz", + "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.9.tgz", + "integrity": "sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.9", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.9", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.9.tgz", + "integrity": "sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==", + "dependencies": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz", + "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", + "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", + "dev": true, + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/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==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/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==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz", + "integrity": "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz", + "integrity": "sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.9.tgz", + "integrity": "sha512-WxYHHUWF2uZ7Hp1K+D1xQgbgkGUfA+5UPOegEXGt2Y5SMog/rYCVaifLZDbw8UkNXozEqqrZTy6bglL7xTaCOw==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.9.tgz", + "integrity": "sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.9", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.9", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, + "dependencies": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" + } + }, + "node_modules/@commitlint/cli": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-15.0.0.tgz", + "integrity": "sha512-Y5xmDCweytqzo4N4lOI2YRiuX35xTjcs8n5hUceBH8eyK0YbwtgWX50BJOH2XbkwEmII9blNhlBog6AdQsqicg==", + "dev": true, + "dependencies": { + "@commitlint/format": "^15.0.0", + "@commitlint/lint": "^15.0.0", + "@commitlint/load": "^15.0.0", + "@commitlint/read": "^15.0.0", + "@commitlint/types": "^15.0.0", + "lodash": "^4.17.19", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-15.0.0.tgz", + "integrity": "sha512-eZBRL8Lk3hMNHp1wUMYj0qrZQEsST1ai7KHR8J1IDD9aHgT7L2giciibuQ+Og7vxVhR5WtYDvh9xirXFVPaSkQ==", + "dev": true, + "dependencies": { + "conventional-changelog-conventionalcommits": "^4.3.1" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/ensure": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-15.0.0.tgz", + "integrity": "sha512-7DV4iNIald3vycwaWBNGk5FbonaNzOlU8nBe5m5AgU2dIeNKuXwLm+zzJzG27j0Ho56rgz//3F6RIvmsoxY9ZA==", + "dev": true, + "dependencies": { + "@commitlint/types": "^15.0.0", + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-15.0.0.tgz", + "integrity": "sha512-pyE4ApxjbWhb1TXz5vRiGwI2ssdMMgZbaaheZq1/7WC0xRnqnIhE1yUC1D2q20qPtvkZPstTYvMiRVtF+DvjUg==", + "dev": true, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/format": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-15.0.0.tgz", + "integrity": "sha512-bPhAfqwRhPk92WiuY0ktEJNpRRHSCd+Eg1MdhGyL9Bl3U25E5zvuInA+dNctnzZiOBSH/37ZaD0eOKCpQE6acg==", + "dev": true, + "dependencies": { + "@commitlint/types": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-15.0.0.tgz", + "integrity": "sha512-edtnkf2QZ/7e/YCJDgn1WDw9wfF1WfOitW5YEoSOb4SxjJEb/oE87kxNPZ2j8mnDMuunspcMfGHeg6fRlwaEWg==", + "dev": true, + "dependencies": { + "@commitlint/types": "^15.0.0", + "semver": "7.3.5" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/lint": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-15.0.0.tgz", + "integrity": "sha512-hUi2+Im/2dJ5FBvWnodypTkg+5haCgsDzB0fyMApWLUA1IucYUAqRCQCW5em1Mhk9Crw1pd5YzFNikhIclkqCw==", + "dev": true, + "dependencies": { + "@commitlint/is-ignored": "^15.0.0", + "@commitlint/parse": "^15.0.0", + "@commitlint/rules": "^15.0.0", + "@commitlint/types": "^15.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/load": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-15.0.0.tgz", + "integrity": "sha512-Ak1YPeOhvxmY3ioe0o6m1yLGvUAYb4BdfGgShU8jiTCmU3Mnmms0Xh/kfQz8AybhezCC3AmVTyBLaBZxOHR8kg==", + "dev": true, + "dependencies": { + "@commitlint/execute-rule": "^15.0.0", + "@commitlint/resolve-extends": "^15.0.0", + "@commitlint/types": "^15.0.0", + "@endemolshinegroup/cosmiconfig-typescript-loader": "^3.0.2", + "chalk": "^4.0.0", + "cosmiconfig": "^7.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0", + "typescript": "^4.4.3" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/message": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-15.0.0.tgz", + "integrity": "sha512-L8euabzboKavPuDJsdIYAY2wx97LbiGEYsckMo6NmV8pOun50c8hQx6ouXFSAx4pp+mX9yUGmMiVqfrk2LKDJQ==", + "dev": true, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/parse": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-15.0.0.tgz", + "integrity": "sha512-7fweM67tZfBNS7zw1KTuuT5K2u9nGytUJqFqT/1Ln3Na9cBCsoAqR47mfsNOTlRCgGwakm4xiQ7BpS2gN0OGuw==", + "dev": true, + "dependencies": { + "@commitlint/types": "^15.0.0", + "conventional-changelog-angular": "^5.0.11", + "conventional-commits-parser": "^3.2.2" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/read": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-15.0.0.tgz", + "integrity": "sha512-5yI1o2HKZFVe7RTjL7IhuhHMKar/MDNY34vEHqqz9gMI7BK/rdP8uVb4Di1efl2V0UPnwID0nPKWESjQ8Ti0gw==", + "dev": true, + "dependencies": { + "@commitlint/top-level": "^15.0.0", + "@commitlint/types": "^15.0.0", + "fs-extra": "^10.0.0", + "git-raw-commits": "^2.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-15.0.0.tgz", + "integrity": "sha512-7apfRJjgJsKja7lHsPfEFixKjA/fk/UeD3owkOw1174yYu4u8xBDLSeU3IinGPdMuF9m245eX8wo7vLUy+EBSg==", + "dev": true, + "dependencies": { + "import-fresh": "^3.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/rules": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-15.0.0.tgz", + "integrity": "sha512-SqXfp6QUlwBS+0IZm4FEA/NmmAwcFQIkG3B05BtemOVWXQdZ8j1vV6hDwvA9oMPCmUSrrGpHOtZK7HaHhng2yA==", + "dev": true, + "dependencies": { + "@commitlint/ensure": "^15.0.0", + "@commitlint/message": "^15.0.0", + "@commitlint/to-lines": "^15.0.0", + "@commitlint/types": "^15.0.0", + "execa": "^5.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-15.0.0.tgz", + "integrity": "sha512-mY3MNA9ujPqVpiJjTYG9MDsYCobue5PJFO0MfcIzS1mCVvngH8ZFTPAh1fT5t+t1h876boS88+9WgqjRvbYItw==", + "dev": true, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/top-level": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-15.0.0.tgz", + "integrity": "sha512-7Gz3t7xcuuUw1d1Nou6YLaztzp2Em+qZ6YdCzrqYc+aquca3Vt0O696nuiBDU/oE+tls4Hx2CNpAbWhTgEwB5A==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/types": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-15.0.0.tgz", + "integrity": "sha512-OMSLX+QJnyNoTwws54ULv9sOvuw9GdVezln76oyUd4YbMMJyaav62aSXDuCdWyL2sm9hTkSzyEi52PNaIj/vqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", + "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "node_modules/@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "node_modules/@endemolshinegroup/cosmiconfig-typescript-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz", + "integrity": "sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==", + "dev": true, + "dependencies": { + "lodash.get": "^4", + "make-error": "^1", + "ts-node": "^9", + "tslib": "^2" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "cosmiconfig": ">=6" + } + }, + "node_modules/@endemolshinegroup/cosmiconfig-typescript-loader/node_modules/ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@hutson/parse-repository-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", + "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/source-map/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.6.tgz", + "integrity": "sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.0.tgz", + "integrity": "sha512-SfJxIxNVYLTsKwzB3MoOQ1yxf4w/E6MdkvTgrgAt1bfxjSrLUoHMKrDOykwN14q65waezZIdqDneUIPh4/sKxg==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@lerna/add": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/add/-/add-4.0.0.tgz", + "integrity": "sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng==", + "dev": true, + "dependencies": { + "@lerna/bootstrap": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/npm-conf": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "npm-package-arg": "^8.1.0", + "p-map": "^4.0.0", + "pacote": "^11.2.6", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/bootstrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-4.0.0.tgz", + "integrity": "sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/has-npm-version": "4.0.0", + "@lerna/npm-install": "4.0.0", + "@lerna/package-graph": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/rimraf-dir": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/symlink-binary": "4.0.0", + "@lerna/symlink-dependencies": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "get-port": "^5.1.1", + "multimatch": "^5.0.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1", + "read-package-tree": "^5.3.1", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/changed": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-4.0.0.tgz", + "integrity": "sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ==", + "dev": true, + "dependencies": { + "@lerna/collect-updates": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/listable": "4.0.0", + "@lerna/output": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/check-working-tree": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz", + "integrity": "sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q==", + "dev": true, + "dependencies": { + "@lerna/collect-uncommitted": "4.0.0", + "@lerna/describe-ref": "4.0.0", + "@lerna/validation-error": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/child-process": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-4.0.0.tgz", + "integrity": "sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "execa": "^5.0.0", + "strong-log-transformer": "^2.1.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/clean": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-4.0.0.tgz", + "integrity": "sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/rimraf-dir": "4.0.0", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/cli": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/cli/-/cli-4.0.0.tgz", + "integrity": "sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA==", + "dev": true, + "dependencies": { + "@lerna/global-options": "4.0.0", + "dedent": "^0.7.0", + "npmlog": "^4.1.2", + "yargs": "^16.2.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/cli/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/collect-uncommitted": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz", + "integrity": "sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "chalk": "^4.1.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/collect-updates": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-4.0.0.tgz", + "integrity": "sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/describe-ref": "4.0.0", + "minimatch": "^3.0.4", + "npmlog": "^4.1.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/command": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/command/-/command-4.0.0.tgz", + "integrity": "sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/package-graph": "4.0.0", + "@lerna/project": "4.0.0", + "@lerna/validation-error": "4.0.0", + "@lerna/write-log-file": "4.0.0", + "clone-deep": "^4.0.1", + "dedent": "^0.7.0", + "execa": "^5.0.0", + "is-ci": "^2.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/conventional-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz", + "integrity": "sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw==", + "dev": true, + "dependencies": { + "@lerna/validation-error": "4.0.0", + "conventional-changelog-angular": "^5.0.12", + "conventional-changelog-core": "^4.2.2", + "conventional-recommended-bump": "^6.1.0", + "fs-extra": "^9.1.0", + "get-stream": "^6.0.0", + "lodash.template": "^4.5.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "pify": "^5.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/conventional-commits/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/create": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-4.0.0.tgz", + "integrity": "sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/npm-conf": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "init-package-json": "^2.0.2", + "npm-package-arg": "^8.1.0", + "p-reduce": "^2.1.0", + "pacote": "^11.2.6", + "pify": "^5.0.0", + "semver": "^7.3.4", + "slash": "^3.0.0", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0", + "whatwg-url": "^8.4.0", + "yargs-parser": "20.2.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/create-symlink": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-4.0.0.tgz", + "integrity": "sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig==", + "dev": true, + "dependencies": { + "cmd-shim": "^4.1.0", + "fs-extra": "^9.1.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/create-symlink/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/create/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/describe-ref": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-4.0.0.tgz", + "integrity": "sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/diff/-/diff-4.0.0.tgz", + "integrity": "sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/validation-error": "4.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/exec": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-4.0.0.tgz", + "integrity": "sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/profiler": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/validation-error": "4.0.0", + "p-map": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/filter-options": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-4.0.0.tgz", + "integrity": "sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw==", + "dev": true, + "dependencies": { + "@lerna/collect-updates": "4.0.0", + "@lerna/filter-packages": "4.0.0", + "dedent": "^0.7.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/filter-packages": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-4.0.0.tgz", + "integrity": "sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA==", + "dev": true, + "dependencies": { + "@lerna/validation-error": "4.0.0", + "multimatch": "^5.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/get-npm-exec-opts": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz", + "integrity": "sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/get-packed": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-4.0.0.tgz", + "integrity": "sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w==", + "dev": true, + "dependencies": { + "fs-extra": "^9.1.0", + "ssri": "^8.0.1", + "tar": "^6.1.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/get-packed/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/github-client": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/github-client/-/github-client-4.0.0.tgz", + "integrity": "sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@octokit/plugin-enterprise-rest": "^6.0.1", + "@octokit/rest": "^18.1.0", + "git-url-parse": "^11.4.4", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/gitlab-client": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz", + "integrity": "sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.1", + "npmlog": "^4.1.2", + "whatwg-url": "^8.4.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/global-options": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/global-options/-/global-options-4.0.0.tgz", + "integrity": "sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ==", + "dev": true, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/has-npm-version": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz", + "integrity": "sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/import": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/import/-/import-4.0.0.tgz", + "integrity": "sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "fs-extra": "^9.1.0", + "p-map-series": "^2.1.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/import/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/info": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/info/-/info-4.0.0.tgz", + "integrity": "sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/output": "4.0.0", + "envinfo": "^7.7.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/init": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/init/-/init-4.0.0.tgz", + "integrity": "sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0", + "write-json-file": "^4.3.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/init/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/link/-/link-4.0.0.tgz", + "integrity": "sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/package-graph": "4.0.0", + "@lerna/symlink-dependencies": "4.0.0", + "p-map": "^4.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/list": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/list/-/list-4.0.0.tgz", + "integrity": "sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/listable": "4.0.0", + "@lerna/output": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/listable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/listable/-/listable-4.0.0.tgz", + "integrity": "sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ==", + "dev": true, + "dependencies": { + "@lerna/query-graph": "4.0.0", + "chalk": "^4.1.0", + "columnify": "^1.5.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/log-packed": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-4.0.0.tgz", + "integrity": "sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ==", + "dev": true, + "dependencies": { + "byte-size": "^7.0.0", + "columnify": "^1.5.4", + "has-unicode": "^2.0.1", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-conf": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-4.0.0.tgz", + "integrity": "sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw==", + "dev": true, + "dependencies": { + "config-chain": "^1.1.12", + "pify": "^5.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-dist-tag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz", + "integrity": "sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw==", + "dev": true, + "dependencies": { + "@lerna/otplease": "4.0.0", + "npm-package-arg": "^8.1.0", + "npm-registry-fetch": "^9.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-install": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-4.0.0.tgz", + "integrity": "sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/get-npm-exec-opts": "4.0.0", + "fs-extra": "^9.1.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "signal-exit": "^3.0.3", + "write-pkg": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-install/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/npm-publish": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-4.0.0.tgz", + "integrity": "sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w==", + "dev": true, + "dependencies": { + "@lerna/otplease": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "fs-extra": "^9.1.0", + "libnpmpublish": "^4.0.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "pify": "^5.0.0", + "read-package-json": "^3.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-publish/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/npm-run-script": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz", + "integrity": "sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/get-npm-exec-opts": "4.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/otplease": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/otplease/-/otplease-4.0.0.tgz", + "integrity": "sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw==", + "dev": true, + "dependencies": { + "@lerna/prompt": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/output": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/output/-/output-4.0.0.tgz", + "integrity": "sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/pack-directory": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-4.0.0.tgz", + "integrity": "sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ==", + "dev": true, + "dependencies": { + "@lerna/get-packed": "4.0.0", + "@lerna/package": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "npm-packlist": "^2.1.4", + "npmlog": "^4.1.2", + "tar": "^6.1.0", + "temp-write": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/package": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/package/-/package-4.0.0.tgz", + "integrity": "sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q==", + "dev": true, + "dependencies": { + "load-json-file": "^6.2.0", + "npm-package-arg": "^8.1.0", + "write-pkg": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/package-graph": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-4.0.0.tgz", + "integrity": "sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw==", + "dev": true, + "dependencies": { + "@lerna/prerelease-id-from-version": "4.0.0", + "@lerna/validation-error": "4.0.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/prerelease-id-from-version": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz", + "integrity": "sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg==", + "dev": true, + "dependencies": { + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/profiler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/profiler/-/profiler-4.0.0.tgz", + "integrity": "sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q==", + "dev": true, + "dependencies": { + "fs-extra": "^9.1.0", + "npmlog": "^4.1.2", + "upath": "^2.0.1" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/profiler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/project": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/project/-/project-4.0.0.tgz", + "integrity": "sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg==", + "dev": true, + "dependencies": { + "@lerna/package": "4.0.0", + "@lerna/validation-error": "4.0.0", + "cosmiconfig": "^7.0.0", + "dedent": "^0.7.0", + "dot-prop": "^6.0.1", + "glob-parent": "^5.1.1", + "globby": "^11.0.2", + "load-json-file": "^6.2.0", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "resolve-from": "^5.0.0", + "write-json-file": "^4.3.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/project/node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/prompt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/prompt/-/prompt-4.0.0.tgz", + "integrity": "sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ==", + "dev": true, + "dependencies": { + "inquirer": "^7.3.3", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/publish": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-4.0.0.tgz", + "integrity": "sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg==", + "dev": true, + "dependencies": { + "@lerna/check-working-tree": "4.0.0", + "@lerna/child-process": "4.0.0", + "@lerna/collect-updates": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/describe-ref": "4.0.0", + "@lerna/log-packed": "4.0.0", + "@lerna/npm-conf": "4.0.0", + "@lerna/npm-dist-tag": "4.0.0", + "@lerna/npm-publish": "4.0.0", + "@lerna/otplease": "4.0.0", + "@lerna/output": "4.0.0", + "@lerna/pack-directory": "4.0.0", + "@lerna/prerelease-id-from-version": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/validation-error": "4.0.0", + "@lerna/version": "4.0.0", + "fs-extra": "^9.1.0", + "libnpmaccess": "^4.0.1", + "npm-package-arg": "^8.1.0", + "npm-registry-fetch": "^9.0.0", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "p-pipe": "^3.1.0", + "pacote": "^11.2.6", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/publish/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/pulse-till-done": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz", + "integrity": "sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/query-graph": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/query-graph/-/query-graph-4.0.0.tgz", + "integrity": "sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg==", + "dev": true, + "dependencies": { + "@lerna/package-graph": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/resolve-symlink": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz", + "integrity": "sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA==", + "dev": true, + "dependencies": { + "fs-extra": "^9.1.0", + "npmlog": "^4.1.2", + "read-cmd-shim": "^2.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/resolve-symlink/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/rimraf-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz", + "integrity": "sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "npmlog": "^4.1.2", + "path-exists": "^4.0.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/run": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/run/-/run-4.0.0.tgz", + "integrity": "sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/npm-run-script": "4.0.0", + "@lerna/output": "4.0.0", + "@lerna/profiler": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/timer": "4.0.0", + "@lerna/validation-error": "4.0.0", + "p-map": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/run-lifecycle": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz", + "integrity": "sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ==", + "dev": true, + "dependencies": { + "@lerna/npm-conf": "4.0.0", + "npm-lifecycle": "^3.1.5", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/run-topologically": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/run-topologically/-/run-topologically-4.0.0.tgz", + "integrity": "sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA==", + "dev": true, + "dependencies": { + "@lerna/query-graph": "4.0.0", + "p-queue": "^6.6.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/symlink-binary": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz", + "integrity": "sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA==", + "dev": true, + "dependencies": { + "@lerna/create-symlink": "4.0.0", + "@lerna/package": "4.0.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/symlink-binary/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/symlink-dependencies": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz", + "integrity": "sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw==", + "dev": true, + "dependencies": { + "@lerna/create-symlink": "4.0.0", + "@lerna/resolve-symlink": "4.0.0", + "@lerna/symlink-binary": "4.0.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/symlink-dependencies/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/timer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/timer/-/timer-4.0.0.tgz", + "integrity": "sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg==", + "dev": true, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/validation-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-4.0.0.tgz", + "integrity": "sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/version": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/version/-/version-4.0.0.tgz", + "integrity": "sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA==", + "dev": true, + "dependencies": { + "@lerna/check-working-tree": "4.0.0", + "@lerna/child-process": "4.0.0", + "@lerna/collect-updates": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/conventional-commits": "4.0.0", + "@lerna/github-client": "4.0.0", + "@lerna/gitlab-client": "4.0.0", + "@lerna/output": "4.0.0", + "@lerna/prerelease-id-from-version": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/validation-error": "4.0.0", + "chalk": "^4.1.0", + "dedent": "^0.7.0", + "load-json-file": "^6.2.0", + "minimatch": "^3.0.4", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "p-pipe": "^3.1.0", + "p-reduce": "^2.1.0", + "p-waterfall": "^2.1.1", + "semver": "^7.3.4", + "slash": "^3.0.0", + "temp-write": "^4.0.0", + "write-json-file": "^4.3.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/write-log-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-4.0.0.tgz", + "integrity": "sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2", + "write-file-atomic": "^3.0.3" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/ci-detect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz", + "integrity": "sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q==", + "dev": true + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/git": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", + "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", + "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", + "dev": true + }, + "node_modules/@npmcli/promise-spawn": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", + "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" + } + }, + "node_modules/@npmcli/run-script": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz", + "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^7.1.0", + "read-package-json-fast": "^2.0.1" + } + }, + "node_modules/@npmcli/run-script/node_modules/node-gyp": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@octokit/auth-token": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.0.3" + } + }, + "node_modules/@octokit/core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "dev": true, + "dependencies": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/endpoint": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "dev": true, + "dependencies": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", + "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==", + "dev": true + }, + "node_modules/@octokit/plugin-enterprise-rest": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", + "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", + "dev": true + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", + "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.34.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "dev": true, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", + "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.34.0", + "deprecation": "^2.3.1" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/request": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "dev": true, + "dependencies": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/request-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/@octokit/rest": { + "version": "18.12.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", + "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", + "dev": true, + "dependencies": { + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + } + }, + "node_modules/@octokit/types": { + "version": "6.34.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", + "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^11.2.0" + } + }, + "node_modules/@opencensus/core": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz", + "integrity": "sha512-31Q4VWtbzXpVUd2m9JS6HEaPjlKvNMOiF7lWKNmXF84yUcgfAFL5re7/hjDmdyQbOp32oGc+RFV78jXIldVz6Q==", + "dev": true, + "dependencies": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^5.5.0", + "shimmer": "^1.2.0", + "uuid": "^3.2.1" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@opencensus/core/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@opencensus/core/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/@opencensus/propagation-b3": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@opencensus/propagation-b3/-/propagation-b3-0.0.8.tgz", + "integrity": "sha512-PffXX2AL8Sh0VHQ52jJC4u3T0H6wDK6N/4bg7xh4ngMYOIi13aR1kzVvX1sVDBgfGwDOkMbl4c54Xm3tlPx/+A==", + "dev": true, + "dependencies": { + "@opencensus/core": "^0.0.8", + "uuid": "^3.2.1" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@opencensus/propagation-b3/node_modules/@opencensus/core": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.8.tgz", + "integrity": "sha512-yUFT59SFhGMYQgX0PhoTR0LBff2BEhPrD9io1jWfF/VDbakRfs6Pq60rjv0Z7iaTav5gQlttJCX2+VPxFWCuoQ==", + "dev": true, + "dependencies": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^5.5.0", + "shimmer": "^1.2.0", + "uuid": "^3.2.1" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@opencensus/propagation-b3/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@opencensus/propagation-b3/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/@pm2/agent": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.1.tgz", + "integrity": "sha512-QKHMm6yexcvdDfcNE7PL9D6uEjoQPGRi+8dh+rc4Hwtbpsbh5IAvZbz3BVGjcd4HaX6pt2xGpOohG7/Y2L4QLw==", + "dev": true, + "dependencies": { + "async": "~3.2.0", + "chalk": "~3.0.0", + "dayjs": "~1.8.24", + "debug": "~4.3.1", + "eventemitter2": "~5.0.1", + "fast-json-patch": "^3.0.0-1", + "fclone": "~1.0.11", + "nssocket": "0.6.0", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.0", + "proxy-agent": "~5.0.0", + "semver": "~7.2.0", + "ws": "~7.4.0" + } + }, + "node_modules/@pm2/agent/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@pm2/agent/node_modules/dayjs": { + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", + "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==", + "dev": true + }, + "node_modules/@pm2/agent/node_modules/semver": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.2.3.tgz", + "integrity": "sha512-utbW9Z7ZxVvwiIWkdOMLOR9G/NFXh2aRucghkVrEMJWuC++r3lCkBC3LwqBinyHzGMAJxY5tn6VakZGHObq5ig==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@pm2/agent/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@pm2/io": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-5.0.0.tgz", + "integrity": "sha512-3rToDVJaRoob5Lq8+7Q2TZFruoEkdORxwzFpZaqF4bmH6Bkd7kAbdPrI/z8X6k1Meq5rTtScM7MmDgppH6aLlw==", + "dev": true, + "dependencies": { + "@opencensus/core": "0.0.9", + "@opencensus/propagation-b3": "0.0.8", + "async": "~2.6.1", + "debug": "~4.3.1", + "eventemitter2": "^6.3.1", + "require-in-the-middle": "^5.0.0", + "semver": "6.3.0", + "shimmer": "^1.2.0", + "signal-exit": "^3.0.3", + "tslib": "1.9.3" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@pm2/io/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/@pm2/io/node_modules/eventemitter2": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", + "dev": true + }, + "node_modules/@pm2/io/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@pm2/io/node_modules/tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, + "node_modules/@pm2/js-api": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.6.7.tgz", + "integrity": "sha512-jiJUhbdsK+5C4zhPZNnyA3wRI01dEc6a2GhcQ9qI38DyIk+S+C8iC3fGjcjUbt/viLYKPjlAaE+hcT2/JMQPXw==", + "dev": true, + "dependencies": { + "async": "^2.6.3", + "axios": "^0.21.0", + "debug": "~4.3.1", + "eventemitter2": "^6.3.1", + "ws": "^7.0.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@pm2/js-api/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/@pm2/js-api/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/@pm2/js-api/node_modules/eventemitter2": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", + "dev": true + }, + "node_modules/@pm2/pm2-version-check": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.4.tgz", + "integrity": "sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==", + "dev": true, + "dependencies": { + "debug": "^4.3.1" + } + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@socket.io/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", + "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==" + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "dev": true, + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "dev": true, + "dependencies": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.6" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@tago-io/sdk": { + "version": "10.4.4", + "resolved": "https://registry.npmjs.org/@tago-io/sdk/-/sdk-10.4.4.tgz", + "integrity": "sha512-5rZxeJCRCCf0wfEVsFjS4OJL31YvRDDJSAA0OgEh1vkGtowO0JuYbASyZV6ZYxU4kczHCC4FfjkeIw5uu8G/hg==", + "dependencies": { + "axios": "0.25.0", + "form-data": "4.0.0", + "lodash.chunk": "4.2.0", + "nanoid": "3.2.0", + "papaparse": "5.3.1", + "qs": "6.10.3", + "socket.io-client": "4.4.1" + }, + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" + } + }, + "node_modules/@tago-io/sdk/node_modules/axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "dependencies": { + "follow-redirects": "^1.14.7" + } + }, + "node_modules/@tago-io/sdk/node_modules/nanoid": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/@tago-io/sdk/node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@tago-io/tcore-api": { + "resolved": "packages/tcore-api", + "link": true + }, + "node_modules/@tago-io/tcore-cli": { + "resolved": "packages/tcore-cli", + "link": true + }, + "node_modules/@tago-io/tcore-console": { + "resolved": "packages/tcore-console", + "link": true + }, + "node_modules/@tago-io/tcore-sdk": { + "resolved": "packages/tcore-sdk", + "link": true + }, + "node_modules/@tago-io/tcore-shared": { + "resolved": "packages/tcore-shared", + "link": true + }, + "node_modules/@testing-library/dom": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.13.0.tgz", + "integrity": "sha512-9VHgfIatKNXQNaZTtLnalIy0jNZzY35a4S3oi08YAt9Hv1VsfZ/DfA45lM8D/UhtHBGJ4/lGwp0PZkVndRkoOQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", + "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^4.2.2", + "chalk": "^3.0.0", + "css": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=8", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.0.0.tgz", + "integrity": "sha512-sh3jhFgEshFyJ/0IxGltRhwZv2kFKfJ3fN1vTZ6hhMXzz9ZbbcTgmDYM4e+zJv+oiVKKEWZPyqPAh4MQBI65gA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/commander": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q==", + "deprecated": "This is a stub types definition for commander (https://github.com/tj/commander.js). commander provides its own type definitions, so you don't need @types/commander installed!", + "dev": true, + "dependencies": { + "commander": "*" + } + }, + "node_modules/@types/component-emitter": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", + "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" + }, + "node_modules/@types/compression": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.1.tgz", + "integrity": "sha512-d6K1bU3qIjtfB2u+A1N0WDf62LpewRjrvbqY79qlPwk2otgQ4mWB4+LzPCWTvGmcuVwo+zAroEhsNlJavRcFvg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" + }, + "node_modules/@types/d3-timer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-2.0.1.tgz", + "integrity": "sha512-TF8aoF5cHcLO7W7403blM7L1T+6NF3XMyN3fxyUolq2uOcFeicG/khQg/dGxiCJWoAcmYulYN7LYSRKO54IXaA==" + }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/history/-/history-5.0.0.tgz", + "integrity": "sha512-hy8b7Y1J8OGe6LbAjj3xniQrj3v6lsivCcrmf4TzSgPzLkhIeKgc5IZnT7ReIqmEuodjfO8EYAuoFvIrHi/+jQ==", + "deprecated": "This is a stub types definition. history provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "history": "*" + } + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz", + "integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==", + "dev": true, + "dependencies": { + "jest-diff": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "node_modules/@types/js-yaml": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.3.tgz", + "integrity": "sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.182", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", + "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", + "dev": true + }, + "node_modules/@types/lodash.clonedeep": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz", + "integrity": "sha512-cE1jYr2dEg1wBImvXlNtp0xDoS79rfEdGozQVgliDZj1uERH4k+rmEMTudP9b4VQ8O6nRb5gPqft0QzEQGMQgA==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/luxon": { + "version": "1.27.1", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-1.27.1.tgz", + "integrity": "sha512-cPiXpOvPFDr2edMnOXlz3UBDApwUfR+cpizvxCy0n3vp9bz/qe8BWzHPIEFcy+ogUOyjKuCISgyq77ELZPmkkg==", + "dev": true + }, + "node_modules/@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==" + }, + "node_modules/@types/method-override": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/method-override/-/method-override-0.0.32.tgz", + "integrity": "sha512-Vf9AohOlANmhNswCbkdRG3p+tYcq1+63O+ex1UoNIVYWW3tO8Mx6Z+5G1R8DENeC6/t1SiDJS+ph6ACKpryokg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "node_modules/@types/minipass": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/minipass/-/minipass-3.1.2.tgz", + "integrity": "sha512-foLGjgrJkUjLG/o2t2ymlZGEoBNBa/TfoUZ7oCTkOjP1T43UGBJspovJou/l3ZuHvye2ewR5cZNtp2zyWgILMA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "node_modules/@types/node": { + "version": "16.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.1.tgz", + "integrity": "sha512-ncRdc45SoYJ2H4eWU9ReDfp3vtFqDYhjOsKlFFUDEn8V1Bgr2RjYal8YT5byfadWIRluhPFU6JiDOl0H6Sl87A==" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.0.tgz", + "integrity": "sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/react": { + "version": "17.0.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz", + "integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "17.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", + "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-helmet": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.4.tgz", + "integrity": "sha512-jyx50RNZXVaTGHY3MsoRPNpeiVk8b0XTPgD/O6KHF6COTDnG/+lRjPYvTK5nfWtR3xDOux0w6bHLAsaHo2ZLTA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz", + "integrity": "sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==", + "dev": true, + "dependencies": { + "@types/history": "*", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz", + "integrity": "sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw==", + "dev": true, + "dependencies": { + "@types/history": "*", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/semver": { + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz", + "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/styled-components": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.11.tgz", + "integrity": "sha512-u8g3bSw9KUiZY+S++gh+LlURGraqBe3MC5I5dygrNjGDHWWQfsmZZRTJ9K9oHU2CqWtxChWmJkDI/gp+TZPQMw==", + "dev": true, + "dependencies": { + "@types/hoist-non-react-statics": "*", + "@types/react": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/tar": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-uTZKMW7ZkdTJXX4+Bsp0ko9N7B5/NJ5wJRW14XTb6KNN+9i2NPel6iPKp8rTQahMW46BM9tM52dTeMSldB55og==", + "dev": true, + "dependencies": { + "@types/minipass": "*", + "@types/node": "*" + } + }, + "node_modules/@types/testing-library__jest-dom": { + "version": "5.14.3", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.3.tgz", + "integrity": "sha512-oKZe+Mf4ioWlMuzVBaXQ9WDnEm1+umLx0InILg+yvZVBBDmzV5KfZyLrCvadtWcx8+916jLmHafcmqqffl+iIw==", + "dev": true, + "dependencies": { + "@types/jest": "*" + } + }, + "node_modules/@types/tinycolor2": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.3.tgz", + "integrity": "sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==", + "dev": true + }, + "node_modules/@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.3.tgz", + "integrity": "sha512-tBgfA3K/3TsZY46ROGvoRxQr1wBkclbVqRQep97MjVHJzcRBURRY3sNFqLk0/Xr//BY5hM9H2p/kp+6qim85SA==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "4.29.3", + "@typescript-eslint/scope-manager": "4.29.3", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.3.tgz", + "integrity": "sha512-ffIvbytTVWz+3keg+Sy94FG1QeOvmV9dP2YSdLFHw/ieLXWCa3U1TYu8IRCOpMv2/SPS8XqhM1+ou1YHsdzKrg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.29.3", + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/typescript-estree": "4.29.3", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.3.tgz", + "integrity": "sha512-jrHOV5g2u8ROghmspKoW7pN8T/qUzk0+DITun0MELptvngtMrwUJ1tv5zMI04CYVEUsSrN4jV7AKSv+I0y0EfQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "4.29.3", + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/typescript-estree": "4.29.3", + "debug": "^4.3.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.3.tgz", + "integrity": "sha512-x+w8BLXO7iWPkG5mEy9bA1iFRnk36p/goVlYobVWHyDw69YmaH9q6eA+Fgl7kYHmFvWlebUTUfhtIg4zbbl8PA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/visitor-keys": "4.29.3" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.3.tgz", + "integrity": "sha512-s1eV1lKNgoIYLAl1JUba8NhULmf+jOmmeFO1G5MN/RBCyyzg4TIOfIOICVNC06lor+Xmy4FypIIhFiJXOknhIg==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.3.tgz", + "integrity": "sha512-45oQJA0bxna4O5TMwz55/TpgjX1YrAPOI/rb6kPgmdnemRZx/dB0rsx+Ku8jpDvqTxcE1C/qEbVHbS3h0hflag==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/visitor-keys": "4.29.3", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.3.tgz", + "integrity": "sha512-MGGfJvXT4asUTeVs0Q2m+sY63UsfnA+C/FDgBKV3itLBmM9H0u+URcneePtkd0at1YELmZK6HSolCqM4Fzs6yA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.29.3", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=", + "dev": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/agentkeepalive/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amp": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", + "integrity": "sha1-at+NWKdPNh6CwfqNOJwHnhOfxH0=", + "dev": true + }, + "node_modules/amp-message": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz", + "integrity": "sha1-p48cmJlQh602GSpBKY5NtJ49/EU=", + "dev": true, + "dependencies": { + "amp": "0.3.1" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/are-we-there-yet/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "dev": true + }, + "node_modules/async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "dev": true, + "dependencies": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "engines": { + "node": "<=0.11.8 || >0.11.10" + } + }, + "node_modules/async-listener/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/aws-sdk": { + "version": "2.1087.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1087.0.tgz", + "integrity": "sha512-m5EERT29Fwh2cv3SaSdygeAjJBXnjSaXRRERy70bf6PQ7KgmASJouBxY11g5G7LTEPK/yfB0TGshujKh3hEtPA==", + "dev": true, + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "node_modules/axe-core": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz", + "integrity": "sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "dependencies": { + "follow-redirects": "^1.14.4" + } + }, + "node_modules/axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-plugin-styled-components": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz", + "integrity": "sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-module-imports": "^7.16.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "lodash": "^4.17.11", + "picomatch": "^2.3.0" + }, + "peerDependencies": { + "styled-components": ">= 2" + } + }, + "node_modules/babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", + "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/blessed": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", + "integrity": "sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk=", + "dev": true, + "bin": { + "blessed": "bin/tput.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/bodec": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", + "integrity": "sha1-vIUVVUMPI8n3ZQp172TGqUw0GMw=", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "node_modules/byline": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/byte-size": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-7.0.1.tgz", + "integrity": "sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001334", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001334.tgz", + "integrity": "sha512-kbaCEBRRVSoeNs74sCuq92MJyGrMtjWVfhltoHUCW4t4pXFvGjUBrfo47weBRViHkiV3eBYyIsfl956NtHGazw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "dependencies": { + "rsvp": "^4.8.4" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.1.tgz", + "integrity": "sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "engines": { + "node": "*" + } + }, + "node_modules/charm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", + "integrity": "sha1-BsIe7RobBq62dVPNxT4jJ0usIpY=", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-tableau": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.1.tgz", + "integrity": "sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==", + "dev": true, + "dependencies": { + "chalk": "3.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/cli-tableau/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/cmd-shim": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz", + "integrity": "sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw==", + "dev": true, + "dependencies": { + "mkdirp-infer-owner": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/columnify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", + "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "dev": true, + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz", + "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", + "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/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==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "engines": [ + "node >= 6.0" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concurrently": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.1.0.tgz", + "integrity": "sha512-Bz0tMlYKZRUDqJlNiF/OImojMB9ruKUz6GCfmhFnSapXgPe+3xzY4byqoKG9tUZ7L2PGEUjfLPOLfIX3labnmw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "bin": { + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.0 || >=16.0.0" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "dev": true, + "dependencies": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", + "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz", + "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz", + "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==", + "dev": true, + "dependencies": { + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^5.0.0", + "conventional-commits-parser": "^3.2.0", + "dateformat": "^3.0.0", + "get-pkg-repo": "^4.0.0", + "git-raw-commits": "^2.0.8", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^4.1.1", + "lodash": "^4.17.15", + "normalize-package-data": "^3.0.0", + "q": "^1.5.1", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0", + "through2": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-preset-loader": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz", + "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==", + "dev": true, + "dependencies": { + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-changelog-writer": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-writer/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/conventional-commits-filter": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", + "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", + "dev": true, + "dependencies": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-commits-parser": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", + "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", + "dev": true, + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-recommended-bump": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz", + "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==", + "dev": true, + "dependencies": { + "concat-stream": "^2.0.0", + "conventional-changelog-preset-loader": "^2.3.4", + "conventional-commits-filter": "^2.0.7", + "conventional-commits-parser": "^3.2.0", + "git-raw-commits": "^2.0.8", + "git-semver-tags": "^4.1.1", + "meow": "^8.0.0", + "q": "^1.5.1" + }, + "bin": { + "conventional-recommended-bump": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-js-pure": { + "version": "3.22.3", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.3.tgz", + "integrity": "sha512-oN88zz7nmKROMy8GOjs+LN+0LedIvbMdnB5XsTlhcOg1WGARt9l0LFg0zohdoFmCsEZ1h2ZbSQ6azj3M+vhzwQ==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/croner": { + "version": "4.1.97", + "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", + "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "engines": { + "node": "*" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/css": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", + "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "source-map": "^0.6.1", + "source-map-resolve": "^0.6.0" + } + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", + "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=", + "dev": true + }, + "node_modules/css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, + "node_modules/culvert": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", + "integrity": "sha1-lQL18BVKLVoioCPnn3HMk2+m728=", + "dev": true + }, + "node_modules/d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" + }, + "node_modules/d3-ease": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", + "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" + }, + "node_modules/d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "dependencies": { + "d3-color": "1" + } + }, + "node_modules/d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "dev": true, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/dayjs": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.1.tgz", + "integrity": "sha512-2xg7JrHQeLBQFkvTumLoy62x1siyeocc98QwjtURgvRqOPYmAkMUdmSjrOA+MlmL6QMQn5MUhDf6rNZNuPc1LQ==" + }, + "node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz", + "integrity": "sha512-YV/0HQHreRwKb7uBopyIkLG17jG6Sv2qUchk9qSoVJ2f+flwRsPNBO0hAnjt6mTNYUT+vw9Gy2ihXg4sUWPi2w==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/degenerator": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/degenerator/node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/degenerator/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/degenerator/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/degenerator/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/degenerator/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/degenerator/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "node_modules/dequal": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz", + "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==" + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", + "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==", + "dev": true + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.124", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.124.tgz", + "integrity": "sha512-VhaE9VUYU6d2eIb+4xf83CATD+T+3bTzvxvlADkQE+c2hisiw3sZmvEDtsW704+Zky9WZGhBuQXijDVqSriQLA==", + "dev": true + }, + "node_modules/emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "dev": true, + "dependencies": { + "shimmer": "^1.2.0" + } + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", + "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", + "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", + "dependencies": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.0", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0", + "yeast": "0.1.2" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", + "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", + "dependencies": { + "@socket.io/base64-arraybuffer": "~1.0.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.38.tgz", + "integrity": "sha512-12fzJ0fsm7gVZX1YQ1InkOE5f9Tl7cgf6JPYXRJtPIoE0zkWAbHdPHVPPaLi9tYAcEBqheGzqLn/3RdTOyBfcA==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.38", + "esbuild-android-arm64": "0.14.38", + "esbuild-darwin-64": "0.14.38", + "esbuild-darwin-arm64": "0.14.38", + "esbuild-freebsd-64": "0.14.38", + "esbuild-freebsd-arm64": "0.14.38", + "esbuild-linux-32": "0.14.38", + "esbuild-linux-64": "0.14.38", + "esbuild-linux-arm": "0.14.38", + "esbuild-linux-arm64": "0.14.38", + "esbuild-linux-mips64le": "0.14.38", + "esbuild-linux-ppc64le": "0.14.38", + "esbuild-linux-riscv64": "0.14.38", + "esbuild-linux-s390x": "0.14.38", + "esbuild-netbsd-64": "0.14.38", + "esbuild-openbsd-64": "0.14.38", + "esbuild-sunos-64": "0.14.38", + "esbuild-windows-32": "0.14.38", + "esbuild-windows-64": "0.14.38", + "esbuild-windows-arm64": "0.14.38" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz", + "integrity": "sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz", + "integrity": "sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz", + "integrity": "sha512-5JJvgXkX87Pd1Og0u/NJuO7TSqAikAcQQ74gyJ87bqWRVeouky84ICoV4sN6VV53aTW+NE87qLdGY4QA2S7KNA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz", + "integrity": "sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz", + "integrity": "sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz", + "integrity": "sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-jest": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/esbuild-jest/-/esbuild-jest-0.5.0.tgz", + "integrity": "sha512-AMZZCdEpXfNVOIDvURlqYyHwC8qC1/BFjgsrOiSL1eyiIArVtHL8YAC83Shhn16cYYoAWEW17yZn0W/RJKJKHQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.17", + "@babel/plugin-transform-modules-commonjs": "^7.12.13", + "babel-jest": "^26.6.3" + }, + "peerDependencies": { + "esbuild": ">=0.8.50" + } + }, + "node_modules/esbuild-jest/node_modules/@jest/transform": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/esbuild-jest/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/esbuild-jest/node_modules/@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/esbuild-jest/node_modules/babel-jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", + "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "dev": true, + "dependencies": { + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/esbuild-jest/node_modules/babel-plugin-jest-hoist": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", + "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/esbuild-jest/node_modules/babel-preset-jest": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", + "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/esbuild-jest/node_modules/jest-haste-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", + "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^26.0.0", + "jest-serializer": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "engines": { + "node": ">= 10.14.2" + }, + "optionalDependencies": { + "fsevents": "^2.1.2" + } + }, + "node_modules/esbuild-jest/node_modules/jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/esbuild-jest/node_modules/jest-serializer": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", + "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/esbuild-jest/node_modules/jest-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/esbuild-jest/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/esbuild-jest/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz", + "integrity": "sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz", + "integrity": "sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz", + "integrity": "sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz", + "integrity": "sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz", + "integrity": "sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz", + "integrity": "sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz", + "integrity": "sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz", + "integrity": "sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz", + "integrity": "sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz", + "integrity": "sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz", + "integrity": "sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz", + "integrity": "sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz", + "integrity": "sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz", + "integrity": "sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb": { + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz", + "integrity": "sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^14.2.1", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-react": "^7.21.5", + "eslint-plugin-react-hooks": "^4 || ^3 || ^2.3.0 || ^1.7.0" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", + "eslint-plugin-import": "^2.22.1" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.4.0.tgz", + "integrity": "sha512-useJKURidCcldRLCNKWemr1fFQL1SzB3G4a0li6lFGvlc5xGe1hY343bvG07cbpCzPuM/lK19FIJB3XGFSkplA==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.24.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.1.tgz", + "integrity": "sha512-KSFWhNxPH8OGJwpRJJs+Z7I0a13E2iFQZJIvSnCu6KUs4qmgAm3xN9GYBCSoiGWmwA7gERZPXqYQjcoCROnYhQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.10.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-plugin-import/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.4.0.tgz", + "integrity": "sha512-8qnt/hgtZ94E9dA6viqfViKBfkJwFHXgJmTWlMGDgunw1XJEGqm3eiPjDsTanM3/u/3Az82nyQM9GX7PM/QGmg==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "^4.0.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": ">= 4", + "eslint": ">=5" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", + "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.11.2", + "aria-query": "^4.2.2", + "array-includes": "^3.1.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.0.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.6", + "emoji-regex": "^9.0.0", + "has": "^1.0.3", + "jsx-ast-utils": "^3.1.0", + "language-tags": "^1.0.5" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=5.0.0", + "prettier": ">=1.13.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", + "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.values": "^1.1.4", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.5" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", + "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", + "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", + "dev": true + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/express": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.0.tgz", + "integrity": "sha512-EJEXxiTQJS3lIPrU1AE2vRuT7X7E+0KBbpm5GSoK524yl0K8X+er8zS2P14E64eqsVNoWbMCT7MpmQ+ErAhgRg==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/express/node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fclone": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", + "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA=", + "dev": true + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "dependencies": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ftp/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/ftp/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/ftp/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-pkg-repo": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", + "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", + "dev": true, + "dependencies": { + "@hutson/parse-repository-url": "^3.0.0", + "hosted-git-info": "^4.0.0", + "through2": "^2.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "get-pkg-repo": "src/cli.js" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-pkg-repo/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/get-pkg-repo/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/get-pkg-repo/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/get-pkg-repo/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/git-node-fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/git-node-fs/-/git-node-fs-1.0.0.tgz", + "integrity": "sha1-SbIV4kLr5Dqkx1Ybu6SZUhdSCA8=", + "dev": true + }, + "node_modules/git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "dev": true, + "dependencies": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", + "dev": true, + "dependencies": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-remote-origin-url/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/git-semver-tags": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", + "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", + "dev": true, + "dependencies": { + "meow": "^8.0.0", + "semver": "^6.0.0" + }, + "bin": { + "git-semver-tags": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-semver-tags/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/git-sha1": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/git-sha1/-/git-sha1-0.1.2.tgz", + "integrity": "sha1-WZrBkrcYdYJeE6RF86bgURjC90U=", + "dev": true + }, + "node_modules/git-up": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-4.0.5.tgz", + "integrity": "sha512-YUvVDg/vX3d0syBsk/CKUTib0srcQME0JyHkL5BaYdwLsiCslPWmDSi8PUMo9pXYjrryMcmsCoCgsTpSCJEQaA==", + "dev": true, + "dependencies": { + "is-ssh": "^1.3.0", + "parse-url": "^6.0.0" + } + }, + "node_modules/git-url-parse": { + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.6.0.tgz", + "integrity": "sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g==", + "dev": true, + "dependencies": { + "git-up": "^4.0.0" + } + }, + "node_modules/gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", + "dev": true, + "dependencies": { + "ini": "^1.3.2" + } + }, + "node_modules/gl-matrix": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", + "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "dependencies": { + "ini": "^1.3.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/got/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/graphql": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.0.1.tgz", + "integrity": "sha512-oPvCuu6dlLdiz8gZupJ47o1clgb72r1u8NDBcQYjcV6G/iEdmE11B1bBlkhXRvV0LisP/SXRFP7tT6AgaTjpzg==", + "engines": { + "node": "^12.22.0 || ^14.16.0 || >=16.0.0" + } + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.7.6" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" + }, + "node_modules/ignore-walk": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", + "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/image-size": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.1.tgz", + "integrity": "sha512-VAwkvNSNGClRw9mDHhc5Efax8PLlsOGcUTh0T/LIriC8vPA3U5PdqXWqkz406MoYHMKW8Uf9gWr05T/rYB44kQ==", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/init-package-json": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.5.tgz", + "integrity": "sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA==", + "dev": true, + "dependencies": { + "npm-package-arg": "^8.1.5", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "^4.1.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/init-package-json/node_modules/read-package-json": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-4.1.2.tgz", + "integrity": "sha512-Dqer4pqzamDE2O4M55xp1qZMuLPqi4ldk2ya648FOMHRjwMzFhuxVrG04wd0c38IsvkVdr3vgHI6z+QTPdAjrQ==", + "dev": true, + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", + "npm-normalize-package-bin": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/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, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-ci/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally/node_modules/global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", + "dev": true + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ssh": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.3.tgz", + "integrity": "sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ==", + "dev": true, + "dependencies": { + "protocols": "^1.1.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "dev": true, + "dependencies": { + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "node_modules/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.6.tgz", + "integrity": "sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==", + "dev": true, + "dependencies": { + "@jest/core": "^27.0.6", + "import-local": "^3.0.2", + "jest-cli": "^27.0.6" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-transform-stub": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jest-transform-stub/-/jest-transform-stub-2.0.0.tgz", + "integrity": "sha512-lspHaCRx/mBbnm3h4uMMS3R5aZzMwyNpNIJLXj4cEsV0mIUtS4IjYJLSoyjRCtnxb6RIGJ4NL2quZzfIeNhbkg==", + "dev": true + }, + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-git": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", + "integrity": "sha1-UvplWrYYd9bxB578ZTS1VPMeVEQ=", + "dev": true, + "dependencies": { + "bodec": "^0.1.0", + "culvert": "^0.1.2", + "git-sha1": "^0.1.2", + "pako": "^0.2.5" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "node_modules/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", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.2.tgz", + "integrity": "sha512-HDAyJ4MNQBboGpUnHAVUNJs6X0lh058s6FuixsFGP7MgJYpD6Vasd6nzSG5iIfXu1zAYlHJ/zsOKNlrenTUBnw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "object.assign": "^4.1.2" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", + "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", + "dev": true, + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lazy": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", + "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=", + "dev": true, + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/lerna": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-4.0.0.tgz", + "integrity": "sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg==", + "dev": true, + "dependencies": { + "@lerna/add": "4.0.0", + "@lerna/bootstrap": "4.0.0", + "@lerna/changed": "4.0.0", + "@lerna/clean": "4.0.0", + "@lerna/cli": "4.0.0", + "@lerna/create": "4.0.0", + "@lerna/diff": "4.0.0", + "@lerna/exec": "4.0.0", + "@lerna/import": "4.0.0", + "@lerna/info": "4.0.0", + "@lerna/init": "4.0.0", + "@lerna/link": "4.0.0", + "@lerna/list": "4.0.0", + "@lerna/publish": "4.0.0", + "@lerna/run": "4.0.0", + "@lerna/version": "4.0.0", + "import-local": "^3.0.2", + "npmlog": "^4.1.2" + }, + "bin": { + "lerna": "cli.js" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libnpmaccess": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-4.0.3.tgz", + "integrity": "sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ==", + "dev": true, + "dependencies": { + "aproba": "^2.0.0", + "minipass": "^3.1.1", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/libnpmaccess/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/libnpmaccess/node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/libnpmaccess/node_modules/npm-registry-fetch": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", + "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/libnpmaccess/node_modules/socks-proxy-agent": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz", + "integrity": "sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/libnpmpublish": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-4.0.2.tgz", + "integrity": "sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw==", + "dev": true, + "dependencies": { + "normalize-package-data": "^3.0.2", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0", + "semver": "^7.1.3", + "ssri": "^8.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/libnpmpublish/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/libnpmpublish/node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/libnpmpublish/node_modules/npm-registry-fetch": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", + "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/libnpmpublish/node_modules/socks-proxy-agent": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz", + "integrity": "sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/load-json-file/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/loader-utils/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "node_modules/lodash.chunk": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", + "integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "node_modules/log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", + "dev": true, + "engines": { + "node": ">=0.8.6" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/luxon": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.3.1.tgz", + "integrity": "sha512-I8vnjOmhXsMSlNMZlMkSOvgrxKJl0uOsEzdGgGNZuZPaS9KlefpE9KV95QFftlJSC+1UyCC9/I69R02cz/zcCA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "8.0.14", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz", + "integrity": "sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.0.5", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^5.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/mdast-util-definitions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.0.tgz", + "integrity": "sha512-5hcR7FL2EuZ4q6lLMUK5w4lHT2H3vqL9quPvYZ/Ku5iifrirfMHiGdhxdXMUbUkDmz5I+TYMd7nbaxUhbQkfpQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions/node_modules/unist-util-visit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-3.1.0.tgz", + "integrity": "sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions/node_modules/unist-util-visit-parents": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz", + "integrity": "sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-11.3.0.tgz", + "integrity": "sha512-4o3Cli3hXPmm1LhB+6rqhfsIUBjnKFlIUZvudaermXB+4/KONdd/W4saWWkC+LBLbPMqhFSSTSRgafHsT5fVJw==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "@types/mdurl": "^1.0.0", + "mdast-util-definitions": "^5.0.0", + "mdurl": "^1.0.0", + "unist-builder": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/meow/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/meow/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/method-override": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz", + "integrity": "sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA==", + "dependencies": { + "debug": "3.1.0", + "methods": "~1.1.2", + "parseurl": "~1.3.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/method-override/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/method-override/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", + "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", + "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", + "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", + "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", + "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", + "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", + "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", + "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", + "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", + "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", + "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", + "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", + "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", + "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz", + "integrity": "sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", + "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", + "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz", + "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", + "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", + "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", + "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + }, + "peerDependencies": { + "prop-types": "^15.0.0", + "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-infer-owner": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz", + "integrity": "sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "infer-owner": "^1.0.4", + "mkdirp": "^1.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mobx": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.4.2.tgz", + "integrity": "sha512-b4xQJYiH8sb0sEbfq/Ws3N77DEJtSihUFD1moeiz2jNoJ5B+mqJutt54ouO9iEfkp7Wk4jQDsVUOh7DPEW3wEw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-7.3.0.tgz", + "integrity": "sha512-RGEcwZokopqyJE5JPwXKB9FWMSqFM9NJVO2QPI+z6laJTJeBHqvPicjnKgY5mvihxTeXB1+72TnooqUePeGV1g==", + "dependencies": { + "mobx-react-lite": "^3.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.1.0", + "react": "^16.8.0 || ^17" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/mobx-react-lite": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.3.0.tgz", + "integrity": "sha512-U/kMSFtV/bNVgY01FuiGWpRkaQVHozBq5CEBZltFvPt4FcV111hEWkgwqVg9GPPZSEuEdV438PEz8mk8mKpYlA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.1.0", + "react": "^16.8.0 || ^17" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=", + "dev": true + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", + "dev": true, + "dependencies": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/multimatch/node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/needle": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", + "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", + "dev": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/needle/node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-gyp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz", + "integrity": "sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.1.2", + "request": "^2.88.0", + "rimraf": "^2.6.3", + "semver": "^5.7.1", + "tar": "^4.4.12", + "which": "^1.3.1" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-gyp/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/node-gyp/node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/node-gyp/node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/node-gyp/node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/node-gyp/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/node-gyp/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/node-gyp/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-gyp/node_modules/tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "dev": true + }, + "node_modules/nodemon": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", + "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", + "hasInstallScript": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5", + "update-notifier": "^5.1.0" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-install-checks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", + "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-lifecycle": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz", + "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==", + "dev": true, + "dependencies": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.15", + "node-gyp": "^5.0.2", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + } + }, + "node_modules/npm-lifecycle/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-lifecycle/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-arg": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", + "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-packlist": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz", + "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==", + "dev": true, + "dependencies": { + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-pick-manifest": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", + "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", + "dev": true, + "dependencies": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + } + }, + "node_modules/npm-registry-fetch": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz", + "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==", + "dev": true, + "dependencies": { + "@npmcli/ci-detect": "^1.0.0", + "lru-cache": "^6.0.0", + "make-fetch-happen": "^8.0.9", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm-run-all/node_modules/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, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/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, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/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, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/npm-run-all/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/npm-run-all/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/npm-run-all/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-run-all/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/nssocket": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.6.0.tgz", + "integrity": "sha1-Wflvb/MhVm8zxw99vu7N/cBxVPo=", + "dev": true, + "dependencies": { + "eventemitter2": "~0.4.14", + "lazy": "~1.0.11" + }, + "engines": { + "node": ">= 0.10.x" + } + }, + "node_modules/nssocket/node_modules/eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", + "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map-series": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz", + "integrity": "sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-pipe": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz", + "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-waterfall": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz", + "integrity": "sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==", + "dev": true, + "dependencies": { + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/pac-resolver": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz", + "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==", + "dev": true, + "dependencies": { + "degenerator": "^3.0.1", + "ip": "^1.1.5", + "netmask": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/pacote": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz", + "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "dev": true, + "dependencies": { + "@npmcli/git": "^2.1.0", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^11.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pacote/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pacote/node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/pacote/node_modules/npm-registry-fetch": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", + "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pacote/node_modules/socks-proxy-agent": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz", + "integrity": "sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "node_modules/papaparse": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.1.tgz", + "integrity": "sha512-Dbt2yjLJrCwH2sRqKFFJaN5XgIASO9YOFeFP8rIBRG2Ain8mqk5r1M6DkfvqEVozVcz3r3HaUGw253hA1nLIcA==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-path": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz", + "integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==", + "dev": true, + "dependencies": { + "is-ssh": "^1.3.0", + "protocols": "^1.4.0", + "qs": "^6.9.4", + "query-string": "^6.13.8" + } + }, + "node_modules/parse-url": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz", + "integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==", + "dev": true, + "dependencies": { + "is-ssh": "^1.3.0", + "normalize-url": "^6.1.0", + "parse-path": "^4.0.0", + "protocols": "^1.4.0" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "node_modules/parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pidusage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.0.tgz", + "integrity": "sha512-8VJLToXhj+RYZGNVw8oxc7dS54iCQXUJ+MDFHezQ/fwF5B8W4OWodAMboc1wb08S/4LiHwAmkT4ohf/d3YPPsw==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pidusage/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pm2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.0.tgz", + "integrity": "sha512-PO5hMVhQ85cTszFM++6v07Me9hPJMkFbHjkFigtMMk+La8ty2wCi2dlBTeZYJDhPUSjK8Ccltpq2buNRcyMOTw==", + "dev": true, + "dependencies": { + "@pm2/agent": "~2.0.0", + "@pm2/io": "~5.0.0", + "@pm2/js-api": "~0.6.7", + "@pm2/pm2-version-check": "latest", + "async": "~3.2.0", + "blessed": "0.1.81", + "chalk": "3.0.0", + "chokidar": "^3.5.1", + "cli-tableau": "^2.0.0", + "commander": "2.15.1", + "croner": "~4.1.92", + "dayjs": "~1.8.25", + "debug": "^4.3.1", + "enquirer": "2.3.6", + "eventemitter2": "5.0.1", + "fclone": "1.0.11", + "mkdirp": "1.0.4", + "needle": "2.4.0", + "pidusage": "~3.0", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.1", + "pm2-deploy": "~1.0.2", + "pm2-multimeter": "^0.1.2", + "promptly": "^2", + "semver": "^7.2", + "source-map-support": "0.5.19", + "sprintf-js": "1.1.2", + "vizion": "~2.2.1", + "yamljs": "0.3.0" + }, + "bin": { + "pm2": "bin/pm2", + "pm2-dev": "bin/pm2-dev", + "pm2-docker": "bin/pm2-docker", + "pm2-runtime": "bin/pm2-runtime" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "pm2-sysmonit": "^1.2.8" + } + }, + "node_modules/pm2-axon": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pm2-axon/-/pm2-axon-4.0.1.tgz", + "integrity": "sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg==", + "dev": true, + "dependencies": { + "amp": "~0.3.1", + "amp-message": "~0.1.1", + "debug": "^4.3.1", + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=5" + } + }, + "node_modules/pm2-axon-rpc": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/pm2-axon-rpc/-/pm2-axon-rpc-0.7.1.tgz", + "integrity": "sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw==", + "dev": true, + "dependencies": { + "debug": "^4.3.1" + }, + "engines": { + "node": ">=5" + } + }, + "node_modules/pm2-deploy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pm2-deploy/-/pm2-deploy-1.0.2.tgz", + "integrity": "sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg==", + "dev": true, + "dependencies": { + "run-series": "^1.1.8", + "tv4": "^1.3.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pm2-multimeter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/pm2-multimeter/-/pm2-multimeter-0.1.2.tgz", + "integrity": "sha1-Gh5VFT1BoFU0zqI8/oYKuqDrSs4=", + "dev": true, + "dependencies": { + "charm": "~0.1.1" + } + }, + "node_modules/pm2-sysmonit": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/pm2-sysmonit/-/pm2-sysmonit-1.2.8.tgz", + "integrity": "sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==", + "dev": true, + "optional": true, + "dependencies": { + "async": "^3.2.0", + "debug": "^4.3.1", + "pidusage": "^2.0.21", + "systeminformation": "^5.7", + "tx2": "~1.0.4" + } + }, + "node_modules/pm2-sysmonit/node_modules/pidusage": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", + "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "dev": true, + "optional": true, + "dependencies": { + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pm2-sysmonit/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/pm2/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pm2/node_modules/commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "node_modules/pm2/node_modules/dayjs": { + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", + "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==", + "dev": true + }, + "node_modules/pm2/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pm2/node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/polished": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.1.3.tgz", + "integrity": "sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA==", + "dependencies": { + "@babel/runtime": "^7.14.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promptly": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/promptly/-/promptly-2.2.0.tgz", + "integrity": "sha1-KhP6BjaIoqWYOxYf/wEIoH0m/HQ=", + "dev": true, + "dependencies": { + "read": "^1.0.4" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/promzard": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", + "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", + "dev": true, + "dependencies": { + "read": "1" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/property-information": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz", + "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "node_modules/protocols": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz", + "integrity": "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/proxy-agent/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/query-string": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", + "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", + "dev": true, + "dependencies": { + "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, + "node_modules/react-helmet": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", + "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", + "dependencies": { + "object-assign": "^4.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.1.1", + "react-side-effect": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "peer": true + }, + "node_modules/react-markdown": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-7.0.0.tgz", + "integrity": "sha512-qdWfKxMgdKF3kHAV5pmcB12fAvytPoTpYwKTO6O/I3HujrK7sKIv6j4RnXVNLrNUh+TaBk+KtqpGzIKslX2rDg==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^17.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^9.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.3.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/react-markdown/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/react-router": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", + "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-dom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", + "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-dom/node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/react-router/node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/react-router/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/react-router/node_modules/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==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/react-router/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-side-effect": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz", + "integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==", + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/read-cmd-shim": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz", + "integrity": "sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw==", + "dev": true + }, + "node_modules/read-package-json": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-3.0.1.tgz", + "integrity": "sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng==", + "dev": true, + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", + "npm-normalize-package-bin": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "deprecated": "The functionality that this package provided is now in @npmcli/arborist", + "dev": true, + "dependencies": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "node_modules/read-package-tree/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-package-tree/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-package-tree/node_modules/read-package-json": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", + "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "dev": true, + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "node_modules/read-package-tree/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-pkg/node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-9.1.0.tgz", + "integrity": "sha512-oLa6YmgAYg19zb0ZrBACh40hpBLteYROaPLhBXzLgjqyHQrN+gVP9N/FJvfzuNNuzCutktkroXEZBrxAxKhh7Q==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^11.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", + "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.12.0" + } + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", + "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", + "dev": true, + "dependencies": { + "global-dirs": "^0.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true, + "engines": { + "node": "6.* || >= 7.*" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-series": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", + "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", + "dev": true, + "dependencies": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "bin": { + "sane": "src/cli.js" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/sane/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/sane/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/sane/node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/sane/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/sane/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sane/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/sane/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/sane/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", + "dev": true + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "dev": true + }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "dev": true + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/snapdragon/node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/socket.io": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", + "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.1.0", + "socket.io-adapter": "~2.3.3", + "socket.io-parser": "~4.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", + "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==" + }, + "node_modules/socket.io-client": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.1.tgz", + "integrity": "sha512-N5C/L5fLNha5Ojd7Yeb/puKcPWWcoB/A09fEjjNsg91EDVr5twk/OEyO6VT9dlLSUNY85NpW6KBhVMvaLKQ3vQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.0.0", + "backo2": "~1.0.2", + "debug": "~4.3.2", + "engine.io-client": "~6.1.1", + "parseuri": "0.0.6", + "socket.io-parser": "~4.1.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-client/node_modules/socket.io-parser": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.2.tgz", + "integrity": "sha512-j3kk71QLJuyQ/hh5F/L2t1goqzdTL0gvDzuhTuNSwihfuFUrcSji0qFZmJJPtG6Rmug153eOPsUizeirf1IIog==", + "dependencies": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", + "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "dependencies": { + "@types/component-emitter": "^1.2.10", + "component-emitter": "~1.3.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dev": true, + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sort-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz", + "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", + "dev": true, + "dependencies": { + "is-plain-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sort-keys/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "dev": true + }, + "node_modules/space-separated-tokens": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz", + "integrity": "sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "dev": true + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.padend": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz", + "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strong-log-transformer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", + "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.1", + "minimist": "^1.2.0", + "through": "^2.3.4" + }, + "bin": { + "sl-log-transformer": "bin/sl-log-transformer.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/styled-components": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.0.tgz", + "integrity": "sha512-bPJKwZCHjJPf/hwTJl6TbkSZg/3evha+XPEizrZUGb535jLImwDUdjTNxXqjjaASt2M4qO4AVfoHJNe3XB/tpQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^0.8.8", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-is": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/styled-components/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/styled-jsx": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-3.4.5.tgz", + "integrity": "sha512-I+IET7OO4MKI710Ez3FesauZkqRIpZFQuePru3+BiGbzksJiWaB1Jew4T/+3vHoMJ1RsTxlO1T+IGOMLaoGcrQ==", + "dependencies": { + "@babel/helper-module-imports": "7.12.5", + "@babel/types": "7.8.3", + "babel-plugin-syntax-jsx": "6.18.0", + "convert-source-map": "1.7.0", + "loader-utils": "1.2.3", + "source-map": "0.7.3", + "string-hash": "1.1.3", + "stylis": "3.5.4", + "stylis-rule-sheet": "0.0.10" + }, + "peerDependencies": { + "react": "15.x.x || 16.x.x || 17.x.x" + } + }, + "node_modules/styled-jsx/node_modules/@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "dependencies": { + "@babel/types": "^7.12.5" + } + }, + "node_modules/styled-jsx/node_modules/@babel/helper-module-imports/node_modules/@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/styled-jsx/node_modules/@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dependencies": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/styled-jsx/node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/styled-jsx/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/stylis": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz", + "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==" + }, + "node_modules/stylis-rule-sheet": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz", + "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==", + "peerDependencies": { + "stylis": "^3.5.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true + }, + "node_modules/swr": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/swr/-/swr-0.5.6.tgz", + "integrity": "sha512-Bmx3L4geMZjYT5S2Z6EE6/5Cx6v1Ka0LhqZKq8d6WL2eu9y6gHWz3dUzfIK/ymZVHVfwT/EweFXiYGgfifei3w==", + "dependencies": { + "dequal": "2.0.2" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/systeminformation": { + "version": "5.9.7", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.9.7.tgz", + "integrity": "sha512-Vcmc8HaWPMFM4DoasuKN2lpvIwS2AqaoPuEGZc4HCT6tlRJH+IQ5GhA2BrUgjpBDJjFMj2Bti6qLOzP3T1arCw==", + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos" + ], + "bin": { + "systeminformation": "lib/cli.js" + }, + "engines": { + "node": ">=4.0.0" + }, + "funding": { + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" + } + }, + "node_modules/table": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tail": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/tail/-/tail-2.2.4.tgz", + "integrity": "sha512-PX8klSxW1u3SdgDrDeewh5GNE+hkJ4h02JvHfV6YrHqWOVJ88nUdSQqtsUf/gWhgZlPAws3fiZ+F1f8euspcuQ==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/temp-write": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/temp-write/-/temp-write-4.0.0.tgz", + "integrity": "sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "is-stream": "^2.0.0", + "make-dir": "^3.0.0", + "temp-dir": "^1.0.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-write/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/tiny-invariant": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/tinycolor2": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==", + "engines": { + "node": "*" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-jest": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.5.tgz", + "integrity": "sha512-lIJApzfTaSSbtlksfFNHkWOzLJuuSm4faFAfo5kvzOiRAuoN4/eKxVJ2zEAho8aecE04qX6K1pAzfH5QHL1/8w==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^27.0.0", + "babel-jest": ">=27.0.0 <28", + "jest": "^27.0.0", + "typescript": ">=3.8 <5.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + } + } + }, + "node_modules/ts-node": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", + "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.6.1", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/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==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tv4": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", + "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "node_modules/tx2": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tx2/-/tx2-1.0.5.tgz", + "integrity": "sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg==", + "dev": true, + "optional": true, + "dependencies": { + "json-stringify-safe": "^5.0.1" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.15.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz", + "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uid-number": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/umask": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", + "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + }, + "node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/unified/node_modules/is-plain-obj": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.0.0.tgz", + "integrity": "sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/union-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unist-builder": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", + "integrity": "sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-generated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.0.tgz", + "integrity": "sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.3.tgz", + "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.0.tgz", + "integrity": "sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz", + "integrity": "sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "dev": true, + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "dev": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uvu": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.3.tgz", + "integrity": "sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw==", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/uvu/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/uvu/node_modules/kleur": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", + "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/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==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vfile": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.2.tgz", + "integrity": "sha512-w0PLIugRY3Crkgw89TeMvHCzqCs/zpreR31hl4D92y6SOE07+bfJe+dK5Q2akwS+i/c801kzjoOr9gMcTe6IAA==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", + "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/vizion": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vizion/-/vizion-2.2.1.tgz", + "integrity": "sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww==", + "dev": true, + "dependencies": { + "async": "^2.6.3", + "git-node-fs": "^1.0.0", + "ini": "^1.3.5", + "js-git": "^0.7.8" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vizion/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/vm2": { + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.9.tgz", + "integrity": "sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw==", + "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + }, + "bin": { + "vm2": "bin/vm2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/vm2/node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/vm2/node_modules/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==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-json-file": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-4.3.0.tgz", + "integrity": "sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ==", + "dev": true, + "dependencies": { + "detect-indent": "^6.0.0", + "graceful-fs": "^4.1.15", + "is-plain-obj": "^2.0.0", + "make-dir": "^3.0.0", + "sort-keys": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8.3" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/write-json-file/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/write-pkg": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz", + "integrity": "sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==", + "dev": true, + "dependencies": { + "sort-keys": "^2.0.0", + "type-fest": "^0.4.1", + "write-json-file": "^3.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/write-pkg/node_modules/detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/write-pkg/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/write-pkg/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/write-pkg/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/write-pkg/node_modules/sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/write-pkg/node_modules/type-fest": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", + "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/write-pkg/node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/write-pkg/node_modules/write-json-file": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz", + "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==", + "dev": true, + "dependencies": { + "detect-indent": "^5.0.0", + "graceful-fs": "^4.1.15", + "make-dir": "^2.1.0", + "pify": "^4.0.1", + "sort-keys": "^2.0.0", + "write-file-atomic": "^2.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "bin": { + "json2yaml": "bin/json2yaml", + "yaml2json": "bin/yaml2json" + } + }, + "node_modules/yamljs/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/yamljs/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/yargs": { + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", + "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.13.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.13.4.tgz", + "integrity": "sha512-LZRucWt4j/ru5azOkJxCfpR87IyFDn8h2UODdqvXzZLb3K7bb9chUrUIGTy3BPsr8XnbQYfQ5Md5Hu2OYIo1mg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "packages/tcore-api": { + "name": "@tago-io/tcore-api", + "version": "0.3.3", + "dependencies": { + "@tago-io/sdk": "10.4.4", + "@tago-io/tcore-sdk": "*", + "@tago-io/tcore-shared": "*", + "axios": "0.24.0", + "boxen": "5.1.2", + "chalk": "4.1.2", + "compression": "1.7.4", + "cors": "^2.8.5", + "dayjs": "1.10.1", + "debug": "4.3.2", + "express": "^4.17.1", + "extract-zip": "2.0.1", + "luxon": "2.0.2", + "md5": "2.3.0", + "method-override": "3.0.0", + "nanoid": "3.3.1", + "nodemon": "2.0.15", + "ora": "5.4.1", + "socket.io": "4.4.1", + "systeminformation": "5.9.7", + "tar": "6.1.11", + "zod": "3.13.4" + }, + "devDependencies": { + "@types/compression": "1.7.1", + "@types/cors": "2.8.12", + "@types/debug": "4.1.7", + "@types/express": "4.17.13", + "@types/jest": "27.0.1", + "@types/luxon": "1.27.1", + "@types/method-override": "0.0.32", + "@types/node": "16.7.1", + "@types/semver": "7.3.9", + "@types/tar": "6.1.0", + "@typescript-eslint/eslint-plugin": "4.29.3", + "@typescript-eslint/parser": "4.29.3", + "eslint": "7.32.0", + "eslint-config-prettier": "8.3.0", + "eslint-import-resolver-typescript": "2.4.0", + "eslint-plugin-import": "2.24.1", + "eslint-plugin-jest": "24.4.0", + "eslint-plugin-prettier": "3.4.1", + "jest": "27.0.6", + "prettier": "2.3.2", + "ts-jest": "27.0.5", + "ts-node": "10.2.1", + "typescript": "4.3.5" + } + }, + "packages/tcore-api/node_modules/luxon": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.0.2.tgz", + "integrity": "sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg==", + "engines": { + "node": "*" + } + }, + "packages/tcore-api/node_modules/typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "packages/tcore-cli": { + "name": "@tago-io/tcore-cli", + "version": "0.3.3", + "dependencies": { + "@tago-io/tcore-api": "*", + "@tago-io/tcore-sdk": "*", + "chalk": "4.1.2", + "commander": "^9.0.0", + "esbuild": "^0.14.23", + "ora": "5.4.1", + "tail": "2.2.4" + }, + "devDependencies": { + "@types/jest": "27.0.1", + "@types/node": "16.7.1", + "@types/semver": "7.3.9", + "@typescript-eslint/eslint-plugin": "4.29.3", + "@typescript-eslint/parser": "4.29.3", + "chalk": "4.1.2", + "eslint": "7.32.0", + "eslint-config-prettier": "8.3.0", + "eslint-import-resolver-typescript": "2.4.0", + "eslint-plugin-import": "2.24.1", + "eslint-plugin-jest": "24.4.0", + "eslint-plugin-prettier": "3.4.1", + "jest": "27.0.6", + "ora": "5.4.1", + "pm2": "^5.2.0", + "prettier": "2.3.2", + "socket.io-client": "4.4.1", + "ts-jest": "27.0.5", + "typescript": "4.3.5" + } + }, + "packages/tcore-cli/node_modules/typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "packages/tcore-console": { + "name": "@tago-io/tcore-console", + "version": "0.3.3", + "dependencies": { + "@antv/g2": "4.1.23", + "@tago-io/sdk": "10.4.4", + "@tago-io/tcore-sdk": "*", + "@tago-io/tcore-shared": "*", + "axios": "0.24.0", + "graphql": "16.0.1", + "lodash.clonedeep": "4.5.0", + "luxon": "2.0.1", + "mobx": "6.4.2", + "mobx-react": "7.3.0", + "polished": "4.1.3", + "qs": "6.10.1", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-helmet": "6.1.0", + "react-markdown": "7.0.0", + "react-router": "5.2.0", + "react-router-dom": "5.2.0", + "semver": "7.3.5", + "socket.io-client": "4.4.1", + "styled-components": "5.3.0", + "styled-jsx": "3.4.5", + "swr": "0.5.6", + "tinycolor2": "1.4.2", + "zod": "3.13.4" + }, + "devDependencies": { + "@svgr/core": "5.5.0", + "@testing-library/jest-dom": "5.14.1", + "@testing-library/react": "12.0.0", + "@types/jest": "27.0.1", + "@types/lodash.clonedeep": "4.5.6", + "@types/luxon": "1.27.1", + "@types/qs": "6.9.7", + "@types/react": "17.0.14", + "@types/react-dom": "17.0.9", + "@types/react-helmet": "6.1.4", + "@types/react-router": "5.1.16", + "@types/react-router-dom": "5.1.8", + "@types/semver": "7.3.9", + "@types/styled-components": "5.1.11", + "@types/tinycolor2": "1.4.3", + "@typescript-eslint/eslint-plugin": "4.29.0", + "@typescript-eslint/parser": "4.29.3", + "esbuild": "0.12.22", + "esbuild-jest": "0.5.0", + "eslint": "7.31.0", + "eslint-config-airbnb": "18.2.1", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-import": "2.23.4", + "eslint-plugin-jest": "24.4.0", + "eslint-plugin-jsx-a11y": "6.4.1", + "eslint-plugin-prettier": "3.4.0", + "eslint-plugin-react": "7.24.0", + "eslint-plugin-react-hooks": "4.2.0", + "jest": "27.0.6", + "jest-transform-stub": "2.0.0", + "prettier": "2.3.2", + "ts-jest": "27.0.5", + "typescript": "4.3.5" + } + }, + "packages/tcore-console/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "packages/tcore-console/node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz", + "integrity": "sha512-eiREtqWRZ8aVJcNru7cT/AMVnYd9a2UHsfZT8MR1dW3UUEg6jDv9EQ9Cq4CUPZesyQ58YUpoAADGv71jY8RwgA==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "4.29.0", + "@typescript-eslint/scope-manager": "4.29.0", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/tcore-console/node_modules/@typescript-eslint/experimental-utils": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.0.tgz", + "integrity": "sha512-FpNVKykfeaIxlArLUP/yQfv/5/3rhl1ov6RWgud4OgbqWLkEq7lqgQU9iiavZRzpzCRQV4XddyFz3wFXdkiX9w==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.29.0", + "@typescript-eslint/types": "4.29.0", + "@typescript-eslint/typescript-estree": "4.29.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "packages/tcore-console/node_modules/@typescript-eslint/scope-manager": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.0.tgz", + "integrity": "sha512-HPq7XAaDMM3DpmuijxLV9Io8/6pQnliiXMQUcAdjpJJSR+fdmbD/zHCd7hMkjJn04UQtCQBtshgxClzg6NIS2w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.29.0", + "@typescript-eslint/visitor-keys": "4.29.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/tcore-console/node_modules/@typescript-eslint/types": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.0.tgz", + "integrity": "sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/tcore-console/node_modules/@typescript-eslint/typescript-estree": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.0.tgz", + "integrity": "sha512-8ZpNHDIOyqzzgZrQW9+xQ4k5hM62Xy2R4RPO3DQxMc5Rq5QkCdSpk/drka+DL9w6sXNzV5nrdlBmf8+x495QXQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.29.0", + "@typescript-eslint/visitor-keys": "4.29.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/tcore-console/node_modules/@typescript-eslint/visitor-keys": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.0.tgz", + "integrity": "sha512-LoaofO1C/jAJYs0uEpYMXfHboGXzOJeV118X4OsZu9f7rG7Pr9B3+4HTU8+err81rADa4xfQmAxnRnPAI2jp+Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.29.0", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/tcore-console/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "packages/tcore-console/node_modules/esbuild": { + "version": "0.12.22", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.22.tgz", + "integrity": "sha512-yWCr9RoFehpqoe/+MwZXJpYOEIt7KOEvNnjIeMZpMSyQt+KCBASM3y7yViiN5dJRphf1wGdUz1+M4rTtWd/ulA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + } + }, + "packages/tcore-console/node_modules/eslint": { + "version": "7.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.31.0.tgz", + "integrity": "sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/tcore-console/node_modules/eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "packages/tcore-console/node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "packages/tcore-console/node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "packages/tcore-console/node_modules/eslint-plugin-prettier": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=5.0.0", + "prettier": ">=1.13.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "packages/tcore-console/node_modules/eslint/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "packages/tcore-console/node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "packages/tcore-console/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "packages/tcore-console/node_modules/globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/tcore-console/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "packages/tcore-console/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "packages/tcore-console/node_modules/luxon": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.0.1.tgz", + "integrity": "sha512-8Eawf81c9ZlQj62W3eq4mp+C7SAIAnmaS7ZuEAiX503YMcn+0C1JnMQRtfaQj6B5qTZLgHv0F4H5WabBCvi1fw==", + "engines": { + "node": "*" + } + }, + "packages/tcore-console/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "packages/tcore-console/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "packages/tcore-console/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "packages/tcore-console/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "packages/tcore-console/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "packages/tcore-console/node_modules/typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "packages/tcore-sdk": { + "name": "@tago-io/tcore-sdk", + "version": "0.3.3", + "dependencies": { + "chalk": "4.1.2", + "commander": "9.1.0", + "glob": "7.2.0", + "image-size": "1.0.1", + "luxon": "2.3.0", + "nanoid": "^3.1.32", + "ora": "5.4.1", + "semver": "7.3.5", + "tar": "6.1.11", + "uuid": "^8.3.2", + "zod": "3.13.4" + }, + "bin": { + "tcore-plugin": "build/Bin/Bin.js" + }, + "devDependencies": { + "@types/commander": "2.12.2", + "@types/glob": "7.2.0", + "@types/jest": "27.0.1", + "@types/luxon": "2.0.9", + "@types/node": "16.7.1", + "@types/semver": "7.3.9", + "@types/tar": "6.1.1", + "@types/uuid": "^8.3.1", + "@typescript-eslint/eslint-plugin": "4.31.2", + "@typescript-eslint/parser": "4.29.3", + "eslint": "7.32.0", + "eslint-config-prettier": "8.3.0", + "eslint-import-resolver-typescript": "2.4.0", + "eslint-plugin-import": "2.24.1", + "eslint-plugin-prettier": "3.4.1", + "jest": "27.0.6", + "prettier": "2.3.2", + "ts-jest": "27.0.5", + "typescript": "4.3.5" + } + }, + "packages/tcore-sdk/node_modules/@types/luxon": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.0.9.tgz", + "integrity": "sha512-ZuzIc7aN+i2ZDMWIiSmMdubR9EMMSTdEzF6R+FckP4p6xdnOYKqknTo/k+xXQvciSXlNGIwA4OPU5X7JIFzYdA==", + "dev": true + }, + "packages/tcore-sdk/node_modules/@types/tar": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/tar/-/tar-6.1.1.tgz", + "integrity": "sha512-8mto3YZfVpqB1CHMaYz1TUYIQfZFbh/QbEq5Hsn6D0ilCfqRVCdalmc89B7vi3jhl9UYIk+dWDABShNfOkv5HA==", + "dev": true, + "dependencies": { + "@types/minipass": "*", + "@types/node": "*" + } + }, + "packages/tcore-sdk/node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.2.tgz", + "integrity": "sha512-w63SCQ4bIwWN/+3FxzpnWrDjQRXVEGiTt9tJTRptRXeFvdZc/wLiz3FQUwNQ2CVoRGI6KUWMNUj/pk63noUfcA==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "4.31.2", + "@typescript-eslint/scope-manager": "4.31.2", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/tcore-sdk/node_modules/@typescript-eslint/experimental-utils": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.2.tgz", + "integrity": "sha512-3tm2T4nyA970yQ6R3JZV9l0yilE2FedYg8dcXrTar34zC9r6JB7WyBQbpIVongKPlhEMjhQ01qkwrzWy38Bk1Q==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.31.2", + "@typescript-eslint/types": "4.31.2", + "@typescript-eslint/typescript-estree": "4.31.2", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "packages/tcore-sdk/node_modules/@typescript-eslint/scope-manager": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz", + "integrity": "sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.31.2", + "@typescript-eslint/visitor-keys": "4.31.2" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/tcore-sdk/node_modules/@typescript-eslint/types": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.2.tgz", + "integrity": "sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/tcore-sdk/node_modules/@typescript-eslint/typescript-estree": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz", + "integrity": "sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.31.2", + "@typescript-eslint/visitor-keys": "4.31.2", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/tcore-sdk/node_modules/@typescript-eslint/visitor-keys": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz", + "integrity": "sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.31.2", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/tcore-sdk/node_modules/commander": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.1.0.tgz", + "integrity": "sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "packages/tcore-sdk/node_modules/luxon": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.3.0.tgz", + "integrity": "sha512-gv6jZCV+gGIrVKhO90yrsn8qXPKD8HYZJtrUDSfEbow8Tkw84T9OnCyJhWvnJIaIF/tBuiAjZuQHUt1LddX2mg==", + "engines": { + "node": ">=12" + } + }, + "packages/tcore-sdk/node_modules/typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "packages/tcore-shared": { + "name": "@tago-io/tcore-shared", + "version": "0.3.3", + "dependencies": { + "@tago-io/tcore-sdk": "*" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@antv/adjust": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.2.5.tgz", + "integrity": "sha512-MfWZOkD9CqXRES6MBGRNe27Q577a72EIwyMnE29wIlPliFvJfWwsrONddpGU7lilMpVKecS3WAzOoip3RfPTRQ==", + "requires": { + "@antv/util": "~2.0.0", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@antv/attr": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.3.3.tgz", + "integrity": "sha512-7iSSRhYzZ7pYXZKTL1ECGhTdKVHPQx1Vj7yYVTAiyLMsWsLUAoMf0m6dT6msTs0SdrXHRbjzXavVXxRj/wZZJA==", + "requires": { + "@antv/color-util": "^2.0.1", + "@antv/util": "~2.0.0", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@antv/color-util": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@antv/color-util/-/color-util-2.0.6.tgz", + "integrity": "sha512-KnPEaAH+XNJMjax9U35W67nzPI+QQ2x27pYlzmSIWrbj4/k8PGrARXfzDTjwoozHJY8qG62Z+Ww6Alhu2FctXQ==", + "requires": { + "@antv/util": "^2.0.9", + "tslib": "^2.0.3" + } + }, + "@antv/component": { + "version": "0.8.27", + "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.8.27.tgz", + "integrity": "sha512-FY9fgUBjEuWxQ4w7VbcMSwFr7pqnRf1/F1ja1weoEpNndKBlStNYWhXTx4p5uMJVLvMpXoFPqan7RzyP8rel6Q==", + "requires": { + "@antv/color-util": "^2.0.3", + "@antv/dom-util": "~2.0.1", + "@antv/g-base": "^0.5.9", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "~2.0.7", + "@antv/scale": "~0.3.1", + "@antv/util": "~2.0.0", + "fecha": "~4.2.0", + "tslib": "^2.0.3" + } + }, + "@antv/coord": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.3.1.tgz", + "integrity": "sha512-rFE94C8Xzbx4xmZnHh2AnlB3Qm1n5x0VT3OROy257IH6Rm4cuzv1+tZaUBATviwZd99S+rOY9telw/+6C9GbRw==", + "requires": { + "@antv/matrix-util": "^3.1.0-beta.2", + "@antv/util": "~2.0.12", + "tslib": "^2.1.0" + } + }, + "@antv/dom-util": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@antv/dom-util/-/dom-util-2.0.4.tgz", + "integrity": "sha512-2shXUl504fKwt82T3GkuT4Uoc6p9qjCKnJ8gXGLSW4T1W37dqf9AV28aCfoVPHp2BUXpSsB+PAJX2rG/jLHsLQ==", + "requires": { + "tslib": "^2.0.3" + } + }, + "@antv/event-emitter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@antv/event-emitter/-/event-emitter-0.1.3.tgz", + "integrity": "sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==" + }, + "@antv/g-base": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/@antv/g-base/-/g-base-0.5.11.tgz", + "integrity": "sha512-10Hkq7XksVCqxZZrPkd6HTU9tb/+2meCVEMy/edhS4I/sokhcgC9m3fQP5bE8rA3EVKwELE7MJHZ98BEpVFqvQ==", + "requires": { + "@antv/event-emitter": "^0.1.1", + "@antv/g-math": "^0.1.6", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "~2.0.5", + "@antv/util": "~2.0.13", + "@types/d3-timer": "^2.0.0", + "d3-ease": "^1.0.5", + "d3-interpolate": "^1.3.2", + "d3-timer": "^1.0.9", + "detect-browser": "^5.1.0", + "tslib": "^2.0.3" + } + }, + "@antv/g-canvas": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-0.5.12.tgz", + "integrity": "sha512-iJ/muwwqCCNONVlPIzv/7OL5iLguaKRj2BxNMytUO3TWwamM+kHkiyYEOkS0dPn9h/hBsHYlLUluSVz2Fp6/bw==", + "requires": { + "@antv/g-base": "^0.5.3", + "@antv/g-math": "^0.1.6", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "~2.0.5", + "@antv/util": "~2.0.0", + "gl-matrix": "^3.0.0", + "tslib": "^2.0.3" + } + }, + "@antv/g-math": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@antv/g-math/-/g-math-0.1.7.tgz", + "integrity": "sha512-xGyXaloD1ynfp7gS4VuV+MjSptZIwHvLHr8ekXJSFAeWPYLu84yOW2wOZHDdp1bzDAIuRv6xDBW58YGHrWsFcA==", + "requires": { + "@antv/util": "~2.0.0", + "gl-matrix": "^3.0.0" + } + }, + "@antv/g-svg": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@antv/g-svg/-/g-svg-0.5.6.tgz", + "integrity": "sha512-Xve1EUGk4HMbl2nq4ozR4QLh6GyoZ8Xw/+9kHYI4B5P2lIUQU95MuRsaLFfW5NNpZDx85ZeH97tqEmC9L96E7A==", + "requires": { + "@antv/g-base": "^0.5.3", + "@antv/g-math": "^0.1.6", + "@antv/util": "~2.0.0", + "detect-browser": "^5.0.0", + "tslib": "^2.0.3" + } + }, + "@antv/g2": { + "version": "4.1.23", + "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-4.1.23.tgz", + "integrity": "sha512-xteff5XFXb4pdI/+9qeuKKqk3jnyecoTPX/hnarmHPnAWkyXL0K1wfFSvNPUxqtn+0FMYyL8VNIdIaGUestVOA==", + "requires": { + "@antv/adjust": "^0.2.1", + "@antv/attr": "^0.3.1", + "@antv/color-util": "^2.0.2", + "@antv/component": "^0.8.7", + "@antv/coord": "^0.3.0", + "@antv/dom-util": "^2.0.2", + "@antv/event-emitter": "~0.1.0", + "@antv/g-base": "~0.5.6", + "@antv/g-canvas": "~0.5.10", + "@antv/g-svg": "~0.5.6", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "^2.0.3", + "@antv/scale": "^0.3.7", + "@antv/util": "~2.0.5", + "tslib": "^2.0.0" + } + }, + "@antv/matrix-util": { + "version": "3.1.0-beta.3", + "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.1.0-beta.3.tgz", + "integrity": "sha512-W2R6Za3A6CmG51Y/4jZUM/tFgYSq7vTqJL1VD9dKrvwxS4sE0ZcXINtkp55CdyBwJ6Cwm8pfoRpnD4FnHahN0A==", + "requires": { + "@antv/util": "^2.0.9", + "gl-matrix": "^3.4.3", + "tslib": "^2.0.3" + } + }, + "@antv/path-util": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", + "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", + "requires": { + "@antv/matrix-util": "^3.0.4", + "@antv/util": "^2.0.9", + "tslib": "^2.0.3" + }, + "dependencies": { + "@antv/matrix-util": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", + "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", + "requires": { + "@antv/util": "^2.0.9", + "gl-matrix": "^3.3.0", + "tslib": "^2.0.3" + } + } + } + }, + "@antv/scale": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.3.17.tgz", + "integrity": "sha512-YjPYG2Lbhou2cnle4MTlsq45dUVjP5tiGG/pYNIerE1sSBqFnC0/7tf9ZWp5OaHZH/qHNX8IfKeQdWHZDR4kDw==", + "requires": { + "@antv/util": "~2.0.3", + "fecha": "~4.2.0", + "tslib": "^2.0.0" + } + }, + "@antv/util": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.17.tgz", + "integrity": "sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==", + "requires": { + "csstype": "^3.0.8", + "tslib": "^2.0.3" + } + }, + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/compat-data": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz", + "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==", + "dev": true + }, + "@babel/core": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.9.tgz", + "integrity": "sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.9", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.9", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.9.tgz", + "integrity": "sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==", + "requires": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz", + "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", + "requires": { + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" + }, + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true + }, + "@babel/helpers": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", + "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", + "dev": true, + "requires": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0" + } + }, + "@babel/highlight": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "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==", + "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==", + "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==", + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz", + "integrity": "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==" + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz", + "integrity": "sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/runtime": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.9.tgz", + "integrity": "sha512-WxYHHUWF2uZ7Hp1K+D1xQgbgkGUfA+5UPOegEXGt2Y5SMog/rYCVaifLZDbw8UkNXozEqqrZTy6bglL7xTaCOw==", + "dev": true, + "requires": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/traverse": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.9.tgz", + "integrity": "sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==", + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.9", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.9", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@commitlint/cli": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-15.0.0.tgz", + "integrity": "sha512-Y5xmDCweytqzo4N4lOI2YRiuX35xTjcs8n5hUceBH8eyK0YbwtgWX50BJOH2XbkwEmII9blNhlBog6AdQsqicg==", + "dev": true, + "requires": { + "@commitlint/format": "^15.0.0", + "@commitlint/lint": "^15.0.0", + "@commitlint/load": "^15.0.0", + "@commitlint/read": "^15.0.0", + "@commitlint/types": "^15.0.0", + "lodash": "^4.17.19", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0", + "yargs": "^17.0.0" + } + }, + "@commitlint/config-conventional": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-15.0.0.tgz", + "integrity": "sha512-eZBRL8Lk3hMNHp1wUMYj0qrZQEsST1ai7KHR8J1IDD9aHgT7L2giciibuQ+Og7vxVhR5WtYDvh9xirXFVPaSkQ==", + "dev": true, + "requires": { + "conventional-changelog-conventionalcommits": "^4.3.1" + } + }, + "@commitlint/ensure": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-15.0.0.tgz", + "integrity": "sha512-7DV4iNIald3vycwaWBNGk5FbonaNzOlU8nBe5m5AgU2dIeNKuXwLm+zzJzG27j0Ho56rgz//3F6RIvmsoxY9ZA==", + "dev": true, + "requires": { + "@commitlint/types": "^15.0.0", + "lodash": "^4.17.19" + } + }, + "@commitlint/execute-rule": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-15.0.0.tgz", + "integrity": "sha512-pyE4ApxjbWhb1TXz5vRiGwI2ssdMMgZbaaheZq1/7WC0xRnqnIhE1yUC1D2q20qPtvkZPstTYvMiRVtF+DvjUg==", + "dev": true + }, + "@commitlint/format": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-15.0.0.tgz", + "integrity": "sha512-bPhAfqwRhPk92WiuY0ktEJNpRRHSCd+Eg1MdhGyL9Bl3U25E5zvuInA+dNctnzZiOBSH/37ZaD0eOKCpQE6acg==", + "dev": true, + "requires": { + "@commitlint/types": "^15.0.0", + "chalk": "^4.0.0" + } + }, + "@commitlint/is-ignored": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-15.0.0.tgz", + "integrity": "sha512-edtnkf2QZ/7e/YCJDgn1WDw9wfF1WfOitW5YEoSOb4SxjJEb/oE87kxNPZ2j8mnDMuunspcMfGHeg6fRlwaEWg==", + "dev": true, + "requires": { + "@commitlint/types": "^15.0.0", + "semver": "7.3.5" + } + }, + "@commitlint/lint": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-15.0.0.tgz", + "integrity": "sha512-hUi2+Im/2dJ5FBvWnodypTkg+5haCgsDzB0fyMApWLUA1IucYUAqRCQCW5em1Mhk9Crw1pd5YzFNikhIclkqCw==", + "dev": true, + "requires": { + "@commitlint/is-ignored": "^15.0.0", + "@commitlint/parse": "^15.0.0", + "@commitlint/rules": "^15.0.0", + "@commitlint/types": "^15.0.0" + } + }, + "@commitlint/load": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-15.0.0.tgz", + "integrity": "sha512-Ak1YPeOhvxmY3ioe0o6m1yLGvUAYb4BdfGgShU8jiTCmU3Mnmms0Xh/kfQz8AybhezCC3AmVTyBLaBZxOHR8kg==", + "dev": true, + "requires": { + "@commitlint/execute-rule": "^15.0.0", + "@commitlint/resolve-extends": "^15.0.0", + "@commitlint/types": "^15.0.0", + "@endemolshinegroup/cosmiconfig-typescript-loader": "^3.0.2", + "chalk": "^4.0.0", + "cosmiconfig": "^7.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0", + "typescript": "^4.4.3" + } + }, + "@commitlint/message": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-15.0.0.tgz", + "integrity": "sha512-L8euabzboKavPuDJsdIYAY2wx97LbiGEYsckMo6NmV8pOun50c8hQx6ouXFSAx4pp+mX9yUGmMiVqfrk2LKDJQ==", + "dev": true + }, + "@commitlint/parse": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-15.0.0.tgz", + "integrity": "sha512-7fweM67tZfBNS7zw1KTuuT5K2u9nGytUJqFqT/1Ln3Na9cBCsoAqR47mfsNOTlRCgGwakm4xiQ7BpS2gN0OGuw==", + "dev": true, + "requires": { + "@commitlint/types": "^15.0.0", + "conventional-changelog-angular": "^5.0.11", + "conventional-commits-parser": "^3.2.2" + } + }, + "@commitlint/read": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-15.0.0.tgz", + "integrity": "sha512-5yI1o2HKZFVe7RTjL7IhuhHMKar/MDNY34vEHqqz9gMI7BK/rdP8uVb4Di1efl2V0UPnwID0nPKWESjQ8Ti0gw==", + "dev": true, + "requires": { + "@commitlint/top-level": "^15.0.0", + "@commitlint/types": "^15.0.0", + "fs-extra": "^10.0.0", + "git-raw-commits": "^2.0.0" + } + }, + "@commitlint/resolve-extends": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-15.0.0.tgz", + "integrity": "sha512-7apfRJjgJsKja7lHsPfEFixKjA/fk/UeD3owkOw1174yYu4u8xBDLSeU3IinGPdMuF9m245eX8wo7vLUy+EBSg==", + "dev": true, + "requires": { + "import-fresh": "^3.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0" + } + }, + "@commitlint/rules": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-15.0.0.tgz", + "integrity": "sha512-SqXfp6QUlwBS+0IZm4FEA/NmmAwcFQIkG3B05BtemOVWXQdZ8j1vV6hDwvA9oMPCmUSrrGpHOtZK7HaHhng2yA==", + "dev": true, + "requires": { + "@commitlint/ensure": "^15.0.0", + "@commitlint/message": "^15.0.0", + "@commitlint/to-lines": "^15.0.0", + "@commitlint/types": "^15.0.0", + "execa": "^5.0.0" + } + }, + "@commitlint/to-lines": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-15.0.0.tgz", + "integrity": "sha512-mY3MNA9ujPqVpiJjTYG9MDsYCobue5PJFO0MfcIzS1mCVvngH8ZFTPAh1fT5t+t1h876boS88+9WgqjRvbYItw==", + "dev": true + }, + "@commitlint/top-level": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-15.0.0.tgz", + "integrity": "sha512-7Gz3t7xcuuUw1d1Nou6YLaztzp2Em+qZ6YdCzrqYc+aquca3Vt0O696nuiBDU/oE+tls4Hx2CNpAbWhTgEwB5A==", + "dev": true, + "requires": { + "find-up": "^5.0.0" + } + }, + "@commitlint/types": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-15.0.0.tgz", + "integrity": "sha512-OMSLX+QJnyNoTwws54ULv9sOvuw9GdVezln76oyUd4YbMMJyaav62aSXDuCdWyL2sm9hTkSzyEi52PNaIj/vqw==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", + "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", + "dev": true, + "requires": { + "@cspotcode/source-map-consumer": "0.8.0" + } + }, + "@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "requires": { + "@emotion/memoize": "0.7.4" + } + }, + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "@endemolshinegroup/cosmiconfig-typescript-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz", + "integrity": "sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==", + "dev": true, + "requires": { + "lodash.get": "^4", + "make-error": "^1", + "ts-node": "^9", + "tslib": "^2" + }, + "dependencies": { + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@hutson/parse-repository-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", + "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + } + }, + "@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + } + }, + "@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + } + }, + "@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dev": true, + "requires": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + } + }, + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.6.tgz", + "integrity": "sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.0.tgz", + "integrity": "sha512-SfJxIxNVYLTsKwzB3MoOQ1yxf4w/E6MdkvTgrgAt1bfxjSrLUoHMKrDOykwN14q65waezZIdqDneUIPh4/sKxg==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@lerna/add": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/add/-/add-4.0.0.tgz", + "integrity": "sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng==", + "dev": true, + "requires": { + "@lerna/bootstrap": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/npm-conf": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "npm-package-arg": "^8.1.0", + "p-map": "^4.0.0", + "pacote": "^11.2.6", + "semver": "^7.3.4" + } + }, + "@lerna/bootstrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-4.0.0.tgz", + "integrity": "sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw==", + "dev": true, + "requires": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/has-npm-version": "4.0.0", + "@lerna/npm-install": "4.0.0", + "@lerna/package-graph": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/rimraf-dir": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/symlink-binary": "4.0.0", + "@lerna/symlink-dependencies": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "get-port": "^5.1.1", + "multimatch": "^5.0.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1", + "read-package-tree": "^5.3.1", + "semver": "^7.3.4" + } + }, + "@lerna/changed": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-4.0.0.tgz", + "integrity": "sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ==", + "dev": true, + "requires": { + "@lerna/collect-updates": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/listable": "4.0.0", + "@lerna/output": "4.0.0" + } + }, + "@lerna/check-working-tree": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz", + "integrity": "sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q==", + "dev": true, + "requires": { + "@lerna/collect-uncommitted": "4.0.0", + "@lerna/describe-ref": "4.0.0", + "@lerna/validation-error": "4.0.0" + } + }, + "@lerna/child-process": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-4.0.0.tgz", + "integrity": "sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "execa": "^5.0.0", + "strong-log-transformer": "^2.1.0" + } + }, + "@lerna/clean": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-4.0.0.tgz", + "integrity": "sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA==", + "dev": true, + "requires": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/rimraf-dir": "4.0.0", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1" + } + }, + "@lerna/cli": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/cli/-/cli-4.0.0.tgz", + "integrity": "sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA==", + "dev": true, + "requires": { + "@lerna/global-options": "4.0.0", + "dedent": "^0.7.0", + "npmlog": "^4.1.2", + "yargs": "^16.2.0" + }, + "dependencies": { + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "@lerna/collect-uncommitted": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz", + "integrity": "sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "chalk": "^4.1.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/collect-updates": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-4.0.0.tgz", + "integrity": "sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@lerna/describe-ref": "4.0.0", + "minimatch": "^3.0.4", + "npmlog": "^4.1.2", + "slash": "^3.0.0" + } + }, + "@lerna/command": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/command/-/command-4.0.0.tgz", + "integrity": "sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@lerna/package-graph": "4.0.0", + "@lerna/project": "4.0.0", + "@lerna/validation-error": "4.0.0", + "@lerna/write-log-file": "4.0.0", + "clone-deep": "^4.0.1", + "dedent": "^0.7.0", + "execa": "^5.0.0", + "is-ci": "^2.0.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/conventional-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz", + "integrity": "sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw==", + "dev": true, + "requires": { + "@lerna/validation-error": "4.0.0", + "conventional-changelog-angular": "^5.0.12", + "conventional-changelog-core": "^4.2.2", + "conventional-recommended-bump": "^6.1.0", + "fs-extra": "^9.1.0", + "get-stream": "^6.0.0", + "lodash.template": "^4.5.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "pify": "^5.0.0", + "semver": "^7.3.4" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/create": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-4.0.0.tgz", + "integrity": "sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/npm-conf": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "init-package-json": "^2.0.2", + "npm-package-arg": "^8.1.0", + "p-reduce": "^2.1.0", + "pacote": "^11.2.6", + "pify": "^5.0.0", + "semver": "^7.3.4", + "slash": "^3.0.0", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0", + "whatwg-url": "^8.4.0", + "yargs-parser": "20.2.4" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/create-symlink": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-4.0.0.tgz", + "integrity": "sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig==", + "dev": true, + "requires": { + "cmd-shim": "^4.1.0", + "fs-extra": "^9.1.0", + "npmlog": "^4.1.2" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/describe-ref": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-4.0.0.tgz", + "integrity": "sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/diff/-/diff-4.0.0.tgz", + "integrity": "sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/validation-error": "4.0.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/exec": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-4.0.0.tgz", + "integrity": "sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/profiler": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/validation-error": "4.0.0", + "p-map": "^4.0.0" + } + }, + "@lerna/filter-options": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-4.0.0.tgz", + "integrity": "sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw==", + "dev": true, + "requires": { + "@lerna/collect-updates": "4.0.0", + "@lerna/filter-packages": "4.0.0", + "dedent": "^0.7.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/filter-packages": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-4.0.0.tgz", + "integrity": "sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA==", + "dev": true, + "requires": { + "@lerna/validation-error": "4.0.0", + "multimatch": "^5.0.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/get-npm-exec-opts": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz", + "integrity": "sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ==", + "dev": true, + "requires": { + "npmlog": "^4.1.2" + } + }, + "@lerna/get-packed": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-4.0.0.tgz", + "integrity": "sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w==", + "dev": true, + "requires": { + "fs-extra": "^9.1.0", + "ssri": "^8.0.1", + "tar": "^6.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/github-client": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/github-client/-/github-client-4.0.0.tgz", + "integrity": "sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@octokit/plugin-enterprise-rest": "^6.0.1", + "@octokit/rest": "^18.1.0", + "git-url-parse": "^11.4.4", + "npmlog": "^4.1.2" + } + }, + "@lerna/gitlab-client": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz", + "integrity": "sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA==", + "dev": true, + "requires": { + "node-fetch": "^2.6.1", + "npmlog": "^4.1.2", + "whatwg-url": "^8.4.0" + } + }, + "@lerna/global-options": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/global-options/-/global-options-4.0.0.tgz", + "integrity": "sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ==", + "dev": true + }, + "@lerna/has-npm-version": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz", + "integrity": "sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "semver": "^7.3.4" + } + }, + "@lerna/import": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/import/-/import-4.0.0.tgz", + "integrity": "sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "fs-extra": "^9.1.0", + "p-map-series": "^2.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/info": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/info/-/info-4.0.0.tgz", + "integrity": "sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q==", + "dev": true, + "requires": { + "@lerna/command": "4.0.0", + "@lerna/output": "4.0.0", + "envinfo": "^7.7.4" + } + }, + "@lerna/init": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/init/-/init-4.0.0.tgz", + "integrity": "sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0", + "write-json-file": "^4.3.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/link/-/link-4.0.0.tgz", + "integrity": "sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w==", + "dev": true, + "requires": { + "@lerna/command": "4.0.0", + "@lerna/package-graph": "4.0.0", + "@lerna/symlink-dependencies": "4.0.0", + "p-map": "^4.0.0", + "slash": "^3.0.0" + } + }, + "@lerna/list": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/list/-/list-4.0.0.tgz", + "integrity": "sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg==", + "dev": true, + "requires": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/listable": "4.0.0", + "@lerna/output": "4.0.0" + } + }, + "@lerna/listable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/listable/-/listable-4.0.0.tgz", + "integrity": "sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ==", + "dev": true, + "requires": { + "@lerna/query-graph": "4.0.0", + "chalk": "^4.1.0", + "columnify": "^1.5.4" + } + }, + "@lerna/log-packed": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-4.0.0.tgz", + "integrity": "sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ==", + "dev": true, + "requires": { + "byte-size": "^7.0.0", + "columnify": "^1.5.4", + "has-unicode": "^2.0.1", + "npmlog": "^4.1.2" + } + }, + "@lerna/npm-conf": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-4.0.0.tgz", + "integrity": "sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw==", + "dev": true, + "requires": { + "config-chain": "^1.1.12", + "pify": "^5.0.0" + } + }, + "@lerna/npm-dist-tag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz", + "integrity": "sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw==", + "dev": true, + "requires": { + "@lerna/otplease": "4.0.0", + "npm-package-arg": "^8.1.0", + "npm-registry-fetch": "^9.0.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/npm-install": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-4.0.0.tgz", + "integrity": "sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@lerna/get-npm-exec-opts": "4.0.0", + "fs-extra": "^9.1.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "signal-exit": "^3.0.3", + "write-pkg": "^4.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/npm-publish": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-4.0.0.tgz", + "integrity": "sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w==", + "dev": true, + "requires": { + "@lerna/otplease": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "fs-extra": "^9.1.0", + "libnpmpublish": "^4.0.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "pify": "^5.0.0", + "read-package-json": "^3.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/npm-run-script": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz", + "integrity": "sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "@lerna/get-npm-exec-opts": "4.0.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/otplease": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/otplease/-/otplease-4.0.0.tgz", + "integrity": "sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw==", + "dev": true, + "requires": { + "@lerna/prompt": "4.0.0" + } + }, + "@lerna/output": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/output/-/output-4.0.0.tgz", + "integrity": "sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w==", + "dev": true, + "requires": { + "npmlog": "^4.1.2" + } + }, + "@lerna/pack-directory": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-4.0.0.tgz", + "integrity": "sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ==", + "dev": true, + "requires": { + "@lerna/get-packed": "4.0.0", + "@lerna/package": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "npm-packlist": "^2.1.4", + "npmlog": "^4.1.2", + "tar": "^6.1.0", + "temp-write": "^4.0.0" + } + }, + "@lerna/package": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/package/-/package-4.0.0.tgz", + "integrity": "sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q==", + "dev": true, + "requires": { + "load-json-file": "^6.2.0", + "npm-package-arg": "^8.1.0", + "write-pkg": "^4.0.0" + } + }, + "@lerna/package-graph": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-4.0.0.tgz", + "integrity": "sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw==", + "dev": true, + "requires": { + "@lerna/prerelease-id-from-version": "4.0.0", + "@lerna/validation-error": "4.0.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "semver": "^7.3.4" + } + }, + "@lerna/prerelease-id-from-version": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz", + "integrity": "sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg==", + "dev": true, + "requires": { + "semver": "^7.3.4" + } + }, + "@lerna/profiler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/profiler/-/profiler-4.0.0.tgz", + "integrity": "sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q==", + "dev": true, + "requires": { + "fs-extra": "^9.1.0", + "npmlog": "^4.1.2", + "upath": "^2.0.1" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/project": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/project/-/project-4.0.0.tgz", + "integrity": "sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg==", + "dev": true, + "requires": { + "@lerna/package": "4.0.0", + "@lerna/validation-error": "4.0.0", + "cosmiconfig": "^7.0.0", + "dedent": "^0.7.0", + "dot-prop": "^6.0.1", + "glob-parent": "^5.1.1", + "globby": "^11.0.2", + "load-json-file": "^6.2.0", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "resolve-from": "^5.0.0", + "write-json-file": "^4.3.0" + }, + "dependencies": { + "dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + } + } + }, + "@lerna/prompt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/prompt/-/prompt-4.0.0.tgz", + "integrity": "sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ==", + "dev": true, + "requires": { + "inquirer": "^7.3.3", + "npmlog": "^4.1.2" + } + }, + "@lerna/publish": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-4.0.0.tgz", + "integrity": "sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg==", + "dev": true, + "requires": { + "@lerna/check-working-tree": "4.0.0", + "@lerna/child-process": "4.0.0", + "@lerna/collect-updates": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/describe-ref": "4.0.0", + "@lerna/log-packed": "4.0.0", + "@lerna/npm-conf": "4.0.0", + "@lerna/npm-dist-tag": "4.0.0", + "@lerna/npm-publish": "4.0.0", + "@lerna/otplease": "4.0.0", + "@lerna/output": "4.0.0", + "@lerna/pack-directory": "4.0.0", + "@lerna/prerelease-id-from-version": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/validation-error": "4.0.0", + "@lerna/version": "4.0.0", + "fs-extra": "^9.1.0", + "libnpmaccess": "^4.0.1", + "npm-package-arg": "^8.1.0", + "npm-registry-fetch": "^9.0.0", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "p-pipe": "^3.1.0", + "pacote": "^11.2.6", + "semver": "^7.3.4" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/pulse-till-done": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz", + "integrity": "sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg==", + "dev": true, + "requires": { + "npmlog": "^4.1.2" + } + }, + "@lerna/query-graph": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/query-graph/-/query-graph-4.0.0.tgz", + "integrity": "sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg==", + "dev": true, + "requires": { + "@lerna/package-graph": "4.0.0" + } + }, + "@lerna/resolve-symlink": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz", + "integrity": "sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA==", + "dev": true, + "requires": { + "fs-extra": "^9.1.0", + "npmlog": "^4.1.2", + "read-cmd-shim": "^2.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/rimraf-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz", + "integrity": "sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg==", + "dev": true, + "requires": { + "@lerna/child-process": "4.0.0", + "npmlog": "^4.1.2", + "path-exists": "^4.0.0", + "rimraf": "^3.0.2" + } + }, + "@lerna/run": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/run/-/run-4.0.0.tgz", + "integrity": "sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ==", + "dev": true, + "requires": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/npm-run-script": "4.0.0", + "@lerna/output": "4.0.0", + "@lerna/profiler": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/timer": "4.0.0", + "@lerna/validation-error": "4.0.0", + "p-map": "^4.0.0" + } + }, + "@lerna/run-lifecycle": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz", + "integrity": "sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ==", + "dev": true, + "requires": { + "@lerna/npm-conf": "4.0.0", + "npm-lifecycle": "^3.1.5", + "npmlog": "^4.1.2" + } + }, + "@lerna/run-topologically": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/run-topologically/-/run-topologically-4.0.0.tgz", + "integrity": "sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA==", + "dev": true, + "requires": { + "@lerna/query-graph": "4.0.0", + "p-queue": "^6.6.2" + } + }, + "@lerna/symlink-binary": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz", + "integrity": "sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA==", + "dev": true, + "requires": { + "@lerna/create-symlink": "4.0.0", + "@lerna/package": "4.0.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/symlink-dependencies": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz", + "integrity": "sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw==", + "dev": true, + "requires": { + "@lerna/create-symlink": "4.0.0", + "@lerna/resolve-symlink": "4.0.0", + "@lerna/symlink-binary": "4.0.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna/timer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/timer/-/timer-4.0.0.tgz", + "integrity": "sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg==", + "dev": true + }, + "@lerna/validation-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-4.0.0.tgz", + "integrity": "sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw==", + "dev": true, + "requires": { + "npmlog": "^4.1.2" + } + }, + "@lerna/version": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/version/-/version-4.0.0.tgz", + "integrity": "sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA==", + "dev": true, + "requires": { + "@lerna/check-working-tree": "4.0.0", + "@lerna/child-process": "4.0.0", + "@lerna/collect-updates": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/conventional-commits": "4.0.0", + "@lerna/github-client": "4.0.0", + "@lerna/gitlab-client": "4.0.0", + "@lerna/output": "4.0.0", + "@lerna/prerelease-id-from-version": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/validation-error": "4.0.0", + "chalk": "^4.1.0", + "dedent": "^0.7.0", + "load-json-file": "^6.2.0", + "minimatch": "^3.0.4", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "p-pipe": "^3.1.0", + "p-reduce": "^2.1.0", + "p-waterfall": "^2.1.1", + "semver": "^7.3.4", + "slash": "^3.0.0", + "temp-write": "^4.0.0", + "write-json-file": "^4.3.0" + } + }, + "@lerna/write-log-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-4.0.0.tgz", + "integrity": "sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg==", + "dev": true, + "requires": { + "npmlog": "^4.1.2", + "write-file-atomic": "^3.0.3" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/ci-detect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz", + "integrity": "sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q==", + "dev": true + }, + "@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", + "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", + "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", + "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz", + "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^7.1.0", + "read-package-json-fast": "^2.0.1" + }, + "dependencies": { + "node-gyp": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "requires": { + "abbrev": "1" + } + } + } + }, + "@octokit/auth-token": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "dev": true, + "requires": { + "@octokit/types": "^6.0.3" + } + }, + "@octokit/core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "dev": true, + "requires": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "dev": true, + "requires": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "dev": true, + "requires": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", + "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==", + "dev": true + }, + "@octokit/plugin-enterprise-rest": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", + "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", + "dev": true + }, + "@octokit/plugin-paginate-rest": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", + "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "dev": true, + "requires": { + "@octokit/types": "^6.34.0" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "dev": true, + "requires": {} + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", + "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "dev": true, + "requires": { + "@octokit/types": "^6.34.0", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "dev": true, + "requires": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/request-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "dev": true, + "requires": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "18.12.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", + "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", + "dev": true, + "requires": { + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + } + }, + "@octokit/types": { + "version": "6.34.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", + "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "dev": true, + "requires": { + "@octokit/openapi-types": "^11.2.0" + } + }, + "@opencensus/core": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz", + "integrity": "sha512-31Q4VWtbzXpVUd2m9JS6HEaPjlKvNMOiF7lWKNmXF84yUcgfAFL5re7/hjDmdyQbOp32oGc+RFV78jXIldVz6Q==", + "dev": true, + "requires": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^5.5.0", + "shimmer": "^1.2.0", + "uuid": "^3.2.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "@opencensus/propagation-b3": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@opencensus/propagation-b3/-/propagation-b3-0.0.8.tgz", + "integrity": "sha512-PffXX2AL8Sh0VHQ52jJC4u3T0H6wDK6N/4bg7xh4ngMYOIi13aR1kzVvX1sVDBgfGwDOkMbl4c54Xm3tlPx/+A==", + "dev": true, + "requires": { + "@opencensus/core": "^0.0.8", + "uuid": "^3.2.1" + }, + "dependencies": { + "@opencensus/core": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.8.tgz", + "integrity": "sha512-yUFT59SFhGMYQgX0PhoTR0LBff2BEhPrD9io1jWfF/VDbakRfs6Pq60rjv0Z7iaTav5gQlttJCX2+VPxFWCuoQ==", + "dev": true, + "requires": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^5.5.0", + "shimmer": "^1.2.0", + "uuid": "^3.2.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "@pm2/agent": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.1.tgz", + "integrity": "sha512-QKHMm6yexcvdDfcNE7PL9D6uEjoQPGRi+8dh+rc4Hwtbpsbh5IAvZbz3BVGjcd4HaX6pt2xGpOohG7/Y2L4QLw==", + "dev": true, + "requires": { + "async": "~3.2.0", + "chalk": "~3.0.0", + "dayjs": "~1.8.24", + "debug": "~4.3.1", + "eventemitter2": "~5.0.1", + "fast-json-patch": "^3.0.0-1", + "fclone": "~1.0.11", + "nssocket": "0.6.0", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.0", + "proxy-agent": "~5.0.0", + "semver": "~7.2.0", + "ws": "~7.4.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "dayjs": { + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", + "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==", + "dev": true + }, + "semver": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.2.3.tgz", + "integrity": "sha512-utbW9Z7ZxVvwiIWkdOMLOR9G/NFXh2aRucghkVrEMJWuC++r3lCkBC3LwqBinyHzGMAJxY5tn6VakZGHObq5ig==", + "dev": true + }, + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "requires": {} + } + } + }, + "@pm2/io": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-5.0.0.tgz", + "integrity": "sha512-3rToDVJaRoob5Lq8+7Q2TZFruoEkdORxwzFpZaqF4bmH6Bkd7kAbdPrI/z8X6k1Meq5rTtScM7MmDgppH6aLlw==", + "dev": true, + "requires": { + "@opencensus/core": "0.0.9", + "@opencensus/propagation-b3": "0.0.8", + "async": "~2.6.1", + "debug": "~4.3.1", + "eventemitter2": "^6.3.1", + "require-in-the-middle": "^5.0.0", + "semver": "6.3.0", + "shimmer": "^1.2.0", + "signal-exit": "^3.0.3", + "tslib": "1.9.3" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "eventemitter2": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + } + } + }, + "@pm2/js-api": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.6.7.tgz", + "integrity": "sha512-jiJUhbdsK+5C4zhPZNnyA3wRI01dEc6a2GhcQ9qI38DyIk+S+C8iC3fGjcjUbt/viLYKPjlAaE+hcT2/JMQPXw==", + "dev": true, + "requires": { + "async": "^2.6.3", + "axios": "^0.21.0", + "debug": "~4.3.1", + "eventemitter2": "^6.3.1", + "ws": "^7.0.0" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.0" + } + }, + "eventemitter2": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", + "dev": true + } + } + }, + "@pm2/pm2-version-check": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.4.tgz", + "integrity": "sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==", + "dev": true, + "requires": { + "debug": "^4.3.1" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@socket.io/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==" + }, + "@socket.io/component-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", + "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==" + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", + "dev": true + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", + "dev": true + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", + "dev": true + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", + "dev": true + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", + "dev": true + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", + "dev": true + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", + "dev": true + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", + "dev": true + }, + "@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "dev": true, + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + } + }, + "@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "dev": true, + "requires": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "dev": true, + "requires": { + "@babel/types": "^7.12.6" + } + }, + "@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + } + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@tago-io/sdk": { + "version": "10.4.4", + "resolved": "https://registry.npmjs.org/@tago-io/sdk/-/sdk-10.4.4.tgz", + "integrity": "sha512-5rZxeJCRCCf0wfEVsFjS4OJL31YvRDDJSAA0OgEh1vkGtowO0JuYbASyZV6ZYxU4kczHCC4FfjkeIw5uu8G/hg==", + "requires": { + "axios": "0.25.0", + "form-data": "4.0.0", + "lodash.chunk": "4.2.0", + "nanoid": "3.2.0", + "papaparse": "5.3.1", + "qs": "6.10.3", + "socket.io-client": "4.4.1" + }, + "dependencies": { + "axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "requires": { + "follow-redirects": "^1.14.7" + } + }, + "nanoid": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==" + }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, + "@tago-io/tcore-api": { + "version": "file:packages/tcore-api", + "requires": { + "@tago-io/sdk": "10.4.4", + "@tago-io/tcore-sdk": "*", + "@tago-io/tcore-shared": "*", + "@types/compression": "1.7.1", + "@types/cors": "2.8.12", + "@types/debug": "4.1.7", + "@types/express": "4.17.13", + "@types/jest": "27.0.1", + "@types/luxon": "1.27.1", + "@types/method-override": "0.0.32", + "@types/node": "16.7.1", + "@types/semver": "7.3.9", + "@types/tar": "6.1.0", + "@typescript-eslint/eslint-plugin": "4.29.3", + "@typescript-eslint/parser": "4.29.3", + "axios": "0.24.0", + "boxen": "5.1.2", + "chalk": "4.1.2", + "compression": "1.7.4", + "cors": "^2.8.5", + "dayjs": "1.10.1", + "debug": "4.3.2", + "eslint": "7.32.0", + "eslint-config-prettier": "8.3.0", + "eslint-import-resolver-typescript": "2.4.0", + "eslint-plugin-import": "2.24.1", + "eslint-plugin-jest": "24.4.0", + "eslint-plugin-prettier": "3.4.1", + "express": "^4.17.1", + "extract-zip": "2.0.1", + "jest": "27.0.6", + "luxon": "2.0.2", + "md5": "2.3.0", + "method-override": "3.0.0", + "nanoid": "3.3.1", + "nodemon": "2.0.15", + "ora": "5.4.1", + "prettier": "2.3.2", + "socket.io": "4.4.1", + "systeminformation": "5.9.7", + "tar": "6.1.11", + "ts-jest": "27.0.5", + "ts-node": "10.2.1", + "typescript": "4.3.5", + "zod": "3.13.4" + }, + "dependencies": { + "luxon": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.0.2.tgz", + "integrity": "sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg==" + }, + "typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "dev": true + } + } + }, + "@tago-io/tcore-cli": { + "version": "file:packages/tcore-cli", + "requires": { + "@tago-io/tcore-api": "*", + "@tago-io/tcore-sdk": "*", + "@types/jest": "27.0.1", + "@types/node": "16.7.1", + "@types/semver": "7.3.9", + "@typescript-eslint/eslint-plugin": "4.29.3", + "@typescript-eslint/parser": "4.29.3", + "chalk": "4.1.2", + "commander": "^9.0.0", + "esbuild": "^0.14.23", + "eslint": "7.32.0", + "eslint-config-prettier": "8.3.0", + "eslint-import-resolver-typescript": "2.4.0", + "eslint-plugin-import": "2.24.1", + "eslint-plugin-jest": "24.4.0", + "eslint-plugin-prettier": "3.4.1", + "jest": "27.0.6", + "ora": "5.4.1", + "pm2": "^5.2.0", + "prettier": "2.3.2", + "socket.io-client": "4.4.1", + "tail": "2.2.4", + "ts-jest": "27.0.5", + "typescript": "4.3.5" + }, + "dependencies": { + "typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "dev": true + } + } + }, + "@tago-io/tcore-console": { + "version": "file:packages/tcore-console", + "requires": { + "@antv/g2": "4.1.23", + "@svgr/core": "5.5.0", + "@tago-io/sdk": "10.4.4", + "@tago-io/tcore-sdk": "*", + "@tago-io/tcore-shared": "*", + "@testing-library/jest-dom": "5.14.1", + "@testing-library/react": "12.0.0", + "@types/jest": "27.0.1", + "@types/lodash.clonedeep": "4.5.6", + "@types/luxon": "1.27.1", + "@types/qs": "6.9.7", + "@types/react": "17.0.14", + "@types/react-dom": "17.0.9", + "@types/react-helmet": "6.1.4", + "@types/react-router": "5.1.16", + "@types/react-router-dom": "5.1.8", + "@types/semver": "7.3.9", + "@types/styled-components": "5.1.11", + "@types/tinycolor2": "1.4.3", + "@typescript-eslint/eslint-plugin": "4.29.0", + "@typescript-eslint/parser": "4.29.3", + "axios": "0.24.0", + "esbuild": "0.12.22", + "esbuild-jest": "0.5.0", + "eslint": "7.31.0", + "eslint-config-airbnb": "18.2.1", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-import": "2.23.4", + "eslint-plugin-jest": "24.4.0", + "eslint-plugin-jsx-a11y": "6.4.1", + "eslint-plugin-prettier": "3.4.0", + "eslint-plugin-react": "7.24.0", + "eslint-plugin-react-hooks": "4.2.0", + "graphql": "16.0.1", + "jest": "27.0.6", + "jest-transform-stub": "2.0.0", + "lodash.clonedeep": "4.5.0", + "luxon": "2.0.1", + "mobx": "6.4.2", + "mobx-react": "7.3.0", + "polished": "4.1.3", + "prettier": "2.3.2", + "qs": "6.10.1", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-helmet": "6.1.0", + "react-markdown": "7.0.0", + "react-router": "5.2.0", + "react-router-dom": "5.2.0", + "semver": "7.3.5", + "socket.io-client": "4.4.1", + "styled-components": "5.3.0", + "styled-jsx": "3.4.5", + "swr": "0.5.6", + "tinycolor2": "1.4.2", + "ts-jest": "27.0.5", + "typescript": "4.3.5", + "zod": "3.13.4" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz", + "integrity": "sha512-eiREtqWRZ8aVJcNru7cT/AMVnYd9a2UHsfZT8MR1dW3UUEg6jDv9EQ9Cq4CUPZesyQ58YUpoAADGv71jY8RwgA==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.29.0", + "@typescript-eslint/scope-manager": "4.29.0", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.0.tgz", + "integrity": "sha512-FpNVKykfeaIxlArLUP/yQfv/5/3rhl1ov6RWgud4OgbqWLkEq7lqgQU9iiavZRzpzCRQV4XddyFz3wFXdkiX9w==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.29.0", + "@typescript-eslint/types": "4.29.0", + "@typescript-eslint/typescript-estree": "4.29.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.0.tgz", + "integrity": "sha512-HPq7XAaDMM3DpmuijxLV9Io8/6pQnliiXMQUcAdjpJJSR+fdmbD/zHCd7hMkjJn04UQtCQBtshgxClzg6NIS2w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.29.0", + "@typescript-eslint/visitor-keys": "4.29.0" + } + }, + "@typescript-eslint/types": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.0.tgz", + "integrity": "sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.0.tgz", + "integrity": "sha512-8ZpNHDIOyqzzgZrQW9+xQ4k5hM62Xy2R4RPO3DQxMc5Rq5QkCdSpk/drka+DL9w6sXNzV5nrdlBmf8+x495QXQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.29.0", + "@typescript-eslint/visitor-keys": "4.29.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.0.tgz", + "integrity": "sha512-LoaofO1C/jAJYs0uEpYMXfHboGXzOJeV118X4OsZu9f7rG7Pr9B3+4HTU8+err81rADa4xfQmAxnRnPAI2jp+Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.29.0", + "eslint-visitor-keys": "^2.0.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "esbuild": { + "version": "0.12.22", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.22.tgz", + "integrity": "sha512-yWCr9RoFehpqoe/+MwZXJpYOEIt7KOEvNnjIeMZpMSyQt+KCBASM3y7yViiN5dJRphf1wGdUz1+M4rTtWd/ulA==", + "dev": true + }, + "eslint": { + "version": "7.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.31.0.tgz", + "integrity": "sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + } + } + }, + "eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-plugin-prettier": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "luxon": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.0.1.tgz", + "integrity": "sha512-8Eawf81c9ZlQj62W3eq4mp+C7SAIAnmaS7ZuEAiX503YMcn+0C1JnMQRtfaQj6B5qTZLgHv0F4H5WabBCvi1fw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "dev": true + } + } + }, + "@tago-io/tcore-sdk": { + "version": "file:packages/tcore-sdk", + "requires": { + "@types/commander": "2.12.2", + "@types/glob": "7.2.0", + "@types/jest": "27.0.1", + "@types/luxon": "2.0.9", + "@types/node": "16.7.1", + "@types/semver": "7.3.9", + "@types/tar": "6.1.1", + "@types/uuid": "^8.3.1", + "@typescript-eslint/eslint-plugin": "4.31.2", + "@typescript-eslint/parser": "4.29.3", + "chalk": "4.1.2", + "commander": "9.1.0", + "eslint": "7.32.0", + "eslint-config-prettier": "8.3.0", + "eslint-import-resolver-typescript": "2.4.0", + "eslint-plugin-import": "2.24.1", + "eslint-plugin-prettier": "3.4.1", + "glob": "7.2.0", + "image-size": "1.0.1", + "jest": "27.0.6", + "luxon": "2.3.0", + "nanoid": "^3.1.32", + "ora": "5.4.1", + "prettier": "2.3.2", + "semver": "7.3.5", + "tar": "6.1.11", + "ts-jest": "27.0.5", + "typescript": "4.3.5", + "uuid": "^8.3.2", + "zod": "3.13.4" + }, + "dependencies": { + "@types/luxon": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.0.9.tgz", + "integrity": "sha512-ZuzIc7aN+i2ZDMWIiSmMdubR9EMMSTdEzF6R+FckP4p6xdnOYKqknTo/k+xXQvciSXlNGIwA4OPU5X7JIFzYdA==", + "dev": true + }, + "@types/tar": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/tar/-/tar-6.1.1.tgz", + "integrity": "sha512-8mto3YZfVpqB1CHMaYz1TUYIQfZFbh/QbEq5Hsn6D0ilCfqRVCdalmc89B7vi3jhl9UYIk+dWDABShNfOkv5HA==", + "dev": true, + "requires": { + "@types/minipass": "*", + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.2.tgz", + "integrity": "sha512-w63SCQ4bIwWN/+3FxzpnWrDjQRXVEGiTt9tJTRptRXeFvdZc/wLiz3FQUwNQ2CVoRGI6KUWMNUj/pk63noUfcA==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.31.2", + "@typescript-eslint/scope-manager": "4.31.2", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.2.tgz", + "integrity": "sha512-3tm2T4nyA970yQ6R3JZV9l0yilE2FedYg8dcXrTar34zC9r6JB7WyBQbpIVongKPlhEMjhQ01qkwrzWy38Bk1Q==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.31.2", + "@typescript-eslint/types": "4.31.2", + "@typescript-eslint/typescript-estree": "4.31.2", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz", + "integrity": "sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.31.2", + "@typescript-eslint/visitor-keys": "4.31.2" + } + }, + "@typescript-eslint/types": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.2.tgz", + "integrity": "sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz", + "integrity": "sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.31.2", + "@typescript-eslint/visitor-keys": "4.31.2", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.31.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz", + "integrity": "sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.31.2", + "eslint-visitor-keys": "^2.0.0" + } + }, + "commander": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.1.0.tgz", + "integrity": "sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w==" + }, + "luxon": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.3.0.tgz", + "integrity": "sha512-gv6jZCV+gGIrVKhO90yrsn8qXPKD8HYZJtrUDSfEbow8Tkw84T9OnCyJhWvnJIaIF/tBuiAjZuQHUt1LddX2mg==" + }, + "typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "dev": true + } + } + }, + "@tago-io/tcore-shared": { + "version": "file:packages/tcore-shared", + "requires": { + "@tago-io/tcore-sdk": "*" + } + }, + "@testing-library/dom": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.13.0.tgz", + "integrity": "sha512-9VHgfIatKNXQNaZTtLnalIy0jNZzY35a4S3oi08YAt9Hv1VsfZ/DfA45lM8D/UhtHBGJ4/lGwp0PZkVndRkoOQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" + }, + "dependencies": { + "aria-query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", + "dev": true + } + } + }, + "@testing-library/jest-dom": { + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", + "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^4.2.2", + "chalk": "^3.0.0", + "css": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@testing-library/react": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.0.0.tgz", + "integrity": "sha512-sh3jhFgEshFyJ/0IxGltRhwZv2kFKfJ3fN1vTZ6hhMXzz9ZbbcTgmDYM4e+zJv+oiVKKEWZPyqPAh4MQBI65gA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.0.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/commander": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q==", + "dev": true, + "requires": { + "commander": "*" + } + }, + "@types/component-emitter": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", + "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" + }, + "@types/compression": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.1.tgz", + "integrity": "sha512-d6K1bU3qIjtfB2u+A1N0WDf62LpewRjrvbqY79qlPwk2otgQ4mWB4+LzPCWTvGmcuVwo+zAroEhsNlJavRcFvg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" + }, + "@types/d3-timer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-2.0.1.tgz", + "integrity": "sha512-TF8aoF5cHcLO7W7403blM7L1T+6NF3XMyN3fxyUolq2uOcFeicG/khQg/dGxiCJWoAcmYulYN7LYSRKO54IXaA==" + }, + "@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "requires": { + "@types/ms": "*" + } + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "requires": { + "@types/unist": "*" + } + }, + "@types/history": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/history/-/history-5.0.0.tgz", + "integrity": "sha512-hy8b7Y1J8OGe6LbAjj3xniQrj3v6lsivCcrmf4TzSgPzLkhIeKgc5IZnT7ReIqmEuodjfO8EYAuoFvIrHi/+jQ==", + "dev": true, + "requires": { + "history": "*" + } + }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz", + "integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==", + "dev": true, + "requires": { + "jest-diff": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "@types/js-yaml": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.3.tgz", + "integrity": "sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/lodash": { + "version": "4.14.182", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", + "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", + "dev": true + }, + "@types/lodash.clonedeep": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz", + "integrity": "sha512-cE1jYr2dEg1wBImvXlNtp0xDoS79rfEdGozQVgliDZj1uERH4k+rmEMTudP9b4VQ8O6nRb5gPqft0QzEQGMQgA==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, + "@types/luxon": { + "version": "1.27.1", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-1.27.1.tgz", + "integrity": "sha512-cPiXpOvPFDr2edMnOXlz3UBDApwUfR+cpizvxCy0n3vp9bz/qe8BWzHPIEFcy+ogUOyjKuCISgyq77ELZPmkkg==", + "dev": true + }, + "@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "requires": { + "@types/unist": "*" + } + }, + "@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==" + }, + "@types/method-override": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/method-override/-/method-override-0.0.32.tgz", + "integrity": "sha512-Vf9AohOlANmhNswCbkdRG3p+tYcq1+63O+ex1UoNIVYWW3tO8Mx6Z+5G1R8DENeC6/t1SiDJS+ph6ACKpryokg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "@types/minipass": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/minipass/-/minipass-3.1.2.tgz", + "integrity": "sha512-foLGjgrJkUjLG/o2t2ymlZGEoBNBa/TfoUZ7oCTkOjP1T43UGBJspovJou/l3ZuHvye2ewR5cZNtp2zyWgILMA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "@types/node": { + "version": "16.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.1.tgz", + "integrity": "sha512-ncRdc45SoYJ2H4eWU9ReDfp3vtFqDYhjOsKlFFUDEn8V1Bgr2RjYal8YT5byfadWIRluhPFU6JiDOl0H6Sl87A==" + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/prettier": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.0.tgz", + "integrity": "sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw==", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/react": { + "version": "17.0.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz", + "integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "17.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", + "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-helmet": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.4.tgz", + "integrity": "sha512-jyx50RNZXVaTGHY3MsoRPNpeiVk8b0XTPgD/O6KHF6COTDnG/+lRjPYvTK5nfWtR3xDOux0w6bHLAsaHo2ZLTA==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-router": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz", + "integrity": "sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*" + } + }, + "@types/react-router-dom": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz", + "integrity": "sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@types/semver": { + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz", + "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/styled-components": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.11.tgz", + "integrity": "sha512-u8g3bSw9KUiZY+S++gh+LlURGraqBe3MC5I5dygrNjGDHWWQfsmZZRTJ9K9oHU2CqWtxChWmJkDI/gp+TZPQMw==", + "dev": true, + "requires": { + "@types/hoist-non-react-statics": "*", + "@types/react": "*", + "csstype": "^3.0.2" + } + }, + "@types/tar": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-uTZKMW7ZkdTJXX4+Bsp0ko9N7B5/NJ5wJRW14XTb6KNN+9i2NPel6iPKp8rTQahMW46BM9tM52dTeMSldB55og==", + "dev": true, + "requires": { + "@types/minipass": "*", + "@types/node": "*" + } + }, + "@types/testing-library__jest-dom": { + "version": "5.14.3", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.3.tgz", + "integrity": "sha512-oKZe+Mf4ioWlMuzVBaXQ9WDnEm1+umLx0InILg+yvZVBBDmzV5KfZyLrCvadtWcx8+916jLmHafcmqqffl+iIw==", + "dev": true, + "requires": { + "@types/jest": "*" + } + }, + "@types/tinycolor2": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.3.tgz", + "integrity": "sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==", + "dev": true + }, + "@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.3.tgz", + "integrity": "sha512-tBgfA3K/3TsZY46ROGvoRxQr1wBkclbVqRQep97MjVHJzcRBURRY3sNFqLk0/Xr//BY5hM9H2p/kp+6qim85SA==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.29.3", + "@typescript-eslint/scope-manager": "4.29.3", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.3.tgz", + "integrity": "sha512-ffIvbytTVWz+3keg+Sy94FG1QeOvmV9dP2YSdLFHw/ieLXWCa3U1TYu8IRCOpMv2/SPS8XqhM1+ou1YHsdzKrg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.29.3", + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/typescript-estree": "4.29.3", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.3.tgz", + "integrity": "sha512-jrHOV5g2u8ROghmspKoW7pN8T/qUzk0+DITun0MELptvngtMrwUJ1tv5zMI04CYVEUsSrN4jV7AKSv+I0y0EfQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.29.3", + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/typescript-estree": "4.29.3", + "debug": "^4.3.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.3.tgz", + "integrity": "sha512-x+w8BLXO7iWPkG5mEy9bA1iFRnk36p/goVlYobVWHyDw69YmaH9q6eA+Fgl7kYHmFvWlebUTUfhtIg4zbbl8PA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/visitor-keys": "4.29.3" + } + }, + "@typescript-eslint/types": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.3.tgz", + "integrity": "sha512-s1eV1lKNgoIYLAl1JUba8NhULmf+jOmmeFO1G5MN/RBCyyzg4TIOfIOICVNC06lor+Xmy4FypIIhFiJXOknhIg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.3.tgz", + "integrity": "sha512-45oQJA0bxna4O5TMwz55/TpgjX1YrAPOI/rb6kPgmdnemRZx/dB0rsx+Ku8jpDvqTxcE1C/qEbVHbS3h0hflag==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/visitor-keys": "4.29.3", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.3.tgz", + "integrity": "sha512-MGGfJvXT4asUTeVs0Q2m+sY63UsfnA+C/FDgBKV3itLBmM9H0u+URcneePtkd0at1YELmZK6HSolCqM4Fzs6yA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.29.3", + "eslint-visitor-keys": "^2.0.0" + } + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + } + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amp": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", + "integrity": "sha1-at+NWKdPNh6CwfqNOJwHnhOfxH0=", + "dev": true + }, + "amp-message": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz", + "integrity": "sha1-p48cmJlQh602GSpBKY5NtJ49/EU=", + "dev": true, + "requires": { + "amp": "0.3.1" + } + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "requires": { + "string-width": "^4.1.0" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "dev": true + }, + "array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + } + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "dev": true + }, + "async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "dev": true, + "requires": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "aws-sdk": { + "version": "2.1087.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1087.0.tgz", + "integrity": "sha512-m5EERT29Fwh2cv3SaSdygeAjJBXnjSaXRRERy70bf6PQ7KgmASJouBxY11g5G7LTEPK/yfB0TGshujKh3hEtPA==", + "dev": true, + "requires": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "axe-core": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz", + "integrity": "sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==", + "dev": true + }, + "axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "requires": { + "follow-redirects": "^1.14.4" + } + }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "requires": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-styled-components": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz", + "integrity": "sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-module-imports": "^7.16.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "lodash": "^4.17.11", + "picomatch": "^2.3.0" + } + }, + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "before-after-hook": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", + "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + } + } + }, + "blessed": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", + "integrity": "sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk=", + "dev": true + }, + "bodec": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", + "integrity": "sha1-vIUVVUMPI8n3ZQp172TGqUw0GMw=", + "dev": true + }, + "body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "byline": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=", + "dev": true + }, + "byte-size": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-7.0.1.tgz", + "integrity": "sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A==", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + }, + "caniuse-lite": { + "version": "1.0.30001334", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001334.tgz", + "integrity": "sha512-kbaCEBRRVSoeNs74sCuq92MJyGrMtjWVfhltoHUCW4t4pXFvGjUBrfo47weBRViHkiV3eBYyIsfl956NtHGazw==", + "dev": true + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "character-entities": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.1.tgz", + "integrity": "sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ==" + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, + "charm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", + "integrity": "sha1-BsIe7RobBq62dVPNxT4jJ0usIpY=", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "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 + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==" + }, + "cli-tableau": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.1.tgz", + "integrity": "sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==", + "dev": true, + "requires": { + "chalk": "3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "dependencies": { + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + } + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "cmd-shim": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz", + "integrity": "sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw==", + "dev": true, + "requires": { + "mkdirp-infer-owner": "^2.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "columnify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", + "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "dev": true, + "requires": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "comma-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz", + "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==" + }, + "commander": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", + "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==" + }, + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "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==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "concurrently": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.1.0.tgz", + "integrity": "sha512-Bz0tMlYKZRUDqJlNiF/OImojMB9ruKUz6GCfmhFnSapXgPe+3xzY4byqoKG9tUZ7L2PGEUjfLPOLfIX3labnmw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "dev": true, + "requires": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, + "conventional-changelog-angular": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", + "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + } + }, + "conventional-changelog-conventionalcommits": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz", + "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + } + }, + "conventional-changelog-core": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz", + "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==", + "dev": true, + "requires": { + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^5.0.0", + "conventional-commits-parser": "^3.2.0", + "dateformat": "^3.0.0", + "get-pkg-repo": "^4.0.0", + "git-raw-commits": "^2.0.8", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^4.1.1", + "lodash": "^4.17.15", + "normalize-package-data": "^3.0.0", + "q": "^1.5.1", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0", + "through2": "^4.0.0" + } + }, + "conventional-changelog-preset-loader": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", + "dev": true + }, + "conventional-changelog-writer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz", + "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==", + "dev": true, + "requires": { + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "conventional-commits-filter": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", + "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", + "dev": true, + "requires": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + } + }, + "conventional-commits-parser": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", + "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", + "dev": true, + "requires": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + } + }, + "conventional-recommended-bump": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz", + "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==", + "dev": true, + "requires": { + "concat-stream": "^2.0.0", + "conventional-changelog-preset-loader": "^2.3.4", + "conventional-commits-filter": "^2.0.7", + "conventional-commits-parser": "^3.2.0", + "git-raw-commits": "^2.0.8", + "git-semver-tags": "^4.1.1", + "meow": "^8.0.0", + "q": "^1.5.1" + } + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js-pure": { + "version": "3.22.3", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.3.tgz", + "integrity": "sha512-oN88zz7nmKROMy8GOjs+LN+0LedIvbMdnB5XsTlhcOg1WGARt9l0LFg0zohdoFmCsEZ1h2ZbSQ6azj3M+vhzwQ==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "croner": { + "version": "4.1.97", + "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", + "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, + "css": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", + "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "source-map": "^0.6.1", + "source-map-resolve": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" + }, + "css-to-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", + "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", + "requires": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=", + "dev": true + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, + "culvert": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", + "integrity": "sha1-lQL18BVKLVoioCPnn3HMk2+m728=", + "dev": true + }, + "d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" + }, + "d3-ease": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", + "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" + }, + "d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "requires": { + "d3-color": "1" + } + }, + "d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" + }, + "damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "dev": true + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "dev": true + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "dayjs": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.1.tgz", + "integrity": "sha512-2xg7JrHQeLBQFkvTumLoy62x1siyeocc98QwjtURgvRqOPYmAkMUdmSjrOA+MlmL6QMQn5MUhDf6rNZNuPc1LQ==" + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "decode-named-character-reference": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz", + "integrity": "sha512-YV/0HQHreRwKb7uBopyIkLG17jG6Sv2qUchk9qSoVJ2f+flwRsPNBO0hAnjt6mTNYUT+vw9Gy2ihXg4sUWPi2w==", + "requires": { + "character-entities": "^2.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "requires": { + "clone": "^1.0.2" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "degenerator": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "dev": true, + "requires": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "dependencies": { + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "dequal": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz", + "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==" + }, + "detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-accessibility-api": { + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", + "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==", + "dev": true + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "electron-to-chromium": { + "version": "1.4.124", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.124.tgz", + "integrity": "sha512-VhaE9VUYU6d2eIb+4xf83CATD+T+3bTzvxvlADkQE+c2hisiw3sZmvEDtsW704+Zky9WZGhBuQXijDVqSriQLA==", + "dev": true + }, + "emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "dev": true, + "requires": { + "shimmer": "^1.2.0" + } + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", + "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + }, + "dependencies": { + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "requires": {} + } + } + }, + "engine.io-client": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", + "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.0", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0", + "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "requires": {} + } + } + }, + "engine.io-parser": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", + "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", + "requires": { + "@socket.io/base64-arraybuffer": "~1.0.2" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "esbuild": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.38.tgz", + "integrity": "sha512-12fzJ0fsm7gVZX1YQ1InkOE5f9Tl7cgf6JPYXRJtPIoE0zkWAbHdPHVPPaLi9tYAcEBqheGzqLn/3RdTOyBfcA==", + "requires": { + "esbuild-android-64": "0.14.38", + "esbuild-android-arm64": "0.14.38", + "esbuild-darwin-64": "0.14.38", + "esbuild-darwin-arm64": "0.14.38", + "esbuild-freebsd-64": "0.14.38", + "esbuild-freebsd-arm64": "0.14.38", + "esbuild-linux-32": "0.14.38", + "esbuild-linux-64": "0.14.38", + "esbuild-linux-arm": "0.14.38", + "esbuild-linux-arm64": "0.14.38", + "esbuild-linux-mips64le": "0.14.38", + "esbuild-linux-ppc64le": "0.14.38", + "esbuild-linux-riscv64": "0.14.38", + "esbuild-linux-s390x": "0.14.38", + "esbuild-netbsd-64": "0.14.38", + "esbuild-openbsd-64": "0.14.38", + "esbuild-sunos-64": "0.14.38", + "esbuild-windows-32": "0.14.38", + "esbuild-windows-64": "0.14.38", + "esbuild-windows-arm64": "0.14.38" + } + }, + "esbuild-android-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz", + "integrity": "sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw==", + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz", + "integrity": "sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA==", + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz", + "integrity": "sha512-5JJvgXkX87Pd1Og0u/NJuO7TSqAikAcQQ74gyJ87bqWRVeouky84ICoV4sN6VV53aTW+NE87qLdGY4QA2S7KNA==", + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz", + "integrity": "sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ==", + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz", + "integrity": "sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig==", + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz", + "integrity": "sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ==", + "optional": true + }, + "esbuild-jest": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/esbuild-jest/-/esbuild-jest-0.5.0.tgz", + "integrity": "sha512-AMZZCdEpXfNVOIDvURlqYyHwC8qC1/BFjgsrOiSL1eyiIArVtHL8YAC83Shhn16cYYoAWEW17yZn0W/RJKJKHQ==", + "dev": true, + "requires": { + "@babel/core": "^7.12.17", + "@babel/plugin-transform-modules-commonjs": "^7.12.13", + "babel-jest": "^26.6.3" + }, + "dependencies": { + "@jest/transform": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "babel-jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", + "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "dev": true, + "requires": { + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", + "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-jest": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", + "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "jest-haste-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", + "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^26.0.0", + "jest-serializer": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7" + } + }, + "jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true + }, + "jest-serializer": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", + "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } + }, + "jest-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" + } + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "esbuild-linux-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz", + "integrity": "sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g==", + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz", + "integrity": "sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q==", + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz", + "integrity": "sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA==", + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz", + "integrity": "sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA==", + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz", + "integrity": "sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ==", + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz", + "integrity": "sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q==", + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz", + "integrity": "sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ==", + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz", + "integrity": "sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ==", + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz", + "integrity": "sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q==", + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz", + "integrity": "sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ==", + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz", + "integrity": "sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA==", + "optional": true + }, + "esbuild-windows-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz", + "integrity": "sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw==", + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz", + "integrity": "sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw==", + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz", + "integrity": "sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw==", + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "eslint-config-airbnb": { + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz", + "integrity": "sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^14.2.1", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + } + }, + "eslint-config-airbnb-base": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + } + }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "requires": {} + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-import-resolver-typescript": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.4.0.tgz", + "integrity": "sha512-useJKURidCcldRLCNKWemr1fFQL1SzB3G4a0li6lFGvlc5xGe1hY343bvG07cbpCzPuM/lK19FIJB3XGFSkplA==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + } + }, + "eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.24.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.1.tgz", + "integrity": "sha512-KSFWhNxPH8OGJwpRJJs+Z7I0a13E2iFQZJIvSnCu6KUs4qmgAm3xN9GYBCSoiGWmwA7gERZPXqYQjcoCROnYhQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.10.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "eslint-plugin-jest": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.4.0.tgz", + "integrity": "sha512-8qnt/hgtZ94E9dA6viqfViKBfkJwFHXgJmTWlMGDgunw1XJEGqm3eiPjDsTanM3/u/3Az82nyQM9GX7PM/QGmg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "^4.0.1" + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", + "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.11.2", + "aria-query": "^4.2.2", + "array-includes": "^3.1.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.0.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.6", + "emoji-regex": "^9.0.0", + "has": "^1.0.3", + "jsx-ast-utils": "^3.1.0", + "language-tags": "^1.0.5" + } + }, + "eslint-plugin-prettier": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-react": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", + "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.values": "^1.1.4", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.5" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", + "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "eventemitter2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", + "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "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 + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "express": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.0.tgz", + "integrity": "sha512-EJEXxiTQJS3lIPrU1AE2vRuT7X7E+0KBbpm5GSoK524yl0K8X+er8zS2P14E64eqsVNoWbMCT7MpmQ+ErAhgRg==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + } + } + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fclone": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", + "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA=", + "dev": true + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-uri-to-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=", + "dev": true + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "follow-redirects": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-pkg-repo": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", + "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", + "dev": true, + "requires": { + "@hutson/parse-repository-url": "^3.0.0", + "hosted-git-info": "^4.0.0", + "through2": "^2.0.0", + "yargs": "^16.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "git-node-fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/git-node-fs/-/git-node-fs-1.0.0.tgz", + "integrity": "sha1-SbIV4kLr5Dqkx1Ybu6SZUhdSCA8=", + "dev": true + }, + "git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "dev": true, + "requires": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + } + }, + "git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", + "dev": true, + "requires": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "git-semver-tags": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", + "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", + "dev": true, + "requires": { + "meow": "^8.0.0", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "git-sha1": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/git-sha1/-/git-sha1-0.1.2.tgz", + "integrity": "sha1-WZrBkrcYdYJeE6RF86bgURjC90U=", + "dev": true + }, + "git-up": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-4.0.5.tgz", + "integrity": "sha512-YUvVDg/vX3d0syBsk/CKUTib0srcQME0JyHkL5BaYdwLsiCslPWmDSi8PUMo9pXYjrryMcmsCoCgsTpSCJEQaA==", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "parse-url": "^6.0.0" + } + }, + "git-url-parse": { + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.6.0.tgz", + "integrity": "sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g==", + "dev": true, + "requires": { + "git-up": "^4.0.0" + } + }, + "gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", + "dev": true, + "requires": { + "ini": "^1.3.2" + } + }, + "gl-matrix": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", + "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + } + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "graphql": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.0.1.tgz", + "integrity": "sha512-oPvCuu6dlLdiz8gZupJ47o1clgb72r1u8NDBcQYjcV6G/iEdmE11B1bBlkhXRvV0LisP/SXRFP7tT6AgaTjpzg==" + }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "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==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" + }, + "history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.7.6" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" + }, + "ignore-walk": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", + "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "image-size": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.1.tgz", + "integrity": "sha512-VAwkvNSNGClRw9mDHhc5Efax8PLlsOGcUTh0T/LIriC8vPA3U5PdqXWqkz406MoYHMKW8Uf9gWr05T/rYB44kQ==", + "requires": { + "queue": "6.0.2" + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "init-package-json": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.5.tgz", + "integrity": "sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA==", + "dev": true, + "requires": { + "npm-package-arg": "^8.1.5", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "^4.1.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "read-package-json": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-4.1.2.tgz", + "integrity": "sha512-Dqer4pqzamDE2O4M55xp1qZMuLPqi4ldk2ya648FOMHRjwMzFhuxVrG04wd0c38IsvkVdr3vgHI6z+QTPdAjrQ==", + "dev": true, + "requires": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + } + } + }, + "inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + } + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "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-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + }, + "dependencies": { + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + } + } + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "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-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.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==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + }, + "dependencies": { + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + } + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "dependencies": { + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "requires": { + "ini": "2.0.0" + } + }, + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" + } + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-ssh": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.3.tgz", + "integrity": "sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ==", + "dev": true, + "requires": { + "protocols": "^1.1.0" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "dev": true, + "requires": { + "text-extensions": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "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==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.6.tgz", + "integrity": "sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==", + "dev": true, + "requires": { + "@jest/core": "^27.0.6", + "import-local": "^3.0.2", + "jest-cli": "^27.0.6" + } + }, + "jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + } + }, + "jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "requires": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "dependencies": { + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, + "requires": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + } + }, + "jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + } + }, + "jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "requires": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + } + }, + "jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + } + }, + "jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + } + }, + "jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + } + }, + "jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dev": true, + "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + } + }, + "jest-transform-stub": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jest-transform-stub/-/jest-transform-stub-2.0.0.tgz", + "integrity": "sha512-lspHaCRx/mBbnm3h4uMMS3R5aZzMwyNpNIJLXj4cEsV0mIUtS4IjYJLSoyjRCtnxb6RIGJ4NL2quZzfIeNhbkg==", + "dev": true + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + } + }, + "jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, + "requires": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "dev": true + }, + "js-git": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", + "integrity": "sha1-UvplWrYYd9bxB578ZTS1VPMeVEQ=", + "dev": true, + "requires": { + "bodec": "^0.1.0", + "culvert": "^0.1.2", + "git-sha1": "^0.1.2", + "pako": "^0.2.5" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "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", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "jsx-ast-utils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.2.tgz", + "integrity": "sha512-HDAyJ4MNQBboGpUnHAVUNJs6X0lh058s6FuixsFGP7MgJYpD6Vasd6nzSG5iIfXu1zAYlHJ/zsOKNlrenTUBnw==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "object.assign": "^4.1.2" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "language-subtag-registry": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", + "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", + "dev": true + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", + "dev": true, + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "requires": { + "package-json": "^6.3.0" + } + }, + "lazy": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", + "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=", + "dev": true + }, + "lerna": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-4.0.0.tgz", + "integrity": "sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg==", + "dev": true, + "requires": { + "@lerna/add": "4.0.0", + "@lerna/bootstrap": "4.0.0", + "@lerna/changed": "4.0.0", + "@lerna/clean": "4.0.0", + "@lerna/cli": "4.0.0", + "@lerna/create": "4.0.0", + "@lerna/diff": "4.0.0", + "@lerna/exec": "4.0.0", + "@lerna/import": "4.0.0", + "@lerna/info": "4.0.0", + "@lerna/init": "4.0.0", + "@lerna/link": "4.0.0", + "@lerna/list": "4.0.0", + "@lerna/publish": "4.0.0", + "@lerna/run": "4.0.0", + "@lerna/version": "4.0.0", + "import-local": "^3.0.2", + "npmlog": "^4.1.2" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "libnpmaccess": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-4.0.3.tgz", + "integrity": "sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ==", + "dev": true, + "requires": { + "aproba": "^2.0.0", + "minipass": "^3.1.1", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, + "npm-registry-fetch": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", + "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "dev": true, + "requires": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + } + }, + "socks-proxy-agent": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz", + "integrity": "sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + } + } + }, + "libnpmpublish": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-4.0.2.tgz", + "integrity": "sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw==", + "dev": true, + "requires": { + "normalize-package-data": "^3.0.2", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0", + "semver": "^7.1.3", + "ssri": "^8.0.1" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, + "npm-registry-fetch": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", + "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "dev": true, + "requires": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + } + }, + "socks-proxy-agent": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz", + "integrity": "sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + } + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.chunk": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", + "integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "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==", + "requires": { + "yallist": "^4.0.0" + } + }, + "luxon": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.3.1.tgz", + "integrity": "sha512-I8vnjOmhXsMSlNMZlMkSOvgrxKJl0uOsEzdGgGNZuZPaS9KlefpE9KV95QFftlJSC+1UyCC9/I69R02cz/zcCA==", + "dev": true + }, + "lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "make-fetch-happen": { + "version": "8.0.14", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz", + "integrity": "sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.0.5", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^5.0.0", + "ssri": "^8.0.0" + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "mdast-util-definitions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.0.tgz", + "integrity": "sha512-5hcR7FL2EuZ4q6lLMUK5w4lHT2H3vqL9quPvYZ/Ku5iifrirfMHiGdhxdXMUbUkDmz5I+TYMd7nbaxUhbQkfpQ==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^3.0.0" + }, + "dependencies": { + "unist-util-visit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-3.1.0.tgz", + "integrity": "sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^4.0.0" + } + }, + "unist-util-visit-parents": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz", + "integrity": "sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + } + } + } + }, + "mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + } + }, + "mdast-util-to-hast": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-11.3.0.tgz", + "integrity": "sha512-4o3Cli3hXPmm1LhB+6rqhfsIUBjnKFlIUZvudaermXB+4/KONdd/W4saWWkC+LBLbPMqhFSSTSRgafHsT5fVJw==", + "requires": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "@types/mdurl": "^1.0.0", + "mdast-util-definitions": "^5.0.0", + "mdurl": "^1.0.0", + "unist-builder": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" + } + }, + "mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, + "meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "method-override": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz", + "integrity": "sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA==", + "requires": { + "debug": "3.1.0", + "methods": "~1.1.2", + "parseurl": "~1.3.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "micromark": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", + "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==", + "requires": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "micromark-core-commonmark": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", + "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "micromark-factory-destination": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", + "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-label": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", + "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-space": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", + "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-title": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", + "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-whitespace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", + "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", + "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", + "requires": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-chunked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", + "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-classify-character": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", + "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-combine-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", + "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-decode-numeric-character-reference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", + "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-decode-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", + "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-encode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", + "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==" + }, + "micromark-util-html-tag-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz", + "integrity": "sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g==" + }, + "micromark-util-normalize-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", + "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-resolve-all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", + "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", + "requires": { + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-sanitize-uri": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz", + "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-subtokenize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", + "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-util-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", + "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==" + }, + "micromark-util-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", + "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "requires": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + } + }, + "minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "requires": { + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "mkdirp-infer-owner": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz", + "integrity": "sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "infer-owner": "^1.0.4", + "mkdirp": "^1.0.3" + } + }, + "mobx": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.4.2.tgz", + "integrity": "sha512-b4xQJYiH8sb0sEbfq/Ws3N77DEJtSihUFD1moeiz2jNoJ5B+mqJutt54ouO9iEfkp7Wk4jQDsVUOh7DPEW3wEw==" + }, + "mobx-react": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-7.3.0.tgz", + "integrity": "sha512-RGEcwZokopqyJE5JPwXKB9FWMSqFM9NJVO2QPI+z6laJTJeBHqvPicjnKgY5mvihxTeXB1+72TnooqUePeGV1g==", + "requires": { + "mobx-react-lite": "^3.3.0" + } + }, + "mobx-react-lite": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.3.0.tgz", + "integrity": "sha512-U/kMSFtV/bNVgY01FuiGWpRkaQVHozBq5CEBZltFvPt4FcV111hEWkgwqVg9GPPZSEuEdV438PEz8mk8mKpYlA==", + "requires": {} + }, + "modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true + }, + "module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=", + "dev": true + }, + "mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + } + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "needle": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", + "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", + "dev": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + } + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, + "node-gyp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz", + "integrity": "sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.1.2", + "request": "^2.88.0", + "rimraf": "^2.6.3", + "semver": "^5.7.1", + "tar": "^4.4.12", + "which": "^1.3.1" + }, + "dependencies": { + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "requires": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-releases": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "dev": true + }, + "nodemon": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", + "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5", + "update-notifier": "^5.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true + }, + "npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-install-checks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", + "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-lifecycle": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz", + "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==", + "dev": true, + "requires": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.15", + "node-gyp": "^5.0.2", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "npm-package-arg": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", + "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz", + "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==", + "dev": true, + "requires": { + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", + "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", + "dev": true, + "requires": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + } + }, + "npm-registry-fetch": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz", + "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==", + "dev": true, + "requires": { + "@npmcli/ci-detect": "^1.0.0", + "lru-cache": "^6.0.0", + "make-fetch-happen": "^8.0.9", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + } + }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "dependencies": { + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nssocket": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.6.0.tgz", + "integrity": "sha1-Wflvb/MhVm8zxw99vu7N/cBxVPo=", + "dev": true, + "requires": { + "eventemitter2": "~0.4.14", + "lazy": "~1.0.11" + }, + "dependencies": { + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + } + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "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 + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", + "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "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" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-map-series": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz", + "integrity": "sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==", + "dev": true + }, + "p-pipe": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz", + "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==", + "dev": true + }, + "p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + } + }, + "p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "p-waterfall": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz", + "integrity": "sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==", + "dev": true, + "requires": { + "p-reduce": "^2.0.0" + } + }, + "pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + } + }, + "pac-resolver": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz", + "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==", + "dev": true, + "requires": { + "degenerator": "^3.0.1", + "ip": "^1.1.5", + "netmask": "^2.0.1" + } + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "pacote": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz", + "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "dev": true, + "requires": { + "@npmcli/git": "^2.1.0", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^11.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, + "npm-registry-fetch": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", + "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "dev": true, + "requires": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + } + }, + "socks-proxy-agent": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz", + "integrity": "sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + } + } + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "papaparse": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.1.tgz", + "integrity": "sha512-Dbt2yjLJrCwH2sRqKFFJaN5XgIASO9YOFeFP8rIBRG2Ain8mqk5r1M6DkfvqEVozVcz3r3HaUGw253hA1nLIcA==" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse-path": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz", + "integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "protocols": "^1.4.0", + "qs": "^6.9.4", + "query-string": "^6.13.8" + } + }, + "parse-url": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz", + "integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "normalize-url": "^6.1.0", + "parse-path": "^4.0.0", + "protocols": "^1.4.0" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true + }, + "pidusage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.0.tgz", + "integrity": "sha512-8VJLToXhj+RYZGNVw8oxc7dS54iCQXUJ+MDFHezQ/fwF5B8W4OWodAMboc1wb08S/4LiHwAmkT4ohf/d3YPPsw==", + "dev": true, + "requires": { + "safe-buffer": "^5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true + }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + } + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "pm2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.0.tgz", + "integrity": "sha512-PO5hMVhQ85cTszFM++6v07Me9hPJMkFbHjkFigtMMk+La8ty2wCi2dlBTeZYJDhPUSjK8Ccltpq2buNRcyMOTw==", + "dev": true, + "requires": { + "@pm2/agent": "~2.0.0", + "@pm2/io": "~5.0.0", + "@pm2/js-api": "~0.6.7", + "@pm2/pm2-version-check": "latest", + "async": "~3.2.0", + "blessed": "0.1.81", + "chalk": "3.0.0", + "chokidar": "^3.5.1", + "cli-tableau": "^2.0.0", + "commander": "2.15.1", + "croner": "~4.1.92", + "dayjs": "~1.8.25", + "debug": "^4.3.1", + "enquirer": "2.3.6", + "eventemitter2": "5.0.1", + "fclone": "1.0.11", + "mkdirp": "1.0.4", + "needle": "2.4.0", + "pidusage": "~3.0", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.1", + "pm2-deploy": "~1.0.2", + "pm2-multimeter": "^0.1.2", + "pm2-sysmonit": "^1.2.8", + "promptly": "^2", + "semver": "^7.2", + "source-map-support": "0.5.19", + "sprintf-js": "1.1.2", + "vizion": "~2.2.1", + "yamljs": "0.3.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "dayjs": { + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", + "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "pm2-axon": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pm2-axon/-/pm2-axon-4.0.1.tgz", + "integrity": "sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg==", + "dev": true, + "requires": { + "amp": "~0.3.1", + "amp-message": "~0.1.1", + "debug": "^4.3.1", + "escape-string-regexp": "^4.0.0" + } + }, + "pm2-axon-rpc": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/pm2-axon-rpc/-/pm2-axon-rpc-0.7.1.tgz", + "integrity": "sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw==", + "dev": true, + "requires": { + "debug": "^4.3.1" + } + }, + "pm2-deploy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pm2-deploy/-/pm2-deploy-1.0.2.tgz", + "integrity": "sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg==", + "dev": true, + "requires": { + "run-series": "^1.1.8", + "tv4": "^1.3.0" + } + }, + "pm2-multimeter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/pm2-multimeter/-/pm2-multimeter-0.1.2.tgz", + "integrity": "sha1-Gh5VFT1BoFU0zqI8/oYKuqDrSs4=", + "dev": true, + "requires": { + "charm": "~0.1.1" + } + }, + "pm2-sysmonit": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/pm2-sysmonit/-/pm2-sysmonit-1.2.8.tgz", + "integrity": "sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==", + "dev": true, + "optional": true, + "requires": { + "async": "^3.2.0", + "debug": "^4.3.1", + "pidusage": "^2.0.21", + "systeminformation": "^5.7", + "tx2": "~1.0.4" + }, + "dependencies": { + "pidusage": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", + "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.2.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "optional": true + } + } + }, + "polished": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.1.3.tgz", + "integrity": "sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA==", + "requires": { + "@babel/runtime": "^7.14.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + }, + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + } + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "promptly": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/promptly/-/promptly-2.2.0.tgz", + "integrity": "sha1-KhP6BjaIoqWYOxYf/wEIoH0m/HQ=", + "dev": true, + "requires": { + "read": "^1.0.4" + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "promzard": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", + "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", + "dev": true, + "requires": { + "read": "1" + } + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "property-information": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz", + "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==" + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "protocols": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz", + "integrity": "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg==", + "dev": true + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dev": true, + "requires": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "requires": { + "escape-goat": "^2.0.0" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "query-string": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", + "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "requires": { + "inherits": "~2.0.3" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + } + } + }, + "react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + } + }, + "react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, + "react-helmet": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", + "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", + "requires": { + "object-assign": "^4.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.1.1", + "react-side-effect": "^2.1.0" + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "peer": true + }, + "react-markdown": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-7.0.0.tgz", + "integrity": "sha512-qdWfKxMgdKF3kHAV5pmcB12fAvytPoTpYwKTO6O/I3HujrK7sKIv6j4RnXVNLrNUh+TaBk+KtqpGzIKslX2rDg==", + "requires": { + "@types/hast": "^2.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^17.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^9.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.3.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "dependencies": { + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + } + } + }, + "react-router": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", + "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "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==", + "requires": { + "isarray": "0.0.1" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "react-router-dom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", + "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + } + } + }, + "react-side-effect": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz", + "integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==", + "requires": {} + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz", + "integrity": "sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw==", + "dev": true + }, + "read-package-json": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-3.0.1.tgz", + "integrity": "sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng==", + "dev": true, + "requires": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "dev": true, + "requires": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "read-package-json": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", + "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "dev": true, + "requires": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "requires": { + "rc": "^1.2.8" + } + }, + "remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + } + }, + "remark-rehype": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-9.1.0.tgz", + "integrity": "sha512-oLa6YmgAYg19zb0ZrBACh40hpBLteYROaPLhBXzLgjqyHQrN+gVP9N/FJvfzuNNuzCutktkroXEZBrxAxKhh7Q==", + "requires": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^11.0.0", + "unified": "^10.0.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-in-the-middle": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", + "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.12.0" + } + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", + "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", + "dev": true, + "requires": { + "global-dirs": "^0.1.1" + } + }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "run-series": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", + "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", + "dev": true + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "requires": { + "mri": "^1.1.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", + "dev": true + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, + "scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + } + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shell-quote": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "dev": true + }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "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 + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "socket.io": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", + "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.1.0", + "socket.io-adapter": "~2.3.3", + "socket.io-parser": "~4.0.4" + } + }, + "socket.io-adapter": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", + "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==" + }, + "socket.io-client": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.1.tgz", + "integrity": "sha512-N5C/L5fLNha5Ojd7Yeb/puKcPWWcoB/A09fEjjNsg91EDVr5twk/OEyO6VT9dlLSUNY85NpW6KBhVMvaLKQ3vQ==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "backo2": "~1.0.2", + "debug": "~4.3.2", + "engine.io-client": "~6.1.1", + "parseuri": "0.0.6", + "socket.io-parser": "~4.1.1" + }, + "dependencies": { + "socket.io-parser": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.2.tgz", + "integrity": "sha512-j3kk71QLJuyQ/hh5F/L2t1goqzdTL0gvDzuhTuNSwihfuFUrcSji0qFZmJJPtG6Rmug153eOPsUizeirf1IIog==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1" + } + } + } + }, + "socket.io-parser": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", + "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "requires": { + "@types/component-emitter": "^1.2.10", + "component-emitter": "~1.3.0", + "debug": "~4.3.1" + } + }, + "socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + } + }, + "sort-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz", + "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", + "dev": true, + "requires": { + "is-plain-obj": "^2.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0" + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "space-separated-tokens": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz", + "integrity": "sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==" + }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "dev": true + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "requires": { + "through": "2" + } + }, + "split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "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 + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + } + } + }, + "string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + } + }, + "string.prototype.padend": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz", + "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "strong-log-transformer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", + "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "minimist": "^1.2.0", + "through": "^2.3.4" + } + }, + "style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "requires": { + "inline-style-parser": "0.1.1" + } + }, + "styled-components": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.0.tgz", + "integrity": "sha512-bPJKwZCHjJPf/hwTJl6TbkSZg/3evha+XPEizrZUGb535jLImwDUdjTNxXqjjaASt2M4qO4AVfoHJNe3XB/tpQ==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^0.8.8", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "styled-jsx": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-3.4.5.tgz", + "integrity": "sha512-I+IET7OO4MKI710Ez3FesauZkqRIpZFQuePru3+BiGbzksJiWaB1Jew4T/+3vHoMJ1RsTxlO1T+IGOMLaoGcrQ==", + "requires": { + "@babel/helper-module-imports": "7.12.5", + "@babel/types": "7.8.3", + "babel-plugin-syntax-jsx": "6.18.0", + "convert-source-map": "1.7.0", + "loader-utils": "1.2.3", + "source-map": "0.7.3", + "string-hash": "1.1.3", + "stylis": "3.5.4", + "stylis-rule-sheet": "0.0.10" + }, + "dependencies": { + "@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "requires": { + "@babel/types": "^7.12.5" + }, + "dependencies": { + "@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "stylis": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz", + "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==" + }, + "stylis-rule-sheet": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz", + "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==", + "requires": {} + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true + }, + "swr": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/swr/-/swr-0.5.6.tgz", + "integrity": "sha512-Bmx3L4geMZjYT5S2Z6EE6/5Cx6v1Ka0LhqZKq8d6WL2eu9y6gHWz3dUzfIK/ymZVHVfwT/EweFXiYGgfifei3w==", + "requires": { + "dequal": "2.0.2" + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "systeminformation": { + "version": "5.9.7", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.9.7.tgz", + "integrity": "sha512-Vcmc8HaWPMFM4DoasuKN2lpvIwS2AqaoPuEGZc4HCT6tlRJH+IQ5GhA2BrUgjpBDJjFMj2Bti6qLOzP3T1arCw==" + }, + "table": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "tail": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/tail/-/tail-2.2.4.tgz", + "integrity": "sha512-PX8klSxW1u3SdgDrDeewh5GNE+hkJ4h02JvHfV6YrHqWOVJ88nUdSQqtsUf/gWhgZlPAws3fiZ+F1f8euspcuQ==" + }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "dev": true + }, + "temp-write": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/temp-write/-/temp-write-4.0.0.tgz", + "integrity": "sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "is-stream": "^2.0.0", + "make-dir": "^3.0.0", + "temp-dir": "^1.0.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "requires": { + "readable-stream": "3" + } + }, + "tiny-invariant": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "tinycolor2": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "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": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "requires": { + "nopt": "~1.0.10" + }, + "dependencies": { + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "requires": { + "abbrev": "1" + } + } + } + }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "dependencies": { + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "ts-jest": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.5.tgz", + "integrity": "sha512-lIJApzfTaSSbtlksfFNHkWOzLJuuSm4faFAfo5kvzOiRAuoN4/eKxVJ2zEAho8aecE04qX6K1pAzfH5QHL1/8w==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + } + }, + "ts-node": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", + "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "0.6.1", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" + }, + "dependencies": { + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "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==", + "dev": true + } + } + }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tv4": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", + "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=", + "dev": true + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "tx2": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tx2/-/tx2-1.0.5.tgz", + "integrity": "sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg==", + "dev": true, + "optional": true, + "requires": { + "json-stringify-safe": "^5.0.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "dev": true + }, + "uglify-js": { + "version": "3.15.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz", + "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==", + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", + "dev": true + }, + "umask": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", + "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + }, + "unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "requires": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, + "is-plain-obj": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.0.0.tgz", + "integrity": "sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw==" + } + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + } + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unist-builder": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", + "integrity": "sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-generated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.0.tgz", + "integrity": "sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==" + }, + "unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==" + }, + "unist-util-position": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.3.tgz", + "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-visit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.0.tgz", + "integrity": "sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" + } + }, + "unist-util-visit-parents": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz", + "integrity": "sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + } + }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "dev": true + }, + "update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "requires": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "uvu": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.3.tgz", + "integrity": "sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw==", + "requires": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "dependencies": { + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" + }, + "kleur": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", + "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==" + } + } + }, + "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==", + "dev": true + }, + "v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vfile": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.2.tgz", + "integrity": "sha512-w0PLIugRY3Crkgw89TeMvHCzqCs/zpreR31hl4D92y6SOE07+bfJe+dK5Q2akwS+i/c801kzjoOr9gMcTe6IAA==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + } + } + }, + "vfile-message": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", + "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + } + }, + "vizion": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vizion/-/vizion-2.2.1.tgz", + "integrity": "sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww==", + "dev": true, + "requires": { + "async": "^2.6.3", + "git-node-fs": "^1.0.0", + "ini": "^1.3.5", + "js-git": "^0.7.8" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } + } + }, + "vm2": { + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.9.tgz", + "integrity": "sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + }, + "dependencies": { + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "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==", + "dev": true + } + } + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "requires": { + "defaults": "^1.0.3" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "requires": { + "string-width": "^4.0.0" + } + }, + "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 + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "write-json-file": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-4.3.0.tgz", + "integrity": "sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ==", + "dev": true, + "requires": { + "detect-indent": "^6.0.0", + "graceful-fs": "^4.1.15", + "is-plain-obj": "^2.0.0", + "make-dir": "^3.0.0", + "sort-keys": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + } + } + }, + "write-pkg": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz", + "integrity": "sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==", + "dev": true, + "requires": { + "sort-keys": "^2.0.0", + "type-fest": "^0.4.1", + "write-json-file": "^3.2.0" + }, + "dependencies": { + "detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", + "dev": true + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "type-fest": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", + "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "write-json-file": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz", + "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==", + "dev": true, + "requires": { + "detect-indent": "^5.0.0", + "graceful-fs": "^4.1.15", + "make-dir": "^2.1.0", + "pify": "^4.0.1", + "sort-keys": "^2.0.0", + "write-file-atomic": "^2.4.2" + } + } + } + }, + "ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "dev": true, + "requires": {} + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "yargs": { + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", + "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "dependencies": { + "yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "dev": true + } + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, + "zod": { + "version": "3.13.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.13.4.tgz", + "integrity": "sha512-LZRucWt4j/ru5azOkJxCfpR87IyFDn8h2UODdqvXzZLb3K7bb9chUrUIGTy3BPsr8XnbQYfQ5Md5Hu2OYIo1mg==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..bae7eee2 --- /dev/null +++ b/package.json @@ -0,0 +1,66 @@ +{ + "name": "@tago-io/tcore", + "version": "0.3.3", + "author": "Tago LLC", + "description": "TCore by TagoIO", + "license": "MIT", + "private": true, + "bin": "packages/tcore-cli/build/index.js", + "engines": { + "node": ">=16.0.0" + }, + "workspaces": [ + "packages/tcore-sdk", + "packages/tcore-shared", + "packages/tcore-console", + "packages/*" + ], + "keywords": [ + "platform", + "iot", + "tagoio", + "tcore" + ], + "bugs": { + "url": "https://github.com/tago-io/tcore/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/tago-io/tcore.git" + }, + "scripts": { + "console:test": "npm run test -w @tago-io/tcore-console", + "console:watch": "npm run watch -w @tago-io/tcore-console", + "console:tsc": "npm run tsc:watch -w @tago-io/tcore-console", + "sdk:test": "npm run test -w @tago-io/tcore-sdk", + "sdk:watch": "npm run watch -w @tago-io/tcore-sdk", + "sdk:tsc": "npm run tsc:watch -w @tago-io/tcore-sdk", + "api:test": "npm run test -w @tago-io/tcore-api", + "api:watch": "npm run watch -w @tago-io/tcore-api", + "api:tsc": "npm run tsc:watch -w @tago-io/tcore-api", + "cli:tsc": "npm run tsc:watch -w @tago-io/tcore-cli", + "watch": "concurrently \"npm:*:watch\"", + "tsc": "concurrently \"npm:*:tsc\"", + "test": "npm run test -ws --if-present", + "linter": "npm run linter -ws --if-present", + "build": "npm run build -ws --if-present", + "clean": "npm run clean -ws --if-present" + }, + "devDependencies": { + "@commitlint/cli": "15.0.0", + "@commitlint/config-conventional": "15.0.0", + "@types/js-yaml": "4.0.3", + "aws-sdk": "2.1087.0", + "axios": "0.24.0", + "chalk": "4.1.2", + "concurrently": "7.1.0", + "husky": "7.0.4", + "lerna": "^4.0.0", + "luxon": "2.3.1", + "ora": "5.4.1", + "typescript": "4.4.3" + }, + "dependencies": { + "js-yaml": "4.1.0" + } +} diff --git a/packages/tcore-api/.eslintignore b/packages/tcore-api/.eslintignore new file mode 100644 index 00000000..92edd6f1 --- /dev/null +++ b/packages/tcore-api/.eslintignore @@ -0,0 +1,11 @@ +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +__build__* +.eslintrc.js +jest.config.js +esbuild/* +build diff --git a/packages/tcore-api/.eslintrc.js b/packages/tcore-api/.eslintrc.js new file mode 100644 index 00000000..bd9cbd16 --- /dev/null +++ b/packages/tcore-api/.eslintrc.js @@ -0,0 +1,30 @@ +module.exports = { + env: { + node: true, + jest: true + }, + root: true, + parserOptions: { + ecmaVersion: 6, + sourceType: "module", + ecmaFeatures: { + jsx: false, + }, + tsconfigRootDir: __dirname, + project: ["./tsconfig.json"], + }, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "import", "jest"], + ignorePatterns: ['.eslintrc.js', 'jest.config.js'], + extends: [ + "plugin:prettier/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript", + "eslint:recommended" + ], + rules: { + "import/order": 1 + }, +}; diff --git a/packages/tcore-api/.prettierrc b/packages/tcore-api/.prettierrc new file mode 100644 index 00000000..3ae934c4 --- /dev/null +++ b/packages/tcore-api/.prettierrc @@ -0,0 +1,11 @@ +{ + "trailingComma": "es5", + "printWidth": 120, + "useTabs": false, + "tabWidth": 2, + "semi": true, + "singleQuote": false, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/packages/tcore-api/jest.config.js b/packages/tcore-api/jest.config.js new file mode 100644 index 00000000..27c177bb --- /dev/null +++ b/packages/tcore-api/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + roots: ['/src'], + testRegex: '(/__tests__/.*|(\\.|/)test)\\.ts?$' +}; diff --git a/packages/tcore-api/nodemon.json b/packages/tcore-api/nodemon.json new file mode 100644 index 00000000..e3ec5644 --- /dev/null +++ b/packages/tcore-api/nodemon.json @@ -0,0 +1,5 @@ +{ + "watch": ["src"], + "ext": "ts,json", + "exec": "ts-node ./src/server.ts" +} diff --git a/packages/tcore-api/package.json b/packages/tcore-api/package.json new file mode 100644 index 00000000..f65a8e34 --- /dev/null +++ b/packages/tcore-api/package.json @@ -0,0 +1,71 @@ +{ + "name": "@tago-io/tcore-api", + "version": "0.3.3", + "private": true, + "description": "TCore API", + "author": "Tago LLC", + "main": "./build/index.js", + "homepage": "https://github.com/tago-io/tcore", + "repository": { + "type": "git", + "url": "https://github.com/tago-io/tcore" + }, + "scripts": { + "clean": "rm -rf node_modules; rm -rf package-lock.json", + "build": "rm -rf ./build; tsc", + "linter": "eslint .", + "test": "TZ=UTC jest --detectOpenHandles", + "test:watch": "TZ=UTC jest --watch", + "tsc:watch": "tsc --watch --preserveWatchOutput", + "watch": "nodemon" + }, + "dependencies": { + "nodemon": "2.0.15", + "extract-zip": "2.0.1", + "@tago-io/tcore-sdk": "*", + "@tago-io/tcore-shared": "*", + "dayjs": "1.10.1", + "axios": "0.24.0", + "compression": "1.7.4", + "cors": "^2.8.5", + "debug": "4.3.2", + "express": "^4.17.1", + "luxon": "2.0.2", + "md5": "2.3.0", + "method-override": "3.0.0", + "nanoid": "3.3.1", + "socket.io": "4.4.1", + "systeminformation": "5.9.7", + "tar": "6.1.11", + "zod": "3.13.4", + "boxen": "5.1.2", + "chalk": "4.1.2", + "ora": "5.4.1", + "@tago-io/sdk": "10.4.4" + }, + "devDependencies": { + "@types/semver": "7.3.9", + "@types/luxon": "1.27.1", + "@types/compression": "1.7.1", + "@types/cors": "2.8.12", + "@types/debug": "4.1.7", + "@types/express": "4.17.13", + "@types/jest": "27.0.1", + "@types/method-override": "0.0.32", + "@types/node": "16.7.1", + "@types/tar": "6.1.0", + "@typescript-eslint/eslint-plugin": "4.29.3", + "@typescript-eslint/parser": "4.29.3", + "eslint": "7.32.0", + "eslint-config-prettier": "8.3.0", + "eslint-import-resolver-typescript": "2.4.0", + "eslint-plugin-import": "2.24.1", + "eslint-plugin-jest": "24.4.0", + "eslint-plugin-prettier": "3.4.1", + "jest": "27.0.6", + "prettier": "2.3.2", + "ts-jest": "27.0.5", + "ts-node": "10.2.1", + "typescript": "4.3.5" + } +} diff --git a/packages/tcore-api/src/Controllers/APIController.ts b/packages/tcore-api/src/Controllers/APIController.ts new file mode 100644 index 00000000..461c95ff --- /dev/null +++ b/packages/tcore-api/src/Controllers/APIController.ts @@ -0,0 +1,216 @@ +import { IncomingHttpHeaders } from "http"; +import express, { Request, Response } from "express"; +import { ZodTypeAny } from "zod"; +import { getDeviceByToken } from "../Services/Device"; + +type TResourceType = "device" | "analysis"; +type TPermission = "full" | "write" | "read"; + +interface ISetupToken { + resource: TResourceType; + permission: TPermission; +} + +interface ISetupTokenAnonymous { + resource: "anonymous"; + permission: "any"; +} + +interface ISetupController { + zBodyParser?: ZodTypeAny; + zQueryStringParser?: ZodTypeAny; + zURLParamsParser?: ZodTypeAny; + allowTokens: (ISetupToken | ISetupTokenAnonymous)[]; +} + +/** + */ +abstract class APIController { + /** + * Status for Request with Success [default=200]. + */ + protected successStatus: number = 200; + /** + * Status for Request with Error [default=400]. + */ + protected failStatus: number = 400; + /** + * This is the response of the request. + */ + protected body: any; + /** + * Add {status; result; message} on requests [default=true]. + */ + protected useBodyWrapper: boolean = true; + /** + * This will contain the parsed version of `req.body`. + */ + protected bodyParams: BodyParams = {} as BodyParams; + /** + * This will contain the parsed version of `req.query`. + */ + protected queryStringParams: QueryStringParams = {} as QueryStringParams; + /** + * This will contain the parsed version of `req.params`. + */ + protected urlParams: URLParams = {} as URLParams; + + protected readonly files: any; + protected readonly requestIP: string; + protected readonly origin: string; + protected readonly rawToken: string | void; + + abstract setup: ISetupController; + + /** + * Main method. + */ + abstract main(): Promise; + + /** + * Headers to be sent along with the response. + */ + private headers = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS", + "Access-Control-Allow-Headers": + "Content-Type, Cache-Control, Pragma, X-Requested-With, Authorization, Account-Token, Device-Token, Token", + "Content-Type": "application/json; charset=utf-8", + }; + + // eslint-disable-next-line no-unused-vars + constructor(protected readonly req: Request, protected readonly res: Response) { + this.files = (req as any).files; + this.requestIP = String(req.headers["x-forwarded-for"] || req.socket.remoteAddress); + this.origin = req.headers.origin || "unknown"; + this.rawToken = this.getToken(req.headers); + + this.res.set(this.headers); + + // Send process to next CPU cycle + setImmediate(() => this.init()); + } + + /** + * Runs the whole routine. + */ + private async init() { + // await this.resolveToken(); + + let errorOn = "unknown"; + try { + if (this.setup.zBodyParser) { + errorOn = "Body parameters"; + this.bodyParams = await this.setup.zBodyParser.parseAsync(this.req.body); + } + + if (this.setup.zQueryStringParser) { + errorOn = "Query String parameters"; + this.queryStringParams = await this.setup.zQueryStringParser.parseAsync(this.req.query); + } + + if (this.setup.zURLParamsParser) { + errorOn = "URL parameters"; + this.urlParams = await this.setup.zURLParamsParser.parseAsync(this.req.params); + } + } catch (error: any) { + this.req.statusCode = this.failStatus; + + if (error?.flatten) { + const zodError = error.flatten()?.fieldErrors; + this.res.json({ status: false, message: `Error on ${errorOn}`, field_errors: zodError }); + } else { + this.res.json({ status: false, message: `Internal Error (${Date.now()})` }); + } + return; + } + + const success = await this.main() + .then(() => true) + .catch((e) => { + this.body = e; + return false; + }); + + this.res.statusCode = success ? this.successStatus : this.failStatus; + + if (!this.useBodyWrapper) { + this.res.send(this.body); + return; + } + + if (success) { + this.res.json({ status: true, result: this.body }); + } else { + if (this.body?.flatten) { + const zodError = this.body?.flatten()?.fieldErrors; + this.res.json({ status: false, message: "Error on object parse", field_errors: zodError }); + } else if (typeof this.body === "string") { + this.res.json({ status: false, message: String(this.body) }); + } else if (this.body instanceof Error) { + this.res.json({ status: false, message: String(this.body.message) }); + } else { + this.res.json({ status: false, result: this.body }); + } + } + } + + /** + */ + private getToken(headers: IncomingHttpHeaders): string | void { + if (!headers || typeof headers !== "object") { + headers = {}; + } + + let token: any; + token = token || headers["account-token"]; + token = token || headers["profile-token"]; + token = token || headers["device-token"]; + token = token || headers["public-token"]; + token = token || headers["analysis-token"]; + token = token || headers.token; + token = token || headers.authorization; + token = token || headers.authorized; + token = token || (this.queryStringParams as any).authorization; + token = token || (this.queryStringParams as any).authorized; + token = token || (this.queryStringParams as any).account_token; + token = token || (this.queryStringParams as any).public_token; + token = token || (this.queryStringParams as any).device_token; + token = token || (this.queryStringParams as any).token; + token = token === "null" ? undefined : token; + + return token; + } + + /** + * Resolves a device from a token. + */ + protected async resolveDeviceFromToken() { + const device = await getDeviceByToken(this.rawToken as string); + if (!device.active) { + throw new Error("Device is deactivated"); + } + return device; + } + + /** + * Resolves the request to a string identifying the agent who made the request. + */ + public resolveAgentString() { + const userAgent = this.req.get("user-agent") || "Unknown"; + const requestIP = this.requestIP; + const contentType = this.req.get("content-type") || "Unknown"; + const endToken = String(this.rawToken).slice(-5); + return `From: ${requestIP} [${userAgent}] - Content-Type: ${contentType} - Token Ending: ${endToken}`; + } +} + +// eslint-disable-next-line no-unused-vars +function warm(APIControllerInstance: { new (...args: any): APIController }) { + return (req: express.Request, res: express.Response, next?: express.NextFunction) => { + return new APIControllerInstance(req, res, next); + }; +} + +export default APIController; +export { warm, ISetupToken, ISetupController }; diff --git a/packages/tcore-api/src/Controllers/Action.ts b/packages/tcore-api/src/Controllers/Action.ts new file mode 100644 index 00000000..8e54c14d --- /dev/null +++ b/packages/tcore-api/src/Controllers/Action.ts @@ -0,0 +1,142 @@ +import { + zActionListQuery, + IActionListQuery, + IActionEdit, + zActionEdit, + IActionCreate, + zActionCreate, +} from "@tago-io/tcore-sdk/types"; +import { Application } from "express"; +import { z } from "zod"; +import { + createAction, + deleteAction, + editAction, + getActionInfo, + getActionList, + getActionTypes, + getActionTriggers, +} from "../Services/Action"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Configuration for ID in the URL. + */ +const zURLParamsID = z.object({ + id: z.string(), +}); + +/** + * Lists all the action types. + */ +class ListActionTriggers extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const response = getActionTriggers(); + this.body = response; + } +} + +/** + * Lists all the action types. + */ +class ListActionTypes extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const response = getActionTypes(); + this.body = response; + } +} + +/** + * Lists all the actions. + */ +class ListActions extends APIController { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zActionListQuery, + }; + + public async main() { + const response = await getActionList(this.queryStringParams); + this.body = response; + } +} + +/** + * Retrieves all the information of a single action. + */ +class GetActionInfo extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + const response = await getActionInfo(this.urlParams.id); + this.body = response; + } +} + +/** + * Deletes a single action. + */ +class DeleteAction extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await deleteAction(this.urlParams.id); + } +} + +/** + * Edits the information of a single action. + */ +class EditAction extends APIController> { + setup: ISetupController = { + allowTokens: [], + zBodyParser: zActionEdit, + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await editAction(this.urlParams.id, this.bodyParams); + } +} + +/** + * Creates a new action. + */ +class CreateAction extends APIController { + setup: ISetupController = { + allowTokens: [], + zBodyParser: zActionCreate, + }; + + public async main() { + const response = await createAction(this.bodyParams); + this.body = response; + } +} + +/** + * Exports the routes of the action. + */ +export default (app: Application) => { + app.delete("/action/:id", warm(DeleteAction)); + app.get("/action-types", warm(ListActionTypes)); + app.get("/action-triggers", warm(ListActionTriggers)); + app.get("/action", warm(ListActions)); + app.get("/action/:id", warm(GetActionInfo)); + app.post("/action", warm(CreateAction)); + app.put("/action/:id", warm(EditAction)); +}; diff --git a/packages/tcore-api/src/Controllers/Analysis.ts b/packages/tcore-api/src/Controllers/Analysis.ts new file mode 100644 index 00000000..0f0f8ac9 --- /dev/null +++ b/packages/tcore-api/src/Controllers/Analysis.ts @@ -0,0 +1,122 @@ +import { Application } from "express"; +import { z } from "zod"; +import { + zAnalysisListQuery, + IAnalysisListQuery, + IAnalysisCreate, + zAnalysisCreate, + IAnalysisEdit, + zAnalysisEdit, +} from "@tago-io/tcore-sdk/types"; +import { runAnalysis } from "../Services/AnalysisCodeExecution"; +import { createAnalysis, deleteAnalysis, editAnalysis, getAnalysisInfo, getAnalysisList } from "../Services/Analysis"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Configuration for ID in the URL. + */ +const zURLParamsID = z.object({ + id: z.string(), +}); + +/** + * Lists all the analyses. + */ +class ListAnalyses extends APIController { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zAnalysisListQuery, + }; + + public async main() { + const response = await getAnalysisList(this.queryStringParams); + this.body = response; + } +} + +/** + * Retrieves all the information of a single analysis. + */ +class GetAnalysisInfo extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + const response = await getAnalysisInfo(this.urlParams.id); + this.body = response; + } +} + +/** + * Deletes a single analysis. + */ +class DeleteAnalysis extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await deleteAnalysis(this.urlParams.id); + } +} + +/** + * Runs a single analysis. + */ +class RunAnalysis extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + zBodyParser: z.any(), + }; + + public async main() { + await runAnalysis(this.urlParams.id, this.bodyParams?.scope); + } +} + +/** + * Edits the information of a single analysis. + */ +class EditAnalysis extends APIController> { + setup: ISetupController = { + allowTokens: [], + zBodyParser: zAnalysisEdit, + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await editAnalysis(this.urlParams.id, this.bodyParams); + } +} + +/** + * Creates a new analysis. + */ +class CreateAnalysis extends APIController { + setup: ISetupController = { + allowTokens: [], + zBodyParser: zAnalysisCreate, + }; + + public async main() { + const response = await createAnalysis(this.bodyParams); + this.body = response; + } +} + +/** + * Exports the routes of the analysis. + */ +export default (app: Application) => { + app.delete("/analysis/:id", warm(DeleteAnalysis)); + app.get("/analysis/:id/run", warm(RunAnalysis)); + app.post("/analysis/:id/run", warm(RunAnalysis)); + app.get("/analysis", warm(ListAnalyses)); + app.get("/analysis/:id", warm(GetAnalysisInfo)); + app.post("/analysis", warm(CreateAnalysis)); + app.put("/analysis/:id", warm(EditAnalysis)); +}; diff --git a/packages/tcore-api/src/Controllers/Device/Device.test.ts b/packages/tcore-api/src/Controllers/Device/Device.test.ts new file mode 100644 index 00000000..668598b7 --- /dev/null +++ b/packages/tcore-api/src/Controllers/Device/Device.test.ts @@ -0,0 +1,36 @@ +import { createServer, Server } from "http"; +import express from "express"; +import axios from "axios"; +import { callbackInterval } from "../../Plugins/Worker/Worker"; +import * as Service from "../../Services/Device"; +import Controller from "./Device"; + +const app = express(); +let httpServer: Server | null = null; + +beforeAll(() => { + httpServer = createServer(app); + httpServer.listen(8888); + Controller(app); +}); + +beforeEach(() => { + jest.clearAllMocks(); + jest.restoreAllMocks(); +}); + +afterAll(() => { + return new Promise((resolve) => { + if (callbackInterval) { + clearTimeout(callbackInterval); + } + httpServer?.close(resolve); + }); +}); + +test("retrieves value from getDeviceData function", async () => { + jest.spyOn(Service, "getDeviceList").mockResolvedValue([1, 2, 3] as any); + const response = await axios.get("http://localhost:8888/device"); + expect(response.data).toEqual({ status: true, result: [1, 2, 3] }); + expect(response.status).toEqual(200); +}); diff --git a/packages/tcore-api/src/Controllers/Device/Device.ts b/packages/tcore-api/src/Controllers/Device/Device.ts new file mode 100644 index 00000000..3463d238 --- /dev/null +++ b/packages/tcore-api/src/Controllers/Device/Device.ts @@ -0,0 +1,201 @@ +import { Application } from "express"; +import { z } from "zod"; +import { + IDeviceCreate, + IDeviceEdit, + IDeviceListQuery, + IDeviceParameterCreate, + IDeviceTokenListQuery, + zDeviceCreate, + zDeviceEdit, + zDeviceListQuery, + zDeviceParameterCreate, + zDeviceTokenListQuery, +} from "@tago-io/tcore-sdk/types"; +import { + createDevice, + createDeviceToken, + deleteDevice, + deleteDeviceToken, + editDevice, + getDeviceInfo, + getDeviceList, + getDeviceParamList, + getDeviceTokenList, + setDeviceParams, +} from "../../Services/Device"; +import APIController, { ISetupController, warm } from "../APIController"; + +/** + * Configuration for ID in the URL. + */ +const zURLParamsID = z.object({ + id: z.string(), +}); + +/** + * Deletes a token of a device. + */ +class DeleteDeviceToken extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await deleteDeviceToken(this.urlParams.id); + } +} + +/** + * Overrides or edits device parameters. + */ +class SetDeviceParams extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + zBodyParser: z.array(zDeviceParameterCreate), + }; + + public async main() { + await setDeviceParams(this.urlParams.id, this.bodyParams); + } +} + +/** + * Lists all the tokens of a device. + */ +class GetDeviceParamList extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + const response = await getDeviceParamList(this.urlParams.id); + this.body = response; + } +} + +/** + * Generates and retrieves a new device token. + */ +class CreateDeviceToken extends APIController { + setup: ISetupController = { + allowTokens: [], + zBodyParser: z.any(), + }; + + public async main() { + const response = await createDeviceToken(this.bodyParams?.device, this.bodyParams); + this.body = response; + } +} + +/** + * Lists all the tokens of a device. + */ +class ListDeviceTokens extends APIController> { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zDeviceTokenListQuery, + zURLParamsParser: zURLParamsID, + }; + + public async main() { + const response = await getDeviceTokenList(this.urlParams.id, this.queryStringParams); + this.body = response; + } +} + +/** + * Lists all the devices. + */ +class ListDevices extends APIController { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zDeviceListQuery, + }; + + public async main() { + const response = await getDeviceList(this.queryStringParams); + this.body = response; + } +} + +/** + * Retrieves all the information of a single device. + */ +class GetDeviceInfo extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + const response = await getDeviceInfo(this.urlParams.id); + this.body = response; + } +} + +/** + * Deletes a single device. + */ +class DeleteDevice extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await deleteDevice(this.urlParams.id); + } +} + +/** + * Edits a single device. + */ +class EditDevice extends APIController> { + setup: ISetupController = { + allowTokens: [], + zBodyParser: zDeviceEdit, + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await editDevice(this.urlParams.id, this.bodyParams); + } +} + +/** + * Creates a new device. + */ +class CreateDevice extends APIController { + setup: ISetupController = { + allowTokens: [], + zBodyParser: zDeviceCreate, + }; + + public async main() { + const response = await createDevice(this.bodyParams); + this.body = response; + } +} + +/** + * Exports the routes of the device. + */ +export default (app: Application) => { + app.delete("/device/:id", warm(DeleteDevice)); + app.get("/device", warm(ListDevices)); + app.get("/device/:id", warm(GetDeviceInfo)); + app.post("/device", warm(CreateDevice)); + app.put("/device/:id", warm(EditDevice)); + + app.post("/device/token", warm(CreateDeviceToken)); + app.get("/device/token/:id", warm(ListDeviceTokens)); + app.delete("/device/token/:id", warm(DeleteDeviceToken)); + + app.get("/device/:id/params", warm(GetDeviceParamList)); + app.post("/device/:id/params", warm(SetDeviceParams)); +}; diff --git a/packages/tcore-api/src/Controllers/DeviceData/DeviceData.test.ts b/packages/tcore-api/src/Controllers/DeviceData/DeviceData.test.ts new file mode 100644 index 00000000..f1674214 --- /dev/null +++ b/packages/tcore-api/src/Controllers/DeviceData/DeviceData.test.ts @@ -0,0 +1,64 @@ +import { createServer, Server } from "http"; +import express from "express"; +import axios from "axios"; +import { callbackInterval } from "../../Plugins/Worker/Worker"; +import APIController from "../APIController"; +import * as Service from "../../Services/DeviceData/DeviceData"; +import Controller from "./DeviceData"; + +const app = express(); +let httpServer: Server | null = null; + +beforeEach(() => { + httpServer = createServer(app); + httpServer.listen(8888); + Controller(app); +}); + +afterEach(() => { + httpServer?.close(); +}); + +afterAll(() => { + httpServer?.close(); + if (callbackInterval) { + clearTimeout(callbackInterval); + } +}); + +const mockDevice = { + name: "My Device #1", + id: "5fa986a120210000264fc684", +}; + +test("throws error if there isn't a device token", async () => { + const fn = jest.fn(); + await axios.get("http://localhost:8888/data").catch(fn); + expect(fn).toHaveBeenCalled(); +}); + +test("throws error if device token isn't valid", async () => { + const fn = jest.fn(); + await axios.get("http://localhost:8888/data").catch(fn); + expect(fn).toHaveBeenCalled(); +}); + +test("retrieves value from getDeviceData function", async () => { + jest.spyOn(APIController.prototype as any, "resolveDeviceFromToken").mockResolvedValue(mockDevice); + jest.spyOn(Service, "getDeviceData").mockResolvedValue([1, 2, 3] as any); + const response = await axios.get("http://localhost:8888/data"); + expect(response.data).toEqual({ status: true, result: [1, 2, 3] }); + expect(response.status).toEqual(200); +}); + +test("calls getDeviceData with correct arguments", async () => { + const fn = jest.spyOn(Service, "getDeviceData").mockResolvedValue([]); + await axios.get("http://localhost:8888/data"); + expect(fn).toHaveBeenCalledWith(mockDevice.id, { ordination: "desc", qty: 15, query: "defaultQ", skip: 0 }); +}); + +test("respects query parameter in queryString", async () => { + const fn = jest.spyOn(Service, "getDeviceData").mockResolvedValue([]); + await axios.get("http://localhost:8888/data?query=last_value"); + expect(fn).toHaveBeenCalledWith(mockDevice.id, { ordination: "desc", qty: 15, query: "last_value", skip: 0 }); +}); diff --git a/packages/tcore-api/src/Controllers/DeviceData/DeviceData.ts b/packages/tcore-api/src/Controllers/DeviceData/DeviceData.ts new file mode 100644 index 00000000..d7cf465d --- /dev/null +++ b/packages/tcore-api/src/Controllers/DeviceData/DeviceData.ts @@ -0,0 +1,170 @@ +import { Application } from "express"; +import { z } from "zod"; +import { IDeviceDataQuery, zDeviceDataQuery } from "@tago-io/tcore-sdk/types"; +import { + addDeviceDataByDevice, + deleteDeviceData, + editDeviceData, + emptyDevice, + getDeviceData, + getDeviceDataAmount, +} from "../../Services/DeviceData/DeviceData"; +import { emitToLiveInspector, getLiveInspectorID } from "../../Services/LiveInspector"; +import APIController, { ISetupController, warm } from "../APIController"; + +/** + * Configuration for ID in the URL. + */ +const zURLParamsID = z.object({ + id: z.string(), +}); + +/** + * Adds data into a device. + */ +class AddData extends APIController { + setup: ISetupController = { + allowTokens: [], + zBodyParser: z.any(), // needs to be any because of raw payload + }; + + async main() { + const device = await this.resolveDeviceFromToken(); + + const liveInspectorID = getLiveInspectorID(device); + const inspectorMsg = [ + { title: "[POST] HTTP Request", content: this.resolveAgentString() }, + { title: "Query params", content: this.queryStringParams }, + ]; + emitToLiveInspector(device, inspectorMsg, liveInspectorID); + + const result = await addDeviceDataByDevice(device, this.bodyParams, { liveInspectorID }); + this.body = result; + this.successStatus = 202; + } +} + +/** + * Deletes data from a device. + */ +class DeleteData extends APIController { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zDeviceDataQuery, + }; + + async main() { + const device = await this.resolveDeviceFromToken(); + const result = await deleteDeviceData(device.id, this.queryStringParams); + this.body = `${result} Data removed`; + } +} + +/** + * Gets the device data by device token. + */ +class GetDataByToken extends APIController { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zDeviceDataQuery, + }; + + async main() { + const device = await this.resolveDeviceFromToken(); + const result = await getDeviceData(device.id, this.queryStringParams); + this.body = result; + } +} + +/** + * Edits device data by device id. + */ +class EditDataByDeviceID extends APIController> { + setup: ISetupController = { + allowTokens: [], + zBodyParser: z.any(), + zURLParamsParser: zURLParamsID, + }; + + async main() { + const result = await editDeviceData(this.urlParams.id, this.bodyParams); + this.body = result; + } +} + +/** + * Delete device data by id. + */ +class DeleteDataByDeviceID extends APIController> { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zDeviceDataQuery, + zURLParamsParser: zURLParamsID, + }; + + async main() { + const result = await deleteDeviceData(this.urlParams.id, this.queryStringParams); + this.body = result; + } +} + +/** + * Gets the device data by the device id. + */ +class GetDataByID extends APIController> { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zDeviceDataQuery, + zURLParamsParser: zURLParamsID, + }; + + async main() { + const result = await getDeviceData(this.urlParams.id, this.queryStringParams); + this.body = result; + } +} + +/** + * Deletes variables of a device. + */ +class EmptyDevice extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + async main() { + await emptyDevice(this.urlParams.id); + this.body = "Successfully Removed"; + } +} + +/** + * Retrieves the data amount of a device. + */ +class GetDataAmount extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + const response = await getDeviceDataAmount(this.urlParams.id); + this.body = response; + } +} + +/** + * Exports the routes of the device. + */ +export default (app: Application) => { + app.get("/device/:id/data", warm(GetDataByID)); + app.post("/device/:id/empty", warm(EmptyDevice)); + app.put("/device/:id/data", warm(EditDataByDeviceID)); + app.delete("/device/:id/data", warm(DeleteDataByDeviceID)); + app.get("/device/:id/data_amount", warm(GetDataAmount)); + + app.delete("/data", warm(DeleteData)); + app.get("/data", warm(GetDataByToken)); + app.post("/data", warm(AddData)); +}; diff --git a/packages/tcore-api/src/Controllers/File.ts b/packages/tcore-api/src/Controllers/File.ts new file mode 100644 index 00000000..65fc6605 --- /dev/null +++ b/packages/tcore-api/src/Controllers/File.ts @@ -0,0 +1,33 @@ +import { Application } from "express"; +import { z } from "zod"; +import { getFileList } from "../Services/FilePicker"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Configuration of a `path` property in the query string. + */ +const zQueryStringPath = z.object({ + path: z.string(), + local_fs: z.any().optional(), +}); + +/** + * Lists all the files. + */ +class GetFileList extends APIController, void> { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zQueryStringPath, + }; + + public async main() { + this.body = await getFileList(this.queryStringParams.path); + } +} + +/** + * Exports the routes of the files. + */ +export default (app: Application) => { + app.get("/file", warm(GetFileList)); +}; diff --git a/packages/tcore-api/src/Controllers/Hardware.ts b/packages/tcore-api/src/Controllers/Hardware.ts new file mode 100644 index 00000000..347f9f55 --- /dev/null +++ b/packages/tcore-api/src/Controllers/Hardware.ts @@ -0,0 +1,70 @@ +import { Application } from "express"; +import { getPlatformAndArch } from "../Helpers/Platform"; +import { getComputerUsage, getNetworkInfo, getOSInfo } from "../Services/Hardware"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Retrieves some of the information of the operational system. + */ +class GetOSInfo extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const response = await getOSInfo(); + this.body = response; + } +} + +/** + * Retrieves some of the information of the network. + */ +class GetNetworkInfo extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const response = await getNetworkInfo(); + this.body = response; + } +} + +/** + * Retrieves the platform and arch for this computer. + */ +class GetPlatformInfo extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const response = getPlatformAndArch(); + this.body = response; + } +} + +/** + * Retrieves the usage of this computer. + */ +class GetUsageInfo extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const response = await getComputerUsage(); + this.body = response; + } +} + +/** + * Exports the routes of the analysis. + */ +export default (app: Application) => { + app.get("/hardware/os", warm(GetOSInfo)); + app.get("/hardware/usage", warm(GetUsageInfo)); + app.get("/hardware/network", warm(GetNetworkInfo)); + app.get("/hardware/platform", warm(GetPlatformInfo)); +}; diff --git a/packages/tcore-api/src/Controllers/Logs.ts b/packages/tcore-api/src/Controllers/Logs.ts new file mode 100644 index 00000000..224c9c71 --- /dev/null +++ b/packages/tcore-api/src/Controllers/Logs.ts @@ -0,0 +1,48 @@ +import { Application } from "express"; +import { z } from "zod"; +import { getLogChannelInfo, getLogChannelList } from "../Services/Logs"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Configuration for ID in the URL. + */ +const zURLParamsID = z.object({ + id: z.string(), +}); + +/** + * Retrieves all the information of a single log channel. + */ +class GetLogChannelInfo extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + const channels = await getLogChannelInfo(this.urlParams.id); + this.body = channels; + } +} + +/** + * Lists all the log channels. + */ +class ListLogChannels extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const channels = await getLogChannelList(); + this.body = channels; + } +} + +/** + * Exports the routes of the logs. + */ +export default (app: Application) => { + app.get("/logs", warm(ListLogChannels)); + app.get("/logs/:id", warm(GetLogChannelInfo)); +}; diff --git a/packages/tcore-api/src/Controllers/Plugins.ts b/packages/tcore-api/src/Controllers/Plugins.ts new file mode 100644 index 00000000..951534c0 --- /dev/null +++ b/packages/tcore-api/src/Controllers/Plugins.ts @@ -0,0 +1,299 @@ +import path from "path"; +import { Request, Response, Application } from "express"; +import { z } from "zod"; +import { IActionTypeModuleSetup, zPluginType } from "@tago-io/tcore-sdk/types"; +import { setPluginModulesSettings } from "../Services/Settings"; +import { plugins } from "../Plugins/Host"; +import { + getPluginInfo, + getLoadedPluginList, + getModuleList, + startPluginModule, + stopPluginModule, + enablePlugin, + disablePlugin, + startPlugin, + stopPlugin, +} from "../Services/Plugins"; +import { installPlugin } from "../Plugins/Install"; +import { uninstallPlugin } from "../Plugins/Uninstall"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Configuration for ID in the URL. + */ +const zURLParamsID = z.object({ + id: z.string(), +}); + +/** + * Configuration for type in the query string. + */ +const zQueryStringType = z.object({ + type: zPluginType.nullish(), +}); + +/** + * Configuration for query strings of the uninstall route. + */ +const zUninstallQueryString = z.object({ + keep_data: z.preprocess((e) => e === "true" || e === "1", z.boolean()).optional(), +}); + +type IURLParamsID = z.infer; + +/** + * Lists all the database plugins. + */ +class UninstallPlugin extends APIController, IURLParamsID> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + zQueryStringParser: zUninstallQueryString, + }; + + public async main() { + const response = await uninstallPlugin(this.urlParams.id, this.queryStringParams.keep_data); + this.body = response; + } +} + +/** + * Lists all modules or modules from a specific type. + */ +class ListModules extends APIController, void> { + setup: ISetupController = { + allowTokens: [], + zQueryStringParser: zQueryStringType, + }; + + public async main() { + const response = getModuleList(this.queryStringParams.type).map((x) => ({ + pluginID: x.plugin?.id, + pluginName: x.plugin?.tcoreName, + setupID: x.setup.id, + setupName: x.setup.name, + })); + this.body = response; + } +} + +/** + * Lists all the plugins. + */ +class ListPlugins extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const response = await getLoadedPluginList(); + this.body = response; + } +} + +/** + * Starts/restarts a plugin module. + */ +class StartPluginModule extends APIController { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: z.any(), + }; + + public async main() { + await startPluginModule(this.urlParams.pluginID, this.urlParams.moduleID); + } +} + +/** + * Stops a plugin module. + */ +class StopPluginModule extends APIController { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: z.any(), + }; + + public async main() { + await stopPluginModule(this.urlParams.pluginID, this.urlParams.moduleID); + } +} + +/** + * Installs a plugin. + */ +class InstallPlugin extends APIController { + setup: ISetupController = { + allowTokens: [], + zBodyParser: z.any(), + }; + + public async main() { + await installPlugin(this.bodyParams.source, { log: true, start: true }); + } +} + +/** + * Enables a plugin (if not enabled yet). + */ +class EnablePlugin extends APIController { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await enablePlugin(this.urlParams.id); + } +} + +/** + * Disables a plugin (if not disabled yet). + */ +class DisablePlugin extends APIController { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await disablePlugin(this.urlParams.id); + } +} + +/** + * Starts a plugin (if not started yet). + */ +class StartPlugin extends APIController { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await startPlugin(this.urlParams.id); + } +} + +/** + * Stops a plugin (if not Stopped yet). + */ +class StopPlugin extends APIController { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + await stopPlugin(this.urlParams.id); + } +} + +/** + * Edits a plugin's settings. + */ +class EditPluginSettings extends APIController { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + zBodyParser: z.any(), + }; + + public async main() { + await setPluginModulesSettings(this.urlParams.id, this.bodyParams); + + const plugin = plugins.get(this.urlParams.id); + if (plugin && plugin?.state !== "disabled" && plugin.state !== "started") { + await plugin.start(); + } + + const cache = {}; + for (const item of this.bodyParams) { + if (!cache[item.moduleID]) { + cache[item.moduleID] = true; + await startPluginModule(this.urlParams.id, item.moduleID); + } + } + } +} + +/** + * Lists all the plugins. + */ +class GetPluginInfo extends APIController { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + const response = await getPluginInfo(this.urlParams.id); + this.body = response; + } +} + +/** + * Resolves the request for a plugin image. + */ +export async function resolvePluginImage(req: Request, res: Response) { + const { type, identifier } = req.params; + const plugin = plugins.get(req.params.plugin); + const tcorePkg = plugin?.package?.tcore; + let fullImagePath = ""; + + if (plugin && tcorePkg) { + if (type === "icon" && tcorePkg.icon) { + // icon (thumbnail/logo) of the plugin + fullImagePath = path.join(plugin.folder, tcorePkg.icon); + } else if (type === "action") { + // icon for the action type + const module = plugin.modules.get(identifier); + const option = (module?.setup as any as IActionTypeModuleSetup)?.option; + fullImagePath = option?.icon?.replace("$PLUGIN_FOLDER$", plugin.folder) || ""; + } + } + + if (fullImagePath) { + res.sendFile(fullImagePath); + } else { + res.sendStatus(404); + } +} + +/** + * Resolves the request for a plugin image. + */ +export async function resolvePluginImage2(req: Request, res: Response) { + const split = req.path.split("/").filter((x) => x); + split.splice(0, 1); + + const [pluginID] = split.splice(0, 1); // pop the plugin id + const plugin = plugins.get(pluginID); + if (!plugin) { + return res.sendStatus(404); + } + + const imgPath = split.join(path.sep); + const fullPath = path.join(plugin.folder, imgPath); + + res.sendFile(fullPath); +} + +/** + * Exports the plugin routes. + */ +export default (app: Application) => { + app.get("/module", warm(ListModules)); + app.get("/plugin-uninstall/:id", warm(UninstallPlugin)); + app.get("/plugin", warm(ListPlugins)); + app.get("/plugin/:id", warm(GetPluginInfo)); + app.post("/plugin/:pluginID/:moduleID/start", warm(StartPluginModule)); + app.post("/plugin/:pluginID/:moduleID/stop", warm(StopPluginModule)); + app.post("/install-plugin", warm(InstallPlugin)); + app.put("/plugin/:id", warm(EditPluginSettings)); + app.post("/plugin/:id/enable", warm(EnablePlugin)); + app.post("/plugin/:id/disable", warm(DisablePlugin)); + app.post("/plugin/:id/start", warm(StartPlugin)); + app.post("/plugin/:id/stop", warm(StopPlugin)); +}; diff --git a/packages/tcore-api/src/Controllers/Settings.ts b/packages/tcore-api/src/Controllers/Settings.ts new file mode 100644 index 00000000..1731735f --- /dev/null +++ b/packages/tcore-api/src/Controllers/Settings.ts @@ -0,0 +1,47 @@ +import { ISettings, zSettings } from "@tago-io/tcore-sdk/types"; +import { Application } from "express"; +import { getMainSettings, setMainSettings } from "../Services/Settings"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Edits the settings. + */ +class EditSettings extends APIController { + setup: ISetupController = { + allowTokens: [], + zBodyParser: zSettings, + }; + + public async main() { + await setMainSettings(this.bodyParams); + } +} + +/** + * Retrieves all the information of the settings. + */ +class GetSettingsInfo extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const settings = await getMainSettings(); + this.body = { + settings, + metadata: { + database_plugin_disabled: !!process.env.TCORE_DATABASE_PLUGIN, + plugin_folder_disabled: !!process.env.TCORE_PLUGIN_FOLDER, + port_disabled: !!process.env.TCORE_PORT, + }, + }; + } +} + +/** + * Exports the routes of the device. + */ +export default (app: Application) => { + app.put("/settings", warm(EditSettings)); + app.get("/settings", warm(GetSettingsInfo)); +}; diff --git a/packages/tcore-api/src/Controllers/Statistic.ts b/packages/tcore-api/src/Controllers/Statistic.ts new file mode 100644 index 00000000..a17300b6 --- /dev/null +++ b/packages/tcore-api/src/Controllers/Statistic.ts @@ -0,0 +1,24 @@ +import { Application } from "express"; +import { getHourlyStatistics } from "../Services/Statistic"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Retrieves all statistics from the last hour. + */ +class GetHourlyStatistic extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const response = await getHourlyStatistics(); + this.body = response; + } +} + +/** + * Exports the routes of the analysis. + */ +export default (app: Application) => { + app.get("/statistics", warm(GetHourlyStatistic)); +}; diff --git a/packages/tcore-api/src/Controllers/Summary.ts b/packages/tcore-api/src/Controllers/Summary.ts new file mode 100644 index 00000000..2ad12a08 --- /dev/null +++ b/packages/tcore-api/src/Controllers/Summary.ts @@ -0,0 +1,24 @@ +import { Application } from "express"; +import { getSummary } from "../Services/Summary"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Retrieves the summary information. + */ +class GetSummaryInfo extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const response = await getSummary(); + this.body = response; + } +} + +/** + * Exports the routes of the analysis. + */ +export default (app: Application) => { + app.get("/summary", warm(GetSummaryInfo)); +}; diff --git a/packages/tcore-api/src/Controllers/System.ts b/packages/tcore-api/src/Controllers/System.ts new file mode 100644 index 00000000..f5786896 --- /dev/null +++ b/packages/tcore-api/src/Controllers/System.ts @@ -0,0 +1,46 @@ +import fs from "fs"; +import path from "path"; +import { Application } from "express"; +// @ts-ignore +import pkg from "../../../../package.json"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Retrieves the status information. + */ +class GetStatus extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const version = pkg.version; + this.body = { version }; + } +} + +/** + * Retrieves the changelog information. + */ +class GetChangelog extends APIController { + setup: ISetupController = { + allowTokens: [], + }; + + public async main() { + const changelogPath = path.join(__dirname, "../../../../CHANGELOG.md"); + const changelogMD = await fs.promises.readFile(changelogPath); + + this.useBodyWrapper = false; + this.res.set("Content-Type", "text/plain"); + this.body = changelogMD; + } +} + +/** + * Exports the routes of the system. + */ +export default (app: Application) => { + app.get("/status", warm(GetStatus)); + app.get("/changelog", warm(GetChangelog)); +}; diff --git a/packages/tcore-api/src/Controllers/Tag.ts b/packages/tcore-api/src/Controllers/Tag.ts new file mode 100644 index 00000000..d2ebd0f2 --- /dev/null +++ b/packages/tcore-api/src/Controllers/Tag.ts @@ -0,0 +1,33 @@ +import { Application } from "express"; +import { z } from "zod"; +import { getTagKeys } from "../Services/Tag"; +import APIController, { ISetupController, warm } from "./APIController"; + +/** + * Configuration for ID in the URL. + */ +const zURLParamsID = z.object({ + id: z.string(), +}); + +/** + * Retrieves all the tag keys of a resource type. + */ +class GetTagKeys extends APIController> { + setup: ISetupController = { + allowTokens: [], + zURLParamsParser: zURLParamsID, + }; + + public async main() { + const response = await getTagKeys(this.urlParams.id); + this.body = response; + } +} + +/** + * Exports the routes of the analysis. + */ +export default (app: Application) => { + app.get("/tags/keys/:id", warm(GetTagKeys)); +}; diff --git a/packages/tcore-api/src/Helpers/CPU.ts b/packages/tcore-api/src/Helpers/CPU.ts new file mode 100644 index 00000000..a980a2ed --- /dev/null +++ b/packages/tcore-api/src/Helpers/CPU.ts @@ -0,0 +1,42 @@ +import os from "os"; + +/** + */ +function getCPUInfo() { + const cpus = os.cpus(); + let total = 0; + let idle = 0; + + for (const key in cpus) { + const cpu = cpus[key]; + total += cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.irq + cpu.times.idle; + idle += cpu.times.idle; + } + + return { + idle: idle, + total: total, + }; +} + +/** + */ +export function getCpuPercentage(): Promise { + const stats1 = getCPUInfo(); + const startIdle = stats1.idle; + const startTotal = stats1.total; + + return new Promise((resolve) => { + setTimeout(function () { + const stats2 = getCPUInfo(); + const endIdle = stats2.idle; + const endTotal = stats2.total; + + const idle = endIdle - startIdle; + const total = endTotal - startTotal; + const percentage = idle / total; + + resolve((1 - percentage) * 100); + }, 1000); + }); +} diff --git a/packages/tcore-api/src/Helpers/Download.ts b/packages/tcore-api/src/Helpers/Download.ts new file mode 100644 index 00000000..c7ec885d --- /dev/null +++ b/packages/tcore-api/src/Helpers/Download.ts @@ -0,0 +1,55 @@ +import path from "path"; +import fs from "fs"; +import axios from "axios"; + +/** + * Options to pass to the `downloadFile` function. + */ +interface IDownloadFileOptions { + filename?: string; + // eslint-disable-next-line no-unused-vars + onProgress?: (percent: number) => void; +} + +/** + * Downloads a file and stores it into a folder. + * @param {string} url HTTP/HTTPS URL. + */ +export async function downloadFile(url: string, dest: string, opts?: IDownloadFileOptions) { + const response = await axios({ method: "GET", url, responseType: "stream" }); + const fileSize = Number(response.headers["content-length"] || 0); + + const destFolder = dest; + const tempFilePath = path.join(destFolder, opts?.filename || "tcore-download"); + const fileStream = fs.createWriteStream(tempFilePath); + + let downloadedSize = 0; + let lastPercentage = 0; + + return new Promise((resolve, reject) => { + if (fileSize) { + response.data.on("data", (chunk: Buffer) => { + downloadedSize += chunk.length; + const percentage = (downloadedSize / fileSize) * 100; + const shouldOutput = percentage === 100 || percentage > lastPercentage + 5; + if (shouldOutput) { + // only outputs every 5% or at 100% to not overwhelm the socket server + lastPercentage = percentage; + opts?.onProgress?.(percentage); + } + }); + } + + fileStream.on("finish", () => { + fileStream.close(); + resolve(tempFilePath); + }); + + fileStream.on("error", (error) => { + fileStream.close(); + reject(error); + }); + + response.data.pipe(fileStream); + }); +} diff --git a/packages/tcore-api/src/Helpers/Files.ts b/packages/tcore-api/src/Helpers/Files.ts new file mode 100644 index 00000000..b78eba52 --- /dev/null +++ b/packages/tcore-api/src/Helpers/Files.ts @@ -0,0 +1,35 @@ +import fs from "fs"; +import path from "path"; + +/** + * Removes directory recursively. + */ +async function rmdir(dir: string) { + if (!fs.existsSync(dir)) { + return; + } + + if (!dir || dir === "/") { + return; + } + + const list = await fs.promises.readdir(dir); + for (let i = 0; i < list.length; i++) { + const filename = path.join(dir, list[i]); + const stat = fs.statSync(filename); + + if (filename == "." || filename == "..") { + // pass these files + } else if (stat.isDirectory()) { + // rmdir recursively + await rmdir(filename); + } else { + // rm filename + await fs.promises.unlink(filename); + } + } + + await fs.promises.rmdir(dir); +} + +export { rmdir }; diff --git a/packages/tcore-api/src/Helpers/Platform.ts b/packages/tcore-api/src/Helpers/Platform.ts new file mode 100644 index 00000000..0690f0e5 --- /dev/null +++ b/packages/tcore-api/src/Helpers/Platform.ts @@ -0,0 +1,63 @@ +import { spawnSync } from "child_process"; + +const isAlpine = detectAlpine(); + +/** + * Detects if the current platform is alpine or not. + */ +function detectAlpine() { + const { platform } = process; + if (platform !== "linux") { + return false; + } + + // https://github.com/sass/node-sass/issues/1589#issuecomment-265292579 + const ldd = spawnSync("ldd").stderr.toString(); + + if (/\bmusl\b/.test(ldd)) { + return true; + } + + const lddNode = spawnSync("ldd", [process.execPath]).stdout.toString(); + return /\bmusl\b/.test(lddNode); +} + +/** + * Gets the platform for this computer. + */ +function getPlatform() { + const platform = process.platform as string; + + if (isAlpine) { + return "alpine"; + } + + if (platform === "darwin") return "mac"; + if (platform === "lin") return "linux"; + if (platform === "macos") return "mac"; + if (platform === "osx") return "mac"; + if (platform === "win32") return "win"; + if (platform === "windows") return "win"; + + return platform; +} + +/** + * Gets the CPU architecture for this computer. + */ +function getArch() { + if (process.arch === "arm") return "armv7"; + if (process.arch === "ia32") return "x86"; + if (process.arch === "x86_64") return "x64"; + return process.arch; +} + +/** + * Gets the platform and arch in a single string. + * The format returned is `platform-arch`. + */ +export function getPlatformAndArch() { + const platform = getPlatform(); + const arch = getArch(); + return `${platform}-${arch}`; +} diff --git a/packages/tcore-api/src/Helpers/Tar/Tar.ts b/packages/tcore-api/src/Helpers/Tar/Tar.ts new file mode 100644 index 00000000..7e45e596 --- /dev/null +++ b/packages/tcore-api/src/Helpers/Tar/Tar.ts @@ -0,0 +1,44 @@ +import zlib from "zlib"; +import fs from "fs"; +import tar from "tar"; + +/** + * Extracts a tar into a folder. + */ +export async function extractTar(tarPath: string, destination: string, useGzip = false): Promise { + // creates the destination folder if it doesn't exist + await fs.promises.mkdir(destination, { recursive: true }); + + return await new Promise((resolve, reject) => { + let stream: any = fs.createReadStream(tarPath); + + if (useGzip) { + stream = stream.pipe(zlib.createGunzip()); + } + + stream + .pipe(tar.extract({ C: destination })) + .on("error", reject) + .on("finish", resolve); + }); +} + +/** + * Peeks a tar file without extracting it. + */ +export async function peekTarFile(tarPath: string, fileName: string): Promise { + const data: Uint8Array[] = []; + + /** + * Called for each file inside of the tar. + */ + const onEntry = (entry: any) => { + if (entry.path === `./${fileName}` || entry.path === fileName) { + entry.on("data", (chunk: Uint8Array) => data.push(chunk)); + } + }; + + return await new Promise((resolve) => { + tar.list({ file: tarPath, onentry: onEntry }, [], () => resolve(data)); + }); +} diff --git a/packages/tcore-api/src/Helpers/Yaml.ts b/packages/tcore-api/src/Helpers/Yaml.ts new file mode 100644 index 00000000..5a916d63 --- /dev/null +++ b/packages/tcore-api/src/Helpers/Yaml.ts @@ -0,0 +1,30 @@ +import fs from "fs/promises"; +import path from "path"; +import yaml from "js-yaml"; + +/** + * Converts a JSON to a .yml and saves it into a file. + */ +export async function saveYml(json: any, filePath: string): Promise { + try { + const file = yaml.dump(json); + const folder = path.join(filePath, ".."); + await fs.mkdir(folder, { recursive: true }); + await fs.writeFile(filePath, file); + } catch (ex) { + // TODO handle better + } +} + +/** + * Gets a .yml file and converts it into a JSON. + */ +export async function loadYml(path: string, defaultValue = {}): Promise { + try { + const file = await fs.readFile(path, { encoding: "utf8" }); + const json = yaml.load(file); + return json || defaultValue; + } catch (ex) { + return defaultValue; + } +} diff --git a/packages/tcore-api/src/Helpers/Zip.ts b/packages/tcore-api/src/Helpers/Zip.ts new file mode 100644 index 00000000..6f7e5dc9 --- /dev/null +++ b/packages/tcore-api/src/Helpers/Zip.ts @@ -0,0 +1,14 @@ +import fs from "fs"; +import extract from "extract-zip"; + +/** + * Extracts a zip into a folder. + */ +async function extractZip(zipFile: string, destination: string): Promise { + // creates the destination folder if it doesn't exist + await fs.promises.mkdir(destination, { recursive: true }); + + await extract(zipFile, { dir: destination }); +} + +export { extractZip }; diff --git a/packages/tcore-api/src/Helpers/log.ts b/packages/tcore-api/src/Helpers/log.ts new file mode 100644 index 00000000..054376f2 --- /dev/null +++ b/packages/tcore-api/src/Helpers/log.ts @@ -0,0 +1,81 @@ +import { ESocketRoom } from "@tago-io/tcore-sdk/types"; +import chalk from "chalk"; +import ora from "ora"; +import { getSystemName } from "../Services/System"; +import { plugins } from "../Plugins/Host"; +import { io } from "../Socket/SocketServer"; + +/** + * Contains a history of all logs in the application and in the plugins. + */ +export const logBuffer = new Map(); + +/** + * Adds the message to the log buffer. + */ +function addToBuffer(channel: string, type: string, ...args: any[]) { + if (!logBuffer.has(channel)) { + logBuffer.set(channel, []); + } + + const data: any = { + error: type === "error", + message: args.join(" "), + timestamp: new Date(), + type, + }; + + // push to log buffer + logBuffer.get(channel).push(data); + + // also emit to the frontend + io?.to(ESocketRoom.log).emit(`log::${channel}`, data); +} + +/** + */ +export function log(channel: string, ...args: any[]) { + addToBuffer(channel, "log", args); + internalLog(channel, ...args); +} + +/** + */ +export function logError(channel: string, ...args: any[]) { + addToBuffer(channel, "error", args); + const redArgs = args.map((x) => chalk.red(x.toString())); + internalLog(channel, ...redArgs); +} + +/** + */ +export function oraLog(channel: string, ...args: any[]) { + ora(...args).succeed(); + addToBuffer(channel, "log", ...args); +} + +/** + */ +export function oraLogError(channel: string, ...args: any[]) { + ora(...args).fail(); + addToBuffer(channel, "error", ...args); +} + +/** + * Internally logs a string. + */ +export function internalLog(channel: string, ...args: any[]) { + if (typeof args[args.length - 1] === "string") { + // trim the last line to prevent extras \n + args[args.length - 1] = args[args.length - 1].trim(); + } + + if (channel === "api") { + const colored = chalk.magenta(`[${getSystemName()}]`); + console.log(colored, ...args); + } else { + const plugin = plugins.get(String(channel).split(":")?.[1])?.tcoreName; + const colored = chalk.yellow(`[Plugin ${plugin}]`); + console.log(colored, ...args); + } +} diff --git a/packages/tcore-api/src/Helpers/removeNullValues.ts b/packages/tcore-api/src/Helpers/removeNullValues.ts new file mode 100644 index 00000000..e3e4a4f5 --- /dev/null +++ b/packages/tcore-api/src/Helpers/removeNullValues.ts @@ -0,0 +1,14 @@ +/** + * Removes all null and undefined values from an object. + */ +function removeNullValues(value: T): T { + for (const key in value) { + if (value[key] === null || value[key] === undefined) { + delete value[key]; + } + } + + return value; +} + +export default removeNullValues; diff --git a/packages/tcore-api/src/Helpers/shutdown.ts b/packages/tcore-api/src/Helpers/shutdown.ts new file mode 100644 index 00000000..258c22c0 --- /dev/null +++ b/packages/tcore-api/src/Helpers/shutdown.ts @@ -0,0 +1,64 @@ +/* eslint-disable no-async-promise-executor */ +import { Server } from "http"; +import { getSystemName } from "../Services/System"; +import { plugins } from "../Plugins/Host"; +import Plugin from "../Plugins/Plugin/Plugin"; +import { log } from "./log"; + +let shutdownTries = 0; + +/** + * Shuts down the server, all plugins, and then the application. + */ +export async function shutdown(httpServer: Server) { + log("api", `Shutting down ${getSystemName()} (${shutdownTries + 1}/3 tries)`); + + // increase the shutdown tries + shutdownTries += 1; + + // first we close the server before closing any plugins + httpServer.close(); + + if (shutdownTries >= 3) { + // forcefully exit + log("api", "Terminated with exit code 1"); + process.exit(1); + } + + const sortedPlugins = await sortPluginsByPriority(); + for (const plugin of sortedPlugins) { + await destroyPlugin(plugin); + } + + log("api", "Terminated with exit code 0"); + process.exit(0); +} + +/** + * Destroys a plugin. + * This will return the flow back to the main function only when the plugin calls the `destroy` event. + */ +async function destroyPlugin(plugin: Plugin) { + return new Promise(async (resolve) => { + await plugin.stop(false, 3000).catch(() => null); + resolve(); + }); +} + +/** + * Sorts the plugins by priority: + * First all the other plugins then the main database one. + */ +async function sortPluginsByPriority() { + const result: Plugin[] = []; + + for (const plugin of plugins.values()) { + if (plugin.types.includes("database")) { + result.unshift(plugin); + } else { + result.push(plugin); + } + } + + return result; +} diff --git a/packages/tcore-api/src/Helpers/splitColon.ts b/packages/tcore-api/src/Helpers/splitColon.ts new file mode 100644 index 00000000..bcf27883 --- /dev/null +++ b/packages/tcore-api/src/Helpers/splitColon.ts @@ -0,0 +1,9 @@ +/** + */ +function splitColon(value: string) { + const value1 = String(value).split(":")[0]; + const value2 = String(value).split(":")[1]; + return [value1, value2]; +} + +export default splitColon; diff --git a/packages/tcore-api/src/Plugins/Host.ts b/packages/tcore-api/src/Plugins/Host.ts new file mode 100644 index 00000000..5a624bb1 --- /dev/null +++ b/packages/tcore-api/src/Plugins/Host.ts @@ -0,0 +1,111 @@ +import { listPluginFolders } from "../Services/Plugins"; +import { oraLog, oraLogError } from "../Helpers/log"; +import { getMainSettings, getPluginSettings } from "../Services/Settings"; +import Plugin from "./Plugin/Plugin"; +import { generatePluginID } from "./PluginID"; +import { getPluginPackageJSON } from "./PluginPackage"; + +/** + * List of plugins paths that are built-in as soon as tcore boots up. + */ +export const BUILT_IN_PLUGINS = []; + +/** + * Map containing the a key with the name of a plugin and the value + * as an instance of the Plugin class. + */ +export const plugins: Map = new Map(); + +/** + */ +export async function startPlugin(folder: string) { + const plugin = new Plugin(folder); + const exists = plugins.get(plugin.id); + if (exists) { + // plugin already running and already inserted in the list + throw new Error("Plugin is already running"); + } + + plugins.set(plugin.id, plugin); + + const settings = await getPluginSettings(plugin.id); + if (settings.disabled) { + await plugin.disable(); + } else { + await plugin.start(); + } + + return plugin; +} + +/** + * Sorts all folders based on their priority: + * First the main database plugin then the other plugins. + */ +async function sortFoldersByPriority(folders: string[]): Promise { + const settings = await getMainSettings(); + const dbModuleID = String(settings.database_plugin).split(":")?.[0]; + + const result: string[] = []; + + for (const folder of folders) { + const pkg = await getPluginPackageJSON(folder); + if (!pkg) { + continue; + } + + const id = generatePluginID(pkg.name); + const isDatabase = dbModuleID === id || pkg?.tcore?.types?.includes("database"); + + if (isDatabase) { + // main database plugin gets priority over other plugins + result.unshift(folder); + } else { + // common plugin, not database + result.push(folder); + } + } + + return result; +} + +/** + * Initializes all the plugins. + */ +export async function startAllPlugins() { + const folders = await listPluginFolders(); + const sorted = await sortFoldersByPriority(folders); + + for (const folder of sorted) { + try { + const plugin = await startPlugin(folder); + + const modules = [...plugin.modules.values()]; + const errors = modules.filter((x) => x.error); + + if (errors.length === 1 && errors[0].error) { + // only one module threw an error, show a single line of error + throw new Error(errors[0].error); + } else if (errors.length > 1) { + // multiple modules threw errors, show multiline of errors, one for + // each module that threw an error + const msgs = errors.map((x) => ` - ${x.name}: ${x.error}`); + const join = msgs.join("\n"); + throw new Error(`\n${join}`); + } + + if (plugin.state === "started") { + oraLog("api", `Started Plugin: ${plugin.tcoreName}`); + } else if (plugin.state === "disabled") { + oraLog("api", `Skipped Disabled Plugin: ${plugin.tcoreName}`); + } + } catch (ex: any) { + const err = ex.message || ex; + + const pluginPkg = Plugin.getPackage(folder); + const pluginName = pluginPkg.tcore?.name || pluginPkg.name; + + oraLogError("api", `Failed to start Plugin ${pluginName || ""}: ${err}`); + } + } +} diff --git a/packages/tcore-api/src/Plugins/Install.ts b/packages/tcore-api/src/Plugins/Install.ts new file mode 100644 index 00000000..8f783671 --- /dev/null +++ b/packages/tcore-api/src/Plugins/Install.ts @@ -0,0 +1,281 @@ +import os from "os"; +import path from "path"; +import fs from "fs"; +import axios from "axios"; +import tar from "tar"; +import { ESocketRoom, IPluginInstallOptions } from "@tago-io/tcore-sdk/types"; +import { extractTar, peekTarFile } from "../Helpers/Tar/Tar"; +import { getPlatformAndArch } from "../Helpers/Platform"; +import { getMainSettings } from "../Services/Settings"; +import { logError, log } from "../Helpers/log"; +import { io } from "../Socket/SocketServer"; +import { generatePluginID } from "./PluginID"; +import { plugins, startPlugin } from "./Host"; +import { uninstallPlugin } from "./Uninstall"; + +/** + * Last progress emitted by the socket. We use this to keep track of it and + * maybe send the same progress if an error ocurred. + */ +let lastProgress: number | undefined = 0; + +/** + * Adds a log into the log buffer of the application and triggers the socket + * event for all sockets attached with the `pluginInstall` resource. + */ +function addLog(opts: IPluginInstallOptions, error: boolean, message: string, progress?: number) { + if (opts?.log) { + if (error) { + logError("api", message); + } else { + log("api", message); + } + } + + io?.to(ESocketRoom.pluginInstall).emit("plugin::install", { + error, + message, + progress: progress ?? lastProgress, + }); + + if (progress) { + lastProgress = progress; + } +} + +/** + * Gracefully stops the execution of the current version of the plugin. + * If the plugin is not currently running then this will do nothing. + */ +async function gracefullyStopCurrentVersion(pluginID: string, opts: IPluginInstallOptions = {}): Promise { + const plugin = plugins.get(pluginID); + if (plugin) { + addLog(opts, false, `Gracefully stopping current version, please wait...`, 98); + await plugin.stop(false, 10000).catch(() => null); + plugins.delete(pluginID); + } +} + +/** + * Extracts the `plugin.tar.gz` file into the plugins folder. + * First it decompresses the file into a simple .tar file (without the gzip) and then + * it proceeds to extract the tar into the plugins folder. + * @param {string} filePath The `plugin.tar.gz` full path location. + * @param {string} pluginID The plugin id to compose the folder name. + */ +async function extract(filePath: string, pluginID: string, opts: IPluginInstallOptions = {}): Promise { + const settings = await getMainSettings(); + const destination = path.join(settings.plugin_folder, pluginID); + + await extractTar(filePath, destination, true); + + addLog(opts, false, `Plugin successfully extracted`, 95); + + return destination; +} + +/** + * Tries to parse the package.json of the plugin and throws an error if it couldn't. + */ +async function parsePackageJSON(str: string): Promise { + try { + return JSON.parse(str); + } catch (ex) { + throw new Error("Invalid JSON data in package.json file"); + } +} + +/** + * This should be called when something went wrong during the installation or execution + * of a new version of a plugin. + * + * This function will delete the current folder of the plugin and replace it with the folder + * in the backup file. + */ +async function restoreBackup(backupFile: string, pluginID: string, opts: IPluginInstallOptions = {}) { + if (!backupFile || !pluginID) { + // backup file not created or plugin id was not acquired yet + return; + } + + const settings = await getMainSettings(); + + addLog(opts, false, `Starting backup restoration`); + + await uninstallPlugin(pluginID); + await extractTar(backupFile, settings.plugin_folder); + await fs.promises.unlink(backupFile); + + addLog(opts, false, `Backup successfully restored!`); + + try { + addLog(opts, false, `Starting the backup, please wait...`); + await startPlugin(path.join(settings.plugin_folder, pluginID)); + addLog(opts, false, `Done!`, 100); + } catch (ex: any) { + addLog(opts, true, "The backup was restored, but could not run"); + } +} + +/** + * Creates a backup of the plugin and stores it into a temporary folder. + * If something goes wrong during the extraction or execution of the new version + * then this backup should be restored. + */ +async function backupPlugin(pluginID: string, opts: IPluginInstallOptions = {}): Promise { + const settings = await getMainSettings(); + const pluginFolder = path.join(settings.plugin_folder, pluginID); + + const backupFile = path.join(pluginFolder, "..", `${pluginID}-bkp.tar`); + + await tar.create({ cwd: path.join(pluginFolder, ".."), file: backupFile }, [pluginID]); + + addLog(opts, false, `Created backup for current version`, 95); + + return backupFile; +} + +/** + * Validates the package.json of the file without extracting it. This function will + * throw an error if the plugin has no support for the current operating system. + */ +async function validatePackage(filePath: string): Promise { + const data: Uint8Array[] = await peekTarFile(filePath, "package.json"); + + if (data.length === 0) { + throw new Error( + "Could not read package.json file of plugin. Make sure the file exists and the plugin is in the .tar.gz format" + ); + } + + const str = Buffer.concat(data).toString(); + const pkg = await parsePackageJSON(str); + + const pluginPlatform = pkg?.tcore?.platform || "any"; + const thisPlatform = getPlatformAndArch(); + if (pluginPlatform !== thisPlatform && pluginPlatform !== "any") { + throw new Error(`The plugin is not compatible with this platform (only ${pluginPlatform})`); + } + + return pkg; +} + +/** + * Downloads a plugin file and stores it into a temporary folder. + * @param {string} url HTTP/HTTPS URL. + */ +async function downloadPlugin(url: string, opts: IPluginInstallOptions = {}): Promise { + addLog(opts, false, `Downloading plugin from URL (this may take a while) ...`, 35); + + const response = await axios({ method: "GET", url, responseType: "stream" }); + const fileSize = Number(response.headers["content-length"] || 0); + + const tempFolder = await fs.promises.mkdtemp(path.join(os.tmpdir(), "tcore-plugin-download")); + const tempFilePath = path.join(tempFolder, "plugin.tar.gz"); + const fileStream = fs.createWriteStream(tempFilePath); + + let downloadedSize = 0; + let lastPercentage = 0; + + return new Promise((resolve, reject) => { + if (fileSize) { + response.data.on("data", (chunk: Buffer) => { + downloadedSize += chunk.length; + const percentage = (downloadedSize / fileSize) * 100; + const shouldOutput = percentage === 100 || percentage > lastPercentage + 5; + if (shouldOutput) { + // only outputs every 5% or at 100% to not overwhelm the socket server + lastPercentage = percentage; + addLog(opts, false, `Downloading | Progress: ${percentage.toFixed(2)}%`, 35); + } + }); + } + + fileStream.on("finish", () => { + addLog(opts, false, `Plugin successfully downloaded`, 50); + fileStream.close(); + resolve(tempFilePath); + }); + + fileStream.on("error", (error) => { + fileStream.close(); + reject(error); + }); + + response.data.pipe(fileStream); + }); +} + +/** + * Resolves the source into a single file path in the system. + * If the source is a URL then the file will be downloaded and the resulting file path will be returned. + * If the source is a local file it will be returned as it is. + * @param {string} source Local path in the filesystem or a HTTP/HTTPS URL. + */ +async function resolveSource(source: string, opts: IPluginInstallOptions = {}) { + if (source.startsWith("http")) { + // online file, we need to download it + return await downloadPlugin(source, opts); + } else { + // local file, just return it because that's where the file is located + return source; + } +} + +/** + * Installs a plugin from a source. + * @param {string} source Local path in the filesystem or a HTTP/HTTPS URL. + */ +export async function installPlugin(source: string, opts: IPluginInstallOptions = {}) { + addLog(opts, false, `Installing plugin`, 0); + + let pluginPath = ""; + let backupFile = ""; + let pluginID = ""; + + try { + const filePath = await resolveSource(source, opts); + const pluginPkg = await validatePackage(filePath); + pluginID = generatePluginID(pluginPkg.name); + + const settings = await getMainSettings(); + const pluginFolder = path.join(settings.plugin_folder, pluginID); + const exists = fs.existsSync(pluginFolder); + if (exists) { + // plugin is already installed. + // we need to gracefully stop the plugin because we will override it with new files + await gracefullyStopCurrentVersion(pluginID, opts); + + // we also need to make a backup of the current files in case something goes wrong + // during the execution or installation of the new version + backupFile = await backupPlugin(pluginID, opts); + } + + pluginPath = await extract(filePath, pluginID, opts); + + addLog(opts, false, `Plugin successfully installed`, 99); + } catch (ex: any) { + addLog(opts, true, `An error ocurred: ${ex.message}`); + addLog(opts, true, "The plugin was not installed"); + + await restoreBackup(backupFile, pluginID, opts); + throw ex; + } + + if (opts?.start) { + try { + addLog(opts, false, `Starting the plugin, please wait...`, 99); + + await startPlugin(pluginPath); + + addLog(opts, false, `Done!`, 100); + } catch (ex: any) { + addLog(opts, true, ex.message || String(ex)); + addLog(opts, true, "The plugin was installed, but could not run"); + await restoreBackup(backupFile, pluginID, opts); + throw ex; + } + } else { + addLog(opts, false, `Done!`, 100); + } +} diff --git a/packages/tcore-api/src/Plugins/Module/Module.ts b/packages/tcore-api/src/Plugins/Module/Module.ts new file mode 100644 index 00000000..22a45bfa --- /dev/null +++ b/packages/tcore-api/src/Plugins/Module/Module.ts @@ -0,0 +1,142 @@ +/* eslint-disable no-unused-vars */ +import { ESocketRoom, IModuleSetup, TModuleState } from "@tago-io/tcore-sdk/types"; +import { flattenConfigFields } from "@tago-io/tcore-shared"; +import { io } from "../../Socket/SocketServer"; +import { getPluginSettings } from "../../Services/Settings"; +import Plugin from "../Plugin/Plugin"; + +/** + * Class that manages a single module of a plugin. + */ +class Module { + public error: string | null; + public id: string; + public message: any = null; + public name: string; + public state: TModuleState; + + constructor(public plugin: Plugin, public setup: IModuleSetup) { + this.name = setup.name; + this.id = setup.id; + this.state = "idle"; + this.error = null; + } + + /** + * Invokes a function in the module. + */ + public async invoke(method: string, ...args: any[]) { + if (this.state !== "started") { + throw new Error(`Module "${this.name}" is not running`); + } + const result = await this.plugin.worker.invoke(this.setup.id, method, ...args); + return result; + } + + /** + * Invokes the "stop" (onDestroy) function of the module. + */ + public async stop() { + if (this.plugin.state === "stopped" || this.plugin.state === "disabled") { + throw new Error("Plugin is stopped"); + } + try { + this.error = null; + this.state = "stopping"; + this.emitSocketUpdate(); + + await this.plugin.worker.invoke(this.setup.id, "stop"); + + this.error = null; + this.state = "stopped"; + } catch (ex: any) { + this.error = ex?.message || String(ex); + this.state = "stopped"; + throw ex; + } finally { + this.emitSocketUpdate(); + } + } + + /** + * Invokes the "start" (onLoad) function of the module. + */ + public async start() { + if (this.plugin.state === "stopped" || this.plugin.state === "disabled") { + throw new Error("Plugin is stopped"); + } + try { + this.error = null; + this.state = "starting"; + this.emitSocketUpdate(); + + this.plugin.validator.validateModuleSetup(this.setup); + + const values = await this.getConfigValues(); + + await this.plugin.worker.invoke(this.setup.id, "start", values); + + this.error = null; + this.state = "started"; + this.plugin.emitSidebarSocketUpdate(); + } catch (ex: any) { + this.error = ex?.message || String(ex); + this.state = "stopped"; + this.plugin.emitSidebarSocketUpdate(); + throw ex; + } finally { + this.emitSocketUpdate(); + } + } + + /** + */ + public emitSocketUpdate() { + io?.to(`${ESocketRoom.module}#${this.id}`).emit("module:status", { + id: this.id, + state: this.state, + error: this.error || undefined, + message: this.message || undefined, + }); + } + + /** + * Invokes the onCall function of the module. + */ + public async invokeOnCall(...args: any[]) { + return await this.invoke("onCall", ...args); + } + + /** + * Invokes the onTriggerChange function of the module. + */ + public async invokeOnTriggerChange(...args: any[]) { + return await this.invoke("onTriggerChange", ...args); + } + + /** + */ + public async getConfigValues() { + const settings = await getPluginSettings(this.plugin.id); + const moduleSettings = settings?.modules?.find((x) => x.id === this.id); + const values = moduleSettings?.values || {}; + + const conf = this.setup.configs || []; + const defs = conf?.filter((x) => "defaultValue" in x && x.defaultValue); + const flat = flattenConfigFields(defs); + const defsObject = {}; + + for (const item of flat) { + if ("field" in item && "defaultValue" in item) { + defsObject[item.field] = item.defaultValue; + } + } + + return { + ...defsObject, + ...values, + }; + } +} + +export default Module; diff --git a/packages/tcore-api/src/Plugins/Plugin/Plugin.test.ts b/packages/tcore-api/src/Plugins/Plugin/Plugin.test.ts new file mode 100644 index 00000000..138c385e --- /dev/null +++ b/packages/tcore-api/src/Plugins/Plugin/Plugin.test.ts @@ -0,0 +1,281 @@ +import path from "path"; +import { plugins } from "../Host"; +import Module from "../Module/Module"; +import Validator from "../Validator/Validator"; +import { callbackInterval } from "../Worker/Worker"; +import Plugin from "./Plugin"; + +afterAll(() => { + if (callbackInterval) { + clearInterval(callbackInterval); + } +}); + +test("throws error if package is not found", () => { + const folder = __dirname; + const msg = "Unable to load plugin package.json"; + expect(() => new Plugin(folder)).toThrowError(msg); +}); + +test("calls Validator.validatePackageJSON", async () => { + const fn = jest.spyOn(Validator.prototype, "validatePackageJSON"); + const folder = path.join(__dirname, "..", "__mocks__", "plugin4"); + const plugin = new Plugin(folder); + await plugin.start(); + expect(fn).toHaveBeenCalled(); + await plugin.stop(true).catch(() => null); +}); + +test("sets properties correctly", () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin2"); + const plugin = new Plugin(folder); + expect(plugin.description).toEqual("Description of plugin2"); + expect(plugin.id).toEqual("27eea77f2d965a9a9d91db45b35d2aa9"); + expect(plugin.packageName).toEqual("@tago-io/mock-plugin-2"); + expect(plugin.package.tcore.permissions).toEqual(["device", "action", "analysis", "device-data"]); + expect(plugin.types).toEqual(["service"]); + expect(plugin.tcoreName).toEqual("Plugin 2"); + expect(plugin.version).toEqual("0.0.1"); + expect(plugin.error).toEqual(null); +}); + +test("loads full_description correctly", () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin3"); + const plugin = new Plugin(folder); + expect(plugin.fullDescription).toEqual("# Hello World\n"); +}); + +test("throws error if full_description file doesn't exist", () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin8"); + expect(() => new Plugin(folder)).toThrowError(/ENOENT/g); +}); + +test("has correct initial state", () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin3"); + const plugin = new Plugin(folder); + expect(plugin.state).toEqual("idle"); +}); + +test("starts a simple plugin", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin4"); + const plugin = new Plugin(folder); + await plugin.start(); + expect(plugin.state).toEqual("started"); + expect(plugin.error).toEqual(null); + expect(plugin.modules.size).toEqual(1); + + const module = plugin.modules.values().next().value; + expect(module.error).toBeNull(); + expect(module.id).toEqual("hello"); + expect(module.message).toBeNull(); + expect(module.name).toEqual("world"); + expect(module.state).toEqual("started"); + + await plugin.stop(true); +}); + +test("throws when attempting to start an already started plugin", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin4"); + const plugin = new Plugin(folder); + await plugin.start(); + try { + await plugin.start(); + } catch (ex: any) { + expect(ex.message).toEqual("Plugin already started"); + } finally { + await plugin.stop(true); + } +}); + +test("gracefully stops a simple plugin", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin4"); + const plugin = new Plugin(folder); + await plugin.start(); + await plugin.stop(); + expect(plugin.modules.size).toEqual(1); + + const module = plugin.modules.values().next().value; + expect(plugin.state).toEqual("stopped"); + expect(module.state).toEqual("stopped"); + + await plugin.stop(true).catch(() => null); +}); + +test("loads a plugin that has just an error", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin5"); + const plugin = new Plugin(folder); + const error = "Invalid database port"; + await plugin.start().catch((e) => expect(e.message).toEqual(error)); + + expect(plugin.error).toEqual(error); + expect(plugin.state).toEqual("stopped"); + expect(plugin.modules.size).toEqual(0); + + await plugin.stop(true).catch(() => null); +}); + +test("loads a plugin that has an error after a module definition", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin6"); + const plugin = new Plugin(folder); + const error = "Invalid database port"; + await plugin.start().catch((e) => expect(e.message).toEqual(error)); + + expect(plugin.modules.size).toEqual(1); + + const module = plugin.modules.values().next().value; + expect(module.error).toBeNull(); + expect(module.id).toEqual("hello"); + expect(module.message).toBeNull(); + expect(module.name).toEqual("world"); + expect(module.state).toEqual("stopped"); + + await plugin.stop(true).catch(() => null); +}); + +test("loads a plugin that has an error in a module.onLoad call", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin9"); + const plugin = new Plugin(folder); + await plugin.start(); + + expect(plugin.modules.size).toEqual(1); + + const module = plugin.modules.values().next().value; + expect(module.error).toEqual("Invalid database port"); + expect(module.id).toEqual("hello"); + expect(module.message).toBeNull(); + expect(module.name).toEqual("world"); + expect(module.state).toEqual("stopped"); + + await plugin.stop(true); +}); + +test("only returns after all modules were loaded", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin10"); + const plugin = new Plugin(folder); + await plugin.start(); + + expect(plugin.modules.size).toEqual(2); + + const modules = [...plugin.modules.values()]; + expect(modules[0].error).toBeNull(); + expect(modules[0].id).toEqual("service1"); + expect(modules[0].message).toBeNull(); + expect(modules[0].name).toEqual("Service 1"); + expect(modules[0].state).toEqual("started"); + + expect(modules[1].error).toEqual("Error in service2"); + expect(modules[1].id).toEqual("service2"); + expect(modules[1].message).toBeNull(); + expect(modules[1].name).toEqual("Service 2"); + expect(modules[1].state).toEqual("stopped"); + + await plugin.stop(true); +}); + +test("stops plugin execution without waiting for onDestroy", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin11"); + const plugin = new Plugin(folder); + await plugin.start(); + + const timestamp = Date.now(); + await plugin.stop(true); + + expect(Date.now() - timestamp).toBeLessThan(1000); + + const modules = [...plugin.modules.values()]; + expect(modules).toHaveLength(1); + expect(modules[0].error).toBeNull(); + expect(modules[0].id).toEqual("service1"); + expect(modules[0].message).toBeNull(); + expect(modules[0].name).toEqual("Service 1"); + expect(modules[0].state).toEqual("stopped"); +}); + +test("stops plugin execution waiting for onDestroy", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin11"); + const plugin = new Plugin(folder); + await plugin.start(); + + const timestamp = Date.now(); + await plugin.stop(); + + expect(Date.now() - timestamp).toBeGreaterThan(2000); + + const modules = [...plugin.modules.values()]; + expect(modules).toHaveLength(1); + expect(modules[0].error).toBeNull(); + expect(modules[0].id).toEqual("service1"); + expect(modules[0].message).toBeNull(); + expect(modules[0].name).toEqual("Service 1"); + expect(modules[0].state).toEqual("stopped"); +}); + +test("sets message property of module correctly", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin12"); + const plugin = new Plugin(folder); + plugins.set(plugin.id, plugin); + await plugin.start(); + + const module = plugin.modules.get("service1") as Module; + expect(module.message).not.toBeNull(); + expect(module.message.icon).toEqual("exclamation-circle"); + expect(module.message.message).toEqual("Hello world"); + + await plugin.stop(true); +}); + +test("shuts down plugin when disabling it", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin12"); + const plugin = new Plugin(folder); + await plugin.start(); + await plugin.disable(); + + expect(plugin.error).toBeNull(); + expect(plugin.state).toEqual("disabled"); + + const module = plugin.modules.get("service1") as Module; + expect(module.error).toBeNull(); + expect(module.state).toEqual("stopped"); +}); + +test("removes error when disabling plugin", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin5"); + const plugin = new Plugin(folder); + await plugin.start().catch(() => null); + + expect(plugin.error).toEqual("Invalid database port"); + expect(plugin.state).toEqual("stopped"); + + await plugin.disable(); + + expect(plugin.error).toBeNull(); +}); + +test("ignores disable if already disabled", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin12"); + const plugin = new Plugin(folder); + await plugin.start(); + await plugin.disable(); + + plugin.error = "not_null_because_it_wasn't_reset"; + await plugin.disable(); + + expect(plugin.error).toEqual("not_null_because_it_wasn't_reset"); +}); + +test("starts plugin when enabling it", async () => { + const folder = path.join(__dirname, "..", "__mocks__", "plugin12"); + const plugin = new Plugin(folder); + await plugin.start(); + await plugin.disable(); + await plugin.enable(); + + expect(plugin.error).toBeNull(); + expect(plugin.state).toEqual("started"); + + const module = plugin.modules.get("service1") as Module; + expect(module.error).toBeNull(); + expect(module.state).toEqual("started"); + + await plugin.stop(true); +}); diff --git a/packages/tcore-api/src/Plugins/Plugin/Plugin.ts b/packages/tcore-api/src/Plugins/Plugin/Plugin.ts new file mode 100644 index 00000000..90d30009 --- /dev/null +++ b/packages/tcore-api/src/Plugins/Plugin/Plugin.ts @@ -0,0 +1,225 @@ +/* eslint-disable no-unused-vars */ +import path from "path"; +import fs from "fs"; +import { ESocketRoom, TPluginState, TPluginType } from "@tago-io/tcore-sdk/types"; +import md5 from "md5"; +import { logError } from "../../Helpers/log"; +import { setPluginDisabledSettings } from "../../Services/Settings"; +import { io } from "../../Socket/SocketServer"; +import M from "../Module/Module"; +import Validator from "../Validator/Validator"; +import Worker from "../Worker/Worker"; +import { generatePluginID } from "../PluginID"; + +/** + */ +class Plugin { + public package: any; + public permissions: string[]; + public types: TPluginType[]; + + public readonly version: string; + public readonly id: string; + public readonly packageName: string; + public readonly tcoreName: string; + public readonly publisher: string; + public readonly description: string; + public fullDescription: string | null = null; + + public error?: string | null = null; + public modules: Map; + public state: TPluginState; + public validator: Validator; + public worker: Worker; + + /** + * Generates a plugin ID based on the plugin name. + */ + public static generatePluginID(packageName: string) { + if (!packageName) { + return null; + } + const id = md5(packageName); + return id; + } + + constructor(public folder: string) { + this.validator = new Validator(this); + this.state = "idle"; + this.modules = new Map(); + this.worker = new Worker(this); + + this.package = Plugin.getPackage(this.folder); + this.permissions = this.package?.tcore?.permissions || []; + this.types = this.package?.tcore?.types || []; + + this.description = this.package.tcore.short_description; + this.id = generatePluginID(this.package.name); + this.packageName = this.package.name; + this.publisher = this.package.tcore.publisher; + this.tcoreName = this.package.tcore.name; + this.version = this.package.version; + + this.loadFullDescription(); + } + + /** + */ + public async start() { + if (this.state === "starting" || this.state === "started") { + throw new Error("Plugin already started"); + } + + try { + this.validator.validatePackageJSON(); + } catch (ex: any) { + this.state = "stopped"; + this.error = ex?.message || ex; + this.emitSocketUpdate(); + throw ex; + } + + try { + this.state = "starting"; + this.modules.clear(); + this.emitSocketUpdate(); + + await new Promise((resolve, reject) => { + this.worker.start(); + this.worker.on("uncaughtException", reject); + this.worker.on("start", resolve); + }); + + this.state = "started"; + this.error = null; + } catch (ex: any) { + this.state = "stopped"; + this.error = this.error || ex.message || ex; + throw ex; + } finally { + this.emitSocketUpdate(); + } + } + + /** + */ + public async stop(force = false, timeout = 30000) { + if (this.state === "stopped") { + throw new Error("Plugin already stopped"); + } + + if (force) { + // quickly stop executing whole plugin + [...this.modules.values()].forEach((x) => (x.state = "stopped")); + this.state = "stopped"; + this.worker.stop(); + this.emitSocketUpdate(); + } else { + // gracefully stop plugin waiting for onDestroy + this.state = "stopping"; + this.emitSocketUpdate(); + + // creates a rejection timeout in order to prevent the plugin + // from taking too long to destroy. If the timeout is exceeded then the + // plugin will be destroyed forcefully + const rejectTimeout = setTimeout(() => { + this.stop(true); + logError("api", `Plugin "${this.tcoreName}" exceeded the shutdown timeout and was terminated.`); + }, timeout); + + for (const module of this.modules.values()) { + await module.stop().catch(() => null); + } + + // this setTimeout is here to prevent the napi_error from node. The error + // happens when you send messages and try to kill the worker immediately + // after. This prevents the error from being thrown. + await new Promise((resolve) => { + setTimeout(() => { + this.state = "stopped"; + this.worker.stop(); + this.emitSocketUpdate(); + resolve(); + clearTimeout(rejectTimeout); + }, 200); + }); + } + } + + /** + */ + public async disable() { + if (this.state !== "disabled") { + await this.stop(true).catch(() => null); + this.error = null; + this.state = "disabled"; + this.emitSocketUpdate(); + await setPluginDisabledSettings(this.id, true); + } + } + + /** + */ + public async enable() { + this.package = Plugin.getPackage(this.folder); + this.permissions = this.package?.tcore?.permissions || []; + this.types = this.package?.tcore?.types || []; + + await this.start().catch(() => null); + await setPluginDisabledSettings(this.id, false); + } + + /** + */ + private loadFullDescription() { + const relativePath = this.package.tcore.full_description; + if (relativePath) { + const fullPath = path.join(this.folder, relativePath); + const data = fs.readFileSync(fullPath, "utf8"); + this.fullDescription = data; + } + } + + /** + */ + public emitSocketUpdate() { + io?.to(`${ESocketRoom.plugin}#${this.id}`).emit("plugin:status", { + id: this.id, + state: this.state, + error: this.error || undefined, + }); + + this.emitSidebarSocketUpdate(); + } + + /** + */ + public emitSidebarSocketUpdate() { + const modulesError = [...this.modules.values()].some((x) => x.error); + io?.to(`${ESocketRoom.plugin}#${this.id}`).emit("plugin:sidebar", { + id: this.id, + state: this.state, + error: !!this.error || modulesError || undefined, + }); + } + + /** + */ + public static getPackage(folder: string) { + try { + const filePath = path.join(folder, "package.json"); + const pkg = fs.readFileSync(filePath, "utf8"); + return JSON.parse(pkg); + } catch (ex) { + throw new Error("Unable to load plugin package.json"); + } + } + + /** + */ + public static async getPackageAsync(folder: string) { + return Plugin.getPackage(folder); + } +} + +export default Plugin; diff --git a/packages/tcore-api/src/Plugins/PluginID.ts b/packages/tcore-api/src/Plugins/PluginID.ts new file mode 100644 index 00000000..71b4a169 --- /dev/null +++ b/packages/tcore-api/src/Plugins/PluginID.ts @@ -0,0 +1,9 @@ +import md5 from "md5"; + +/** + * Generates a plugin ID based on the plugin name. + */ +export function generatePluginID(packageName: string) { + const id = md5(packageName); + return id; +} diff --git a/packages/tcore-api/src/Plugins/PluginPackage.ts b/packages/tcore-api/src/Plugins/PluginPackage.ts new file mode 100644 index 00000000..38ac38ae --- /dev/null +++ b/packages/tcore-api/src/Plugins/PluginPackage.ts @@ -0,0 +1,16 @@ +import fs from "fs"; +import path from "path"; + +/** + * Gets the package.json file in a plugin folder. + */ +export async function getPluginPackageJSON(folder: string) { + try { + const pkgPath = path.join(folder, "package.json"); + const pkgStr = await fs.promises.readFile(pkgPath, "utf-8"); + const pkgData = JSON.parse(pkgStr); + return pkgData || null; + } catch (ex) { + return null; + } +} diff --git a/packages/tcore-api/src/Plugins/Uninstall.ts b/packages/tcore-api/src/Plugins/Uninstall.ts new file mode 100644 index 00000000..162aefe6 --- /dev/null +++ b/packages/tcore-api/src/Plugins/Uninstall.ts @@ -0,0 +1,69 @@ +import fs from "fs"; +import path from "path"; +import { ESocketRoom } from "@tago-io/tcore-sdk/types"; +import { io } from "../Socket/SocketServer"; +import { getPluginSettingsFolder } from "../Services/Settings"; +import { plugins } from "./Host"; + +/** + * Uninstalls a plugin. + */ +export async function uninstallPlugin(id: string, keepPluginData?: boolean) { + const plugin = plugins.get(id); + if (plugin) { + await plugin.stop(false, 3000).catch(() => null); + await rmdir(plugin.folder); + plugins.delete(id); + + if (!keepPluginData) { + const settingsFolder = await getPluginSettingsFolder(id); + await rmdir(settingsFolder); + } + + const socketData = { + id: id, + deleted: true, + }; + + io?.to(`${ESocketRoom.plugin}#${id}`).emit("plugin:sidebar", socketData); + io?.to(`${ESocketRoom.plugin}#${id}`).emit("plugin:status", socketData); + } +} + +/** + * Uninstalls a plugin. + */ +export async function uninstallPluginByFolder(folder: string) { + await rmdir(folder); +} + +/** + * Removes directory recursively. + */ +async function rmdir(dir: string) { + if (!fs.existsSync(dir)) { + return; + } + + if (!dir || dir === "/") { + return; + } + + const list = await fs.promises.readdir(dir); + for (let i = 0; i < list.length; i++) { + const filename = path.join(dir, list[i]); + const stat = fs.statSync(filename); + + if (filename == "." || filename == "..") { + // pass these files + } else if (stat.isDirectory()) { + // rmdir recursively + await rmdir(filename); + } else { + // rm filename + await fs.promises.unlink(filename); + } + } + + await fs.promises.rmdir(dir); +} diff --git a/packages/tcore-api/src/Plugins/Validator/Validator.ts b/packages/tcore-api/src/Plugins/Validator/Validator.ts new file mode 100644 index 00000000..d877ca1f --- /dev/null +++ b/packages/tcore-api/src/Plugins/Validator/Validator.ts @@ -0,0 +1,57 @@ +/* eslint-disable no-unused-vars */ +import semver from "semver"; +import { IModuleSetup, zPluginPackageTCore } from "@tago-io/tcore-sdk/types"; +import Plugin from "../Plugin/Plugin"; +// @ts-ignore +import pkg from "../../../package.json"; + +/** + */ +class Validator { + constructor(public plugin: Plugin) { + // + } + + /** + */ + private validateEngine() { + const pluginEngineVersion = this.plugin.package?.engines?.tcore || "*"; + const tcoreVersion = pkg.version; + const valid = semver.satisfies(tcoreVersion, pluginEngineVersion); + return valid; + } + + /** + */ + public validatePackageJSON() { + const pkg = this.plugin.package; + if (!pkg.tcore) { + throw new Error(`"tcore" property missing in package.json`); + } + + const valid = this.validateEngine(); + if (!valid) { + throw new Error(`Not compatible with this TCore version, only compatible with ${pkg.engines.tcore}`); + } + + try { + zPluginPackageTCore.parse(pkg.tcore); + } catch (err: any) { + const { fieldErrors } = err.flatten(); + const str = JSON.stringify(fieldErrors, null, 2); + const msg = `Validation error in package.json:\n${str}`; + throw new Error(msg); + } + } + + /** + */ + public validateModuleSetup(setup: IModuleSetup) { + const allowed = this.plugin.types.includes(setup.type); + if (!allowed) { + throw new Error(`Not allowed to start a "${setup.type}" module`); + } + } +} + +export default Validator; diff --git a/packages/tcore-api/src/Plugins/Worker/Worker.ts b/packages/tcore-api/src/Plugins/Worker/Worker.ts new file mode 100644 index 00000000..df57f96e --- /dev/null +++ b/packages/tcore-api/src/Plugins/Worker/Worker.ts @@ -0,0 +1,250 @@ +/* eslint-disable no-unused-vars */ +import path from "path"; +import { Worker as WorkerThread } from "worker_threads"; +import EventEmitter from "events"; +import fs from "fs"; +import { IModuleSetup, IPluginMessage } from "@tago-io/tcore-sdk/types"; +import { nanoid } from "nanoid"; +import { getActionList, invokeActionOnTriggerChange } from "../../Services/Action"; +import { log, logError } from "../../Helpers/log"; +import Plugin from "../Plugin/Plugin"; +import Module from "../Module/Module"; +import executePluginRequest from "../executePluginRequest"; + +/** + * Keeps track of the messages sent to plugins to use the reject/resolve + * function and return the result to the same promise. + */ +const callbacks = new Map(); + +/** + * Controls the communication between the plugin, modules, and the API. + * The whole lifecycle of the plugin is in here. + */ +class Worker extends EventEmitter { + /** + * Inner worker object. This is the thread that actually runs the plugin + * code. + */ + private worker?: WorkerThread; + private startRejectTimeout?: ReturnType; + private moduleLoadTimeout?: ReturnType; + + constructor(public plugin: Plugin) { + super(); + } + + /** + */ + public start() { + if (this.worker) { + throw new Error("Plugin already running"); + } + + this.plugin.state = "started"; + + const fileName = this.plugin.package.main || "index.js"; + const filePath = path.join(this.plugin.folder, fileName); + const exists = fs.existsSync(filePath); + if (!exists) { + throw new Error(`File "${filePath}" doesn't exist`); + } + + this.worker = new WorkerThread(filePath, { stdout: true, stderr: true }); + this.worker.on("error", this.onError.bind(this)); + this.worker.on("exit", this.onExit.bind(this)); + this.worker.on("message", this.onWorkerMessage.bind(this)); + this.worker.stdout.on("data", this.onWorkerStdout.bind(this)); + this.worker.stderr.on("data", this.onWorkerStderr.bind(this)); + + this.startRejectTimeout = setTimeout(() => { + this.onError(new Error("Took too long to load (30s)")); + }, 30 * 1000); + } + + /** + * Terminates the worker instance. + */ + public stop() { + for (const [key, value] of callbacks.entries()) { + if (value.plugin === this.plugin) { + const err = new Error("Unexpected Plugin shutdown"); + callbacks?.get(key).reject?.(err); + callbacks.delete(key); + } + } + + this.removeAllListeners(); + this.worker?.removeAllListeners(); + this.worker?.stderr?.removeAllListeners(); + this.worker?.stdout?.removeAllListeners(); + this.worker?.terminate(); + this.worker = undefined; + } + + /** + */ + public invoke(moduleID: string, method: string, ...args: any[]) { + return new Promise((resolve, reject) => { + const connectionID = nanoid(10); + + callbacks.set(connectionID, { + resolve, + reject, + plugin: this.plugin, + method, + time: Date.now(), + }); + + this.worker?.postMessage({ + connectionID, + event: "executePluginMethod", + method, + params: [args].flat(), + setupID: moduleID, + }); + }); + } + + /** + */ + private onExit(code: number) { + const error = new Error(`Plugin forced exit with status ${code || 0}`); + this.onError(error); + } + + /** + */ + private onError(ex: Error) { + if (this.startRejectTimeout) { + clearTimeout(this.startRejectTimeout); + } + this.emit("uncaughtException", ex); + this.plugin.error = ex?.message || String(ex); + this.plugin.stop(true); + } + + /** + */ + private onWorkerStdout(buffer: Buffer) { + log(`plugin:${this.plugin.id}`, buffer.toString()); + } + + /** + */ + private onWorkerStderr(buffer: Buffer) { + logError(`plugin:${this.plugin.id}`, buffer.toString()); + } + + /** + */ + private onWorkerMessage(message: IPluginMessage) { + if (message.event === "init") { + this.onModuleInit(message.params); + } else if (message.event === "executeApiMethod") { + this.onWorkerExecuteApiMethod(message); + } else if (message.event === "pluginMethodResponse") { + this.onWorkerResponse(message); + } + } + + /** + * @event + */ + private async onModuleInit(setup: IModuleSetup) { + const module = new Module(this.plugin, setup); + this.plugin.modules.set(module.id, module); + + await module.start().catch(() => null); + + this.onModuleLoaded(); + + // TODO improve + if (setup.type === "action-trigger") { + const actions = await getActionList({ amount: 99899, fields: ["type", "trigger"] }).catch(() => null); + const filtered = actions?.filter((x) => x.type === `${this.plugin.id}:${setup.id}`); + for (const item of filtered || []) { + invokeActionOnTriggerChange(item.id, item.type as string, item.trigger); + } + } + } + + /** + */ + private onModuleLoaded() { + if (this.moduleLoadTimeout) { + clearTimeout(this.moduleLoadTimeout); + } + + this.moduleLoadTimeout = setTimeout(() => { + const mods = [...this.plugin.modules.values()]; + const done = mods.every((x) => ["started", "stopped"].includes(x.state)); + if (done) { + // all modules are either done, or stopped (error), + // this means that this worker has successfully started + this.emit("start"); + + if (this.moduleLoadTimeout) { + // clear the timeout that stops loading modules + clearTimeout(this.moduleLoadTimeout); + } + + if (this.startRejectTimeout) { + // clears the timeout that rejects plugins if they take too long + clearTimeout(this.startRejectTimeout); + } + } + }, 250); + } + + /** + */ + private onWorkerResponse(message: IPluginMessage) { + const callback = callbacks.get(message.connectionID); + if (callback) { + if (message.error) { + callback?.reject(message.error); + } else { + callback?.resolve(message.params); + } + callbacks.delete(message.connectionID); + } + } + + /** + */ + private async onWorkerExecuteApiMethod(message: IPluginMessage) { + const { method, connectionID } = message; + try { + const args = [message.params].flat(); + const params = await executePluginRequest(this.plugin.id, method, ...args); + this.worker?.postMessage({ event: "apiMethodResponse", connectionID, method, params }); + } catch (error) { + this.worker?.postMessage({ event: "apiMethodResponse", connectionID, method, error }); + } + } +} + +/** + * Starts the interval to erase old callbacks that were unanswered. + */ +export function startCallbackInterval() { + const maximumTime = 60 * 1000; // 1 min without response + const checkTime = 10 * 1000; // check every 10 seconds + + callbackInterval = setInterval(() => { + for (const [key, value] of callbacks.entries()) { + if (Date.now() - value.time >= maximumTime) { + const message = `Response timed out (60s) for method "${value.method}"`; + callbacks.get(key)?.reject(message); + callbacks.delete(key); + logError("api", `Plugin "${value.plugin.tcoreName}" - ${message}.`); + } + } + }, checkTime); +} + +let callbackInterval: ReturnType | null = null; + +export { callbackInterval }; +export default Worker; diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin1/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin1/package.json new file mode 100644 index 00000000..7e95d7b4 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin1/package.json @@ -0,0 +1,10 @@ +{ + "name": "@tago-io/mock-plugin-1", + "version": "0.0.1", + "private": true, + "tago": { + "name": "Plugin 1", + "permissions": [], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin10/index.js b/packages/tcore-api/src/Plugins/__mocks__/plugin10/index.js new file mode 100644 index 00000000..0ca85997 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin10/index.js @@ -0,0 +1,15 @@ +const { ServiceModule } = require("@tago-io/tcore-sdk"); + +const service1 = new ServiceModule({ id: "service1", name: "Service 1" }); +service1.onLoad = () => { + return new Promise((resolve) => { + setTimeout(resolve, 2500); + }); +}; + +const service2 = new ServiceModule({ id: "service2", name: "Service 2" }); +service2.onLoad = () => { + return new Promise((resolve, reject) => { + reject("Error in service2"); + }); +}; diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin10/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin10/package.json new file mode 100644 index 00000000..0d698763 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin10/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-10", + "version": "0.0.1", + "private": true, + "main": "./index.js", + "tcore": { + "name": "Plugin 10", + "permissions": [], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin11/index.js b/packages/tcore-api/src/Plugins/__mocks__/plugin11/index.js new file mode 100644 index 00000000..8653b3b1 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin11/index.js @@ -0,0 +1,8 @@ +const { ServiceModule } = require("@tago-io/tcore-sdk"); + +const service1 = new ServiceModule({ id: "service1", name: "Service 1" }); +service1.onDestroy = () => { + return new Promise((resolve) => { + setTimeout(resolve, 3000); + }); +}; diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin11/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin11/package.json new file mode 100644 index 00000000..b3fac346 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin11/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-11", + "version": "0.0.1", + "private": true, + "main": "./index.js", + "tcore": { + "name": "Plugin 11", + "permissions": [], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin12/index.js b/packages/tcore-api/src/Plugins/__mocks__/plugin12/index.js new file mode 100644 index 00000000..77ea2059 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin12/index.js @@ -0,0 +1,5 @@ +const { ServiceModule } = require("@tago-io/tcore-sdk"); + +const service = new ServiceModule({ id: "service1", name: "Service 1" }); + +service.showMessage("info", "Hello world"); diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin12/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin12/package.json new file mode 100644 index 00000000..b3fac346 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin12/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-11", + "version": "0.0.1", + "private": true, + "main": "./index.js", + "tcore": { + "name": "Plugin 11", + "permissions": [], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin2/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin2/package.json new file mode 100644 index 00000000..c1f0890a --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin2/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-2", + "version": "0.0.1", + "private": true, + "tcore": { + "name": "Plugin 2", + "short_description": "Description of plugin2", + "permissions": ["device", "action", "analysis", "device-data"], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin3/README.md b/packages/tcore-api/src/Plugins/__mocks__/plugin3/README.md new file mode 100644 index 00000000..29658341 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin3/README.md @@ -0,0 +1 @@ +# Hello World diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin3/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin3/package.json new file mode 100644 index 00000000..f81337da --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin3/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-3", + "version": "0.0.1", + "private": true, + "tcore": { + "name": "Plugin 3", + "full_description": "./README.md", + "permissions": ["device", "action", "analysis", "device-data"], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin4/index.js b/packages/tcore-api/src/Plugins/__mocks__/plugin4/index.js new file mode 100644 index 00000000..5f25f463 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin4/index.js @@ -0,0 +1,2 @@ +const { ServiceModule } = require("@tago-io/tcore-sdk"); +new ServiceModule({ id: "hello", name: "world" }); diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin4/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin4/package.json new file mode 100644 index 00000000..4dcb3df4 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin4/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-4", + "version": "0.0.1", + "private": true, + "main": "./index.js", + "tcore": { + "name": "Plugin 4", + "permissions": [], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin5/index.js b/packages/tcore-api/src/Plugins/__mocks__/plugin5/index.js new file mode 100644 index 00000000..2bd82865 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin5/index.js @@ -0,0 +1 @@ +throw new Error("Invalid database port"); diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin5/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin5/package.json new file mode 100644 index 00000000..4dcb3df4 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin5/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-4", + "version": "0.0.1", + "private": true, + "main": "./index.js", + "tcore": { + "name": "Plugin 4", + "permissions": [], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin6/index.js b/packages/tcore-api/src/Plugins/__mocks__/plugin6/index.js new file mode 100644 index 00000000..d58abe53 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin6/index.js @@ -0,0 +1,7 @@ +const { ServiceModule } = require("@tago-io/tcore-sdk"); + +new ServiceModule({ id: "hello", name: "world" }); + +setTimeout(() => { + throw new Error("Invalid database port"); +}, 100); diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin6/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin6/package.json new file mode 100644 index 00000000..4dcb3df4 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin6/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-4", + "version": "0.0.1", + "private": true, + "main": "./index.js", + "tcore": { + "name": "Plugin 4", + "permissions": [], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin7/index.js b/packages/tcore-api/src/Plugins/__mocks__/plugin7/index.js new file mode 100644 index 00000000..d58abe53 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin7/index.js @@ -0,0 +1,7 @@ +const { ServiceModule } = require("@tago-io/tcore-sdk"); + +new ServiceModule({ id: "hello", name: "world" }); + +setTimeout(() => { + throw new Error("Invalid database port"); +}, 100); diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin7/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin7/package.json new file mode 100644 index 00000000..4dcb3df4 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin7/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-4", + "version": "0.0.1", + "private": true, + "main": "./index.js", + "tcore": { + "name": "Plugin 4", + "permissions": [], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin8/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin8/package.json new file mode 100644 index 00000000..7f9c40c3 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin8/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-8", + "version": "0.0.1", + "private": true, + "tcore": { + "name": "Plugin 8", + "full_description": "./README.md", + "permissions": ["device", "action", "analysis", "device-data"], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin9/index.js b/packages/tcore-api/src/Plugins/__mocks__/plugin9/index.js new file mode 100644 index 00000000..aeb793f0 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin9/index.js @@ -0,0 +1,7 @@ +const { ServiceModule } = require("@tago-io/tcore-sdk"); + +const service = new ServiceModule({ id: "hello", name: "world" }); + +service.onLoad = async () => { + throw new Error("Invalid database port"); +}; diff --git a/packages/tcore-api/src/Plugins/__mocks__/plugin9/package.json b/packages/tcore-api/src/Plugins/__mocks__/plugin9/package.json new file mode 100644 index 00000000..a635fbe4 --- /dev/null +++ b/packages/tcore-api/src/Plugins/__mocks__/plugin9/package.json @@ -0,0 +1,11 @@ +{ + "name": "@tago-io/mock-plugin-9", + "version": "0.0.1", + "private": true, + "main": "./index.js", + "tcore": { + "name": "Plugin 9", + "permissions": [], + "types": ["service"] + } +} diff --git a/packages/tcore-api/src/Plugins/executePluginRequest.ts b/packages/tcore-api/src/Plugins/executePluginRequest.ts new file mode 100644 index 00000000..81233018 --- /dev/null +++ b/packages/tcore-api/src/Plugins/executePluginRequest.ts @@ -0,0 +1,104 @@ +/* eslint-disable prettier/prettier */ +import { hideModuleMessage, showModuleMessage } from "../Services/Plugins"; +import { createFolder, doesFileOrFolderExist, getFileURI, getFolderURI, readFile, writeFile } from "../Services/File"; +import { deletePluginStorageItem, getAllPluginStorageItems, getPluginStorageItem, setPluginStorageItem } from "../Services/PluginsStorage"; +import * as DeviceService from "../Services/Device"; +import * as DeviceDataService from "../Services/DeviceData/DeviceData"; +import * as AnalysisService from "../Services/Analysis"; +import * as ActionService from "../Services/Action"; +import * as LiveInspectorService from "../Services/LiveInspector"; +import { getTagKeys } from "../Services/Tag"; +import { getSummary } from "../Services/Summary"; +import { getComputerUsage, getOSInfo } from "../Services/Hardware"; +import { plugins } from "./Host"; + +/** + * This function is a helper to execute plugin requests, such as creating + * devices, listing resources, and stuff like that. + */ +async function executePluginRequest(pluginID: string, method: string, ...e: any[]) { + switch (method) { + // pluginStorage + case "getPluginStorageItem" : return getPluginStorageItem(pluginID, e[0]); + case "setPluginStorageItem" : return setPluginStorageItem(pluginID, e[0], e[1]); + case "deletePluginStorageItem" : return deletePluginStorageItem(pluginID, e[0]); + case "getAllPluginStorageItems" : return getAllPluginStorageItems(pluginID); + + // file + case "writeFile" : return writeFile(pluginID, e[0], e[1], e[2]); + case "createFolder" : return createFolder(pluginID, e[0]); + case "deleteFileOrFolder" : return createFolder(pluginID, e[0]); + case "readFile" : return readFile(pluginID, e[0], e[1]); + case "doesFileOrFolderExist" : return doesFileOrFolderExist(pluginID, e[0]); + case "getFileURI" : return getFileURI(pluginID, e[0]); + case "getFolderURI" : return getFolderURI(pluginID); + + // device + case "deleteDeviceParam" : return call(pluginID, "device", DeviceService, "deleteDeviceParam", ...e); + case "setDeviceParams" : return call(pluginID, "device", DeviceService, "setDeviceParams", ...e); + case "getDeviceParamList" : return call(pluginID, "device", DeviceService, "getDeviceParamList", ...e); + case "deleteDeviceToken" : return call(pluginID, "device", DeviceService, "deleteDeviceToken", ...e); + case "createDeviceToken" : return call(pluginID, "device", DeviceService, "createDeviceToken", ...e); + case "getDeviceTokenList" : return call(pluginID, "device", DeviceService, "getDeviceTokenList", ...e); + case "getDeviceByToken" : return call(pluginID, "device", DeviceService, "getDeviceByToken", ...e); + case "getDeviceList" : return call(pluginID, "device", DeviceService, "getDeviceList", ...e); + case "getDeviceInfo" : return call(pluginID, "device", DeviceService, "getDeviceInfo", ...e); + case "editDevice" : return call(pluginID, "device", DeviceService, "editDevice", ...e); + case "deleteDevice" : return call(pluginID, "device", DeviceService, "deleteDevice", ...e); + case "createDevice" : return call(pluginID, "device", DeviceService, "createDevice", ...e); + case "emitToLiveInspector" : return call(pluginID, "device", LiveInspectorService, "emitToLiveInspectorViaPlugin", pluginID, ...e); + + // deviceData + case "getDeviceDataAmount" : return call(pluginID, "device-data", DeviceDataService, "getDeviceDataAmount", ...e); + case "addDeviceData" : return call(pluginID, "device-data", DeviceDataService, "addDeviceData", ...e); + case "getDeviceData" : return call(pluginID, "device-data", DeviceDataService, "getDeviceData", ...e); + case "deleteDeviceData" : return call(pluginID, "device-data", DeviceDataService, "deleteDeviceData", ...e); + + // analysis + case "getAnalysisList" : return call(pluginID, "analysis", AnalysisService, "getAnalysisList", ...e); + case "getAnalysisInfo" : return call(pluginID, "analysis", AnalysisService, "getAnalysisInfo", ...e); + case "editAnalysis" : return call(pluginID, "analysis", AnalysisService, "editAnalysis", ...e); + case "deleteAnalysis" : return call(pluginID, "analysis", AnalysisService, "deleteAnalysis", ...e); + case "createAnalysis" : return call(pluginID, "analysis", AnalysisService, "createAnalysis", ...e); + + // action + case "getActionTypes" : return call(pluginID, "action", ActionService, "getActionTypes", ...e); + case "getActionList" : return call(pluginID, "action", ActionService, "getActionList", ...e); + case "getActionInfo" : return call(pluginID, "action", ActionService, "getActionInfo", ...e); + case "triggerAction" : return call(pluginID, "action", ActionService, "triggerAction", ...e); + case "editAction" : return call(pluginID, "action", ActionService, "editAction", ...e); + case "deleteAction" : return call(pluginID, "action", ActionService, "deleteAction", ...e); + case "createAction" : return call(pluginID, "action", ActionService, "createAction", ...e); + + // tag + case "getTagKeys" : return getTagKeys(e[0]); + + // summary + case "getSummary" : return getSummary(); + + // hardware + case "getOSInfo" : return getOSInfo(); + case "getComputerUsage" : return getComputerUsage(); + + // others + case "showMessage" : return showModuleMessage(pluginID, e[0], e[1]); + case "hideMessage" : return hideModuleMessage(pluginID, e[0]); + } + + throw new Error("API Service not implemented"); +} + +/** + */ +async function call(pluginID: string, perm: string, service: any, name: string, ...e: any[]) { + const plugin = plugins.get(pluginID); + if (!plugin?.permissions?.includes?.(perm)) { + // not enough permission to call this function + const message = `Failed to call "${name}", needs "${perm}" permission`; + throw message; + } + + return await service[name](...e); +} + +export default executePluginRequest; diff --git a/packages/tcore-api/src/Plugins/invokeDatabaseFunction.ts b/packages/tcore-api/src/Plugins/invokeDatabaseFunction.ts new file mode 100644 index 00000000..2e54bf48 --- /dev/null +++ b/packages/tcore-api/src/Plugins/invokeDatabaseFunction.ts @@ -0,0 +1,14 @@ +import { getMainDatabaseModule } from "../Services/Plugins"; + +/** + * Invokes a function from the main database plugin. + */ +export async function invokeDatabaseFunction(method: string, ...args: any): Promise { + const module = await getMainDatabaseModule(); + if (!module) { + throw new Error("Database module doesn't exist or isn't running"); + } + + const result = await module.invoke(method, ...args); + return result; +} diff --git a/packages/tcore-api/src/Plugins/invokeFilesystemFunction.ts b/packages/tcore-api/src/Plugins/invokeFilesystemFunction.ts new file mode 100644 index 00000000..cd908acd --- /dev/null +++ b/packages/tcore-api/src/Plugins/invokeFilesystemFunction.ts @@ -0,0 +1,14 @@ +import { getMainFilesystemModule } from "../Services/Plugins"; + +/** + * TODO + */ +export async function invokeFilesystemFunction(method: string, ...args: any): Promise { + const module = await getMainFilesystemModule(); + if (!module) { + throw new Error("Filesystem module doesn't exist or isn't running"); + } + + const result = await module.invoke(method, ...args); + return result; +} diff --git a/packages/tcore-api/src/Services/Action.ts b/packages/tcore-api/src/Services/Action.ts new file mode 100644 index 00000000..17bc84ae --- /dev/null +++ b/packages/tcore-api/src/Services/Action.ts @@ -0,0 +1,283 @@ +import { + IAction, + IActionCreate, + IActionEdit, + IActionList, + IActionListQuery, + IActionOption, + IActionTriggerModuleSetup, + IActionType, + IActionTypeModuleSetup, + IDeviceData, + TGenericID, + zAction, + zActionCreate, + zActionEdit, + zActionList, + zActionListQuery, +} from "@tago-io/tcore-sdk/types"; +import axios from "axios"; +import { Device } from "@tago-io/sdk"; +import splitColon from "../Helpers/splitColon"; +import { plugins } from "../Plugins/Host"; +import { invokeDatabaseFunction } from "../Plugins/invokeDatabaseFunction"; +import { runAnalysis } from "./AnalysisCodeExecution"; +import { addDeviceData } from "./DeviceData/DeviceData"; +import { getDeviceByToken } from "./Device"; +import { getModuleList } from "./Plugins"; + +/** + * Validates an action ID, throws an error if it doesn't exist. + */ +export async function validateActionID(id: TGenericID): Promise { + const action = await invokeDatabaseFunction("getActionInfo", id); + if (!action) { + throw new Error("Invalid Action ID"); + } +} + +/** + * Lists all the action triggers. + */ +export function getActionTriggers(): IActionType[] { + const options: IActionType[] = []; + const modules = getModuleList("action-trigger"); + + for (const module of modules) { + const option = (module.setup as unknown as IActionTriggerModuleSetup).option; + + const type: IActionType = { + configs: option.configs || [], + description: option.description, + id: `${module.plugin.id}:${module.setup.id}`, + name: option.name, + showDeviceSelector: !!option.showDeviceSelector, + }; + + options.push(type); + } + + return options; +} + +/** + * Lists all the action types. + */ +export function getActionTypes(): IActionOption[] { + const options: IActionOption[] = []; + const modules = getModuleList("action-type"); + + for (const module of modules) { + const option = (module.setup as unknown as IActionTypeModuleSetup).option; + options.push({ ...option, id: `${module.plugin.id}:${module.setup.id}` } as any); + } + + return options; +} + +/** + * Lists all the actions. + */ +export const getActionList = async (query: IActionListQuery): Promise => { + const queryParsed = await zActionListQuery.parseAsync(query); + const response = await invokeDatabaseFunction("getActionList", queryParsed); + const parsed = await zActionList.parseAsync(response); + return parsed; +}; + +/** + * Retrieves all the information of a single action. + */ +export async function getActionInfo(id: TGenericID): Promise { + const action = await invokeDatabaseFunction("getActionInfo", id); + if (!action) { + throw new Error("Invalid Action ID"); + } + const parsed = await zAction.parseAsync(action); + return parsed; +} + +/** + */ +export function shouldNativeActionTrigger(action: Partial, data: IDeviceData[]): boolean { + const conditions = action.trigger?.conditions || []; + for (const item of data) { + for (const trigger of conditions) { + const itemValue = Number(item.value); + + const triggerValue = Number(trigger.value); + const triggerSecondValue = Number(trigger.second_value); + + if (item.variable === trigger.variable) { + if (trigger.is === "=" && itemValue === triggerValue) return true; + if (trigger.is === "<>" && itemValue !== triggerValue) return true; + if ((!trigger.is || trigger.is === "<") && itemValue < triggerValue) return true; + if (trigger.is === ">" && itemValue > triggerValue) return true; + if (trigger.is === "><" && itemValue > triggerValue && itemValue < triggerSecondValue) return true; + if (trigger.is === "*") return true; + } + + return false; + } + } + + return false; +} + +/** + * Triggers an action. + */ +export async function triggerAction(id: TGenericID, data?: any): Promise { + await validateActionID(id); + + const action = await getActionInfo(id); + const actionObject = action.action; + + const usesPluginTrigger = actionObject.type?.includes(":"); + if (usesPluginTrigger) { + // custom type for the action + triggerActionPluginType(action, data); + } else if (actionObject.type === "script") { + // analysis type + triggerActionScriptType(action, data); + } else if (actionObject.type === "post") { + // post HTTP type + triggerActionPostType(action, data); + } else if (actionObject.type === "tagoio") { + // post to TagoIO + triggerActionTagoIOType(action, data); + } + + editAction(id, { last_triggered: new Date() }); +} + +/** + * Triggers an action that redirects data to TagoIO. + */ +async function triggerActionTagoIOType(action: IAction, data: any): Promise { + const token = action?.action?.token; + if (!token) { + return; + } + + const device = new Device({ token, region: "usa-1" }); + await device.sendData(data); +} + +/** + * Triggers an action that does a POST HTTP. + * @param {IAction} action The action to be triggered. + * @param {any} data The data to be passed as parameter to the analyses. + */ +async function triggerActionPostType(action: IAction, data: any): Promise { + if (!action?.action?.url) { + return; + } + + const headers = Array.isArray(action.action.headers) ? action.action.headers : []; + const headersObj = {}; + + for (const headerItem of headers) { + headersObj[headerItem.name] = headerItem.value; + } + + for (let i = 0; i < 10; i++) { + try { + headersObj["TagoIO-Retries"] = i + 1; + await axios({ + method: "POST", + data, + url: action.action.url, + headers: headersObj, + }); + return; + } catch (ex) { + // error + } + } + + if (action.action.http_post_fallback_enabled && action.action.fallback_token) { + const device = await getDeviceByToken(action.action.fallback_token); + await addDeviceData(device.id, data); + } +} + +/** + * Triggers an action that runs analyses. + * @param {IAction} action The action to be triggered. + * @param {any} data The data to be passed as parameter to the analyses. + */ +async function triggerActionScriptType(action: IAction, data: any): Promise { + const analyses = action?.action?.analyses; + for (const analysis of analyses) { + runAnalysis(analysis, data); + } +} + +/** + * Triggers an action with a custom plugin type. + * @param {IAction} action The action to be triggered. + * @param {any} data The data to be passed as parameter to the onCall of the action. + */ +async function triggerActionPluginType(action: IAction, data: any): Promise { + const actionObject = action.action; + if (!actionObject.type?.includes(":")) { + return; + } + + const [pluginID, moduleID] = splitColon(action?.action.type); + const plugin = plugins.get(pluginID); + const module = plugin?.modules.get(moduleID); + delete actionObject.type; + + await module?.invokeOnCall(action.id, actionObject, data).catch(() => false); +} + +/** + * Invokes the `onTriggerChange` in the `action-trigger` plugins. + */ +export async function invokeActionOnTriggerChange(id: TGenericID, actionType: string, actionTrigger: any) { + const modules = getModuleList("action-trigger"); + + for (const module of modules) { + const usesPluginTrigger = actionType?.includes(":"); + if (usesPluginTrigger) { + const [pluginID, moduleID] = splitColon(actionType); + if (module.setup.id === moduleID && module.plugin.id === pluginID) { + module.invokeOnTriggerChange(id, actionTrigger); + } + } + } +} + +/** + * Edits a single action. + */ +export async function editAction(id: TGenericID, action: IActionEdit): Promise { + const oldAction = await getActionInfo(id); + + const parsed = await zActionEdit.parseAsync(action); + await invokeDatabaseFunction("editAction", id, parsed); + + const triggerChanged = JSON.stringify(oldAction.trigger) !== JSON.stringify(parsed.trigger); + if (triggerChanged) { + invokeActionOnTriggerChange(id, oldAction.type, action.trigger); + } +} + +/** + * Deletes a single action. + */ +export async function deleteAction(id: TGenericID): Promise { + await validateActionID(id); + await invokeDatabaseFunction("deleteAction", id); +} + +/** + * Creates a new action. + */ +export async function createAction(action: IActionCreate): Promise { + const parsed = await zActionCreate.parseAsync(action); + await invokeDatabaseFunction("createAction", parsed); + return parsed.id; +} diff --git a/packages/tcore-api/src/Services/Analysis.ts b/packages/tcore-api/src/Services/Analysis.ts new file mode 100644 index 00000000..89648c45 --- /dev/null +++ b/packages/tcore-api/src/Services/Analysis.ts @@ -0,0 +1,97 @@ +import { + IAnalysis, + IAnalysisCreate, + IAnalysisEdit, + IAnalysisList, + IAnalysisListQuery, + ILog, + ILogCreate, + TGenericID, + zAnalysis, + zAnalysisCreate, + zAnalysisEdit, + zAnalysisList, + zAnalysisListQuery, + zLog, + zLogCreate, +} from "@tago-io/tcore-sdk/types"; +import { z } from "zod"; +import { invokeDatabaseFunction } from "../Plugins/invokeDatabaseFunction"; + +/** + * Validates an analysis ID, throws an error if it doesn't exist. + */ +export async function validateAnalysisID(id: TGenericID): Promise { + const analysis = await invokeDatabaseFunction("getAnalysisInfo", id); + if (!analysis) { + throw new Error("Invalid Analysis ID"); + } +} + +/** + * Creates/adds a new log for an analysis. + */ +export async function addAnalysisLog(analysisID: TGenericID, data: ILogCreate) { + const parsed = await zLogCreate.parseAsync(data); + return invokeDatabaseFunction("addAnalysisLog", analysisID, parsed); +} + +/** + * Retrieves all the logs of an analysis. + */ +export async function getAnalysisLogs(analysisID: TGenericID): Promise { + const response = await invokeDatabaseFunction("getAnalysisLogs", analysisID); + const parsed = await z.array(zLog).parseAsync(response); + return parsed; +} + +/** + * Lists all the analyses. + */ +export async function getAnalysisList(query: IAnalysisListQuery): Promise { + const params = await zAnalysisListQuery.parseAsync(query); + const response = await invokeDatabaseFunction("getAnalysisList", params); + const parsed = await zAnalysisList.parseAsync(response); + return parsed; +} + +/** + * Retrieves all the information of a single analysis. + */ +export async function getAnalysisInfo(id: TGenericID): Promise { + const analysis = (await invokeDatabaseFunction("getAnalysisInfo", id)) as IAnalysis; + if (!analysis) { + throw new Error("Invalid Analysis ID"); + } + + analysis.console = await getAnalysisLogs(id); + + const parsed = await zAnalysis.parseAsync(analysis); + return parsed; +} + +/** + * Edits a single analysis. + */ +export async function editAnalysis(id: TGenericID, analysis: IAnalysisEdit): Promise { + await validateAnalysisID(id); + const parsed = await zAnalysisEdit.parseAsync(analysis); + await invokeDatabaseFunction("editAnalysis", id, parsed); +} + +/** + * Deletes a single analysis. + */ +export async function deleteAnalysis(id: TGenericID): Promise { + await validateAnalysisID(id); + await invokeDatabaseFunction("deleteAnalysis", id); +} + +/** + * Creates a new analysis. + */ +export async function createAnalysis(analysis: IAnalysisCreate): Promise { + const parsed = await zAnalysisCreate.parseAsync(analysis); + await invokeDatabaseFunction("createAnalysis", parsed); + return parsed.id; +} diff --git a/packages/tcore-api/src/Services/AnalysisCodeExecution.ts b/packages/tcore-api/src/Services/AnalysisCodeExecution.ts new file mode 100644 index 00000000..9c959fce --- /dev/null +++ b/packages/tcore-api/src/Services/AnalysisCodeExecution.ts @@ -0,0 +1,109 @@ +import { spawn } from "child_process"; +import fs from "fs"; +import { ESocketRoom, ILog, TGenericID } from "@tago-io/tcore-sdk/types"; +import { invokeFilesystemFunction } from "../Plugins/invokeFilesystemFunction"; +import { io } from "../Socket/SocketServer"; +import { log, logError } from "../Helpers/log"; +import { addAnalysisLog, editAnalysis, getAnalysisInfo } from "./Analysis"; +import { getMainSettings } from "./Settings"; + +/** + * Adds a log into the log buffer of the application and triggers the socket + * event for all sockets attached with the `analysis:log` resource. + */ +function addLog(error: boolean, id: TGenericID, message: string): void { + if (error) { + logError("api", `Analysis ${id}: ${message}`); + } else { + log("api", `Analysis ${id}: ${message}`); + } + + const data: ILog = { + error, + message, + timestamp: new Date(), + }; + + io.to(ESocketRoom.analysis).emit(`analysis:log:${id}`, data); + + addAnalysisLog(id, data); +} + +/** + * Runs an analysis script. + * @param {TGenericID} id The ID of the analysis. + * @param {any} data The data to be passed to the analysis' script. + */ +export async function runAnalysis(id: string, data: any): Promise { + const analysis = await getAnalysisInfo(id); + const settings = await getMainSettings(); + + const filePath = await invokeFilesystemFunction("resolveFile", analysis.file_path); + + try { + if (!analysis.active) { + const message = `The analysis is deactivated and can't run. To run the analysis activate it.`; + throw new Error(message); + } + if (!analysis.binary_path || !fs.existsSync(analysis.binary_path)) { + const message = `Binary executable path is missing or doesn't exist`; + throw new Error(message); + } + if (!analysis.file_path || !fs.existsSync(filePath)) { + const message = `File path is missing or doesn't exist`; + throw new Error(message); + } + + addLog(false, id, `Starting analysis ${id}`); + + const localAddress = `http://localhost:${settings.port}`; + + const child = spawn(`${analysis.binary_path}`, [filePath], { + env: { + T_ANALYSIS_CONTEXT: "tago-io", + T_ANALYSIS_ENV: stringifySafe(analysis.variables || []), + T_ANALYSIS_DATA: stringifySafe(data), + T_ANALYSIS_TOKEN: "", + T_ANALYSIS_ID: analysis.id, + TAGOIO_API: localAddress, + TAGO_API: localAddress, + }, + }); + + child.stdout.setEncoding("utf8"); + child.stderr.setEncoding("utf8"); + + child.stdout.on("data", (data) => { + addLog(false, id, data); + }); + + child.stderr.on("data", (data) => { + addLog(true, id, data); + }); + + child.on("close", (code) => { + addLog(false, id, `Finishing script execution with code ${code}`); + clearTimeout(timeout); + }); + + const timeout = setTimeout(() => { + addLog(true, id, `Script execution took too long (60s)`); + child.kill(); + }, 60 * 1000); + + editAnalysis(id, { last_run: new Date() }); + } catch (ex: any) { + addLog(true, id, `${ex?.message || ex}`); + } +} + +/** + * Safely stringifies an object. If the object cannot be stringified, `undefined` will be returned. + */ +function stringifySafe(data: any) { + try { + return JSON.stringify(data); + } catch (ex) { + return undefined; + } +} diff --git a/packages/tcore-api/src/Services/Device.ts b/packages/tcore-api/src/Services/Device.ts new file mode 100644 index 00000000..751b849d --- /dev/null +++ b/packages/tcore-api/src/Services/Device.ts @@ -0,0 +1,171 @@ +import { + ICreateDeviceResponse, + IDevice, + IDeviceCreate, + IDeviceEdit, + IDeviceList, + IDeviceListQuery, + IDeviceParameterCreate, + IDeviceToken, + IDeviceTokenCreate, + IDeviceTokenCreateResponse, + IDeviceTokenListQuery, + TGenericID, + TGenericToken, + zDevice, + zDeviceCreate, + zDeviceEdit, + zDeviceList, + zDeviceListQuery, + zDeviceParameter, + zDeviceParameterCreate, + zDeviceTokenCreate, +} from "@tago-io/tcore-sdk/types"; +import { z } from "zod"; +import { invokeDatabaseFunction } from "../Plugins/invokeDatabaseFunction"; + +/** + * Validates a device ID, throws an error if it doesn't exist. + */ +export const validateDeviceID = async (deviceID: TGenericID): Promise => { + const device = await getDeviceInfo(deviceID); + if (!device) { + throw new Error("Invalid Device ID"); + } +}; + +/** + * Deletes a device's param. + */ +export async function deleteDeviceParam(id: TGenericID): Promise { + await invokeDatabaseFunction("deleteDeviceParam", id); +} + +/** + * Overrides or edits device parameters. + */ +export async function setDeviceParams(deviceID: TGenericID, parameters: IDeviceParameterCreate[]): Promise { + await validateDeviceID(deviceID); + const parsed = await z.array(zDeviceParameterCreate).parseAsync(parameters); + await invokeDatabaseFunction("setDeviceParams", deviceID, parsed); +} + +/** + * Gets all the parameters of a device. + */ +export async function getDeviceParamList(deviceID: TGenericID, sentStatus?: boolean) { + await validateDeviceID(deviceID); + const response = await invokeDatabaseFunction("getDeviceParamList", deviceID, sentStatus); + const parsed = await z.array(zDeviceParameter).parseAsync(response); + return parsed; +} + +/** + * Deletes a device's token. + */ +export async function deleteDeviceToken(token: TGenericToken): Promise { + await invokeDatabaseFunction("deleteDeviceToken", token); +} + +/** + * Generates and retrieves a new device token. + */ +export async function createDeviceToken( + deviceID: TGenericID, + data: IDeviceTokenCreate +): Promise { + await validateDeviceID(deviceID); + + const parsed = await zDeviceTokenCreate.parseAsync(data); + await invokeDatabaseFunction("createDeviceToken", deviceID, parsed); + + return { + expire_time: parsed.expire_time, + permission: parsed.permission, + token: parsed.token, + }; +} + +/** + * Lists all the tokens of a device. + */ +export async function getDeviceTokenList(deviceID: TGenericID, query: IDeviceTokenListQuery): Promise { + await validateDeviceID(deviceID); + const response = await invokeDatabaseFunction("getDeviceTokenList", deviceID, query); + return response; +} + +/** + * Retrieves all the information of a single device via token. + */ +export async function getDeviceByToken(token: TGenericToken): Promise { + if (!token) { + throw new Error("Invalid token"); + } + + const device = await invokeDatabaseFunction("getDeviceByToken", token); + if (!device) { + throw new Error("Invalid token"); + } + + const response = await zDevice.parseAsync(device); + return response; +} + +/** + * Lists all the devices. + */ +export async function getDeviceList(query: IDeviceListQuery): Promise { + const queryParsed = await zDeviceListQuery.parseAsync(query); + const response = await invokeDatabaseFunction("getDeviceList", queryParsed); + const parsed = await zDeviceList.parseAsync(response); + return parsed; +} + +/** + * Retrieves all the information of a single device. + */ +export const getDeviceInfo = async (id: TGenericID): Promise => { + if (!id) { + throw new Error("Invalid Device ID"); + } + const device = await invokeDatabaseFunction("getDeviceInfo", id); + if (!device) { + throw new Error("Invalid Device ID"); + } + const parsed = await zDevice.parseAsync(device); + return parsed; +}; + +/** + * Edits a single device. + */ +export const editDevice = async (id: TGenericID, device: IDeviceEdit): Promise => { + await validateDeviceID(id); + const parsed = await zDeviceEdit.parseAsync(device); + await invokeDatabaseFunction("editDevice", id, parsed); +}; + +/** + * Deletes a single device. + */ +export async function deleteDevice(id: TGenericID): Promise { + await validateDeviceID(id); + await invokeDatabaseFunction("deleteDevice", id); +} + +/** + * Creates a new device. + */ +export async function createDevice(data: IDeviceCreate): Promise { + const parsed = await zDeviceCreate.parseAsync(data); + + await invokeDatabaseFunction("createDevice", parsed); + + const token = await createDeviceToken(parsed.id, { name: "Default", expire_time: "never" }); + + return { + device_id: parsed.id, + token: token.token, + }; +} diff --git a/packages/tcore-api/src/Services/DeviceData/DeviceData.test.ts b/packages/tcore-api/src/Services/DeviceData/DeviceData.test.ts new file mode 100644 index 00000000..30e86603 --- /dev/null +++ b/packages/tcore-api/src/Services/DeviceData/DeviceData.test.ts @@ -0,0 +1,977 @@ +const invokeDatabaseFunction = jest.fn((method: string) => { + switch (method) { + case "getDeviceInfo": + return activeDevice; + default: + return []; + } +}); + +jest.mock("../../Plugins/invokeDatabaseFunction", () => ({ invokeDatabaseFunction })); + +import { + IAction, + IDevice, + IDeviceAddDataOptions, + IDeviceData, + IDeviceDataCreate, + zDeviceDataQuery, +} from "@tago-io/tcore-sdk/types"; +import Module from "../../Plugins/Module/Module"; +import * as Device from "../Device"; +import * as Statistic from "../Statistic"; +import * as Action from "../Action"; +import * as LiveInspector from "../LiveInspector"; +import * as PayloadParser from "../PayloadParserCodeExecution"; +import { plugins } from "../../Plugins/Host"; +import * as DeviceData from "./DeviceData"; + +beforeAll(() => { + jest.useFakeTimers(); +}); + +afterEach(() => { + jest.restoreAllMocks(); + jest.clearAllMocks(); + plugins.clear(); +}); + +afterAll(() => { + jest.clearAllTimers(); +}); + +const inactiveDevice: any = { + id: "123", + name: "Hello world", +}; + +const action: IAction = { + id: "456", + type: "post", + active: true, + created_at: new Date(), + tags: [], + name: "Action #1", +}; + +const activeDevice: IDevice = { + id: "123", + active: true, + created_at: new Date(), + tags: [], + name: "Hello world", + inspected_at: new Date(), + type: "immutable", +}; + +const mutableDevice: IDevice = { + ...activeDevice, + type: "mutable", +}; + +const immutableDevice: IDevice = { + ...activeDevice, + type: "immutable", +}; + +const dataCreate: IDeviceDataCreate = { + variable: "temperature", + value: 120, + unit: "F", + time: new Date(), +}; + +const mockData: IDeviceData = { + id: "789", + variable: "temperature", + value: 120, + unit: "F", + time: new Date(), + created_at: new Date(), +}; + +describe("addDeviceData", () => { + test("resolves device", async () => { + const mock = jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(inactiveDevice); + await DeviceData.addDeviceData("123", []).catch(() => null); + expect(mock).toHaveBeenCalled(); + }); +}); + +describe("addDeviceDataByDevice", () => { + test("rejects inactive devices", async () => { + const error = jest.fn(); + await DeviceData.addDeviceDataByDevice(inactiveDevice, []).catch(error); + expect(error).toHaveBeenCalledWith(new Error("Device not found or inactive")); + }); + + test("rejects falsy devices", async () => { + const error = jest.fn(); + await DeviceData.addDeviceDataByDevice(null as any, []).catch(error); + expect(error).toHaveBeenCalledWith(new Error("Device not found or inactive")); + }); + + test("applies payload encoder", async () => { + jest.spyOn(DeviceData, "applyPayloadEncoder").mockResolvedValue(123); + const fn = () => DeviceData.addDeviceDataByDevice(activeDevice, []); + await expect(fn).rejects.toThrow("invalid_type"); + }); + + test("applies payload parser", async () => { + jest.spyOn(PayloadParser, "runPayloadParser").mockResolvedValue("abc"); + const fn = () => DeviceData.addDeviceDataByDevice(activeDevice, []); + await expect(fn).rejects.toThrow("invalid_type"); + }); + + test("payload parser cannot return a string", async () => { + jest.spyOn(PayloadParser, "runPayloadParser").mockResolvedValue("hello"); + const fn = () => DeviceData.addDeviceDataByDevice(activeDevice, []); + await expect(fn).rejects.toThrow("Expected object, received string"); + }); + + test("payload parser cannot return a number", async () => { + jest.spyOn(PayloadParser, "runPayloadParser").mockResolvedValue(123); + const fn = () => DeviceData.addDeviceDataByDevice(activeDevice, []); + await expect(fn).rejects.toThrow("Expected object, received number"); + }); + + test("payload parser cannot return a non-data object", async () => { + jest.spyOn(PayloadParser, "runPayloadParser").mockResolvedValue({}); + const fn = () => DeviceData.addDeviceDataByDevice(activeDevice, []); + await expect(fn).rejects.toThrow("variable"); + }); + + test("payload parser cannot return a random array", async () => { + jest.spyOn(PayloadParser, "runPayloadParser").mockResolvedValue([1, 2, 3]); + const fn = () => DeviceData.addDeviceDataByDevice(activeDevice, []); + await expect(fn).rejects.toThrow("Expected object, received number"); + }); + + test("payload parser can return a data object", async () => { + jest.spyOn(PayloadParser, "runPayloadParser").mockResolvedValue(dataCreate); + const result = await DeviceData.addDeviceDataByDevice(activeDevice, []); + expect(result).toEqual("1 items added"); + }); + + test("payload parser can return a data array", async () => { + jest.spyOn(PayloadParser, "runPayloadParser").mockResolvedValue([dataCreate, dataCreate]); + const result = await DeviceData.addDeviceDataByDevice(activeDevice, []); + expect(result).toEqual("2 items added"); + }); + + test("calls invokeDatabaseFunction", async () => { + const data = { ...dataCreate, time: null }; + await DeviceData.addDeviceDataByDevice(activeDevice, data); + + const arg1 = invokeDatabaseFunction.mock.calls[0][0]; // method + const arg2 = (invokeDatabaseFunction as any).mock.calls[0][1]; // device id + const arg3 = (invokeDatabaseFunction as any).mock.calls[0][3]; // data + expect(arg1).toEqual("addDeviceData"); + expect(arg2).toEqual(activeDevice.id); + expect(arg3).toHaveLength(1); + expect(arg3[0].id).toBeTruthy(); + expect(arg3[0].created_at).toBeTruthy(); + expect(arg3[0].type).toEqual("number"); + expect(arg3[0].time).toBeInstanceOf(Date); + }); + + test("applies payload encoder, then parser, then inserts data", async () => { + const m1 = jest.spyOn(DeviceData, "applyPayloadEncoder").mockResolvedValue(123); + const m2 = jest.spyOn(PayloadParser, "runPayloadParser").mockResolvedValue([]); + await DeviceData.addDeviceDataByDevice(activeDevice, dataCreate); + + expect(m1.mock.calls[0][0]).toEqual(activeDevice); + expect(m1.mock.calls[0][1]).toEqual(dataCreate); + expect(m1.mock.calls[0][2]).toBeTruthy(); + + expect(m2.mock.calls[0][0]).toEqual(activeDevice); + expect(m2.mock.calls[0][1]).toEqual(123); + expect(m2.mock.calls[0][2]).toBeTruthy(); + + const data = (invokeDatabaseFunction as any).mock.calls[0][3]; + expect(data).toEqual([]); + }); + + test("triggers actions after inserting data", async () => { + const mock = jest.spyOn(DeviceData, "triggerActions"); + await DeviceData.addDeviceDataByDevice(activeDevice, dataCreate); + expect(mock).toHaveBeenCalled(); + }); + + test("adds statistics", async () => { + const mock = jest.spyOn(Statistic, "addStatistic"); + await DeviceData.addDeviceDataByDevice(activeDevice, [dataCreate, dataCreate]); + expect(mock).toHaveBeenCalledWith({ input: 2, output: 0 }); + }); + + test("updates device last_input", async () => { + const mock = jest.spyOn(Device, "editDevice"); + await DeviceData.addDeviceDataByDevice(activeDevice, dataCreate); + + const arg1 = mock.mock.calls[0][0]; + const arg2 = mock.mock.calls[0][1]; + expect(arg1).toEqual(activeDevice.id); + expect(arg2.updated_at).toBeInstanceOf(Date); + expect(arg2.last_input).toBeInstanceOf(Date); + }); + + test("throws if mutable device has too much data", async () => { + jest.spyOn(DeviceData, "getDeviceDataAmount").mockResolvedValue(50000); + const fn = () => DeviceData.addDeviceDataByDevice(mutableDevice, dataCreate); + await expect(fn).rejects.toThrow("has reached the limit"); + }); + + test("doesn't throws if mutable device doesn't have too much data", async () => { + jest.spyOn(DeviceData, "getDeviceDataAmount").mockResolvedValue(1000); + const result = await DeviceData.addDeviceDataByDevice(mutableDevice, dataCreate); + expect(result).toEqual("1 items added"); + }); + + test("doesn't throw if immutable device has too much data", async () => { + jest.spyOn(DeviceData, "getDeviceDataAmount").mockResolvedValue(50000); + const result = await DeviceData.addDeviceDataByDevice(immutableDevice, dataCreate); + expect(result).toEqual("1 items added"); + }); + + test("doesn't generate liveInspectorID if options has it", async () => { + const options: IDeviceAddDataOptions = { liveInspectorID: "123" }; + await DeviceData.addDeviceDataByDevice(immutableDevice, dataCreate, options); + expect(options.liveInspectorID).toEqual("123"); + }); + + test("generates liveInspectorID if options doesn't have it", async () => { + const options: IDeviceAddDataOptions = {}; + await DeviceData.addDeviceDataByDevice(immutableDevice, dataCreate, options); + expect(options.liveInspectorID).toHaveLength(10); + }); + + test("sets rawPayload on options as object", async () => { + const options: IDeviceAddDataOptions = {}; + await DeviceData.addDeviceDataByDevice(immutableDevice, dataCreate, options); + expect(options.rawPayload).toEqual([dataCreate]); + }); + + test("sets rawPayload on options as array", async () => { + const options: IDeviceAddDataOptions = {}; + await DeviceData.addDeviceDataByDevice(immutableDevice, [dataCreate], options); + expect(options.rawPayload).toEqual([dataCreate]); + }); + + test("sets rawPayload on options as anything", async () => { + const options: IDeviceAddDataOptions = {}; + const data = "hello-world"; + await DeviceData.addDeviceDataByDevice(immutableDevice, data, options).catch(() => null); + expect(options.rawPayload).toEqual(data); + }); + + test("calls emitToLiveInspector with the raw payload", async () => { + const mock = jest.spyOn(LiveInspector, "emitToLiveInspector"); + await DeviceData.addDeviceDataByDevice(immutableDevice, dataCreate); + const arg1 = mock.mock.calls[0][0]; // device + const arg2 = mock.mock.calls[0][1]; // inspector data + const arg3 = mock.mock.calls[0][2]; // live inspector id + expect(arg1).toEqual(immutableDevice); + expect(arg2).toEqual({ title: "Raw Payload", content: dataCreate }); + expect(arg3).toBeTruthy(); + }); +}); + +describe("group generation", () => { + test("generates a group", async () => { + await DeviceData.addDeviceDataByDevice(activeDevice, dataCreate); + const argData = (invokeDatabaseFunction as any).mock.calls[0][3]; + expect(argData).toHaveLength(1); + expect(argData[0].group).toHaveLength(24); + }); + + test("generates a single group for multiple items", async () => { + const data = [dataCreate, dataCreate, dataCreate]; + await DeviceData.addDeviceDataByDevice(activeDevice, data); + const argData = (invokeDatabaseFunction as any).mock.calls[0][3]; + expect(argData).toHaveLength(3); + expect(argData[0].group).toHaveLength(24); + expect(argData[1].group).toHaveLength(24); + expect(argData[2].group).toHaveLength(24); + expect(argData[1].group).toEqual(argData[0].group); + expect(argData[2].group).toEqual(argData[0].group); + }); + + test("doesn't generate new group for items with a group", async () => { + const data = [dataCreate, { ...dataCreate, group: "abc" }]; + await DeviceData.addDeviceDataByDevice(activeDevice, data); + const argData = (invokeDatabaseFunction as any).mock.calls[0][3]; + expect(argData).toHaveLength(2); + expect(argData[0].group).toHaveLength(24); + expect(argData[1].group).toEqual("abc"); + }); + + test("respects serie property", async () => { + const data = [dataCreate, { ...dataCreate, serie: "abc" }]; + await DeviceData.addDeviceDataByDevice(activeDevice, data); + const argData = (invokeDatabaseFunction as any).mock.calls[0][3]; + expect(argData).toHaveLength(2); + expect(argData[0].group).toHaveLength(24); + expect(argData[1].group).toEqual("abc"); + }); + + test("respects serie, group, and auto-generation", async () => { + const data = [ + { ...dataCreate, serie: "456" }, + { ...dataCreate, serie: "abc" }, + { ...dataCreate, group: undefined }, + ]; + await DeviceData.addDeviceDataByDevice(activeDevice, data); + const argData = (invokeDatabaseFunction as any).mock.calls[0][3]; + expect(argData).toHaveLength(3); + expect(argData[0].group).toEqual("456"); + expect(argData[1].group).toEqual("abc"); + expect(argData[2].group).toHaveLength(24); + }); +}); + +describe("deleteDeviceData", () => { + test("cannot delete data from immutable devices", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(immutableDevice); + const fn = () => DeviceData.deleteDeviceData(immutableDevice.id); + await expect(fn).rejects.toThrow("Data in immutable devices cannot be deleted"); + }); + + test("can delete data from mutable devices", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(mutableDevice); + jest.spyOn(DeviceData, "getDeviceData").mockResolvedValue([]); + await DeviceData.deleteDeviceData(mutableDevice.id); + expect(invokeDatabaseFunction).toHaveBeenCalled(); + }); + + test("passes array of ids to database deleteDeviceData", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(mutableDevice); + jest.spyOn(DeviceData, "getDeviceData").mockResolvedValue([mockData, mockData]); + await DeviceData.deleteDeviceData(mutableDevice.id); + + const arg1 = invokeDatabaseFunction.mock.calls[0][0]; // method + const arg2 = (invokeDatabaseFunction as any).mock.calls[0][1]; // device id + const arg3 = (invokeDatabaseFunction as any).mock.calls[0][3]; // ids + expect(arg1).toEqual("deleteDeviceData"); + expect(arg2).toEqual(mutableDevice.id); + expect(arg3).toHaveLength(2); + expect(arg3).toEqual(["789", "789"]); + }); + + test("returns the amount of deleted items", async () => { + const deviceData = [mockData, mockData, mockData, mockData]; + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(mutableDevice); + jest.spyOn(DeviceData, "getDeviceData").mockResolvedValue(deviceData); + const result = await DeviceData.deleteDeviceData(mutableDevice.id); + expect(result).toEqual(deviceData.length); + }); + + test("throws if getDeviceData result is not an array", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(mutableDevice); + jest.spyOn(DeviceData, "getDeviceData").mockResolvedValue(123); + const fn = () => DeviceData.deleteDeviceData(mutableDevice.id); + await expect(fn).rejects.toThrow("Invalid query"); + }); +}); + +describe("getDeviceDataAmount", () => { + test("validates the device id", async () => { + const spy = jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + await DeviceData.getDeviceDataAmount(mutableDevice.id).catch(() => null); + expect(spy).toHaveBeenCalled(); + }); + + test("database getDeviceDataAmount cannot return a string", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + invokeDatabaseFunction.mockResolvedValueOnce("123"); + const fn = () => DeviceData.getDeviceDataAmount(mutableDevice.id); + await expect(fn).rejects.toThrow("Expected number, received string"); + }); + + test("database getDeviceDataAmount cannot return an array", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + invokeDatabaseFunction.mockResolvedValueOnce([]); + const fn = () => DeviceData.getDeviceDataAmount(mutableDevice.id); + await expect(fn).rejects.toThrow("Expected number, received array"); + }); + + test("database getDeviceDataAmount cannot return an object", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + invokeDatabaseFunction.mockResolvedValueOnce({}); + const fn = () => DeviceData.getDeviceDataAmount(mutableDevice.id); + await expect(fn).rejects.toThrow("Expected number, received object"); + }); + + test("database getDeviceDataAmount cannot return false", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + invokeDatabaseFunction.mockResolvedValueOnce(false); + const fn = () => DeviceData.getDeviceDataAmount(mutableDevice.id); + await expect(fn).rejects.toThrow("Expected number, received boolean"); + }); + + test("database getDeviceDataAmount cannot return true", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + invokeDatabaseFunction.mockResolvedValueOnce(true); + const fn = () => DeviceData.getDeviceDataAmount(mutableDevice.id); + await expect(fn).rejects.toThrow("Expected number, received boolean"); + }); + + test("database getDeviceDataAmount must return a number", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + invokeDatabaseFunction.mockResolvedValueOnce(1000); + const result = await DeviceData.getDeviceDataAmount(mutableDevice.id); + expect(result).toEqual(1000); + }); +}); + +describe("applyPayloadEncoder", () => { + test("returns original data if there are no encoders", async () => { + const result = await DeviceData.applyPayloadEncoder(mutableDevice, "123"); + expect(result).toEqual("123"); + }); + + test("emits to live inspector if encoder plugin is not found", async () => { + const mock = jest.spyOn(LiveInspector, "emitToLiveInspector"); + const device = { ...mutableDevice, encoder_stack: ["plugin1:module1"] }; + const result = await DeviceData.applyPayloadEncoder(device, "123"); + expect(result).toEqual("123"); + expect(mock.mock.calls[0][1]).toEqual({ title: "Encoder plugin not found", content: "plugin1" }); + }); + + test("emits to live inspector if encoder module is not found", async () => { + plugins.set("plugin1", { modules: new Map() } as any); + const mock = jest.spyOn(LiveInspector, "emitToLiveInspector"); + const device = { ...mutableDevice, encoder_stack: ["plugin1:module1"] }; + const result = await DeviceData.applyPayloadEncoder(device, "123"); + expect(result).toEqual("123"); + expect(mock.mock.calls[0][1]).toEqual({ title: "Encoder module not found", content: "module1" }); + }); + + test("invokes onCall on the module", async () => { + const plugin: any = { modules: new Map() }; + plugin.modules.set("module1", new Module(plugin, {} as any)); + plugin.modules.get("module1").invokeOnCall = jest.fn().mockResolvedValue(444); + plugins.set("plugin1", plugin); + + const device = { ...mutableDevice, encoder_stack: ["plugin1:module1"] }; + const result = await DeviceData.applyPayloadEncoder(device, "123"); + + expect(plugin.modules.get("module1").invokeOnCall).toHaveBeenCalledWith("123"); + expect(result).toEqual(444); + }); + + test("ignores encoder if onCall throws an error", async () => { + const plugin: any = { modules: new Map() }; + plugin.modules.set("module1", new Module(plugin, {} as any)); + plugin.modules.get("module1").invokeOnCall = jest.fn().mockRejectedValue(null); + plugins.set("plugin1", plugin); + + const device = { ...mutableDevice, encoder_stack: ["plugin1:module1"] }; + const result = await DeviceData.applyPayloadEncoder(device, "123"); + + expect(plugin.modules.get("module1").invokeOnCall).toHaveBeenCalledWith("123"); + expect(result).toEqual("123"); + }); + + test("emits to live inspector after module.onCall", async () => { + const plugin: any = { modules: new Map() }; + plugin.modules.set("module1", new Module(plugin, { id: "1", name: "Temp" } as any)); + plugin.modules.get("module1").invokeOnCall = jest.fn().mockResolvedValue(1000); + plugins.set("plugin1", plugin); + + const mock = jest.spyOn(LiveInspector, "emitToLiveInspector"); + const device = { ...mutableDevice, encoder_stack: ["plugin1:module1"] }; + await DeviceData.applyPayloadEncoder(device, "123"); + + expect(mock.mock.calls[0][1]).toEqual({ title: `Applied encoder Temp`, content: 1000 }); + }); + + test("emits to live inspector using liveInspectorID", async () => { + const options = { liveInspectorID: "684613516843586" }; + + const plugin: any = { modules: new Map() }; + plugin.modules.set("module1", new Module(plugin, { id: "1", name: "Temp" } as any)); + plugin.modules.get("module1").invokeOnCall = jest.fn().mockResolvedValue(null); + plugins.set("plugin1", plugin); + + const mock = jest.spyOn(LiveInspector, "emitToLiveInspector"); + const device = { ...mutableDevice, encoder_stack: ["plugin1:module1"] }; + await DeviceData.applyPayloadEncoder(device, "123", options); + + expect(mock.mock.calls[0][1]).toEqual({ title: `Applied encoder Temp`, content: "null" }); + expect(mock.mock.calls[0][2]).toEqual(options.liveInspectorID); + }); +}); + +describe("editDeviceData", () => { + test("calls invokeDatabaseFunction", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(mutableDevice); + await DeviceData.editDeviceData("123", [mockData]); + expect(invokeDatabaseFunction).toHaveBeenCalled(); + }); + + test("deletes time and created_at", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(mutableDevice); + await DeviceData.editDeviceData("123", [mockData]); + const arg3 = invokeDatabaseFunction.mock.calls[0][2][0]; + expect(arg3.time).toBeUndefined(); + expect(arg3.created_at).toBeUndefined(); + }); + + test("keeps data id", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(mutableDevice); + await DeviceData.editDeviceData("123", [mockData]); + const arg3 = invokeDatabaseFunction.mock.calls[0][3][0]; + expect(arg3.id).toEqual(mockData.id); + }); +}); + +describe("emptyDevice", () => { + test("calls invokeDatabaseFunction", async () => { + await DeviceData.emptyDevice("123"); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("emptyDevice", "123", "immutable"); + }); +}); + +describe("getDeviceData", () => { + test("throws on invalid query type", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "invalid_query" }; + const fn = () => DeviceData.getDeviceData("123", query); + await expect(fn).rejects.toThrow("Invalid enum value"); + }); + + test("calls getDeviceDataCount on count", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "count" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataCount", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataCount on count", async () => { + invokeDatabaseFunction.mockResolvedValueOnce(456); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "count" }; + const result = await DeviceData.getDeviceData("123", query); + expect(result).toEqual(456); + }); + + test("calls getDeviceDataAvg on avg", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { start_date: new Date(), query: "avg" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataAvg", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataAvg on avg", async () => { + invokeDatabaseFunction.mockResolvedValueOnce(1000); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { start_date: new Date(), query: "avg" }; + const result = await DeviceData.getDeviceData("123", query); + expect(result).toEqual(1000); + }); + + test("calls getDeviceDataSum on sum", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { start_date: new Date(), query: "sum" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataSum", "123", "immutable", parsed); + }); + + test("calls getDeviceDataDefaultQ without a query", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const parsed = zDeviceDataQuery.parse({}); + await DeviceData.getDeviceData("123"); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataDefaultQ", "123", "immutable", parsed); + }); + + test("calls getDeviceDataDefaultQ on defaultQ", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "defaultQ" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataDefaultQ", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataDefaultQ", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataLastValue on last_value", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "last_value" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataLastValue", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataLastValue", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataLastLocation on last_location", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "last_location" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataLastLocation", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataLastLocation", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataLastItem on last_item", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "last_item" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataLastItem", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataLastItem", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataLastInsert on last_insert", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "last_insert" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataLastInsert", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataLastInsert", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataFirstValue on first_value", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "first_value" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataFirstValue", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataFirstValue", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataFirstLocation on first_location", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "first_location" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataFirstLocation", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataFirstLocation", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataFirstItem on first_item", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "first_item" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataFirstItem", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataFirstItem", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataFirstInsert on first_insert", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { query: "first_insert" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataFirstInsert", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataFirstInsert", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataMin on min", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { start_date: new Date(), query: "min" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataMin", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataMin", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("calls getDeviceDataMax on max", async () => { + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const query: any = { start_date: new Date(), query: "max" }; + const parsed = zDeviceDataQuery.parse(query); + await DeviceData.getDeviceData("123", query); + expect(invokeDatabaseFunction).toHaveBeenCalledWith("getDeviceDataMax", "123", "immutable", parsed); + }); + + test("returns the value of getDeviceDataMax", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + }); + + test("adds device to return on array queries", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData, serie: "123" }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123"); + expect(result).toHaveLength(1); + expect(result[0].id).toEqual(mockData.id); + expect(result[0].device).toEqual("123"); + expect(result[0].created_at).toBeUndefined(); + expect(result[0].group).toEqual("123"); + }); + + test("only adds created_at if details is set", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const result = await DeviceData.getDeviceData("123", { details: true }); + expect(result).toHaveLength(1); + expect(result[0].created_at).toBeInstanceOf(Date); + }); + + test("adds statistics", async () => { + invokeDatabaseFunction.mockResolvedValueOnce([{ ...mockData }]); + jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(activeDevice); + const mock = jest.spyOn(Statistic, "addStatistic"); + await DeviceData.getDeviceData("123"); + expect(mock).toHaveBeenCalledWith({ input: 0, output: 1 }); + }); +}); + +describe("triggerActions", () => { + test("gets all actions", async () => { + const mock = jest.spyOn(Action, "getActionList").mockResolvedValue([]); + await DeviceData.triggerActions("123", []); + expect(mock.mock.calls[0][0].amount).toBeGreaterThanOrEqual(999999); + }); + + test("triggers basic action", async () => { + const data = { ...mockData, value: 100 }; + const conditions = [{ variable: "temperature", is: "<", value: "150" }]; + action.device_info = { id: "123" }; + action.trigger = { conditions }; + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + await DeviceData.triggerActions("123", [data]); + expect(mock1).toHaveBeenCalled(); + expect(mock2).toHaveBeenCalled(); + }); + + test("triggers if device tag key and value match", async () => { + const data = { ...mockData, value: 100 }; + const device = { ...activeDevice, tags: [{ key: "hello", value: "world" }] }; + const conditions = [{ variable: "temperature", is: "<", value: "150" }]; + action.device_info = { tag_key: "hello", tag_value: "world" }; + action.trigger = { conditions }; + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + const mock3 = jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(device); + await DeviceData.triggerActions("123", [data]); + expect(mock1).toHaveBeenCalled(); + expect(mock2).toHaveBeenCalled(); + expect(mock3).toHaveBeenCalled(); + }); + + test("doesn't trigger if device id doesn't match", async () => { + const data = { ...mockData, value: 100 }; + const conditions = [{ variable: "temperature", is: "<", value: "150" }]; + action.device_info = { id: "456" }; + action.trigger = { conditions }; + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + await DeviceData.triggerActions("123", [data]); + expect(mock1).toHaveBeenCalled(); + expect(mock2).not.toHaveBeenCalled(); + }); + + test("doesn't trigger if device_info doesn't match", async () => { + const data = { ...mockData, value: 100 }; + const conditions = [{ variable: "temperature", is: "<", value: "150" }]; + action.device_info = null; + action.trigger = { conditions }; + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + await DeviceData.triggerActions("123", [data]); + expect(mock1).toHaveBeenCalled(); + expect(mock2).not.toHaveBeenCalled(); + }); + + test("doesn't trigger if device tag is not found", async () => { + const data = { ...mockData, value: 100 }; + const device = { ...activeDevice, tags: [] }; + const conditions = [{ variable: "temperature", is: "<", value: "150" }]; + action.device_info = { tag_key: "hello", tag_value: "world" }; + action.trigger = { conditions }; + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + const mock3 = jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(device); + await DeviceData.triggerActions("123", [data]); + expect(mock1).toHaveBeenCalled(); + expect(mock2).not.toHaveBeenCalled(); + expect(mock3).toHaveBeenCalled(); + }); + + test("doesn't trigger if device tag key is not match", async () => { + const data = { ...mockData, value: 100 }; + const device: any = { ...activeDevice, tags: [{ value: "world" }] }; + const conditions = [{ variable: "temperature", is: "<", value: "150" }]; + action.device_info = { tag_key: "hello", tag_value: "world" }; + action.trigger = { conditions }; + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + const mock3 = jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(device); + await DeviceData.triggerActions("123", [data]); + expect(mock1).toHaveBeenCalled(); + expect(mock2).not.toHaveBeenCalled(); + expect(mock3).toHaveBeenCalled(); + }); + + test("doesn't trigger if device tag value is not match", async () => { + const data = { ...mockData, value: 100 }; + const device: any = { ...activeDevice, tags: [{ key: "hello" }] }; + const conditions = [{ variable: "temperature", is: "<", value: "150" }]; + action.device_info = { tag_key: "hello", tag_value: "world" }; + action.trigger = { conditions }; + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + const mock3 = jest.spyOn(Device, "getDeviceInfo").mockResolvedValue(device); + await DeviceData.triggerActions("123", [data]); + expect(mock1).toHaveBeenCalled(); + expect(mock2).not.toHaveBeenCalled(); + expect(mock3).toHaveBeenCalled(); + }); + + test("doesn't trigger with invalid condition", async () => { + const data = { ...mockData, value: 200 }; + const conditions = [{ variable: "temperature", is: "<", value: "100" }]; + action.device_info = { id: "123" }; + action.trigger = { conditions }; + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + await DeviceData.triggerActions("123", [data]); + expect(mock1).toHaveBeenCalled(); + expect(mock2).not.toHaveBeenCalled(); + }); + + test("triggers custom plugin action type", async () => { + action.device_info = { id: "123" }; + action.type = "plugin1:module1"; + + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + const mock3 = jest.fn().mockResolvedValue(true); + + const plugin: any = { modules: new Map() }; + plugin.modules.set("module1", new Module(plugin, {} as any)); + plugin.modules.get("module1").invokeOnCall = mock3; + plugins.set("plugin1", plugin); + + await DeviceData.triggerActions("123", [mockData]); + + expect(mock1).toHaveBeenCalled(); + expect(mock2).toHaveBeenCalled(); + expect(mock3).toHaveBeenCalledWith(action.id, { ...action.trigger }, [mockData]); + }); + + test("doesn't trigger custom plugin action type if an error is thrown", async () => { + action.device_info = { id: "123" }; + action.type = "plugin1:module1"; + + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + const mock3 = jest.fn().mockRejectedValue(null); + + const plugin: any = { modules: new Map() }; + plugin.modules.set("module1", new Module(plugin, {} as any)); + plugin.modules.get("module1").invokeOnCall = mock3; + plugins.set("plugin1", plugin); + + await DeviceData.triggerActions("123", [mockData]); + + expect(mock1).toHaveBeenCalled(); + expect(mock2).not.toHaveBeenCalled(); + expect(mock3).toHaveBeenCalledWith(action.id, { ...action.trigger }, [mockData]); + }); + + test("doesn't trigger custom plugin action type if plugin is not found", async () => { + action.device_info = { id: "123" }; + action.type = "plugin1:module1"; + + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + + await DeviceData.triggerActions("123", [mockData]); + + expect(mock1).toHaveBeenCalled(); + expect(mock2).not.toHaveBeenCalled(); + }); + + test("doesn't trigger custom plugin action type if module is not found", async () => { + action.device_info = { id: "123" }; + action.type = "plugin1:module1"; + + const mock1 = jest.spyOn(Action, "getActionList").mockResolvedValue([action]); + const mock2 = jest.spyOn(Action, "triggerAction").mockResolvedValue(); + + const plugin: any = { modules: new Map() }; + plugins.set("plugin1", plugin); + + await DeviceData.triggerActions("123", [mockData]); + + expect(mock1).toHaveBeenCalled(); + expect(mock2).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/tcore-api/src/Services/DeviceData/DeviceData.ts b/packages/tcore-api/src/Services/DeviceData/DeviceData.ts new file mode 100644 index 00000000..ee069031 --- /dev/null +++ b/packages/tcore-api/src/Services/DeviceData/DeviceData.ts @@ -0,0 +1,341 @@ +import { + TGenericID, + IDeviceDataQuery, + IDeviceData, + zDeviceDataCreate, + zDeviceData, + zDeviceDataQuery, + IDevice, + generateResourceID, + IDeviceAddDataOptions, + zDeviceDataUpdate, +} from "@tago-io/tcore-sdk/types"; +import { z } from "zod"; +import { DateTime } from "luxon"; +import removeNullValues from "../../Helpers/removeNullValues"; +import splitColon from "../../Helpers/splitColon"; +import { plugins } from "../../Plugins/Host"; +import { invokeDatabaseFunction } from "../../Plugins/invokeDatabaseFunction"; +import { getActionList, shouldNativeActionTrigger, triggerAction } from "../Action"; +import { editDevice, getDeviceInfo } from "../Device"; +import { addStatistic } from "../Statistic"; +import { runPayloadParser } from "../PayloadParserCodeExecution"; +import { emitToLiveInspector, getLiveInspectorID } from "../LiveInspector"; + +const LIMIT_DATA_ON_MUTABLE = 50_000; +const MAXIMUM_MONTH_RANGE = 1.1; + +/** + * Empties a device completely. + */ +export async function emptyDevice(deviceID: TGenericID) { + const device = await getDeviceInfo(deviceID); + await invokeDatabaseFunction("emptyDevice", deviceID, device.type); +} + +/** + * Retrieves the data amount in a device. + */ +export const getDeviceDataAmount = async (deviceID: TGenericID): Promise => { + const device = await getDeviceInfo(deviceID); + const response = await invokeDatabaseFunction("getDeviceDataAmount", deviceID, device.type); + const parsed = await z.number().parseAsync(response); + return parsed; +}; + +/** + * Triggers all the actions related to the device that just sent the last data insert. + */ +export const triggerActions = async (deviceID: TGenericID, data: IDeviceData[]): Promise => { + const device = await getDeviceInfo(deviceID); + const actions = await getActionList({ fields: ["trigger", "type", "device_info"], amount: 999999 }); + + for (const action of actions) { + const { device_info } = action as any; + + const deviceMatchesAction = + device_info && + (device_info.id === deviceID || + device.tags.find((x) => x.key === device_info.tag_key && x.value === device_info.tag_value)); + + if (deviceMatchesAction) { + const usesPluginType = String(action.type).includes(":"); + if (usesPluginType) { + // using a custom plugin type for the action + const [pluginID, moduleID] = splitColon(action.type as string); + const plugin = plugins.get(pluginID); + const module = plugin?.modules.get(moduleID); + const values = { ...action.trigger }; + + const shouldTrigger = await module + ?.invokeOnCall(action.id, values, data) + .then(() => true) + .catch(() => false); + + if (shouldTrigger) { + triggerAction(action.id, data); + } + } else { + // using a built-in native type for the action + const shouldTrigger = shouldNativeActionTrigger(action, data); + if (shouldTrigger) { + triggerAction(action.id, data); + } + } + } + } +}; + +/** + * Applies all payload encoders available in order of priority. + */ +export const applyPayloadEncoder = async ( + device: IDevice, + data: any, + options?: IDeviceAddDataOptions +): Promise => { + const stack = device.encoder_stack || []; + + let lastData: any = data; + for (const encoder of stack) { + try { + const [pluginID, moduleID] = splitColon(encoder); + const plugin = plugins.get(pluginID); + if (!plugin) { + emitToLiveInspector(device, { title: "Encoder plugin not found", content: pluginID }, options?.liveInspectorID); + continue; + } + + const module = plugin.modules.get(moduleID); + + if (!module) { + emitToLiveInspector(device, { title: "Encoder module not found", content: moduleID }, options?.liveInspectorID); + continue; + } + + lastData = await module.invokeOnCall(lastData); + emitToLiveInspector( + device, + { + title: `Applied encoder ${module.name}`, + content: lastData || "null", + }, + options?.liveInspectorID + ); + } catch (ex: any) { + const content = ex?.message || ex?.toString?.() || "Unknown error"; + emitToLiveInspector(device, { title: "Error while encoding data", content }, options?.liveInspectorID); + } + } + + return lastData; +}; + +/** + * Adds data into a device by an actual device object. + * @param {IDevice} device Device object who sent the data. + * @param {any} data Data to be inserted. + */ +export const addDeviceDataByDevice = async (device: IDevice, data: any, options?: IDeviceAddDataOptions) => { + if (!device || !device.active) { + throw new Error("Device not found or inactive"); + } + if (!options) { + options = {}; + } + if (!options.liveInspectorID) { + options.liveInspectorID = getLiveInspectorID(device); + } + + if (Array.isArray(data)) { + options.rawPayload = data; + } else if (typeof data === "object") { + options.rawPayload = [data]; + } else { + options.rawPayload = data; + } + + if (device.type === "mutable") { + const amount = await getDeviceDataAmount(device.id); + if (amount >= LIMIT_DATA_ON_MUTABLE) { + throw new Error(`The device has reached the limit of ${LIMIT_DATA_ON_MUTABLE} data registers`); + } + } + + let items: any = data; + items = await applyPayloadEncoder(device, items, options); + items = await runPayloadParser(device, items, options); + items = await z.array(zDeviceDataCreate).parseAsync([items].flat()); + + await emitToLiveInspector(device, { title: "Raw Payload", content: data }, options.liveInspectorID); + + const group = generateResourceID().split("").reverse().join(""); + const now = new Date(); + + for (const item of items) { + item.group = item.group ?? item.serie ?? group; + item.time = item.time || now; + item.type = typeof item.value; + item.created_at = now; + delete item.serie; + } + + await invokeDatabaseFunction("addDeviceData", device.id, device.type, items); + + await triggerActions(device.id, items); + await addStatistic({ input: items.length }); + await editDevice(device.id, { updated_at: now, last_input: now }); + + return `${items.length} items added`; +}; + +/** + * Adds data into a device by device ID. + * @param {TGenericID} deviceID ID of the device who sent the data. + * @param {any} data Data to be inserted. + */ +export async function addDeviceData(deviceID: TGenericID, data: any) { + const device = await getDeviceInfo(deviceID); + return await addDeviceDataByDevice(device, data); +} + +/** + */ +export async function editDeviceData(deviceID: TGenericID, data: any[]) { + const device = await getDeviceInfo(deviceID); + if (device.type === "immutable") { + throw new Error("You cannot edit data on immutable device"); + } + + const payload = [data].flat(); + const amount = Array.isArray(payload) ? payload.length : 1; + if (amount > 25) { + throw new Error("You have exceeded the maximum number of 25 items in a single request"); + } + + for (let i = 0; i < payload.length; i++) { + const parsed: any = await zDeviceDataUpdate.parseAsync(payload[i]); + if ("value" in parsed) { + parsed.type = typeof parsed.value; + } + payload[i] = parsed; + } + + return await invokeDatabaseFunction("editDeviceData", deviceID, device.id, payload); +} + +/** + * Retrieves data from a device. + */ +export const getDeviceDataByDevice = async ( + device: IDevice, + query?: IDeviceDataQuery +): Promise => { + if (!query) { + query = {}; + } + + query = zDeviceDataQuery.parse(query) as IDeviceDataQuery; + + if (device.type === "immutable" && query.ids?.length) { + throw new Error("Filter using ID(s) is not supported on Immutable Storage Type"); + } + + if (query.query === "count") { + return await invokeDatabaseFunction("getDeviceDataCount", device.id, device.type, query); + } else if (query.query === "avg") { + await validateMonthRange(query); + return await invokeDatabaseFunction("getDeviceDataAvg", device.id, device.type, query); + } else if (query.query === "sum") { + await validateMonthRange(query); + return await invokeDatabaseFunction("getDeviceDataSum", device.id, device.type, query); + } else { + let response: any[] = []; + + if (!query.query || query.query === "defaultQ") { + response = await invokeDatabaseFunction("getDeviceDataDefaultQ", device.id, device.type, query); + } else if (query.query === "last_value") { + response = await invokeDatabaseFunction("getDeviceDataLastValue", device.id, device.type, query); + } else if (query.query === "last_location") { + response = await invokeDatabaseFunction("getDeviceDataLastLocation", device.id, device.type, query); + } else if (query.query === "last_item") { + response = await invokeDatabaseFunction("getDeviceDataLastItem", device.id, device.type, query); + } else if (query.query === "last_insert") { + response = await invokeDatabaseFunction("getDeviceDataLastInsert", device.id, device.type, query); + } else if (query.query === "first_value") { + response = await invokeDatabaseFunction("getDeviceDataFirstValue", device.id, device.type, query); + } else if (query.query === "first_location") { + response = await invokeDatabaseFunction("getDeviceDataFirstLocation", device.id, device.type, query); + } else if (query.query === "first_item") { + response = await invokeDatabaseFunction("getDeviceDataFirstItem", device.id, device.type, query); + } else if (query.query === "first_insert") { + response = await invokeDatabaseFunction("getDeviceDataFirstInsert", device.id, device.type, query); + } else if (query.query === "min") { + await validateMonthRange(query); + response = await invokeDatabaseFunction("getDeviceDataMin", device.id, device.type, query); + } else if (query.query === "max") { + await validateMonthRange(query); + response = await invokeDatabaseFunction("getDeviceDataMax", device.id, device.type, query); + } + + for (let i = 0; i < response.length; i++) { + response[i].device = device.id; + response[i].group = response[i].group || response[i].serie; + response[i] = removeNullValues(response[i]); + if (!query.details) { + delete response[i].created_at; + } + } + + let items: any = await z.array(zDeviceData).parseAsync(response); + items = await z.array(zDeviceData).parseAsync(items); + + await addStatistic({ output: items.length }); + + return items; + } +}; + +/** + */ +export const getDeviceData = async (id: TGenericID, query?: IDeviceDataQuery) => { + const device = await getDeviceInfo(id); + return await getDeviceDataByDevice(device, query); +}; + +/** + * Deletes data from a device. + * @returns {number} The amount of data deleted from the device. + */ +export async function deleteDeviceData(id: TGenericID, query?: IDeviceDataQuery): Promise { + const device = await getDeviceInfo(id); + if (device.type === "immutable") { + throw new Error("Data in immutable devices cannot be deleted"); + } + + const data = await getDeviceData(id, query); + + if (!Array.isArray(data)) { + throw new Error("Invalid query"); + } + + const dataIDs = (data as IDeviceData[]).map((x) => x.id); + + await invokeDatabaseFunction("deleteDeviceData", id, device.id, dataIDs); + + return data.length; +} + +async function validateMonthRange(query: IDeviceDataQuery) { + if (!query.start_date) { + throw new Error("start_date field is required"); + } + + const startDate = query.start_date as Date; + const endDate = query.end_date || new Date(); + const diff = DateTime.fromJSDate(endDate).diff(DateTime.fromJSDate(startDate), "months").toObject(); + const value = diff.months || 0; + if (value > MAXIMUM_MONTH_RANGE) { + throw new Error(`The maximum range for ${query.query} is 1 month between start_end and end_date`); + } +} diff --git a/packages/tcore-api/src/Services/File.ts b/packages/tcore-api/src/Services/File.ts new file mode 100644 index 00000000..2af1159b --- /dev/null +++ b/packages/tcore-api/src/Services/File.ts @@ -0,0 +1,77 @@ +import fs from "fs/promises"; +import { WriteFileOptions } from "fs"; +import path from "path"; +import { getPluginSettingsFolder } from "./Settings"; + +/** + * Writes data to the file, replacing the file if it already exists. + * `data` can be a string or a buffer. + */ +export async function writeFile( + pluginID: string, + filename: string, + data: string, + options?: WriteFileOptions +): Promise { + const root = await getPluginSettingsFolder(pluginID); + const fullPath = path.join(root, filename); + await fs.writeFile(fullPath, data, options); +} + +/** + * Creates a new sub-folder in the plugins settings folder. + * This function will recursively create each folder in the path until the last one. + */ +export async function createFolder(pluginID: string, folderPath: string): Promise { + const root = await getPluginSettingsFolder(pluginID); + const fullPath = path.join(root, folderPath); + await fs.mkdir(fullPath, { recursive: true }); +} + +/** + * Deletes a file or folder. + */ +export async function deleteFileOrFolder(pluginID: string, folderPath: string): Promise { + const root = await getPluginSettingsFolder(pluginID); + const fullPath = path.join(root, folderPath); + await fs.unlink(fullPath); +} + +/** + * Reads the entire contents of a file. + */ +export async function readFile(pluginID: string, filename: string, options?: any): Promise { + const root = await getPluginSettingsFolder(pluginID); + const fullPath = path.join(root, filename); + const response = await fs.readFile(fullPath, options); + return response.toString(); +} + +/** + * Checks if a file exists. Returns `true` if it does, `false` if it doesn't. + */ +export async function doesFileOrFolderExist(pluginID: string, filename: string): Promise { + const root = await getPluginSettingsFolder(pluginID); + const fullPath = path.join(root, filename); + return await fs + .lstat(fullPath) + .then(() => true) + .catch(() => false); +} + +/** + * Gets the full path of a file via its filename. + */ +export async function getFileURI(pluginID: string, filename: string): Promise { + const root = await getPluginSettingsFolder(pluginID); + const fullPath = path.join(root, filename); + return fullPath; +} + +/** + * Gets the full path of the plugin settings folder. + */ +export async function getFolderURI(pluginID: string): Promise { + const root = await getPluginSettingsFolder(pluginID); + return root; +} diff --git a/packages/tcore-api/src/Services/FilePicker.ts b/packages/tcore-api/src/Services/FilePicker.ts new file mode 100644 index 00000000..db83f1f6 --- /dev/null +++ b/packages/tcore-api/src/Services/FilePicker.ts @@ -0,0 +1,104 @@ +import fs from "fs"; +import path from "path"; +import os from "os"; +import si from "systeminformation"; + +interface ITransformedFiles { + name: string; + path: string; + is_folder: boolean; + children: ITransformedFiles[]; +} + +function sortFiles(a, b): number { + if (a.is_folder && !b.is_folder) { + return -1; + } + if (!a.is_folder && b.is_folder) { + return 1; + } + return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); +} + +/** + */ +async function isDirectory(file: string): Promise { + try { + const stat = await fs.promises.lstat(file); + const isDir = stat.isDirectory(); + return isDir; + } catch (ex) { + return false; + } +} + +/** + */ +async function transformFiles(root: string, paths: string[]): Promise { + const transformed: any[] = []; + + for (const item of paths) { + transformed.push({ + name: item, + path: root ? path.join(root, item) : item, + is_folder: await isDirectory(root ? path.join(root, item) : item), + children: [], + }); + } + + transformed.sort(sortFiles); + + return transformed; +} + +/** + */ +async function getFileSystems() { + if (os.platform() === "win32") { + const mounts = await si.fsSize(); + return mounts.map((x) => x.mount); + } else { + return ["/"]; + } +} + +/** + */ +export async function getFileList(filter: string): Promise { + const fileSystems = await transformFiles("", await getFileSystems()); + + const filterArray = filter.split(/\/|\\/g).filter((x) => x); + if (os.platform() !== "win32") { + filterArray.unshift("/"); + } + + const isExistingFile = filter && fs.existsSync(filter) && !(await isDirectory(filter)); + if (isExistingFile) { + filterArray.pop(); + } + + const accumulated: string[] = []; + let last: any = fileSystems; + + for (const folder of filterArray) { + accumulated.push(folder); + let accumulatedString = accumulated.join(path.sep).replace(/\/\//g, "/"); + if (accumulatedString.endsWith(":")) { + accumulatedString += path.sep; + } + + const subFolders = await fs.promises.readdir(accumulatedString).catch(() => []); + + last = last?.find((x) => x.name === folder); + if (last) { + last.children = await transformFiles(accumulatedString, subFolders).catch(() => []); + last = last.children; + } + } + + if (fileSystems.length === 1) { + return fileSystems[0].children; + } + + return fileSystems; +} diff --git a/packages/tcore-api/src/Services/Hardware.ts b/packages/tcore-api/src/Services/Hardware.ts new file mode 100644 index 00000000..0b50683e --- /dev/null +++ b/packages/tcore-api/src/Services/Hardware.ts @@ -0,0 +1,198 @@ +import os from "os"; +import si from "systeminformation"; +import { IComputerUsage, INetworkInfo } from "@tago-io/tcore-sdk/types"; +import { getCpuPercentage } from "../Helpers/CPU"; + +/** + * Formats the bytes into a more readable format. + */ +function formatBytes(bytes: number) { + if (bytes === 0) { + return "0 B"; + } + + const k = 1024; + const dm = 2; + const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`; +} + +/** + * Retrieves all the local ips of this computer. + */ +export function getLocalIPs() { + const interfaces = os.networkInterfaces(); + const addresses: string[] = []; + + for (const name of Object.keys(interfaces)) { + for (const tmp of interfaces[name] || []) { + const { address, family, internal } = tmp; + if (family === "IPv4" && !internal) { + addresses.push(address); + } + } + } + + return addresses; +} + +/** + * Retrieves the main information of the OS. + */ +export async function getOSInfo() { + const system = await si.system(); + const osInfo = await si.osInfo(); + const osPlatform = os.platform(); + + let version = osInfo.release; + let code = ""; + let hardware = ""; + let name = osInfo.distro || osInfo.codename; + const arch = osInfo.arch; + + // debian + // redhat + // ubuntu + // amazon linux + // fedora + // alpine + // bsd (not linux) + + switch (osPlatform) { + case "win32": + code = "windows"; + break; + case "linux": + code = "linux"; + break; + case "darwin": + code = "mac"; + break; + default: + code = "other"; + break; + } + + if (system.raspberry) { + hardware = "raspberry-pi"; + version = system.raspberry?.type; + name = "Raspberry Pi"; + } + + return { + arch, + name, + code, + hardware, + version, + }; +} + +/** + * Retrieves the RAM usage. + */ +export async function getRAMUsage(): Promise { + const data = await si.mem(); + return { + description: `${formatBytes(data.used)} / ${formatBytes(data.total)}`, + title: "RAM usage", + total: data.total, + type: "memory", + used: data.used, + }; +} + +/** + * Retrieves the swap memory usage. + */ +export async function getSwapUsage(): Promise { + const data = await si.mem(); + if (data.swaptotal && data.swapused) { + return { + description: `${formatBytes(data.swapused)} / ${formatBytes(data.swaptotal)}`, + title: "Swap Memory usage", + total: data.swaptotal, + type: "memory", + used: data.swapused, + }; + } +} + +/** + * Retrieves the main network information. + */ +export async function getNetworkInfo(): Promise { + const stats = await si.networkStats(); + const interfaces = await si.networkInterfaces(); + const interfacesWithIP = [...interfaces.filter((x) => x.ip4 && x.ip4 !== "127.0.0.1")]; + + return interfacesWithIP.map((x) => { + const stat = stats.find((x) => x.iface === x.iface); + return { + bytesDropped: stat?.tx_dropped || 0, + bytesTransferred: stat?.tx_bytes || 0, + ip: x.ip4, + name: x.ifaceName, + }; + }); +} + +/** + * Retrieves the CPU usage. + */ +export async function getCPUUsage(): Promise { + const data = await Promise.all([si.cpu(), getCpuPercentage()]); + const percentage = Math.round(data[1]); + + return { + description: `${percentage}%`, + detail: `${data[0].manufacturer} ${data[0].brand}`, + title: `CPU usage`, + total: 100, + type: "cpu", + used: percentage, + }; +} + +/** + * Retrieves disk usages across all mounts. + */ +export async function getDiskUsages(): Promise { + const data = await si.fsSize(); + return data.map((x, i) => ({ + description: `${formatBytes(x.used)} / ${formatBytes(x.size)}`, + detail: x.mount, + title: `Disk ${i + 1}`, + total: x.size, + type: "disk", + used: x.used, + })); +} + +/** + * Retrieves the battery usage. + */ +export async function getBatteryUsage(): Promise { + const battery = await si.battery(); + if (battery && battery.percent > 0) { + return { + description: battery.isCharging ? "Charging" : "", + detail: `${battery.percent}%`, + title: "Battery", + total: 100, + type: "battery", + used: battery.percent, + }; + } +} + +/** + * Retrieves all the computer usage statistics. + * Some statistics may not be available on all systems. + */ +export async function getComputerUsage(): Promise { + const usages = await Promise.all([getRAMUsage(), getSwapUsage(), getBatteryUsage(), getCPUUsage(), getDiskUsages()]); + const filtered = usages.flat().filter((x) => x) as IComputerUsage[]; + return filtered; +} diff --git a/packages/tcore-api/src/Services/LiveInspector.ts b/packages/tcore-api/src/Services/LiveInspector.ts new file mode 100644 index 00000000..b023f94a --- /dev/null +++ b/packages/tcore-api/src/Services/LiveInspector.ts @@ -0,0 +1,73 @@ +import { + ESocketRoom, + IDevice, + ILiveInspectorMessageCreate, + TGenericID, + TLiveInspectorConnectionID, +} from "@tago-io/tcore-sdk/types"; +import { DateTime } from "luxon"; +import { nanoid } from "nanoid"; +import { plugins } from "../Plugins/Host"; +import { io } from "../Socket/SocketServer"; +import { getDeviceInfo } from "./Device"; + +/** + */ +export function canLiveInspectorBeActivated(device: IDevice): boolean { + const { inspected_at } = device; + if (inspected_at && DateTime.fromJSDate(new Date(inspected_at)) >= DateTime.utc().minus({ minute: 1 })) { + return true; + } + return false; +} + +/** + * Gets the live inspector connection ID based on the time when the device was last inspected. + * If the last inspection date was too long ago, a `null` connection id will be returned. + */ +export function getLiveInspectorID(device: IDevice): TLiveInspectorConnectionID { + return canLiveInspectorBeActivated(device) ? nanoid(10) : null; +} + +/** + * Emits one or more messages to the live inspector of a device. + */ +export const emitToLiveInspector = async ( + device: IDevice, + msg: ILiveInspectorMessageCreate | ILiveInspectorMessageCreate[], + liveInspectorID?: TLiveInspectorConnectionID +) => { + const connectionID = liveInspectorID || getLiveInspectorID(device); + if (!connectionID) { + // no one is watching the device's live inspector + return; + } + + const data = [msg].flat().map((x, i) => ({ + connection_id: connectionID, + content: typeof x.content === "object" ? JSON.stringify(x.content) : x.content, + device_id: device.id, + timestamp: new Date(Date.now() + i), + title: x.title, + })); + + io?.to(`${ESocketRoom.deviceInspection}#${device.id}`).emit("device::inspection", data); +}; + +/** + * Emits one or more messages to the live inspector of a via a plugin call. + * This should only be used actual plugins, and not the api. + */ +export async function emitToLiveInspectorViaPlugin( + pluginID: TGenericID, + deviceID: TGenericID, + msg: ILiveInspectorMessageCreate | ILiveInspectorMessageCreate[], + liveInspectorID?: TLiveInspectorConnectionID +) { + const device = await getDeviceInfo(deviceID); + const pluginName = plugins.get(pluginID)?.tcoreName; + if (pluginName && canLiveInspectorBeActivated(device)) { + const data = [msg].flat().map((x) => ({ ...x, title: `[Plugin ${pluginName}] ${x.title}` })); + emitToLiveInspector(device, data, liveInspectorID); + } +} diff --git a/packages/tcore-api/src/Services/Logs.ts b/packages/tcore-api/src/Services/Logs.ts new file mode 100644 index 00000000..0a30bf56 --- /dev/null +++ b/packages/tcore-api/src/Services/Logs.ts @@ -0,0 +1,33 @@ +import { logBuffer } from "../Helpers/log"; +import { plugins } from "../Plugins/Host"; + +/** + * Retrieves all the logs of a single channel. + */ +export async function getLogChannelInfo(id: string) { + const logs = logBuffer.get(id) || []; + return logs; +} + +/** + * Lists all the log channels. + */ +export async function getLogChannelList(): Promise { + const channels = [ + { + name: "Application", + channel: "api", + plugin: false, + }, + ]; + + for (const plugin of plugins.values()) { + channels.push({ + name: `Plugin:${plugin.tcoreName}`, + channel: `plugin:${plugin.id}`, + plugin: true, + }); + } + + return channels; +} diff --git a/packages/tcore-api/src/Services/PayloadParserCodeExecution.ts b/packages/tcore-api/src/Services/PayloadParserCodeExecution.ts new file mode 100644 index 00000000..f0501c61 --- /dev/null +++ b/packages/tcore-api/src/Services/PayloadParserCodeExecution.ts @@ -0,0 +1,71 @@ +import fs from "fs"; +import vm from "vm"; +import { IDevice, IDeviceAddDataOptions } from "@tago-io/tcore-sdk/types"; +import dayjs from "dayjs"; +import customParseFormat from "dayjs/plugin/customParseFormat"; +import advancedFormat from "dayjs/plugin/advancedFormat"; +import utc from "dayjs/plugin/utc"; +import timezone from "dayjs/plugin/timezone"; +import { logError } from "../Helpers/log"; +import { emitToLiveInspector } from "./LiveInspector"; + +dayjs.extend(utc); +dayjs.extend(timezone); +dayjs.extend(customParseFormat); +dayjs.extend(advancedFormat); + +/** + * Runs a payload parser script. + * @param {IDevice} device Device object who sent the data. + * @param {any} data The data to be passed to the parser' script. + */ +export const runPayloadParser = async ( + device: IDevice, + payload?: any, + options?: IDeviceAddDataOptions +): Promise => { + try { + if (!device.payload_parser) { + return payload; + } + + const fileData = await fs.promises.readFile(device.payload_parser, "utf8").catch(() => null); + if (!fileData) { + throw new Error(`Payload parser file is empty or doesn't exist`); + } + + const context = vm.createContext({ + payload, + raw_payload: options?.rawPayload, + dayjs, + device: { + id: device.id, + tags: device.tags, + params: [], + }, + console: { + log: (...args: any[]) => onLog(device, args, options), + debug: (...args: any[]) => onLog(device, args, options), + error: (...args: any[]) => onLog(device, args, options), + }, + }); + + const code = `Promise.resolve().then(async () => { await (async function() { ${fileData} }()); return payload; })`; + const script = new vm.Script(code); + const response = await script.runInContext(context); + + emitToLiveInspector(device, { title: "Result of payload parser", content: response }, options?.liveInspectorID); + + return response; + } catch (error: any) { + logError("api", `Unexpected error while running payload parser (${device.id}): ${error.message}`); + emitToLiveInspector(device, { title: "Error on payload parser", content: error.message }, options?.liveInspectorID); + return payload; + } +}; + +/** + */ +function onLog(device: IDevice, args: any, options?: IDeviceAddDataOptions) { + emitToLiveInspector(device, { title: "Log from payload parser", content: args[0] }, options?.liveInspectorID); +} diff --git a/packages/tcore-api/src/Services/Plugins.ts b/packages/tcore-api/src/Services/Plugins.ts new file mode 100644 index 00000000..ce8393a4 --- /dev/null +++ b/packages/tcore-api/src/Services/Plugins.ts @@ -0,0 +1,292 @@ +import fs from "fs"; +import path from "path"; +import { IPlugin, TGenericID, TPluginType, IPluginList } from "@tago-io/tcore-sdk/types"; +import { flattenConfigFields } from "@tago-io/tcore-shared"; +import Module from "../Plugins/Module/Module"; +import { BUILT_IN_PLUGINS, plugins } from "../Plugins/Host"; +import Plugin from "../Plugins/Plugin/Plugin"; +import { getMainSettings, getPluginSettings } from "./Settings"; + +/** + * Lists all the plugins that are loaded. + */ +export async function getLoadedPluginList(): Promise { + const result: IPluginList = []; + + for (const plugin of plugins.values()) { + const buttonModules = [...plugin.modules.values()].filter( + (x) => x.setup.type === "sidebar-button" || x.setup.type === "navbar-button" + ); + const error = !!plugin.error || [...plugin.modules.values()].some((x) => x.error); + + const buttons = buttonModules.map((x: any) => ({ + type: x.setup.type, + color: x.setup.color, + icon: x.setup.icon, + name: x.setup.name, + route: x.setup.route, + })); + + const object = { + buttons: buttons.length > 0 ? buttons : [], + error: error, + hidden: plugin.package.tcore.hidden || false, + id: plugin.id, + name: plugin.tcoreName, + state: plugin.state, + version: plugin.version, + }; + + result.push(object); + } + + return result; +} + +/** + */ +export async function listPluginFolders(): Promise { + const settings = await getMainSettings(); + const root = settings.plugin_folder || ""; + const folders = await fs.promises.readdir(root); + const plugins: string[] = []; + + for (const folder of folders) { + const fullPath = path.join(root, folder); + const hasPackage = await Plugin.getPackageAsync(fullPath).catch(() => null); + if (hasPackage) { + plugins.push(fullPath); + } + } + + for (const item of BUILT_IN_PLUGINS) { + if (!plugins.includes(item)) { + plugins.unshift(item); + } + } + + return plugins; +} + +/** + * Lists all the plugins directly from the folder. + */ +export async function getPluginList(): Promise { + const folders = await listPluginFolders(); + const result: any = []; + + for (const folder of folders) { + const pkg = await Plugin.getPackageAsync(folder).catch(() => null); + if (pkg) { + const object = { + folder, + id: Plugin.generatePluginID(pkg.name), + manifest: pkg.tcore, + name: pkg.tcore?.name || "", + version: pkg.version, + }; + + result.push(object); + } + } + + return result; +} + +export async function showModuleMessage(pluginID: string, moduleID: string, message?: any) { + const plugin = plugins.get(pluginID); + const module = plugin?.modules.get(moduleID); + if (module) { + module.message = message; + module.emitSocketUpdate(); + } +} + +export async function hideModuleMessage(pluginID: string, moduleID: string) { + const plugin = plugins.get(pluginID); + const module = plugin?.modules.get(moduleID); + if (module) { + module.message = null; + module.emitSocketUpdate(); + } +} + +/** + * Starts/restarts a plugin module. + */ +export async function startPluginModule(pluginID: string, moduleID: string) { + const plugin = plugins.get(pluginID); + const module = plugin?.modules.get(moduleID); + if (module) { + await module.start(); + } +} + +/** + * Stops a plugin module. + */ +export async function stopPluginModule(pluginID: string, moduleID: string) { + const plugin = plugins.get(pluginID); + const module = plugin?.modules.get(moduleID); + if (module) { + await module.stop(); + } +} + +/** + * Enables a plugin (if not enabled yet). + */ +export async function enablePlugin(pluginID: string) { + const plugin = plugins.get(pluginID); + if (plugin) { + await plugin.enable(); + } +} + +/** + * Disables a plugin (if not disabled yet). + */ +export async function disablePlugin(pluginID: string) { + const plugin = plugins.get(pluginID); + if (plugin) { + await plugin.disable(); + } +} + +/** + * Starts a plugin (if not started yet). + */ +export async function startPlugin(pluginID: string) { + const plugin = plugins.get(pluginID); + if (plugin) { + await plugin.start(); + } +} + +/** + * Stops a plugin (if not Stopped yet). + */ +export async function stopPlugin(pluginID: string) { + const plugin = plugins.get(pluginID); + if (plugin) { + await plugin.stop(); + } +} + +/** + * Retrieves all the information of a single plugin. + */ +export async function getPluginInfo(id: TGenericID): Promise { + const plugin = plugins.get(id); + if (!plugin) { + throw new Error("Invalid Plugin ID"); + } + + const settings = await getPluginSettings(id); + + const modules = [...plugin.modules.values()].map((module) => { + const moduleSettings = settings?.modules?.find((y) => y.id === module.setup.id); + const moduleValues = moduleSettings?.values || {}; + + const moduleFields = flattenConfigFields(module.setup.configs || []); + for (const field of moduleFields) { + // we override the default value of the config field to use the last + // inserted value or the actual default from the module configuration + if ("field" in field) { + if (moduleValues[field.field] !== null && moduleValues[field.field] !== undefined) { + (field as any).defaultValue = moduleValues[field.field]; + } else if ((field as any).defaultValue === undefined || (field as any).defaultValue === null) { + (field as any).defaultValue = ""; + } + } + } + + return { + ...module.setup, + error: module.error, + message: module.message, + state: module.state, + }; + }); + + const data: IPlugin = { + id: plugin.id, + error: plugin.error, + short_description: plugin.description, + full_description: plugin.fullDescription || "", + name: plugin.tcoreName, + state: plugin.state, + slug: plugin.packageName, + publisher: { + name: plugin.publisher, + }, + modules, + version: plugin.version, + }; + + return data; +} + +/** + * Finds and returns the main database plugin. + */ +export async function getMainDatabaseModule(): Promise { + const settings = await getMainSettings(); + const pluginID = String(settings.database_plugin).split(":")?.[0]; + const moduleID = String(settings.database_plugin).split(":")?.[1]; + + if (pluginID && moduleID) { + // main database plugin was informed, we'll use that + const plugin = plugins.get(pluginID); + if (plugin) { + const module = plugin.modules.get(moduleID); + if (module) { + return module; + } + } + } + + const modules = getModuleList("database"); + return modules.find((x) => x.state === "started"); +} + +/** + * TODO + */ +export async function getMainFilesystemModule(): Promise { + const settings = await getMainSettings(); + const pluginID = String(settings.filesystem_plugin).split(":")?.[0]; + const moduleID = String(settings.filesystem_plugin).split(":")?.[1]; + + if (pluginID && moduleID) { + // main database plugin was informed, we'll use that + const plugin = plugins.get(pluginID); + if (plugin) { + const module = plugin.modules.get(moduleID); + if (module) { + return module; + } + } + } + + const modules = getModuleList("filesystem"); + return modules.find((x) => x.state === "started"); +} + +/** + * Lists modules from the plugins. + * @param {TPluginType} type - optional type to filter the modules. + */ +export function getModuleList(type?: TPluginType | null): Module[] { + const result: Module[] = []; + + for (const plugin of plugins.values()) { + for (const module of plugin.modules.values()) { + if (!type || module.setup.type === type) { + result.push(module); + } + } + } + + return result; +} diff --git a/packages/tcore-api/src/Services/PluginsStorage.ts b/packages/tcore-api/src/Services/PluginsStorage.ts new file mode 100644 index 00000000..0c8f5356 --- /dev/null +++ b/packages/tcore-api/src/Services/PluginsStorage.ts @@ -0,0 +1,37 @@ +import { zPluginStorageItemSet } from "@tago-io/tcore-sdk/types"; +import { invokeDatabaseFunction } from "../Plugins/invokeDatabaseFunction"; + +/** + * Retrieves a storage item of a plugin. + */ +export async function getPluginStorageItem(pluginID: string, key: string) { + const response = await invokeDatabaseFunction("getPluginStorageItem", pluginID, key); + return response; +} + +/** + * Creates/edits a storage item of a plugin. + */ +export async function setPluginStorageItem(pluginID: string, key: string, value: any) { + const parsed = await zPluginStorageItemSet.parseAsync({ key, value }); + await invokeDatabaseFunction("setPluginStorageItem", pluginID, parsed); +} + +/** + * Deletes a storage item of a plugin. + */ +export async function deletePluginStorageItem(pluginID: string, key: string) { + await invokeDatabaseFunction("deletePluginStorageItem", pluginID, key); +} + +/** + * Retrieves all storage items. + */ +export async function getAllPluginStorageItems(pluginID: string): Promise { + const response = await invokeDatabaseFunction("getAllPluginStorageItems", pluginID); + for (const item of response) { + delete item.created_at; + delete item.type; + } + return response; +} diff --git a/packages/tcore-api/src/Services/Settings.ts b/packages/tcore-api/src/Services/Settings.ts new file mode 100644 index 00000000..00b1b171 --- /dev/null +++ b/packages/tcore-api/src/Services/Settings.ts @@ -0,0 +1,139 @@ +import path from "path"; +import fs from "fs"; +import os from "os"; +import { IPluginSettings, IPluginSettingsModule, ISettings } from "@tago-io/tcore-sdk/types"; +import { plugins } from "../Plugins/Host"; +import { loadYml, saveYml } from "../Helpers/Yaml"; + +const folderName = os.platform() === "win32" ? "TCore" : ".tcore"; + +/** + * Retrieves the main settings folder. + */ +export async function getMainSettingsFolder(): Promise { + const folder = path.join(os.homedir(), folderName); + await fs.promises.mkdir(folder, { recursive: true }); + return folder; +} + +/** + * Retrieves the settings folder of a plugin. + */ +export async function getPluginSettingsFolder(pluginID: string): Promise { + const folder = path.join(os.homedir(), folderName, "PluginFiles", pluginID || ""); + await fs.promises.mkdir(folder, { recursive: true }); + return folder; +} + +/** + * Retrieves the plugins folder. + */ +export async function getPluginsFolder(): Promise { + const folder = path.join(os.homedir(), folderName, "Plugins"); + await fs.promises.mkdir(folder, { recursive: true }); + return folder; +} + +/** + * Retrieves the main settings of the application. + */ +export async function getMainSettings(): Promise { + const folder = await getMainSettingsFolder(); + const data = await loadYml(path.join(folder, "tcore.yml")); + + const filesystem_plugin = process.env.TCORE_FILESYSTEM_PLUGIN || data.filesystem_plugin || ""; + const database_plugin = process.env.TCORE_DATABASE_PLUGIN || data.database_plugin || ""; + const settings_folder = process.env.TCORE_SETTINGS_FOLDER || folder; + const plugin_folder = process.env.TCORE_PLUGIN_FOLDER || data.plugin_folder || (await getPluginsFolder()); + const port = process.env.TCORE_PORT || data.port || "8888"; + const plugin_auto_update_enable = data.plugin_auto_update_enable || false; + const plugin_auto_update_check_time = data.plugin_auto_update_check_time || ""; + const plugin_auto_update_last_checked_time = data.plugin_auto_update_last_checked_time || ""; + + const settings: ISettings = { + filesystem_plugin, + database_plugin, + plugin_auto_update_check_time, + plugin_auto_update_enable, + plugin_auto_update_last_checked_time, + plugin_folder, + port, + settings_folder, + }; + + if (!fs.existsSync(settings.plugin_folder)) { + fs.promises.mkdir(settings.plugin_folder, { recursive: true }); + } + + return settings; +} + +/** + * Saves the main settings of the application into the settings file. + */ +export async function setMainSettings(data: ISettings): Promise { + const folder = await getMainSettingsFolder(); + await saveYml(data, path.join(folder, "tcore.yml")); +} + +/** + * Retrieves the settings of a plugin. + */ +export async function getPluginSettings(id: string): Promise { + const root = await getPluginSettingsFolder(id); + const filePath = path.join(root, "settings.yml"); + const fileData = (await loadYml(filePath, {})) as IPluginSettings; + + if (Array.isArray(fileData)) { + // structure before 0.3.2 + return { + disabled: false, + modules: fileData.map((x) => ({ id: x.setupID, values: x.configValues })), + }; + } + + return fileData; +} + +/** + * Saves the main settings of the application into the settings file. + */ +export async function setPluginModulesSettings(id: string, values: any) { + const root = await getPluginSettingsFolder(id); + const filePath = path.join(root, "settings.yml"); + const plugin = plugins.get(id); + const modules: IPluginSettingsModule[] = []; + + for (const item of values) { + const group = modules.find((x) => x.id === item.moduleID); + if (group) { + group.values[item.field] = item.value; + } else { + modules.push({ id: item.moduleID, values: { [item.field]: item.value } }); + } + } + + const data: IPluginSettings = { + disabled: plugin?.state === "disabled", + modules, + }; + + await saveYml(data, filePath); +} + +/** + */ +export async function setPluginSettings(id: string, settings: IPluginSettings) { + const root = await getPluginSettingsFolder(id); + const filePath = path.join(root, "settings.yml"); + await saveYml(settings, filePath); +} + +/** + * Saves the main settings of the application into the settings file. + */ +export async function setPluginDisabledSettings(id: string, disabled: boolean) { + const data = await getPluginSettings(id); + data.disabled = disabled; + await setPluginSettings(id, data); +} diff --git a/packages/tcore-api/src/Services/Statistic.ts b/packages/tcore-api/src/Services/Statistic.ts new file mode 100644 index 00000000..1a73dfcc --- /dev/null +++ b/packages/tcore-api/src/Services/Statistic.ts @@ -0,0 +1,27 @@ +import { ESocketRoom, IStatistic, IStatisticCreate, zStatistic } from "@tago-io/tcore-sdk/types"; +import { DateTime } from "luxon"; +import { z } from "zod"; +import { io } from "../Socket/SocketServer"; +import { invokeDatabaseFunction } from "../Plugins/invokeDatabaseFunction"; + +/** + * Retrieves the summary information. + */ +export const addStatistic = async (data: IStatisticCreate): Promise => { + const time = DateTime.utc().startOf("minute").toJSDate().toISOString(); + data.input = data.input || 0; + data.output = data.output || 0; + + await invokeDatabaseFunction("addStatistic", time, data); + + io?.to(ESocketRoom.statistic).emit(`statistic::hourly`, { time, ...data }); +}; + +/** + * Retrieves all statistics from the last hour. + */ +export async function getHourlyStatistics(): Promise { + const statistics = await invokeDatabaseFunction("getHourlyStatistics"); + const parsed = z.array(zStatistic).parseAsync(statistics); + return parsed; +} diff --git a/packages/tcore-api/src/Services/Summary.ts b/packages/tcore-api/src/Services/Summary.ts new file mode 100644 index 00000000..43392732 --- /dev/null +++ b/packages/tcore-api/src/Services/Summary.ts @@ -0,0 +1,11 @@ +import { ISummary, zSummary } from "@tago-io/tcore-sdk/types"; +import { invokeDatabaseFunction } from "../Plugins/invokeDatabaseFunction"; + +/** + * Retrieves the summary information. + */ +export async function getSummary(): Promise { + const response = await invokeDatabaseFunction("getSummary"); + const parsed = await zSummary.parseAsync(response); + return parsed; +} diff --git a/packages/tcore-api/src/Services/System.ts b/packages/tcore-api/src/Services/System.ts new file mode 100644 index 00000000..7f7fc955 --- /dev/null +++ b/packages/tcore-api/src/Services/System.ts @@ -0,0 +1,16 @@ +// @ts-ignore +import data from "../../../../data.json"; + +/** + */ +function getSystemSlug() { + return data.slug; +} + +/** + */ +function getSystemName() { + return data.name; +} + +export { getSystemSlug, getSystemName }; diff --git a/packages/tcore-api/src/Services/Tag.ts b/packages/tcore-api/src/Services/Tag.ts new file mode 100644 index 00000000..e4c88d6b --- /dev/null +++ b/packages/tcore-api/src/Services/Tag.ts @@ -0,0 +1,11 @@ +import { z } from "zod"; +import { invokeDatabaseFunction } from "../Plugins/invokeDatabaseFunction"; + +/** + * Retrieves all the tag keys of a resource type. + */ +export async function getTagKeys(table: string) { + const response = await invokeDatabaseFunction("getTagKeys", table); + const parsed = await z.array(z.string()).parseAsync(response); + return parsed; +} diff --git a/packages/tcore-api/src/Socket/SocketServer.ts b/packages/tcore-api/src/Socket/SocketServer.ts new file mode 100644 index 00000000..f155e6f4 --- /dev/null +++ b/packages/tcore-api/src/Socket/SocketServer.ts @@ -0,0 +1,71 @@ +import { Server } from "http"; +import { Server as SocketServer } from "socket.io"; +import { ESocketResource, ESocketRoom, TGenericID } from "@tago-io/tcore-sdk/types"; +import { editDevice } from "../Services/Device"; + +/** + * Socket server instance. + */ +export let io: SocketServer; + +/** + * Sets up the socket server. + */ +export async function setupSocketServer(httpServer: Server) { + io = new SocketServer(httpServer, { cors: { origin: "*" } }); + + io.on("connection", (socket) => { + socket.on("attach", (resourceType: ESocketResource, resourceID?: TGenericID) => { + if (resourceType === ESocketResource.pluginInstall) { + socket.join(ESocketRoom.pluginInstall); + } + if (resourceType === ESocketResource.log) { + socket.join(ESocketRoom.log); + } + if (resourceType === ESocketResource.statistic) { + socket.join(ESocketRoom.statistic); + } + if (resourceType === ESocketResource.analysis) { + socket.join(ESocketRoom.analysis); + } + if (resourceType === ESocketResource.module && resourceID) { + socket.join(`${ESocketRoom.module}#${resourceID}`); + } + if (resourceType === ESocketResource.plugin && resourceID) { + socket.join(`${ESocketRoom.plugin}#${resourceID}`); + } + if (resourceType === ESocketResource.deviceInspection && resourceID) { + editDevice(resourceID, { inspected_at: new Date() }).catch(() => false); + socket.join(`${ESocketRoom.deviceInspection}#${resourceID}`); + } + }); + + socket.on("detach", (resourceType: ESocketResource, resourceID?: string) => { + if (resourceType === ESocketResource.pluginInstall) { + socket.leave(ESocketRoom.pluginInstall); + } + if (resourceType === ESocketResource.log) { + socket.leave(ESocketRoom.log); + } + if (resourceType === ESocketResource.statistic) { + socket.leave(ESocketRoom.statistic); + } + if (resourceType === ESocketResource.analysis) { + socket.leave(ESocketRoom.analysis); + } + if (resourceType === ESocketResource.module) { + socket.leave(`${ESocketRoom.module}#${resourceID}`); + } + if (resourceType === ESocketResource.deviceInspection) { + socket.leave(`${ESocketRoom.deviceInspection}#${resourceID}`); + } + if (resourceType === ESocketResource.plugin) { + socket.leave(`${ESocketRoom.plugin}#${resourceID}`); + } + }); + + socket.emit("ready"); + }); + + io.on("error", console.error); +} diff --git a/packages/tcore-api/src/index.ts b/packages/tcore-api/src/index.ts new file mode 100644 index 00000000..1da6a4b5 --- /dev/null +++ b/packages/tcore-api/src/index.ts @@ -0,0 +1,24 @@ +import { installPlugin } from "./Plugins/Install"; +import { uninstallPlugin, uninstallPluginByFolder } from "./Plugins/Uninstall"; +import { startServer } from "./server"; +import { log, logError } from "./Helpers/log"; +import { getPlatformAndArch } from "./Helpers/Platform"; +import { downloadFile } from "./Helpers/Download"; +import Plugin from "./Plugins/Plugin/Plugin"; +export * from "./Helpers/Tar/Tar"; +export * from "./Helpers/Zip"; +export * from "./Services/Plugins"; +export * from "./Services/Settings"; +export * from "./Services/System"; + +export { + downloadFile, + getPlatformAndArch, + installPlugin, + log, + logError, + Plugin, + startServer, + uninstallPlugin, + uninstallPluginByFolder, +}; diff --git a/packages/tcore-api/src/server.ts b/packages/tcore-api/src/server.ts new file mode 100644 index 00000000..25252537 --- /dev/null +++ b/packages/tcore-api/src/server.ts @@ -0,0 +1,184 @@ +import { createServer } from "http"; +import path from "path"; +import express from "express"; +import boxen from "boxen"; +import cors from "cors"; +import chalk from "chalk"; +import ora from "ora"; +import compression from "compression"; +import method_override from "method-override"; +import { startAllPlugins } from "./Plugins/Host"; +import SystemController from "./Controllers/System"; +import DeviceController from "./Controllers/Device/Device"; +import ActionController from "./Controllers/Action"; +import AnalysisController from "./Controllers/Analysis"; +import SummaryController from "./Controllers/Summary"; +import PluginsController, { resolvePluginImage, resolvePluginImage2 } from "./Controllers/Plugins"; +import FileController from "./Controllers/File"; +import LogsController from "./Controllers/Logs"; +import DeviceDataController from "./Controllers/DeviceData/DeviceData"; +import TagController from "./Controllers/Tag"; +import SettingsController from "./Controllers/Settings"; +import StatisticController from "./Controllers/Statistic"; +import { getMainSettings } from "./Services/Settings"; +import HardwareController from "./Controllers/Hardware"; +import { setupSocketServer } from "./Socket/SocketServer"; +import { shutdown } from "./Helpers/shutdown"; +import { getLocalIPs } from "./Services/Hardware"; +import { getModuleList } from "./Services/Plugins"; +import { startCallbackInterval } from "./Plugins/Worker/Worker"; +import { getSystemName } from "./Services/System"; + +const app = express(); +const httpServer = createServer(app); +const consolePath = path.join(__dirname, "../../tcore-console/build"); + +/** + * Sets up express and its configuration. + */ +async function setupExpress() { + app.use(cors()); + app.disable("x-powered-by"); + app.use(compression()); + app.use(express.json({ limit: "10mb" })); + app.use(express.urlencoded({ extended: true })); + app.use(express.text({ limit: "5mb" })); + + app.use(method_override("X-HTTP-Method")); // Microsoft + app.use(method_override("X-HTTP-Method-Override")); // Google/GData + app.use(method_override("X-Method-Override")); // IBM + app.use(method_override("_method")); // QueryString +} + +/** + * Sets up the routes of express. + */ +async function setupExpressRoutes() { + SystemController(app); + DeviceController(app); + SummaryController(app); + ActionController(app); + AnalysisController(app); + PluginsController(app); + FileController(app); + LogsController(app); + DeviceDataController(app); + SettingsController(app); + StatisticController(app); + HardwareController(app); + TagController(app); + + app.use("/console", express.static(consolePath, { index: "./index.html" })); + + app.get("/", (req, res) => { + res.redirect("/console"); + }); + + app.get("/console/*", (req, res) => { + res.header("content-type", "text/html"); + res.sendFile(`${consolePath}/index.html`); + }); + + app.get("/images/:plugin/:type/:identifier?", resolvePluginImage); + app.get("/images2/:plugin/*", resolvePluginImage2); + + app.options("*", (req, res) => { + const defaultHeaders = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS", + "Access-Control-Allow-Headers": + "Content-Type, Cache-Control, Pragma, X-Requested-With, Authorization, Account-Token, Device-Token, Token", + "Content-Type": "application/json; charset=utf-8", + }; + // const headers = { ...defaultHeaders }; + res.set(defaultHeaders); + }); + + app.use((err, req, res, next) => { + if (err.stack.match(/body-parser/)) { + res.status(400).send({ + status: false, + result: { + request_error: err.message, + request_body: err.body, + server_response: "Malformed request syntax", + }, + }); + } else { + next(); + } + }); +} + +/** + * Sets up the plugin pages. + */ +async function setupPluginPages() { + const modules: any = getModuleList("page"); + + for (const module of modules) { + const fullPath = module.plugin.folder; + const assetsPath = path.join(fullPath, module.setup.assets); + const fullRoute = `/pages/${module.setup.route.substring(1)}`; + app.use(fullRoute, express.static(assetsPath, { index: "./index.html" })); + } + + app.use((req, res) => { + res.status(404); + res.send({ status: false, message: "Route Not Found" }); + }); +} + +/** + * Starts listening on the application port. + */ +async function listenOnApplicationPort() { + const settings = await getMainSettings(); + const port = Number(settings.port); + + const systemName = getSystemName(); + + httpServer + .listen(port, () => { + const lines = [`${systemName} is ready!`, "", `- Local: http://localhost:${port}`]; + + const netAddresses = getLocalIPs(); + if (netAddresses[0]) { + lines.push(`- On your network: http://${netAddresses[0]}:${port}`); + } + + console.log(""); + console.log(chalk.green(boxen(lines.join("\n"), { padding: 1 }))); + console.log(""); + }) + .on("error", () => { + ora(chalk.redBright(`Could not start ${systemName} on port ${port}`)).fail(); + process.exit(1); + }); +} + +/** + * Starts the application. + */ +export async function startServer() { + ora(`Started ${getSystemName()}`).succeed(); + + startCallbackInterval(); + + await setupExpress(); + await setupExpressRoutes(); + await setupSocketServer(httpServer); + + await startAllPlugins(); + await setupPluginPages(); + + await listenOnApplicationPort(); + + process.on("SIGTERM", () => shutdown(httpServer)); + process.on("SIGINT", () => shutdown(httpServer)); +} + +const watchMode = process.argv.some((x) => x.includes("ts-node")); +if (watchMode) { + startServer(); +} diff --git a/packages/tcore-api/tsconfig.json b/packages/tcore-api/tsconfig.json new file mode 100644 index 00000000..ab92c025 --- /dev/null +++ b/packages/tcore-api/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020", "dom"], + "allowJs": true, + "sourceMap": false, + "outDir": "./build", + "strict": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": false, + "rootDir": "./src", + "baseUrl": ".", + "skipLibCheck": true, + "declaration": true + }, + "exclude": [ + "node_module", + "jest.config.js", + ".eslintrc.js" + ], + "include": ["src/**/*"], + "ts-node": { + "transpileOnly": true + } +} diff --git a/packages/tcore-cli/.eslintignore b/packages/tcore-cli/.eslintignore new file mode 100644 index 00000000..92edd6f1 --- /dev/null +++ b/packages/tcore-cli/.eslintignore @@ -0,0 +1,11 @@ +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +__build__* +.eslintrc.js +jest.config.js +esbuild/* +build diff --git a/packages/tcore-cli/.eslintrc.js b/packages/tcore-cli/.eslintrc.js new file mode 100644 index 00000000..bd9cbd16 --- /dev/null +++ b/packages/tcore-cli/.eslintrc.js @@ -0,0 +1,30 @@ +module.exports = { + env: { + node: true, + jest: true + }, + root: true, + parserOptions: { + ecmaVersion: 6, + sourceType: "module", + ecmaFeatures: { + jsx: false, + }, + tsconfigRootDir: __dirname, + project: ["./tsconfig.json"], + }, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "import", "jest"], + ignorePatterns: ['.eslintrc.js', 'jest.config.js'], + extends: [ + "plugin:prettier/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript", + "eslint:recommended" + ], + rules: { + "import/order": 1 + }, +}; diff --git a/packages/tcore-cli/.prettierrc b/packages/tcore-cli/.prettierrc new file mode 100644 index 00000000..3ae934c4 --- /dev/null +++ b/packages/tcore-cli/.prettierrc @@ -0,0 +1,11 @@ +{ + "trailingComma": "es5", + "printWidth": 120, + "useTabs": false, + "tabWidth": 2, + "semi": true, + "singleQuote": false, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/packages/tcore-cli/jest.config.js b/packages/tcore-cli/jest.config.js new file mode 100644 index 00000000..27c177bb --- /dev/null +++ b/packages/tcore-cli/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + roots: ['/src'], + testRegex: '(/__tests__/.*|(\\.|/)test)\\.ts?$' +}; diff --git a/packages/tcore-cli/package.json b/packages/tcore-cli/package.json new file mode 100644 index 00000000..b306c40b --- /dev/null +++ b/packages/tcore-cli/package.json @@ -0,0 +1,47 @@ +{ + "name": "@tago-io/tcore-cli", + "version": "0.3.3", + "private": true, + "description": "TCore CLI", + "author": "Tago LLC", + "homepage": "https://github.com/tago-io/tcore", + "repository": { + "type": "git", + "url": "https://github.com/tago-io/tcore" + }, + "scripts": { + "clean": "rm -rf node_modules; rm -rf package-lock.json", + "build": "rm -rf ./build; tsc", + "tsc:watch": "tsc --watch --preserveWatchOutput" + }, + "dependencies": { + "tail": "2.2.4", + "@tago-io/tcore-api": "*", + "@tago-io/tcore-sdk": "*", + "chalk": "4.1.2", + "commander": "^9.0.0", + "esbuild": "^0.14.23", + "ora": "5.4.1" + }, + "devDependencies": { + "@types/jest": "27.0.1", + "@types/node": "16.7.1", + "@types/semver": "7.3.9", + "@typescript-eslint/eslint-plugin": "4.29.3", + "@typescript-eslint/parser": "4.29.3", + "chalk": "4.1.2", + "eslint": "7.32.0", + "eslint-config-prettier": "8.3.0", + "eslint-import-resolver-typescript": "2.4.0", + "eslint-plugin-import": "2.24.1", + "eslint-plugin-jest": "24.4.0", + "eslint-plugin-prettier": "3.4.1", + "jest": "27.0.6", + "ora": "5.4.1", + "pm2": "^5.2.0", + "prettier": "2.3.2", + "socket.io-client": "4.4.1", + "ts-jest": "27.0.5", + "typescript": "4.3.5" + } +} diff --git a/packages/tcore-cli/src/Commands/Logs.ts b/packages/tcore-cli/src/Commands/Logs.ts new file mode 100644 index 00000000..d8dfbff0 --- /dev/null +++ b/packages/tcore-cli/src/Commands/Logs.ts @@ -0,0 +1,40 @@ +import fs from "fs"; +import path from "path"; +import * as API from "@tago-io/tcore-api"; +import chalk from "chalk"; +import { Tail } from "tail"; +import { pm2Connect, pm2Disconnect, pm2GetApp } from "../Helpers/PM2"; +import { log, oraLog } from "../Helpers/Log"; + +/** + */ +export async function showLogs() { + try { + await pm2Connect(); + + const app = await pm2GetApp(); + if (!app) { + log(`TCore Server is ${chalk.yellow("not running in the background")}`); + return; + } + + const settingsPath = await API.getMainSettingsFolder(); + const pm2LogPath = path.join(settingsPath, "tcore.log"); + + const data = fs.readFileSync(pm2LogPath, { encoding: "utf-8" }); + console.log(data); + + const tail = new Tail(pm2LogPath); + + tail.on("line", (data: any) => { + console.log(data); + }); + + tail.on("error", () => { + oraLog(`Something went wrong while fetching the logs`).fail(); + process.exit(1); + }); + } finally { + await pm2Disconnect(); + } +} diff --git a/packages/tcore-cli/src/Commands/Restart.ts b/packages/tcore-cli/src/Commands/Restart.ts new file mode 100644 index 00000000..9215cd1a --- /dev/null +++ b/packages/tcore-cli/src/Commands/Restart.ts @@ -0,0 +1,38 @@ +import path from "path"; +import fs from "fs"; +import * as API from "@tago-io/tcore-api"; +import chalk from "chalk"; +import { pm2Connect, pm2Disconnect, pm2Restart, pm2GetApp } from "../Helpers/PM2"; +import { log } from "../Helpers/Log"; + +/** + * Restarts the server if it is started. + * If the server is not started, this command will no do anything. + */ +export async function restart() { + try { + await pm2Connect(); + + const app = await pm2GetApp(); + if (app) { + const settingsPath = await API.getMainSettingsFolder(); + const pm2LogPath = path.join(settingsPath, "tcore.log"); + await fs.promises.unlink(pm2LogPath).catch(() => null); + + await pm2Restart(); + + const newApp = await pm2GetApp(); + if (newApp) { + log(`${API.getSystemName()} Server was ${chalk.green("successfully restarted")} with PID`, newApp.pid); + } else { + log(`${API.getSystemName()} Server ${chalk.redBright("could not be started")}.`); + log(`You can check the logs by running ${chalk.cyan("tcore logs")}`); + } + } else { + log(`${API.getSystemName()} Server is ${chalk.redBright("not started")}`); + log(`To start ${API.getSystemName()}, run ${chalk.cyan("tcore start")}`); + } + } finally { + await pm2Disconnect(); + } +} diff --git a/packages/tcore-cli/src/Commands/Start.ts b/packages/tcore-cli/src/Commands/Start.ts new file mode 100644 index 00000000..477fdc21 --- /dev/null +++ b/packages/tcore-cli/src/Commands/Start.ts @@ -0,0 +1,107 @@ +import path from "path"; +import fs from "fs"; +import { StartOptions } from "pm2"; +import * as API from "@tago-io/tcore-api"; +import chalk from "chalk"; +import { pm2Connect, pm2Delete, pm2Disconnect, pm2GetApp, pm2Start, PM2_APP_NAME } from "../Helpers/PM2"; +import { log } from "../Helpers/Log"; + +/** + * Options of CLI. + */ +interface IStartOptions { + daemon: boolean; + databasePlugin: string; + force: boolean; + port: string; + pluginsFolder: string; + settingsFolder: string; +} + +function getEnv(opts: IStartOptions) { + const env: any = {}; + if (opts.port) env.TCORE_PORT = opts.port; + if (opts.daemon) env.TCORE_DAEMON = String(opts.daemon); + if (opts.pluginsFolder) env.TCORE_PLUGIN_FOLDER = opts.pluginsFolder; + if (opts.settingsFolder) env.TCORE_SETTINGS_FOLDER = opts.settingsFolder; + if (opts.databasePlugin) env.TCORE_DATABASE_PLUGIN = opts.databasePlugin; + return env; +} + +/** + * Starts the server. + * + * If `opts.daemon` is set to `true`, then the server will be started + * in the pm2 daemon, otherwise it will be started in the foreground. + */ +export async function start(opts: IStartOptions) { + if (!opts.daemon) { + // no daemon, meaning we need to run in foreground + const env = getEnv(opts); + for (const key in env) { + process.env[key] = env[key]; + } + await API.startServer(); + } else { + // run with daemon + await startWithDaemon(opts); + } +} + +/** + * Start the server with a daemon (background process). + */ +async function startWithDaemon(opts: IStartOptions) { + try { + const systemName = API.getSystemName(); + const exeName = path.basename(process.execPath); + + await pm2Connect(); + + const app = await pm2GetApp(); + if (app?.pm2_env?.status === "online") { + log(`${systemName} Server is ${chalk.yellow("already started")} with PID`, app.pid); + + if (!opts.force) { + // the app is already online + log(`To restart ${systemName}, run ${chalk.cyan(`${exeName} restart`)}`); + return; + } else { + log(`Flag ${chalk.yellow("--force")} detected, restarting down ${systemName} Server`); + await pm2Delete(); + } + } else { + log("${systemName} Server is stopped, starting it..."); + await pm2Delete().catch(() => null); + } + + const settingsPath = await API.getMainSettingsFolder(); + const pm2LogPath = path.join(settingsPath, "tcore.log"); + + await fs.promises.unlink(pm2LogPath).catch(() => null); + + const startOptions: StartOptions = { + script: path.join(__dirname, "../Scripts/StartPM2Dev.js"), + name: PM2_APP_NAME, + output: pm2LogPath, + error: pm2LogPath, + env: getEnv(opts), + }; + + await pm2Start(startOptions); + + const newApp = await pm2GetApp(); + if (newApp?.pm2_env?.status === "online") { + // successfully started new process + log(`${systemName} Server successfully ${chalk.green("started")} with PID`, newApp.pid); + } else { + // for some reason pm2 could not start the script + log(`${systemName} Server ${chalk.redBright("could not be started")}.`); + log(`You can check the logs by running ${chalk.cyan(`${exeName} logs`)}`); + } + } catch (ex: any) { + log(chalk.redBright(`Unexpected error: ${ex?.message || ex}`)); + } finally { + await pm2Disconnect(); + } +} diff --git a/packages/tcore-cli/src/Commands/Status.ts b/packages/tcore-cli/src/Commands/Status.ts new file mode 100644 index 00000000..b30e19a2 --- /dev/null +++ b/packages/tcore-cli/src/Commands/Status.ts @@ -0,0 +1,24 @@ +import chalk from "chalk"; +import * as API from "@tago-io/tcore-api"; +import { log } from "../Helpers/Log"; +import { pm2Connect, pm2Disconnect, pm2GetApp } from "../Helpers/PM2"; + +/** + * Prints the status of the server (started/stopped). + */ +export async function status() { + try { + await pm2Connect(); + + const app = await pm2GetApp(); + if (app?.pm2_env?.status === "online") { + log(`${API.getSystemName()} Server is ${chalk.green("started")} with PID`, app.pid); + } else { + log(`${API.getSystemName()} Server is ${chalk.redBright("stopped")}`); + } + } catch (ex: any) { + log(chalk.redBright(`Unexpected error: ${ex?.message || ex}`)); + } finally { + await pm2Disconnect(); + } +} diff --git a/packages/tcore-cli/src/Commands/Stop.ts b/packages/tcore-cli/src/Commands/Stop.ts new file mode 100644 index 00000000..56f9ec03 --- /dev/null +++ b/packages/tcore-cli/src/Commands/Stop.ts @@ -0,0 +1,30 @@ +import chalk from "chalk"; +import * as API from "@tago-io/tcore-api"; +import { pm2Connect, pm2Delete, pm2Disconnect, pm2GetApp } from "../Helpers/PM2"; +import { log } from "../Helpers/Log"; + +/** + * Stops the server if it is running through the PM2 daemon, and then logs the + * status of the server. + * + * If the server is running in foreground this command will do nothing. + * If the server is already stopped, this command will do nothing. + */ +export async function stop() { + try { + await pm2Connect(); + + const app = await pm2GetApp(); + if (app) { + log(`${API.getSystemName()} Server is started, stopping it...`); + } + + await pm2Delete(); + + log(chalk.green("Successfully stopped")); + } catch (ex) { + log(`${API.getSystemName()} Server is`, chalk.yellow("already stopped")); + } finally { + await pm2Disconnect(); + } +} diff --git a/packages/tcore-cli/src/Helpers/Log.ts b/packages/tcore-cli/src/Helpers/Log.ts new file mode 100644 index 00000000..64c1f00b --- /dev/null +++ b/packages/tcore-cli/src/Helpers/Log.ts @@ -0,0 +1,14 @@ +import chalk from "chalk"; +import ora from "ora"; +import * as API from "@tago-io/tcore-api"; + +export function log(...args: any[]) { + console.log(chalk.cyan(`[${API.getSystemName()} CLI]`), ...args); +} + +export function oraLog(text: string) { + const spinner = ora(text); + spinner.prefixText = chalk.cyan(`[${API.getSystemName()} CLI]`); + spinner.start(); + return spinner; +} diff --git a/packages/tcore-cli/src/Helpers/PM2.ts b/packages/tcore-cli/src/Helpers/PM2.ts new file mode 100644 index 00000000..0797ee95 --- /dev/null +++ b/packages/tcore-cli/src/Helpers/PM2.ts @@ -0,0 +1,87 @@ +import pm2, { ProcessDescription, StartOptions } from "pm2"; +import * as API from "@tago-io/tcore-api"; + +export const PM2_APP_NAME = API.getSystemName(); + +/** + */ +export function pm2Connect() { + return new Promise((resolve, reject) => { + pm2.connect((err) => { + if (err) { + return reject(err); + } + resolve(); + }); + }); +} + +/** + */ +export function pm2Start(options: StartOptions) { + return new Promise((resolve, reject) => { + pm2.start(options, (err) => { + if (err) { + return reject(err); + } + resolve(); + }); + }); +} + +/** + */ +export async function pm2GetApp(): Promise { + const name = PM2_APP_NAME; + const apps = await pm2List(); + const app = apps.find((x) => x.name === name); + return app || null; +} + +/** + */ +export function pm2List() { + return new Promise((resolve, reject) => { + pm2.list((err, list) => { + if (err) { + return reject(err); + } + resolve(Array.isArray(list) ? list : []); + }); + }); +} + +/** + */ +export function pm2Disconnect() { + return new Promise((resolve) => { + pm2.disconnect(); + resolve(); + }); +} + +/** + */ +export function pm2Restart() { + return new Promise((resolve, reject) => { + pm2.restart(PM2_APP_NAME, (err) => { + if (err) { + reject(err); + } + resolve(); + }); + }); +} + +/** + */ +export function pm2Delete() { + return new Promise((resolve, reject) => { + pm2.delete(PM2_APP_NAME, (err) => { + if (err) { + return reject(err); + } + resolve(); + }); + }); +} diff --git a/packages/tcore-cli/src/PluginCLI.ts b/packages/tcore-cli/src/PluginCLI.ts new file mode 100644 index 00000000..2bdbc133 --- /dev/null +++ b/packages/tcore-cli/src/PluginCLI.ts @@ -0,0 +1,57 @@ +import path from "path"; +import * as API from "@tago-io/tcore-api"; +import { Command } from "commander"; + +/** + * Try to require a module and returns null if the module doesn't exist. + */ +function tryRequire(folder: string) { + try { + return require(folder); + } catch (ex) { + return null; + } +} + +/** + * Adds plugin commands to the CLI. + */ +async function addPluginCommands(program: Command) { + const list = await API.getPluginList(); + + for (const item of list) { + const commands = item.manifest?.cli_commands || []; + + for (const pluginCommand of commands) { + if (!pluginCommand || !pluginCommand.name) { + continue; + } + + const commandName = pluginCommand.name; + const commandDesc = pluginCommand.description || ""; + const commandOpts = pluginCommand.options || []; + const commandArgs = pluginCommand.arguments || []; + const cliCommand = program.command(commandName).description(commandDesc); + + for (const arg of commandArgs) { + cliCommand.argument(arg.flags, arg.description); + } + for (const option of commandOpts) { + cliCommand.option(option.flags, option.description); + } + + const folder = path.join(item.folder, pluginCommand.file); + const func = tryRequire(folder); + + if (func) { + if (typeof func === "function") { + cliCommand.action(func); + } else if (typeof func.default === "function") { + cliCommand.action(func.default); + } + } + } + } +} + +export { addPluginCommands }; diff --git a/packages/tcore-cli/src/Scripts/StartPM2Dev.ts b/packages/tcore-cli/src/Scripts/StartPM2Dev.ts new file mode 100644 index 00000000..cb06c5d9 --- /dev/null +++ b/packages/tcore-cli/src/Scripts/StartPM2Dev.ts @@ -0,0 +1,10 @@ +// This script is the PM2 Start script. +// It just starts the api server. + +// ! This script only runs in dev mode with Node.js +// ? It will not run in production mode with PKG. To understand more about how +// ? it works, check the `Start.ts` file + +import * as API from "@tago-io/tcore-api"; + +API.startServer(); diff --git a/packages/tcore-cli/src/index.ts b/packages/tcore-cli/src/index.ts new file mode 100644 index 00000000..0a302c8a --- /dev/null +++ b/packages/tcore-cli/src/index.ts @@ -0,0 +1,63 @@ +import { Command } from "commander"; +import * as API from "@tago-io/tcore-api"; +// @ts-ignore +import pkg from "../package.json"; +import { showLogs } from "./Commands/Logs"; +import { start } from "./Commands/Start"; +import { status } from "./Commands/Status"; +import { stop } from "./Commands/Stop"; +import { restart } from "./Commands/Restart"; +import { addPluginCommands } from "./PluginCLI"; + +/** + */ +function getBaseProgram() { + const program = new Command(); + + const systemName = API.getSystemName(); + + program.name("tcore").description(`${systemName} CLI v${pkg.version}`).version(pkg.version, "-v, --version"); + + program + .command("start") + .description(`Start ${systemName} Server`) + .option("-f, --force", `Restarts ${systemName} if already started`) + .option("--port ", `Set the port for the ${systemName} server`) + .option("--database-plugin ", "Set the database plugin") + .option("--plugins-folder ", "Set the folder to store Plugins") + .option("--settings-folder ", "Set the folder to store Settings") + .option("--no-daemon", `Run ${systemName} in the foreground without a daemon`) + .action(start); + + program.command("restart").description(`Restart ${systemName} Server`).action(restart); + + program.command("stop").description(`Stop the ${systemName} Server`).action(stop); + + program.command("status").description(`Get the ${systemName} Server's status`).action(status); + + program.command("logs").description(`Shows the ${systemName} Server logs in real time`).action(showLogs); + + return program; +} + +/** + */ +async function startCLI() { + const program = getBaseProgram(); + + await addPluginCommands(program); + + if (process.env.TCORE_DAEMON) { + // Workaround: + // sometimes pm2 replaces the first argument with the bin file path of the cli. + // This happens at random and I couldn't figure out why, so in daemon mode we + // manually override the argv to start tcore. + // (only command that can run in daemon is start) + const argv = [process.argv[0], process.argv[1], "start", "--no-daemon"]; + program.parse(argv); + } else { + program.parse(process.argv); + } +} + +startCLI(); diff --git a/packages/tcore-cli/tsconfig.json b/packages/tcore-cli/tsconfig.json new file mode 100644 index 00000000..e05a0b2d --- /dev/null +++ b/packages/tcore-cli/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020", "dom"], + "allowJs": true, + "sourceMap": false, + "outDir": "./build", + "strict": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": false, + "rootDir": "./src", + "baseUrl": ".", + "skipLibCheck": true, + }, + "exclude": [ + "node_module", + "jest.config.js", + ".eslintrc.js" + ], + "include": ["src/**/*"], + "ts-node": { + "transpileOnly": true + } +} diff --git a/packages/tcore-console/.eslintignore b/packages/tcore-console/.eslintignore new file mode 100644 index 00000000..99eb831a --- /dev/null +++ b/packages/tcore-console/.eslintignore @@ -0,0 +1,4 @@ +esbuild/* +build/* +build-tsc/* +*.js diff --git a/packages/tcore-console/.eslintrc.js b/packages/tcore-console/.eslintrc.js new file mode 100644 index 00000000..51a67dd4 --- /dev/null +++ b/packages/tcore-console/.eslintrc.js @@ -0,0 +1,110 @@ +module.exports = { + root: true, + env: { + 'browser': true, + 'commonjs': true, + 'es6': true, + 'jest/globals': true, + }, + extends: [ + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:import/errors', + 'plugin:import/warnings', + 'plugin:import/typescript', + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:prettier/recommended', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaversion: 6, + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + settings: { + react: { + version: 'detect', + }, + }, + plugins: ['@typescript-eslint', 'import', 'jest', 'react', 'react-hooks'], + ignorePatterns: [ + "*.js", + "utils/*", + "build*", + "index.d.ts", + ], + rules: { + 'no-async-promise-executor': 0, + 'arrow-parens': 0, + 'camelcase': 0, + 'class-methods-use-this': 0, + 'import/order': 'error', + 'import/extensions': 0, + 'import/imports-first': 0, + 'import/newline-after-import': 0, + 'import/no-cycle': 0, + 'import/no-extraneous-dependencies': 0, + 'import/no-unresolved': [ + 'error', + { + ignore: [ + '@', + ], + }, + ], + '@typescript-eslint/no-explicit-any': 'off', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + 'no-console': 'error', + 'no-template-curly-in-string': 'warn', + 'curly': 'error', + 'array-callback-return': ['error', { allowImplicit: true }], + 'block-scoped-var': 'error', + 'default-case': ['error', { commentPattern: '^no default$' }], + 'dot-notation': 'error', + 'eqeqeq': ['error', 'smart'], + 'guard-for-in': 'error', + 'no-alert': 'warn', + 'no-caller': 'error', + 'no-empty-function': 'warn', + 'no-eval': 'error', + 'no-floating-decimal': 'error', + 'no-implied-eval': 'error', + 'no-labels': ['error', { allowLoop: false, allowSwitch: false }], + 'no-lone-blocks': 'error', + 'no-loop-func': 'error', + '@typescript-eslint/no-shadow': 'error', + 'id-denylist': [ + 'error', + 'any', + 'Number', + 'number', + 'String', + 'string', + 'Boolean', + 'boolean', + 'Undefined', + 'undefined', + ], + 'react/prop-types': 0, + "react/jsx-uses-react": "off", // new JSX Transformation + "react/react-in-jsx-scope": "off", // new JSX Transformation + "react/display-name": "off", + }, + overrides: [ + // Let TypeScript do its own checks for no-undef, see FAQ. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/FAQ.md + { + files: ['*.tsx', '*.ts'], + rules: { + 'no-undef': 'off', + } + } + ] +}; diff --git a/packages/tcore-console/.prettierrc b/packages/tcore-console/.prettierrc new file mode 100644 index 00000000..f3a28ce1 --- /dev/null +++ b/packages/tcore-console/.prettierrc @@ -0,0 +1,12 @@ +{ + "trailingComma": "es5", + "printWidth": 100, + "useTabs": false, + "tabWidth": 2, + "semi": true, + "singleQuote": false, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf", + "max-line-length": [true, { "limit": 100 }] +} diff --git a/packages/tcore-console/assets/icons/apple.svg b/packages/tcore-console/assets/icons/apple.svg new file mode 100644 index 00000000..230bc0c8 --- /dev/null +++ b/packages/tcore-console/assets/icons/apple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/ban.svg b/packages/tcore-console/assets/icons/ban.svg new file mode 100644 index 00000000..716ce003 --- /dev/null +++ b/packages/tcore-console/assets/icons/ban.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/bars.svg b/packages/tcore-console/assets/icons/bars.svg new file mode 100644 index 00000000..e0b17bb2 --- /dev/null +++ b/packages/tcore-console/assets/icons/bars.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/battery-full.svg b/packages/tcore-console/assets/icons/battery-full.svg new file mode 100644 index 00000000..722109d0 --- /dev/null +++ b/packages/tcore-console/assets/icons/battery-full.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/bolt.svg b/packages/tcore-console/assets/icons/bolt.svg new file mode 100644 index 00000000..4ecf0146 --- /dev/null +++ b/packages/tcore-console/assets/icons/bolt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/brush.svg b/packages/tcore-console/assets/icons/brush.svg new file mode 100644 index 00000000..9b312d4c --- /dev/null +++ b/packages/tcore-console/assets/icons/brush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/bucket.svg b/packages/tcore-console/assets/icons/bucket.svg new file mode 100644 index 00000000..b0f37c10 --- /dev/null +++ b/packages/tcore-console/assets/icons/bucket.svg @@ -0,0 +1 @@ + diff --git a/packages/tcore-console/assets/icons/bullhorn.svg b/packages/tcore-console/assets/icons/bullhorn.svg new file mode 100644 index 00000000..7e9eb2e0 --- /dev/null +++ b/packages/tcore-console/assets/icons/bullhorn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/caret-down.svg b/packages/tcore-console/assets/icons/caret-down.svg new file mode 100644 index 00000000..bf855706 --- /dev/null +++ b/packages/tcore-console/assets/icons/caret-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/caret-right.svg b/packages/tcore-console/assets/icons/caret-right.svg new file mode 100644 index 00000000..6a5233a4 --- /dev/null +++ b/packages/tcore-console/assets/icons/caret-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/caret-up.svg b/packages/tcore-console/assets/icons/caret-up.svg new file mode 100644 index 00000000..526e8c28 --- /dev/null +++ b/packages/tcore-console/assets/icons/caret-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/certificate.svg b/packages/tcore-console/assets/icons/certificate.svg new file mode 100644 index 00000000..a02c60ae --- /dev/null +++ b/packages/tcore-console/assets/icons/certificate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/check.svg b/packages/tcore-console/assets/icons/check.svg new file mode 100644 index 00000000..d98354cf --- /dev/null +++ b/packages/tcore-console/assets/icons/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/chevron-left.svg b/packages/tcore-console/assets/icons/chevron-left.svg new file mode 100644 index 00000000..6deba1a1 --- /dev/null +++ b/packages/tcore-console/assets/icons/chevron-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/chevron-right.svg b/packages/tcore-console/assets/icons/chevron-right.svg new file mode 100644 index 00000000..a4347ebd --- /dev/null +++ b/packages/tcore-console/assets/icons/chevron-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/circle.svg b/packages/tcore-console/assets/icons/circle.svg new file mode 100644 index 00000000..0bac0611 --- /dev/null +++ b/packages/tcore-console/assets/icons/circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/clock.svg b/packages/tcore-console/assets/icons/clock.svg new file mode 100644 index 00000000..b7f11e0c --- /dev/null +++ b/packages/tcore-console/assets/icons/clock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/cloud.svg b/packages/tcore-console/assets/icons/cloud.svg new file mode 100644 index 00000000..b07047df --- /dev/null +++ b/packages/tcore-console/assets/icons/cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/code.svg b/packages/tcore-console/assets/icons/code.svg new file mode 100644 index 00000000..dc7b8f73 --- /dev/null +++ b/packages/tcore-console/assets/icons/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/cog.svg b/packages/tcore-console/assets/icons/cog.svg new file mode 100644 index 00000000..17cc5c30 --- /dev/null +++ b/packages/tcore-console/assets/icons/cog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/comment-dots.svg b/packages/tcore-console/assets/icons/comment-dots.svg new file mode 100644 index 00000000..396e3ef7 --- /dev/null +++ b/packages/tcore-console/assets/icons/comment-dots.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/connector.svg b/packages/tcore-console/assets/icons/connector.svg new file mode 100644 index 00000000..ea02b638 --- /dev/null +++ b/packages/tcore-console/assets/icons/connector.svg @@ -0,0 +1 @@ + diff --git a/packages/tcore-console/assets/icons/copy.svg b/packages/tcore-console/assets/icons/copy.svg new file mode 100644 index 00000000..0e96699e --- /dev/null +++ b/packages/tcore-console/assets/icons/copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/cube.svg b/packages/tcore-console/assets/icons/cube.svg new file mode 100644 index 00000000..6df1e28e --- /dev/null +++ b/packages/tcore-console/assets/icons/cube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/cubes.svg b/packages/tcore-console/assets/icons/cubes.svg new file mode 100644 index 00000000..0d54023e --- /dev/null +++ b/packages/tcore-console/assets/icons/cubes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/database-double.svg b/packages/tcore-console/assets/icons/database-double.svg new file mode 100644 index 00000000..d2e41d82 --- /dev/null +++ b/packages/tcore-console/assets/icons/database-double.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/tcore-console/assets/icons/database.svg b/packages/tcore-console/assets/icons/database.svg new file mode 100644 index 00000000..98aca187 --- /dev/null +++ b/packages/tcore-console/assets/icons/database.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/desktop.svg b/packages/tcore-console/assets/icons/desktop.svg new file mode 100644 index 00000000..d21bac4a --- /dev/null +++ b/packages/tcore-console/assets/icons/desktop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/device-union.svg b/packages/tcore-console/assets/icons/device-union.svg new file mode 100644 index 00000000..4ec9ab16 --- /dev/null +++ b/packages/tcore-console/assets/icons/device-union.svg @@ -0,0 +1 @@ + diff --git a/packages/tcore-console/assets/icons/device.svg b/packages/tcore-console/assets/icons/device.svg new file mode 100644 index 00000000..664164a4 --- /dev/null +++ b/packages/tcore-console/assets/icons/device.svg @@ -0,0 +1 @@ + diff --git a/packages/tcore-console/assets/icons/dice-d20.svg b/packages/tcore-console/assets/icons/dice-d20.svg new file mode 100644 index 00000000..881efc7c --- /dev/null +++ b/packages/tcore-console/assets/icons/dice-d20.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/download.svg b/packages/tcore-console/assets/icons/download.svg new file mode 100644 index 00000000..935e5ee9 --- /dev/null +++ b/packages/tcore-console/assets/icons/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/ellipsis-v.svg b/packages/tcore-console/assets/icons/ellipsis-v.svg new file mode 100644 index 00000000..d2e1a36f --- /dev/null +++ b/packages/tcore-console/assets/icons/ellipsis-v.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/envelope.svg b/packages/tcore-console/assets/icons/envelope.svg new file mode 100644 index 00000000..2da8a009 --- /dev/null +++ b/packages/tcore-console/assets/icons/envelope.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/exclamation-circle.svg b/packages/tcore-console/assets/icons/exclamation-circle.svg new file mode 100644 index 00000000..fdbcac7c --- /dev/null +++ b/packages/tcore-console/assets/icons/exclamation-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/exclamation-triangle.svg b/packages/tcore-console/assets/icons/exclamation-triangle.svg new file mode 100644 index 00000000..f8d6ed83 --- /dev/null +++ b/packages/tcore-console/assets/icons/exclamation-triangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/external-link-alt.svg b/packages/tcore-console/assets/icons/external-link-alt.svg new file mode 100644 index 00000000..b9b9522f --- /dev/null +++ b/packages/tcore-console/assets/icons/external-link-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/eye.svg b/packages/tcore-console/assets/icons/eye.svg new file mode 100644 index 00000000..2a67e34f --- /dev/null +++ b/packages/tcore-console/assets/icons/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/file-alt.svg b/packages/tcore-console/assets/icons/file-alt.svg new file mode 100644 index 00000000..10d2a2f2 --- /dev/null +++ b/packages/tcore-console/assets/icons/file-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/file-import.svg b/packages/tcore-console/assets/icons/file-import.svg new file mode 100644 index 00000000..a8eae91c --- /dev/null +++ b/packages/tcore-console/assets/icons/file-import.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/folder.svg b/packages/tcore-console/assets/icons/folder.svg new file mode 100644 index 00000000..f9058b08 --- /dev/null +++ b/packages/tcore-console/assets/icons/folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/github.svg b/packages/tcore-console/assets/icons/github.svg new file mode 100644 index 00000000..ec2bab20 --- /dev/null +++ b/packages/tcore-console/assets/icons/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/globe-americas.svg b/packages/tcore-console/assets/icons/globe-americas.svg new file mode 100644 index 00000000..642a234f --- /dev/null +++ b/packages/tcore-console/assets/icons/globe-americas.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/globe.svg b/packages/tcore-console/assets/icons/globe.svg new file mode 100644 index 00000000..8aede13b --- /dev/null +++ b/packages/tcore-console/assets/icons/globe.svg @@ -0,0 +1 @@ + diff --git a/packages/tcore-console/assets/icons/grip-horizontal.svg b/packages/tcore-console/assets/icons/grip-horizontal.svg new file mode 100644 index 00000000..3db99ef2 --- /dev/null +++ b/packages/tcore-console/assets/icons/grip-horizontal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/hashtag.svg b/packages/tcore-console/assets/icons/hashtag.svg new file mode 100644 index 00000000..7693834c --- /dev/null +++ b/packages/tcore-console/assets/icons/hashtag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/hdd.svg b/packages/tcore-console/assets/icons/hdd.svg new file mode 100644 index 00000000..af7c45d0 --- /dev/null +++ b/packages/tcore-console/assets/icons/hdd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/home.svg b/packages/tcore-console/assets/icons/home.svg new file mode 100644 index 00000000..5c9d6238 --- /dev/null +++ b/packages/tcore-console/assets/icons/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/image.svg b/packages/tcore-console/assets/icons/image.svg new file mode 100644 index 00000000..c32f68b8 --- /dev/null +++ b/packages/tcore-console/assets/icons/image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/io.svg b/packages/tcore-console/assets/icons/io.svg new file mode 100644 index 00000000..32efbc89 --- /dev/null +++ b/packages/tcore-console/assets/icons/io.svg @@ -0,0 +1 @@ + diff --git a/packages/tcore-console/assets/icons/key.svg b/packages/tcore-console/assets/icons/key.svg new file mode 100644 index 00000000..383c9ace --- /dev/null +++ b/packages/tcore-console/assets/icons/key.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/link.svg b/packages/tcore-console/assets/icons/link.svg new file mode 100644 index 00000000..f0fdbf4f --- /dev/null +++ b/packages/tcore-console/assets/icons/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/linux.svg b/packages/tcore-console/assets/icons/linux.svg new file mode 100644 index 00000000..8ae1ba96 --- /dev/null +++ b/packages/tcore-console/assets/icons/linux.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/list.svg b/packages/tcore-console/assets/icons/list.svg new file mode 100644 index 00000000..4a7f7b59 --- /dev/null +++ b/packages/tcore-console/assets/icons/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/lock.svg b/packages/tcore-console/assets/icons/lock.svg new file mode 100644 index 00000000..86a172a8 --- /dev/null +++ b/packages/tcore-console/assets/icons/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/markdown.svg b/packages/tcore-console/assets/icons/markdown.svg new file mode 100644 index 00000000..30af43c4 --- /dev/null +++ b/packages/tcore-console/assets/icons/markdown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/memory.svg b/packages/tcore-console/assets/icons/memory.svg new file mode 100644 index 00000000..311a65ea --- /dev/null +++ b/packages/tcore-console/assets/icons/memory.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/microchip.svg b/packages/tcore-console/assets/icons/microchip.svg new file mode 100644 index 00000000..0f5f58b0 --- /dev/null +++ b/packages/tcore-console/assets/icons/microchip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/minus.svg b/packages/tcore-console/assets/icons/minus.svg new file mode 100644 index 00000000..8a43aa3e --- /dev/null +++ b/packages/tcore-console/assets/icons/minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/mountain.svg b/packages/tcore-console/assets/icons/mountain.svg new file mode 100644 index 00000000..f17aca39 --- /dev/null +++ b/packages/tcore-console/assets/icons/mountain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/network-wired.svg b/packages/tcore-console/assets/icons/network-wired.svg new file mode 100644 index 00000000..95b67076 --- /dev/null +++ b/packages/tcore-console/assets/icons/network-wired.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/pause.svg b/packages/tcore-console/assets/icons/pause.svg new file mode 100644 index 00000000..74ac840f --- /dev/null +++ b/packages/tcore-console/assets/icons/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/pencil-alt.svg b/packages/tcore-console/assets/icons/pencil-alt.svg new file mode 100644 index 00000000..da9c0bb4 --- /dev/null +++ b/packages/tcore-console/assets/icons/pencil-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/play.svg b/packages/tcore-console/assets/icons/play.svg new file mode 100644 index 00000000..e817cc8e --- /dev/null +++ b/packages/tcore-console/assets/icons/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/plus-circle.svg b/packages/tcore-console/assets/icons/plus-circle.svg new file mode 100644 index 00000000..86d47f5f --- /dev/null +++ b/packages/tcore-console/assets/icons/plus-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/plus.svg b/packages/tcore-console/assets/icons/plus.svg new file mode 100644 index 00000000..74cf3932 --- /dev/null +++ b/packages/tcore-console/assets/icons/plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/puzzle-piece.svg b/packages/tcore-console/assets/icons/puzzle-piece.svg new file mode 100644 index 00000000..48ca1c23 --- /dev/null +++ b/packages/tcore-console/assets/icons/puzzle-piece.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/question-circle.svg b/packages/tcore-console/assets/icons/question-circle.svg new file mode 100644 index 00000000..48dd6067 --- /dev/null +++ b/packages/tcore-console/assets/icons/question-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/raspberry-pi.svg b/packages/tcore-console/assets/icons/raspberry-pi.svg new file mode 100644 index 00000000..ea4e276d --- /dev/null +++ b/packages/tcore-console/assets/icons/raspberry-pi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/redo.svg b/packages/tcore-console/assets/icons/redo.svg new file mode 100644 index 00000000..fd681119 --- /dev/null +++ b/packages/tcore-console/assets/icons/redo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/save.svg b/packages/tcore-console/assets/icons/save.svg new file mode 100644 index 00000000..ef9e6894 --- /dev/null +++ b/packages/tcore-console/assets/icons/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/scroll.svg b/packages/tcore-console/assets/icons/scroll.svg new file mode 100644 index 00000000..7581632c --- /dev/null +++ b/packages/tcore-console/assets/icons/scroll.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/search.svg b/packages/tcore-console/assets/icons/search.svg new file mode 100644 index 00000000..1309464b --- /dev/null +++ b/packages/tcore-console/assets/icons/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/shapes.svg b/packages/tcore-console/assets/icons/shapes.svg new file mode 100644 index 00000000..302e030a --- /dev/null +++ b/packages/tcore-console/assets/icons/shapes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/sign-out-alt.svg b/packages/tcore-console/assets/icons/sign-out-alt.svg new file mode 100644 index 00000000..591f2754 --- /dev/null +++ b/packages/tcore-console/assets/icons/sign-out-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/snowflake.svg b/packages/tcore-console/assets/icons/snowflake.svg new file mode 100644 index 00000000..818e4c1b --- /dev/null +++ b/packages/tcore-console/assets/icons/snowflake.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/spinner.svg b/packages/tcore-console/assets/icons/spinner.svg new file mode 100644 index 00000000..5e3d42ce --- /dev/null +++ b/packages/tcore-console/assets/icons/spinner.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/star.svg b/packages/tcore-console/assets/icons/star.svg new file mode 100644 index 00000000..0d33b8eb --- /dev/null +++ b/packages/tcore-console/assets/icons/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/stopwatch.svg b/packages/tcore-console/assets/icons/stopwatch.svg new file mode 100644 index 00000000..1a283c25 --- /dev/null +++ b/packages/tcore-console/assets/icons/stopwatch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/store.svg b/packages/tcore-console/assets/icons/store.svg new file mode 100644 index 00000000..9656e1ae --- /dev/null +++ b/packages/tcore-console/assets/icons/store.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/sync-alt.svg b/packages/tcore-console/assets/icons/sync-alt.svg new file mode 100644 index 00000000..fffda490 --- /dev/null +++ b/packages/tcore-console/assets/icons/sync-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/tag.svg b/packages/tcore-console/assets/icons/tag.svg new file mode 100644 index 00000000..1d5ba3db --- /dev/null +++ b/packages/tcore-console/assets/icons/tag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/tcore.svg b/packages/tcore-console/assets/icons/tcore.svg new file mode 100644 index 00000000..6b559f48 --- /dev/null +++ b/packages/tcore-console/assets/icons/tcore.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/temperature-high.svg b/packages/tcore-console/assets/icons/temperature-high.svg new file mode 100644 index 00000000..e12454e5 --- /dev/null +++ b/packages/tcore-console/assets/icons/temperature-high.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/th-large.svg b/packages/tcore-console/assets/icons/th-large.svg new file mode 100644 index 00000000..02bf0976 --- /dev/null +++ b/packages/tcore-console/assets/icons/th-large.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/times.svg b/packages/tcore-console/assets/icons/times.svg new file mode 100644 index 00000000..3d12ed1a --- /dev/null +++ b/packages/tcore-console/assets/icons/times.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/trash-alt.svg b/packages/tcore-console/assets/icons/trash-alt.svg new file mode 100644 index 00000000..edf03840 --- /dev/null +++ b/packages/tcore-console/assets/icons/trash-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/user-alt.svg b/packages/tcore-console/assets/icons/user-alt.svg new file mode 100644 index 00000000..43ee7b36 --- /dev/null +++ b/packages/tcore-console/assets/icons/user-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/wifi.svg b/packages/tcore-console/assets/icons/wifi.svg new file mode 100644 index 00000000..9389a17d --- /dev/null +++ b/packages/tcore-console/assets/icons/wifi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/window-maximize.svg b/packages/tcore-console/assets/icons/window-maximize.svg new file mode 100644 index 00000000..daa50e73 --- /dev/null +++ b/packages/tcore-console/assets/icons/window-maximize.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/icons/windows.svg b/packages/tcore-console/assets/icons/windows.svg new file mode 100644 index 00000000..9aa2c4a5 --- /dev/null +++ b/packages/tcore-console/assets/icons/windows.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/tcore-console/assets/images/favicon.png b/packages/tcore-console/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..ea9db3c018b1cf8776b239d7a2cbcf66baca2410 GIT binary patch literal 405683 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 z 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 G + + + + + + + + + + + diff --git a/packages/tcore-console/assets/images/logo-white.svg b/packages/tcore-console/assets/images/logo-white.svg new file mode 100644 index 00000000..13fb0cd8 --- /dev/null +++ b/packages/tcore-console/assets/images/logo-white.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + diff --git a/packages/tcore-console/assets/images/retention.gif b/packages/tcore-console/assets/images/retention.gif new file mode 100644 index 0000000000000000000000000000000000000000..87bcd01b3f3de924935737747d2c98be4928cad1 GIT binary patch literal 59159 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

V>+a3(2I9*G4(Z5#O!zk^A1s#&#BDM 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 { + console.log("✔ Detected changes and rebuilt tcore-console"); + } + } : null, + external: ["path"], + plugins: [svgr()], + loader: { + ".png": "file", + ".gif": "file", + }, + }) + .catch(() => process.exit(1)); diff --git a/packages/tcore-console/esbuild/buildPath.js b/packages/tcore-console/esbuild/buildPath.js new file mode 100644 index 00000000..7690fbfb --- /dev/null +++ b/packages/tcore-console/esbuild/buildPath.js @@ -0,0 +1,6 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const path = require("path"); + +const buildPath = path.join(__dirname, "../build"); + +module.exports = buildPath; diff --git a/packages/tcore-console/esbuild/generateIndex.js b/packages/tcore-console/esbuild/generateIndex.js new file mode 100644 index 00000000..6630f99a --- /dev/null +++ b/packages/tcore-console/esbuild/generateIndex.js @@ -0,0 +1,27 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const fs = require("fs"); +const buildPath = require("./buildPath"); +const version = require("../../../package.json").version; + +const temp = ` + + + + + + + + +

+ + + +`; + +try { + fs.mkdirSync(buildPath); +} catch (ex) { + // +} + +fs.writeFileSync(`${buildPath}/index.html`, temp, { encoding: "utf-8" }); diff --git a/packages/tcore-console/esbuild/icon.js b/packages/tcore-console/esbuild/icon.js new file mode 100644 index 00000000..843c7a64 --- /dev/null +++ b/packages/tcore-console/esbuild/icon.js @@ -0,0 +1,39 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const fs = require("fs"); +const path = require("path"); + +// lists all files in the icons folder +const files = fs.readdirSync(path.join(__dirname, "../assets/icons")); + +// we will insert the enum into this file +const outputPath = path.join(__dirname, "../src/Components/Icon/Icon.types.ts"); + +const template = [ + "/* eslint-disable prettier/prettier */", + "", + "// ! This file is automatically generated. Please don't change it.", + "", + "/**", + " * Types of icons available in the system.", + " * Each one must match the corresponding filename in the /assets/icons folder.", + " */", + "enum EIcon {", + files + .filter((x) => !x.startsWith(".")) // can't start with a dot + .map((x) => ` "${x.replace(".svg", "")}" = "${x.replace(".svg", "")}",`) // map the output to be an enum field + .join("\n"), // join and break lines, + "}", + "", + "const icons = {", + files + .filter((x) => !x.startsWith(".")) // can't start with a dot + .map((x) => ` "${x.replace(".svg", "")}": require("../../../assets/icons/${x}"),`) // map the output to be an enum field + .join("\n"), + "}", + "", + "export { EIcon, icons };", + "", +].join("\n"); + +// writes the enum string to the file +fs.writeFileSync(outputPath, template, { encoding: "utf-8" }); diff --git a/packages/tcore-console/esbuild/svgr.js b/packages/tcore-console/esbuild/svgr.js new file mode 100644 index 00000000..476201ac --- /dev/null +++ b/packages/tcore-console/esbuild/svgr.js @@ -0,0 +1,17 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const svgr = require("@svgr/core").default; +const fs = require("fs"); + +module.exports = (options = {}) => ({ + name: "svgr", + setup(build) { + build.onLoad({ filter: /\.svg$/ }, async (args) => { + const svg = await fs.promises.readFile(args.path, "utf8"); + const contents = await svgr(svg, { ...options }, { filePath: args.path }); + return { + contents, + loader: "jsx", + }; + }); + }, +}); diff --git a/packages/tcore-console/index.d.ts b/packages/tcore-console/index.d.ts new file mode 100644 index 00000000..95cc1906 --- /dev/null +++ b/packages/tcore-console/index.d.ts @@ -0,0 +1 @@ +export * from "./build-tsc"; diff --git a/packages/tcore-console/jest.config.js b/packages/tcore-console/jest.config.js new file mode 100644 index 00000000..5d007c2c --- /dev/null +++ b/packages/tcore-console/jest.config.js @@ -0,0 +1,14 @@ +module.exports = { + moduleDirectories: [ + "node_modules", + "utils", + __dirname, + ], + modulePathIgnorePatterns: ["./build-tsc"], + testEnvironment: "jsdom", + setupFiles: ["./utils/setup-jest.tsx"], + transform: { + '^.+\\.tsx?$': "ts-jest", + ".+\\.(css|svg|gif|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub" + } +}; diff --git a/packages/tcore-console/package.json b/packages/tcore-console/package.json new file mode 100644 index 00000000..18ecb134 --- /dev/null +++ b/packages/tcore-console/package.json @@ -0,0 +1,84 @@ +{ + "name": "@tago-io/tcore-console", + "version": "0.3.3", + "private": true, + "description": "TCore Console", + "author": "Tago LLC", + "main": "./build-tsc/index", + "homepage": "https://github.com/tago-io/tcore", + "repository": { + "type": "git", + "url": "https://github.com/tago-io/tcore" + }, + "scripts": { + "clean": "rm -rf node_modules; rm -rf package-lock.json", + "build": "rm -rf ./build; node esbuild/build.js; npm run tsc", + "linter": "eslint .", + "watch": "node esbuild/build.js --watch", + "tsc:watch": "npm run watch", + "test:watch": "TZ=UTC jest --watch", + "test": "TZ=UTC jest", + "tsc": "rm -rf ./build-tsc; tsc -p tsconfig-tsc.json" + }, + "dependencies": { + "semver": "7.3.5", + "@antv/g2": "4.1.23", + "@tago-io/tcore-sdk": "*", + "@tago-io/tcore-shared": "*", + "axios": "0.24.0", + "lodash.clonedeep": "4.5.0", + "luxon": "2.0.1", + "tinycolor2": "1.4.2", + "polished": "4.1.3", + "qs": "6.10.1", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-helmet": "6.1.0", + "react-markdown": "7.0.0", + "react-router": "5.2.0", + "react-router-dom": "5.2.0", + "socket.io-client": "4.4.1", + "styled-components": "5.3.0", + "styled-jsx": "3.4.5", + "swr": "0.5.6", + "zod": "3.13.4", + "@tago-io/sdk": "10.4.4", + "mobx-react": "7.3.0", + "mobx": "6.4.2" + }, + "devDependencies": { + "@types/semver": "7.3.9", + "@svgr/core": "5.5.0", + "@testing-library/jest-dom": "5.14.1", + "@testing-library/react": "12.0.0", + "@types/jest": "27.0.1", + "@types/lodash.clonedeep": "4.5.6", + "@types/luxon": "1.27.1", + "@types/qs": "6.9.7", + "@types/react": "17.0.14", + "@types/react-dom": "17.0.9", + "@types/react-helmet": "6.1.4", + "@types/react-router": "5.1.16", + "@types/react-router-dom": "5.1.8", + "@types/styled-components": "5.1.11", + "@types/tinycolor2": "1.4.3", + "@typescript-eslint/eslint-plugin": "4.29.0", + "@typescript-eslint/parser": "4.29.3", + "esbuild": "0.12.22", + "esbuild-jest": "0.5.0", + "eslint": "7.31.0", + "eslint-config-airbnb": "18.2.1", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-import": "2.23.4", + "eslint-plugin-jest": "24.4.0", + "eslint-plugin-jsx-a11y": "6.4.1", + "eslint-plugin-prettier": "3.4.0", + "eslint-plugin-react": "7.24.0", + "eslint-plugin-react-hooks": "4.2.0", + "jest": "27.0.6", + "jest-transform-stub": "2.0.0", + "prettier": "2.3.2", + "ts-jest": "27.0.5", + "typescript": "4.3.5" + } +} diff --git a/packages/tcore-console/react-shim.js b/packages/tcore-console/react-shim.js new file mode 100644 index 00000000..392f014c --- /dev/null +++ b/packages/tcore-console/react-shim.js @@ -0,0 +1,5 @@ +import * as React from "react"; +window.require = () => {}; // for 'path' in tagoio sdk +window.process = window; +window.process.env = {}; +export { React }; diff --git a/packages/tcore-console/src/App.tsx b/packages/tcore-console/src/App.tsx new file mode 100644 index 00000000..f42d8ce8 --- /dev/null +++ b/packages/tcore-console/src/App.tsx @@ -0,0 +1,77 @@ +// we do this workaround to make sure the API always points to the right place, +// regardless in which URL the application is running. +const { location } = window; +process.env.TAGOIO_API = `${location.protocol}//${location.hostname}:${location.port}`; + +import ReactDOM from "react-dom"; +import { ThemeProvider } from "styled-components"; +import { Route, BrowserRouter, Switch } from "react-router-dom"; +import { Helmet } from "react-helmet"; +import imgFavicon from "../assets/images/favicon.png"; +import { lightTheme } from "./theme"; +import MainScreen from "./Components/MainScreen/MainScreen"; +import GlobalStyles from "./Components/Styles/GlobalStyles"; +import DeviceList from "./Components/Device/List/DeviceList"; +import BucketList from "./Components/Bucket/List/BucketList"; +import ActionList from "./Components/Action/List/ActionList"; +import AnalysisList from "./Components/Analysis/List/AnalysisList"; +import Settings from "./Components/Settings/Edit/Settings"; +import Home from "./Components/Home/Home"; +import Logs from "./Components/Logs/Logs"; +import DeviceEdit from "./Components/Device/Edit/DeviceEdit"; +import BucketEdit from "./Components/Bucket/Edit/BucketEdit"; +import ActionEdit from "./Components/Action/Edit/ActionEdit"; +import AnalysisEdit from "./Components/Analysis/Edit/AnalysisEdit"; +import PluginEdit from "./Components/Plugins/Edit/PluginEdit"; + +/** + * Main component of the application. + */ +function App() { + const themeObject = lightTheme; + + return ( + <> + + + + + + + + + + + null} /> + + + + + ); +} + +/** + * Renders the main admin screen, the main screen is the one that has the sidebar and navbar. + */ +function renderMainScreen() { + return ( + + + + + + + + + + + + + + + + + ); +} + +ReactDOM.render(, document.getElementById("root")); diff --git a/packages/tcore-console/src/Components/Accordion/Accordion.style.ts b/packages/tcore-console/src/Components/Accordion/Accordion.style.ts new file mode 100644 index 00000000..8cc2c1a3 --- /dev/null +++ b/packages/tcore-console/src/Components/Accordion/Accordion.style.ts @@ -0,0 +1,80 @@ +import styled, { css } from "styled-components"; + +/** + * Container of the item. + */ +export const Container = styled.div<{ error?: boolean }>` + display: flex; + position: relative; + flex: none; + border: 1px solid ${(props) => props.theme.fieldsetBorder}; + border-radius: 3px; + flex-direction: column; + margin-bottom: 1rem; + transition: border-color 0.2s; + + > .content { + padding: 10px; + } +`; + +/** + */ +export const TitleBar = styled.div<{ isAlwaysOpen?: boolean; open?: boolean }>` + display: flex; + align-items: center; + justify-content: space-between; + flex-direction: row; + padding: 10px; + + ${(props) => + !props.isAlwaysOpen && + css` + cursor: pointer; + :hover { + background: rgb(245, 245, 245); + } + :active { + background: rgb(230, 230, 230); + } + `} + + > .left-side { + flex: 1; + display: flex; + align-items: center; + flex-direction: row; + + > i { + margin: 0px 5px; + } + + > .title { + display: flex; + align-items: flex-start; + flex: 1; + flex-direction: column; + margin-left: 10px; + + > h3 { + font-size: 1.1rem; + } + + .description { + color: hsl(0, 0%, 55%); + display: block; + margin-top: 3px; + } + } + } + + > .right-side { + flex: none; + } + + ${(props) => + props.open && + css` + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + `} +`; diff --git a/packages/tcore-console/src/Components/Accordion/Accordion.test.tsx b/packages/tcore-console/src/Components/Accordion/Accordion.test.tsx new file mode 100644 index 00000000..ca54a5b4 --- /dev/null +++ b/packages/tcore-console/src/Components/Accordion/Accordion.test.tsx @@ -0,0 +1,97 @@ +import { fireEvent, render, screen } from "../../../utils/test-utils"; +import { EIcon } from "../Icon/Icon.types"; +import Accordion from "./Accordion"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("doesn't render children if `open` = `false`", () => { + render(Hello world); + expect(screen.queryByText("Hello world")).not.toBeInTheDocument(); +}); + +test("renders children if `open` = `true`", () => { + render(Hello world); + expect(screen.queryByText("Hello world")).toBeInTheDocument(); +}); + +test("calls onChangeOpen when clicking on the title bar", () => { + const onChangeOpen = jest.fn(); + render(Hello world); + expect(onChangeOpen).not.toHaveBeenCalled(); + fireEvent.click(screen.getByTestId("title-bar")); + expect(onChangeOpen).toHaveBeenCalled(); +}); + +test("doesn't call onChangeOpen if it's undefined", () => { + render(Hello world); + const fn = () => fireEvent.click(screen.getByTestId("title-bar")); + expect(fn).not.toThrowError(); +}); + +test("doesn't call onChangeOpen if `isAlwaysOpen` = `true`", () => { + const onChangeOpen = jest.fn(); + render( + + Hello world + + ); + expect(onChangeOpen).not.toHaveBeenCalled(); + fireEvent.click(screen.getByTestId("title-bar")); + expect(onChangeOpen).not.toHaveBeenCalled(); +}); + +test("doesn't call onChangeOpen if clicking on the children", () => { + const onChangeOpen = jest.fn(); + render( + + Hello world + + ); + expect(onChangeOpen).not.toHaveBeenCalled(); + fireEvent.click(screen.getByText("Hello world")); + expect(onChangeOpen).not.toHaveBeenCalled(); +}); + +test("renders title as string", () => { + render(); + expect(screen.getByText("Settings")).toBeInTheDocument(); +}); + +test("renders title as node", () => { + render(Settings} />); + expect(screen.getByText("Settings")).toBeInTheDocument(); +}); + +test("renders description as string", () => { + render(); + expect(screen.getByText("Adjust the settings")).toBeInTheDocument(); +}); + +test("renders icon", () => { + render(); + expect(screen.getByText("cog-icon-mock")).toBeInTheDocument(); +}); + +test("renders description as node", () => { + render(Adjust the settings} />); + expect(screen.getByText("Adjust the settings")).toBeInTheDocument(); +}); + +test("renders caret-down icon when title bar is closed", () => { + render(); + expect(screen.getByText("caret-down-icon-mock")).toBeInTheDocument(); +}); + +test("renders caret-up icon when title bar is closed", () => { + render(); + expect(screen.getByText("caret-up-icon-mock")).toBeInTheDocument(); +}); + +test("doesn't render caret icons when `isAlwaysOpen` = `true`", () => { + render(); + expect(screen.queryByText("caret-up-icon-mock")).not.toBeInTheDocument(); + expect(screen.queryByText("caret-down-icon-mock")).not.toBeInTheDocument(); +}); diff --git a/packages/tcore-console/src/Components/Accordion/Accordion.tsx b/packages/tcore-console/src/Components/Accordion/Accordion.tsx new file mode 100644 index 00000000..a74e531d --- /dev/null +++ b/packages/tcore-console/src/Components/Accordion/Accordion.tsx @@ -0,0 +1,105 @@ +import { ReactNode } from "react"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import * as Style from "./Accordion.style"; + +/** + * Props. + */ +interface IAccordion { + /** + * Content to be rendered inside of this component. + */ + children?: ReactNode; + /** + * Title to be rendered in the title bar. + */ + title?: ReactNode; + /** + * Optional description to appear below the title. + */ + description?: ReactNode; + /** + * Optional icon for the title bar. + */ + icon?: EIcon; + /** + * Indicates if this component is open or not. + * If this component is open its `children` will be rendered, otherwise they will be omitted. + */ + open?: boolean; + /** + * Called when the user clicks on the title bar. This should toggle the `open` prop. + */ + onChangeOpen?: (open: boolean) => void; + /** + * Indicates if this component can be open or not. + * If this is set to `false` this component will always be open and will not be clickable. + */ + isAlwaysOpen?: boolean; +} + +/** + * This component shows an accordion that can be "expanded" by clicking on it. + * When this component is expanded its children will be rendered. + */ +function Accordion(props: IAccordion) { + const { icon, isAlwaysOpen, title, children, description } = props; + const open = props.open || isAlwaysOpen; + + /** + * Renders the text part of the accordion. + */ + function renderTitle() { + return ( +
+ {title &&

{title}

} + {description &&
{description}
} +
+ ); + } + + /** + * Renders the icon part of the accordion. + */ + function renderIcon() { + if (!icon) { + return null; + } + return ; + } + + /** + * Called when the main container is clicked. + */ + const onClick = () => { + if (!isAlwaysOpen) { + props.onChangeOpen?.(!open); + } + }; + + return ( + + +
+ {renderIcon()} + {renderTitle()} +
+ + {!isAlwaysOpen && ( +
+ +
+ )} +
+ + {open && ( +
e.stopPropagation()}> + {children} +
+ )} +
+ ); +} + +export default Accordion; diff --git a/packages/tcore-console/src/Components/Action/Common/ActionFields/ActionFields.tsx b/packages/tcore-console/src/Components/Action/Common/ActionFields/ActionFields.tsx new file mode 100644 index 00000000..688d2c18 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Common/ActionFields/ActionFields.tsx @@ -0,0 +1,182 @@ +import { IActionOption } from "@tago-io/tcore-sdk/types"; +import FlexRow from "../../../FlexRow/FlexRow"; +import FormGroup from "../../../FormGroup/FormGroup"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import Switch from "../../../Switch/Switch"; +import ActionTypePicker from "../ActionTypePicker/ActionTypePicker"; +import HttpHeaders from "../HttpHeaders/HttpHeaders"; +import MultipleAnalysis from "../MultipleAnalysis/MultipleAnalysis"; +import PluginConfigFields from "../../../Plugins/Common/PluginConfigFields/PluginConfigFields"; + +/** + * Props. + */ +interface IActionFields { + /** + * Additional options provided by plugins. + */ + options?: IActionOption[]; + option: any; + onChangeOption: any; + optionFields: any; + onChangeOptionFields: any; + /** + * Position of the options container. Default is `bottom`. + */ + optionsPosition?: "top" | "bottom"; + errors?: any; +} + +/** + */ +function ActionFields(props: IActionFields) { + const { + option, + optionsPosition, + onChangeOption, + optionFields, + onChangeOptionFields, + errors, + options, + } = props; + + /** + */ + const renderTagoIO = () => { + return ( + <> + + onChangeOptionFields({ ...optionFields, token: e.target.value })} + placeholder="enter a device's token" + type="password" + value={optionFields?.token || ""} + /> + + + ); + }; + + /** + */ + const renderPost = () => { + return ( + <> + + onChangeOptionFields({ ...optionFields, url: e.target.value })} + placeholder="enter the url address" + value={optionFields?.url || ""} + /> + + + + { + onChangeOptionFields({ ...optionFields, headers }); + }} + /> + + + + +
+ + onChangeOptionFields({ ...optionFields, fallback_token: e.target.value }) + } + disabled={!optionFields.http_post_fallback_enabled} + placeholder="Fallback device token" + /> +
+ +
+ + onChangeOptionFields({ ...optionFields, http_post_fallback_enabled: e }) + } + > + Enabled + +
+
+
+ + ); + }; + + /** + */ + const renderAnalysis = () => { + return ( + onChangeOptionFields({ ...optionFields, analyses: e })} + errors={errors?.analyses} + optionsPosition={optionsPosition} + /> + ); + }; + + /** + */ + const renderCustomOption = () => { + return ( + + ); + }; + + /** + */ + const renderContent = () => { + if (option?.id === "script") { + return renderAnalysis(); + } else if (option?.id === "post") { + return renderPost(); + } else if (option?.id === "tagoio") { + return renderTagoIO(); + } else if (option?.id) { + return renderCustomOption(); + } + return null; + }; + + return ( + <> + + + + +
{renderContent()}
+ + ); +} + +export default ActionFields; diff --git a/packages/tcore-console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.style.ts b/packages/tcore-console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.style.ts new file mode 100644 index 00000000..9b7917d5 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.style.ts @@ -0,0 +1,43 @@ +import styled from "styled-components"; + +/** + */ +export const Item = styled.div` + margin: 3px 0px; + + .icon-container { + width: 40px; + display: flex; + align-items: center; + justify-content: center; + margin-right: 7px; + flex: none; + + img { + width: 30px; + height: 30px; + object-fit: contain; + } + } + + > .content { + display: flex; + align-items: center; + + .info { + > .title { + font-weight: bold; + font-size: 0.88rem; + color: ${(props) => props.color || "inherit"}; + } + + > .description { + display: block; + font-size: 12px; + font-weight: 400; + margin: 0; + opacity: 0.7; + } + } + } +`; diff --git a/packages/tcore-console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.tsx b/packages/tcore-console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.tsx new file mode 100644 index 00000000..2385b068 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.tsx @@ -0,0 +1,138 @@ +import { useCallback } from "react"; +import { IActionOption } from "@tago-io/tcore-sdk/types"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import OptionsPicker from "../../../OptionsPicker/OptionsPicker"; +import * as Style from "./ActionTypePicker.style"; + +/** + * Props. + */ +interface IActionTypePicker { + /** + * Device object. + */ + value?: IActionOption; + /** + * Called when a new device gets picked. + */ + onChange: (value: IActionOption) => void; + /** + * Additional options provided by plugins. + */ + options?: IActionOption[]; + /** + * Position of the options container. Default is `bottom`. + */ + optionsPosition?: "top" | "bottom"; +} + +/** + * Options to be displayed in the component. + */ +const defaultOptions: IActionOption[] = [ + { + description: "Run an analysis whenever this action is triggered", + icon: EIcon.code, + id: "script", + name: "Run Analysis", + }, + { + description: "Will send a POST request to an endpoint whenever this action is triggered", + icon: EIcon["network-wired"], + id: "post", + name: "Post data to endpoint using HTTP", + }, + { + description: "Insert the data from the device into TagoIO", + icon: EIcon.io, + id: "tagoio", + name: "Insert data into TagoIO", + }, +]; + +/** + * Picker for the type of action. + */ +function ActionTypePicker(props: IActionTypePicker) { + const { options, optionsPosition } = props; + + /** + * Renders a single row. + */ + const renderPluginImage = (item: IActionOption) => { + const idSplit = item.id.split(":"); + const pluginMd5 = idSplit[0]; + const pluginID = idSplit[1]; + return ; + }; + + /** + * Renders a single row. + */ + const renderOption = (item: IActionOption) => { + const isCustom = options?.includes(item); + return ( + +
+
+ {isCustom ? renderPluginImage(item) : } +
+ +
+
{item.name}
+
{item.description}
+
+
+
+ ); + }; + + /** + * Resolves an option by an ID. + * This transforms the ID into an object. + */ + const resolveOptionByID = useCallback( + async (id: string | number) => { + const allOptions = [...defaultOptions, ...(options || [])]; + const response = allOptions.find((x) => x.id === id); + return response; + }, + [options] + ); + + /** + * Retrieves the options. + */ + const onGetOptions = useCallback( + (query: string, page: number) => { + if (page > 1) { + return []; + } + + const allOptions = [...defaultOptions, ...(options || [])]; + return allOptions.filter((x) => { + return ( + String(x.description).toLowerCase().includes(query) || + String(x.name).toLowerCase().includes(query) + ); + }); + }, + [options] + ); + + return ( + + doesRequest + labelField="name" + onChange={props.onChange} + onGetOptions={onGetOptions} + onRenderOption={renderOption} + onResolveOption={resolveOptionByID} + optionsPosition={optionsPosition} + value={props.value} + /> + ); +} + +export default ActionTypePicker; diff --git a/packages/tcore-console/src/Components/Action/Common/DeviceRadio/DeviceRadio.style.tsx b/packages/tcore-console/src/Components/Action/Common/DeviceRadio/DeviceRadio.style.tsx new file mode 100644 index 00000000..c835194e --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Common/DeviceRadio/DeviceRadio.style.tsx @@ -0,0 +1,48 @@ +import styled from "styled-components"; + +/** + */ +export const Container = styled.div<{ type?: string }>` + display: flex; + flex: 1; + margin: -15px; + max-height: calc(100% + 30px); + + section > .title { + text-align: center; + margin-bottom: 1rem; + font-size: 15px; + font-weight: bold; + color: rgb(111, 111, 111); + padding-bottom: 1rem; + border-bottom: 1px solid ${(props) => props.theme.fieldsetBorder}; + display: flex; + align-items: center; + flex: none; + justify-content: center; + } +`; + +/** + */ +export const LeftSection = styled.section` + display: flex; + flex-direction: column; + flex: 1.4; + border-right: 1px solid ${(props) => props.theme.fieldsetBorder}; + padding: 15px; + overflow: auto; + max-height: 100%; + position: relative; +`; + +/** + */ +export const RightSection = styled.section` + display: flex; + flex-direction: column; + flex: 1; + padding: 15px; + overflow: auto; + max-height: 100%; +`; diff --git a/packages/tcore-console/src/Components/Action/Common/DeviceRadio/DeviceRadio.tsx b/packages/tcore-console/src/Components/Action/Common/DeviceRadio/DeviceRadio.tsx new file mode 100644 index 00000000..a10fa803 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Common/DeviceRadio/DeviceRadio.tsx @@ -0,0 +1,117 @@ +import { useTheme } from "styled-components"; +import { IDevice, ITag } from "@tago-io/tcore-sdk/types"; +import Col from "../../../Col/Col"; +import DevicePicker from "../../../Device/Common/DevicePicker/DevicePicker"; +import FlexRow from "../../../FlexRow/FlexRow"; +import FormGroup from "../../../FormGroup/FormGroup"; +import { EIcon } from "../../../Icon/Icon.types"; +import IconRadio from "../../../IconRadio/IconRadio"; +import Input from "../../../Input/Input"; +import Row from "../../../Row/Row"; + +/** + * Props. + */ +interface IDeviceRadioProps { + /** + * Selected device if type = `single`. + */ + device?: IDevice; + /** + * Selected tag if type = `multiple`. + */ + tag?: ITag; + /** + * Type of selection. + */ + deviceType: "single" | "multiple"; + /** + * Called when the device changes. + */ + onChangeDevice: (device: IDevice) => void; + /** + * Called when the tag changes. + */ + onChangeTag: (tag: ITag) => void; + /** + * Called when the type changes. + */ + onChangeDeviceType: (type: string) => void; + /** + * Indicates if this device radio has an error. + */ + error?: boolean; +} + +/** + * An input radio to select types of devices. + */ +function DeviceRadio(props: IDeviceRadioProps) { + const { deviceType, error, device, tag, onChangeDeviceType, onChangeTag, onChangeDevice } = props; + + const theme = useTheme(); + + return ( + + + + + + + + + {deviceType === "single" ? ( + + + + ) : ( + + + onChangeTag({ key: e.target.value, value: tag?.value || "" })} + placeholder="Enter a tag key" + error={error} + /> + onChangeTag({ key: tag?.key || "", value: e.target.value })} + placeholder="Tag value" + error={error} + /> + + + )} + + + ); +} + +export default DeviceRadio; diff --git a/packages/tcore-console/src/Components/Action/Common/HttpHeaders/HttpHeaders.tsx b/packages/tcore-console/src/Components/Action/Common/HttpHeaders/HttpHeaders.tsx new file mode 100644 index 00000000..f6db843d --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Common/HttpHeaders/HttpHeaders.tsx @@ -0,0 +1,94 @@ +import Input from "../../../Input/Input"; +import RowManipulatorTable from "../../../RowManipulatorTable/RowManipulatorTable"; + +/** + * Props. + */ +interface IHttpHeaders { + value: any[]; + onChange: (data: any[]) => void; +} + +/** + */ +function HttpHeaders(props: IHttpHeaders) { + const { value, onChange } = props; + + const firstItem = value[0]; + if (firstItem?.name !== "TagoIO-Retries") { + value.unshift({ name: "TagoIO-Retries", value: "" }); + } + if (value.length === 1) { + value.push({ name: "", value: "" }); + } + + /** + */ + const onChangeField = (field: keyof any, v: string, rowIndex: number) => { + if (!value[rowIndex]) { + value[rowIndex] = { name: "", value: "" }; // create the item if it doesn't exist + } + value[rowIndex][field] = v; + onChange([...value]); + }; + + /** + */ + const renderKey = (item: any, index: number) => { + return ( + onChangeField("name", e.target.value, index)} + placeholder="content/type" + disabled={index === 0} + /> + ); + }; + + /** + */ + const renderValue = (item: any, index: number) => { + return ( + onChangeField("value", e.target.value, index)} + placeholder="application/json" + disabled={index === 0} + /> + ); + }; + + /** + */ + const addItem = () => { + props.value.push({ name: "", value: "" }); + onChange([...props.value]); + }; + + /** + */ + const removeItem = (index: number) => { + props.value.splice(index, 1); + onChange([...props.value]); + }; + + return ( + + data={value} + onAddItem={addItem} + onRemoveItem={removeItem} + columns={[ + { + label: "Name", + onRender: renderKey, + }, + { + label: "Value", + onRender: renderValue, + }, + ]} + /> + ); +} + +export default HttpHeaders; diff --git a/packages/tcore-console/src/Components/Action/Common/ModalAddAction/ModalAddAction.tsx b/packages/tcore-console/src/Components/Action/Common/ModalAddAction/ModalAddAction.tsx new file mode 100644 index 00000000..d017f6ac --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Common/ModalAddAction/ModalAddAction.tsx @@ -0,0 +1,132 @@ +import { IActionOption, zName } from "@tago-io/tcore-sdk/types"; +import { MouseEvent, useCallback, useEffect, useState } from "react"; +import { useHistory } from "react-router"; +import { useTheme } from "styled-components"; +import useApiRequest from "../../../../Helpers/useApiRequest"; +import createAction from "../../../../Requests/createAction/createAction"; +import FormGroup from "../../../FormGroup/FormGroup"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import Modal from "../../../Modal/Modal"; +import normalizeOption from "../../Helpers/normalizeType"; +import ActionFields from "../ActionFields/ActionFields"; +import TypeRadio from "../TypeRadio/TypeRadio"; + +/** + */ +interface IModalAddAction { + onClose: () => void; +} + +/** + * The modal to create a new action. + */ +function ModalAddAction(props: IModalAddAction) { + const theme = useTheme(); + const [name, setName] = useState(""); + const [type, setType] = useState("variable"); + const [newID, setNewID] = useState(""); + const [option, setOption] = useState(null); + const [optionFields, setOptionFields] = useState({}); + const [errors, setErrors] = useState({}); + const { data: additionalTriggers } = useApiRequest("/action-types"); + const history = useHistory(); + const { onClose } = props; + + /** + * Validates the data of the action. + */ + const validate = useCallback(async () => { + const err: any = { + // option: !option, + name: await zName + .parseAsync(name) + .then(() => false) + .catch(() => true), + }; + if (err.name) { + setErrors(err); + return false; + } + + return true; + }, [name]); + + /** + * Creates the action. + */ + const doRequest = useCallback(async () => { + const data = { + action: { type: option?.id, ...normalizeOption(option, optionFields) }, + name: name, + type, + active: true, + tags: [], + }; + + const response = await createAction(data); + + setNewID(response); + }, [type, option, optionFields, name]); + + /** + * Called when the confirm button is pressed. + */ + const confirm = useCallback( + async (e?: MouseEvent) => { + if (await validate()) { + await doRequest(); + } + e?.preventDefault(); + }, + [doRequest, validate] + ); + + /** + * Used to transfer the user to the newly created action. + */ + useEffect(() => { + if (newID) { + history.push(`/console/actions/${newID}`); + } + }, [history, newID]); + + return ( + + + setName(e.target.value)} + placeholder="Enter a name for this action" + value={name} + /> + + + + + + + + + + + ); +} + +export default ModalAddAction; diff --git a/packages/tcore-console/src/Components/Action/Common/MultipleAnalysis/MultipleAnalysis.tsx b/packages/tcore-console/src/Components/Action/Common/MultipleAnalysis/MultipleAnalysis.tsx new file mode 100644 index 00000000..d206a404 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Common/MultipleAnalysis/MultipleAnalysis.tsx @@ -0,0 +1,68 @@ +import { IAnalysis } from "@tago-io/tcore-sdk/types"; +import AnalysisPicker from "../../../Analysis/Common/AnalysisPicker/AnalysisPicker"; +import RowManipulator from "../../../RowManipulator/RowManipulator"; + +/** + * Props. + */ +interface IMultipleAnalysis { + data: (IAnalysis | null)[]; + onChange: (data: (IAnalysis | null)[]) => void; + /** + * Error of the fields. + */ + errors?: boolean[]; + /** + * Position of the options container. Default is `bottom`. + */ + optionsPosition?: "top" | "bottom"; +} + +/** + */ +function MultipleAnalysis(props: IMultipleAnalysis) { + const { data, errors, optionsPosition, onChange } = props; + + /** + */ + const addItem = () => { + data.push(null); + onChange([...data]); + }; + + /** + */ + const removeItem = (index: number) => { + data.splice(index, 1); + onChange([...data]); + }; + + /** + */ + const renderItem = (item: any, index: number) => { + return ( +
+ { + data[index] = e; + onChange([...data]); + }} + /> +
+ ); + }; + + return ( + + ); +} + +export default MultipleAnalysis; diff --git a/packages/tcore-console/src/Components/Action/Common/TypeRadio/TypeRadio.tsx b/packages/tcore-console/src/Components/Action/Common/TypeRadio/TypeRadio.tsx new file mode 100644 index 00000000..ab6a79cf --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Common/TypeRadio/TypeRadio.tsx @@ -0,0 +1,70 @@ +import { IActionOption } from "@tago-io/tcore-sdk/types"; +import { useTheme } from "styled-components"; +import { EIcon } from "../../../Icon/Icon.types"; +import IconRadio from "../../../IconRadio/IconRadio"; +import Icon from "../../../Icon/Icon"; +import useApiRequest from "../../../../Helpers/useApiRequest"; + +/** + * Props. + */ +interface ITypeRadioProps { + /** + * The selected value. + */ + value: string; + /** + * Called when the value changes. + */ + onChange: (value: string) => void; +} + +/** + * Shows a list of possible action types. + * This shows the default list and all the plugin options too. + */ +function TypeRadio(props: ITypeRadioProps) { + const { data } = useApiRequest("/action-triggers"); + const { value, onChange } = props; + const theme = useTheme(); + + /** + * Renders the options. + */ + const renderOptions = () => { + const options = [ + { + color: value === "variable" ? theme.action : theme.font, + description: "Triggered when the selected variables meet certain conditions.", + icon: EIcon.database, + label: "Variable", + value: "variable", + }, + ]; + + for (const item of data || []) { + options.push({ + color: value === item.id ? theme.action : theme.font, + description: item.description as string, + icon: EIcon.cog, + label: item.name, + value: item.id, + }); + } + + return options; + }; + + return ( +
+ + + Select a trigger + + + +
+ ); +} + +export default TypeRadio; diff --git a/packages/tcore-console/src/Components/Action/Edit/ActionEdit.test.tsx b/packages/tcore-console/src/Components/Action/Edit/ActionEdit.test.tsx new file mode 100644 index 00000000..8ff90ad2 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Edit/ActionEdit.test.tsx @@ -0,0 +1,9 @@ +jest.mock("../../../Helpers/useApiRequest.ts"); + +import { render } from "../../../../utils/test-utils"; +import ActionEdit from "./ActionEdit"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); diff --git a/packages/tcore-console/src/Components/Action/Edit/ActionEdit.tsx b/packages/tcore-console/src/Components/Action/Edit/ActionEdit.tsx new file mode 100644 index 00000000..ee288298 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Edit/ActionEdit.tsx @@ -0,0 +1,345 @@ +import { useCallback, useRef, useState } from "react"; +import { useTheme } from "styled-components"; +import { + IAction, + IActionOption, + IActionType, + ITag, + IDevice, + IActionEdit, + zAction, +} from "@tago-io/tcore-sdk/types"; +import { useRouteMatch } from "react-router"; +import { cloneDeep } from "lodash"; +import useApiRequest from "../../../Helpers/useApiRequest"; +import EditPage from "../../EditPage/EditPage"; +import { EIcon } from "../../Icon/Icon.types"; +import Switch from "../../Switch/Switch"; +import normalizeTags from "../../../Helpers/normalizeTags"; +import TagsTab from "../../Tags/TagsTab"; +import validateConfigFields from "../../../Helpers/validateConfigFields"; +import normalizeOption from "../Helpers/normalizeType"; +import deleteAction from "../../../Requests/deleteAction"; +import editAction from "../../../Requests/editAction/editAction"; +import validateOption from "../Helpers/validateOption"; +import buildZodError from "../../../Validation/buildZodError"; +import ActionTab from "./ActionTab/ActionTab"; +import MoreTab from "./MoreTab/MoreTab"; + +/** + * The action's edit page. + */ +function ActionEdit() { + const match = useRouteMatch<{ id: string }>(); + const { id } = match.params; + + const theme = useTheme(); + const [data, setData] = useState({} as IAction); + const [errors, setErrors] = useState({}); + const [trigger, setTrigger] = useState({}); + const [tabIndex, setTabIndex] = useState(0); + const [option, setOption] = useState(null); + const [optionFields, setOptionFields] = useState({}); + const [device, setDevice] = useState(null); + const [tag, setTag] = useState({ key: "", value: "" }); + const [deviceType, setDeviceType] = useState<"single" | "multiple">("single"); + const { data: options } = useApiRequest("/action-types"); + const { data: pluginTypes } = useApiRequest("/action-triggers"); + + const initialData = useRef({} as IAction); + const initialDevice = useRef(null); + const initialOption = useRef(null); + const initialOptionFields = useRef({}); + const initialTag = useRef({ key: "", value: "" }); + const initialTrigger = useRef([]); + const initialDeviceType = useRef(deviceType); + + const loading = !data.id || !options || !pluginTypes; + + // custom type object provided by the plugin. If this object is !== null then + // it means that the current action has a custom (plugin) type. + const customType = pluginTypes?.find((x) => x.id === data.type); + + /** + * Called when the record was fetched by the edit page. + * We use this to set the data state to manipulate the object. + */ + const onFetch = useCallback((action: any) => { + initialOptionFields.current = { ...action.action }; + initialOption.current = { id: action.action?.type } as any as IActionOption; + + setData(action); + setOption(action.action?.type); + setOptionFields({ ...action.action }); + setTrigger(cloneDeep(action.trigger || {})); + + initialData.current = cloneDeep(action); + initialTrigger.current = cloneDeep(action.trigger || {}); + + if (!action.device_info) { + setDeviceType("single"); + } else if (action.device_info?.id) { + setDevice(action.device_info.id as IDevice); + setDeviceType("single"); + initialDevice.current = { id: action.device_info.id } as IDevice; + initialDeviceType.current = "single"; + } else { + setDeviceType("multiple"); + setTag({ key: action.device_info?.tag_key, value: action.device_info?.tag_value }); + initialTag.current = { + key: action.device_info?.tag_key, + value: action.device_info?.tag_value, + }; + initialDeviceType.current = "multiple"; + } + }, []); + + /** + */ + const formatTriggerToSave = useCallback(() => { + return trigger; + }, [trigger]); + + /** + */ + const formatDeviceInfoToSave = useCallback(() => { + if (customType && !customType?.showDeviceSelector) { + return null; + } + if (deviceType === "single") { + return { id: device?.id }; + } else { + return { tag_key: tag?.key || "", tag_value: tag?.value || "" }; + } + }, [customType, device?.id, tag?.key, tag?.value, deviceType]); + + /** + */ + const formatActionToSave = useCallback(() => { + const formatted = { + action: { type: option?.id, ...normalizeOption(option, optionFields) }, + active: data.active, + device_info: formatDeviceInfoToSave(), + id: data.id, + name: data.name, + tags: normalizeTags(data.tags), + trigger: formatTriggerToSave(), + }; + return formatted; + }, [data, option, optionFields, formatDeviceInfoToSave, formatTriggerToSave]); + + /** + * Validates the `trigger` property of the action. + * In case the trigger contains an error, this function will only set + * the error state of the trigger, and nothing else. + */ + const validateTrigger = useCallback(() => { + if (customType) { + const triggerErrors = validateConfigFields(customType.configs, trigger); + if (triggerErrors) { + // error during trigger validation + setErrors({ trigger: triggerErrors }); + return false; + } + } + return true; + }, [customType, trigger]); + + /** + * Validates the form data to make sure the object is not faulty. + * This should return a boolean to indicate if the data is correct or not. + */ + const validate = useCallback(async () => { + try { + const validTrigger = validateTrigger(); + if (!validTrigger) { + return false; + } + + const optionError = validateOption(option, optionFields); + if (optionError) { + setErrors({ option: optionError }); + return false; + } + + await zAction.parseAsync({ + ...data, + tags: normalizeTags(data.tags), + created_at: new Date(data.created_at), + updated_at: new Date(data.updated_at as Date), + device_info: formatDeviceInfoToSave(), + last_triggered: undefined, + }); + + setErrors({}); + + return true; + } catch (ex: any) { + const err = buildZodError(ex.issues); + if (err.tags) { + setTabIndex(1); + } else { + setTabIndex(0); + } + setErrors(err); + return false; + } + }, [data, validateTrigger, option, optionFields, formatDeviceInfoToSave]); + + /** + * Saves the action. + */ + const save = useCallback(async () => { + const formatted = formatActionToSave(); + + await editAction(id, formatted as IActionEdit); + + initialDevice.current = { ...device } as IDevice; + initialOption.current = { ...option } as IActionOption; + initialOptionFields.current = { ...optionFields }; + initialTag.current = { ...tag }; + initialTrigger.current = cloneDeep(trigger); + initialDeviceType.current = deviceType; + initialData.current = cloneDeep(data); + }, [trigger, id, device, deviceType, tag, data, option, optionFields, formatActionToSave]); + + /** + * Deletes the action. + */ + const deleteData = useCallback(async () => { + await deleteAction(id); + }, [id]); + + /** + * Called when a field from a tab gets modified. + * This will apply the change to the data state. + */ + const onChangeData = useCallback( + (field: keyof IAction, value) => { + setData({ ...data, [field]: value }); + }, + [data] + ); + + /** + * Renders the `Action` tab's content. + */ + const renderActionTab = () => { + return ( + + ); + }; + + /** + * Renders the `Tags` tab's content. + */ + const renderTagsTab = () => { + return ( + onChangeData("tags", tags)} + /> + ); + }; + + /** + * Renders the `More` tab. + */ + const renderMoreTab = () => { + return ; + }; + + /** + * Renders the right side of the inner nav. + */ + const renderInnerNav = useCallback(() => { + if (loading) { + // still loading + return null; + } + + return ( + onChangeData("active", e)}> + Active + + ); + }, [loading, onChangeData, data]); + + /** + * Should return if the initial data is different from the current data. + */ + const checkIfDataChanged = useCallback(() => { + const initialDataNorm = { + ...initialData.current, + tags: normalizeTags(initialData.current.tags), + }; + const currentDataNorm = { + ...data, + tags: normalizeTags(data.tags), + }; + + return ( + JSON.stringify(initialDataNorm) !== JSON.stringify(currentDataNorm) || + JSON.stringify(initialOptionFields.current) !== JSON.stringify(optionFields) || + JSON.stringify(initialTrigger.current) !== JSON.stringify(trigger) || + JSON.stringify(initialTag.current) !== JSON.stringify(tag) || + initialOption.current?.id !== option?.id || + String(initialDevice.current?.id) !== String(device?.id) || + initialDeviceType.current !== deviceType + ); + }, [data, tag, option, device, deviceType, trigger, optionFields]); + + return ( + + color={theme.action} + documentTitle="Action" + icon={EIcon.bolt} + innerNavTitle={data.name || "Action"} + loading={loading} + onChangeTabIndex={setTabIndex} + onCheckIfDataChanged={checkIfDataChanged} + onFetch={onFetch} + onRenderInnerNav={renderInnerNav} + onSave={save} + onValidate={validate} + requestPath="action" + tabIndex={tabIndex} + tabs={[ + { + label: "Action", + content: renderActionTab(), + }, + { + label: "Tags", + content: renderTagsTab(), + }, + { + label: "More", + content: renderMoreTab(), + }, + ]} + /> + ); +} + +export default ActionEdit; diff --git a/packages/tcore-console/src/Components/Action/Edit/ActionTab/ActionTab.style.tsx b/packages/tcore-console/src/Components/Action/Edit/ActionTab/ActionTab.style.tsx new file mode 100644 index 00000000..c835194e --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Edit/ActionTab/ActionTab.style.tsx @@ -0,0 +1,48 @@ +import styled from "styled-components"; + +/** + */ +export const Container = styled.div<{ type?: string }>` + display: flex; + flex: 1; + margin: -15px; + max-height: calc(100% + 30px); + + section > .title { + text-align: center; + margin-bottom: 1rem; + font-size: 15px; + font-weight: bold; + color: rgb(111, 111, 111); + padding-bottom: 1rem; + border-bottom: 1px solid ${(props) => props.theme.fieldsetBorder}; + display: flex; + align-items: center; + flex: none; + justify-content: center; + } +`; + +/** + */ +export const LeftSection = styled.section` + display: flex; + flex-direction: column; + flex: 1.4; + border-right: 1px solid ${(props) => props.theme.fieldsetBorder}; + padding: 15px; + overflow: auto; + max-height: 100%; + position: relative; +`; + +/** + */ +export const RightSection = styled.section` + display: flex; + flex-direction: column; + flex: 1; + padding: 15px; + overflow: auto; + max-height: 100%; +`; diff --git a/packages/tcore-console/src/Components/Action/Edit/ActionTab/ActionTab.tsx b/packages/tcore-console/src/Components/Action/Edit/ActionTab/ActionTab.tsx new file mode 100644 index 00000000..390f0db8 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Edit/ActionTab/ActionTab.tsx @@ -0,0 +1,196 @@ +import { IAction, IActionOption, IActionType } from "@tago-io/tcore-sdk/types"; +import Accordion from "../../../Accordion/Accordion"; +import FormGroup from "../../../FormGroup/FormGroup"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import VariableCondition from "../../../VariableCondition/VariableCondition"; +import ActionFields from "../../Common/ActionFields/ActionFields"; +import PluginConfigFields from "../../../Plugins/Common/PluginConfigFields/PluginConfigFields"; +import DeviceRadio from "../../Common/DeviceRadio/DeviceRadio"; +import * as Style from "./ActionTab.style"; + +/** + * Props. + */ +interface IActionTabProps { + /** + * Action's form data. + */ + data: IAction; + /** + */ + trigger: any; + /** + * Called when a field is changed. + */ + onChange: (field: keyof IAction, value: IAction[keyof IAction]) => void; + /** + */ + onChangeTrigger: (trigger: any) => void; + /** + * Additional options provided by plugins. + */ + options?: IActionOption[]; + option: any; + onChangeOption: any; + optionFields: any; + onChangeOptionFields: any; + device?: any; + tag?: any; + deviceType?: any; + onChangeDevice: any; + onChangeTag: any; + onChangeDeviceType: any; + types?: any; + errors: any; + /** + * Custom type selected. + */ + customType: IActionType; +} + +/** + * The action's `Action` tab. + */ +function ActionTab(props: IActionTabProps) { + const { + option, + onChangeOption, + optionFields, + onChangeOptionFields, + onChangeTag, + onChangeDeviceType, + onChangeDevice, + tag, + deviceType, + device, + data, + options, + trigger, + errors, + customType, + onChangeTrigger, + onChange, + } = props; + + const isCustomType = !!customType; + + /** + * Renders a section's title. + */ + const renderSectionTitle = (title: string) => { + return
{title}
; + }; + + /** + */ + const renderCustomLeftSectionContent = () => { + const configs = customType?.configs || []; + return ( + <> + {customType?.showDeviceSelector && ( + + )} + + + + ); + }; + + /** + * Renders the left section (`Triggers`) of the screen. + */ + const renderLeftSectionContent = () => { + if (isCustomType) { + return renderCustomLeftSectionContent(); + } + + return ( + <> + + +
+ + onChangeTrigger({ ...trigger, conditions: e })} + /> + +
+ + ); + }; + + /** + * Renders the left section (`Action`) of the screen. + */ + const renderRightSectionContent = () => { + return ( + <> +
+ + onChange("name", e.target.value)} + placeholder="Enter a name that describes the purpose of your action" + error={errors.name} + errorMessage="This field requires at least 3 characters" + /> + +
+ + + + ); + }; + + return ( + + + {renderSectionTitle("Trigger")} + {renderLeftSectionContent()} + + + + {renderSectionTitle("Action")} + {renderRightSectionContent()} + + + ); +} + +export default ActionTab; diff --git a/packages/tcore-console/src/Components/Action/Edit/MoreTab/MoreTab.tsx b/packages/tcore-console/src/Components/Action/Edit/MoreTab/MoreTab.tsx new file mode 100644 index 00000000..e1e096b9 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Edit/MoreTab/MoreTab.tsx @@ -0,0 +1,133 @@ +import { useCallback, useEffect, useState } from "react"; +import { useHistory } from "react-router"; +import { IAction } from "@tago-io/tcore-sdk/types"; +import Button from "../../../Button/Button"; +import { EButton } from "../../../Button/Button.types"; +import Col from "../../../Col/Col"; +import FormDivision from "../../../FormDivision/FormDivision"; +import FormGroup from "../../../FormGroup/FormGroup"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import Modal from "../../../Modal/Modal"; +import RelativeDate from "../../../RelativeDate/RelativeDate"; +import Row from "../../../Row/Row"; + +/** + * Props. + */ +interface IMoreTabProps { + /** + * Action's form data. + */ + data: IAction; + /** + * Called when the action was requested to be deleted. + */ + onDelete: () => Promise; +} + +/** + * The device edit page. + */ +function MoreTab(props: IMoreTabProps) { + const history = useHistory(); + const { data, onDelete } = props; + const [modalDelete, setModalDelete] = useState(false); + const [deleted, setDeleted] = useState(false); + + /** + * Confirms the delete request. + */ + const confirmDelete = useCallback(async () => { + await onDelete(); + setDeleted(true); + }, [onDelete]); + + /** + * Opens the delete modal. + */ + const activateModalDelete = useCallback(() => { + setModalDelete(true); + }, []); + + /** + * Closes the delete modal. + */ + const deactivateModalDelete = useCallback(() => { + setModalDelete(false); + }, []); + + /** + * Used to transfer the user back to the list page upon deleting the action. + */ + useEffect(() => { + if (deleted) { + history.push("/console/actions"); + } + }, [history, deleted]); + + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {modalDelete && ( + + Do you really want to delete this Action? there is no going back after this! + + )} +
+ ); +} + +export default MoreTab; diff --git a/packages/tcore-console/src/Components/Action/Helpers/normalizeType.ts b/packages/tcore-console/src/Components/Action/Helpers/normalizeType.ts new file mode 100644 index 00000000..d460a47c --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Helpers/normalizeType.ts @@ -0,0 +1,36 @@ +import { IActionOption } from "@tago-io/tcore-sdk/types"; + +/** + * Normalizes the action type values by removing unnecessary data and trimming + * existing fields. + */ +function normalizeOption(option: IActionOption | null, values: any): any { + if (option?.configs) { + // custom option selected + const newValues: any = {}; + for (const config of option.configs) { + if ("field" in config) { + newValues[config.field] = values[config.field] || null; + } + } + return newValues; + } else if (option?.id === "script") { + // run analysis option selected + const analyses = values?.analyses?.map((x: any) => x?.id) || [false]; + return { analyses }; + } else if (option?.id === "post") { + // make a post request + return { + url: values?.url || "", + headers: (values?.headers || []) + .filter((x: any) => x?.name) + .filter((x: any) => x.name !== "TagoIO-Retries"), + fallback_token: values?.fallback_token || "", + http_post_fallback_enabled: values?.http_post_fallback_enabled || false, + }; + } + + return values; +} + +export default normalizeOption; diff --git a/packages/tcore-console/src/Components/Action/Helpers/validateOption.ts b/packages/tcore-console/src/Components/Action/Helpers/validateOption.ts new file mode 100644 index 00000000..75a68645 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/Helpers/validateOption.ts @@ -0,0 +1,26 @@ +import { IActionOption } from "@tago-io/tcore-sdk/types"; +import validateConfigFields from "../../../Helpers/validateConfigFields"; +import normalizeOption from "./normalizeType"; + +/** + * Validates the action type (`action` field in the database). + */ +function validateOption(option: IActionOption | null, values: any): boolean { + let errors: any = {}; + let hasError = false; + const normalizedValues = normalizeOption(option, values); + + if (option?.configs) { + // custom option selected + errors = validateConfigFields(option.configs, normalizedValues); + hasError = errors ? true : false; + } else if (option?.id === "script") { + // run analysis option selected + errors.analyses = normalizedValues?.analyses?.map((x: string) => !x); + hasError = errors.analyses.some((x: any) => x === true); + } + + return hasError ? errors : null; +} + +export default validateOption; diff --git a/packages/tcore-console/src/Components/Action/List/ActionList.tsx b/packages/tcore-console/src/Components/Action/List/ActionList.tsx new file mode 100644 index 00000000..0e5335f9 --- /dev/null +++ b/packages/tcore-console/src/Components/Action/List/ActionList.tsx @@ -0,0 +1,104 @@ +import { useTheme } from "styled-components"; +import { useState } from "react"; +import { IAction, IActionOption } from "@tago-io/tcore-sdk/types"; +import BooleanStatus from "../../BooleanStatus/BooleanStatus"; +import Button from "../../Button/Button"; +import { EButton } from "../../Button/Button.types"; +import Icon from "../../Icon/Icon"; +import { EIcon } from "../../Icon/Icon.types"; +import ListPage from "../../ListPage/ListPage"; +import RelativeDate from "../../RelativeDate/RelativeDate"; +import ModalAddAction from "../Common/ModalAddAction/ModalAddAction"; +import useApiRequest from "../../../Helpers/useApiRequest"; +import getActionList from "../../../Requests/getActionList"; + +/** + * The device edit page. + */ +function ActionList() { + const { data } = useApiRequest("/action-types"); + const [modal, setModal] = useState(false); + const theme = useTheme(); + + /** + * Renders the action type. + */ + const renderActionType = (item: IAction) => { + const isCustom = String(item.action?.type).includes(":"); + if (isCustom) { + const type = data?.find((x) => x.id === item.action?.type); + return type?.name || "Unknown"; + } else if (item.action?.type === "script") { + return "Run Analysis"; + } else if (item.action?.type === "post") { + return "Post data to endpoint using HTTP"; + } else if (item.action?.type === "tagoio") { + return "Insert data into TagoIO"; + } else { + return "None"; + } + }; + + return ( + <> + + color={theme.action} + description="Actions give you total control over your devices based on events determined by you." + icon={EIcon.bolt} + path="actions" + innerNavTitle="Actions" + documentTitle="Actions" + onGetData={getActionList} + summaryKey="action" + columns={[ + { + id: "name", + label: "Name", + onRender: (item) => item.name, + type: "text", + }, + { + id: "action", + label: "Action", + onRender: renderActionType, + type: "text", + }, + { + flex: "none", + id: "active", + label: "Active", + onRender: (item) => , + type: "boolean", + width: 100, + }, + { + id: "last_triggered", + label: "Last triggered", + onRender: (item) => , + type: "date", + }, + { + id: "created_at", + label: "Created at", + onRender: (item) => , + type: "date", + }, + ]} + > + + + + {modal && setModal(false)} />} + + ); +} + +export default ActionList; diff --git a/packages/tcore-console/src/Components/Analysis/Common/AnalysisPicker/AnalysisPicker.tsx b/packages/tcore-console/src/Components/Analysis/Common/AnalysisPicker/AnalysisPicker.tsx new file mode 100644 index 00000000..1b9b7dde --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Common/AnalysisPicker/AnalysisPicker.tsx @@ -0,0 +1,74 @@ +import { IAnalysis, TGenericID } from "@tago-io/tcore-sdk/types"; +import { useCallback } from "react"; +import getAnalysisInfo from "../../../../Requests/getAnalysisInfo"; +import getAnalysisList from "../../../../Requests/getAnalysisList"; +import OptionsPicker from "../../../OptionsPicker/OptionsPicker"; + +/** + * Props. + */ +interface IAnalysisPicker { + /** + * Device object. + */ + value: IAnalysis | undefined; + /** + * Called when a new device gets picked. + */ + onChange: (value: IAnalysis) => void; + /** + * Indicates if the this field has an error. + */ + error?: boolean; + /** + * Position of the options container. Default is `bottom`. + */ + optionsPosition?: "top" | "bottom"; +} + +/** + */ +function AnalysisPicker(props: IAnalysisPicker) { + const { error, optionsPosition } = props; + + /** + * Retrieves the options. + */ + const onGetOptions = useCallback(async (query: string, page: number) => { + const result = await getAnalysisList(page, 20, { name: `*${query}*` }); + return result; + }, []); + + /** + * Resolves an option by an ID. + * This transforms the ID into an object. + */ + const resolveOptionByID = useCallback(async (id: string | number) => { + const analysis = await getAnalysisInfo(id as TGenericID); + return analysis; + }, []); + + /** + * Renders a single option row. + */ + const renderOption = useCallback((i) => { + return i.name; + }, []); + + return ( + + doesRequest + error={error} + labelField="name" + onChange={props.onChange} + onGetOptions={onGetOptions} + onRenderOption={renderOption} + onResolveOption={resolveOptionByID} + placeholder="Select an analysis" + optionsPosition={optionsPosition} + value={props.value} + /> + ); +} + +export default AnalysisPicker; diff --git a/packages/tcore-console/src/Components/Analysis/Common/AutomateTip/AutomateTip.style.ts b/packages/tcore-console/src/Components/Analysis/Common/AutomateTip/AutomateTip.style.ts new file mode 100644 index 00000000..18ae656a --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Common/AutomateTip/AutomateTip.style.ts @@ -0,0 +1,37 @@ +import styled from "styled-components"; + +/** + */ +export const Container = styled.div` + padding: 10px; + background: ${(props) => props.theme.background1}; + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 3px; + display: inline-block; + position: relative; + width: 100%; + color: rgb(70, 70, 70); + overflow: hidden; + + > .left-content { + width: calc(100% - 80px); + + > .title { + margin-bottom: 5px; + display: flex; + align-items: center; + + h2 { + font-weight: bold; + font-size: 1.1rem; + margin-left: 7px; + } + } + } + + > .right-content { + position: absolute; + right: -10px; + top: -5px; + } +`; diff --git a/packages/tcore-console/src/Components/Analysis/Common/AutomateTip/AutomateTip.tsx b/packages/tcore-console/src/Components/Analysis/Common/AutomateTip/AutomateTip.tsx new file mode 100644 index 00000000..f743ad7e --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Common/AutomateTip/AutomateTip.tsx @@ -0,0 +1,37 @@ +import { memo } from "react"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import Link from "../../../Link/Link"; +import * as Style from "./AutomateTip.style"; + +/** + */ +function AutomateTip() { + return ( + +
+
+ +

Automate your Analysis

+
+ +
+ If you want to trigger this Analysis based on a + time interval + , + schedule + or + data from devices + , you need to create an + Action. +
+
+ +
+ +
+
+ ); +} + +export default memo(AutomateTip); diff --git a/packages/tcore-console/src/Components/Analysis/Common/ModalAddAnalysis/ModalAddAnalysis.tsx b/packages/tcore-console/src/Components/Analysis/Common/ModalAddAnalysis/ModalAddAnalysis.tsx new file mode 100644 index 00000000..357736b5 --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Common/ModalAddAnalysis/ModalAddAnalysis.tsx @@ -0,0 +1,106 @@ +import { zName } from "@tago-io/tcore-sdk/types"; +import { MouseEvent, useCallback, useEffect, useState } from "react"; +import { useHistory } from "react-router"; +import { useTheme } from "styled-components"; +import createAnalysis from "../../../../Requests/createAnalysis"; +import FormGroup from "../../../FormGroup/FormGroup"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import Modal from "../../../Modal/Modal"; + +/** + */ +interface IModalAddAnalysis { + onClose: () => void; +} + +/** + * The modal to create a new analysis. + */ +function ModalAddAnalysis(props: IModalAddAnalysis) { + const theme = useTheme(); + const [name, setName] = useState(""); + const [newID, setNewID] = useState(""); + const [errors, setErrors] = useState({}); + const history = useHistory(); + const { onClose } = props; + + /** + * Validates the data of the analysis. + */ + const validate = useCallback(async () => { + const err: any = { + name: await zName + .parseAsync(name) + .then(() => false) + .catch(() => true), + }; + if (err.name) { + setErrors(err); + return false; + } + + return true; + }, [name]); + + /** + * Creates the analysis. + */ + const doRequest = useCallback(async () => { + const data = { + name: name, + active: true, + tags: [], + }; + + const response = await createAnalysis(data); + + setNewID(response); + }, [name]); + + /** + * Called when the confirm button is pressed. + */ + const confirm = useCallback( + async (e?: MouseEvent) => { + if (await validate()) { + await doRequest(); + } + e?.preventDefault(); + }, + [doRequest, validate] + ); + + /** + * Used to transfer the user to the newly created analysis. + */ + useEffect(() => { + if (newID) { + history.push(`/console/analysis/${newID}`); + } + }, [history, newID]); + + return ( + + + setName(e.target.value)} + placeholder="Enter a name that describes the purpose of your code" + value={name} + /> + + + ); +} + +export default ModalAddAnalysis; diff --git a/packages/tcore-console/src/Components/Analysis/Common/SaveAndRun/SaveAndRun.style.ts b/packages/tcore-console/src/Components/Analysis/Common/SaveAndRun/SaveAndRun.style.ts new file mode 100644 index 00000000..dd266cb5 --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Common/SaveAndRun/SaveAndRun.style.ts @@ -0,0 +1,14 @@ +import styled from "styled-components"; + +/** + */ +export const Container = styled.div` + display: inline-flex; + margin-right: 5px; + vertical-align: bottom; + + .cog-button { + margin-right: 5px; + padding: 5px 10px; + } +`; diff --git a/packages/tcore-console/src/Components/Analysis/Common/SaveAndRun/SaveAndRun.tsx b/packages/tcore-console/src/Components/Analysis/Common/SaveAndRun/SaveAndRun.tsx new file mode 100644 index 00000000..dcf65568 --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Common/SaveAndRun/SaveAndRun.tsx @@ -0,0 +1,42 @@ +import { memo } from "react"; +import Button from "../../../Button/Button"; +import * as Style from "./SaveAndRun.style"; + +/** + * Props. + */ +interface ISaveAndRunProps { + /** + * If only `run` should be written in the text. + */ + onlyRun: boolean; + /** + * Called when the button is clicked. + */ + onClick: () => void; + /** + * If the button is disabled or not. + */ + disabled: boolean; +} + +/** + * Button of "save and run" in the analysis edit screen. + */ +function SaveAndRun(props: ISaveAndRunProps) { + const { onlyRun, disabled, onClick } = props; + + return ( + + {/* Temporarily removed: */} + {/* */} + + + ); +} + +export default memo(SaveAndRun); diff --git a/packages/tcore-console/src/Components/Analysis/Edit/AnalysisEdit.test.tsx b/packages/tcore-console/src/Components/Analysis/Edit/AnalysisEdit.test.tsx new file mode 100644 index 00000000..1821057c --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Edit/AnalysisEdit.test.tsx @@ -0,0 +1,10 @@ +jest.mock("../../../Helpers/useApiRequest.ts"); +jest.mock("../../../System/Socket.ts"); + +import { render } from "../../../../utils/test-utils"; +import AnalysisEdit from "./AnalysisEdit"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); diff --git a/packages/tcore-console/src/Components/Analysis/Edit/AnalysisEdit.tsx b/packages/tcore-console/src/Components/Analysis/Edit/AnalysisEdit.tsx new file mode 100644 index 00000000..14c735c0 --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Edit/AnalysisEdit.tsx @@ -0,0 +1,273 @@ +import { ESocketResource, IAnalysis, ILog } from "@tago-io/tcore-sdk/types"; +import cloneDeep from "lodash.clonedeep"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { useRouteMatch } from "react-router"; +import { useTheme } from "styled-components"; +import { observer } from "mobx-react"; +import normalizeTags from "../../../Helpers/normalizeTags"; +import EditPage from "../../EditPage/EditPage"; +import { EIcon } from "../../Icon/Icon.types"; +import Switch from "../../Switch/Switch"; +import SaveAndRun from "../Common/SaveAndRun/SaveAndRun"; +import TagsTab from "../../Tags/TagsTab"; +import { socket } from "../../../System/Socket"; +import deleteAnalysis from "../../../Requests/deleteAnalysis"; +import editAnalysis from "../../../Requests/editAnalysis"; +import runAnalysis from "../../../Requests/runAnalysis"; +import store from "../../../System/Store"; +import AnalysisTab from "./AnalysisTab/AnalysisTab"; +import EnvVarsTab from "./EnvVarsTab/EnvVarsTab"; +import MoreTab from "./MoreTab/MoreTab"; + +/** + * The analysis' edit page. + */ +function AnalysisEdit() { + const match = useRouteMatch<{ id: string }>(); + const { id } = match.params; + + const theme = useTheme(); + const [data, setData] = useState({} as IAnalysis); + const [tabIndex, setTabIndex] = useState(0); + const [errors] = useState({}); + const [saveAndRunDisabled, setSaveAndRunDisabled] = useState(false); + const [logs, setLogs] = useState([]); + + const initialData = useRef({} as IAnalysis); + const loading = !data.id; + + /** + * Should return if the initial data is different from the current data. + */ + const checkIfDataChanged = useCallback(() => { + const initialDataNorm = { + ...initialData.current, + tags: normalizeTags(initialData.current.tags), + variables: normalizeTags(initialData.current.variables || []), + }; + const currentDataNorm = { + ...data, + tags: normalizeTags(data.tags), + variables: normalizeTags(data.variables || []), + }; + + return JSON.stringify(initialDataNorm) !== JSON.stringify(currentDataNorm); + }, [data]); + + /** + * Called when the record was fetched by the edit page. + * We use this to set the data state to manipulate the object. + */ + const onFetch = useCallback((analysis: IAnalysis) => { + setData(analysis); + setLogs(analysis.console?.reverse?.() || []); + initialData.current = cloneDeep(analysis); + }, []); + + /** + * Validates the form data to make sure the object is not faulty. + * This should return a boolean to indicate if the data is correct or not. + */ + const validate = useCallback(async () => { + return true; + }, []); + + /** + * Saves the analysis. + */ + const save = useCallback(async () => { + setSaveAndRunDisabled(true); + try { + const formatted = { + active: data.active, + binary_path: data.binary_path, + file_path: data.file_path, + id: data.id, + name: data.name, + options: data.options, + tags: normalizeTags(data.tags), + variables: normalizeTags(data.variables || []), + }; + + await editAnalysis(id, formatted); + + initialData.current = cloneDeep(data); + } finally { + setSaveAndRunDisabled(false); + } + }, [id, data]); + + /** + * Runs the analysis. + */ + const run = useCallback(async () => { + setSaveAndRunDisabled(true); + try { + await runAnalysis(id); + } finally { + setSaveAndRunDisabled(false); + } + }, [id]); + + /** + * Saves and runs the analysis. + */ + const saveAndRun = useCallback(async () => { + const dataChanged = checkIfDataChanged(); + if (dataChanged) { + await save(); + await run(); + } else { + await run(); + } + }, [checkIfDataChanged, save, run]); + + /** + * Deletes the analysis. + */ + const deleteData = useCallback(async () => { + await deleteAnalysis(id); + }, [id]); + + /** + * Clears the logs. + */ + const clearLogs = useCallback(() => { + setLogs([]); + }, []); + + /** + * Called when a field from a tab gets modified. + * This will apply the change to the data state. + */ + const onChangeData = useCallback( + (field: keyof IAnalysis, value) => { + setData({ ...data, [field]: value }); + }, + [data] + ); + + /** + * Renders the `Analysis` tab. + */ + const renderAnalysisTab = () => { + return ; + }; + + /** + * Renders the `Environment Variables` tab. + */ + const renderEnvVarsTab = () => { + return ; + }; + + /** + * Renders the `Tags` tab. + */ + const renderTagsTab = () => { + return ( + onChangeData("tags", tags)} + /> + ); + }; + + /** + * Renders the `More` tab. + */ + const renderMoreTab = () => { + return ; + }; + + /** + * Renders the right side of the inner nav. + */ + const renderInnerNav = useCallback(() => { + if (loading) { + // still loading + return null; + } + + return ( + onChangeData("active", e)}> + Active + + ); + }, [loading, onChangeData, data]); + + /** + * Renders the `Footer` tab. + */ + const renderFooter = useCallback(() => { + const dataChanged = checkIfDataChanged(); + const onlyRun = !dataChanged; + return ; + }, [saveAndRunDisabled, checkIfDataChanged, saveAndRun]); + + /** + */ + useEffect(() => { + function onLog(params: any) { + setLogs((x) => [params, ...x]); + } + + socket.on(`analysis:log:${id}`, onLog); + return () => { + socket.off(`analysis:log:${id}`, onLog); + }; + }); + + /** + */ + useEffect(() => { + if (store.socketConnected) { + socket.emit("attach", ESocketResource.analysis); + return () => { + socket.emit("detach", ESocketResource.analysis); + }; + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [store.socketConnected]); + + return ( + + color={theme.analysis} + documentTitle="Analysis" + icon={EIcon.code} + innerNavTitle={data.name || "Analysis"} + loading={loading} + onChangeTabIndex={setTabIndex} + onCheckIfDataChanged={checkIfDataChanged} + onFetch={onFetch} + onRenderFooter={renderFooter} + onRenderInnerNav={renderInnerNav} + onSave={save} + onValidate={validate} + requestPath="analysis" + tabIndex={tabIndex} + tabs={[ + { + label: "Analysis", + content: renderAnalysisTab(), + }, + { + label: "Environment Variables", + content: renderEnvVarsTab(), + }, + { + label: "Tags", + content: renderTagsTab(), + }, + { + label: "More", + content: renderMoreTab(), + }, + ]} + /> + ); +} + +export default observer(AnalysisEdit); diff --git a/packages/tcore-console/src/Components/Analysis/Edit/AnalysisTab/AnalysisTab.style.ts b/packages/tcore-console/src/Components/Analysis/Edit/AnalysisTab/AnalysisTab.style.ts new file mode 100644 index 00000000..898973a8 --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Edit/AnalysisTab/AnalysisTab.style.ts @@ -0,0 +1,45 @@ +import styled from "styled-components"; + +export const Container = styled.div` + flex: 1; + display: flex; + height: 100%; + flex: 1; + margin: -15px; + + > .data { + flex: none; + width: 550px; + padding: 15px; + overflow: auto; + } + + > .console { + flex: 1; + border-left: 1px solid rgba(0, 0, 0, 0.1); + height: 100%; + display: flex; + flex-direction: column; + position: relative; + } +`; + +export const ConsoleHeader = styled.div` + background: rgba(0, 0, 0, 0.04); + display: flex; + padding: 7px 10px; + align-items: center; + justify-content: space-between; + box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.1); + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + border-top: 1px solid rgba(0, 0, 0, 0.05); + + h2 { + font-size: 1.1rem; + font-weight: 500; + } + + button:first-child { + margin-right: 5px; + } +`; diff --git a/packages/tcore-console/src/Components/Analysis/Edit/AnalysisTab/AnalysisTab.tsx b/packages/tcore-console/src/Components/Analysis/Edit/AnalysisTab/AnalysisTab.tsx new file mode 100644 index 00000000..1fc4b0e7 --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Edit/AnalysisTab/AnalysisTab.tsx @@ -0,0 +1,112 @@ +import { IAnalysis, ILog } from "@tago-io/tcore-sdk/types"; +import { memo, useCallback } from "react"; +import downloadFile from "../../../../Helpers/download"; +import getDateTimeObject from "../../../../Helpers/getDateTimeObject"; +import Button from "../../../Button/Button"; +import { EButton } from "../../../Button/Button.types"; +import Console from "../../../Console/Console"; +import FlexRow from "../../../FlexRow/FlexRow"; +import FormGroup from "../../../FormGroup/FormGroup"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import ProgramFieldset from "../../../ProgramFieldset/ProgramFieldset"; +import AutomateTip from "../../Common/AutomateTip/AutomateTip"; +import * as Style from "./AnalysisTab.style"; + +/** + * Props. + */ +interface IAnalysisTabProps { + /** + * Analysis' form data + */ + data: IAnalysis; + /** + * Called when a field is changed. + */ + onChange: (field: keyof IAnalysis, value: IAnalysis[keyof IAnalysis]) => void; + /** + * Output logs for the analysis. + */ + logs: ILog[]; + /** + * Called when the logs are cleared. + */ + onClearLogs: () => void; +} + +/** + * The device edit page. + */ +function AnalysisTab(props: IAnalysisTabProps) { + const { data, logs, onClearLogs, onChange } = props; + + /** + * Downloads the logs in a `txt` file. + */ + const downloadLogs = useCallback(() => { + const mapped = logs.map((item) => { + const date = getDateTimeObject(item.timestamp)?.toFormat("yyyy-LL-dd HH:mm:ss.SSS"); + const message = String(item.message).trim(); + return `[${date}]: ${message}`; + }); + downloadFile(mapped.join("\n"), "txt", "console"); + }, [logs]); + + /** + * Renders the console header. + */ + const renderConsoleHeader = () => { + return ( + +
+

Console

+
+ + + + + + +
+ ); + }; + + return ( + +
+ + onChange("name", e.target.value)} + value={data.name} + placeholder="Enter the analysis' name" + /> + + + + + + + onChange("binary_path", e)} + onChangeFilePath={(e) => onChange("file_path", e)} + title="Code" + /> +
+ +
+ {renderConsoleHeader()} + +
+
+ ); +} + +export default memo(AnalysisTab); diff --git a/packages/tcore-console/src/Components/Analysis/Edit/EnvVarsTab/EnvVarsTab.tsx b/packages/tcore-console/src/Components/Analysis/Edit/EnvVarsTab/EnvVarsTab.tsx new file mode 100644 index 00000000..352a039d --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Edit/EnvVarsTab/EnvVarsTab.tsx @@ -0,0 +1,104 @@ +import { IAnalysis, IAnalysisVariable } from "@tago-io/tcore-sdk/types"; +import FormDivision from "../../../FormDivision/FormDivision"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import RowManipulatorTable from "../../../RowManipulatorTable/RowManipulatorTable"; + +/** + * Props. + */ +interface IEnvVarsTabProps { + data: IAnalysis; + onChange: (field: keyof IAnalysis, value: IAnalysisVariable[]) => void; +} + +/** + * The analysis' `Environment Variables` tab. + */ +function EnvVarsTab(props: IEnvVarsTabProps) { + const { data, onChange } = props; + const parameters = data.variables || []; + + /** + * Called when a field gets modified. + */ + const onChangeField = (field: keyof IAnalysisVariable, value: string, rowIndex: number) => { + if (!parameters[rowIndex]) { + parameters[rowIndex] = { key: "", value: "" }; // create the item if it doesn't exist + } + parameters[rowIndex][field] = value; + onChange("variables", [...parameters]); + }; + + /** + * Renders the key of the variable. + */ + const renderKey = (item: IAnalysisVariable, index: number) => { + return ( + onChangeField("key", e.target.value, index)} + placeholder="Enter the variable key (unique)" + /> + ); + }; + + /** + * Renders the value input. + */ + const renderValue = (item: IAnalysisVariable, index: number) => { + return ( + onChangeField("value", e.target.value, index)} + placeholder="Enter the variable value" + /> + ); + }; + + /** + * Adds a single row. + */ + const addItem = () => { + parameters.push({ key: "", value: "" }); + onChange("variables", [...parameters]); + }; + + /** + * Removes a single row. + */ + const removeItem = (index: number) => { + parameters.splice(index, 1); + onChange("variables", [...parameters]); + }; + + return ( +
+ + + + data={parameters} + onAddItem={addItem} + onRemoveItem={removeItem} + columns={[ + { + label: "Key", + tooltip: "The variable identifier", + onRender: renderKey, + }, + { + label: "Value", + tooltip: "The value of the variable", + onRender: renderValue, + }, + ]} + /> +
+ ); +} + +export default EnvVarsTab; diff --git a/packages/tcore-console/src/Components/Analysis/Edit/MoreTab/MoreTab.tsx b/packages/tcore-console/src/Components/Analysis/Edit/MoreTab/MoreTab.tsx new file mode 100644 index 00000000..523aad69 --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/Edit/MoreTab/MoreTab.tsx @@ -0,0 +1,132 @@ +import { IAnalysis } from "@tago-io/tcore-sdk/types"; +import { useCallback, useEffect, useState } from "react"; +import { useHistory } from "react-router"; +import Button from "../../../Button/Button"; +import { EButton } from "../../../Button/Button.types"; +import Col from "../../../Col/Col"; +import FormDivision from "../../../FormDivision/FormDivision"; +import FormGroup from "../../../FormGroup/FormGroup"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import Modal from "../../../Modal/Modal"; +import RelativeDate from "../../../RelativeDate/RelativeDate"; +import Row from "../../../Row/Row"; + +/** + * Props. + */ +interface IMoreTabProps { + /** + * Analysis' form data + */ + data: IAnalysis; + /** + * Called when the analysis was requested to be deleted. + */ + onDelete: () => Promise; +} + +/** + */ +function MoreTab(props: IMoreTabProps) { + const history = useHistory(); + const { data, onDelete } = props; + const [modalDelete, setModalDelete] = useState(false); + const [deleted, setDeleted] = useState(false); + + /** + * Confirms the delete request. + */ + const confirmDelete = useCallback(async () => { + await onDelete(); + setDeleted(true); + }, [onDelete]); + + /** + * Opens the delete modal. + */ + const activateModalDelete = useCallback(() => { + setModalDelete(true); + }, []); + + /** + * Closes the delete modal. + */ + const deactivateModalDelete = useCallback(() => { + setModalDelete(false); + }, []); + + /** + * Used to transfer the user back to the list page upon deleting the analysis. + */ + useEffect(() => { + if (deleted) { + history.push("/console/analysis"); + } + }, [history, deleted]); + + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {modalDelete && ( + + Do you really want to delete this Analysis? there is no going back after this! + + )} +
+ ); +} + +export default MoreTab; diff --git a/packages/tcore-console/src/Components/Analysis/List/AnalysisList.tsx b/packages/tcore-console/src/Components/Analysis/List/AnalysisList.tsx new file mode 100644 index 00000000..32bd264d --- /dev/null +++ b/packages/tcore-console/src/Components/Analysis/List/AnalysisList.tsx @@ -0,0 +1,77 @@ +import { IAnalysis } from "@tago-io/tcore-sdk/types"; +import { useState } from "react"; +import { useTheme } from "styled-components"; +import getAnalysisList from "../../../Requests/getAnalysisList"; +import BooleanStatus from "../../BooleanStatus/BooleanStatus"; +import Button from "../../Button/Button"; +import { EButton } from "../../Button/Button.types"; +import Icon from "../../Icon/Icon"; +import { EIcon } from "../../Icon/Icon.types"; +import ListPage from "../../ListPage/ListPage"; +import RelativeDate from "../../RelativeDate/RelativeDate"; +import ModalAddAnalysis from "../Common/ModalAddAnalysis/ModalAddAnalysis"; + +/** + * The device edit page. + */ +function AnalysisList() { + const [modal, setModal] = useState(false); + const theme = useTheme(); + + return ( + <> + + color={theme.analysis} + description="Implement scripts to analyze and manipulate data in real-time." + icon={EIcon.code} + path="analysis" + innerNavTitle="Analysis" + documentTitle="Analysis" + onGetData={getAnalysisList} + summaryKey="analysis" + columns={[ + { + id: "name", + label: "Name", + onRender: (item) => item.name, + type: "text", + }, + { + flex: "none", + id: "active", + label: "Active", + onRender: (item) => , + type: "boolean", + width: 100, + }, + { + id: "last_run", + label: "Last run", + onRender: (item) => , + type: "date", + }, + { + id: "created_at", + label: "Created at", + onRender: (item) => , + type: "date", + }, + ]} + > + + + + {modal && setModal(false)} />} + + ); +} + +export default AnalysisList; diff --git a/packages/tcore-console/src/Components/BooleanStatus/BooleanStatus.test.tsx b/packages/tcore-console/src/Components/BooleanStatus/BooleanStatus.test.tsx new file mode 100644 index 00000000..21326ba3 --- /dev/null +++ b/packages/tcore-console/src/Components/BooleanStatus/BooleanStatus.test.tsx @@ -0,0 +1,19 @@ +import { render, screen } from "../../../utils/test-utils"; +import BooleanStatus from "./BooleanStatus"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("renders correct text for value = `true`", async () => { + render(); + const text = screen.getByText("Yes"); + expect(text).toBeInTheDocument(); +}); + +test("renders correct text for value = `false`", async () => { + render(); + const text = screen.getByText("No"); + expect(text).toBeInTheDocument(); +}); diff --git a/packages/tcore-console/src/Components/BooleanStatus/BooleanStatus.tsx b/packages/tcore-console/src/Components/BooleanStatus/BooleanStatus.tsx new file mode 100644 index 00000000..ccba6867 --- /dev/null +++ b/packages/tcore-console/src/Components/BooleanStatus/BooleanStatus.tsx @@ -0,0 +1,26 @@ +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; + +/** + * Props. + */ +interface IBooleanStatusProps { + value?: boolean; +} + +/** + * Renders a ball and a text by its side. + * - If `value` is true then the ball will be green and the text will say Yes. + * - If `value` is false, then the ball will be red and the text will say No. + */ +function BooleanStatus(props: IBooleanStatusProps) { + const { value } = props; + return ( + <> + +  {value ? "Yes" : "No"} + + ); +} + +export default BooleanStatus; diff --git a/packages/tcore-console/src/Components/Bucket/Common/DataRetention/DataRetention.style.ts b/packages/tcore-console/src/Components/Bucket/Common/DataRetention/DataRetention.style.ts new file mode 100644 index 00000000..288aac8f --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Common/DataRetention/DataRetention.style.ts @@ -0,0 +1,88 @@ +import styled, { css } from "styled-components"; +import { fonts } from "../../../../theme"; +import * as SelectStyle from "../../../Select/Select.style"; +import * as InputStyle from "../../../Input/Input.style"; + +/** + * Main style of the component. + */ +export const Container = styled.div<{ disabled: boolean; isForever: boolean }>` + ${(props) => + props.disabled && + css` + opacity: 0.5; + pointer-events: none; + `} + + .form-group-content { + display: flex; + + ${InputStyle.Container} { + /* glue the input to the select */ + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-top-right-radius: 0; + flex: none; + margin-right: -1px; + text-align: center; + width: 150px; + } + + ${SelectStyle.Container} { + /* glue the select to the input */ + + ${(props) => + !props.isForever && + css` + /* only apply the top left if there is an input to glue to */ + border-top-left-radius: 0; + `} + + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + flex: 1; + height: 33px; + } + } +`; + +/** + * Banner style. + */ +export const Banner = styled.div` + display: flex; + flex-direction: column; + background: ${(props) => props.theme.background2}; + align-items: center; + justify-content: center; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + height: 220px; + opacity: 1; + transition: opacity 0.3s, height 0.3s; + overflow: hidden; + border: 1px solid rgba(0, 0, 0, 0.07); + margin-top: -1px; + padding: 30px; + text-align: center; + + .title { + font-size: ${fonts.medium}; + font-weight: bold; + } + + .sub-title { + font-size: ${fonts.default}; + margin-bottom: 10px; + margin-top: 3px; + } + + img { + max-width: 70px; + } + + a { + text-decoration: underline; + cursor: pointer; + } +`; diff --git a/packages/tcore-console/src/Components/Bucket/Common/DataRetention/DataRetention.tsx b/packages/tcore-console/src/Components/Bucket/Common/DataRetention/DataRetention.tsx new file mode 100644 index 00000000..35e3bba2 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Common/DataRetention/DataRetention.tsx @@ -0,0 +1,145 @@ +import { useCallback, useEffect, useRef } from "react"; +import retentionGIF from "../../../../../assets/images/retention.gif"; +import FormGroup from "../../../FormGroup/FormGroup"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import Select from "../../../Select/Select"; +import * as Style from "./DataRetention.style"; + +/** + * Props. + */ +interface IDataRetention { + /** + * Retention data. + */ + retention: any; + /** + * Called when a retention field changes. + */ + onChangeRetention: (newRetention: any) => void; + /** + */ + error?: boolean; + disabled?: boolean; +} + +/** + * Controls the data retention property of a device. + * This component shows some inputs to define the retention of the device and a visual + * representation below the inputs. + */ +function DataRetention(props: IDataRetention) { + const { retention, error, onChangeRetention } = props; + const isForever = retention.unit === "forever"; + const input = useRef(null); + + /** + * Renders the banner of the component. + */ + const renderBanner = () => { + const pluralDisplay = `${retention.value || 0} ${retention.unit}${ + retention.value === "1" ? "" : "s" + }`; + + return ( + <> + {retention.unit === "forever" ? ( + // forever retention + + Data retention strategy: + The data in the bucket will be kept forever. + + ) : ( + // custom retention + + Data retention strategy: + + All data older than {pluralDisplay} will be deleted from the bucket. + + data-retention + + )} + + ); + }; + + /** + * Called when the select changes values. + */ + const onChangeUnit = useCallback( + (e: React.ChangeEvent) => { + if (!retention.value) { + retention.value = "1"; + } + onChangeRetention({ ...retention, unit: e.target.value }); + }, + [retention, onChangeRetention] + ); + + /** + * This effect is used to focus the input after changing the unit. + */ + useEffect(() => { + if (input.current) { + input.current.focus(); + } + }, [retention?.unit]); + + return ( + + +
+ ); +} + +export default MoreTab; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/VariablesTab/VariablesTab.style.ts b/packages/tcore-console/src/Components/Bucket/Edit/VariablesTab/VariablesTab.style.ts new file mode 100644 index 00000000..56e7d00e --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/VariablesTab/VariablesTab.style.ts @@ -0,0 +1,11 @@ +import styled from "styled-components"; + +export const Buttons = styled.div` + display: flex; + justify-content: flex-end; + margin-bottom: 1rem; + + button { + white-space: nowrap; + } +`; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/VariablesTab/VariablesTab.tsx b/packages/tcore-console/src/Components/Bucket/Edit/VariablesTab/VariablesTab.tsx new file mode 100644 index 00000000..03cff098 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/VariablesTab/VariablesTab.tsx @@ -0,0 +1,91 @@ +import { IDeviceData, IDevice } from "@tago-io/tcore-sdk/types"; +import { memo, useCallback, useState } from "react"; +import Button from "../../../Button/Button"; +import { EButton } from "../../../Button/Button.types"; +import Col from "../../../Col/Col"; +import FormDivision from "../../../FormDivision/FormDivision"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import Row from "../../../Row/Row"; +import VariablesTable from "../../Common/VariablesTable/VariablesTable"; +import * as Style from "./VariablesTab.style"; + +/** + * Props. + */ +interface IVariablesTab { + /** + * Device object. + */ + data: IDevice; + /** + */ + onDeleteData: (ids: string[]) => Promise; + /** + */ + onReloadDataAmount: () => void; + /** + * Data amount in the device's bucket. + */ + dataAmount: number; +} + +/** + */ +function VariablesTab(props: IVariablesTab) { + const [selectedVariables, setSelectedVariables] = useState([]); + const [refetchID, setRefetchID] = useState(0); + const { data, dataAmount, onDeleteData } = props; + + /** + * Deletes the selected data. + */ + const deleteSelectedData = useCallback(async () => { + const ids = selectedVariables.map((x) => x.id); + setSelectedVariables([]); + await onDeleteData(ids); + setRefetchID(Date.now()); + }, [onDeleteData, selectedVariables]); + + return ( + <> + + + + + + + + {data.type === "mutable" && ( + + )} + + + + + setRefetchID(Date.now())} + refetchID={refetchID} + /> + + ); +} + +export default memo(VariablesTab); diff --git a/packages/tcore-console/src/Components/Bucket/Helpers/joinDataRetention.ts b/packages/tcore-console/src/Components/Bucket/Helpers/joinDataRetention.ts new file mode 100644 index 00000000..6c160eb0 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Helpers/joinDataRetention.ts @@ -0,0 +1,12 @@ +/** + * Joins the data retention into one single field. + */ +function joinBucketDataRetention(retention: any) { + if (retention.unit === "forever") { + return "forever"; + } else { + return `${retention.value} ${String(retention.unit).toLowerCase()}`; + } +} + +export default joinBucketDataRetention; diff --git a/packages/tcore-console/src/Components/Bucket/Helpers/separateDataRetention.ts b/packages/tcore-console/src/Components/Bucket/Helpers/separateDataRetention.ts new file mode 100644 index 00000000..3390f77b --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Helpers/separateDataRetention.ts @@ -0,0 +1,27 @@ +import { IDevice } from "@tago-io/tcore-sdk/types"; + +/** + * Separate the data retention fields into two separate fields. + */ +function separateDataRetention(device: IDevice) { + if (!device.data_retention || device.data_retention === "forever") { + return { value: "1", unit: "forever" }; + } else { + const splitted = String(device.data_retention) + .replace(/\s+/g, " ") + .trim() + .toLowerCase() + .replace("s", "") + .split(" "); + const firstPart = splitted[0]; + const secondPart = splitted[1]; + + if (["day", "week", "month", "quarter", "year"].indexOf(secondPart) >= 0) { + return { value: firstPart, unit: secondPart }; + } + } + + return { value: "1", unit: "month" }; +} + +export default separateDataRetention; diff --git a/packages/tcore-console/src/Components/Bucket/List/BucketList.tsx b/packages/tcore-console/src/Components/Bucket/List/BucketList.tsx new file mode 100644 index 00000000..0a2d1822 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/List/BucketList.tsx @@ -0,0 +1,65 @@ +import { useTheme } from "styled-components"; +import { IDevice } from "@tago-io/tcore-sdk/types"; +import { EIcon } from "../../Icon/Icon.types"; +import ListPage from "../../ListPage/ListPage"; +import RelativeDate from "../../RelativeDate/RelativeDate"; +import Capitalize from "../../Capitalize/Capitalize"; +import getDeviceList from "../../../Requests/getDeviceList"; +import getDeviceTypeName from "../../../Helpers/getDeviceTypeName"; +import ButtonDataAmount from "./ButtonDataAmount/ButtonDataAmount"; + +/** + * The bucket list page. + */ +function BucketList() { + const theme = useTheme(); + + return ( + + color={theme.bucket} + description="Buckets are where data from your devices is stored and accessed." + documentTitle="Buckets" + icon={EIcon.bucket} + innerNavTitle="Buckets" + onGetData={getDeviceList} + path="buckets" + summaryKey="device" + columns={[ + { + id: "name", + label: "Name", + onRender: (item) => item.name, + type: "text", + }, + { + flex: "none", + id: "data_amount", + label: "Data amount", + onRender: (item) => , + width: 180, + }, + { + id: "data_retention", + label: "Retain data for", + onRender: (item) => {item.data_retention || "forever"}, + }, + { + id: "type", + label: "Type", + onRender: (item) => getDeviceTypeName(item.type), + filterDisabled: true, + flex: "none", + width: 250, + }, + { + id: "created_at", + label: "Created at", + onRender: (item) => , + type: "date", + }, + ]} + /> + ); +} + +export default BucketList; diff --git a/packages/tcore-console/src/Components/Bucket/List/ButtonDataAmount/ButtonDataAmount.style.ts b/packages/tcore-console/src/Components/Bucket/List/ButtonDataAmount/ButtonDataAmount.style.ts new file mode 100644 index 00000000..d492f4bf --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/List/ButtonDataAmount/ButtonDataAmount.style.ts @@ -0,0 +1,23 @@ +import styled from "styled-components"; +import { darken } from "polished"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import Button, { IButtonProps } from "../../../Button/Button"; + +/** + * Main style of the component. + */ +export const Container = styled(Button)` + padding-top: 5px; + padding-bottom: 5px; + border: 0; + background-color: transparent; + width: 150px; + position: absolute; + + :hover { + background-color: ${(props) => darken(0.04, props.theme.bucket)}; + } + :active { + background-color: ${(props) => darken(0.08, props.theme.bucket)}; + } +`; diff --git a/packages/tcore-console/src/Components/Bucket/List/ButtonDataAmount/ButtonDataAmount.tsx b/packages/tcore-console/src/Components/Bucket/List/ButtonDataAmount/ButtonDataAmount.tsx new file mode 100644 index 00000000..ad61c324 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/List/ButtonDataAmount/ButtonDataAmount.tsx @@ -0,0 +1,62 @@ +import { IDevice } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; +import { useState } from "react"; +import { formatDataAmount } from "../../../../Helpers/formatDataAmount"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import * as Style from "./ButtonDataAmount.style"; + +/** + * Props. + */ +interface IButtonDataAmountProps { + /** + * Device object. + */ + device: IDevice; +} + +/** + * This is the button rendered in the `Data amount` column of each bucket row. + * It fetches the amount of data in the device when clicked. + */ +function ButtonDataAmount(props: IButtonDataAmountProps) { + const [value, setValue] = useState(); + const [loading, setLoading] = useState(false); + const { device } = props; + + /** + * Fetches the amount of data in the device and then re-renders this component. + */ + async function fetchAmount() { + try { + setLoading(true); + const response = await axios.get(`/device/${device.id}/data_amount`); + setValue(response.data?.result); + } finally { + setLoading(false); + } + } + + if (value !== undefined) { + return <>{formatDataAmount(value)}; + } + + return ( + { + e.stopPropagation(); + e.preventDefault(); + if (!loading) { + fetchAmount(); + } + }} + > + {!loading && } + {loading ? "Loading..." : "Show amount"} + + ); +} + +export default ButtonDataAmount; diff --git a/packages/tcore-console/src/Components/Button/Button.style.ts b/packages/tcore-console/src/Components/Button/Button.style.ts new file mode 100644 index 00000000..d24761ac --- /dev/null +++ b/packages/tcore-console/src/Components/Button/Button.style.ts @@ -0,0 +1,138 @@ +import styled, { css, DefaultTheme } from "styled-components"; +import { darken } from "polished"; +import * as IconStyle from "../Icon/Icon.style"; +import { EButton } from "./Button.types"; + +/** + * Props for the container. + */ +interface IContainerProps { + buttonType?: EButton; + theme: DefaultTheme; + color?: string; + addIconMargin?: boolean; +} + +/** + * Main style for the button component. + */ +export const Container = styled.button` + display: inline-flex; + padding: 8px 20px; + border-radius: 3px; + cursor: pointer; + outline: 0; + border: 1px solid transparent; + justify-content: center; + align-items: center; + + :disabled { + pointer-events: none; + opacity: 0.7; + color: ${(props) => props.theme.buttonDisabledFont} !important; + border-color: transparent; + background-color: ${(props) => props.theme.buttonDisabled}; + + * { + fill: ${(props) => props.theme.buttonDisabledFont} !important; + color: ${(props) => props.theme.buttonDisabledFont} !important; + } + } + + ${(props) => applyTypeCss(props)} + + ${(props) => + props.addIconMargin && + css` + ${IconStyle.Container} { + /* used to add a bit of margin between an icon and the text */ + margin-right: 5px; + } + `} +`; + +/** + * Returns the css for the button colors. + */ +function applyTypeCss(props: IContainerProps) { + let color = props.theme.buttonDefaultFont; + + let background = props.theme.buttonDefault; + let hoverBackground = null; + let activeBackground = null; + let hoverColor = null; + + // let borderColor = "rgba(0, 0, 0, 0.12)"; + let padding = "8px 20px"; + let width = "auto"; + + if (props.buttonType === EButton.primary) { + color = props.theme.buttonPrimaryFont; + background = props.theme.buttonPrimary; + // borderColor = "transparent"; + } else if (props.buttonType === EButton.danger) { + color = props.theme.buttonDangerFont; + background = props.theme.buttonDanger; + // borderColor = "transparent"; + } else if (props.buttonType === EButton.danger_outline) { + color = props.theme.buttonDanger; + background = "transparent"; + // borderColor = props.theme.buttonDanger; + hoverBackground = darken(0.04, props.theme.buttonDanger); + activeBackground = darken(0.08, props.theme.buttonDanger); + hoverColor = "white"; + } else if (props.buttonType === EButton.warning) { + color = props.theme.buttonWarningText; + background = props.theme.buttonWarning; + // borderColor = "transparent"; + } else if (props.buttonType === EButton.icon) { + padding = "8px 15px"; + width = "45px"; + } + + if (props.color) { + color = "white"; + background = props.color; + // borderColor = background; + } + + if (!hoverBackground) { + // if the hover background-color wasn't informed, use the default one but darker + hoverBackground = darken(0.04, background); + } + if (!activeBackground) { + // if the active background-color wasn't informed, use the default one but darker + activeBackground = darken(0.08, background); + } + if (!hoverColor) { + // if the hover color wasn't specified, use the default color + // hoverColor = color; + } + + return css` + color: ${color}; + background: ${background}; + border-color: transparent; + padding: ${padding}; + width: ${width}; + + * { + fill: ${color}; + color: ${color}; + } + + :hover { + background-color: ${hoverBackground}; + color: ${hoverColor}; + + * { + fill: ${hoverColor}; + color: ${hoverColor}; + } + } + + :active { + background-color: ${activeBackground}; + } + `; +} diff --git a/packages/tcore-console/src/Components/Button/Button.test.tsx b/packages/tcore-console/src/Components/Button/Button.test.tsx new file mode 100644 index 00000000..c539e988 --- /dev/null +++ b/packages/tcore-console/src/Components/Button/Button.test.tsx @@ -0,0 +1,41 @@ +import { fireEvent, render, screen } from "../../../utils/test-utils"; +import Button from "./Button"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(screen.getByText("Hello world")).toBeInTheDocument(); +}); + +test("passes className to inner DOM node", () => { + render( + + ); +} + +export default CopyButton; diff --git a/packages/tcore-console/src/Components/Device/Common/DeviceInputOutput.tsx b/packages/tcore-console/src/Components/Device/Common/DeviceInputOutput.tsx new file mode 100644 index 00000000..e7932801 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/DeviceInputOutput.tsx @@ -0,0 +1,41 @@ +import { useTheme } from "styled-components"; +import getDateTimeObject from "../../../Helpers/getDateTimeObject"; +import RelativeDate from "../../RelativeDate/RelativeDate"; + +/** + * Props. + */ +interface DeviceInputOutputProps { + value?: Date | string | number | null; + bold?: boolean; +} + +/** + * Renders the device last_input or last_output values in a relative format. The colors + * are adjusted based on how long ago the input/output happened. + */ +function DeviceInputOutput(props: DeviceInputOutputProps) { + const { value } = props; + const theme = useTheme(); + let color = theme.font; + + const hours3 = 10800000; // 3 hours in milliseconds + const hours6 = 21600000; // 6 hours in milliseconds + const day1 = 86400000; // 1 day in milliseconds + const day3 = day1 * 3; // 3 days in milliseconds + + const timestamp = getDateTimeObject(value)?.toMillis() || 0; + if (timestamp > Date.now() - hours3) { + color = theme.deviceInputOutput3Hours; + } else if (timestamp > Date.now() - hours6) { + color = theme.deviceInputOutput6Hours; + } else if (timestamp > Date.now() - day1) { + color = theme.deviceInputOutput1Day; + } else if (timestamp > Date.now() - day3) { + color = theme.deviceInputOutput3Days; + } + + return ; +} + +export default DeviceInputOutput; diff --git a/packages/tcore-console/src/Components/Device/Common/DevicePicker/DevicePicker.tsx b/packages/tcore-console/src/Components/Device/Common/DevicePicker/DevicePicker.tsx new file mode 100644 index 00000000..a55aac69 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/DevicePicker/DevicePicker.tsx @@ -0,0 +1,70 @@ +import { IDevice, TGenericID } from "@tago-io/tcore-sdk/types"; +import { useCallback } from "react"; +import getDeviceInfo from "../../../../Requests/getDeviceInfo"; +import getDeviceList from "../../../../Requests/getDeviceList"; +import OptionsPicker from "../../../OptionsPicker/OptionsPicker"; + +/** + * Props. + */ +interface IDevicePicker { + /** + * Device object. + */ + value?: IDevice; + /** + * Called when a new device gets picked. + */ + onChange: (value: IDevice) => void; + /** + * Indicates if this component has invalid data. + * If this is set to `true`, this component will get a red border. + */ + error?: boolean; +} + +/** + */ +function DevicePicker(props: IDevicePicker) { + const { value, error } = props; + + /** + * Retrieves the options. + */ + const onGetOptions = useCallback(async (query: string, page: number) => { + const devices = await getDeviceList(page, 20, query); + return devices; + }, []); + + /** + * Resolves an option by an ID. + * This transforms the ID into an object. + */ + const resolveOptionByID = useCallback(async (id: string | number) => { + const device = await getDeviceInfo(id as TGenericID); + return device; + }, []); + + /** + * Renders a single option row. + */ + const renderOption = useCallback((i) => { + return i.name; + }, []); + + return ( + + doesRequest + error={error} + labelField="name" + onChange={props.onChange} + onGetOptions={onGetOptions} + onRenderOption={renderOption} + onResolveOption={resolveOptionByID} + placeholder="Select a device" + value={value} + /> + ); +} + +export default DevicePicker; diff --git a/packages/tcore-console/src/Components/Device/Common/DeviceTypePicker/DeviceTypePicker.style.ts b/packages/tcore-console/src/Components/Device/Common/DeviceTypePicker/DeviceTypePicker.style.ts new file mode 100644 index 00000000..9b7917d5 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/DeviceTypePicker/DeviceTypePicker.style.ts @@ -0,0 +1,43 @@ +import styled from "styled-components"; + +/** + */ +export const Item = styled.div` + margin: 3px 0px; + + .icon-container { + width: 40px; + display: flex; + align-items: center; + justify-content: center; + margin-right: 7px; + flex: none; + + img { + width: 30px; + height: 30px; + object-fit: contain; + } + } + + > .content { + display: flex; + align-items: center; + + .info { + > .title { + font-weight: bold; + font-size: 0.88rem; + color: ${(props) => props.color || "inherit"}; + } + + > .description { + display: block; + font-size: 12px; + font-weight: 400; + margin: 0; + opacity: 0.7; + } + } + } +`; diff --git a/packages/tcore-console/src/Components/Device/Common/DeviceTypePicker/DeviceTypePicker.tsx b/packages/tcore-console/src/Components/Device/Common/DeviceTypePicker/DeviceTypePicker.tsx new file mode 100644 index 00000000..cf4cdbf5 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/DeviceTypePicker/DeviceTypePicker.tsx @@ -0,0 +1,112 @@ +import { useCallback } from "react"; +import { useTheme } from "styled-components"; +import getDeviceTypeName from "../../../../Helpers/getDeviceTypeName"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import OptionsPicker from "../../../OptionsPicker/OptionsPicker"; +import * as Style from "./DeviceTypePicker.style"; + +/** + * Props. + */ +interface IDeviceTypePicker { + /** + * Device type object. + */ + value?: any; + /** + * Called when a new device type gets picked. + */ + onChange: (value: any) => void; + /** + * Indicates if this component has invalid data. + * If this is set to `true`, this component will get a red border. + */ + error?: boolean; +} + +/** + * Options to be displayed in the component. + */ +const defaultOptions: any[] = [ + { + description: "Recommended for huge amounts of device and sensor data", + icon: EIcon.mountain, + id: "immutable", + name: getDeviceTypeName("immutable"), + }, + { + description: "Recommended for small amounts of data that can change", + icon: EIcon.cubes, + id: "mutable", + name: getDeviceTypeName("mutable"), + }, +]; + +/** + * Picker for the type of devices. + */ +function DeviceTypePicker(props: IDeviceTypePicker) { + const { error } = props; + const theme = useTheme(); + + /** + * Renders a single row. + */ + const renderOption = (item: any) => { + return ( + +
+
+ +
+ +
+
{item.name}
+
{item.description}
+
+
+
+ ); + }; + + /** + * Resolves an option by an ID. + * This transforms the ID into an object. + */ + const resolveOptionByID = useCallback(async (id: string | number) => { + const response = defaultOptions.find((x) => x.id === id); + return response; + }, []); + + /** + * Retrieves the options. + */ + const onGetOptions = useCallback((query: string, page: number) => { + if (page > 1) { + return []; + } + + return defaultOptions.filter((x) => { + return ( + String(x.description).toLowerCase().includes(query) || + String(x.name).toLowerCase().includes(query) + ); + }); + }, []); + + return ( + + doesRequest + labelField="name" + onChange={props.onChange} + onGetOptions={onGetOptions} + onRenderOption={renderOption} + onResolveOption={resolveOptionByID} + error={error} + value={props.value} + /> + ); +} + +export default DeviceTypePicker; diff --git a/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.style.tsx b/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.style.tsx new file mode 100644 index 00000000..f7141dec --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.style.tsx @@ -0,0 +1,112 @@ +import { darken } from "polished"; +import styled, { css } from "styled-components"; + +/** + * The main style container. + */ +export const Container = styled.div` + display: flex; + flex-direction: column; + border-top: 1px solid ${(props) => props.theme.fieldsetBorder}; + margin: 0px -15px; + flex: 1; + overflow: auto; + margin-bottom: -15px; +`; + +/** + * The header part of the inspector. + */ +export const Header = styled.div` + display: flex; + background: ${(props) => props.theme.tableHeader}; + padding: 7px 12px; + + > * { + margin: 0px 3px; + } +`; + +/** + */ +export const Body = styled.div<{ isEmpty: boolean }>` + flex: 1; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + position: relative; + overflow: auto; + background-color: hsl(0, 0%, 99%); + border-top: solid 1px hsla(0, 0%, 0%, 0.07); + border-bottom: solid 1px hsla(0, 0%, 0%, 0.07); + + * { + font-size: 1.1rem; + } + + ${(props) => + props.isEmpty && + css` + text-align: center; + `} +`; + +/** + */ +export const Item = styled.div` + border-top: 1px dotted rgba(0, 0, 0, 0.1); + margin-bottom: 10px; + padding-top: 5px; + cursor: pointer; + width: 100%; + + &:first-child { + border: 0; + } +`; + +/** + */ +export const Row = styled.div` + display: flex; + align-items: center; + padding: 0px 5px; + + div { + font-family: monospace; + font-size: 1rem; + white-space: nowrap; + } + + &:hover { + background-color: ${(props) => darken(0.04, props.color || props.theme.buttonDefault)}; + } + + > .time { + margin-right: 3px; + } + + > .title { + font-weight: bold; + } + + > .code-preview { + margin-left: 5px; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + color: hsl(208, 56%, 46%); + } +`; + +/** + */ +export const Code = styled.div` + white-space: pre-wrap; + font-size: 1rem; + font-family: monospace; + cursor: default; + padding-left: 30px; + background-color: rgba(0, 0, 0, 0.015); +`; diff --git a/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.tsx b/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.tsx new file mode 100644 index 00000000..04daf1de --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.tsx @@ -0,0 +1,230 @@ +import { memo, useCallback, useEffect, useState } from "react"; +import { useTheme } from "styled-components"; +import { ILiveInspectorMessage } from "@tago-io/tcore-sdk/types"; +import downloadFile from "../../../../Helpers/download"; +import getDateTimeObject from "../../../../Helpers/getDateTimeObject"; +import Button from "../../../Button/Button"; +import { EButton } from "../../../Button/Button.types"; +import EmptyMessage from "../../../EmptyMessage/EmptyMessage"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import InputRadio from "../../../InputRadio/InputRadio"; +import Tooltip from "../../../Tooltip/Tooltip"; +import * as Style from "./LiveInspector.style"; +import LiveInspectorRow from "./LiveInspectorRow"; + +/** + * Props. + */ +interface ILiveInspectorProps { + /** + * Indicates if the live inspector is enabled or not. + */ + enabled: boolean; + /** + * Limit amount of records. + */ + limit: number; + /** + * Logs of the inspector. + */ + logs: { [key: string]: ILiveInspectorMessage[] }; + /** + * Called when the limit changes. + */ + onChangeLimit: (newLimit: number) => void; + /** + * Called when the enabled status changes. + */ + onChangeEnabled: (enabled: boolean) => void; + /** + * Called when the console is cleared. + */ + onClear: () => void; +} + +/** + */ +function LiveInspector(props: ILiveInspectorProps) { + const [filter, setFilter] = useState(""); + const [logsFiltered, setLogsFiltered] = useState([]); + const { enabled, limit, logs, onClear, onChangeEnabled, onChangeLimit } = props; + const theme = useTheme(); + + /** + * Downloads the logs in a `txt` file. + */ + const downloadLogs = useCallback(() => { + const mapped = []; + for (const item of logsFiltered) { + for (const subItem of item) { + const format = "yyyy-LL-dd HH:mm:ss.SSS"; + const date = getDateTimeObject(subItem.timestamp)?.toFormat(format); + const content = subItem.content; + mapped.push(`[${date}]: ${subItem.title} ${content}`); + } + mapped.push("------"); + } + + downloadFile(mapped.join("\n"), "txt", "console"); + }, [logsFiltered]); + + /** + */ + const filterLogs = useCallback(() => { + const result: any = {}; + + Object.keys(logs).forEach((key: string) => { + result[key] = logs[key].filter((item: any) => { + const filterLowerCase = filter.toLowerCase(); + const content = (String(item.content) || "").toLowerCase(); + const timestamp = (String(item.timestamp) || "").toLowerCase(); + const title = (String(item.title) || "").toLowerCase(); + return ( + !filter || + content.includes(filterLowerCase) || + timestamp.includes(filterLowerCase) || + title.includes(filterLowerCase) + ); + }); + + if (!result[key].length) { + delete result[key]; + } + }); + + const array = Object.keys(result).map((key) => result[key]); + + const sorted = array + .sort((a, b) => { + return new Date(b[0].timestamp).getTime() - new Date(a[0].timestamp).getTime(); + }) + .slice(0, limit); + + return sorted; + }, [filter, limit, logs]); + + /** + * Renders the header of the live inspector. + */ + const renderHeader = () => { + return ( + + setFilter(e.target.value)} + /> + + onChangeLimit(Number(e))} + options={[ + { label: "25", value: "25" }, + { label: "50", value: "50" }, + { label: "100", value: "100" }, + { label: "500", value: "500" }, + ]} + /> + + + + + + + + + + + + ); + }; + + /** + * Renders the empty message in the middle of the component. + * This should only be called when there is no data (logs) in the component. + */ + const renderEmptyMessage = () => { + return ( + +
Nothing yet.
+
Waiting for data to arrive...
+ + ) : ( + <> +
Nothing yet.
+
+ Press to start the inspector. +
+ + ) + } + /> + ); + }; + + /** + * Renders all the lines of the log. + */ + const renderLogs = () => { + return logsFiltered.map((x, i) => ( + + {x.map((item: ILiveInspectorMessage, index: number) => { + const key = `${item.connection_id}${index}`; + return ( + + ); + })} + + )); + }; + + /** + * Renders the body of the live inspector. + */ + const renderBody = () => { + const hasLogs = Object.keys(logsFiltered).length > 0; + return ( + {hasLogs ? renderLogs() : renderEmptyMessage()} + ); + }; + + /** + * Resets the filtered array when a new data arrives on when one of the filter changes. + */ + useEffect(() => { + const filtered = filterLogs(); + setLogsFiltered(filtered); + }, [filterLogs, logs]); + + return ( + + {renderHeader()} + {renderBody()} + + ); +} + +export default memo(LiveInspector); diff --git a/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.types.ts b/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.types.ts new file mode 100644 index 00000000..e6c87eb1 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspector.types.ts @@ -0,0 +1,9 @@ +import { ILiveInspectorMessage } from "@tago-io/tcore-sdk/types"; + +export interface IInspectorData { + enabled: boolean; + limit: number; + logs: { + [key: string]: ILiveInspectorMessage[]; + }; +} diff --git a/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspectorRow.tsx b/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspectorRow.tsx new file mode 100644 index 00000000..7fd76c45 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/LiveInspector/LiveInspectorRow.tsx @@ -0,0 +1,62 @@ +import { memo, useState } from "react"; +import Icon from "../../../Icon/Icon"; +import getDateTimeObject from "../../../../Helpers/getDateTimeObject"; +import { EIcon } from "../../../Icon/Icon.types"; +import * as Style from "./LiveInspector.style"; + +/** + * Props of the LiveInspectorRow. + */ +interface ILiveInspectorRow { + /** + * Content of content to the inspect. + */ + content: string; + /** + * Time of the content + */ + timestamp: number; + /** + * Title of the content + */ + title: string; + /** + * id of the value + */ + id: string; +} + +const stateMemory: { [key: string]: boolean } = {}; + +/** + */ +function LiveInspectorRow(props: ILiveInspectorRow) { + const { content, timestamp, title, id } = props; + const [expand, setExpand] = useState(stateMemory[id] || false); + + let code = props.content; + try { + if (typeof content === "object") { + code = JSON.stringify(content, null, 4); + } else { + code = JSON.stringify(JSON.parse(content), null, 4); + } + } catch (e) { + code = JSON.stringify(content); + } + + return ( + <> + setExpand((stateMemory[id] = !expand))}> + +
[{getDateTimeObject(timestamp)?.toFormat("HH:mm:ss")}]
+
{title}:
+
{code}
+
+ + {expand && {code}} + + ); +} + +export default memo(LiveInspectorRow); diff --git a/packages/tcore-console/src/Components/Device/Common/ModalAddDevice/ModalAddDevice.tsx b/packages/tcore-console/src/Components/Device/Common/ModalAddDevice/ModalAddDevice.tsx new file mode 100644 index 00000000..36e81a29 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/ModalAddDevice/ModalAddDevice.tsx @@ -0,0 +1,124 @@ +import { MouseEvent, useCallback, useEffect, useState } from "react"; +import { useHistory } from "react-router"; +import { useTheme } from "styled-components"; +import { zName } from "@tago-io/tcore-sdk/types"; +import FormGroup from "../../../FormGroup/FormGroup"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import Modal from "../../../Modal/Modal"; +import BucketTypePicker from "../DeviceTypePicker/DeviceTypePicker"; +import createDevice from "../../../../Requests/createDevice"; +import DataRetention from "../../../Bucket/Common/DataRetention/DataRetention"; +import joinBucketDataRetention from "../../../Bucket/Helpers/joinDataRetention"; + +/** + * Props. + */ +interface IModalAddDeviceProps { + onClose: () => void; +} + +/** + * The device's wizard modal. + */ +function ModalAddDevice(props: IModalAddDeviceProps) { + const [name, setName] = useState(""); + const [type, setType] = useState("immutable"); + const [retention, setRetention] = useState({ value: "1", unit: "forever" }); + const [newID, setNewID] = useState(""); + const [errors, setErrors] = useState({}); + const history = useHistory(); + const theme = useTheme(); + + const { onClose } = props; + + /** + * Validates the data of the device. + */ + const validate = useCallback(async () => { + const err: any = { + name: !zName.safeParse(name).success, + data_retention: retention.unit !== "forever" && (!retention.value || !retention.unit), + type: !type?.id, + }; + + if (err.name || err.data_retention || err.type) { + setErrors(err); + return false; + } + + return true; + }, [name, type?.id, retention]); + + /** + * Creates the device. + */ + const doRequest = useCallback(async () => { + const data = { + name: name, + data_retention: joinBucketDataRetention(retention), + type: type?.id, + }; + + const response = await createDevice(data); + + setNewID(response.device_id); + }, [name, type?.id, retention]); + + /** + * Called when the confirm button is pressed. + */ + const confirm = useCallback( + async (e?: MouseEvent) => { + if (await validate()) { + await doRequest(); + } + e?.preventDefault(); + }, + [doRequest, validate] + ); + + /** + * Used to transfer the user to the newly created device. + */ + useEffect(() => { + if (newID) { + history.push(`/console/devices/${newID}`); + } + }, [history, newID]); + + return ( + + + setName(e.target.value)} + placeholder="Enter a name for this device" + value={name} + /> + + + + + + + + + ); +} + +export default ModalAddDevice; diff --git a/packages/tcore-console/src/Components/Device/Common/PayloadParser/PayloadParser.style.ts b/packages/tcore-console/src/Components/Device/Common/PayloadParser/PayloadParser.style.ts new file mode 100644 index 00000000..4f604550 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/PayloadParser/PayloadParser.style.ts @@ -0,0 +1,62 @@ +import styled from "styled-components"; + +/** + * The main style container. + */ +export const Container = styled.fieldset` + border: 1px solid ${(props) => props.theme.fieldsetBorder}; + margin: 0; + + .fields { + display: flex; + + .input-container { + position: relative; + flex: 1; + margin-right: -1px; + + input { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + } + + button { + flex: none; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } +`; + +/** + * The main style container. + */ +export const Description = styled.span` + color: ${(props) => props.theme.font2}; + margin-bottom: 1rem; + display: inline-block; +`; + +/** + */ +export const IconContainer = styled.div` + position: absolute; + right: 10px; + z-index: 4; + top: 50%; + transform: translate(0%, -50%); + padding: 5px; + border-radius: 3px; + display: flex; + align-items: center; + + cursor: pointer; + + &:hover { + background: rgba(0, 0, 0, 0.07); + } + &:active { + background: rgba(0, 0, 0, 0.14); + } +`; diff --git a/packages/tcore-console/src/Components/Device/Common/PayloadParser/PayloadParser.tsx b/packages/tcore-console/src/Components/Device/Common/PayloadParser/PayloadParser.tsx new file mode 100644 index 00000000..7f7e4bf9 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/PayloadParser/PayloadParser.tsx @@ -0,0 +1,63 @@ +import { IDevice } from "@tago-io/tcore-sdk/types"; +import { useCallback } from "react"; +import FileSelect from "../../../FileSelect/FileSelect"; +import FormGroup from "../../../FormGroup/FormGroup"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import * as Style from "./PayloadParser.style"; + +/** + * Props. + */ +interface IPayloadParserProps { + /** + * Device's form data. + */ + data: IDevice; + /** + * Called when a field is changed. + */ + onChange: (field: keyof IDevice, value: IDevice[keyof IDevice]) => void; +} + +/** + * Payload parser field, located in the device edit screen. + */ +function PayloadParser(props: IPayloadParserProps) { + const { data, onChange } = props; + + /** + * Closes the file selector modal. + */ + const setPayloadParser = useCallback( + (filePath: string) => { + onChange("payload_parser", filePath); + }, + [onChange] + ); + + return ( + + + + Payload parser + + + + Payload Parser is a code which will run when your device makes a POST request. You can post + process your data by adding a javascript file. + + + + setPayloadParser(e)} + placeholder="Select a .js file to parse incoming data" + value={data.payload_parser || ""} + accept=".js" + /> + + + ); +} + +export default PayloadParser; diff --git a/packages/tcore-console/src/Components/Device/Common/TokenTable/TokenTable.style.ts b/packages/tcore-console/src/Components/Device/Common/TokenTable/TokenTable.style.ts new file mode 100644 index 00000000..544c657b --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/TokenTable/TokenTable.style.ts @@ -0,0 +1,39 @@ +import styled from "styled-components"; +import * as FormGroupStyle from "../../../FormGroup/FormGroup.style"; +import * as SimpleTableStyle from "../../../SimpleTable/SimpleTable.style"; + +/** + * Main style for the token table. + */ +export const Container = styled.div` + height: 250px; + + .buttons { + /* these are the buttons of each row */ + flex: none; + width: 100%; + display: flex; + justify-content: center; + padding: 5px 0px; + + button { + margin: 0px 3px; + } + } + + ${FormGroupStyle.Container} { + width: 100%; + margin-bottom: 0; + + button { + /* make the 'generate' button stretch to match the form group */ + width: 100%; + border: 0; + } + } + + ${SimpleTableStyle.Container} { + /* make the table follow the height of this container */ + height: 100%; + } +`; diff --git a/packages/tcore-console/src/Components/Device/Common/TokenTable/TokenTable.tsx b/packages/tcore-console/src/Components/Device/Common/TokenTable/TokenTable.tsx new file mode 100644 index 00000000..8f8c79f2 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Common/TokenTable/TokenTable.tsx @@ -0,0 +1,176 @@ +import { IDevice, IDeviceToken } from "@tago-io/tcore-sdk/types"; +import { useCallback, useEffect, useState, memo } from "react"; +import copyToClipboard from "../../../../Helpers/copyToClipboard"; +import Button from "../../../Button/Button"; +import { EButton } from "../../../Button/Button.types"; +import CopyButton from "../../../CopyButton/CopyButton"; +import FormGroup from "../../../FormGroup/FormGroup"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import SimpleTable from "../../../SimpleTable/SimpleTable"; +import Tooltip from "../../../Tooltip/Tooltip"; +import * as Style from "./TokenTable.style"; + +/** + * Props. + */ +interface ITokenTableProps { + /** + * Device's form data. + */ + data: IDevice; + /** + * Tokens of the device. + */ + tokens: IDeviceToken[]; + /** + * Called when the tokens change. + */ + onChangeTokens: (tokens: IDeviceToken[]) => void; + /** + * Called when a new token needs to be generated. + */ + onGenerateToken: (data: IDeviceToken) => Promise; + /** + * Called when a token needs to be deleted. + */ + onDeleteToken: (token: string) => Promise; +} + +/** + * The token & serial number table of a device. + */ +function TokenTable(props: ITokenTableProps) { + const [name, setName] = useState("Token #1"); + const [error, setError] = useState(false); + const [loading, setLoading] = useState(false); + const { tokens, onDeleteToken, onGenerateToken, onChangeTokens } = props; + + /** + * Renders the input in the header. + */ + const renderTokenLabel = () => { + return ( + + setName(e.target.value)} + placeholder="Token #1" + value={name} + /> + + ); + }; + + /** + * Renders the `Generate` button in the header. + */ + const renderButtonsLabel = () => { + return ( +  }> + + + ); + }; + + /** + * Returns the sequential name for the next token. + */ + const getSequentialName = useCallback(() => { + return `Token #${tokens.length + 1}`; + }, [tokens.length]); + + /** + * Removes an item from this table. + */ + const removeItem = async (index: number) => { + const item = tokens[index]; + await onDeleteToken(item.token as string); + tokens.splice(index, 1); + props.onChangeTokens([...tokens]); + }; + + /** + * Called when the `Generate token` button is pressed. + * This function generates a new token and appends it to the token array. + */ + const generateToken = async () => { + if (!name) { + setError(true); + return; + } + + setError(false); + setLoading(true); + + const token: any = { + device_id: props.data.id, + expire_time: "never", + name, + permission: "full", + serie_number: "", + }; + + const response = await onGenerateToken(token); + token.token = response.token; + + onChangeTokens([...tokens, token]); + setName(getSequentialName()); + setLoading(false); + }; + + /** + * Renders the buttons cell of each row. + */ + const renderButtons = (token: IDeviceToken, index: number) => { + return ( +
+ + + + + copyToClipboard(token.token)} /> +
+ ); + }; + + /** + * Used to adjust the header name based on the amount of tokens. + */ + useEffect(() => { + setName(getSequentialName()); + }, [getSequentialName]); + + return ( + + + data={tokens} + useAlternateRowColor + emptyMessageIcon={EIcon.cube} + emptyMessage="No tokens yet." + columns={[ + { + key: "label", + label: renderTokenLabel(), + onRender: (token) => token.name, + }, + { + key: "buttons", + label: renderButtonsLabel(), + flex: "none", + width: 145, + onRender: renderButtons, + }, + ]} + /> + + ); +} + +export default memo(TokenTable); diff --git a/packages/tcore-console/src/Components/Device/Edit/ConfigParametersTab/ConfigParametersTab.tsx b/packages/tcore-console/src/Components/Device/Edit/ConfigParametersTab/ConfigParametersTab.tsx new file mode 100644 index 00000000..63c76ab8 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/ConfigParametersTab/ConfigParametersTab.tsx @@ -0,0 +1,147 @@ +import { IDeviceParameter } from "@tago-io/tcore-sdk/types"; +import { useTheme } from "styled-components"; +import FormDivision from "../../../FormDivision/FormDivision"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import RowManipulatorTable from "../../../RowManipulatorTable/RowManipulatorTable"; +import Switch from "../../../Switch/Switch"; +import { ESwitchSize } from "../../../Switch/Switch.types"; + +/** + * Props. + */ +interface IConfigParametersTabProps { + /** + * Array of parameters from the device. + */ + params?: IDeviceParameter[]; + /** + * Device's form errors. + */ + errors: any; + /** + * Called when the params change. + */ + onChangeParams: (value: IDeviceParameter[]) => void; +} + +/** + * The device's `Configuration Parameters` tab. + */ +function ConfigParametersTab(props: IConfigParametersTabProps) { + const { errors, onChangeParams } = props; + const params = props.params || []; + const theme = useTheme(); + + /** + * Called when a field gets modified. + */ + const onChangeField = ( + field: keyof IDeviceParameter, + value: string | boolean, + rowIndex: number + ) => { + if (!params[rowIndex]) { + params[rowIndex] = { key: "", value: "", sent: false } as any; // create the item if it doesn't exist + } + (params[rowIndex] as any)[field] = value; + onChangeParams([...params]); + }; + + /** + * Renders the status switch. + */ + const renderStatus = (item: IDeviceParameter, index: number) => { + return ( +
+ onChangeField("sent", e, index)} + size={ESwitchSize.big} + selectedText="Read" + unselectedText="Unread" + selectedColor={theme.switchBigSelected} + unselectedColor={theme.switchBigUnselected} + /> +
+ ); + }; + + /** + * Renders the key of the parameter. + */ + const renderKey = (item: IDeviceParameter, index: number) => { + const error = errors?.parameters?.[index]?.key; + return ( + onChangeField("key", e.target.value, index)} + placeholder="Key of the parameter (unique)" + value={item.key || ""} + /> + ); + }; + + /** + * Renders the value input. + */ + const renderValue = (item: IDeviceParameter, index: number) => { + const error = errors?.parameters?.[index]?.value; + return ( + onChangeField("value", e.target.value, index)} + placeholder="Value of the parameter" + value={item.value || ""} + /> + ); + }; + + /** + */ + const addItem = () => { + params.push({ key: "", value: "", sent: false } as any); + onChangeParams([...params]); + }; + + /** + */ + const removeItem = (index: number) => { + params.splice(index, 1); + onChangeParams([...params]); + }; + + return ( +
+ + + + data={params} + onAddItem={addItem} + onRemoveItem={removeItem} + columns={[ + { + label: "Status", + flex: "none", + width: "105px", + onRender: renderStatus, + }, + { + label: "Key", + onRender: renderKey, + }, + { + label: "Value", + onRender: renderValue, + }, + ]} + /> +
+ ); +} + +export default ConfigParametersTab; diff --git a/packages/tcore-console/src/Components/Device/Edit/DeviceEdit.test.tsx b/packages/tcore-console/src/Components/Device/Edit/DeviceEdit.test.tsx new file mode 100644 index 00000000..1c162b9b --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/DeviceEdit.test.tsx @@ -0,0 +1,10 @@ +jest.mock("../../../Helpers/useApiRequest.ts"); +jest.mock("../../../System/Socket.ts"); + +import { render } from "../../../../utils/test-utils"; +import DeviceEdit from "./DeviceEdit"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); diff --git a/packages/tcore-console/src/Components/Device/Edit/DeviceEdit.tsx b/packages/tcore-console/src/Components/Device/Edit/DeviceEdit.tsx new file mode 100644 index 00000000..0691d1c6 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/DeviceEdit.tsx @@ -0,0 +1,437 @@ +import { + ESocketResource, + IDevice, + ILiveInspectorMessage, + IDeviceParameter, + IDeviceToken, + zDevice, + zDeviceParameter, + IPluginClassListItem, +} from "@tago-io/tcore-sdk/types"; +import cloneDeep from "lodash.clonedeep"; +import { useEffect, useCallback, useState, useRef } from "react"; +import { useRouteMatch } from "react-router"; +import { useTheme } from "styled-components"; +import { z } from "zod"; +import { observer } from "mobx-react"; +import normalizeTags from "../../../Helpers/normalizeTags"; +import useApiRequest from "../../../Helpers/useApiRequest"; +import buildZodError from "../../../Validation/buildZodError"; +import EditPage from "../../EditPage/EditPage"; +import Icon from "../../Icon/Icon"; +import { EIcon } from "../../Icon/Icon.types"; +import Switch from "../../Switch/Switch"; +import TagsTab from "../../Tags/TagsTab"; +import DeviceInputOutput from "../Common/DeviceInputOutput"; +import normalizeConfigParameters from "../Helpers/normalizeConfigParameters"; +import { IInspectorData } from "../Common/LiveInspector/LiveInspector.types"; +import { socket } from "../../../System/Socket"; +import setDeviceParams from "../../../Requests/setDeviceParams"; +import createDeviceToken from "../../../Requests/createDeviceToken"; +import deleteDevice from "../../../Requests/deleteDevice"; +import deleteDeviceToken from "../../../Requests/deleteDeviceToken"; +import editDevice from "../../../Requests/editDevice"; +import { setLocalStorageAsJSON } from "../../../Helpers/localStorage"; +import getDeviceTypeName from "../../../Helpers/getDeviceTypeName"; +import ConfigParametersTab from "./ConfigParametersTab/ConfigParametersTab"; +import GeneralInformationTab from "./GeneralInformationTab/GeneralInformationTab"; +import LiveInspectorTab from "./LiveInspectorTab/LiveInspectorTab"; +import MoreTab from "./MoreTab/MoreTab"; + +/** + * The device's edit page. + */ +function DeviceEdit() { + const match = useRouteMatch<{ id: string }>(); + const { id } = match.params; + + const theme = useTheme(); + const [data, setData] = useState({} as IDevice); + const [tabIndex, setTabIndex] = useState(0); + const [errors, setErrors] = useState({}); + const [params, setParams] = useState(); + const [tokens, setTokens] = useState(); + const [inspectorData, setInspectorData] = useState({ + enabled: false, + limit: 25, + logs: {}, + }); + const { data: encoderModules } = useApiRequest("/module?type=encoder"); + const { data: apiTokens, mutate: mutateApiTokens } = useApiRequest( + `/device/token/${id}` + ); + const { data: apiParams, mutate: mutateApiParams } = useApiRequest( + `/device/${id}/params` + ); + const initialData = useRef({} as IDevice); + const intervalInspectorAttach = useRef(null); + + const loading = !encoderModules || !data.id || !tokens || !params; + + /** + * Called when the record was fetched by the edit page. + * We use this to set the data state to manipulate the object. + */ + const onFetch = useCallback((device: IDevice) => { + setData(device); + initialData.current = cloneDeep(device); + }, []); + + /** + * Validates the form data to make sure the object is not faulty. + * This should return a boolean to indicate if the data is correct or not. + */ + const validate = useCallback(async () => { + try { + await z + .object({ + parameters: z.array((zDeviceParameter as any).omit({ id: true })), + }) + .parseAsync({ + parameters: normalizeConfigParameters(params), + }); + } catch (ex: any) { + const err = buildZodError(ex.issues); + if (err.parameters) { + setErrors(err); + setTabIndex(2); + return false; + } + } + + try { + await zDevice.parseAsync({ + ...data, + tags: normalizeTags(data.tags), + created_at: new Date(data.created_at), + updated_at: new Date(data.updated_at as Date), + last_input: new Date(data.last_input as Date), + last_output: new Date(data.last_output as Date), + inspected_at: undefined, + }); + + setErrors({}); + + return true; + } catch (ex: any) { + const err = buildZodError(ex.issues); + if (err.tags) { + setTabIndex(3); + } else { + setTabIndex(0); + } + setErrors(err); + return false; + } + }, [params, data]); + + /** + * Saves the device. + */ + const save = useCallback(async () => { + const formatted = { + active: data.active, + id: data.id, + name: data.name, + payload_parser: data.payload_parser, + tags: normalizeTags(data.tags), + encoder_stack: data.encoder_stack || [], + }; + + await editDevice(id, formatted); + await setDeviceParams(data.id, normalizeConfigParameters(params) as any); + + await mutateApiParams(() => params, false); + await mutateApiTokens(() => tokens, false); + + setLocalStorageAsJSON("last-encoder-stack", formatted.encoder_stack); + + initialData.current = cloneDeep(data); + }, [mutateApiTokens, id, tokens, params, mutateApiParams, data]); + + /** + * Deletes the device. + */ + const deleteData = useCallback(async () => { + await deleteDevice(id); + }, [id]); + + /** + * Clears the whole inspector data. + */ + const clearInspector = useCallback(() => { + setInspectorData({ ...inspectorData, logs: {} }); + }, [inspectorData]); + + /** + * Stops the live inspector. + */ + const stopInspector = useCallback(() => { + socket.emit("detach", ESocketResource.deviceInspection, id); + socket.off("device::inspection"); + clearInterval(intervalInspectorAttach.current); + }, [id]); + + /** + * Called when the inspector receives a new message. + */ + const onInspectorMessage = useCallback( + (msg: ILiveInspectorMessage | ILiveInspectorMessage[]) => { + if (Array.isArray(msg)) { + for (const item of msg) { + inspectorData.logs[item.connection_id] = inspectorData.logs[item.connection_id] || []; + inspectorData.logs[item.connection_id].push(item); + } + } else { + inspectorData.logs[msg.connection_id] = inspectorData.logs[msg.connection_id] || []; + inspectorData.logs[msg.connection_id].push(msg); + } + setInspectorData({ ...inspectorData, logs: { ...inspectorData.logs } }); + }, + [inspectorData] + ); + + /** + * Called when a field from a tab gets modified. + * This will apply the change to the data state. + */ + const onChangeData = useCallback( + (field: keyof IDevice, value: IDevice[keyof IDevice]) => { + setData({ ...data, [field]: value }); + }, + [data] + ); + + /** + * Renders the `Live Inspector` tab's title. + */ + const renderLiveInspectorTitle = () => { + return ( + <> + +   Live Inspector + + ); + }; + + /** + * Renders the `Live Inspector` tab's content. + */ + const renderLiveInspectorTab = () => { + return ( + setInspectorData({ ...inspectorData, enabled })} + onChangeLimit={(limit) => setInspectorData({ ...inspectorData, limit })} + onClear={clearInspector} + /> + ); + }; + + /** + * Renders the `General Information` tab's content. + */ + const renderGeneralInformationTab = () => { + return ( + + ); + }; + + /** + * Renders the `Configuration Parameters` tab's content. + */ + const renderConfigParamsTab = () => { + return ; + }; + + /** + * Renders the `Tags` tab's content. + */ + const renderTagsTab = () => { + return ( + onChangeData("tags", tags)} + /> + ); + }; + + /** + * Renders the page's nav description. + */ + const renderDescription = () => { + return ( + <> + Last Input + +  |  + Last Output + +  |  + Bucket + {data.name} + +  |  + Type + {getDeviceTypeName(data.type)} + + ); + }; + + /** + * Renders the `More` tab. + */ + const renderMoreTab = useCallback(() => { + return ; + }, [data, deleteData]); + + /** + * Renders the right side of the inner nav. + */ + const renderInnerNav = useCallback(() => { + if (loading) { + // still loading + return null; + } + + return ( + onChangeData("active", e)}> + Active + + ); + }, [loading, onChangeData, data]); + + /** + * Should return if the initial data is different from the current data. + */ + const checkIfDataChanged = useCallback(() => { + // the initial data, but normalized: + const initialDataNormalized = { + ...initialData.current, + tags: normalizeTags(initialData.current.tags), + }; + + // the current data being edited, but normalized: + const currentDataNormalized = { + ...data, + tags: normalizeTags(data.tags), + }; + + const initialParameters = normalizeConfigParameters(apiParams); + const currentParameters = normalizeConfigParameters(params); + + return ( + JSON.stringify(initialDataNormalized) !== JSON.stringify(currentDataNormalized) || + JSON.stringify(initialParameters) !== JSON.stringify(currentParameters) + ); + }, [data, apiParams, params]); + + /** + * Used to transfer the tokens API data to the state data. + */ + useEffect(() => { + if (apiTokens) { + setTokens(apiTokens); + } + }, [apiTokens]); + + /** + * Used to transfer the params API data to the state data. + */ + useEffect(() => { + if (apiParams) { + setParams(JSON.parse(JSON.stringify(apiParams))); + } + }, [apiParams]); + + /** + * Called to attach the live inspector events or shutdown the live inspector socket link. + * This effect will trigger when the `inspectorData.enabled` changes. + */ + useEffect(() => { + if (inspectorData.enabled) { + if (intervalInspectorAttach.current) { + clearInterval(intervalInspectorAttach.current); + } + + intervalInspectorAttach.current = setInterval(() => { + socket.emit("attach", "device", id); + }, 30000); // 30 seconds + + socket.emit("attach", ESocketResource.deviceInspection, id); + socket.off("device::inspection"); + socket.on("device::inspection", onInspectorMessage); + } else { + stopInspector(); + } + return () => stopInspector(); + }); + + return ( + + color={theme.device} + description={renderDescription()} + documentTitle="Device" + icon={EIcon.device} + innerNavTitle={data.name || "Device"} + loading={loading} + onChangeTabIndex={setTabIndex} + onCheckIfDataChanged={checkIfDataChanged} + onFetch={onFetch} + onRenderInnerNav={renderInnerNav} + onSave={save} + onValidate={validate} + requestPath="device" + tabIndex={tabIndex} + tabs={[ + { + label: "General Information", + content: renderGeneralInformationTab(), + }, + { + label: renderLiveInspectorTitle(), + content: renderLiveInspectorTab(), + }, + { + label: "Configuration Parameters", + content: renderConfigParamsTab(), + }, + { + label: "Tags", + content: renderTagsTab(), + }, + { + label: "More", + content: renderMoreTab(), + }, + ]} + /> + ); +} + +/** + * Makes the request to generate a token for the device. + */ +async function generateToken(data: any) { + return createDeviceToken(data.device_id, data); +} + +export default observer(DeviceEdit); diff --git a/packages/tcore-console/src/Components/Device/Edit/EncoderStack/EncoderStack.style.ts b/packages/tcore-console/src/Components/Device/Edit/EncoderStack/EncoderStack.style.ts new file mode 100644 index 00000000..ac4f8dfb --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/EncoderStack/EncoderStack.style.ts @@ -0,0 +1,121 @@ +import styled, { css } from "styled-components"; + +export const STACK_ITEM_HEIGHT = 45; + +/** + */ +export const Container = styled.div<{ itemAmount: number }>` + .title { + margin-bottom: 0.5rem; + display: flex; + align-items: center; + + .description { + color: rgba(0, 0, 0, 0.5); + } + .text { + flex: 1; + } + } + + > .stacks { + border: 1px solid ${(props) => props.theme.fieldsetBorder}; + border-radius: 5px; + position: relative; + min-height: 234px; + max-height: 700px; + height: ${(props) => props.itemAmount * STACK_ITEM_HEIGHT + 2}px; + overflow: auto; + background: ${(props) => props.theme.tableHeader}; + } +`; + +/** + * Component for a render item or 'stack' in the list. + */ +export const Item = styled.div<{ selected: boolean; index: number }>` + box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.1); + background: white; + display: flex; + align-items: center; + height: ${STACK_ITEM_HEIGHT}px; + position: absolute; + width: 100%; + top: ${(props) => props.index * STACK_ITEM_HEIGHT}px; + transition: top 0.2s; + padding-left: 10px; + + &:not(:last-child) { + /* no border for last child */ + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + } + + .a { + display: flex; + align-items: center; + flex: 1; + + .b { + margin-right: 10px; + } + + .c { + display: flex; + flex-direction: column; + + div { + font-weight: bold; + } + } + } + + .description { + color: rgba(0, 0, 0, 0.5); + } + + /* Grip icon container */ + > .icon-container { + cursor: pointer; + padding: 0px 10px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + opacity: 0.5; + + > div:nth-child(2) { + margin-bottom: 3px; + } + + svg * { + fill: black; + } + + > div { + width: 15px; + height: 2px; + background: black; + margin: -1px 0px; + } + } + + ${(props) => + /* Style for the selected item */ + props.selected && + css` + background: ${props.theme.buttonPrimary}; + z-index: 10; + + * { + color: white !important; + fill: white !important; + } + + > .icon-container { + opacity: 1; + div { + background: white !important; + } + } + `} +`; diff --git a/packages/tcore-console/src/Components/Device/Edit/EncoderStack/EncoderStack.tsx b/packages/tcore-console/src/Components/Device/Edit/EncoderStack/EncoderStack.tsx new file mode 100644 index 00000000..07a9c76f --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/EncoderStack/EncoderStack.tsx @@ -0,0 +1,216 @@ +import { memo, useCallback, useEffect, useRef, useState } from "react"; +import { useTheme } from "styled-components"; +import { IPluginClassListItem } from "@tago-io/tcore-sdk/types"; +import Button from "../../../Button/Button"; +import { EButton } from "../../../Button/Button.types"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import EmptyMessage from "../../../EmptyMessage/EmptyMessage"; +import * as Style from "./EncoderStack.style"; +import ModalAddEncoder from "./ModalAddEncoder"; + +/** + * Props. + */ +interface IEncoderStackProps { + /** + * Stack value. + */ + value: string[]; + /** + * Called when the stack value or order changes. + */ + onChange: (value: string[]) => void; + /** + * List of all encoder modules installed. + */ + encoderModules?: IPluginClassListItem[]; +} + +/** + * Renders a stack of encoder modules. + * Allows you to add unused encoder modules or remove used encoder modules. + */ +function EncoderStack(props: IEncoderStackProps) { + const { value, encoderModules, onChange } = props; + const theme = useTheme(); + + const [modalAddEncoder, setModalAddEncoder] = useState(false); + const [selectedID, setSelectedID] = useState(""); + const [targetIndex, setTargetIndex] = useState(-1); + const containerRef = useRef(null); + + /** + */ + const onItemMouseDown = useCallback((e: React.MouseEvent, item: string) => { + setSelectedID(item); + // we do these to prevent selecting the text: + e.preventDefault(); + e.stopPropagation(); + }, []); + + /** + * Removes an item from the stack. + */ + const removeItem = useCallback( + (item: string) => { + const index = value.indexOf(item); + if (index >= 0) { + value.splice(index, 1); + onChange(value); + } + }, + [value, onChange] + ); + + /** + * Renders a single encoder class in the stack. + */ + const renderItem = useCallback( + (item: string, i: number) => { + const plugin = encoderModules?.find((x) => `${x.pluginID}:${x.setupID}` === item); + return ( + + + {i + 1}. + {plugin ? ( +
+
{plugin?.setupName}
+ {plugin?.pluginName} +
+ ) : ( + <> + +   Encoder not found + + )} +
+ +
onItemMouseDown(e, item)}> + +
+
+ +
+ +
removeItem(item)}> + +
+ + ); + }, + [theme, encoderModules, removeItem, onItemMouseDown, selectedID] + ); + + /** + * This effect adds a window listener when the user is trying to drag an item in the stack. + */ + useEffect(() => { + if (selectedID) { + /** + * Called when the mouse moves with an item selected. + */ + const onMouseMove = (e: MouseEvent) => { + if (!containerRef.current) { + return; + } + + const { scrollTop } = containerRef.current; + const containerBounds = containerRef.current.getBoundingClientRect(); + + const position = e.clientY - containerBounds.y + scrollTop; + const floatIndex = Math.floor(position / Style.STACK_ITEM_HEIGHT); + const clampIndex = Math.min(Math.max(floatIndex, 0), value.length); + + if (targetIndex !== clampIndex) { + setTargetIndex(clampIndex); + } + }; + + /** + * Called when the mouse is released with an item selected. + */ + const onMouseUp = () => { + setTargetIndex(-1); + setSelectedID(""); + }; + + window.addEventListener("mousemove", onMouseMove); + window.addEventListener("mouseup", onMouseUp); + + return () => { + window.removeEventListener("mousemove", onMouseMove); + window.removeEventListener("mouseup", onMouseUp); + }; + } + }, [value.length, targetIndex, selectedID]); + + /** + * This effect is used to change the position of the array when the user + * is dragging an item to switch positions. + */ + useEffect(() => { + if (selectedID && targetIndex >= 0) { + const fromIndex = value.findIndex((x) => x === selectedID); + value.splice(fromIndex, 0, value.splice(targetIndex, 1)[0]); + onChange([...value].filter((x) => x)); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedID, targetIndex]); + + /** + * This array will contain all of the `unselected` encoders, + * which means the ones that weren't selected yet. + */ + const unselectedPlugins = encoderModules?.filter((x) => { + const selected = value.includes(`${x.pluginID}:${x.setupID}`); + return !selected; + }); + + return ( + <> + +
+
+
Encoder Stack
+ Select the order of encoder plugins for new data. +
+ + +
+ +
+ {value.length === 0 ? ( + + ) : ( + value.map(renderItem) + )} +
+
+ + {modalAddEncoder && ( + setModalAddEncoder(false)} + onConfirm={(selectedIDs: string[]) => { + const newList = value.concat(selectedIDs); + onChange(newList); + }} + /> + )} + + ); +} + +export default memo(EncoderStack); diff --git a/packages/tcore-console/src/Components/Device/Edit/EncoderStack/ModalAddEncoder.style.tsx b/packages/tcore-console/src/Components/Device/Edit/EncoderStack/ModalAddEncoder.style.tsx new file mode 100644 index 00000000..e4468c1a --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/EncoderStack/ModalAddEncoder.style.tsx @@ -0,0 +1,64 @@ +import styled from "styled-components"; +import { STACK_ITEM_HEIGHT } from "./EncoderStack.style"; + +/** + */ +export const Container = styled.div` + border: 1px solid ${(props) => props.theme.fieldsetBorder}; + border-radius: 5px; + overflow: hidden; + position: relative; + min-height: 400px; + overflow: auto; + background: ${(props) => props.theme.tableHeader}; +`; + +/** + * Component for a render item or 'stack' in the list. + */ +export const Item = styled.div` + box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.1); + background: white; + display: flex; + align-items: center; + height: ${STACK_ITEM_HEIGHT}px; + width: 100%; + cursor: pointer; + + &:not(:last-child) { + /* no border for last child */ + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + } + + .data { + /* main data of the row (title, description) */ + display: flex; + align-items: center; + + .index { + /* index number (1, 2, 3, ...) */ + margin-right: 10px; + } + + .texts { + display: flex; + flex-direction: column; + + > .title { + /* setup name */ + font-weight: bold; + } + + > .description { + /* plugin name */ + color: rgba(0, 0, 0, 0.5); + } + } + } + + /* Grip icon container */ + > .icon-container { + display: flex; + padding: 0px 10px; + } +`; diff --git a/packages/tcore-console/src/Components/Device/Edit/EncoderStack/ModalAddEncoder.tsx b/packages/tcore-console/src/Components/Device/Edit/EncoderStack/ModalAddEncoder.tsx new file mode 100644 index 00000000..1d3e4811 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/EncoderStack/ModalAddEncoder.tsx @@ -0,0 +1,87 @@ +import { IPluginClassListItem } from "@tago-io/tcore-sdk/types"; +import { memo, useCallback, useState } from "react"; +import Modal from "../../../Modal/Modal"; +import * as Style from "./ModalAddEncoder.style"; + +/** + * Props. + */ +interface IModalAddEncoder { + /** + * List of options that will be rendered. + */ + list: IPluginClassListItem[]; + /** + * Called to close this modal. + */ + onClose: () => void; + /** + * Called when the confirm is pressed, the parameter will contain an + * array of `pluginID:setupID` for each selected option in the list. + */ + onConfirm: (selectedIDs: string[]) => void; +} + +/** + * Modal to select encoder modules. + */ +function ModalAddEncoder(props: IModalAddEncoder) { + const [items, setItems] = useState([]); + const { list, onClose, onConfirm } = props; + + /** + * Confirms the choices and exits out of the modal. + */ + const confirm = () => { + onConfirm(items); + }; + + /** + * Toggles the checkbox/selected status of an item. + */ + const toggle = useCallback( + (e: React.MouseEvent, id: string) => { + if (items.includes(id)) { + const index = items.indexOf(id); + items.splice(index, 1); + } else { + items.push(id); + } + setItems([...items]); + }, + [items] + ); + + /** + * Renders a single item. + */ + const renderItem = useCallback( + (item: IPluginClassListItem, i: number) => { + const id = `${item.pluginID}:${item.setupID}`; + return ( + toggle(e, id)}> +
+ +
+ + + {i + 1}. +
+
{item?.setupName}
+ {item?.pluginName} +
+
+
+ ); + }, + [toggle, items] + ); + + return ( + + {list.map(renderItem)} + + ); +} + +export default memo(ModalAddEncoder); diff --git a/packages/tcore-console/src/Components/Device/Edit/GeneralInformationTab/GeneralInformationTab.tsx b/packages/tcore-console/src/Components/Device/Edit/GeneralInformationTab/GeneralInformationTab.tsx new file mode 100644 index 00000000..ecce7a45 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/GeneralInformationTab/GeneralInformationTab.tsx @@ -0,0 +1,133 @@ +import { IDeviceToken, IDevice } from "@tago-io/tcore-sdk/types"; +import { useCallback } from "react"; +import Col from "../../../Col/Col"; +import FormDivision from "../../../FormDivision/FormDivision"; +import FormGroup from "../../../FormGroup/FormGroup"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import ResourceLinkField from "../../../ResourceLinkField/ResourceLinkField"; +import Row from "../../../Row/Row"; +import PayloadParser from "../../Common/PayloadParser/PayloadParser"; +import TokenTable from "../../Common/TokenTable/TokenTable"; +import EncoderStack from "../EncoderStack/EncoderStack"; + +/** + * Props. + */ +interface IGeneralInformationTabProps { + /** + * Device's form data. + */ + data: IDevice; + /** + * Device's form errors. + */ + errors: any; + /** + * Tokens of the device. + */ + tokens?: IDeviceToken[]; + /** + * Called when a field is changed. + */ + onChange: (field: keyof IDevice, value: IDevice[keyof IDevice]) => void; + /** + * Called when the tokens change. + */ + onChangeTokens: (tokens: IDeviceToken[]) => void; + /** + * Called when a new token needs to be generated. + */ + onGenerateToken: (data: IDeviceToken) => Promise; + /** + * Called when a token needs to be deleted. + */ + onDeleteToken: (token: string) => Promise; + encoderModules: any; +} + +/** + * The device's `General Information` tab. + */ +function GeneralInformationTab(props: IGeneralInformationTabProps) { + const { data, errors, encoderModules, onChange } = props; + + /** + * Can be called to change the value of the encoder stack. + */ + const onChangeEncoderStack = useCallback( + (value: string[]) => { + onChange("encoder_stack", value); + }, + [onChange] + ); + + return ( +
+ + + + + + + + onChange("name", e.target.value)} + placeholder="Enter the device's name" + /> + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ); +} + +export default GeneralInformationTab; diff --git a/packages/tcore-console/src/Components/Device/Edit/LiveInspectorTab/LiveInspectorTab.tsx b/packages/tcore-console/src/Components/Device/Edit/LiveInspectorTab/LiveInspectorTab.tsx new file mode 100644 index 00000000..0be185d2 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/LiveInspectorTab/LiveInspectorTab.tsx @@ -0,0 +1,66 @@ +import { IDevice } from "@tago-io/tcore-sdk/types"; +import FormDivision from "../../../FormDivision/FormDivision"; +import { EIcon } from "../../../Icon/Icon.types"; +import LiveInspector from "../../Common/LiveInspector/LiveInspector"; + +/** + * Props. + */ +interface ILiveInspectorTabProps { + /** + * Device's form data. + */ + data: IDevice; + /** + * Indicates if the live inspector is enabled or not. + */ + enabled: boolean; + /** + * Limit amount of records. + */ + limit: number; + /** + * Logs of the inspector. + */ + logs: any; + /** + * Called when the limit changes. + */ + onChangeLimit: (newLimit: number) => void; + /** + * Called when the enabled status changes. + */ + onChangeEnabled: (enabled: boolean) => void; + /** + * Called when the console is cleared. + */ + onClear: () => void; +} + +/** + * The device's `Live Inspector` tab. + */ +function LiveInspectorTab(props: ILiveInspectorTabProps) { + const { enabled, limit, logs, onChangeEnabled, onChangeLimit, onClear } = props; + + return ( + <> + + + + + ); +} + +export default LiveInspectorTab; diff --git a/packages/tcore-console/src/Components/Device/Edit/MoreTab/MoreTab.tsx b/packages/tcore-console/src/Components/Device/Edit/MoreTab/MoreTab.tsx new file mode 100644 index 00000000..39c1753d --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Edit/MoreTab/MoreTab.tsx @@ -0,0 +1,123 @@ +import { useCallback, useEffect, useState } from "react"; +import { useHistory } from "react-router"; +import { IDevice } from "@tago-io/tcore-sdk/types"; +import Button from "../../../Button/Button"; +import { EButton } from "../../../Button/Button.types"; +import Col from "../../../Col/Col"; +import FormDivision from "../../../FormDivision/FormDivision"; +import FormGroup from "../../../FormGroup/FormGroup"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import Modal from "../../../Modal/Modal"; +import RelativeDate from "../../../RelativeDate/RelativeDate"; +import Row from "../../../Row/Row"; + +/** + * Props. + */ +interface IMoreTabProps { + /** + * Device's form data. + */ + data: IDevice; + /** + * Called when the device was requested to be deleted. + */ + onDelete: () => Promise; +} + +/** + * The device's `More` tab. + */ +function MoreTab(props: IMoreTabProps) { + const history = useHistory(); + const [deleted, setDeleted] = useState(false); + const [modalDevice, setModalDevice] = useState(false); + const { data, onDelete } = props; + + /** + * Confirms the delete request. + */ + const confirmDelete = useCallback(async () => { + await onDelete(); + setDeleted(true); + }, [onDelete]); + + /** + * Opens the delete device modal. + */ + const activateModalDevice = useCallback(() => { + setModalDevice(true); + }, []); + + /** + * Closes the delete device modal. + */ + const deactivateModalDevice = useCallback(() => { + setModalDevice(false); + }, []); + + /** + * Used to transfer the user back to the list page upon deleting the device. + */ + useEffect(() => { + if (deleted) { + history.push("/console/devices"); + } + }, [history, deleted]); + + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {modalDevice && ( + + Do you really want to delete this Device? there is no going back after this! + + )} +
+ ); +} + +export default MoreTab; diff --git a/packages/tcore-console/src/Components/Device/Helpers/normalizeConfigParameters.ts b/packages/tcore-console/src/Components/Device/Helpers/normalizeConfigParameters.ts new file mode 100644 index 00000000..f9b72cd5 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/Helpers/normalizeConfigParameters.ts @@ -0,0 +1,27 @@ +import { IDeviceParameter } from "@tago-io/tcore-sdk/types"; + +/** + * Normalizes the configuration parameters array to return a consistent + * output free of small errors. + */ +function normalizeConfigParameters(params?: IDeviceParameter[]) { + if (!params) { + return []; + } + + if (params.length === 1) { + if (!params[0].key && !params[0].value && !params[0].sent) { + return []; + } + } + + const normalized = params.map((x) => ({ + sent: x.sent ? true : false, + key: x.key, + value: x.value, + })); + + return normalized; +} + +export default normalizeConfigParameters; diff --git a/packages/tcore-console/src/Components/Device/List/DeviceList.tsx b/packages/tcore-console/src/Components/Device/List/DeviceList.tsx new file mode 100644 index 00000000..15cb3bf4 --- /dev/null +++ b/packages/tcore-console/src/Components/Device/List/DeviceList.tsx @@ -0,0 +1,107 @@ +import { useTheme } from "styled-components"; +import { IDevice } from "@tago-io/tcore-sdk/types"; +import { useState, useCallback } from "react"; +import BooleanStatus from "../../BooleanStatus/BooleanStatus"; +import Button from "../../Button/Button"; +import { EButton } from "../../Button/Button.types"; +import Icon from "../../Icon/Icon"; +import { EIcon } from "../../Icon/Icon.types"; +import ListPage from "../../ListPage/ListPage"; +import RelativeDate from "../../RelativeDate/RelativeDate"; +import DeviceInputOutput from "../Common/DeviceInputOutput"; +import getDeviceList from "../../../Requests/getDeviceList"; +import ModalAddDevice from "../Common/ModalAddDevice/ModalAddDevice"; +import getDeviceTypeName from "../../../Helpers/getDeviceTypeName"; + +/** + * The device's list page. + */ +function DeviceList() { + const [modalAdd, setModalAdd] = useState(false); + const theme = useTheme(); + + /** + * Opens the add modal. + */ + const activateModalAdd = useCallback(() => { + setModalAdd(true); + }, []); + + /** + * Closes the add modal. + */ + const deactivateModalAdd = useCallback(() => { + setModalAdd(false); + }, []); + + return ( + <> + + color={theme.device} + description="Devices are the link between external things and the buckets in your account." + icon={EIcon.device} + path="devices" + innerNavTitle="Devices" + documentTitle="Devices" + onGetData={getDeviceList} + summaryKey="device" + columns={[ + { + id: "name", + label: "Name", + onRender: (item) => item.name, + type: "text", + }, + { + id: "last_input", + label: "Last Input", + onRender: (item) => , + type: "date", + }, + { + id: "last_output", + label: "Last Output", + onRender: (item) => , + type: "date", + }, + { + id: "type", + label: "Type", + onRender: (item) => getDeviceTypeName(item.type), + filterDisabled: true, + flex: "none", + width: 250, + }, + { + flex: "none", + id: "active", + label: "Active", + onRender: (item) => , + type: "boolean", + width: 100, + }, + { + id: "created_at", + label: "Created at", + onRender: (item) => , + type: "date", + }, + ]} + > + + + + {modalAdd && } + + ); +} + +export default DeviceList; diff --git a/packages/tcore-console/src/Components/EditPage/EditPage.style.ts b/packages/tcore-console/src/Components/EditPage/EditPage.style.ts new file mode 100644 index 00000000..e9c17001 --- /dev/null +++ b/packages/tcore-console/src/Components/EditPage/EditPage.style.ts @@ -0,0 +1,14 @@ +import styled from "styled-components"; + +/** + * Main style of the component. + */ +export const Container = styled.div` + display: flex; + flex-direction: column; + flex: 1; + width: 100%; + height: 100%; + position: relative; + background: ${(props) => props.theme.background2}; +`; diff --git a/packages/tcore-console/src/Components/EditPage/EditPage.tsx b/packages/tcore-console/src/Components/EditPage/EditPage.tsx new file mode 100644 index 00000000..446d8118 --- /dev/null +++ b/packages/tcore-console/src/Components/EditPage/EditPage.tsx @@ -0,0 +1,249 @@ +import { ReactNode, useEffect, useState, useRef } from "react"; +import { useHistory, useRouteMatch } from "react-router"; +import cloneDeep from "lodash.clonedeep"; +import setDocumentTitle from "../../Helpers/setDocumentTitle"; +import useApiRequest from "../../Helpers/useApiRequest"; +import Button from "../Button/Button"; +import { EButton } from "../Button/Button.types"; +import Footer from "../Footer/Footer"; +import { EIcon } from "../Icon/Icon.types"; +import Loading from "../Loading/Loading"; +import InnerNav from "../InnerNav/InnerNav"; +import Tabs from "../Tabs/Tabs"; +import { ITab } from "../Tabs/Tabs.types"; +import * as Style from "./EditPage.style"; + +/** + * Props. + */ +interface IEditPageProps { + /** + * Color of the tabs and the inner navigation bar. + */ + color?: string; + /** + * Description of the inner navigation bar. + */ + description?: ReactNode; + /** + * Icon of the inner navigation bar. + */ + icon?: EIcon; + /** + * Image of the inner navigation bar. This will override the `icon` prop. + */ + image?: string; + /** + * This is the actual content to be rendered in the middle of the screen. + * The tabs here follow the same structure as defined in the `Tabs` component. + */ + tabs: ITab[]; + /** + * Title of the document/page. + */ + documentTitle?: string; + /** + * Title of the inner navigation bar. + */ + innerNavTitle?: string; + /** + * Indicates if the record is still being loaded. + * This is useful to specify if the record needs multiple requests before being shown + * and you want to wait for those requests. + */ + loading?: boolean; + /** + * Request path to retrieve the resource from the backend. + */ + requestPath?: string; + /** + * Controls the selected tab. + */ + tabIndex: number; + /** + * Called when the user presses the `Save` button. + */ + onSave: () => Promise; + /** + * Called when the user presses the `Save` button. + * This should return a boolean to indicate that something is missing/wrong in the form. + */ + onValidate?: () => Promise | boolean; + /** + * Called when the initial data is fetched from the backend. + */ + onFetch: (data: T) => void; + /** + * Optional function to render the right side of the inner navigation bar. + */ + onRenderInnerNav?: () => ReactNode; + /** + * Optional function to render the right side of the footer. + * Everything returned from this function will be placed on the left side of the `Save` button. + */ + onRenderFooter?: () => ReactNode; + /** + * Function that is called every render to check if the initial data is different from the current data. + * This is used to disable the `Save` button in case nothing changed. + */ + onCheckIfDataChanged?: (initialData?: T) => boolean; + /** + * Called when the user clicks on another tab. + */ + onChangeTabIndex: (tabIndex: number) => void; + /** + * Optional custom rendering of the inner nav icon. + */ + onRenderInnerNavIcon?: () => ReactNode; +} + +/** + * This component controls the edit form of the resources in the application. + */ +function EditPage(props: IEditPageProps) { + const match = useRouteMatch<{ id: string }>(); + const { id } = match.params; + + const history = useHistory(); + const uniqueID = useRef(Date.now()); + const { requestPath } = props; + const { data } = useApiRequest(`/${requestPath}${id ? `/${id}` : ""}?t=${uniqueID.current}`); + const [saving, setSaving] = useState(false); + const [internalLoading, setInternalLoading] = useState(false); + + const loaded = useRef(false); + + const { + documentTitle, + loading, + onChangeTabIndex, + onCheckIfDataChanged, + onFetch, + onRenderFooter, + onRenderInnerNav, + onSave, + onValidate, + tabIndex, + } = props; + + /** + * Saves the record. + */ + const save = async () => { + const validated = await onValidate?.(); + if (!validated) { + return; + } + + setSaving(true); + try { + await onSave(); + } finally { + setSaving(false); + } + }; + + /** + * Renders the tabs render. + */ + const renderTabs = () => { + return ( + + ); + }; + + /** + * Renders the footer with the `Back` and `Save` buttons. + */ + const renderFooter = () => { + let saveDisabled = false; + + if (onCheckIfDataChanged && loaded.current) { + const dataChanged = onCheckIfDataChanged(); + saveDisabled = !dataChanged; + } + + return ( +
+ +
+ {onRenderFooter?.()} + +
+
+ ); + }; + + /** + * Renders the inner navigation bar that contains the icon, title and description. + */ + const renderInnerNav = () => { + const innerNavTitle = loading ? "" : props.innerNavTitle; + const description = loading ? "" : props.description; + return ( + + {onRenderInnerNav?.()} + + ); + }; + + /** + */ + useEffect(() => { + if (loaded.current) { + setInternalLoading(true); + uniqueID.current = Date.now(); + } + loaded.current = false; + }, [id]); + + /** + * Used to fetch the record and assign the initial data. + */ + useEffect(() => { + if (data && !loaded.current) { + setInternalLoading(false); + onFetch(cloneDeep(data)); + loaded.current = true; + } + }, [onFetch, id, data]); + + /** + * Sets the document title. + */ + useEffect(() => { + if (documentTitle) { + setDocumentTitle(documentTitle); + } + }, [documentTitle]); + + return ( + + {loading || internalLoading ? ( + + ) : ( + <> + {renderInnerNav()} + {renderTabs()} + {renderFooter()} + + )} + + ); +} + +export default EditPage; diff --git a/packages/tcore-console/src/Components/EmptyMessage/EmptyMessage.style.ts b/packages/tcore-console/src/Components/EmptyMessage/EmptyMessage.style.ts new file mode 100644 index 00000000..b18358eb --- /dev/null +++ b/packages/tcore-console/src/Components/EmptyMessage/EmptyMessage.style.ts @@ -0,0 +1,32 @@ +import styled from "styled-components"; +import { fonts } from "../../theme"; +import * as IconStyle from "../Icon/Icon.style"; + +/** + * Main container. + */ +export const Container = styled.div` + display: flex; + flex-direction: column; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + justify-content: center; + align-items: center; + + > .message { + margin-top: 5px; + } + + > .message, + > .message * { + /* font-size: ${() => fonts.medium}; */ + color: ${(props) => props.theme.font3}; + text-align: center; + } + + > ${IconStyle.Container} { + opacity: 0.3; + } +`; diff --git a/packages/tcore-console/src/Components/EmptyMessage/EmptyMessage.tsx b/packages/tcore-console/src/Components/EmptyMessage/EmptyMessage.tsx new file mode 100644 index 00000000..902452cf --- /dev/null +++ b/packages/tcore-console/src/Components/EmptyMessage/EmptyMessage.tsx @@ -0,0 +1,28 @@ +import { memo, ReactNode } from "react"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import * as Style from "./EmptyMessage.style"; + +/** + * Props. + */ +interface IEmptyMessageProps { + icon: EIcon; + message?: ReactNode; +} + +/** + * Renders a message indicating that the content is empty. + */ +function EmptyMessage(props: IEmptyMessageProps) { + const { icon, message } = props; + + return ( + + +
{message}
+
+ ); +} + +export default memo(EmptyMessage); diff --git a/packages/tcore-console/src/Components/ErrorMessage/ErrorMessage.style.ts b/packages/tcore-console/src/Components/ErrorMessage/ErrorMessage.style.ts new file mode 100644 index 00000000..040acd98 --- /dev/null +++ b/packages/tcore-console/src/Components/ErrorMessage/ErrorMessage.style.ts @@ -0,0 +1,11 @@ +import styled from "styled-components"; +import { fonts } from "../../theme"; + +export const Container = styled.span` + color: ${(props) => props.theme.buttonDanger}; + display: inline-block; + font-size: ${() => fonts.small}; + font-weight: bold; + margin-top: 5px; + text-align: center; +`; diff --git a/packages/tcore-console/src/Components/ErrorMessage/ErrorMessage.tsx b/packages/tcore-console/src/Components/ErrorMessage/ErrorMessage.tsx new file mode 100644 index 00000000..d3968d68 --- /dev/null +++ b/packages/tcore-console/src/Components/ErrorMessage/ErrorMessage.tsx @@ -0,0 +1,10 @@ +import * as Style from "./ErrorMessage.style"; + +/** + */ +function ErrorMessage(props: any) { + const { children } = props; + return {children}; +} + +export default ErrorMessage; diff --git a/packages/tcore-console/src/Components/FileSelect/FileSelect.style.ts b/packages/tcore-console/src/Components/FileSelect/FileSelect.style.ts new file mode 100644 index 00000000..80bf92c7 --- /dev/null +++ b/packages/tcore-console/src/Components/FileSelect/FileSelect.style.ts @@ -0,0 +1,49 @@ +import styled from "styled-components"; + +/** + * The main style container. + */ +export const Container = styled.div` + display: flex; + + .input-container { + position: relative; + flex: 1; + margin-right: -1px; + + input { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + padding-right: 40px; + } + } + + button { + flex: none; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } +`; + +/** + */ +export const IconContainer = styled.div` + position: absolute; + right: 10px; + z-index: 4; + top: 50%; + transform: translate(0%, -50%); + padding: 5px; + border-radius: 3px; + display: flex; + align-items: center; + + cursor: pointer; + + &:hover { + background: rgba(0, 0, 0, 0.07); + } + &:active { + background: rgba(0, 0, 0, 0.14); + } +`; diff --git a/packages/tcore-console/src/Components/FileSelect/FileSelect.tsx b/packages/tcore-console/src/Components/FileSelect/FileSelect.tsx new file mode 100644 index 00000000..d64eab93 --- /dev/null +++ b/packages/tcore-console/src/Components/FileSelect/FileSelect.tsx @@ -0,0 +1,128 @@ +import { useCallback, useState } from "react"; +import Button from "../Button/Button"; +import { EButton } from "../Button/Button.types"; +import ErrorMessage from "../ErrorMessage/ErrorMessage"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import Input from "../Input/Input"; +import ModalFileSelect from "../ModalFileSelect/ModalFileSelect"; +import * as Style from "./FileSelect.style"; + +/** + * Props. + */ +interface IFileSelectProps { + /** + * The selected file path. + */ + value: string; + /** + * Called when the selected file path changes. + */ + onChange: (value: string) => void; + /** + * Message that will appear inside of the file selector modal. + */ + modalMessage?: string; + /** + * Placeholder for the input. + */ + placeholder?: string; + /** + * Extensions to accept. + */ + accept?: string; + /** + * If the select can only select folders. + */ + onlyFolders?: boolean; + /** + * Indicates if the input has an error. + */ + error?: boolean; + /** + * If the input is disabled or not. + */ + disabled?: boolean; + /** + * Use local filesystem for the list. + */ + useLocalFs?: boolean; +} + +/** + * Input and a button that reads "Select a file". + * When the button is clicked, the `ModalFileSelect` will appear. + */ +function FileSelect(props: IFileSelectProps) { + const [modalFile, setModalFile] = useState(false); + const { value, error, disabled, accept, modalMessage, onlyFolders, onChange } = props; + const placeholder = props.placeholder || `Select a ${onlyFolders ? `folder` : `file`}`; + + /** + * Opens the file selector modal. + */ + const activateModalFile = useCallback(() => { + setModalFile(true); + }, []); + + /** + * Closes the file selector modal. + */ + const deactivateModalFile = useCallback(() => { + setModalFile(false); + }, []); + + /** + * Renders the input icon on the right side of the component. + */ + const renderInputIcon = () => { + if (!value) { + // nothing to clear + return null; + } + + return ( + onChange("")}> + + + ); + }; + + return ( + <> + +
+ onChange(e.target.value)} + disabled={disabled} + /> + {!disabled && renderInputIcon()} +
+ + + + {modalFile && ( + + )} +
+ + {error && This field is required} + + ); +} + +export default FileSelect; diff --git a/packages/tcore-console/src/Components/FlexRow/FlexRow.style.ts b/packages/tcore-console/src/Components/FlexRow/FlexRow.style.ts new file mode 100644 index 00000000..54ff70f8 --- /dev/null +++ b/packages/tcore-console/src/Components/FlexRow/FlexRow.style.ts @@ -0,0 +1,19 @@ +import styled from "styled-components"; + +/** + */ +export const Container = styled.div` + display: flex; + align-items: center; + + > input:nth-child(1) { + margin-right: -1px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + > input:nth-child(2) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } +`; diff --git a/packages/tcore-console/src/Components/FlexRow/FlexRow.test.tsx b/packages/tcore-console/src/Components/FlexRow/FlexRow.test.tsx new file mode 100644 index 00000000..75b1e4b3 --- /dev/null +++ b/packages/tcore-console/src/Components/FlexRow/FlexRow.test.tsx @@ -0,0 +1,7 @@ +import { render } from "../../../utils/test-utils"; +import FlexRow from "./FlexRow"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); diff --git a/packages/tcore-console/src/Components/FlexRow/FlexRow.tsx b/packages/tcore-console/src/Components/FlexRow/FlexRow.tsx new file mode 100644 index 00000000..d4901f55 --- /dev/null +++ b/packages/tcore-console/src/Components/FlexRow/FlexRow.tsx @@ -0,0 +1,19 @@ +import { ReactNode } from "react"; +import * as Style from "./FlexRow.style"; + +/** + * Props. + */ +interface IFlexRow { + children?: ReactNode; +} + +/** + * Component that renders the content side by side, in a horizontal line. + * If the children are inputs, they will be "glued" together. + */ +function FlexRow(props: IFlexRow) { + return {props.children}; +} + +export default FlexRow; diff --git a/packages/tcore-console/src/Components/Footer/Footer.style.tsx b/packages/tcore-console/src/Components/Footer/Footer.style.tsx new file mode 100644 index 00000000..27dd0073 --- /dev/null +++ b/packages/tcore-console/src/Components/Footer/Footer.style.tsx @@ -0,0 +1,21 @@ +import styled from "styled-components"; +import * as ButtonStyle from "../Button/Button.style"; + +/** + * Main style. + */ +export const Container = styled.footer` + display: flex; + background-color: ${(props) => props.theme.background1}; + border-top: solid 1px ${(props) => props.theme.fieldsetBorder}; + justify-content: space-between; + padding: 3px 15px; + min-height: 40px; + align-items: center; + + ${ButtonStyle.Container} { + /* buttons should be a tiny bit smaller in this footer */ + padding-top: 5px; + padding-bottom: 5px; + } +`; diff --git a/packages/tcore-console/src/Components/Footer/Footer.test.tsx b/packages/tcore-console/src/Components/Footer/Footer.test.tsx new file mode 100644 index 00000000..debb36a2 --- /dev/null +++ b/packages/tcore-console/src/Components/Footer/Footer.test.tsx @@ -0,0 +1,12 @@ +import { render, screen } from "../../../utils/test-utils"; +import Footer from "./Footer"; + +test("renders without crashing", () => { + const fn = () => render(
); + expect(fn).not.toThrowError(); +}); + +test("renders children", () => { + render(
Hello world
); + expect(screen.getByText("Hello world")).toBeInTheDocument(); +}); diff --git a/packages/tcore-console/src/Components/Footer/Footer.tsx b/packages/tcore-console/src/Components/Footer/Footer.tsx new file mode 100644 index 00000000..afc9d900 --- /dev/null +++ b/packages/tcore-console/src/Components/Footer/Footer.tsx @@ -0,0 +1,22 @@ +import { ReactNode } from "react"; +import * as Style from "./Footer.style"; + +/** + * Props. + */ +interface IFooterProps { + /** + * Content to be rendered inside of this component. + */ + children?: ReactNode; +} + +/** + * Default footer for the application. + * This component will render the children inside of a `space-between` container. + */ +function Footer(props: IFooterProps) { + return {props.children}; +} + +export default Footer; diff --git a/packages/tcore-console/src/Components/FormDivision/FormDivision.style.ts b/packages/tcore-console/src/Components/FormDivision/FormDivision.style.ts new file mode 100644 index 00000000..e87c8bab --- /dev/null +++ b/packages/tcore-console/src/Components/FormDivision/FormDivision.style.ts @@ -0,0 +1,38 @@ +import styled, { css } from "styled-components"; +import { fonts } from "../../theme"; +import * as IconStyle from "../Icon/Icon.style"; + +/** + * Main style, holds everything together. + */ +export const Container = styled.div<{ renderBorder?: boolean }>` + margin-bottom: 1rem; + + ${(props) => + props.renderBorder && + css` + padding-top: 1rem; + border-top: 1px solid ${props.theme.fieldsetBorder}; + `} + + > .title { + display: flex; + align-items: center; + + h2 { + display: inline-block; + font-weight: 500; + font-size: ${fonts.medium}; + } + + ${IconStyle.Container} { + margin-right: 7px; + } + } + + > .description { + color: ${(props) => props.theme.font2}; + display: inline-block; + margin-top: 2px; + } +`; diff --git a/packages/tcore-console/src/Components/FormDivision/FormDivision.test.tsx b/packages/tcore-console/src/Components/FormDivision/FormDivision.test.tsx new file mode 100644 index 00000000..bc8b5af0 --- /dev/null +++ b/packages/tcore-console/src/Components/FormDivision/FormDivision.test.tsx @@ -0,0 +1,39 @@ +import { render, screen } from "../../../utils/test-utils"; +import { EIcon } from "../Icon/Icon.types"; +import FormDivision from "./FormDivision"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("renders title as string", () => { + render(); + expect(screen.getByText("Settings")).toBeInTheDocument(); +}); + +test("renders title as node", () => { + render(Settings
} />); + expect(screen.getByText("Settings")).toBeInTheDocument(); +}); + +test("renders description as string", () => { + render(); + expect(screen.getByText("Adjust the settings")).toBeInTheDocument(); +}); + +test("renders icon", () => { + render(); + expect(screen.getByText("cog-icon-mock")).toBeInTheDocument(); +}); + +test("renders description as node", () => { + render(Adjust the settings
} />); + expect(screen.getByText("Adjust the settings")).toBeInTheDocument(); +}); + +test("respects `renderBorder` prop", () => { + const { container } = render(); + const style = window.getComputedStyle(container.firstChild as HTMLElement); + expect(style.paddingTop).toEqual("1rem"); +}); diff --git a/packages/tcore-console/src/Components/FormDivision/FormDivision.tsx b/packages/tcore-console/src/Components/FormDivision/FormDivision.tsx new file mode 100644 index 00000000..ce439687 --- /dev/null +++ b/packages/tcore-console/src/Components/FormDivision/FormDivision.tsx @@ -0,0 +1,50 @@ +import { ReactNode } from "react"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import * as Style from "./FormDivision.style"; + +/** + * Props. + */ +interface IFormDivision { + /** + * The icon for this component. + */ + icon?: EIcon; + /** + * Indicates if a border should be rendered above the component. + * This also enables padding above the item to create some distance between the border and the title. + */ + renderBorder?: boolean; + /** + * Description below the title. + */ + description?: ReactNode; + /** + * The main title of this component. + */ + title?: ReactNode; +} + +/** + * This component acts like a division between sections of the page. + * It shows a title, description and an icon to provide explanation for a new section in a form. + */ +function FormDivision(props: IFormDivision) { + const { renderBorder, icon, title, description } = props; + + return ( + + {(icon || title) && ( +
+ {icon && } + {title &&

{title}

} +
+ )} + + {description &&
{description}
} +
+ ); +} + +export default FormDivision; diff --git a/packages/tcore-console/src/Components/FormGroup/FormGroup.style.ts b/packages/tcore-console/src/Components/FormGroup/FormGroup.style.ts new file mode 100644 index 00000000..40de214d --- /dev/null +++ b/packages/tcore-console/src/Components/FormGroup/FormGroup.style.ts @@ -0,0 +1,35 @@ +import styled from "styled-components"; +import * as IconStyle from "../Icon/Icon.style"; +import * as SwitchStyle from "../Switch/Switch.style"; + +/** + * Main style. + */ +export const Container = styled.div<{ addMarginBottom?: boolean }>` + margin-bottom: ${(props) => (props.addMarginBottom === false ? 0 : "1rem")}; + text-align: left; + + > label { + margin-bottom: 0.5rem; + font-weight: bold; + font-size: 0.88rem; + display: flex; + align-items: center; + + ${IconStyle.Container} { + margin-right: 7px; + } + + > .required { + margin-left: 3px; + color: red; + font-weight: bold; + } + } + + ${SwitchStyle.Container} { + &:not(:first-child) { + margin-top: 3px; + } + } +`; diff --git a/packages/tcore-console/src/Components/FormGroup/FormGroup.test.tsx b/packages/tcore-console/src/Components/FormGroup/FormGroup.test.tsx new file mode 100644 index 00000000..e875c815 --- /dev/null +++ b/packages/tcore-console/src/Components/FormGroup/FormGroup.test.tsx @@ -0,0 +1,43 @@ +import { within } from "@testing-library/react"; +import { fireEvent, render, screen } from "../../../utils/test-utils"; +import { EIcon } from "../Icon/Icon.types"; +import FormGroup from "./FormGroup"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("renders label", () => { + render(); + expect(screen.getByText("Hello world")).toBeInTheDocument(); +}); + +test("renders children", () => { + render(Foo); + expect(screen.getByText("Foo")).toBeInTheDocument(); +}); + +test("renders children", () => { + render(Foo); + expect(screen.getByText("Foo")).toBeInTheDocument(); +}); + +test("renders icon", () => { + render(); + expect(screen.getByText("cog-icon-mock")).toBeInTheDocument(); +}); + +test("respects `style` prop", () => { + const { container } = render(); + const style = window.getComputedStyle(container.firstChild as HTMLElement); + expect(style.backgroundColor).toEqual("red"); +}); + +test("hovering over label with `tooltip` opens tooltip", () => { + render(); + fireEvent.mouseEnter(screen.getByText("Hello")); + const tooltip = screen.getByTestId("tooltip"); + expect(tooltip).toBeInTheDocument(); + expect(within(tooltip).getByText("world")).toBeInTheDocument(); +}); diff --git a/packages/tcore-console/src/Components/FormGroup/FormGroup.tsx b/packages/tcore-console/src/Components/FormGroup/FormGroup.tsx new file mode 100644 index 00000000..908c1eef --- /dev/null +++ b/packages/tcore-console/src/Components/FormGroup/FormGroup.tsx @@ -0,0 +1,66 @@ +import { ReactNode } from "react"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import TooltipText from "../TooltipText/TooltipText"; +import * as Style from "./FormGroup.style"; + +/** + * Props. + */ +interface IFormGroupProps { + /** + * Content to be rendered inside of the form group. + */ + children?: ReactNode; + /** + * Icon for the label of this form group. + */ + icon?: EIcon; + /** + * Label/title of the form group. + */ + label?: ReactNode; + /** + * Optional style for this component, it will be passed straight to the root component. + */ + style?: React.CSSProperties; + /** + * Tooltip to underline the label. This is optional. + */ + tooltip?: string; + /** + * Indicates if this component should add a margin bottom style or not. Default is `true`. + */ + addMarginBottom?: boolean; + /** + * + */ + required?: boolean; +} + +function FormGroup(props: IFormGroupProps) { + const { addMarginBottom, tooltip } = props; + const useLabel = props.icon || props.label; + + /** + * Renders the label of this form group. + */ + const renderLabel = () => { + return ( + + ); + }; + + return ( + + {useLabel && renderLabel()} + {props.children} + + ); +} + +export default FormGroup; diff --git a/packages/tcore-console/src/Components/Home/ComputerUsage/ComputerUsage.style.ts b/packages/tcore-console/src/Components/Home/ComputerUsage/ComputerUsage.style.ts new file mode 100644 index 00000000..d7df6ef4 --- /dev/null +++ b/packages/tcore-console/src/Components/Home/ComputerUsage/ComputerUsage.style.ts @@ -0,0 +1,88 @@ +import styled, { css } from "styled-components"; +import { fonts } from "../../../theme"; + +/** + * Main style. + */ +export const Container = styled.div<{ $loading?: boolean }>` + display: flex; + align-items: center; + padding: 15px 5px; + height: 100%; + flex-direction: column; + + ${(props) => + props.$loading && + css` + opacity: 0.5; + `} + + > .space { + width: 100%; + height: 1px; + flex: none; + } +`; + +/** + */ +export const Item = styled.div` + width: 100%; + display: flex; + align-items: center; + flex: 1; + margin-bottom: 25px; + + .data { + display: flex; + flex-direction: column; + margin-left: 20px; + flex: 1; + + > .bar-container { + /* container of the bar */ + display: flex; + align-items: center; + + span { + margin-left: 10px; + font-size: ${fonts.medium}; + font-weight: 500; + } + } + + > h3 { + /* title */ + font-size: ${fonts.medium}; + font-weight: 500; + } + + > .description { + /* grey-colored description */ + color: ${(props) => props.theme.font2}; + word-break: break-word; + } + } +`; + +/** + * The progress bar. + */ +export const Bar = styled.div<{ value?: number }>` + height: 10px; + border-radius: 5px; + overflow: hidden; + background: rgba(0, 0, 0, 0.2); + width: 100%; + position: relative; + margin: 7px 0px; + + &::before { + background: ${(props) => props.theme.home}; + height: 100%; + width: ${(props) => props.value}%; + content: ""; + position: absolute; + transition: width 0.35s; + } +`; diff --git a/packages/tcore-console/src/Components/Home/ComputerUsage/ComputerUsage.tsx b/packages/tcore-console/src/Components/Home/ComputerUsage/ComputerUsage.tsx new file mode 100644 index 00000000..937d3e72 --- /dev/null +++ b/packages/tcore-console/src/Components/Home/ComputerUsage/ComputerUsage.tsx @@ -0,0 +1,80 @@ +import { IComputerUsage } from "@tago-io/tcore-sdk/types"; +import Icon from "../../Icon/Icon"; +import { EIcon } from "../../Icon/Icon.types"; +import Loading from "../../Loading/Loading"; +import * as Style from "./ComputerUsage.style"; + +/** + * Props. + */ +interface IComputerUsageProps { + /** + * Values. + */ + usages: IComputerUsage[] | null; +} + +/** + * This is the content of the `Computer Usage` card in the home page. + */ +function ComputerUsage(props: IComputerUsageProps) { + const { usages } = props; + if (!usages) { + return ; + } + + /** + * Gets the icon. + */ + const getIcon = (type: string) => { + if (type === "memory") { + return EIcon.memory; + } else if (type === "cpu") { + return EIcon.microchip; + } else if (type === "disk") { + return EIcon.hdd; + } else if (type === "battery") { + return EIcon["battery-full"]; + } else { + return EIcon.cog; + } + }; + + /** + * Renders a single usage. + */ + const renderUsage = (usage: IComputerUsage) => { + const { title, total, type, detail, used, description } = usage; + const percent = Math.floor((used / total) * 100); + + return ( + + + +
+

{title}

+ +
+ + {percent}% +
+ + + {detail} + {detail && description ? " • " : ""} + {description} + +
+
+ ); + }; + + return ( + + {(usages || []).map(renderUsage)} +
+ + ); +} + +export default ComputerUsage; diff --git a/packages/tcore-console/src/Components/Home/Home.style.ts b/packages/tcore-console/src/Components/Home/Home.style.ts new file mode 100644 index 00000000..bf90b40b --- /dev/null +++ b/packages/tcore-console/src/Components/Home/Home.style.ts @@ -0,0 +1,84 @@ +import styled from "styled-components"; +import * as ButtonStyle from "../Button/Button.style"; + +/** + * Main style. + */ +export const Container = styled.div` + background-color: ${(props) => props.theme.background2}; + flex: 1; + padding: 6px 0px; + display: flex; + flex-direction: column; + + .home-row { + display: flex; + width: 100%; + padding: 0px 7px; + min-width: 50%; + overflow: hidden; + + &:nth-child(2) { + flex: 1; + } + + > .charts-column { + flex: none; + width: 50%; + display: flex; + flex-direction: column; + } + + > .usage-column { + flex: none; + width: 50%; + display: flex; + flex-direction: column; + } + } +`; + +/** + */ +export const Card = styled.div` + background: ${(props) => props.theme.background1}; + flex: 1; + overflow: hidden; + border: 1px solid rgba(0, 0, 0, 0.1); + margin: 3px; + border-radius: 5px; + box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.07); + display: flex; + flex-direction: column; + + > .title { + display: flex; + padding: 0px 15px; + border-bottom: 1px solid rgba(0, 0, 0, 0.07); + height: 33px; + align-items: center; + justify-content: space-between; + + h2, + h2 span { + font-size: 1rem; + font-weight: 500; + } + + ${ButtonStyle.Container} { + border: 0px; + padding: 6px 8px; + } + } + + > .content { + position: relative; + padding: 7px 13px; + flex: 1; + overflow: auto; + + > div { + transition: opacity 0.2s; + } + } +`; diff --git a/packages/tcore-console/src/Components/Home/Home.test.tsx b/packages/tcore-console/src/Components/Home/Home.test.tsx new file mode 100644 index 00000000..9ba1562d --- /dev/null +++ b/packages/tcore-console/src/Components/Home/Home.test.tsx @@ -0,0 +1,32 @@ +jest.setMock("./RequestChart/RequestChart.tsx", "div"); + +import { render, screen } from "../../../utils/test-utils"; +import Home from "./Home"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("sets document.title", () => { + render(); + expect(document.title).toEqual("Home | TCore"); +}); + +test("renders `Summary` card", () => { + render(); + expect(screen.getByText("Summary")).toBeInTheDocument(); + expect(screen.getByTestId("home-summary")).toBeInTheDocument(); +}); + +test("renders `Computer Usage` card", () => { + render(); + expect(screen.getByText("Computer Usage")).toBeInTheDocument(); + expect(screen.getByTestId("home-computer-usage")).toBeInTheDocument(); +}); + +test("renders `Operating System` card", () => { + render(); + expect(screen.getByText("Operating System")).toBeInTheDocument(); + expect(screen.getByTestId("home-os")).toBeInTheDocument(); +}); diff --git a/packages/tcore-console/src/Components/Home/Home.tsx b/packages/tcore-console/src/Components/Home/Home.tsx new file mode 100644 index 00000000..d26dfa5f --- /dev/null +++ b/packages/tcore-console/src/Components/Home/Home.tsx @@ -0,0 +1,146 @@ +import { memo, useEffect } from "react"; +import { IOSInfo, INetworkInfo, IComputerUsage, ISummary } from "@tago-io/tcore-sdk/types"; +import setDocumentTitle from "../../Helpers/setDocumentTitle"; +import TooltipText from "../TooltipText/TooltipText"; +import Tooltip from "../Tooltip/Tooltip"; +import Button from "../Button/Button"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import useApiRequest from "../../Helpers/useApiRequest"; +import ComputerUsage from "./ComputerUsage/ComputerUsage"; +import * as Style from "./Home.style"; +import OperatingSystem from "./OperatingSystem/OperatingSystem"; +import Summary from "./Summary/Summary"; +import Network from "./Network/Network"; +import Statistics from "./Statistics/Statistics"; + +/** + * This is the home page. + */ +function Home() { + const { data: summary, mutate: mutateSummary } = useApiRequest("/summary"); + const { data: os } = useApiRequest("/hardware/os"); + const { data: network } = useApiRequest("/hardware/network"); + const { data: usages, mutate: mutateUsages } = useApiRequest( + "/hardware/usage" + ); + + /** + * Refreshes the data. + */ + const refresh = () => { + mutateSummary(() => null, true); + mutateUsages(() => usages, true); + }; + + /** + * Renders the operating system card. + */ + const renderOperatingSystem = () => { + return ( + +
+

Operating System

+
+
+ +
+
+ ); + }; + + /** + * Renders the summary card. + */ + const renderSummary = () => { + return ( + +
+ +

Summary

+
+ +
+ + + +
+
+
+ +
+
+ ); + }; + + /** + * Renders the `Network interfaces` card. + */ + const renderNetworkInterfaces = () => { + if (!network || network?.length === 0) { + return null; + } + + return ( + +
+ +

Network Overview

+
+
+
+ +
+
+ ); + }; + + /** + * Renders the `Computer Usage` card. + */ + const renderComputerUsage = () => { + return ( + +
+ +

Computer Usage

+
+
+
+ +
+
+ ); + }; + + /** + * Sets the document title. + */ + useEffect(() => { + setDocumentTitle("Home"); + }, []); + + return ( + +
+ {renderSummary()} + {renderOperatingSystem()} +
+ +
+
+ +
+ +
+ {renderNetworkInterfaces()} + {renderComputerUsage()} +
+
+
+ ); +} + +export default memo(Home); diff --git a/packages/tcore-console/src/Components/Home/Network/Network.style.ts b/packages/tcore-console/src/Components/Home/Network/Network.style.ts new file mode 100644 index 00000000..a2d4fa7f --- /dev/null +++ b/packages/tcore-console/src/Components/Home/Network/Network.style.ts @@ -0,0 +1,73 @@ +import styled from "styled-components"; +import { fonts } from "../../../theme"; + +/** + * Main style. + */ +export const Container = styled.div` + display: flex; + height: 100%; + transition: opacity 0.1s; + flex-wrap: wrap; + + > .space { + width: 100%; + height: 1px; + flex: none; + } +`; + +/** + */ +export const Item = styled.div` + width: 100%; + display: flex; + align-items: center; + flex: 1; + min-width: 50%; + padding: 10px 5px; + + .data { + display: flex; + flex-direction: column; + margin-left: 20px; + flex: 1; + + > h3 { + /* title */ + font-size: ${fonts.medium}; + font-weight: 500; + } + + > .ip { + margin: 3px 0px; + } + + > .description { + /* grey-colored description */ + color: ${(props) => props.theme.font2}; + } + } +`; + +/** + * The progress bar. + */ +export const Bar = styled.div<{ value?: number }>` + height: 10px; + border-radius: 5px; + overflow: hidden; + background: rgba(0, 0, 0, 0.2); + width: 100%; + position: relative; + margin: 7px 0px; + + &::before { + background: ${(props) => props.theme.home}; + height: 100%; + width: ${(props) => props.value}%; + content: ""; + position: absolute; + transition: width 0.35s; + } +`; diff --git a/packages/tcore-console/src/Components/Home/Network/Network.tsx b/packages/tcore-console/src/Components/Home/Network/Network.tsx new file mode 100644 index 00000000..76aa6a0b --- /dev/null +++ b/packages/tcore-console/src/Components/Home/Network/Network.tsx @@ -0,0 +1,43 @@ +import { INetworkInfo } from "@tago-io/tcore-sdk/types"; +import { memo } from "react"; +import formatBytes from "../../../Helpers/formatBytes"; +import Icon from "../../Icon/Icon"; +import { EIcon } from "../../Icon/Icon.types"; +import * as Style from "./Network.style"; + +/** + * Props. + */ +interface INetworkProps { + data: INetworkInfo[]; +} + +/** + * This is the content of the `Computer Usage` card in the home page. + */ +function Network(props: INetworkProps) { + const { data } = props; + + /** + * Renders a single usage. + */ + const renderData = (item: any) => { + const { ip, name, bytesTransferred, bytesDropped } = item; + return ( + + + +
+

{name}

+ {ip} + Transferred: {formatBytes(bytesTransferred)} + Dropped: {formatBytes(bytesDropped)} +
+
+ ); + }; + + return {data.map(renderData)}; +} + +export default memo(Network); diff --git a/packages/tcore-console/src/Components/Home/OperatingSystem/OperatingSystem.style.ts b/packages/tcore-console/src/Components/Home/OperatingSystem/OperatingSystem.style.ts new file mode 100644 index 00000000..40aaace4 --- /dev/null +++ b/packages/tcore-console/src/Components/Home/OperatingSystem/OperatingSystem.style.ts @@ -0,0 +1,45 @@ +import styled from "styled-components"; +import { fonts } from "../../../theme"; + +/** + * Main style. + */ +export const Container = styled.div` + display: flex; + align-items: center; + padding: 10px 5px; + height: 100%; + + .icon-container { + position: relative; + + .little-icon { + position: absolute; + bottom: -3px; + right: -5px; + padding: 3px; + background: white; + border-radius: 15%; + border: 1px solid rgba(0, 0, 0, 0.1); + display: flex; + align-items: center; + } + } + + .data { + display: flex; + flex-direction: column; + margin-left: 15px; + + > h3 { + font-weight: 500; + font-size: ${fonts.xlarge}; + } + + > .description { + color: ${(props) => props.theme.font2}; + margin-top: 3px; + font-size: ${fonts.default}; + } + } +`; diff --git a/packages/tcore-console/src/Components/Home/OperatingSystem/OperatingSystem.tsx b/packages/tcore-console/src/Components/Home/OperatingSystem/OperatingSystem.tsx new file mode 100644 index 00000000..0a7dcfad --- /dev/null +++ b/packages/tcore-console/src/Components/Home/OperatingSystem/OperatingSystem.tsx @@ -0,0 +1,83 @@ +import { IOSInfo } from "@tago-io/tcore-sdk/types"; +import { memo } from "react"; +import Icon from "../../Icon/Icon"; +import { EIcon } from "../../Icon/Icon.types"; +import Loading from "../../Loading/Loading"; +import * as Style from "./OperatingSystem.style"; + +/** + * Props. + */ +interface IOperatingSystemProps { + /** + * Value. + */ + os: IOSInfo | null; +} + +/** + * This is the content of the `Operating System` card in the home page. + */ +function OperatingSystem(props: IOperatingSystemProps) { + const { os } = props; + if (!os) { + return ; + } + + /** + * Gets the hardware icon. + */ + const getHardwareIcon = () => { + if (os.hardware === "raspberry-pi") { + return EIcon["raspberry-pi"]; + } + }; + + /** + * Gets the os icon. + */ + const getIcon = () => { + if (os.code === "windows") { + return EIcon.windows; + } else if (os.code === "linux") { + return EIcon.linux; + } else if (os.code === "mac") { + return EIcon.apple; + } else { + return null; + } + }; + + const osIcon = getIcon(); + const hardwareIcon = getHardwareIcon(); + + return ( + + {os.hardware ? ( +
+ + {osIcon && ( +
+ +
+ )} +
+ ) : ( +
+ +
+ )} + +
+

{os.name || "-"}

+ + Version {os.version} + {os.arch ? " • " : ""} + {os.arch} + +
+
+ ); +} + +export default memo(OperatingSystem); diff --git a/packages/tcore-console/src/Components/Home/RequestChart/RequestChart.style.ts b/packages/tcore-console/src/Components/Home/RequestChart/RequestChart.style.ts new file mode 100644 index 00000000..90a9daef --- /dev/null +++ b/packages/tcore-console/src/Components/Home/RequestChart/RequestChart.style.ts @@ -0,0 +1,31 @@ +import styled from "styled-components"; + +/** + * Main style. + */ +export const Container = styled.div<{ visible: boolean }>` + display: flex; + align-items: center; + height: 100%; + opacity: ${(props) => (props.visible ? "1" : "0")}; + + .tooltip-container { + display: flex; + flex-direction: column; + } + + .tooltip-content { + padding: 8px; + } + + .tooltip-warning { + padding: 8px; + background-color: rgba(0, 0, 0, 0.05); + + svg { + width: 12px; + height: 12px; + margin-right: 5px; + } + } +`; diff --git a/packages/tcore-console/src/Components/Home/RequestChart/RequestChart.tsx b/packages/tcore-console/src/Components/Home/RequestChart/RequestChart.tsx new file mode 100644 index 00000000..41468622 --- /dev/null +++ b/packages/tcore-console/src/Components/Home/RequestChart/RequestChart.tsx @@ -0,0 +1,198 @@ +import { Chart } from "@antv/g2"; +import { IStatistic } from "@tago-io/tcore-sdk/types"; +import { useEffect, useRef } from "react"; +import { useTheme } from "styled-components"; +import Loading from "../../Loading/Loading"; +import * as Style from "./RequestChart.style"; + +/** + * Props. + */ +interface IResourceHistoryChart { + /** + * Unique identifier for this chart. + */ + id: string; + /** + * Values. + */ + statistics: IStatistic[] | null; + /** + * Property to use. + */ + type: "input" | "output"; +} + +/** + * Usage statistic history chart. + */ +function ResourceHistoryChart(props: IResourceHistoryChart) { + const id = `resource-history-chart-${props.id}`; + const theme = useTheme(); + const chart = useRef(); + + const { statistics, type } = props; + + /** + * Gets the tooltip template. + */ + const getTooltipTemplate = () => { + return ` +
+
+ {value} {description} +
+ +
+ + + + + In progress +
+
+ `; + }; + + /** + * Runs when the data arrives and creates the chart. + */ + useEffect(() => { + chart.current = new Chart({ + autoFit: true, + container: id, + }); + + chart.current.legend(false); // hides the legend + chart.current.axis("value", false); // hides the y-axis + + // sets the tooltip info + chart.current.tooltip({ + itemTpl: getTooltipTemplate(), + showCrosshairs: true, + showTitle: false, + domStyles: { + "g2-tooltip": { padding: 0 }, // Remove horizontal padding + "g2-tooltip-title": { display: "none" }, // Remove top padding + }, + }); + + // make the x-axis start in 0 and end at the very end of the chart.current + chart.current.scale("time", { + range: [0, 1], + }); + + // formats the time according to the settings of the user + chart.current.axis("time", { + label: { + autoRotate: false, + }, + }); + + chart.current.animate(false); + + // shows the actual line: + chart.current + .line() + .position("time*value") + .color(theme.home) + .shape("line") + .tooltip({ + callback: (description, value, time, lastStyle) => ({ + description, + time, + value, + lastStyle, + }), + fields: ["description", "value", "time", "lastStyle"], + }) + .animate({ + appear: false, + enter: false, + leave: false, + }) + .label({ + callback: (value) => ({ + content: value || "", + }), + fields: ["value"], + }); + + // shows dots at every point in the data + chart.current + .point() + .position("time*value") + .color({ + callback: (last) => (last ? theme.buttonWarning : theme.buttonPrimary), + fields: ["last"], + }) + .shape("circle") + .tooltip(false) + .animate({ + appear: false, + enter: false, + leave: false, + }); + + // renders the modifications + chart.current.render(); + + return () => { + chart.current?.destroy(); + }; + }, [id, theme]); + + /** + */ + useEffect(() => { + const data = []; + let maximum = 0; + + for (let i = 0; i <= 15; i++) { + const p = statistics?.find((x) => { + const diff = new Date().getMinutes() - new Date(x.time).getMinutes(); + return i === diff; + }); + + const time = i === 0 ? "Now" : `${i}m`; + const value = p?.[type] || 0; + const last = i === 0; + + maximum = Math.max(maximum, value); + + let description = value === 1 ? `${type}` : `${type}s`; + if (i === 0) { + description += ` so far`; + } else { + description += ` ${time} ago`; + } + + data.unshift({ + time, + value, + description, + lastStyle: last ? "flex" : "none", + last, + }); + } + + chart.current?.scale({ + value: { + min: 0, + max: maximum * 1.2, + }, + }); + + chart.current?.changeData(data); + chart.current?.render(true); + }, [type, statistics]); + + return ( + <> + {!statistics && } + {} + + ); +} + +export default ResourceHistoryChart; diff --git a/packages/tcore-console/src/Components/Home/Statistics/Statistics.tsx b/packages/tcore-console/src/Components/Home/Statistics/Statistics.tsx new file mode 100644 index 00000000..2b99f56a --- /dev/null +++ b/packages/tcore-console/src/Components/Home/Statistics/Statistics.tsx @@ -0,0 +1,105 @@ +import { ESocketResource, IStatistic } from "@tago-io/tcore-sdk/types"; +import { observer } from "mobx-react"; +import { memo, useEffect, useRef, useState } from "react"; +import useApiRequest from "../../../Helpers/useApiRequest"; +import { socket } from "../../../System/Socket"; +import store from "../../../System/Store"; +import TooltipText from "../../TooltipText/TooltipText"; +import * as HomeStyle from "../Home.style"; +import RequestChart from "../RequestChart/RequestChart"; + +/** + * Statistics section of the home page. + * This component contains two cards that show two different charts. + */ +function Statistics() { + const [statistics, setStatistics] = useState(null); + const { data } = useApiRequest("/statistics"); + const interval = useRef(); + + /** + * Listens to a new hourly statistic. + */ + useEffect(() => { + function onNewStatistic(stat: IStatistic) { + const item = statistics?.find((x) => x.time === stat.time); + if (item) { + item.input += stat.input; + item.output += stat.output; + } else { + statistics?.push(stat); + } + setStatistics([...(statistics as IStatistic[])]); + } + + socket.on(`statistic::hourly`, onNewStatistic); + return () => { + socket.off(`statistic::hourly`, onNewStatistic); + }; + }); + + /** + * Attaches and detaches the socket to get the statistic updates in realtime. + */ + useEffect(() => { + if (store.socketConnected) { + socket.emit("attach", ESocketResource.statistic); + return () => { + socket.emit("detach", ESocketResource.statistic); + }; + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [store.socketConnected]); + + /** + * Sets the statistics interval. + */ + useEffect(() => { + interval.current = setInterval(() => { + setStatistics([...(statistics as IStatistic[])]); + }, 1000 * 60); + + return () => { + clearInterval(interval.current); + }; + }, [statistics]); + + /** + * Sets the local statistics. + */ + useEffect(() => { + if (data) { + setStatistics(data as IStatistic[]); + } + }, [data]); + + return ( + <> + {/* Input */} + +
+ +

Data input per minute

+
+
+
+ +
+
+ + {/* Output */} + +
+ +

Data output per minute

+
+
+
+ +
+
+ + ); +} + +export default memo(observer(Statistics)); diff --git a/packages/tcore-console/src/Components/Home/Summary/Summary.style.ts b/packages/tcore-console/src/Components/Home/Summary/Summary.style.ts new file mode 100644 index 00000000..4840af12 --- /dev/null +++ b/packages/tcore-console/src/Components/Home/Summary/Summary.style.ts @@ -0,0 +1,52 @@ +import styled, { css } from "styled-components"; + +/** + * Main container. + */ +export const Container = styled.div<{ $loading: boolean }>` + > .group { + display: flex; + flex-direction: row; + + &.separator { + margin-top: 5px; + padding-top: 5px; + border-top: 1px solid rgba(0, 0, 0, 0.1); + } + } + + ${(props) => + props.$loading && + css` + opacity: 0.5; + `} +`; + +/** + */ +export const Item = styled.div` + display: flex; + padding: 7px 0px; + align-items: center; + flex: 1; + justify-content: space-between; + + &:nth-child(1) { + padding-right: 10px; + margin-right: 10px; + border-right: 1px solid rgba(0, 0, 0, 0.1); + } + + > .left { + display: flex; + align-items: center; + + i { + margin-right: 10px; + } + } + + > .value { + color: ${(props) => props.theme.home}; + } +`; diff --git a/packages/tcore-console/src/Components/Home/Summary/Summary.tsx b/packages/tcore-console/src/Components/Home/Summary/Summary.tsx new file mode 100644 index 00000000..fb96c4ac --- /dev/null +++ b/packages/tcore-console/src/Components/Home/Summary/Summary.tsx @@ -0,0 +1,62 @@ +import { ISummary } from "@tago-io/tcore-sdk/types"; +import { memo } from "react"; +import Icon from "../../Icon/Icon"; +import { EIcon } from "../../Icon/Icon.types"; +import * as Style from "./Summary.style"; + +/** + * Props. + */ +interface ISummaryProps { + /** + * Data to be rendered. + */ + data?: ISummary | null; +} + +/** + * Summary component for the home page. + */ +function Summary(props: ISummaryProps) { + const { data } = props; + const loading = !data; + + /** + * Renders a single item in the list. + */ + const renderItem = (icon: EIcon, name: string, value?: number | string) => { + let realValue = value; + if (loading || value === undefined || value === null) { + realValue = "-"; + } + + return ( + +
+ + {name} +
+
{realValue}
+
+ ); + }; + + return ( + +
+ {renderItem(EIcon.device, "Devices", data?.device)} + {renderItem(EIcon.bucket, "Buckets", data?.device)} +
+
+ {renderItem(EIcon.code, "Analysis", data?.analysis)} + {renderItem(EIcon.bolt, "Actions", data?.action)} +
+
+ {renderItem(EIcon.connector, "Connectors", "-")} + {renderItem(EIcon.tcore, "Version", "0.3.3")} +
+
+ ); +} + +export default memo(Summary); diff --git a/packages/tcore-console/src/Components/Icon/Icon.style.tsx b/packages/tcore-console/src/Components/Icon/Icon.style.tsx new file mode 100644 index 00000000..79d0be03 --- /dev/null +++ b/packages/tcore-console/src/Components/Icon/Icon.style.tsx @@ -0,0 +1,45 @@ +import styled, { css, keyframes } from "styled-components"; + +const rotate = keyframes` + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +`; + +/** + * Main style of the component. + */ +export const Container = styled.i<{ + isRotating?: boolean; + size: string; + color?: string; +}>` + display: inline-block; + width: ${(props) => props.size}; + height: ${(props) => props.size}; + + svg { + fill: ${(props) => props.color}; + display: block; + width: ${(props) => props.size}; + height: ${(props) => props.size}; + + *:not(.preserve) { + fill: ${(props) => props.color}; + stroke: ${(props) => props.color}; + } + } + + ${(props) => + props.isRotating && + css` + svg { + animation: ${rotate} infinite linear 0.75s; + } + `} +`; + +export default Container; diff --git a/packages/tcore-console/src/Components/Icon/Icon.test.tsx b/packages/tcore-console/src/Components/Icon/Icon.test.tsx new file mode 100644 index 00000000..94dfbff5 --- /dev/null +++ b/packages/tcore-console/src/Components/Icon/Icon.test.tsx @@ -0,0 +1,34 @@ +import { render, screen } from "../../../utils/test-utils"; +import Icon from "./Icon"; +import { EIcon } from "./Icon.types"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("renders icon data", () => { + render(); + expect(screen.getByText("cog-icon-mock")); +}); + +test("has correct default size", () => { + const { container } = render(); + const style = window.getComputedStyle(container.firstChild as HTMLElement); + expect(style.width).toEqual("12px"); + expect(style.height).toEqual("12px"); +}); + +test("respects `size` prop", () => { + const { container } = render(); + const style = window.getComputedStyle(container.firstChild as HTMLElement); + expect(style.width).toEqual("20px"); + expect(style.height).toEqual("20px"); +}); + +test("respects `color` prop", () => { + render(); + const svg = screen.getByText("cog-icon-mock"); + const style = window.getComputedStyle(svg); + expect(style.fill).toEqual("red"); +}); diff --git a/packages/tcore-console/src/Components/Icon/Icon.tsx b/packages/tcore-console/src/Components/Icon/Icon.tsx new file mode 100644 index 00000000..5f1117b9 --- /dev/null +++ b/packages/tcore-console/src/Components/Icon/Icon.tsx @@ -0,0 +1,54 @@ +import { memo } from "react"; +import { EIcon, icons } from "./Icon.types"; +import * as Style from "./Icon.style"; + +/** + * Props. + */ +interface IIcon { + /** + * Size of the icon. + */ + size?: string; + /** + * The icon identifier. + */ + icon?: EIcon; + /** + * Optional color of the icon. + */ + color?: string; + /** + * If the icon should be rotating or not. + */ + rotate?: boolean; +} + +/** + * Renders a dynamic SVG icon. + */ +function Icon(props: IIcon) { + if (!props.icon) { + return null; + } + + const { rotate } = props; + const Component = icons[props.icon]; + const size = props.size || "12px"; + + return ( + + {Component?.ReactComponent ? ( + // For CRA projects, the svg can be imported manually by using the `ReactComponent` + // object inside of the imported .svg. This won't work for the tcore-console project. + + ) : Component?.default ? ( + // The default import that is provided by the `@svg/core` library, this is the way that + // tcore-console uses the svg element. + + ) : null} + + ); +} + +export default memo(Icon); diff --git a/packages/tcore-console/src/Components/Icon/Icon.types.ts b/packages/tcore-console/src/Components/Icon/Icon.types.ts new file mode 100644 index 00000000..43f71a30 --- /dev/null +++ b/packages/tcore-console/src/Components/Icon/Icon.types.ts @@ -0,0 +1,197 @@ +/* eslint-disable prettier/prettier */ + +// ! This file is automatically generated. Please don't change it. + +/** + * Types of icons available in the system. + * Each one must match the corresponding filename in the /assets/icons folder. + */ +enum EIcon { + "apple" = "apple", + "ban" = "ban", + "bars" = "bars", + "battery-full" = "battery-full", + "bolt" = "bolt", + "brush" = "brush", + "bucket" = "bucket", + "bullhorn" = "bullhorn", + "caret-down" = "caret-down", + "caret-right" = "caret-right", + "caret-up" = "caret-up", + "certificate" = "certificate", + "check" = "check", + "chevron-left" = "chevron-left", + "chevron-right" = "chevron-right", + "circle" = "circle", + "clock" = "clock", + "cloud" = "cloud", + "code" = "code", + "cog" = "cog", + "comment-dots" = "comment-dots", + "connector" = "connector", + "copy" = "copy", + "cube" = "cube", + "cubes" = "cubes", + "database-double" = "database-double", + "database" = "database", + "desktop" = "desktop", + "device-union" = "device-union", + "device" = "device", + "dice-d20" = "dice-d20", + "download" = "download", + "ellipsis-v" = "ellipsis-v", + "envelope" = "envelope", + "exclamation-circle" = "exclamation-circle", + "exclamation-triangle" = "exclamation-triangle", + "external-link-alt" = "external-link-alt", + "eye" = "eye", + "file-alt" = "file-alt", + "file-import" = "file-import", + "folder" = "folder", + "github" = "github", + "globe-americas" = "globe-americas", + "globe" = "globe", + "grip-horizontal" = "grip-horizontal", + "hashtag" = "hashtag", + "hdd" = "hdd", + "home" = "home", + "image" = "image", + "io" = "io", + "key" = "key", + "link" = "link", + "linux" = "linux", + "list" = "list", + "lock" = "lock", + "markdown" = "markdown", + "memory" = "memory", + "microchip" = "microchip", + "minus" = "minus", + "mountain" = "mountain", + "network-wired" = "network-wired", + "pause" = "pause", + "pencil-alt" = "pencil-alt", + "play" = "play", + "plus-circle" = "plus-circle", + "plus" = "plus", + "puzzle-piece" = "puzzle-piece", + "question-circle" = "question-circle", + "raspberry-pi" = "raspberry-pi", + "redo" = "redo", + "save" = "save", + "scroll" = "scroll", + "search" = "search", + "shapes" = "shapes", + "sign-out-alt" = "sign-out-alt", + "snowflake" = "snowflake", + "spinner" = "spinner", + "star" = "star", + "stopwatch" = "stopwatch", + "store" = "store", + "sync-alt" = "sync-alt", + "tag" = "tag", + "tcore" = "tcore", + "temperature-high" = "temperature-high", + "th-large" = "th-large", + "times" = "times", + "trash-alt" = "trash-alt", + "user-alt" = "user-alt", + "wifi" = "wifi", + "window-maximize" = "window-maximize", + "windows" = "windows", +} + +const icons = { + "apple": require("../../../assets/icons/apple.svg"), + "ban": require("../../../assets/icons/ban.svg"), + "bars": require("../../../assets/icons/bars.svg"), + "battery-full": require("../../../assets/icons/battery-full.svg"), + "bolt": require("../../../assets/icons/bolt.svg"), + "brush": require("../../../assets/icons/brush.svg"), + "bucket": require("../../../assets/icons/bucket.svg"), + "bullhorn": require("../../../assets/icons/bullhorn.svg"), + "caret-down": require("../../../assets/icons/caret-down.svg"), + "caret-right": require("../../../assets/icons/caret-right.svg"), + "caret-up": require("../../../assets/icons/caret-up.svg"), + "certificate": require("../../../assets/icons/certificate.svg"), + "check": require("../../../assets/icons/check.svg"), + "chevron-left": require("../../../assets/icons/chevron-left.svg"), + "chevron-right": require("../../../assets/icons/chevron-right.svg"), + "circle": require("../../../assets/icons/circle.svg"), + "clock": require("../../../assets/icons/clock.svg"), + "cloud": require("../../../assets/icons/cloud.svg"), + "code": require("../../../assets/icons/code.svg"), + "cog": require("../../../assets/icons/cog.svg"), + "comment-dots": require("../../../assets/icons/comment-dots.svg"), + "connector": require("../../../assets/icons/connector.svg"), + "copy": require("../../../assets/icons/copy.svg"), + "cube": require("../../../assets/icons/cube.svg"), + "cubes": require("../../../assets/icons/cubes.svg"), + "database-double": require("../../../assets/icons/database-double.svg"), + "database": require("../../../assets/icons/database.svg"), + "desktop": require("../../../assets/icons/desktop.svg"), + "device-union": require("../../../assets/icons/device-union.svg"), + "device": require("../../../assets/icons/device.svg"), + "dice-d20": require("../../../assets/icons/dice-d20.svg"), + "download": require("../../../assets/icons/download.svg"), + "ellipsis-v": require("../../../assets/icons/ellipsis-v.svg"), + "envelope": require("../../../assets/icons/envelope.svg"), + "exclamation-circle": require("../../../assets/icons/exclamation-circle.svg"), + "exclamation-triangle": require("../../../assets/icons/exclamation-triangle.svg"), + "external-link-alt": require("../../../assets/icons/external-link-alt.svg"), + "eye": require("../../../assets/icons/eye.svg"), + "file-alt": require("../../../assets/icons/file-alt.svg"), + "file-import": require("../../../assets/icons/file-import.svg"), + "folder": require("../../../assets/icons/folder.svg"), + "github": require("../../../assets/icons/github.svg"), + "globe-americas": require("../../../assets/icons/globe-americas.svg"), + "globe": require("../../../assets/icons/globe.svg"), + "grip-horizontal": require("../../../assets/icons/grip-horizontal.svg"), + "hashtag": require("../../../assets/icons/hashtag.svg"), + "hdd": require("../../../assets/icons/hdd.svg"), + "home": require("../../../assets/icons/home.svg"), + "image": require("../../../assets/icons/image.svg"), + "io": require("../../../assets/icons/io.svg"), + "key": require("../../../assets/icons/key.svg"), + "link": require("../../../assets/icons/link.svg"), + "linux": require("../../../assets/icons/linux.svg"), + "list": require("../../../assets/icons/list.svg"), + "lock": require("../../../assets/icons/lock.svg"), + "markdown": require("../../../assets/icons/markdown.svg"), + "memory": require("../../../assets/icons/memory.svg"), + "microchip": require("../../../assets/icons/microchip.svg"), + "minus": require("../../../assets/icons/minus.svg"), + "mountain": require("../../../assets/icons/mountain.svg"), + "network-wired": require("../../../assets/icons/network-wired.svg"), + "pause": require("../../../assets/icons/pause.svg"), + "pencil-alt": require("../../../assets/icons/pencil-alt.svg"), + "play": require("../../../assets/icons/play.svg"), + "plus-circle": require("../../../assets/icons/plus-circle.svg"), + "plus": require("../../../assets/icons/plus.svg"), + "puzzle-piece": require("../../../assets/icons/puzzle-piece.svg"), + "question-circle": require("../../../assets/icons/question-circle.svg"), + "raspberry-pi": require("../../../assets/icons/raspberry-pi.svg"), + "redo": require("../../../assets/icons/redo.svg"), + "save": require("../../../assets/icons/save.svg"), + "scroll": require("../../../assets/icons/scroll.svg"), + "search": require("../../../assets/icons/search.svg"), + "shapes": require("../../../assets/icons/shapes.svg"), + "sign-out-alt": require("../../../assets/icons/sign-out-alt.svg"), + "snowflake": require("../../../assets/icons/snowflake.svg"), + "spinner": require("../../../assets/icons/spinner.svg"), + "star": require("../../../assets/icons/star.svg"), + "stopwatch": require("../../../assets/icons/stopwatch.svg"), + "store": require("../../../assets/icons/store.svg"), + "sync-alt": require("../../../assets/icons/sync-alt.svg"), + "tag": require("../../../assets/icons/tag.svg"), + "tcore": require("../../../assets/icons/tcore.svg"), + "temperature-high": require("../../../assets/icons/temperature-high.svg"), + "th-large": require("../../../assets/icons/th-large.svg"), + "times": require("../../../assets/icons/times.svg"), + "trash-alt": require("../../../assets/icons/trash-alt.svg"), + "user-alt": require("../../../assets/icons/user-alt.svg"), + "wifi": require("../../../assets/icons/wifi.svg"), + "window-maximize": require("../../../assets/icons/window-maximize.svg"), + "windows": require("../../../assets/icons/windows.svg"), +} + +export { EIcon, icons }; diff --git a/packages/tcore-console/src/Components/IconRadio/IconRadio.style.ts b/packages/tcore-console/src/Components/IconRadio/IconRadio.style.ts new file mode 100644 index 00000000..ef88e2af --- /dev/null +++ b/packages/tcore-console/src/Components/IconRadio/IconRadio.style.ts @@ -0,0 +1,58 @@ +import styled, { css } from "styled-components"; +import * as IconStyle from "../Icon/Icon.style"; + +/** + * Main style. + */ +export const Container = styled.div``; + +/** + * A single option. + */ +export const Option = styled.label<{ + color?: string; + disabled?: boolean; +}>` + display: flex; + align-items: center; + margin-bottom: 1rem; + + ${(props) => + props.disabled && + css` + pointer-events: none; + opacity: 0.7; + `} + + > input { + float: left; + vertical-align: middle; + color: inherit; + margin: 0; + } + + > .content { + display: flex; + align-items: center; + + ${IconStyle.Container} { + margin: 0px 10px; + } + + .info { + > .title { + font-weight: bold; + font-size: 1rem; + color: ${(props) => props.color || "inherit"}; + } + + > .description { + display: block; + font-size: 12px; + font-weight: 400; + margin: 0; + color: ${(props) => props.theme.font2}; + } + } + } +`; diff --git a/packages/tcore-console/src/Components/IconRadio/IconRadio.test.tsx b/packages/tcore-console/src/Components/IconRadio/IconRadio.test.tsx new file mode 100644 index 00000000..be46ce7e --- /dev/null +++ b/packages/tcore-console/src/Components/IconRadio/IconRadio.test.tsx @@ -0,0 +1,63 @@ +import { within } from "@testing-library/react"; +import { fireEvent, render, screen } from "../../../utils/test-utils"; +import { EIcon } from "../Icon/Icon.types"; +import IconRadio from "./IconRadio"; + +/** + * Default (required) props for the component. + */ +const defaultProps = { + value: "", + options: [], + onChange: jest.fn(), +}; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("renders simple option", () => { + const options = [{ icon: EIcon.cog, label: "Hello", value: "world" }]; + render(); + + const option = screen.getByTestId("option-world"); + expect(within(option).getByText("Hello")).toBeInTheDocument(); + expect(within(option).getByText("cog-icon-mock")).toBeInTheDocument(); +}); + +test("renders detailed option", () => { + const options = [ + { + icon: EIcon.home, + color: "red", + description: "I work remotely", + label: "Remote", + value: "remote", + }, + ]; + render(); + const remote = screen.getByTestId("option-remote"); + expect(within(remote).getByText("I work remotely")).toBeInTheDocument(); + expect(within(remote).getByText("Remote")).toBeInTheDocument(); + + const svg = screen.getByText("home-icon-mock"); + const style = window.getComputedStyle(svg); + expect(style.fill).toEqual("red"); +}); + +test("doesn't call onChange if the option is disabled", () => { + const onChange = jest.fn(); + const options = [{ icon: EIcon.cog, disabled: true, label: "Hello", value: "world" }]; + render(); + fireEvent.click(screen.getByTestId("option-world")); + expect(onChange).toHaveBeenCalledWith("world"); +}); + +test("calls onChange when an option is clicked", () => { + const onChange = jest.fn(); + const options = [{ icon: EIcon.cog, label: "Hello", value: "world" }]; + render(); + fireEvent.click(screen.getByTestId("option-world")); + expect(onChange).toHaveBeenCalledWith("world"); +}); diff --git a/packages/tcore-console/src/Components/IconRadio/IconRadio.tsx b/packages/tcore-console/src/Components/IconRadio/IconRadio.tsx new file mode 100644 index 00000000..183f888d --- /dev/null +++ b/packages/tcore-console/src/Components/IconRadio/IconRadio.tsx @@ -0,0 +1,60 @@ +import Icon from "../Icon/Icon"; +import { IIconRadioOption } from "./IconRadio.types"; +import * as Style from "./IconRadio.style"; + +/** + * Props. + */ +interface IIconRadioProps { + /** + * Value currently selected. + */ + value: string; + /** + * Options in the list. + * Each option here will be rendered as a selectable input option. + */ + options: IIconRadioOption[]; + /** + * Called when the value changes. + */ + onChange: (value: string) => void; +} + +/** + * This component shows a list of inputs with type="radio". + * For each option, a big icon, a title and a description will be rendered. + */ +function IconRadio(props: IIconRadioProps) { + const { value, onChange, options } = props; + + /** + * Renders a single option in the list. + */ + const renderOption = (option: IIconRadioOption) => { + const checked = value === option.value; + return ( + onChange(option.value)} + color={option.color} + disabled={option.disabled} + key={option.value} + data-testid={`option-${option.value}`} + > + + +
+ +
+
{option.label}
+
{option.description}
+
+
+
+ ); + }; + + return {options.map(renderOption)}; +} + +export default IconRadio; diff --git a/packages/tcore-console/src/Components/IconRadio/IconRadio.types.ts b/packages/tcore-console/src/Components/IconRadio/IconRadio.types.ts new file mode 100644 index 00000000..b0dc34ea --- /dev/null +++ b/packages/tcore-console/src/Components/IconRadio/IconRadio.types.ts @@ -0,0 +1,32 @@ +import { ReactNode } from "react"; +import { EIcon } from "../Icon/Icon.types"; + +/** + * A single option in the icon radio. + */ +export interface IIconRadioOption { + /** + * Inner value for the option. + */ + value: string; + /** + * Label of the option. + */ + label: ReactNode; + /** + * Icon for the option. + */ + icon: EIcon; + /** + * Description that will appear below the title. + */ + description?: string; + /** + * Color for the icon when selected. + */ + color?: string; + /** + * If the option is disabled or not. + */ + disabled?: boolean; +} diff --git a/packages/tcore-console/src/Components/InnerNav/InnerNav.style.ts b/packages/tcore-console/src/Components/InnerNav/InnerNav.style.ts new file mode 100644 index 00000000..3f22691e --- /dev/null +++ b/packages/tcore-console/src/Components/InnerNav/InnerNav.style.ts @@ -0,0 +1,60 @@ +import styled from "styled-components"; +import { fonts } from "../../theme"; +import * as ButtonStyle from "../Button/Button.style"; + +/** + * Main style. + */ +export const Container = styled.nav` + display: flex; + align-items: center; + height: 40px; + padding: 0px 15px; + flex: none; + box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 8px 0px; + justify-content: space-between; + z-index: 2; + position: relative; + background: ${(props) => props.theme.background1}; + + > section { + height: 100%; + display: flex; + align-items: center; + + .title-data { + display: flex; + flex-direction: column; + + h1 { + color: ${(props) => props.color}; + font-weight: 500; + } + + span, + b { + font-size: ${fonts.small}; + color: ${(props) => props.theme.font2}; + } + } + } + + ${ButtonStyle.Container} { + /* buttons should be a tiny bit smaller in this inner nav */ + padding: 5px 10px; + white-space: nowrap; + } +`; + +/** + */ +export const LogoContainer = styled.div` + border-right: 2px solid ${(props) => props.color}; + display: flex; + height: 30px; + flex: none; + align-items: center; + justify-content: center; + margin-right: 15px; + padding-right: 15px; +`; diff --git a/packages/tcore-console/src/Components/InnerNav/InnerNav.test.tsx b/packages/tcore-console/src/Components/InnerNav/InnerNav.test.tsx new file mode 100644 index 00000000..c0fa4ef2 --- /dev/null +++ b/packages/tcore-console/src/Components/InnerNav/InnerNav.test.tsx @@ -0,0 +1,36 @@ +import { render, screen } from "../../../utils/test-utils"; +import { EIcon } from "../Icon/Icon.types"; +import InnerNav from "./InnerNav"; + +/** + * Default (required) props for the component. + */ +const defaultProps = { + icon: EIcon.cog, + title: "", +}; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("renders title", () => { + render(); + expect(screen.getByText("Hello world")).toBeInTheDocument(); +}); + +test("renders icon", () => { + render(); + expect(screen.getByText("device-icon-mock")).toBeInTheDocument(); +}); + +test("renders description", () => { + render(); + expect(screen.getByText("Foo")).toBeInTheDocument(); +}); + +test("renders children", () => { + render(Page Content); + expect(screen.getByText("Page Content")).toBeInTheDocument(); +}); diff --git a/packages/tcore-console/src/Components/InnerNav/InnerNav.tsx b/packages/tcore-console/src/Components/InnerNav/InnerNav.tsx new file mode 100644 index 00000000..1691ffb0 --- /dev/null +++ b/packages/tcore-console/src/Components/InnerNav/InnerNav.tsx @@ -0,0 +1,67 @@ +import { ReactNode } from "react"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import * as Style from "./InnerNav.style"; + +/** + * Props. + */ +interface IInnerNavProps { + /** + * Title of this component. + */ + title: ReactNode; + /** + * Description of the component, will be rendered below the title. + */ + description?: ReactNode; + /** + * Optional content to be rendered in the right side of this component. + */ + children?: ReactNode; + /** + * Optional color, will be passed to the Icon component. + */ + color?: string; + /** + * Icon to be used in this component. This can be overridden by the `image` prop. + */ + icon?: EIcon; + /** + * Optional custom rendering of the icon. + */ + onRenderIcon?: () => ReactNode; +} + +/** + * This is a page title nav-like element that shows an icon with a specific color, + * a text, and a description of the screen. + * + * You can customize whatever appears on the right side of the component by using the children prop. + */ +function InnerNav(props: IInnerNavProps) { + const { title, description, children, color, icon, onRenderIcon } = props; + + return ( + +
+ + {onRenderIcon !== undefined ? ( + onRenderIcon() + ) : icon ? ( + + ) : null} + + +
+

{title}

+ {description && {description}} +
+
+ +
{children}
+
+ ); +} + +export default InnerNav; diff --git a/packages/tcore-console/src/Components/Input/Input.style.ts b/packages/tcore-console/src/Components/Input/Input.style.ts new file mode 100644 index 00000000..c4091773 --- /dev/null +++ b/packages/tcore-console/src/Components/Input/Input.style.ts @@ -0,0 +1,11 @@ +import styled from "styled-components"; +import FormControlStyles from "../Styles/FormControlStyles"; + +/** + * Main input style. + */ +export const Container = styled.input` + ${FormControlStyles} +`; + +export default Container; diff --git a/packages/tcore-console/src/Components/Input/Input.test.tsx b/packages/tcore-console/src/Components/Input/Input.test.tsx new file mode 100644 index 00000000..f8291bca --- /dev/null +++ b/packages/tcore-console/src/Components/Input/Input.test.tsx @@ -0,0 +1,44 @@ +import { createRef } from "react"; +import { fireEvent, render, screen } from "../../../utils/test-utils"; +import Input from "./Input"; + +test("renders without crashing", async () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("sets ref correctly", async () => { + const ref = createRef(); + expect(ref.current).toBeFalsy(); + render(); + expect(ref.current).toBeTruthy(); +}); + +test("calls onChange correctly", async () => { + const onChange = jest.fn(); + render(); + + const input = await screen.findByRole("textbox"); + fireEvent.change(input, { target: { value: "Hello world" } }); + + expect(onChange).toHaveBeenCalled(); + expect(onChange.mock.calls[0][0].target.value).toEqual("Hello world"); +}); + +test("passes value prop to inner DOM node", async () => { + render(); + const input = (await screen.findByRole("textbox")) as HTMLInputElement; + expect(input.value).toEqual("Hello world"); +}); + +test("passes readOnly prop to inner DOM node", async () => { + render(); + const input = (await screen.findByRole("textbox")) as HTMLInputElement; + expect(input.readOnly).toBeTruthy(); +}); + +test("passes disabled prop to inner DOM node", async () => { + render(); + const input = (await screen.findByRole("textbox")) as HTMLInputElement; + expect(input.disabled).toBeTruthy(); +}); diff --git a/packages/tcore-console/src/Components/Input/Input.tsx b/packages/tcore-console/src/Components/Input/Input.tsx new file mode 100644 index 00000000..29baf7ee --- /dev/null +++ b/packages/tcore-console/src/Components/Input/Input.tsx @@ -0,0 +1,30 @@ +import { InputHTMLAttributes, memo, forwardRef } from "react"; +import ErrorMessage from "../ErrorMessage/ErrorMessage"; +import * as Style from "./Input.style"; + +interface IInput extends InputHTMLAttributes { + /** + * Indicates if this component has invalid data. + * If this is set to `true`, this component will get a red border. + */ + error?: boolean; + /** + * Sets the message that will appear below the input if this component has an error. + */ + errorMessage?: string; +} + +/** + * Default HTML input but with a style applied to it. + */ +function Input(props: IInput, ref: any) { + const { error, errorMessage } = props; + return ( + <> + + {error && errorMessage && {errorMessage}} + + ); +} + +export default memo(forwardRef(Input)); diff --git a/packages/tcore-console/src/Components/InputList/InputList.tsx b/packages/tcore-console/src/Components/InputList/InputList.tsx new file mode 100644 index 00000000..296f0f20 --- /dev/null +++ b/packages/tcore-console/src/Components/InputList/InputList.tsx @@ -0,0 +1,85 @@ +import Accordion from "../Accordion/Accordion"; +import { EIcon } from "../Icon/Icon.types"; +import Input from "../Input/Input"; +import RowManipulator from "../RowManipulator/RowManipulator"; + +/** + * Props. + */ +interface IInputList { + title?: string; + description?: string; + icon?: EIcon; + value: string[]; + onChange: (value: string[]) => void; + errors?: any; + placeholder?: string; +} + +/** + * A Row manipulator of inputs. + */ +function InputList(props: IInputList) { + const { title, description, placeholder, icon, value, errors, onChange } = props; + + /** + * Called when an item changes. + */ + const onChangeItem = (index: number, e: string) => { + value[index] = e; + onChange([...value]); + }; + + /** + * Adds a row. + */ + const addItem = () => { + value.push(""); + onChange([...value]); + }; + + /** + * Removes a row. + */ + const removeItem = (index: number) => { + value.splice(index, 1); + onChange([...value]); + }; + + /** + * Renders the input. + */ + const renderInput = (item: any, index: number) => { + return ( + onChangeItem(index, e.target.value)} + placeholder={placeholder || "enter the value for this row"} + value={item} + style={{ marginRight: "5px" }} + error={errors?.[index]} + /> + ); + }; + + // main content, may or may not be encapsulated by an accordion. + const content = ( + + ); + + if (!title) { + return content; + } + + return ( + + {content} + + ); +} + +export default InputList; diff --git a/packages/tcore-console/src/Components/InputRadio/InputRadio.style.tsx b/packages/tcore-console/src/Components/InputRadio/InputRadio.style.tsx new file mode 100644 index 00000000..d4f43bbc --- /dev/null +++ b/packages/tcore-console/src/Components/InputRadio/InputRadio.style.tsx @@ -0,0 +1,52 @@ +import styled, { css } from "styled-components"; + +/** + */ +export const Container = styled.div<{ stretch?: boolean }>` + display: flex; + + > .item:nth-child(1) { + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + } + + > .item:last-child { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + } + + ${(props) => + props.stretch && + css` + flex: 1; + width: 100%; + `} +`; + +/** + */ +export const Item = styled.button<{ stretch?: boolean; selected?: boolean }>` + padding: 5px 10px; + border: 1px solid rgba(0, 0, 0, 0.1); + display: flex; + align-items: center; + background: ${(props) => props.theme.buttonDefault}; + color: ${(props) => props.theme.buttonDefaultFont}; + margin-right: -1px; + cursor: pointer; + outline: 0; + justify-content: center; + + ${(props) => + props.selected && + css` + background: ${props.theme.buttonPrimary}; + color: ${props.theme.buttonPrimaryFont}; + `} + + ${(props) => + props.stretch && + css` + flex: 1; + `} +`; diff --git a/packages/tcore-console/src/Components/InputRadio/InputRadio.tsx b/packages/tcore-console/src/Components/InputRadio/InputRadio.tsx new file mode 100644 index 00000000..e1a5ce74 --- /dev/null +++ b/packages/tcore-console/src/Components/InputRadio/InputRadio.tsx @@ -0,0 +1,51 @@ +import * as Style from "./InputRadio.style"; + +/** + * Props. + */ +interface IInputRadioProps { + /** + * Options. + */ + options: any[]; + /** + * Selected value. + */ + value: string; + /** + * If this component should stretch with flex to fill remaining space. + */ + stretch?: boolean; + /** + * Called when the user selects a new value. + */ + onChange: (value: string) => void; +} + +/** + */ +function InputRadio(props: IInputRadioProps) { + const { options, value, stretch, onChange } = props; + + /** + * Renders a single item. + */ + const renderItem = (item: any) => { + const selected = value === item.value; + return ( + onChange(item.value)} + stretch={stretch} + key={item.value} + className="item" + selected={selected} + > + {item.label} + + ); + }; + + return {options.map(renderItem)}; +} + +export default InputRadio; diff --git a/packages/tcore-console/src/Components/Link/Link.style.ts b/packages/tcore-console/src/Components/Link/Link.style.ts new file mode 100644 index 00000000..9fedf189 --- /dev/null +++ b/packages/tcore-console/src/Components/Link/Link.style.ts @@ -0,0 +1,22 @@ +import styled from "styled-components"; +import { Link } from "react-router-dom"; + +/** + */ +export const Local = styled(Link)` + color: ${(props) => props.theme.link}; + + &:hover { + text-decoration: underline; + } +`; + +/** + */ +export const External = styled.a` + color: ${(props) => props.theme.link}; + + &:hover { + text-decoration: underline; + } +`; diff --git a/packages/tcore-console/src/Components/Link/Link.test.tsx b/packages/tcore-console/src/Components/Link/Link.test.tsx new file mode 100644 index 00000000..8b88d823 --- /dev/null +++ b/packages/tcore-console/src/Components/Link/Link.test.tsx @@ -0,0 +1,20 @@ +import { render, screen } from "../../../utils/test-utils"; +import Link from "./Link"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("respects `href` prop", async () => { + render(); + const link = screen.getByRole("link"); + expect(link).not.toBeDisabled(); + expect(link).toHaveProperty("href", "http://localhost/console/test"); +}); + +test("respects `target` prop", async () => { + render(); + const link = screen.getByRole("link"); + expect(link).toHaveProperty("target", "_blank"); +}); diff --git a/packages/tcore-console/src/Components/Link/Link.tsx b/packages/tcore-console/src/Components/Link/Link.tsx new file mode 100644 index 00000000..249f29bb --- /dev/null +++ b/packages/tcore-console/src/Components/Link/Link.tsx @@ -0,0 +1,39 @@ +import { memo, ReactNode } from "react"; +import * as Style from "./Link.style"; + +/** + * Props. + */ +interface ILinkProps { + /** + * Link to be passed to the inner DOM node. + */ + href: string; + /** + * Target to be passed to the inner DOM node. + */ + target?: string; + /** + * Text or content to be rendered inside of the link. + */ + children?: ReactNode; +} + +/** + * A simple HTML `` tag, with style. + */ +function Link(props: ILinkProps) { + const { href, target } = props; + + return href.startsWith("/") ? ( + + {props.children} + + ) : ( + + {props.children} + + ); +} + +export default memo(Link); diff --git a/packages/tcore-console/src/Components/ListPage/ListPage.style.ts b/packages/tcore-console/src/Components/ListPage/ListPage.style.ts new file mode 100644 index 00000000..c0f16e48 --- /dev/null +++ b/packages/tcore-console/src/Components/ListPage/ListPage.style.ts @@ -0,0 +1,17 @@ +import styled from "styled-components"; + +/** + * Main style. + */ +export const Container = styled.div` + display: flex; + flex-direction: column; + flex: 1; + width: 100%; + + > div { + flex: 1; + border: 0; + border-radius: 0; + } +`; diff --git a/packages/tcore-console/src/Components/ListPage/ListPage.tsx b/packages/tcore-console/src/Components/ListPage/ListPage.tsx new file mode 100644 index 00000000..0c95b5ae --- /dev/null +++ b/packages/tcore-console/src/Components/ListPage/ListPage.tsx @@ -0,0 +1,165 @@ +import { useState, useCallback, useEffect, ReactNode, useRef } from "react"; +import { ITag, ISummary } from "@tago-io/tcore-sdk/types"; +import { EIcon } from "../Icon/Icon.types"; +import InnerNav from "../InnerNav/InnerNav"; +import PaginatedTable from "../PaginatedTable/PaginatedTable"; +import { IColumn } from "../PaginatedTable/PaginatedTable.types"; +import setDocumentTitle from "../../Helpers/setDocumentTitle"; +import useApiRequest from "../../Helpers/useApiRequest"; +import * as Style from "./ListPage.style"; + +/** + * Props. + */ +interface IListPageProps { + /** + * Custom component to be inserted at the right side of the navigation bar. + */ + children?: ReactNode; + /** + * Color of the rows and the inner navigation bar. + */ + color: string; + /** + * Description of the inner navigation bar. + */ + description: ReactNode; + /** + * Icon of the inner navigation bar. + */ + icon: EIcon; + /** + * URL to redirect the user when they click on a row. + */ + path: string; + /** + * Title of the document/page. + */ + documentTitle?: string; + /** + * Title of the inner navigation bar. + */ + innerNavTitle: string; + /** + * Columns of the table. + */ + columns: IColumn[]; + /** + * Summary key to get the amount of records. + */ + summaryKey: keyof ISummary; + /** + * Called to fetch the data for the page. + */ + onGetData: (page: number, idealAmountOfRows: number, filter: any) => Promise | T[]; +} + +/** + * List page for a certain type of resource. + */ +function ListPage(props: IListPageProps) { + const [page, setPage] = useState(0); + const tagValues = useRef([]); + const { onGetData, summaryKey, documentTitle, path, color, columns } = props; + const { data: summary } = useApiRequest("/summary"); + const { data: tags } = useApiRequest(`/tags/keys/${summaryKey}`); + + /** + * Returns the link for a record. + */ + const getRowLink = useCallback( + (item: T) => { + return `/console/${path}/${item.id}`; + }, + [path] + ); + + /** + * Fetches the data and returns it. + */ + const getData = useCallback( + async (pg: number, idealAmountOfRows: number, filter: any) => { + const filterWithTags = { ...filter }; + if (tagValues.current.length > 0) { + filterWithTags.tags = tagValues.current; + } + return onGetData(pg, idealAmountOfRows, filterWithTags); + }, + [onGetData] + ); + + /** + * Renders the tag value. + */ + const renderTag = (item: any, rowIndex: number, column: IColumn) => { + const tag = item?.tags?.find((x: ITag) => x?.key === column?.id); + return tag?.value || ""; + }; + + /** + * Renders the tag value. + */ + const onTagFilterChange = (value: string, column: IColumn) => { + const item = tagValues.current.find((x) => x.key === column?.id); + if (item && value) { + item.value = `*${value}*`; + } else if (!item && value) { + tagValues.current.push({ key: column.id, value: `*${value}*` }); + } else if (item && !value) { + tagValues.current = tagValues.current.filter((x) => x !== item); + } + }; + + /** + * Combines the tags of the resource and the default columns. + */ + const getColumns = () => { + const cols: IColumn[] = [...columns]; + for (const tag of tags || []) { + cols.push({ + icon: EIcon.tag, + id: tag, + label: tag, + onFilter: onTagFilterChange, + onRender: renderTag, + }); + } + return cols; + }; + + /** + * Sets the document title. + */ + useEffect(() => { + if (documentTitle) { + setDocumentTitle(documentTitle); + } + }, [documentTitle]); + + return ( + + + {props.children} + + + + amountOfRecords={summary?.[summaryKey] || 0} + columns={getColumns()} + emptyMessage={"Nothing here yet."} + emptyMessageIcon={props.icon} + highlightColor={color} + onChangePage={setPage} + onGetData={getData} + onGetRowLink={getRowLink} + page={page} + /> + + ); +} + +export default ListPage; diff --git a/packages/tcore-console/src/Components/Loading/Loading.style.ts b/packages/tcore-console/src/Components/Loading/Loading.style.ts new file mode 100644 index 00000000..277bd91e --- /dev/null +++ b/packages/tcore-console/src/Components/Loading/Loading.style.ts @@ -0,0 +1,33 @@ +import styled, { keyframes } from "styled-components"; + +/** + * The inner ball's animation. + */ +const spinnerAnimation = keyframes` + 0% { + transform: scale(0); + } + + 100% { + transform: scale(1.0); + opacity: 0; + } +`; + +/** + * Main style. + */ +export const Container = styled.div` + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + + .spinner { + width: 40px; + height: 40px; + background-color: ${(props) => props.theme.font2}; + border-radius: 100%; + animation: ${spinnerAnimation} 1s infinite ease-in-out; + } +`; diff --git a/packages/tcore-console/src/Components/Loading/Loading.test.tsx b/packages/tcore-console/src/Components/Loading/Loading.test.tsx new file mode 100644 index 00000000..0b27576b --- /dev/null +++ b/packages/tcore-console/src/Components/Loading/Loading.test.tsx @@ -0,0 +1,7 @@ +import { render } from "../../../utils/test-utils"; +import Loading from "./Loading"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); diff --git a/packages/tcore-console/src/Components/Loading/Loading.tsx b/packages/tcore-console/src/Components/Loading/Loading.tsx new file mode 100644 index 00000000..59dcd829 --- /dev/null +++ b/packages/tcore-console/src/Components/Loading/Loading.tsx @@ -0,0 +1,16 @@ +import { memo } from "react"; +import * as Style from "./Loading.style"; + +/** + * This component shows a tiny ball that expands and fades out. It indicates + * that some processing is going on and the user needs to wait. + */ +function Loading() { + return ( + +
+ + ); +} + +export default memo(Loading); diff --git a/packages/tcore-console/src/Components/Logs/Logs.style.ts b/packages/tcore-console/src/Components/Logs/Logs.style.ts new file mode 100644 index 00000000..1322e31d --- /dev/null +++ b/packages/tcore-console/src/Components/Logs/Logs.style.ts @@ -0,0 +1,67 @@ +import styled from "styled-components"; +import * as FormGroupStyle from "../FormGroup/FormGroup.style"; +import * as SelectStyle from "../Select/Select.style"; + +/** + */ +export const Container = styled.div` + display: flex; + flex-direction: column; + width: 100%; + flex: 1; + background: ${(props) => props.theme.background1}; +`; + +/** + */ +export const Header = styled.div` + width: 100%; + background: ${(props) => props.theme.tableHeader}; + padding: 10px; + display: flex; + align-items: center; + box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.15); + + ${FormGroupStyle.Container} { + display: flex; + align-items: center; + + &:first-child { + margin-right: 15px; + padding-right: 15px; + border-right: 1px solid rgba(0, 0, 0, 0.1); + } + + label { + margin: 0; + margin-right: 10px; + } + } + + ${SelectStyle.Container} { + &.channel { + flex: none; + width: 250px; + } + + &.type { + flex: none; + width: 250px; + } + } +`; + +/** + * Contains the empty message. + */ +export const EmptyMessageContainer = styled.div` + position: relative; + flex: 1; + padding: 10px; + overflow: auto; + + .row { + display: block; + margin-bottom: 3px; + } +`; diff --git a/packages/tcore-console/src/Components/Logs/Logs.tsx b/packages/tcore-console/src/Components/Logs/Logs.tsx new file mode 100644 index 00000000..325587f5 --- /dev/null +++ b/packages/tcore-console/src/Components/Logs/Logs.tsx @@ -0,0 +1,181 @@ +import { ESocketResource, ILog, IPluginLogChannel } from "@tago-io/tcore-sdk/types"; +import { useEffect, useState } from "react"; +import { useTheme } from "styled-components"; +import qs from "qs"; +import setDocumentTitle from "../../Helpers/setDocumentTitle"; +import useApiRequest from "../../Helpers/useApiRequest"; +import Console from "../Console/Console"; +import EmptyMessage from "../EmptyMessage/EmptyMessage"; +import FormGroup from "../FormGroup/FormGroup"; +import { EIcon } from "../Icon/Icon.types"; +import InnerNav from "../InnerNav/InnerNav"; +import Select, { ISelectOption } from "../Select/Select"; +import Loading from "../Loading/Loading"; +import { socket } from "../../System/Socket"; +import * as Style from "./Logs.style"; + +/** + * This page shows the logs of all channels in the application. + */ +function Logs() { + const [selectedChannel, setSelectedChannel] = useState(() => { + const query = qs.parse(window.location.search, { ignoreQueryPrefix: true }); + return String(query.channel || "") || "api"; + }); + + const [selectedType, setSelectedType] = useState(() => { + const query = qs.parse(window.location.search, { ignoreQueryPrefix: true }); + return String(query.type || "") || "all"; + }); + + const { data: channels } = useApiRequest("/logs"); + const { data } = useApiRequest(`/logs/${encodeURIComponent(selectedChannel)}`); + const [logs, setLogs] = useState([]); + const theme = useTheme(); + + const loading = !channels || !data; + + /** + * Returns a list of channel options. + */ + const getChannelOptions = (): ISelectOption[] => { + return (channels || []).map((x) => ({ + label: x.name, + value: x.channel, + })); + }; + + /** + * Renders the header part of the page. The header contains filters. + */ + const renderHeader = () => { + return ( + + + setSelectedType(e.target.value)} + options={[ + { label: "All", value: "all" }, + { label: "Verbose", value: "verbose" }, + { label: "Errors", value: "error" }, + ]} + /> + + + ); + }; + + /** + */ + const filterLogs = () => { + return (logs || []).filter((x) => { + if (selectedType === "all") { + return x; + } else if (selectedType === "verbose") { + return (x as any).type === "log"; + } else { + return (x as any).type === "error"; + } + }); + }; + + /** + * Renders the logs content in the middle of the page. + */ + const renderContent = () => { + const logsFiltered = filterLogs(); + + if (!loading && logsFiltered.length === 0) { + return ( + + + + ); + } + + if (loading) { + return ; + } + + return ; + }; + + /** + */ + useEffect(() => { + if (data) { + setLogs(data); + } + }, [data]); + + /** + * Sets the document title. + */ + useEffect(() => { + setDocumentTitle("Application Logs"); + }, []); + + /** + * Makes the request to install the plugin. + */ + useEffect(() => { + function onLog(params: any) { + setLogs((x) => [...x, params]); + } + + socket.on(`log::${selectedChannel}`, onLog); + return () => { + socket.off(`log::${selectedChannel}`, onLog); + }; + }); + + /** + * Attaches and detaches the plugin to get the logs in realtime. + */ + useEffect(() => { + socket.emit("attach", ESocketResource.log); + return () => { + socket.emit("detach", ESocketResource.log); + }; + }, []); + + /** + * Sets the query string parameters. + */ + useEffect(() => { + history.replaceState(null, "", `/console/logs?channel=${selectedChannel}&type=${selectedType}`); + }, [selectedChannel, selectedType]); + + return ( + + + {renderHeader()} + {renderContent()} + + ); +} + +export default Logs; diff --git a/packages/tcore-console/src/Components/MainScreen/MainScreen.style.ts b/packages/tcore-console/src/Components/MainScreen/MainScreen.style.ts new file mode 100644 index 00000000..55048490 --- /dev/null +++ b/packages/tcore-console/src/Components/MainScreen/MainScreen.style.ts @@ -0,0 +1,20 @@ +import styled from "styled-components"; + +export const Container = styled.div` + display: flex; + flex-direction: column; + flex: 1; + height: 100%; + width: 100%; +`; + +export const Content = styled.div<{ sidebarOpen?: boolean }>` + display: flex; + flex: 1; + margin-left: ${(props) => (props.sidebarOpen ? "270px" : "0px")}; + position: relative; + transition: margin-left 0.5s; + transition-timing-function: cubic-bezier(0.55, 0, 0.1, 1); + overflow: auto; + background: ${(props) => props.theme.background2}; +`; diff --git a/packages/tcore-console/src/Components/MainScreen/MainScreen.tsx b/packages/tcore-console/src/Components/MainScreen/MainScreen.tsx new file mode 100644 index 00000000..838ece05 --- /dev/null +++ b/packages/tcore-console/src/Components/MainScreen/MainScreen.tsx @@ -0,0 +1,37 @@ +import { ReactNode, useCallback, useState } from "react"; +import Navbar from "../Navbar/Navbar"; +import Sidebar from "../Sidebar/Sidebar"; +import * as Style from "./MainScreen.style"; + +/** + * Props. + */ +interface IMainScreenProps { + children?: ReactNode; +} + +/** + * Main screen for the whole application. + * This component shows a sidebar and the navbar, as well as an empty space in + * the middle that will render the children of this component. + */ +function MainScreen(props: IMainScreenProps) { + const [sidebarOpen, setSidebarOpen] = useState(true); + + /** + * Toggles the sidebar visibility. + */ + const onSidebarToggle = useCallback(() => { + setSidebarOpen(!sidebarOpen); + }, [sidebarOpen]); + + return ( + + + + {props.children} + + ); +} + +export default MainScreen; diff --git a/packages/tcore-console/src/Components/Markdown/Markdown.style.ts b/packages/tcore-console/src/Components/Markdown/Markdown.style.ts new file mode 100644 index 00000000..cfa40ad0 --- /dev/null +++ b/packages/tcore-console/src/Components/Markdown/Markdown.style.ts @@ -0,0 +1,64 @@ +import styled, { css } from "styled-components"; +import { fonts } from "../../theme"; + +/** + * Main container. + */ +export const Container = styled.div` + word-wrap: break-word; + + img { + max-width: 100%; + } + + code { + display: inline-block; + font-family: Monospace; + font-size: ${() => fonts.default}; + padding: 1px 7px; + background: rgba(0, 0, 0, 0.1); + border-radius: 5px; + } + + h1 { + font-size: ${() => fonts.xlarge}; + margin-top: 2.5rem; + } + + h2 { + font-size: ${() => fonts.large}; + margin-top: 2rem; + } + + h3 { + font-size: ${() => fonts.medium}; + margin-top: 1.5rem; + } + + p { + margin-top: 5px; + } + + hr { + margin: 2.5rem 0px; + height: 1px; + opacity: 0.35; + } + + /* ul { + margin: 5px 0px; + } */ +`; + +/** + */ +export const Img = styled.img` + ${(props) => + props.src?.includes("logo-plugin-black") && + css` + height: 40px; + margin: 0 auto; + display: flex; + margin-top: 1rem; + `}} +`; diff --git a/packages/tcore-console/src/Components/Markdown/Markdown.tsx b/packages/tcore-console/src/Components/Markdown/Markdown.tsx new file mode 100644 index 00000000..be0e4758 --- /dev/null +++ b/packages/tcore-console/src/Components/Markdown/Markdown.tsx @@ -0,0 +1,54 @@ +import { ImgHTMLAttributes, lazy, memo, Suspense } from "react"; +import * as Style from "./Markdown.style"; + +/** + * Props. + */ +interface IMarkdownProps { + /** + * Markdown content. + */ + value: string; + /** + * Path to prepend to local img paths. + */ + localImgPrefix?: string; +} + +/** + * Renders a markdown content. + */ +function Markdown(props: IMarkdownProps) { + const { value, localImgPrefix } = props; + const ReactMarkdown = lazy(() => import("react-markdown")); + + /** + */ + const prependIfLocal = (src?: string) => { + if (src?.startsWith("http")) { + return src; + } + if (src?.startsWith("/")) { + src = src.substring(1); + } + src = `${localImgPrefix}/${src}`; + return src; + }; + + /** + */ + const renderImg = (imgProps: ImgHTMLAttributes) => { + const src = localImgPrefix ? prependIfLocal(imgProps?.src) : imgProps?.src; + return ; + }; + + return ( + + }> + {value} + + + ); +} + +export default memo(Markdown); diff --git a/packages/tcore-console/src/Components/Modal/Modal.style.ts b/packages/tcore-console/src/Components/Modal/Modal.style.ts new file mode 100644 index 00000000..572a2c26 --- /dev/null +++ b/packages/tcore-console/src/Components/Modal/Modal.style.ts @@ -0,0 +1,91 @@ +import styled, { css, keyframes } from "styled-components"; +import { fonts } from "../../theme"; + +const fadeIn = keyframes` + from { opacity: 0 }; + to { opacity: 1 }; +`; + +/** + */ +export const Container = styled.div` + position: fixed; + left: 0px; + top: 0px; + right: 0px; + bottom: 0px; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 100; + animation: ${fadeIn} 0.2s; +`; + +/** + */ +export const Icon = styled.div<{ backgroundColor?: string }>` + align-items: center; + background: hsl(0, 100%, 100%); + border-radius: 15px; + border: 4px solid ${(props) => props.backgroundColor}; + box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.1); + display: inline-flex; + height: 47px; + justify-content: center; + width: 70px; + margin-right: 10px; +`; + +/** + */ +export const Header = styled.header<{ backgroundColor?: string }>` + padding: 10px 15px; + border-bottom: 1px solid ${(props) => props.theme.fieldsetBorder}; + flex: none; + display: flex; + justify-content: space-between; + align-items: center; + + > div { + display: flex; + align-items: center; + } + + h1 { + font-size: ${() => fonts.large}; + font-weight: bold; + } + + ${(props) => + props.backgroundColor && + css` + background-color: ${props.backgroundColor}; + + h1 { + color: white; + } + `} +`; + +/** + */ +export const Card = styled.div<{ height?: string; width?: string }>` + position: relative; + background: ${(props) => props.theme.background1}; + border-radius: 5px; + overflow: hidden; + box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.3); + max-height: 90%; + display: flex; + flex-direction: column; + width: 100%; + max-width: ${(props) => props.width || "400px"}; + height: ${(props) => props.height || null}; + + > .content { + padding: 15px; + flex: 1; + overflow: auto; + } +`; diff --git a/packages/tcore-console/src/Components/Modal/Modal.tsx b/packages/tcore-console/src/Components/Modal/Modal.tsx new file mode 100644 index 00000000..be754497 --- /dev/null +++ b/packages/tcore-console/src/Components/Modal/Modal.tsx @@ -0,0 +1,228 @@ +import { MouseEvent, useCallback, useEffect, useState } from "react"; +import { createPortal } from "react-dom"; +import { ReactNode } from "react-markdown/lib/react-markdown"; +import Button from "../Button/Button"; +import { EButton } from "../Button/Button.types"; +import Footer from "../Footer/Footer"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import * as Style from "./Modal.style"; + +/** + * Props. + */ +interface IModalProps { + /** + * Called when the modal is closed by the user. + */ + onClose: () => void; + /** + */ + onCancel?: () => Promise | void; + /** + */ + onConfirm?: (e: MouseEvent) => Promise | void; + /** + * Content of the modal. + */ + children?: ReactNode; + /** + * Main title of the modal, appears in the header. + */ + title?: string; + /** + */ + confirmButtonType?: EButton; + /** + */ + confirmButtonText?: ReactNode; + /** + */ + isConfirmButtonDisabled?: boolean; + /** + */ + width?: string; + /** + */ + height?: string; + /** + */ + cancelButtonText?: ReactNode; + /** + */ + color?: string; + /** + */ + icon?: EIcon; + /** + */ + showCloseButton?: boolean; + /** + */ + showCancelButton?: boolean; + /** + */ + showConfirmButton?: boolean; + /** + */ + showHeader?: boolean; + /** + */ + isCancelButtonDisabled?: boolean; +} + +/** + */ +function Modal(props: IModalProps) { + const [buttonsDisabled, setButtonsDisabled] = useState(false); + const [shouldClose, setShouldClose] = useState(false); + const { + cancelButtonText, + color, + confirmButtonText, + confirmButtonType, + height, + icon, + isConfirmButtonDisabled, + isCancelButtonDisabled, + onCancel, + onClose, + onConfirm, + showCancelButton, + showCloseButton, + showConfirmButton, + showHeader, + title, + width, + } = props; + + /** + */ + const confirm = useCallback( + async (e: MouseEvent) => { + setButtonsDisabled(true); + try { + await onConfirm?.(e); + if (!e.defaultPrevented) { + setShouldClose(true); + } + } finally { + setButtonsDisabled(false); + } + }, + [onConfirm] + ); + + /** + */ + const cancel = useCallback(async () => { + if (!onCancel) { + onClose(); + return; + } + + setButtonsDisabled(true); + try { + await onCancel(); + setShouldClose(true); + } finally { + setButtonsDisabled(false); + } + }, [onCancel, onClose]); + + /** + * Renders the header. + */ + const renderHeader = () => { + if (showHeader === false) { + return null; + } + + return ( + +
+ {icon && ( + + + + )} + +

{title}

+
+ + {showCloseButton !== false && ( + + )} +
+ ); + }; + + /** + * Renders the content. + */ + const renderContent = () => { + return
{props.children}
; + }; + + /** + * Renders the footer. + */ + const renderFooter = () => { + const shouldRender = showCancelButton !== false || showConfirmButton !== false; + if (!shouldRender) { + return null; + } + + return ( +
+
+ {showCancelButton !== false && ( + + )} +
+ +
+ {showConfirmButton !== false && ( + + )} +
+
+ ); + }; + + useEffect(() => { + if (shouldClose) { + onClose(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [shouldClose]); + + return createPortal( + + + {renderHeader()} + {renderContent()} + {renderFooter()} + + , + document.body + ); +} + +export default Modal; diff --git a/packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.style.ts b/packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.style.ts new file mode 100644 index 00000000..3b1d4ac1 --- /dev/null +++ b/packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.style.ts @@ -0,0 +1,92 @@ +import styled, { css } from "styled-components"; + +/** + */ +export const Container = styled.div` + display: flex; + flex: 1; + flex-direction: column; + height: 100%; +`; + +/** + * Style for the input container. + */ +export const InputContainer = styled.div``; + +/** + */ +export const Files = styled.div` + flex: 1; + overflow: auto; + border: 1px solid ${(props) => props.theme.fieldsetBorder}; + border-radius: 5px; + position: relative; + + .empty-warning { + font-style: italic; + color: rgba(0, 0, 0, 0.5); + margin-left: 30px; + padding: 5px 0px; + } +`; + +/** + */ +export const SingleFile = styled.div<{ + selected: boolean; + disabled: boolean; + indentation: number; +}>` + padding: 5px 10px; + cursor: pointer; + display: flex; + align-items: center; + padding-left: ${(props) => props.indentation * 10 + 10}px; + + > span { + margin-left: 7px; + } + + ${(props) => + props.selected && + !props.disabled && + css` + background: ${props.theme.buttonPrimary} !important; + + * { + color: white !important; + fill: white !important; + } + + &:active { + background: hsl(207, 85%, 10%) !important; + } + `} + + ${(props) => + props.disabled && + css` + opacity: 0.5; + cursor: not-allowed; + `} + + ${(props) => + !props.disabled && + css` + &:hover { + background: rgba(0, 0, 0, 0.1); + } + + &:active { + background: rgba(0, 0, 0, 0.2); + } + `} +`; + +/** + */ +export const Message = styled.div` + margin-bottom: 1rem; + color: ${(props) => props.theme.font2}; +`; diff --git a/packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.tsx b/packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.tsx new file mode 100644 index 00000000..08132a83 --- /dev/null +++ b/packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.tsx @@ -0,0 +1,304 @@ +import React, { memo, ReactNode, useCallback, useEffect, useRef, useState } from "react"; +import { useTheme } from "styled-components"; +import useApiRequest from "../../Helpers/useApiRequest"; +import FormGroup from "../FormGroup/FormGroup"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import Input from "../Input/Input"; +import Loading from "../Loading/Loading"; +import Modal from "../Modal/Modal"; +import { EmptyMessage } from "../.."; +import { IFile } from "./ModalFileSelect.types"; +import * as Style from "./ModalFileSelect.style"; + +/** + * Props. + */ +interface IModalFileSelect { + /** + * File extension to be accepted. + * For example, if you only want `javascript` files to be selected, then this prop would have to be = ".js". + */ + accept: string; + /** + * Called when the modal is closed. + */ + onClose: () => void; + /** + * Called when a file is selected. + */ + onConfirm: (filePath: string) => void; + /** + * Optional message to be rendered at the top of the component. + */ + message?: ReactNode; + /** + * Default file path to be used in the input. + */ + defaultFilePath?: string; + /** + * If only folders can be selected. + */ + onlyFolders?: boolean; + /** + * The title of the modal. This parameter is optional. + */ + title?: string; + /** + * Optional placeholder for the input. + */ + placeholder?: string; + /** + * Use local filesystem for the list. + */ + useLocalFs?: boolean; +} + +/** + * This modal shows the computer file tree. + * The file tree shown here is from the server, not from the client executing this code. + */ +function ModalFileSelect(props: IModalFileSelect) { + const [value, setValue] = useState(props.defaultFilePath || ""); + const [path, setPath] = useState(() => props.defaultFilePath || ""); + const [loading, setLoading] = useState(true); + const [files, setFiles] = useState([]); + const [selected, setSelected] = useState(""); + const [isSelectedFolder, setIsSelectedFolder] = useState(false); + const { data } = useApiRequest( + `/file?local_fs=${props.useLocalFs ? "true" : ""}&path=${path}` + ); + const theme = useTheme(); + const focused = useRef(false); + const refFilesContainer = useRef(null); + + const { accept, title, placeholder, onClose, onConfirm } = props; + + // used to enable/disable the confirm button: + let confirmDisabled = (accept && !selected.endsWith(accept)) as boolean; + if (props.onlyFolders) { + confirmDisabled = !isSelectedFolder; + } + + /** + * Called when the main modal button is pressed. + * This is used to send the selected file path to the other side. + */ + const confirm = useCallback(() => { + onConfirm(value); + }, [onConfirm, value]); + + /** + * Renders the message at the top of the component. This is a great way + * to show some additional information for the user. + */ + const renderMessage = () => { + if (!props.message) { + return null; + } + return {props.message}; + }; + + /** + * Called when a file is clicked. + * This will toggle the selection for the file: if it's already selected it will be unselected + * and if it's unselected it will be selected. + */ + const onClickFile = (file: IFile) => { + if (file.is_folder) { + setPath(file.path); + setSelected(file.path); + setValue(file.path); + setIsSelectedFolder(file.is_folder); + if (path !== file.path) { + setLoading(true); + } + } else { + setSelected(file.path); + setValue(file.path); + setIsSelectedFolder(file.is_folder); + } + }; + + /** + * Renders the input part. + */ + const renderInput = () => { + return ( + + + (focused.current = false)} + onChange={(e) => setValue(e.target.value)} + onFocus={() => (focused.current = true)} + placeholder={placeholder || "enter a path or select one in the list"} + value={value} + /> + + + ); + }; + + /** + * Renders the empty warning for a folder. + * This indicates that the folder has no contents inside of it. + */ + const renderEmptyWarning = () => { + return
Nothing in this folder.
; + }; + + /** + * Renders a single file/folder. + * The indentation indicates how much padding-left the component should have. + */ + const renderSingleFile = (file: IFile, indentation: number) => { + const isSelected = selected === file.path; + + let icon = EIcon.spinner; + if (loading && isSelected) { + icon = EIcon.spinner; + } else if (file.is_folder) { + icon = EIcon.folder; + } else { + icon = EIcon["file-alt"]; + } + + const iconColor = file.is_folder ? theme.files : ""; + + const matchesExtension = !accept || file.name.endsWith(accept); + + let enabled = file.is_folder || matchesExtension; + if (props.onlyFolders && !file.is_folder) { + enabled = false; + } + + const showEmptyWarning = file.children.length === 0 && file.is_folder && isSelected && !loading; + + return ( + + enabled && onClickFile(file)} + selected={isSelected} + ref={(e) => ((file as any).ref = e)} + > + + {file.name} + + + {showEmptyWarning + ? renderEmptyWarning() + : file.children.map((f) => renderSingleFile(f, indentation + 1))} + + ); + }; + + /** + */ + const renderFiles = () => { + return ( + + {loading && files.length === 0 ? ( + + ) : !loading && files.length === 0 ? ( + + ) : ( + files.map((file) => renderSingleFile(file, 0)) + )} + + ); + }; + + /** + * Used to transfer the data from the API request to the state. + * We have to transfer to the local state in order to avoid `null` values + * in-between requests. + */ + useEffect(() => { + if (data) { + setFiles([...data]); + setLoading(false); + } + }, [data]); + + /** + * Effect responsible for verifying if the string typed in the input really exists or not. + * If the path does not exist, the selected path will be set to an empty string. + * if the path does exist, the selected path will be set to the current input value. + * This should be called every time the input changes its value and it's not focused. + */ + useEffect(() => { + if (files.length <= 0) { + return; + } + + let increments = 0; + let max: IFile | undefined; + + for (const i of files) { + let item: IFile = i; + let newItem: IFile | undefined = undefined; + let localIncrements = 0; + + // eslint-disable-next-line no-constant-condition + while (true) { + localIncrements++; + newItem = (item.children || []).find((x) => x?.children.length > 0); + if (!newItem) { + break; + } + item = newItem; + } + + if (localIncrements > increments) { + max = item; + increments = localIncrements; + } + } + + if (refFilesContainer.current && max && increments > 1) { + const split = String(value).split("/"); + const last = split[split.length - 1]; + const item = max.children.find((x) => x.name === last); + if (item) { + setSelected(item.path); + refFilesContainer.current.scrollTop = (item as any)?.ref.offsetTop; + } else { + setSelected(max.path); + refFilesContainer.current.scrollTop = (max as any)?.ref.offsetTop; + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [files.length]); + + /** + */ + useEffect(() => { + if (files.length > 0) { + setPath(value); + } + }, [files.length, value]); + + return ( + + + {renderMessage()} + {renderInput()} + {renderFiles()} + + + ); +} + +export default memo(ModalFileSelect); diff --git a/packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.types.ts b/packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.types.ts new file mode 100644 index 00000000..6f628326 --- /dev/null +++ b/packages/tcore-console/src/Components/ModalFileSelect/ModalFileSelect.types.ts @@ -0,0 +1,22 @@ +/** + * Represents a file or a folder. + */ +export interface IFile { + /** + * Local name, excluding the full path. + */ + name: string; + /** + * Full path of the file, including the name. + */ + path: string; + /** + * Indicates if this file is a folder or not. + */ + is_folder: boolean; + /** + * If the file is a folder this will contain the files inside of the folder. + * If the file is not a folder this will always be empty. + */ + children: IFile[]; +} diff --git a/packages/tcore-console/src/Components/ModalListConfiguration/ModalListConfiguration.style.ts b/packages/tcore-console/src/Components/ModalListConfiguration/ModalListConfiguration.style.ts new file mode 100644 index 00000000..e8dd8e93 --- /dev/null +++ b/packages/tcore-console/src/Components/ModalListConfiguration/ModalListConfiguration.style.ts @@ -0,0 +1,29 @@ +import styled from "styled-components"; + +/** + */ +export const Container = styled.div` + flex: 1; + height: 100%; + display: flex; + + h2 { + font-size: 1.1rem; + font-weight: bold; + margin-bottom: 10px; + } + + > section { + flex: 1; + } + + > section:first-child { + border-right: 1px solid rgba(0, 0, 0, 0.1); + padding-right: 15px; + margin-right: 15px; + } + + .item:not(:last-child) { + margin-bottom: 5px; + } +`; diff --git a/packages/tcore-console/src/Components/ModalListConfiguration/ModalListConfiguration.tsx b/packages/tcore-console/src/Components/ModalListConfiguration/ModalListConfiguration.tsx new file mode 100644 index 00000000..914a400a --- /dev/null +++ b/packages/tcore-console/src/Components/ModalListConfiguration/ModalListConfiguration.tsx @@ -0,0 +1,96 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import { useEffect, useState } from "react"; +import { Switch } from "../.."; +import { getLocalStorageAsJSON, setLocalStorageAsJSON } from "../../Helpers/localStorage"; +import Modal from "../Modal/Modal"; +import Select from "../Select/Select"; +import * as Style from "./ModalListConfiguration.style"; + +/** + * Props. + */ +interface IModalListConfigurationProps { + visible?: boolean; + /** + */ + deviceID: TGenericID; + /** + */ + onClose: (data: any) => void; +} + +/** + */ +function ModalListConfiguration(props: IModalListConfigurationProps) { + const { deviceID, onClose } = props; + + const [dateFormat, setDateFormat] = useState(() => { + const data = getLocalStorageAsJSON(`${deviceID}::data::settings`); + return data?.dateFormat || ""; + }); + const [enabledColumns, setEnabledColumns] = useState(() => { + const data = getLocalStorageAsJSON(`${deviceID}::data::settings`); + return data?.enabledColumns || {}; + }); + + /** + */ + const renderItem = (id: string, text: string) => { + const enabled = enabledColumns[id] ?? true; + return ( +
+ setEnabledColumns({ ...enabledColumns, [id]: e })}> + {text} + +
+ ); + }; + + /** + */ + useEffect(() => { + setLocalStorageAsJSON(`${deviceID}::data::settings`, { + dateFormat, + enabledColumns, + }); + }); + + return ( + onClose({ dateFormat, enabledColumns })} + showCancelButton={false} + showConfirmButton={false} + title="List Configuration" + width="550px" + > + +
+

Hide/Show Columns

+ {renderItem("id", "ID")} + {renderItem("variable", "Variable")} + {renderItem("value", "Value")} + {renderItem("location", "Location")} + {renderItem("group", "Group")} + {renderItem("metadata", "Metadata")} + {renderItem("time", "Time")} +
+ +
+

Time Format

+ onChangeItem(index, "key", e.target.value)} + value={item?.key} + style={{ marginRight: "5px" }} + error={errors?.[index]?.key} + options={[{ label: "Select an option", value: "", disabled: true }, ...props.optionsKey]} + /> + + + {focused && ( + + {loading ? renderLoading() : options.map(renderOption)} + + )} + + {renderInputIcon()} + + + {error && errorMessage && {errorMessage}} + + ); +} + +export default memo(OptionsPicker) as typeof OptionsPicker; diff --git a/packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.style.ts b/packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.style.ts new file mode 100644 index 00000000..5643bf48 --- /dev/null +++ b/packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.style.ts @@ -0,0 +1,150 @@ +import { Link } from "react-router-dom"; +import styled, { css } from "styled-components"; + +export const Container = styled.div` + display: flex; + flex-direction: column; + border: 1px solid ${(props) => props.theme.fieldsetBorder}; + border-radius: 5px; + overflow: hidden; + background: ${(props) => props.theme.background1}; + + .content { + display: flex; + flex: 1; + min-height: 0; + overflow: auto; + + > div { + width: 100%; + } + } + + .cell { + padding: 0px 4px; + white-space: nowrap; + text-overflow: ellipsis; + position: relative; + } +`; + +/** + * CSS shared between all types of rows. + */ +const rowCSS = css<{ $highlightColor?: string }>` + padding: 10px 10px; + display: flex; + align-items: center; + min-width: 0; + + &:hover { + .table-hover-edit { + display: initial !important; + } + } + + .cell { + flex: 1 1 0%; + display: flex; + align-items: center; + } + + &:nth-of-type(even) { + background-color: ${(props) => props.theme.tableOddRow}; + } + + ${(props) => + props.$highlightColor && + css` + &:hover { + cursor: pointer; + background: ${props.$highlightColor}; + * { + color: white !important; + fill: white !important; + } + } + `} +`; + +/** + * Style for a link row (clickable). + */ +export const LinkRow = styled(Link)<{ $highlightColor?: string }>` + ${rowCSS} +`; + +/** + * Style for a div row (not clickable). + */ +export const DivRow = styled.div<{ $highlightColor?: string }>` + ${rowCSS} +`; + +/** + * Style for the filter container. + */ +export const FilterContainer = styled.div<{ disabled: boolean }>` + ${(props) => + props.disabled && + css` + pointer-events: none; + opacity: 0.5; + `} +`; + +/** + * Rows container style. + */ +export const Body = styled.div` + flex: 1; + + .cell { + /* overflow: hidden; */ + white-space: nowrap; + text-overflow: ellipsis; + display: flex; + min-width: 0; + } +`; + +/** + * Header style. + */ +export const Header = styled.div` + display: flex; + background: rgba(0, 0, 0, 0.05); + padding: 7px 10px; + align-items: center; + flex: none; + + .cell { + flex: 1; + + h2 { + margin-bottom: 3px; + font-weight: 500; + display: inline-flex; + align-items: center; + + i { + margin-right: 5px; + } + } + + input, + select { + padding: 0px 12px; + height: 27px; + } + } +`; + +/** + */ +export const InnerContent = styled.div<{ minWidth: number }>` + min-width: ${(props) => props.minWidth}px; + display: flex; + flex-direction: column; + position: relative; +`; diff --git a/packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.tsx b/packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.tsx new file mode 100644 index 00000000..0e34088d --- /dev/null +++ b/packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.tsx @@ -0,0 +1,316 @@ +import { useRef, useEffect, useCallback, useState } from "react"; +import EmptyMessage from "../EmptyMessage/EmptyMessage"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import Input from "../Input/Input"; +import Pagination from "../Pagination/Pagination"; +import Select from "../Select/Select"; +import TooltipText from "../TooltipText/TooltipText"; +import { IColumn, IFilter } from "./PaginatedTable.types"; +import * as Style from "./PaginatedTable.style"; + +/** + * Props. + */ +interface IPaginatedTableProps { + /** + * The configuration for the columns. + */ + columns: (IColumn | null)[]; + /** + * The highlight color for when the user hovers an item. + */ + highlightColor?: string; + /** + * Current page. + */ + page: number; + /** + * Total number of records in the list. + * This is used to calculate the correct amount of pages in the table. + */ + amountOfRecords: number; + /** + * Called to fetch the data for the page. + */ + onGetData: (page: number, idealAmountOfRows: number, filter: IFilter) => Promise | T[]; + /** + * Called when the page was changed. + */ + onChangePage: (page: number) => void; + /** + * Called for every row about to be rendered. + * If a string is returned from this function, then that specific row will be a `
` tag with a functional link. + */ + onGetRowLink?: (item: T) => string | null | undefined; + /** + * Icon to be rendered in the empty message. + */ + emptyMessageIcon?: EIcon; + /** + * Message to be rendered when there are no records in the table. + */ + emptyMessage?: string; + /** + * Shows page number or not. + */ + infinitePages?: boolean; + /** + */ + showConfigButton?: boolean; + /** + */ + onConfigButtonClick?: () => void; + /** + */ + refetchID?: number; + /** + */ + showRefreshButton?: boolean; + /** + */ + onRefreshButtonClick?: () => void; +} + +/** + */ +function PaginatedTable(props: IPaginatedTableProps) { + const [data, setData] = useState([]); + const [filter, setFilter] = useState({}); + const [pageAmount, setPageAmount] = useState(0); + const { + amountOfRecords, + emptyMessage, + emptyMessageIcon, + highlightColor, + infinitePages, + onChangePage, + onConfigButtonClick, + onGetData, + onGetRowLink, + onRefreshButtonClick, + page, + refetchID, + showConfigButton, + showRefreshButton, + } = props; + + const columns = props.columns.filter((x) => x) as IColumn[]; + + const rowsNode = useRef(null); + const filterTimeout = useRef>(); + const firstRender = useRef(true); + + /** + * Called when one of the filter changes values. + */ + const onChangeFilter = (column: IColumn, text: any) => { + setFilter({ ...filter, [column.id]: text }); + column.onFilter?.(text, column); + }; + + /** + * Renders a header cell. + */ + const renderHeaderCell = (column: IColumn) => { + const flex = column.flex || "1"; + const width = column.width || "auto"; + const filterVisible = column.filterVisible !== false; + + return ( +
+ +

+ {column.icon && } + {column.label} +

+
+ + {filterVisible && renderFilter(column)} +
+ ); + }; + + /** + * Renders a header cell. + */ + const renderFilter = (column: IColumn) => { + const filterDisabled = column.filterDisabled || column.type === "date"; + return ( + + {column.type === "boolean" ? ( + onChangeFilter(column, e.target.value)} + placeholder={filterDisabled ? "" : "search..."} + value={filter[column.id] || ""} + /> + )} + + ); + }; + + /** + * Renders a row cell. + */ + const renderRowCell = (item: T, column: IColumn, rowIndex: number) => { + const flex = column.flex || "1"; + const width = column.width || "auto"; + + return ( +
+ {column.onRender(item, rowIndex, column)} +
+ ); + }; + + /** + * Renders a single row. + */ + const renderRow = (item: T, rowIndex: number) => { + const link = onGetRowLink?.(item) as string; + + if (link) { + return ( + + {columns.map((column) => renderRowCell(item, column, rowIndex))} + + ); + } else { + return ( + + {columns.map((column) => renderRowCell(item, column, rowIndex))} + + ); + } + }; + + /** + * Renders the empty message in the center of the table if there are no records in it. + */ + const renderEmptyMessage = () => { + if (!emptyMessage) { + return null; + } + return ; + }; + + /** + */ + const getIdealAmountOfRows = () => { + const node = rowsNode.current as HTMLDivElement; + if (node) { + const headerHeight = 60; + const tableHeight = node.getBoundingClientRect().height - headerHeight; + const rowHeight = 35; + const idealAmount = Math.floor(tableHeight / rowHeight); + return idealAmount; + } + return 0; + }; + + /** + */ + const fetchPageData = useCallback(async () => { + if (!rowsNode.current) { + return; + } + + clearTimeout(filterTimeout.current as unknown as number); + const idealAmount = getIdealAmountOfRows(); + const result = await onGetData(page, idealAmount, filter); + setData(result); + }, [page, filter, onGetData]); + + /** + */ + useEffect(() => { + fetchPageData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [page]); + + /** + */ + useEffect(() => { + if (!firstRender.current) { + filterTimeout.current = setTimeout(fetchPageData, 300); + return () => clearTimeout(filterTimeout.current as unknown as number); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [filter]); + + /** + */ + useEffect(() => { + if (!firstRender.current && refetchID) { + fetchPageData(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [refetchID]); + + /** + * Sets the "first render" variable in order to prevent useless requests. + */ + useEffect(() => { + firstRender.current = false; + }, []); + + /** + * Calculates the amount of pages based on the amount of records inside + * of the table. The amount of pages will be set in a state for future use in + * the footer component. + */ + useEffect(() => { + if (!infinitePages) { + const idealAmount = getIdealAmountOfRows(); + const total = Math.ceil(amountOfRecords / idealAmount); + setPageAmount(total); + fetchPageData(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [amountOfRecords]); + + let minWidth = 0; + for (const column of columns) { + minWidth += column.width || 160; + } + + return ( + +
+ + {columns.map(renderHeaderCell)} + + {amountOfRecords === 0 ? renderEmptyMessage() : data.map(renderRow)} + + +
+ + +
+ ); +} + +export default PaginatedTable; diff --git a/packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.types.ts b/packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.types.ts new file mode 100644 index 00000000..2ce9f8da --- /dev/null +++ b/packages/tcore-console/src/Components/PaginatedTable/PaginatedTable.types.ts @@ -0,0 +1,60 @@ +import { ReactNode } from "react"; +import { EIcon } from "../Icon/Icon.types"; + +/** + * A single column in a paginated table. + */ +export interface IColumn { + /** + * Label of the column. This is what will appear above the filter in the header. + */ + label: string; + /** + * Optional icon on the left side of the label. + */ + icon?: EIcon; + /** + * The amount of flex of this column. + */ + flex?: string; + /** + * If flex = `none` then this will specify the desired width for the column. + */ + width?: number; + /** + * Tooltip for the label. + */ + tooltip?: string; + filter?: string; + /** + * Unique ID for this column. This is used to associate the filter object to this ID when fetching data. + */ + id: string; + /** + * Type of data in this column, this is used to adjust the filter accordingly. + */ + type?: "text" | "boolean" | "date" | "number" | "icon"; + /** + * Called for every cell in the body. This should return the content of the cell. + */ + onRender: (item: T, rowIndex: number, column: IColumn) => ReactNode; + /** + * Called when the filter changes. + */ + onFilter?: (value: string, column: IColumn) => void; + /** + * Indicates if the filter can be visible or not. + */ + filterVisible?: boolean; + /** + * Indicates if the filter is disabled or not. + */ + filterDisabled?: boolean; +} + +/** + * Filter object used in the state. + */ +export interface IFilter { + [key: string]: string; +} diff --git a/packages/tcore-console/src/Components/Pagination/Pagination.style.ts b/packages/tcore-console/src/Components/Pagination/Pagination.style.ts new file mode 100644 index 00000000..658d93da --- /dev/null +++ b/packages/tcore-console/src/Components/Pagination/Pagination.style.ts @@ -0,0 +1,87 @@ +import styled, { css, keyframes } from "styled-components"; + +const fadeIn = keyframes` + from { opacity: 0 }; + to { opacity: 1 }; +`; + +/** + * Main style. + */ +export const Container = styled.div` + flex: none; + background: ${(props) => props.theme.background2}; + display: flex; + height: 40px; + align-items: center; + justify-content: center; + text-align: center; + padding: 0px 15px; + display: flex; + z-index: 1; + position: relative; + + .config-button, + .refresh-button { + position: absolute; + top: 50%; + padding: 7px 10px; + cursor: pointer; + border-radius: 5px; + transform: translate(0%, -50%); + display: flex; + align-items: center; + + &:hover { + background: rgba(0, 0, 0, 0.1); + } + } + + .config-button { + left: 10px; + } + + .refresh-button { + right: 10px; + } +`; + +/** + * A single page button. + */ +export const Button = styled.button<{ selected?: boolean }>` + border: 0; + height: 27px; + min-width: 30px; + padding: 0; + background: transparent; + display: flex; + align-items: center; + justify-content: center; + border-radius: 3px; + cursor: pointer; + transition: background-color 0.15s; + animation: ${fadeIn} 0.2s; + + &:hover { + background: rgba(0, 0, 0, 0.1); + } + + &:active { + background: rgba(0, 0, 0, 0.2); + } + + &:disabled { + > * { + opacity: 0.4; + } + background: transparent !important; + cursor: initial; + } + + ${(props) => + props.selected && + css` + background: rgba(0, 0, 0, 0.25); + `} +`; diff --git a/packages/tcore-console/src/Components/Pagination/Pagination.tsx b/packages/tcore-console/src/Components/Pagination/Pagination.tsx new file mode 100644 index 00000000..f3d5ebac --- /dev/null +++ b/packages/tcore-console/src/Components/Pagination/Pagination.tsx @@ -0,0 +1,130 @@ +import { Tooltip } from "../.."; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import * as Style from "./Pagination.style"; + +/** + * Props. + */ +interface IPaginationProps { + /** + * Current page. + */ + page: number; + /** + * Amount of pages to be rendered. + */ + pageAmount: number; + /** + * Called when the page was changed. + */ + onChange: (page: number) => void; + /** + * Shows page number or not. + */ + infinitePages?: boolean; + /** + * Total number of records in the list. + * This is used only if the `infinitePages` prop is active. + */ + amountOfRecords?: number; + /** + * Ideal amount of rows in the list. + * This is used only if the `infinitePages` prop is active. + */ + idealAmountOfRows?: number; + /** + */ + showConfigButton?: boolean; + /** + */ + onConfigButtonClick?: () => void; + /** + */ + showRefreshButton?: boolean; + /** + */ + onRefreshButtonClick?: () => void; +} + +/** + */ +function Pagination(props: IPaginationProps) { + const { page, pageAmount, amountOfRecords, idealAmountOfRows, infinitePages, onChange } = props; + const array = new Array(pageAmount || 1).fill("").map((_, i) => i); + + /** + * Goes back one page. + */ + const goBack = () => { + onChange(page - 1); + }; + + /** + * Advances one page. + */ + const goForward = () => { + onChange(page + 1); + }; + + /** + * Renders a single item. + */ + const renderItem = (value: number) => { + const selected = page === value; + return ( + onChange(value)} selected={selected}> + {value + 1} + + ); + }; + + /** + */ + const renderArrow = (icon: EIcon, disabled: boolean, onClick: VoidFunction) => { + return ( + + + + ); + }; + + return ( + + {props.showConfigButton && ( + +
+ +
+
+ )} + + {infinitePages ? ( + <> + {renderArrow(EIcon["chevron-left"], page === 0, goBack)} + {renderArrow( + EIcon["chevron-right"], + (amountOfRecords || 0) < (idealAmountOfRows || 0), + goForward + )} + + ) : pageAmount > 0 ? ( + <> + {renderArrow(EIcon["chevron-left"], page === 0, goBack)} + {array.map(renderItem)} + {renderArrow(EIcon["chevron-right"], page === pageAmount - 1, goForward)} + + ) : null} + + {props.showRefreshButton && ( + +
+ +
+
+ )} +
+ ); +} + +export default Pagination; diff --git a/packages/tcore-console/src/Components/PluginImage/PluginImage.style.ts b/packages/tcore-console/src/Components/PluginImage/PluginImage.style.ts new file mode 100644 index 00000000..9e754e95 --- /dev/null +++ b/packages/tcore-console/src/Components/PluginImage/PluginImage.style.ts @@ -0,0 +1,28 @@ +import styled from "styled-components"; + +/** + */ +export const Container = styled.div<{ width: number; height: number }>` + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 20%; + width: ${(props) => props.width}px; + height: ${(props) => props.height}px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + background: white; + + i svg { + opacity: 0.3; + position: relative; + top: 1px; + } + + img { + object-fit: contain; + width: 90%; + height: 90%; + border: 0; + } +`; diff --git a/packages/tcore-console/src/Components/PluginImage/PluginImage.tsx b/packages/tcore-console/src/Components/PluginImage/PluginImage.tsx new file mode 100644 index 00000000..83d560da --- /dev/null +++ b/packages/tcore-console/src/Components/PluginImage/PluginImage.tsx @@ -0,0 +1,45 @@ +import { useCallback, useState } from "react"; +import { Icon, EIcon } from "../.."; +import * as Style from "./PluginImage.style"; + +/** + * Props. + */ +interface IPluginImageProps { + /** + * Width in pixels for the image. The height will be adjusted based on this. + */ + width: number; + /** + * Source of the image. + */ + src?: string | null; +} + +/** + * Shows the logo of a plugin in the usual dimensions. + */ +function PluginImage(props: IPluginImageProps) { + const [fail, setFail] = useState(false); + const { src, width } = props; + const height = width / 1.35; + + /** + * Called when the image couldn't load. + */ + const onImgError = useCallback(() => { + setFail(true); + }, []); + + return ( + + {fail ? ( + + ) : src ? ( + + ) : null} + + ); +} + +export default PluginImage; diff --git a/packages/tcore-console/src/Components/Plugins/Common/ClassTypes/ClassTypes.style.ts b/packages/tcore-console/src/Components/Plugins/Common/ClassTypes/ClassTypes.style.ts new file mode 100644 index 00000000..83aff4f6 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/ClassTypes/ClassTypes.style.ts @@ -0,0 +1,58 @@ +import styled from "styled-components"; +import { fonts } from "../../../../theme"; + +/** + */ +export const Container = styled.ul` + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + margin-top: 0; + + > i { + color: ${(props) => props.theme.font2}; + } +`; + +/** + */ +export const Item = styled.li` + display: flex; + margin-bottom: 10px; + align-items: center; + + .icon-container { + width: 30px; + display: flex; + flex: none; + justify-content: center; + margin-left: 10px; + } + + &:before { + content: ""; + width: 5px; + height: 5px; + background: black; + border-radius: 50%; + } + + &:last-child { + margin-bottom: 0; + } + + .info { + margin-left: 10px; + } + + .title { + font-size: ${() => fonts.medium}; + font-weight: 500; + margin-bottom: 2px; + } + + .description { + color: ${(props) => props.theme.font2}; + } +`; diff --git a/packages/tcore-console/src/Components/Plugins/Common/ClassTypes/ClassTypes.tsx b/packages/tcore-console/src/Components/Plugins/Common/ClassTypes/ClassTypes.tsx new file mode 100644 index 00000000..9d93e0f3 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/ClassTypes/ClassTypes.tsx @@ -0,0 +1,70 @@ +import { TPluginType } from "@tago-io/tcore-sdk/types"; +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import * as Style from "./ClassTypes.style"; + +/** + * Props. + */ +interface IClassTypesProps { + value: TPluginType[]; +} + +/** + * Indicates what ClassTypes a plugin can run on + */ +function ClassTypes(props: IClassTypesProps) { + const { value } = props; + + /** + * Renders a single platform. + */ + const renderItem = (item: TPluginType) => { + let title = ""; + let icon = null; + let description = ""; + + if (item === "action-trigger") { + title = "Action Trigger"; + icon = EIcon.bolt; + description = "Creates one or more Action Triggers."; + } else if (item === "action-type") { + title = "Action Types"; + icon = EIcon.bolt; + description = "Creates one or more Action Types."; + } else if (item === "database") { + title = "Database"; + icon = EIcon.database; + description = "Creates one or more Databases."; + } else if (item === "decoder") { + title = "Payload Decoder"; + icon = EIcon.device; + description = "Creates one or more Payload Decoders."; + } else if (item === "encoder") { + title = "Payload Encoder"; + icon = EIcon.device; + description = "Creates one or more Payload Encoders."; + } else if (item === "service") { + title = "Service"; + icon = EIcon.cog; + description = "Creates one or more services for running code."; + } + + return ( + +
+ +
+ +
+
{title}
+
{description}
+
+
+ ); + }; + + return {value.map(renderItem)}; +} + +export default ClassTypes; diff --git a/packages/tcore-console/src/Components/Plugins/Common/MainInformation/MainInformation.style.ts b/packages/tcore-console/src/Components/Plugins/Common/MainInformation/MainInformation.style.ts new file mode 100644 index 00000000..79eb21bf --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/MainInformation/MainInformation.style.ts @@ -0,0 +1,23 @@ +import styled from "styled-components"; + +/** + */ +export const Container = styled.div` + display: flex; + flex-direction: column; + + .item { + display: flex; + margin-bottom: 5px; + align-items: center; + } + + .item:last-child { + margin-bottom: 0; + } + + .item > div:first-child { + width: 100px; + flex: none; + } +`; diff --git a/packages/tcore-console/src/Components/Plugins/Common/MainInformation/MainInformation.tsx b/packages/tcore-console/src/Components/Plugins/Common/MainInformation/MainInformation.tsx new file mode 100644 index 00000000..04f382ce --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/MainInformation/MainInformation.tsx @@ -0,0 +1,73 @@ +import { TPluginState } from "@tago-io/tcore-sdk/types"; +import Capitalize from "../../../Capitalize/Capitalize"; +import RelativeDate from "../../../RelativeDate/RelativeDate"; +import Publisher from "../Publisher/Publisher"; +import * as Style from "./MainInformation.style"; + +/** + * Props. + */ +interface IMainInformationProps { + /** + * Name of the publisher. + */ + publisherName: string; + /** + * Domain in case the publisher is verified. + */ + publisherDomain?: string; + /** + * Version of the plugin. + */ + version: string; + /** + * Date of install for the plugin. + */ + installDate?: string; + /** + * Date of publish for the plugin. + */ + publishDate?: string; + /** + * State of execution of the plugin. + */ + state?: TPluginState; +} + +/** + * Renders the main information of a plugin in a tabular way. + * Some of the information shown here: `publisher`, `version`, `install date`. + */ +function MainInformation(props: IMainInformationProps) { + const { version, state, publisherName, publisherDomain, publishDate } = props; + + return ( + +
+
Version
+
{version}
+
+ +
+
Publisher
+ +
+ + {state && ( +
+
State
+ {state} +
+ )} + + {publishDate && ( +
+
Publish Date
+ +
+ )} +
+ ); +} + +export default MainInformation; diff --git a/packages/tcore-console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.style.ts b/packages/tcore-console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.style.ts new file mode 100644 index 00000000..bad039be --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.style.ts @@ -0,0 +1,112 @@ +import styled, { css, keyframes } from "styled-components"; + +/** + */ +const animationEffectProgressBar = keyframes` + 0% { + background-position: 0 0; + } + 100% { + background-position: 50px 50px; + } +`; + +/** + * Main container. + */ +export const Container = styled.div` + display: flex; + flex-direction: column; + height: 100%; + + .console-container { + height: 300px; + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 3px; + overflow: auto; + flex: 1; + } +`; + +/** + * Description of the modal. + */ +export const Progress = styled.div<{ done: boolean; error: boolean; value: number }>` + width: 100%; + background: rgba(0, 0, 0, 0.1); + border-radius: 5px; + margin-bottom: 1rem; + height: 20px; + overflow: hidden; + position: relative; + flex: none; + + > .value { + width: ${(props) => props.value}%; + background: ${(props) => props.theme.buttonPrimary}; + height: 100%; + position: absolute; + left: 0px; + top: 0px; + transition: width 0.2s; + + .effect { + content: ""; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background-image: linear-gradient( + -45deg, + rgba(255, 255, 255, 0.2) 25%, + transparent 25%, + transparent 50%, + rgba(255, 255, 255, 0.2) 50%, + rgba(255, 255, 255, 0.2) 75%, + transparent 75%, + transparent + ); + z-index: 1; + background-size: 50px 50px; + animation: ${animationEffectProgressBar} 2s linear infinite; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + border-top-left-radius: 20px; + border-bottom-left-radius: 20px; + overflow: hidden; + } + } + + ${(props) => + props.error && + css` + > .value { + background: ${props.theme.buttonDanger}; + } + `} + + ${(props) => + props.done && + css` + > .value { + .effect { + animation: none; + } + } + `} +`; + +/** + * Description of the modal. + */ +export const Message = styled.div` + margin-bottom: 1rem; + color: ${(props) => props.theme.font2}; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + flex: none; +`; diff --git a/packages/tcore-console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.tsx b/packages/tcore-console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.tsx new file mode 100644 index 00000000..6760dc6e --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.tsx @@ -0,0 +1,149 @@ +import { ESocketResource, ILog } from "@tago-io/tcore-sdk/types"; +import { observer } from "mobx-react"; +import { memo, MouseEvent, useCallback, useEffect, useState } from "react"; +import { unstable_batchedUpdates } from "react-dom"; +import { useTheme } from "styled-components"; +import installPlugin from "../../../../Requests/installPlugin"; +import { socket } from "../../../../System/Socket"; +import store from "../../../../System/Store"; +import Console from "../../../Console/Console"; +import { EIcon } from "../../../Icon/Icon.types"; +import Modal from "../../../Modal/Modal"; +import * as Style from "./ModalInstallPlugin.style"; + +/** + * Props. + */ +interface IModalInstallPlugin { + /** + * Called when the modal is closed. + */ + onClose: () => void; + /** + * The file path for the plugin that will be installed. + */ + source: string; +} + +/** + * Controls the whole logic of making the request to install a plugin. + * It also shows a progress bar and some output for the user to see how long the process may take. + * This modal only install plugins in the filesystem, not files that can be downloaded. + */ +function ModalInstallPlugin(props: IModalInstallPlugin) { + const [logs, setLogs] = useState([]); + const [done, setDone] = useState(false); + const [error, setError] = useState(false); + const [buttonDisabled, setButtonDisabled] = useState(false); + const [progress, setProgress] = useState(0); + const theme = useTheme(); + const { source } = props; + + /** + * Sends the install request to the back-end. + */ + const sendInstallRequest = useCallback(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + try { + await installPlugin(source); + setProgress(100); // just to make sure it shows the bar complete + } catch (e) { + setError(true); + } finally { + setTimeout(() => { + setDone(true); + }, 500); + } + }, [source]); + + /** + * Confirms and closes the modal. + */ + const confirm = async (e: MouseEvent) => { + setButtonDisabled(true); + e.preventDefault(); + window.location.reload(); + }; + + /** + * Makes the request to install the plugin. + */ + useEffect(() => { + if (done) { + return; + } + + function onInstallLogs(data: any) { + const log: ILog = { + message: data.message, + error: data.error, + timestamp: Date.now() as any, + }; + + unstable_batchedUpdates(() => { + if (data.error) { + setError(true); + } + setProgress(data.progress); + setLogs((l) => [...l, log]); + }); + } + + socket.on("plugin::install", onInstallLogs); + return () => { + socket.off("plugin::install", onInstallLogs); + }; + }, [done]); + + /** + * Attaches and detaches the plugin to get the logs during installation. + */ + useEffect(() => { + if (store.socketConnected) { + socket.emit("attach", ESocketResource.pluginInstall); + return () => { + socket.emit("detach", ESocketResource.pluginInstall); + }; + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [store.socketConnected]); + + /** + * Makes the request to install the plugin. + */ + useEffect(() => { + sendInstallRequest(); + }, [sendInstallRequest]); + + return ( + window.location.reload()} + onConfirm={confirm} + confirmButtonText="Close" + title="Installing Plugin" + width="850px" + height="90%" + showCancelButton={false} + showCloseButton={false} + isConfirmButtonDisabled={buttonDisabled || !done} + > + + Plugin source: {source} + + +
+
+
+ + +
+ +
+ + + ); +} + +export default memo(observer(ModalInstallPlugin)); diff --git a/packages/tcore-console/src/Components/Plugins/Common/ModalUninstallPlugin/ModalUninstallPlugin.tsx b/packages/tcore-console/src/Components/Plugins/Common/ModalUninstallPlugin/ModalUninstallPlugin.tsx new file mode 100644 index 00000000..53c1b559 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/ModalUninstallPlugin/ModalUninstallPlugin.tsx @@ -0,0 +1,102 @@ +import { KeyboardEvent, MouseEvent, useCallback, useState } from "react"; +import Checkbox from "../../../Checkbox/Checkbox"; +import FormGroup from "../../../FormGroup/FormGroup"; +import Input from "../../../Input/Input"; +import Modal from "../../../Modal/Modal"; +import TooltipText from "../../../TooltipText/TooltipText"; + +/** + * Props. + */ +interface IModalUninstallPluginProps { + /** + * Called when the user cancels the uninstall. + */ + onClose: () => void; + /** + * Called when the user confirms the uninstall. + */ + onConfirm: (keepData: boolean) => Promise; + /** + * This prop indicates where to send the user to once the process end. + */ + redirectTo?: string; +} + +/** + */ +function ModalUninstallPlugin(props: IModalUninstallPluginProps) { + const [value, setValue] = useState(""); + const [keepData, setKeepData] = useState(false); + const [buttonDisabled, setButtonDisabled] = useState(false); + + const { onConfirm, onClose, redirectTo } = props; + + /** + * Confirms the uninstall for the plugin. + */ + const confirm = useCallback( + async (e?: MouseEvent) => { + setButtonDisabled(true); + await onConfirm(keepData); + e?.preventDefault(); + + if (redirectTo) { + window.location.href = `/console${redirectTo}`; + } else { + window.location.reload(); + } + }, + [keepData, onConfirm, redirectTo] + ); + + /** + * Called when the input receives a keydown event. + */ + const onKeyDown = useCallback( + (e: KeyboardEvent) => { + if (e.key === "Enter") { + if (value === "uninstall") { + confirm(); + } + } + }, + [confirm, value] + ); + + return ( + + Do you really want to uninstall this plugin? + + + setValue(e.target.value)} + onKeyDown={onKeyDown} + placeholder="uninstall" + disabled={buttonDisabled} + value={value} + /> + + + + setKeepData(e.target.checked)}> + + Keep settings + + + + + ); +} + +export default ModalUninstallPlugin; diff --git a/packages/tcore-console/src/Components/Plugins/Common/ModuleSetup/ModuleSetup.style.tsx b/packages/tcore-console/src/Components/Plugins/Common/ModuleSetup/ModuleSetup.style.tsx new file mode 100644 index 00000000..7a8bae18 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/ModuleSetup/ModuleSetup.style.tsx @@ -0,0 +1,15 @@ +import styled from "styled-components"; + +/** + */ +export const Container = styled.div` + margin-bottom: 3px; + border-radius: 5px; + box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.05); + overflow: hidden; + border: 1px solid rgba(0, 0, 0, 0.07); + + > * { + background: white; + } +`; diff --git a/packages/tcore-console/src/Components/Plugins/Common/ModuleSetup/ModuleSetup.tsx b/packages/tcore-console/src/Components/Plugins/Common/ModuleSetup/ModuleSetup.tsx new file mode 100644 index 00000000..ab4db681 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/ModuleSetup/ModuleSetup.tsx @@ -0,0 +1,136 @@ +import { IPlugin, IPluginModule } from "@tago-io/tcore-sdk/types"; +import { useCallback, useState } from "react"; +import Accordion from "../../../Accordion/Accordion"; +import { EIcon } from "../../../Icon/Icon.types"; +import PluginConfigFields from "../PluginConfigFields/PluginConfigFields"; +import ModuleStatus from "../ModuleStatus/ModuleStatus"; +import { getLocalStorageAsBoolean, setLocalStorage } from "../../../../Helpers/localStorage"; +import { FormGroup } from "../../../.."; +import Status from "../Status/Status"; +import * as Style from "./ModuleSetup.style"; + +/** + * Props. + */ +interface ISetupConfigProps { + /** + */ + module: IPluginModule; + /** + */ + data: IPlugin; + /** + * The value for the fields. + */ + values: any; + /** + * Called when a value of a field changes. + */ + onChangeValues: (values: any) => void; + /** + * The error for the fields. + */ + errors: any; + /** + * Called when this module gets started. + */ + onStart: (module: IPluginModule) => Promise; + /** + * Called when this module gets stopped. + */ + onStop: (module: IPluginModule) => Promise; +} + +/** + */ +function ModuleSetup(props: ISetupConfigProps) { + const { module, data, errors, values, onStart, onStop, onChangeValues } = props; + const [open, setOpen] = useState(() => getLocalStorageAsBoolean(module.id, true)); + + /** + */ + const setValues = useCallback( + (oldValues) => { + onChangeValues({ [module.id]: { ...oldValues } }); + }, + [onChangeValues, module.id] + ); + + /** + */ + const changeOpen = useCallback( + (newOpen: boolean) => { + setOpen(newOpen); + setLocalStorage(module.id, String(newOpen)); + }, + [module.id] + ); + + /** + * Returns the icon for a type of plugin. + */ + const getIcon = (): EIcon => { + switch (module.type) { + case "database": + return EIcon.database; + case "action-trigger": + return EIcon.bolt; + case "action-type": + return EIcon.bolt; + case "filesystem": + return EIcon.folder; + default: + return EIcon.cog; + } + }; + + if (module.type === "encoder") { + // encoder types do not get rendered. + return null; + } + + if (!module.configs || module.configs.length === 0) { + // no configs + return null; + } + + return ( + + + {module.message && ( + + + + )} + + onStart(module)} + onStop={() => onStop(module)} + data={data} + module={module} + /> + + + + + ); +} + +export default ModuleSetup; diff --git a/packages/tcore-console/src/Components/Plugins/Common/ModuleStatus/ModuleStatus.style.ts b/packages/tcore-console/src/Components/Plugins/Common/ModuleStatus/ModuleStatus.style.ts new file mode 100644 index 00000000..bfdfc859 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/ModuleStatus/ModuleStatus.style.ts @@ -0,0 +1,77 @@ +import styled, { css } from "styled-components"; +import * as ButtonStyle from "../../../Button/Button.style"; + +/** + * Main container. + */ +export const Container = styled.div` + display: flex; + flex-direction: column; + flex: 1; + width: 100%; + margin-bottom: 1rem; + border: 1px solid rgba(0, 0, 0, 0.1); + overflow: hidden; + border-radius: 5px; + + > .error { + background: hsla(0, 100%, 44%, 0.1); + padding: 5px 10px; + display: flex; + align-items: center; + + i { + margin-right: 7px; + } + } +`; + +/** + */ +export const Status = styled.div<{ running?: boolean }>` + flex: 1; + margin-right: 10px; + display: flex; + align-items: center; + justify-content: space-between; + background: rgba(0, 0, 0, 0.03); + padding: 10px; + width: 100%; + transition: opacity 0.2s; + + ${(props) => + !props.running && + css` + opacity: 0.7; + `} + + > .title { + display: flex; + align-items: center; + flex: 1; + } + + > .buttons-container { + flex: none; + > .buttons-inner { + flex: none; + position: relative; + border: 1px solid rgba(0, 0, 0, 0.1); + overflow: hidden; + border-radius: 3px; + + ${ButtonStyle.Container}:first-child { + margin-right: -1px; + } + + ${ButtonStyle.Container}:not(:disabled) { + z-index: 1; + } + + ${ButtonStyle.Container} { + border-radius: 0; + border: 0 !important; + } + } + } +`; diff --git a/packages/tcore-console/src/Components/Plugins/Common/ModuleStatus/ModuleStatus.tsx b/packages/tcore-console/src/Components/Plugins/Common/ModuleStatus/ModuleStatus.tsx new file mode 100644 index 00000000..409e81cc --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/ModuleStatus/ModuleStatus.tsx @@ -0,0 +1,104 @@ +import { IPlugin, IPluginModule } from "@tago-io/tcore-sdk/types"; +import { useCallback, useEffect, useState } from "react"; +import { useTheme } from "styled-components"; +import { EIcon, Icon } from "../../../.."; +import Button from "../../../Button/Button"; +import Capitalize from "../../../Capitalize/Capitalize"; +import * as Style from "./ModuleStatus.style"; + +/** + * Props. + */ +interface IModuleStatusProps { + /** + */ + data: IPlugin; + /** + */ + module: IPluginModule; + /** + * Called when this module gets started. + */ + onStart: () => Promise; + /** + * Called when this module gets stopped. + */ + onStop: () => Promise; +} + +/** + */ +function ModuleStatus(props: IModuleStatusProps) { + const { data, module, onStop, onStart } = props; + const [state, setState] = useState(() => module.state); + const { error } = module; + const theme = useTheme(); + + /** + * Starts the service. + */ + const start = useCallback(() => { + setState("starting"); + setTimeout(onStart, 200); + }, [onStart]); + + /** + * Stops the service. + */ + const stop = useCallback(() => { + setState("stopping"); + setTimeout(onStop, 200); + }, [onStop]); + + /** + */ + useEffect(() => { + if (module.state !== state) { + setState(module.state); + // setState("starting"); + // timeout.current = setTimeout(() => setState(module.state), 200); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [module.state]); + + const pluginRunning = data.state === "started"; + const loading = state === "starting" || state === "stopping"; + const started = state === "started"; + + return ( + + +
+ Module status:  + {loading ? ( + + ) : ( + + {state} + + )} +
+ +
+
+ + +
+
+
+ + {error && !loading && pluginRunning && ( +
+ + {error} +
+ )} +
+ ); +} + +export default ModuleStatus; diff --git a/packages/tcore-console/src/Components/Plugins/Common/Permissions/Permissions.style.ts b/packages/tcore-console/src/Components/Plugins/Common/Permissions/Permissions.style.ts new file mode 100644 index 00000000..83aff4f6 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/Permissions/Permissions.style.ts @@ -0,0 +1,58 @@ +import styled from "styled-components"; +import { fonts } from "../../../../theme"; + +/** + */ +export const Container = styled.ul` + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + margin-top: 0; + + > i { + color: ${(props) => props.theme.font2}; + } +`; + +/** + */ +export const Item = styled.li` + display: flex; + margin-bottom: 10px; + align-items: center; + + .icon-container { + width: 30px; + display: flex; + flex: none; + justify-content: center; + margin-left: 10px; + } + + &:before { + content: ""; + width: 5px; + height: 5px; + background: black; + border-radius: 50%; + } + + &:last-child { + margin-bottom: 0; + } + + .info { + margin-left: 10px; + } + + .title { + font-size: ${() => fonts.medium}; + font-weight: 500; + margin-bottom: 2px; + } + + .description { + color: ${(props) => props.theme.font2}; + } +`; diff --git a/packages/tcore-console/src/Components/Plugins/Common/Permissions/Permissions.tsx b/packages/tcore-console/src/Components/Plugins/Common/Permissions/Permissions.tsx new file mode 100644 index 00000000..748d9e72 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/Permissions/Permissions.tsx @@ -0,0 +1,71 @@ +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import * as Style from "./Permissions.style"; + +/** + * Props. + */ +interface IPermissionsProps { + value: string[]; +} + +/** + * Indicates what permissions a plugin is requesting. + */ +function Permissions(props: IPermissionsProps) { + const { value } = props; + + /** + * Renders a single permission. + */ + const renderPermission = (perm: string) => { + let title = ""; + let icon = null; + let description = ""; + + if (perm === "device") { + title = "Devices"; + icon = EIcon.device; + description = "Create, modify, and delete devices."; + } else if (perm === "action") { + title = "Actions"; + icon = EIcon.bolt; + description = "Create, modify, and delete actions."; + } else if (perm === "analysis") { + title = "Analyses"; + icon = EIcon.code; + description = "Create, modify, and delete analyses."; + } else if (perm === "bucket-data" || perm === "device-data") { + title = "Device data"; + icon = EIcon.cube; + description = "Add and remove data in devices."; + } else { + return null; + } + + return ( + +
+ +
+ +
+
{title}
+
{description}
+
+
+ ); + }; + + return ( + + {value.length > 0 ? ( + value.map(renderPermission) + ) : ( + This plugin doesn't require any permissions. + )} + + ); +} + +export default Permissions; diff --git a/packages/tcore-console/src/Components/Plugins/Common/Platforms/Platforms.style.ts b/packages/tcore-console/src/Components/Plugins/Common/Platforms/Platforms.style.ts new file mode 100644 index 00000000..83aff4f6 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/Platforms/Platforms.style.ts @@ -0,0 +1,58 @@ +import styled from "styled-components"; +import { fonts } from "../../../../theme"; + +/** + */ +export const Container = styled.ul` + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + margin-top: 0; + + > i { + color: ${(props) => props.theme.font2}; + } +`; + +/** + */ +export const Item = styled.li` + display: flex; + margin-bottom: 10px; + align-items: center; + + .icon-container { + width: 30px; + display: flex; + flex: none; + justify-content: center; + margin-left: 10px; + } + + &:before { + content: ""; + width: 5px; + height: 5px; + background: black; + border-radius: 50%; + } + + &:last-child { + margin-bottom: 0; + } + + .info { + margin-left: 10px; + } + + .title { + font-size: ${() => fonts.medium}; + font-weight: 500; + margin-bottom: 2px; + } + + .description { + color: ${(props) => props.theme.font2}; + } +`; diff --git a/packages/tcore-console/src/Components/Plugins/Common/Platforms/Platforms.tsx b/packages/tcore-console/src/Components/Plugins/Common/Platforms/Platforms.tsx new file mode 100644 index 00000000..f7c1a410 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/Platforms/Platforms.tsx @@ -0,0 +1,69 @@ +import Icon from "../../../Icon/Icon"; +import { EIcon } from "../../../Icon/Icon.types"; +import * as Style from "./Platforms.style"; + +/** + * Props. + */ +interface IPlatformsProps { + value: string[]; +} + +/** + * Indicates what platforms a plugin can run on + */ +function Platforms(props: IPlatformsProps) { + const { value } = props; + + /** + * Renders a single platform. + */ + const renderItem = (item: string) => { + let title = ""; + let icon = null; + let description = ""; + + if (item === "mac-x64") { + title = "MacOS x64"; + icon = EIcon.apple; + description = "Runs on MacOS x64."; + } else if (item === "win-x64") { + title = "Windows x64"; + icon = EIcon.windows; + description = "Runs on Windows x64."; + } else if (item === "linux-x64") { + title = "Linux x64"; + icon = EIcon.linux; + description = "Runs on Linux x64."; + } else if (item === "linux-arm64") { + title = "Linux ARM64"; + icon = EIcon.linux; + description = "Runs on Linux ARM64."; + } else if (item === "linux-armv7") { + title = "Linux ARMV7"; + icon = EIcon.linux; + description = "Runs on Linux ARMV7."; + } else if (item === "any") { + title = "Any"; + icon = EIcon.desktop; + description = "Runs on any supported system."; + } + + return ( + +
+ +
+ +
+
{title}
+
{description}
+
+
+ ); + }; + + return {value.map(renderItem)}; +} + +export default Platforms; diff --git a/packages/tcore-console/src/Components/Plugins/Common/PluginConfigFields/PluginConfigFields.style.ts b/packages/tcore-console/src/Components/Plugins/Common/PluginConfigFields/PluginConfigFields.style.ts new file mode 100644 index 00000000..fb9dce2c --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/PluginConfigFields/PluginConfigFields.style.ts @@ -0,0 +1,30 @@ +import styled from "styled-components"; + +/** + * Main container. + */ +export const Container = styled.div` + margin-bottom: -1rem; +`; + +/** + */ +export const Row = styled.div` + display: flex; + margin: 0px -10px; +`; + +/** + */ +export const RowField = styled.div` + flex: 1; + margin: 0px 10px; +`; + +/** + */ +export const Divisor = styled.div` + height: 1px; + background: rgba(0, 0, 0, 0.1); + margin: 1rem 0px; +`; diff --git a/packages/tcore-console/src/Components/Plugins/Common/PluginConfigFields/PluginConfigFields.tsx b/packages/tcore-console/src/Components/Plugins/Common/PluginConfigFields/PluginConfigFields.tsx new file mode 100644 index 00000000..4861cdf5 --- /dev/null +++ b/packages/tcore-console/src/Components/Plugins/Common/PluginConfigFields/PluginConfigFields.tsx @@ -0,0 +1,329 @@ +import { + IPluginConfigField, + IPluginConfigFieldBoolean, + IPluginConfigFieldFile, + IPluginConfigFieldFolder, + IPluginConfigFieldGroup, + IPluginConfigFieldNumber, + IPluginConfigFieldOption, + IPluginConfigFieldPassword, + IPluginConfigFieldRadio, + IPluginConfigFieldRow, + IPluginConfigFieldString, + IPluginConfigFieldStringList, +} from "@tago-io/tcore-sdk/types"; +import { ReactNode } from "react"; +import Icon from "../../../Icon/Icon"; +import TooltipText from "../../../TooltipText/TooltipText"; +import FileSelect from "../../../FileSelect/FileSelect"; +import FormGroup from "../../../FormGroup/FormGroup"; +import IconRadio from "../../../IconRadio/IconRadio"; +import Input from "../../../Input/Input"; +import InputList from "../../../InputList/InputList"; +import OptionList from "../../../OptionList/OptionList"; +import Select from "../../../Select/Select"; +import Switch from "../../../Switch/Switch"; +import { EIcon } from "../../../.."; +import isConfigFieldVisible from "../../../../Helpers/isConfigFieldVisible"; +import * as Style from "./PluginConfigFields.style"; + +/** + * Props + */ +interface IPluginConfigFieldsProps { + /** + * The data containing all the fields' information. + */ + data: IPluginConfigField[]; + /** + * The value for the fields. + */ + values: any; + /** + * Called when a value of a field changes. + */ + onChangeValues: (values: any) => void; + /** + * Error of the fields. + */ + errors?: any; +} + +/** + * Shows a series of fields based on a plugin configuration. + */ +function PluginConfigFields(props: IPluginConfigFieldsProps) { + const { data, values, errors, onChangeValues } = props; + + /** + * Renders a switch/checkbox field. + */ + const renderBoolean = (field: IPluginConfigFieldBoolean) => { + return ( + + onChangeValues({ ...values, [field.field]: e })} + > + {field.name} + + + ); + }; + + /** + * Renders a simple string field. + */ + const renderString = (field: IPluginConfigFieldString) => { + return ( + onChangeValues({ ...values, [field.field]: e.target.value })} + placeholder={field.placeholder || ""} + value={values[field.field] || ""} + /> + ); + }; + + /** + * Renders a password string field. + */ + const renderPassword = (field: IPluginConfigFieldPassword) => { + return ( + onChangeValues({ ...values, [field.field]: e.target.value })} + placeholder={field.placeholder || ""} + type="password" + value={values[field.field] || ""} + /> + ); + }; + + /** + * Renders a simple number field. + */ + const renderInputNumber = (field: IPluginConfigFieldNumber) => { + return ( + onChangeValues({ ...values, [field.field]: Number(e.target.value) })} + onWheel={(e) => (e.target as HTMLInputElement).blur()} // annoying scroll + placeholder={field.placeholder || ""} + type="number" + value={values[field.field] || ""} + min={typeof field.min === "number" ? field.min : undefined} + max={typeof field.max === "number" ? field.max : undefined} + /> + ); + }; + + /** + * Renders a select field with a bunch of options. + */ + const renderOption = (field: IPluginConfigFieldOption) => { + const options = [{ value: "", label: "", disabled: true }, ...(field.options || [])]; + return ( + + + + + + + + + ); +} + +export default ResourceLinkField; diff --git a/packages/tcore-console/src/Components/Row/Row.style.tsx b/packages/tcore-console/src/Components/Row/Row.style.tsx new file mode 100644 index 00000000..7a53bd0c --- /dev/null +++ b/packages/tcore-console/src/Components/Row/Row.style.tsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; + +export const Container = styled.div` + display: flex; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px; +`; diff --git a/packages/tcore-console/src/Components/Row/Row.tsx b/packages/tcore-console/src/Components/Row/Row.tsx new file mode 100644 index 00000000..e00f0c08 --- /dev/null +++ b/packages/tcore-console/src/Components/Row/Row.tsx @@ -0,0 +1,19 @@ +import { CSSProperties, ReactNode } from "react"; +import * as Style from "./Row.style"; + +/** + * Props. + */ +interface IRowProps { + style?: CSSProperties; + children?: ReactNode; +} + +/** + * Bootstrap row. + */ +function Row(props: IRowProps) { + return {props.children}; +} + +export default Row; diff --git a/packages/tcore-console/src/Components/RowManipulator/RowManipulator.style.ts b/packages/tcore-console/src/Components/RowManipulator/RowManipulator.style.ts new file mode 100644 index 00000000..66bddf54 --- /dev/null +++ b/packages/tcore-console/src/Components/RowManipulator/RowManipulator.style.ts @@ -0,0 +1,52 @@ +import styled, { css } from "styled-components"; + +export const Container = styled.div` + display: flex; + flex-direction: column; + width: 100%; + + .row { + display: flex; + align-items: center; + + .content { + display: flex; + align-items: center; + flex: 1; + } + + &:not(:first-child) { + margin-top: 5px; + } + } +`; + +/** + */ +export const Buttons = styled.div<{ last: boolean }>` + flex: none; + display: flex; + justify-content: center; + width: 81px; + + button:nth-child(1) { + margin-right: -1px; + + ${(props) => + !props.last && + css` + border-top-right-radius: 0; + border-bottom-right-radius: 0; + `} + } + + button:nth-child(2) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + + button { + padding: 0px 12px; + height: 33px; + } +`; diff --git a/packages/tcore-console/src/Components/RowManipulator/RowManipulator.tsx b/packages/tcore-console/src/Components/RowManipulator/RowManipulator.tsx new file mode 100644 index 00000000..e2cd9a97 --- /dev/null +++ b/packages/tcore-console/src/Components/RowManipulator/RowManipulator.tsx @@ -0,0 +1,83 @@ +import { ReactNode, useEffect } from "react"; +import Button from "../Button/Button"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import * as Style from "./RowManipulator.style"; + +/** + * Props. + */ +interface IRowManipulatorProps { + /** + * Data to be rendered in this component. + */ + data: T[]; + /** + * Called for each item in the data array. + */ + onRenderItem: (item: T, index: number) => ReactNode; + /** + * Called when the user presses the add button. + */ + onAddItem?: () => void; + /** + * Called when the user presses the remove button to remove a specific row. + */ + onRemoveItem?: (index: number) => void; + /** + */ + disabled?: boolean; +} + +/** + */ +function RowManipulator(props: IRowManipulatorProps) { + const { data, disabled, onRenderItem, onAddItem, onRemoveItem } = props; + + /** + * Renders the buttons at the end of each row. + */ + const renderButtons = (rowIndex: number) => { + const last = rowIndex !== data.length - 1; + return ( + + + + + + ); + }; + + /** + * Renders a single row. + */ + const renderRow = (item: T, rowIndex: number) => { + return ( +
+
{onRenderItem(item, rowIndex)}
+ {renderButtons(rowIndex)} +
+ ); + }; + + /** + */ + useEffect(() => { + if (!data || data.length === 0) { + onAddItem?.(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data]); + + return {data.map(renderRow)}; +} + +export default RowManipulator; diff --git a/packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.style.ts b/packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.style.ts new file mode 100644 index 00000000..b48a96d1 --- /dev/null +++ b/packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.style.ts @@ -0,0 +1,58 @@ +import styled from "styled-components"; + +/** + * Main style container. + */ +export const Container = styled.div` + display: flex; + flex-direction: column; + border: 1px solid ${(props) => props.theme.fieldsetBorder}; + border-radius: 5px; + overflow: hidden; + + .cell { + white-space: nowrap; + min-height: 35px; + display: flex; + align-items: center; + margin-right: 7px; + flex: 1; + } +`; + +/** + */ +export const Body = styled.div` + overflow: auto; + padding: 7px; +`; + +/** + * The header style. + */ +export const Header = styled.div` + background: ${(props) => props.theme.tableHeader}; + + .slide-header { + /* this div will align the cells horizontally */ + display: flex; + align-items: center; + + > .offset { + background: red; + display: flex; + flex: none; + width: 81px; + } + } + + .cell { + font-weight: 500; + padding-top: 7px; + padding-bottom: 7px; + } + + .cell:first-child { + margin-left: 7px; + } +`; diff --git a/packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.tsx b/packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.tsx new file mode 100644 index 00000000..e694c3de --- /dev/null +++ b/packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.tsx @@ -0,0 +1,114 @@ +import React, { UIEvent, useRef } from "react"; +import RowManipulator from "../RowManipulator/RowManipulator"; +import TooltipText from "../TooltipText/TooltipText"; +import { IRowManipulatorTableColumn } from "./RowManipulatorTable.types"; +import * as Style from "./RowManipulatorTable.style"; + +/** + * Props. + */ +interface IRowManipulatorTableProps { + /** + * Columns for the table. + */ + columns: IRowManipulatorTableColumn[]; + /** + * The highlight color for when the user hovers an item. + */ + highlightColor?: string; + /** + * Data to be rendered in this component. + */ + data: T[]; + /** + * Called when the user presses the add button. + */ + onAddItem?: () => void; + /** + * Called when the user presses the remove button to remove a specific row. + */ + onRemoveItem?: (index: number) => void; + /** + */ + disabled?: boolean; +} + +/** + */ +function RowManipulatorTable(props: IRowManipulatorTableProps) { + const { columns, disabled, onAddItem, onRemoveItem } = props; + const data = props.data || []; + const refHeader = useRef(null); + + /** + * Renders a single header cell. + */ + const renderHeaderCell = (column: IRowManipulatorTableColumn) => { + const flex = column.flex || "1"; + const width = column.width || "auto"; + return ( +
+ {column.label} +
+ ); + }; + + /** + * Renders a single body/row cell. + */ + const renderRowCell = (item: T, column: IRowManipulatorTableColumn, rowIndex: number) => { + const flex = column.flex || "1"; + const width = column.width || "auto"; + return ( +
+ {column.onRender(item, rowIndex)} +
+ ); + }; + + /** + * Renders a single row. + */ + const renderRow = (item: T, rowIndex: number) => { + return ( + + {props.columns.map((column) => renderRowCell(item, column, rowIndex))} + + ); + }; + + /** + * Called when the body gets scrolled. + * We use this to scroll the header accordingly by the same amount in order for it to stay + * horizontally aligned with the cells of the row. + */ + const onBodyScroll = (e: UIEvent) => { + if (refHeader.current) { + const visibleTableStyle = refHeader.current.style; + visibleTableStyle.transform = `translateX(-${(e.target as HTMLDivElement).scrollLeft}px)`; + } + }; + + return ( + + +
+ {columns.map(renderHeaderCell)} +
+
+ + + + + + + ); +} + +export default RowManipulatorTable; diff --git a/packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.types.ts b/packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.types.ts new file mode 100644 index 00000000..021bc620 --- /dev/null +++ b/packages/tcore-console/src/Components/RowManipulatorTable/RowManipulatorTable.types.ts @@ -0,0 +1,27 @@ +import { ReactNode } from "react"; + +/** + * A single column in a row manipulator table. + */ +export interface IRowManipulatorTableColumn { + /** + * Label of the column. This is what will appear above the filter in the header. + */ + label: string; + /** + * The amount of flex of this column. + */ + flex?: string; + /** + * If flex = `none` then this will specify the desired width for the column. + */ + width?: string; + /** + * Optional tooltip for explanation. + */ + tooltip?: string; + /** + * Called for every cell in the body. This should return the content of the cell. + */ + onRender: (item: T, rowIndex: number) => ReactNode; +} diff --git a/packages/tcore-console/src/Components/Select/Select.style.ts b/packages/tcore-console/src/Components/Select/Select.style.ts new file mode 100644 index 00000000..5fb363b5 --- /dev/null +++ b/packages/tcore-console/src/Components/Select/Select.style.ts @@ -0,0 +1,9 @@ +import styled from "styled-components"; +import FormControlStyles from "../Styles/FormControlStyles"; + +export const Container = styled.select` + ${FormControlStyles} + padding: 0px 12px; +`; + +export const Option = styled.option``; diff --git a/packages/tcore-console/src/Components/Select/Select.test.tsx b/packages/tcore-console/src/Components/Select/Select.test.tsx new file mode 100644 index 00000000..ea1511af --- /dev/null +++ b/packages/tcore-console/src/Components/Select/Select.test.tsx @@ -0,0 +1,22 @@ +import { render, screen } from "../../../utils/test-utils"; +import Select from "./Select"; + +describe("Select", () => { + it("renders without crashing", async () => { + const fn = () => render( + ); + const options = await screen.findAllByRole("option"); + expect(options).toHaveLength(2); + }); +}); diff --git a/packages/tcore-console/src/Components/Select/Select.tsx b/packages/tcore-console/src/Components/Select/Select.tsx new file mode 100644 index 00000000..a526b5c9 --- /dev/null +++ b/packages/tcore-console/src/Components/Select/Select.tsx @@ -0,0 +1,68 @@ +import { SelectHTMLAttributes } from "react"; +import ErrorMessage from "../ErrorMessage/ErrorMessage"; +import * as Style from "./Select.style"; + +/** + * A Single option. + */ +interface IOption { + /** + * Inner value of the option. + */ + value: string; + /** + * Visual text for the option. + */ + label: string; + /** + * The option will not be able to be selected. + */ + disabled?: boolean; +} + +/** + * Props. + */ +interface ISelectProps extends SelectHTMLAttributes { + /** + * Each one of these options will become a `
` tag with a functional link. + */ + onGetRowLink?: (item: T) => string | null | undefined; + /** + * Icon to be rendered in the empty message. + */ + emptyMessageIcon?: EIcon; + /** + * Message to be rendered when there are no records in the table. + */ + emptyMessage?: string; +} + +/** + */ +function SimpleTable(props: ISimpleTableProps) { + const { + columns, + useAlternateRowColor, + highlightColor, + onGetRowLink, + emptyMessageIcon, + emptyMessage, + } = props; + const data = props.data || []; + const refHeader = useRef(null); + + /** + * Renders a single header cell. + */ + const renderHeaderCell = (column: ISimpleTableColumn) => { + const flex = column.flex || "1"; + const width = column.width || "auto"; + const key = column.key || String(column.label); + return ( +
+ {column.label} +
+ ); + }; + + /** + * Renders a single body/row cell. + */ + const renderRowCell = (item: T, column: ISimpleTableColumn, rowIndex: number) => { + const flex = column.flex || "1"; + const width = column.width || "auto"; + const key = column.key || String(column.label); + return ( +
+ {column.onRender(item, rowIndex)} +
+ ); + }; + + /** + * Renders a single row. + */ + const renderRow = (item: T, rowIndex: number) => { + const link = onGetRowLink?.(item) as string; + + if (link) { + return ( + + {props.columns.map((column) => renderRowCell(item, column, rowIndex))} + + ); + } else { + return ( + + {props.columns.map((column) => renderRowCell(item, column, rowIndex))} + + ); + } + }; + + /** + * Renders the empty message in the center of the table if there are no records in it. + */ + const renderEmptyMessage = () => { + if (!emptyMessage) { + return null; + } + return ; + }; + + /** + * Called when the body gets scrolled. + * We use this to scroll the header accordingly by the same amount in order for it to stay + * horizontally aligned with the cells of the row. + */ + const onBodyScroll = (e: UIEvent) => { + if (refHeader.current) { + const visibleTableStyle = refHeader.current.style; + visibleTableStyle.transform = `translateX(-${(e.target as HTMLDivElement).scrollLeft}px)`; + } + }; + + return ( + + +
+ {columns.map(renderHeaderCell)} +
+
+ + + {data?.length === 0 ? renderEmptyMessage() : data.map(renderRow)} + +
+ ); +} + +export default SimpleTable; diff --git a/packages/tcore-console/src/Components/SimpleTable/SimpleTable.types.ts b/packages/tcore-console/src/Components/SimpleTable/SimpleTable.types.ts new file mode 100644 index 00000000..d3c8e422 --- /dev/null +++ b/packages/tcore-console/src/Components/SimpleTable/SimpleTable.types.ts @@ -0,0 +1,27 @@ +import { ReactNode } from "react"; + +/** + * A single column in a simple table. + */ +export interface ISimpleTableColumn { + /** + * Optional key for the column. If this is not informed, the label will be used. + */ + key?: string; + /** + * Label of the column.. + */ + label: ReactNode; + /** + * The amount of flex of this column. + */ + flex?: string; + /** + * If flex = `none` then this will specify the desired width for the column. + */ + width?: number; + /** + * Called for every cell in the body. This should return the content of the cell. + */ + onRender: (item: T, rowIndex: number) => ReactNode; +} diff --git a/packages/tcore-console/src/Components/Styles/FormControlStyles.ts b/packages/tcore-console/src/Components/Styles/FormControlStyles.ts new file mode 100644 index 00000000..a6bfb89e --- /dev/null +++ b/packages/tcore-console/src/Components/Styles/FormControlStyles.ts @@ -0,0 +1,55 @@ +import { css } from "styled-components"; + +export default css<{ disabled?: boolean; error?: boolean; readOnly?: boolean }>` + outline-style: none; + box-shadow: none; + width: 100%; + display: block; + padding: 8px 12px; + line-height: 1.25; + margin: 0; + border-width: 1px; + border-style: solid; + border-color: rgba(0, 0, 0, 0.1); + transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s; + border-radius: 3px; + color: ${(props) => props.theme.formControlFont}; + background-color: ${(props) => (props.theme as any).formControlBackground}; + height: 33px; + + :focus { + /* applied when the element is focused */ + z-index: 1; + position: relative; + border-color: ${(props) => !props.error && (props.theme as any).formControlFocus}; + } + + ::-moz-focus-inner { + /* disables firefox's default focus color */ + border: 0; + } + + :disabled { + /* applied when the element is disabled */ + pointer-events: none; + border-color: transparent; + background-color: ${(props) => props.theme.formControlDisabled}; + color: ${(props) => (props.theme as any).formControlDisabledFont}; + } + + ${(props) => + props.readOnly && + css` + border-color: transparent; + background-color: ${props.theme.formControlDisabled}; + color: ${(props.theme as any).formControlDisabledFont}; + `} + + ${(props) => + props.error && + css` + border-color: ${props.theme.buttonDanger}; + z-index: 1; + position: relative; + `} +`; diff --git a/packages/tcore-console/src/Components/Styles/GlobalStyles.ts b/packages/tcore-console/src/Components/Styles/GlobalStyles.ts new file mode 100644 index 00000000..390e8aa8 --- /dev/null +++ b/packages/tcore-console/src/Components/Styles/GlobalStyles.ts @@ -0,0 +1,74 @@ +import { createGlobalStyle } from "styled-components"; +import { fonts } from "../../theme"; +import * as IconStyle from "../Icon/Icon.style"; + +/** + * Global styles for the application. Everything here will be applied + * to all the corresponding elements. + */ +const GlobalStyles = createGlobalStyle` + html, + body { + padding: 0; + margin: 0; + height: 100%; + width: 100%; + background: ${(props) => props.theme.background3} + } + + pre { + font-family: Monospace; + } + + fieldset { + border: 1px solid ${(props) => props.theme.fieldsetBorder}; + border-radius: 3px; + padding: 0px 10px; + padding-top: 1rem; + background: rgba(0, 0, 0, 0.02); + + legend { + font-weight: 500; + display: flex; + align-items: center; + + ${IconStyle.Container} { + margin-right: 7px; + } + } + } + + ::-webkit-scrollbar-thumb { + border-radius: 10px; + background-color: hsl(0, 0%, 76%); + } + + ::-webkit-scrollbar { + background: transparent; + width: 8px; + height: 8px; + } + + body, * { + font-family: ${fonts.fontFamily}; + color: ${(props) => props.theme.font}; + font-size: 0.88rem; + box-sizing: border-box; + } + + h1, h2, h3, h4, h5, h6 { + margin: 0; + } + + #root { + height: 100%; + width: 100%; + } + + a { + color: inherit; + text-decoration: none !important; + } +`; + +export default GlobalStyles; diff --git a/packages/tcore-console/src/Components/Switch/Switch.style.tsx b/packages/tcore-console/src/Components/Switch/Switch.style.tsx new file mode 100644 index 00000000..8a40c294 --- /dev/null +++ b/packages/tcore-console/src/Components/Switch/Switch.style.tsx @@ -0,0 +1,102 @@ +import styled, { css } from "styled-components"; +import { fonts } from "../../theme"; +import { ESwitchSize } from "./Switch.types"; + +/** + * Main style. + */ +export const Container = styled.div<{ stretch?: boolean }>` + display: inline-flex; + align-items: center; + cursor: pointer; + + .text { + margin-right: 5px; + } + + ${(props) => + // stretch to fill remaining size + props.stretch && + css` + display: flex; + flex: 1; + + > span { + flex: 1; + } + `} +`; + +/** + * This is rectangle that contains the slider and the text. + */ +export const Rectangle = styled.button<{ + selected?: boolean; + size?: ESwitchSize; + selectedColor?: string; + unselectedColor?: string; +}>` + height: ${(props) => (props.size === ESwitchSize.big ? 33 : 20)}px; + width: ${(props) => (props.size === ESwitchSize.big ? 105 : 45)}px; + position: relative; + border-radius: 3px; + border: 0; + padding: 0px; + transition: 0.2s; + text-align: left; + cursor: pointer; + display: flex; + align-items: center; + background: ${(props) => (props.selected ? props.selectedColor : props.unselectedColor)}; + + :disabled { + pointer-events: none; + opacity: 0.7; + color: inherit; + } +`; + +/** + * The little ball that goes from left to right + */ +export const Slider = styled.span<{ selected: boolean }>` + line-height: 1.5rem; + text-align: center; + position: absolute; + top: 3px; + left: ${(props) => (props.selected ? `calc(100% - 33% - 3px)` : "3px")}; + right: 0; + bottom: 0; + background-color: white; + transition: 0.4s; + border-radius: 3px; + height: calc(100% - 6px); + width: 33%; +`; + +/** + * The inner text in the middle of the switch. + */ +export const InnerText = styled.span<{ selected?: boolean }>` + vertical-align: initial; + white-space: nowrap; + font-weight: bold; + overflow: hidden; + text-overflow: ellipsis; + font-size: ${fonts.default}; + position: relative; + transition: transform 0.15s, left 0.25s; + color: white; + display: inline-block; + + ${(props) => + props.selected + ? css` + left: 9px; + transform: translate(0%, 0); + ` + : css` + left: calc(100% - 9px); + transform: translate(-100%, 0); + `} +`; diff --git a/packages/tcore-console/src/Components/Switch/Switch.test.tsx b/packages/tcore-console/src/Components/Switch/Switch.test.tsx new file mode 100644 index 00000000..073baa8d --- /dev/null +++ b/packages/tcore-console/src/Components/Switch/Switch.test.tsx @@ -0,0 +1,46 @@ +import { fireEvent, render, screen } from "../../../utils/test-utils"; +import Switch from "./Switch"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("uses `✓` by default as selected text", () => { + render(); + expect(screen.getByText("✓")).toBeInTheDocument(); +}); + +test("uses `✓` by default as unselected text", () => { + render(); + expect(screen.getByText("✕")).toBeInTheDocument(); +}); + +test("respects `selectedText` prop", () => { + render(); + expect(screen.getByText("On")).toBeInTheDocument(); +}); + +test("respects `unselectedText` prop", () => { + render(); + expect(screen.getByText("Off")).toBeInTheDocument(); +}); + +test("calls onChange", () => { + const onChange = jest.fn(); + const { container } = render(); + fireEvent.click(container.firstChild as HTMLElement); + expect(onChange).toHaveBeenLastCalledWith(true); +}); + +test("doesn't call onChange if it's undefined", () => { + const onChange = jest.fn(); + const { container } = render(); + fireEvent.click(container.firstChild as HTMLElement); + expect(onChange).not.toHaveBeenCalled(); +}); + +test("renders children", () => { + render(Hello world); + expect(screen.getByText("Hello world")).toBeInTheDocument(); +}); diff --git a/packages/tcore-console/src/Components/Switch/Switch.tsx b/packages/tcore-console/src/Components/Switch/Switch.tsx new file mode 100644 index 00000000..eaa9d1cc --- /dev/null +++ b/packages/tcore-console/src/Components/Switch/Switch.tsx @@ -0,0 +1,87 @@ +import { ReactNode, memo } from "react"; +import { ESwitchSize } from "./Switch.types"; +import * as Style from "./Switch.style"; + +/** + * Props. + */ +interface ISwitchProps { + /** + * Indicates if the switch is selected or not. + */ + value?: boolean; + /** + * Called when the user clicks on the switch. + * This will its value by sending the new value as the first parameter. + */ + onChange?: (newValue: boolean) => void; + /** + * Optional text/content that appears on the left-side of the switch. + */ + children?: ReactNode; + /** + * If set to `true` the switch will be slightly faded-out and the user will + * not be able to change its value. + */ + disabled?: boolean; + /** + * If set to `true` the switch will get a `flex: 1` style and stretch + * to fill the remaining size of the parent. + */ + stretch?: boolean; + /** + * Optional text to be rendered inside of the switch when it is selected. + * By default this value is equal to `✓`. + */ + selectedText?: string; + /** + * Optional text to be rendered inside of the switch when it is unselected. + * By default this value is equal to `✕`. + */ + unselectedText?: string; + /** + */ + selectedColor?: string; + /** + */ + unselectedColor?: string; + /** + * Optional parameter to control the size of the switch. + */ + size?: ESwitchSize; +} + +/** + * This component is like a checkbox, but instead of a `checked`/`unchecked` state + * it displays a `on`/`off` state. + */ +function Switch(props: ISwitchProps) { + const selected = props.value || false; + const selectedText = props.selectedText || "✓"; + const unselectedText = props.unselectedText || "✕"; + + const selectedColor = props.selectedColor || "green"; + const unselectedColor = props.unselectedColor || "red"; + + const { size, onChange } = props; + const icon = selected ? selectedText : unselectedText; + + return ( + onChange?.(!selected)}> + {props.children && {props.children}} + + + + {icon} + + + ); +} + +export default memo(Switch); diff --git a/packages/tcore-console/src/Components/Switch/Switch.types.ts b/packages/tcore-console/src/Components/Switch/Switch.types.ts new file mode 100644 index 00000000..63ba0af3 --- /dev/null +++ b/packages/tcore-console/src/Components/Switch/Switch.types.ts @@ -0,0 +1,7 @@ +/** + * Types of sizes available. + */ +export enum ESwitchSize { + default = 1, + big = 2, +} diff --git a/packages/tcore-console/src/Components/Tabs/Tabs.style.ts b/packages/tcore-console/src/Components/Tabs/Tabs.style.ts new file mode 100644 index 00000000..92b6ac25 --- /dev/null +++ b/packages/tcore-console/src/Components/Tabs/Tabs.style.ts @@ -0,0 +1,81 @@ +import styled, { css } from "styled-components"; + +/** + * Main style of the component. + */ +export const Container = styled.div<{ $loading?: boolean }>` + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; + + > .content { + /* container of the content */ + flex: 1; + padding: 15px; + overflow: auto; + min-height: 0; + background: ${(props) => props.theme.background1}; + display: flex; + flex-direction: column; + transition: opacity 0.3s; + opacity: ${(props) => (props.$loading ? 0.5 : 1)}; + } +`; + +/** + * A single tab's title. + */ +export const TabTitle = styled.div<{ + highlightColor?: string; + selected?: boolean; +}>` + cursor: ${(props) => (props.selected ? "default" : "pointer")}; + position: relative; + padding: 8px 25px; + margin-left: 0; + white-space: nowrap; + min-height: 40px; + background-color: transparent; + border: 1px solid transparent; + border-radius: 3px; + border-top: 3px solid transparent; /* thick border to transition when selected */ + display: inline-flex; + align-items: center; + box-shadow: none; + transition: box-shadow 0.2s; + + ${(props) => + props.selected + ? css` + /* This css will be executed when the tab is selected */ + background-color: ${props.theme.background1}; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + border-top: 2px solid ${props.highlightColor}; + border-bottom: 0px; + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); + ` + : css` + /* This css will be executed when the tab is not selected */ + :hover { + background-color: ${props.theme.tabTitleHover}; + } + :active { + background-color: ${props.theme.tabTitleActive}; + } + `}; +`; + +/** + * Main container for the tab titles. + */ +export const Titles = styled.div<{ backgroundColor?: string }>` + overflow-x: auto; + overflow-y: hidden; + height: 40px; + flex-wrap: wrap; + white-space: nowrap; + background: ${(props) => props.backgroundColor || props.theme.background2}; + display: inline-block; +`; diff --git a/packages/tcore-console/src/Components/Tabs/Tabs.tsx b/packages/tcore-console/src/Components/Tabs/Tabs.tsx new file mode 100644 index 00000000..260598f8 --- /dev/null +++ b/packages/tcore-console/src/Components/Tabs/Tabs.tsx @@ -0,0 +1,74 @@ +import { ITab } from "./Tabs.types"; +import * as Style from "./Tabs.style"; + +/** + * Props. + */ +interface ITabsProps { + /** + * The actual content information (titles + contents). + */ + data: ITab[]; + /** + * Index of the currently selected tab. + */ + index: number; + /** + * The highlight color for the borders of the titles. + */ + highlightColor?: string; + /** + * The background color for the title row. + */ + titleBackgroundColor?: string; + /** + * Called when a tab's title is pressed. + */ + onChangeIndex: (index: number) => void; + /** + * Makes the tab content faded-out, as if it's waiting for something else to load. + */ + loading?: boolean; + /** + */ + showTitles?: boolean; +} + +/** + * Shows multiple tabs. Whenever you click a tab the content changes to the tab's content. + */ +function Tabs(props: ITabsProps) { + const { data } = props; + const selectedTab = data[props.index]; + const content = selectedTab?.content || null; + + /** + * Renders a single tab's title. + */ + const renderTabTitle = (tab: ITab, index: number) => { + const selected = index === props.index; + return ( + props.onChangeIndex(index)} + key={index} + highlightColor={props.highlightColor} + selected={selected} + > + {tab.label} + + ); + }; + + return ( + + {data.length > 1 && ( + + {data.map(renderTabTitle)} + + )} +
{content}
+
+ ); +} + +export default Tabs; diff --git a/packages/tcore-console/src/Components/Tabs/Tabs.types.ts b/packages/tcore-console/src/Components/Tabs/Tabs.types.ts new file mode 100644 index 00000000..894ee799 --- /dev/null +++ b/packages/tcore-console/src/Components/Tabs/Tabs.types.ts @@ -0,0 +1,6 @@ +import { ReactNode } from "react"; + +export interface ITab { + label: ReactNode; + content: ReactNode; +} diff --git a/packages/tcore-console/src/Components/Tags/Tags.test.tsx b/packages/tcore-console/src/Components/Tags/Tags.test.tsx new file mode 100644 index 00000000..97d3dd3b --- /dev/null +++ b/packages/tcore-console/src/Components/Tags/Tags.test.tsx @@ -0,0 +1,50 @@ +import { fireEvent, render, screen } from "../../../utils/test-utils"; +import Tags from "./Tags"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); + +test("renders inputs with correct properties", async () => { + render( + + ); + const inputs = (await screen.findAllByRole("textbox")) as HTMLInputElement[]; + expect(inputs).toHaveLength(4); + expect(inputs[0].value).toEqual("city"); + expect(inputs[1].value).toEqual("Raleigh"); + + expect(inputs[2].value).toEqual("type"); + expect(inputs[3].value).toEqual("internal"); +}); + +test("calls onChange when any input change happens", async () => { + const onChange = jest.fn(); + + render(); + + const inputs = (await screen.findAllByRole("textbox")) as HTMLInputElement[]; + fireEvent.change(inputs[0], { target: { value: "state" } }); + fireEvent.change(inputs[1], { target: { value: "NC" } }); + + expect(onChange).toHaveBeenCalledWith([{ key: "state", value: "NC" }]); +}); + +test("calls onChange when the add row button is pressed", async () => { + const onChange = jest.fn(); + const emptyObject = { key: "", value: "" }; + + render(); + + const buttons = (await screen.findAllByRole("button")) as HTMLButtonElement[]; + fireEvent.click(buttons[1]); + + expect(onChange).toHaveBeenCalledWith([emptyObject, emptyObject]); +}); diff --git a/packages/tcore-console/src/Components/Tags/Tags.tsx b/packages/tcore-console/src/Components/Tags/Tags.tsx new file mode 100644 index 00000000..36ca8a90 --- /dev/null +++ b/packages/tcore-console/src/Components/Tags/Tags.tsx @@ -0,0 +1,103 @@ +import { ITag } from "@tago-io/tcore-sdk/types"; +import Input from "../Input/Input"; +import RowManipulatorTable from "../RowManipulatorTable/RowManipulatorTable"; + +/** + * Props. + */ +interface ITagsProps { + data: ITag[]; + /** + * Tags' errors. + */ + errors?: any; + /** + */ + onChange: (newData: ITag[]) => void; + /** + */ + disabled?: boolean; +} + +/** + */ +function Tags(props: ITagsProps) { + const { data, disabled, errors } = props; + + /** + */ + const onChange = (field: keyof ITag, value: string, rowIndex: number) => { + if (!data[rowIndex]) { + data[rowIndex] = { key: "", value: "" }; // create the item if it doesn't exist + } + data[rowIndex][field] = value; + props.onChange([...data]); + }; + + /** + */ + const renderKey = (item: ITag, index: number) => { + const error = errors?.[index]?.key; + return ( + onChange("key", e.target.value, index)} + placeholder="Enter the tag key (unique)" + value={item.key} + disabled={disabled} + /> + ); + }; + + /** + */ + const renderValue = (item: ITag, index: number) => { + const error = errors?.[index]?.value; + return ( + onChange("value", e.target.value, index)} + placeholder="Enter the tag value" + value={item.value} + error={error} + disabled={disabled} + /> + ); + }; + + /** + */ + const addItem = () => { + props.data.push({ key: "", value: "" }); + props.onChange([...props.data]); + }; + + /** + */ + const removeItem = (index: number) => { + props.data.splice(index, 1); + props.onChange([...props.data]); + }; + + return ( + + data={props.data} + onAddItem={addItem} + onRemoveItem={removeItem} + disabled={disabled} + columns={[ + { + label: "Key", + tooltip: "The tag identifier", + onRender: renderKey, + }, + { + label: "Value", + tooltip: "The value of the tag", + onRender: renderValue, + }, + ]} + /> + ); +} + +export default Tags; diff --git a/packages/tcore-console/src/Components/Tags/TagsTab.tsx b/packages/tcore-console/src/Components/Tags/TagsTab.tsx new file mode 100644 index 00000000..bb46e11e --- /dev/null +++ b/packages/tcore-console/src/Components/Tags/TagsTab.tsx @@ -0,0 +1,51 @@ +import { ITag } from "@tago-io/tcore-sdk/types"; +import FormDivision from "../FormDivision/FormDivision"; +import { EIcon } from "../Icon/Icon.types"; +import Tags from "./Tags"; + +/** + * Props. + */ +interface ITagsTabProps { + /** + * Name for this tab. + */ + name?: string; + /** + * The tags to be rendered. + */ + data?: ITag[]; + /** + * Tags' errors. + */ + errors?: any; + /** + * Called when a tag field has changed. + */ + onChange: (tags: ITag[]) => void; + /** + * Doesn't allow editing or adding new tags. + */ + disabled?: boolean; +} + +/** + * This is the tags tab in an edit page. + * It shows a title and the tags component below the title. + */ +function TagsTab(props: ITagsTabProps) { + const { data, disabled, errors, name } = props; + + return ( +
+ + +
+ ); +} + +export default TagsTab; diff --git a/packages/tcore-console/src/Components/Tooltip/Tooltip.style.tsx b/packages/tcore-console/src/Components/Tooltip/Tooltip.style.tsx new file mode 100644 index 00000000..9846fae4 --- /dev/null +++ b/packages/tcore-console/src/Components/Tooltip/Tooltip.style.tsx @@ -0,0 +1,85 @@ +import styled, { css } from "styled-components"; + +/** + * Main container. + */ +export const Container = styled.div<{ + zIndex?: number; + hoverable?: boolean; + vertical?: boolean; + error?: boolean; + color?: string; +}>` + position: fixed; + z-index: ${(props) => props.zIndex || 99999}; + background-color: ${(props) => props.theme.background1}; + box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.2); + border-radius: 3px; + border: 1px solid rgba(0, 0, 0, 0.15); + max-width: 350px; + display: flex; + transition: opacity 0.2s, margin 0.3s; + transition-timing-function: cubic-bezier(0.17, 0.67, 0.2, 1.37); + opacity: 0; + margin-top: 10px; + pointer-events: none; + flex-direction: ${(props) => (props.vertical ? "column" : "row")}; + + &.invisible { + opacity: 0; + margin-top: 10px; + pointer-events: none; + } + &.visible, + &:hover { + opacity: 1; + margin-top: 0px; + display: flex; + pointer-events: ${(props) => (props.hoverable ? "inherit" : "none")}; + } + + .header { + padding: 8px; + background-color: ${(props) => props.color || "rgba(0, 0, 0, 0.05)"}; + display: flex; + align-items: center; + flex: none; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + + i { + margin: 0px 4px; + } + + span { + margin-left: 3px; + } + + * { + font-size: 1rem; + font-weight: 500; + } + + ${(props) => + props.color && + css` + * { + fill: white; + } + `} + } + + .content { + position: relative; + padding: ${(props) => (props.vertical ? "8px 10px" : "8px")}; + } + + .hoverable-step { + width: 100%; + position: absolute; + left: 0px; + bottom: -10px; + height: 20px; + } +`; +Container.displayName = "TooltipContainer"; diff --git a/packages/tcore-console/src/Components/Tooltip/Tooltip.tsx b/packages/tcore-console/src/Components/Tooltip/Tooltip.tsx new file mode 100644 index 00000000..37007699 --- /dev/null +++ b/packages/tcore-console/src/Components/Tooltip/Tooltip.tsx @@ -0,0 +1,99 @@ +import { ReactNode, cloneElement, Children, useEffect, useRef } from "react"; +import { EIcon } from "../.."; +import TooltipPopup from "./TooltipPopup"; + +/** + * Props. + */ +interface ITooltipProps { + text?: ReactNode; + color?: string; + children: ReactNode; + /** + * Icon of the tooltip. + */ + icon?: EIcon | null; +} + +/** + */ +function Tooltip(props: ITooltipProps) { + const tooltipPopup = useRef(null); + const childrenRefs = useRef([]); + const { text, children } = props; + + /** + */ + const open = (e: any) => { + const el = e.target.getBoundingClientRect(); + tooltipPopup.current?.open(el.x, el.y, el.width, el.height); + e?.stopPropagation(); + }; + + /** + */ + const close = (e?: any) => { + tooltipPopup.current?.close(); + e?.stopPropagation(); + }; + + /** + */ + useEffect(() => { + const items = childrenRefs.current; + for (const item of items) { + item?.addEventListener("mouseenter", open); + item?.addEventListener("mouseleave", close); + } + + return () => { + for (const item of items) { + item?.removeEventListener("mouseenter", open); + item?.removeEventListener("mouseleave", close); + } + }; + }); + + /** + */ + useEffect(() => { + window.addEventListener("mousewheel", close); + window.addEventListener("resize", close); + window.addEventListener("touchend", close); // handles movement on mobile to close the popup + window.addEventListener("touchmove", close); // handles movement on mobile to close the popup + + return () => { + window.removeEventListener("mousewheel", close); + window.removeEventListener("resize", close); + window.removeEventListener("touchmove", close); + window.removeEventListener("touchend", close); + }; + }); + + if (!text) { + // no text for the tooltip, just render the children + return <>{children}; + } + + return ( + <> + {Children.map(children, (child, index) => + cloneElement(child as any, { + ref: (e: HTMLElement) => (childrenRefs.current[index] = e), + }) + )} + + + + ); +} + +export default Tooltip; diff --git a/packages/tcore-console/src/Components/Tooltip/TooltipPopup.tsx b/packages/tcore-console/src/Components/Tooltip/TooltipPopup.tsx new file mode 100644 index 00000000..21e36c28 --- /dev/null +++ b/packages/tcore-console/src/Components/Tooltip/TooltipPopup.tsx @@ -0,0 +1,172 @@ +import { Component } from "react"; +import { createPortal } from "react-dom"; +import Icon from "../Icon/Icon"; +import { EIcon } from "../Icon/Icon.types"; +import * as Style from "./Tooltip.style"; + +/* + * Props. + */ +interface ITooltipPopup { + align?: string; + header?: string; + icon?: EIcon; + text?: any; + color?: string; + hoverable?: boolean; + position?: string; + zIndex?: number; +} + +/** + * State. + */ +interface IState { + open: boolean; +} + +/** + * The popup for the tooltip. This is a class because we override + * the shouldComponentUpdate and it can't be overridden for state using hooks. + */ +class TooltipPopup extends Component { + public state = { + open: false, + }; + + // @ts-ignore + private ref: HTMLDivElement; + private width = 0; + private height = 0; + + /** + * We override this event because the tooltip is an extremely sensitive component + * since it's used in a ton of places in a system. We need to make sure it doesn't + * update without a purpose. + */ + public shouldComponentUpdate(nextProps: ITooltipPopup, nextState: IState) { + if (!this.state.open && !nextState.open) { + // closed, don't update + return false; + } + return ( + this.props.align !== nextProps.align || + this.props.header !== nextProps.header || + this.props.icon !== nextProps.icon || + this.props.text !== nextProps.text || + this.props.color !== nextProps.color || + this.props.hoverable !== nextProps.hoverable || + this.props.position !== nextProps.position || + this.props.zIndex !== nextProps.zIndex || + this.state.open !== nextState.open + ); + } + + /** + * Calculates the size for the tooltip. + */ + public calculateSize() { + const bounds = this.ref.getBoundingClientRect(); + this.width = bounds.width; + this.height = bounds.height; + } + + /** + * Opens the tooltip popup with the anchor data. + */ + public open(anchorX: number, anchorY: number, anchorWidth: number, anchorHeight: number) { + this.setState( + { + open: true, + }, + () => { + this.calculateSize(); + + let x = anchorX; + let y = anchorY; + + const { position, align } = this.props; + + if (align === "left") { + x = anchorX; + } else if (align === "right") { + x = anchorX + anchorWidth - this.width; + } else { + // if no valid align was informed we use the 'center' one + x = anchorX + anchorWidth / 2 - this.width / 2; + } + + if (position === "bottom") { + y = anchorY + anchorHeight + 5; + } else { + // if no valid position was informed we use the 'top' one + y = anchorY - this.height - 5; + } + + // validates x-axis bounds of screen: + if (x + this.width >= window.innerWidth) { + x = window.innerWidth - this.width - 5; + } else if (x < 0) { + x = 5; + } + // validates y-axis bounds of screen: + if (y + this.height >= window.innerHeight) { + y = window.innerHeight - this.width - 5; + } else if (y < 0) { + y = anchorY + anchorHeight + 5; + } + + this.ref.style.left = `${x}px`; + this.ref.style.top = `${y}px`; + this.ref.classList.remove("invisible"); + this.ref.classList.add("visible"); + } + ); + } + + /** + * Closes the popup. + */ + public close() { + if (this.state.open) { + this.ref.classList.remove("visible"); + this.ref.classList.add("invisible"); + } + } + + /** + * Main render function. + */ + public render() { + const { header, icon, text, zIndex, color, hoverable } = this.props; + + if (!this.state.open) { + return null; + } + + return createPortal( + ((this as any).ref = e)} + data-testid="tooltip" + > + {icon !== null && ( +
+ + {header && {header}} +
+ )} + +
{text}
+ + {hoverable &&
} + , + document.body + ); + } +} + +export default TooltipPopup; diff --git a/packages/tcore-console/src/Components/TooltipText/TooltipText.style.ts b/packages/tcore-console/src/Components/TooltipText/TooltipText.style.ts new file mode 100644 index 00000000..1361a8e2 --- /dev/null +++ b/packages/tcore-console/src/Components/TooltipText/TooltipText.style.ts @@ -0,0 +1,30 @@ +import styled, { css } from "styled-components"; + +/** + * Main style for the component. + */ +export const Container = styled.span<{ + color?: string; + bold?: boolean; + usesTooltip: boolean; +}>` + ${(props) => + props.color && + css` + color: ${props.color} !important; + border-bottom-color: ${props.color} !important; + `}; + + ${(props) => + props.bold && + css` + font-weight: ${props.bold ? "bold" : "normal"}; + `}; + + ${(props) => + props.usesTooltip && + css` + border-bottom: 1px dotted black; + margin-bottom: -1px; + `} +`; diff --git a/packages/tcore-console/src/Components/TooltipText/TooltipText.tsx b/packages/tcore-console/src/Components/TooltipText/TooltipText.tsx new file mode 100644 index 00000000..f58ce3a7 --- /dev/null +++ b/packages/tcore-console/src/Components/TooltipText/TooltipText.tsx @@ -0,0 +1,48 @@ +import { memo, ReactNode } from "react"; +import { EIcon } from "../.."; +import Tooltip from "../Tooltip/Tooltip"; +import * as Style from "./TooltipText.style"; + +/** + * Props. + */ +interface ITooltipTextProps { + /** + * Contents of the component. + */ + children: ReactNode; + /** + * Tooltip to appear when you hover over this component. + */ + tooltip?: ReactNode; + /** + * Makes the text bold. + */ + bold?: boolean; + /** + * Optional color of the text. + */ + color?: string; + /** + * Icon of the tooltip. + */ + icon?: EIcon | null; +} + +/** + * HTML span that shows a tooltip when the user hovers over this component.+ + */ +function TooltipText(props: ITooltipTextProps) { + const { icon, bold, color, tooltip, children } = props; + const usesTooltip = !!tooltip; + + return ( + + + {children} + + + ); +} + +export default memo(TooltipText); diff --git a/packages/tcore-console/src/Components/VariableCondition/VariableCondition.style.ts b/packages/tcore-console/src/Components/VariableCondition/VariableCondition.style.ts new file mode 100644 index 00000000..8052c786 --- /dev/null +++ b/packages/tcore-console/src/Components/VariableCondition/VariableCondition.style.ts @@ -0,0 +1,45 @@ +import styled from "styled-components"; + +/** + * Container of the item. + */ +export const Container = styled.div<{ error?: boolean }>` + display: flex; + align-items: center; + flex: 1; + width: 100%; + + .text { + font-size: 1.3rem; + color: ${(props) => props.theme.font2}; + font-weight: bold; + flex: none; + } + + .space { + margin: 0px 5px; + flex: none; + } + + .input-container { + flex: none; + width: 200px; + } + + .condition-container { + flex: 1; + display: flex; + + select { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + height: 33px; + margin-right: -1px; + } + + input { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + } + } +`; diff --git a/packages/tcore-console/src/Components/VariableCondition/VariableCondition.tsx b/packages/tcore-console/src/Components/VariableCondition/VariableCondition.tsx new file mode 100644 index 00000000..2f1338f5 --- /dev/null +++ b/packages/tcore-console/src/Components/VariableCondition/VariableCondition.tsx @@ -0,0 +1,106 @@ +import Input from "../Input/Input"; +import RowManipulator from "../RowManipulator/RowManipulator"; +import Select from "../Select/Select"; +import * as Style from "./VariableCondition.style"; + +/** + * Props. + */ +interface IVariableCondition { + data: any; + name?: string; + useTextInput?: string; + onChange: (data: any) => void; +} + +/** + */ +function VariableCondition(props: IVariableCondition) { + const { data, onChange } = props; + + /** + */ + const onChangeItem = (item: any, field: any, value: any) => { + item[field] = value; + onChange([...data]); + }; + + /** + */ + const addItem = () => { + data.push({}); + props.onChange([...data]); + }; + + /** + */ + const removeItem = (index: number) => { + data.splice(index, 1); + props.onChange([...data]); + }; + + /** + */ + const renderInput = (item: any) => { + return ( + onChangeItem(item, "variable", e.target.value)} + placeholder="type the variable here" + /> + ); + }; + + /** + */ + const renderCondition = (item: any) => { + return ( + <> + onChangeItem(item, "value", e.target.value)} /> + )} + + ); + }; + + /** + */ + const renderItem = (item: any) => { + return ( + <> + If +
+
{renderInput(item)}
+
+ is +
+
{renderCondition(item)}
+
+ + ); + }; + + return ( + + + + ); +} + +export default VariableCondition; diff --git a/packages/tcore-console/src/Helpers/__mocks__/useApiRequest.ts b/packages/tcore-console/src/Helpers/__mocks__/useApiRequest.ts new file mode 100644 index 00000000..79d92c12 --- /dev/null +++ b/packages/tcore-console/src/Helpers/__mocks__/useApiRequest.ts @@ -0,0 +1,11 @@ +import { useState } from "react"; + +/** + * Mock of the `useApiRequest` file. + */ +function useApiRequestMock() { + const [data] = useState([]); + return { data }; +} + +export default useApiRequestMock; diff --git a/packages/tcore-console/src/Helpers/copyToClipboard.ts b/packages/tcore-console/src/Helpers/copyToClipboard.ts new file mode 100644 index 00000000..80b128b9 --- /dev/null +++ b/packages/tcore-console/src/Helpers/copyToClipboard.ts @@ -0,0 +1,17 @@ +const copyToClipboard = (value: string) => { + return new Promise((resolve) => { + const textarea = document.createElement("textarea"); + textarea.textContent = value; + textarea.style.position = "fixed"; + document.body.appendChild(textarea); + textarea.select(); + try { + document.execCommand("copy"); + resolve(); + } finally { + document.body.removeChild(textarea); + } + }); +}; + +export default copyToClipboard; diff --git a/packages/tcore-console/src/Helpers/download.ts b/packages/tcore-console/src/Helpers/download.ts new file mode 100644 index 00000000..175c1ab4 --- /dev/null +++ b/packages/tcore-console/src/Helpers/download.ts @@ -0,0 +1,27 @@ +/** + * Mounts and downloads a file. + * @param content The content inside of the file. + * @param extension The extension of the file (.txt, .csv, etc). + * @param nameFile The name of the file, it will be mounted as `nameOfFile.extension`. + */ +function downloadFile(content: string, extension: string, nameFile: string, isBase64?: boolean) { + const isJson = extension === "json"; + const fileContent = isJson ? JSON.stringify(content) : content; + + const encodedUri = encodeURI( + `data:text/${extension};${isBase64 ? "base64" : "charset=utf-8"},${fileContent}` + ); + const link = document.createElement("a"); + + try { + link.href = encodedUri; + link.download = `${nameFile}.${extension}`; + document.body.appendChild(link); + + link.click(); + } finally { + link.remove(); + } +} + +export default downloadFile; diff --git a/packages/tcore-console/src/Helpers/findConfigField.ts b/packages/tcore-console/src/Helpers/findConfigField.ts new file mode 100644 index 00000000..5008b9df --- /dev/null +++ b/packages/tcore-console/src/Helpers/findConfigField.ts @@ -0,0 +1,19 @@ +import { IPluginConfigField } from "@tago-io/tcore-sdk/types"; +import { flattenConfigFields } from "@tago-io/tcore-shared"; + +/** + */ +function findConfigField( + configs: IPluginConfigField[], + fieldID: string +): IPluginConfigField | null { + const fields = flattenConfigFields(configs); + for (const field of fields) { + if ("field" in field && field.field === fieldID) { + return field; + } + } + return null; +} + +export default findConfigField; diff --git a/packages/tcore-console/src/Helpers/formatBytes.ts b/packages/tcore-console/src/Helpers/formatBytes.ts new file mode 100644 index 00000000..cd2a6661 --- /dev/null +++ b/packages/tcore-console/src/Helpers/formatBytes.ts @@ -0,0 +1,16 @@ +/** + * Formats the bytes into a more readable format. + */ +function formatBytes(bytes: number) { + if (bytes === 0) { + return "0 B"; + } + + const k = 1024; + const dm = 2; + const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`; +} + +export default formatBytes; diff --git a/packages/tcore-console/src/Helpers/formatDataAmount.ts b/packages/tcore-console/src/Helpers/formatDataAmount.ts new file mode 100644 index 00000000..b923ff4b --- /dev/null +++ b/packages/tcore-console/src/Helpers/formatDataAmount.ts @@ -0,0 +1,21 @@ +const BUCKET_DATA_AMOUNT_PRECISION_THRESHOLD = 1_000; + +/** + * Format a bucket's data amount number into a shorter format when it's over 1,000. + * + * The shorter format should include K for thousands, M for millions, B for billions, + * and T for trillions. See tests for more information if the implementation needs changes. + * + * @param amount Amount to format. + * + * @returns Amount formatted as a compact string. + */ +function formatDataAmount(amount: number): string { + if (amount > BUCKET_DATA_AMOUNT_PRECISION_THRESHOLD) { + const formatter = new Intl.NumberFormat("en-US", { notation: "compact" }); + return `~${formatter.format(amount)}`; + } + return String(amount); +} + +export { formatDataAmount }; diff --git a/packages/tcore-console/src/Helpers/getDateTimeObject.ts b/packages/tcore-console/src/Helpers/getDateTimeObject.ts new file mode 100644 index 00000000..c5146792 --- /dev/null +++ b/packages/tcore-console/src/Helpers/getDateTimeObject.ts @@ -0,0 +1,20 @@ +import { DateTime } from "luxon"; + +/** + * Gets the `luxon` DateTime object from an input. + */ +function getDateTimeObject(value?: Date | string | number | null): DateTime | null { + if (!value) { + return null; + } + if (value instanceof Date) { + return DateTime.fromJSDate(value); + } else if (typeof value === "string") { + return DateTime.fromISO(value); + } else if (typeof value === "number") { + return DateTime.fromMillis(value); + } + return null; +} + +export default getDateTimeObject; diff --git a/packages/tcore-console/src/Helpers/getDeviceTypeName.ts b/packages/tcore-console/src/Helpers/getDeviceTypeName.ts new file mode 100644 index 00000000..5c475cd7 --- /dev/null +++ b/packages/tcore-console/src/Helpers/getDeviceTypeName.ts @@ -0,0 +1,14 @@ +import { TDeviceType } from "@tago-io/tcore-sdk/types"; + +/** + * Returns the `pretty` name of the type of the bucket. + */ +function getDeviceTypeName(type?: TDeviceType | null) { + if (type === "mutable") { + return "Managed Data Optimized (Mutable)"; + } else { + return "Device Data Optimized (Immutable)"; + } +} + +export default getDeviceTypeName; diff --git a/packages/tcore-console/src/Helpers/isConfigFieldVisible.ts b/packages/tcore-console/src/Helpers/isConfigFieldVisible.ts new file mode 100644 index 00000000..f007743c --- /dev/null +++ b/packages/tcore-console/src/Helpers/isConfigFieldVisible.ts @@ -0,0 +1,82 @@ +import { IPluginConfigField } from "@tago-io/tcore-sdk/types"; +import findConfigField from "./findConfigField"; +import isNumber from "./isNumber"; + +/** + */ +function isConfigFieldVisible( + rootConfigs: IPluginConfigField[], + fieldToCheck: IPluginConfigField, + values: any +) { + const conditions = fieldToCheck.visibility_conditions || []; + if (conditions.length === 0) { + return true; + } + + for (const data of conditions) { + const { value, valueTwo, condition } = data; + + if (condition === "*") { + // any condition matches, just exit to save time + return true; + } + + const field = findConfigField(rootConfigs, data.field); + if (!field) { + // field not found, exit to save time + continue; + } + + const fieldValue = values[data.field]; + const fieldValueParsed = isNumber(fieldValue) ? parseFloat(fieldValue) : String(fieldValue); + const fieldValueArray = [fieldValue].flat(); + + const valueCondition = isNumber(value) ? parseFloat(value) : String(value); + const valueConditionTwo = isNumber(valueTwo) ? parseFloat(valueTwo) : String(valueTwo); + + if (condition === "<" && fieldValueParsed < valueCondition) { + return true; + } else if (condition === ">" && fieldValueParsed > valueCondition) { + return true; + } else if (condition === "=") { + if (field.type === "string-list") { + return fieldValueArray.some((x) => x === valueCondition); + } + if (field.type === "select-key-select-value") { + return fieldValueArray.some((x) => x.value === valueCondition); + } + if (fieldValueParsed === valueCondition) { + return true; + } + } else if (condition === "!") { + if (field.type === "string-list") { + return !fieldValueArray.some((x) => x === valueCondition); + } + if (field.type === "select-key-select-value") { + return !fieldValueArray.some((x) => x.value === valueCondition); + } + if (fieldValueParsed !== valueCondition) { + return true; + } + } else if (condition === "ne") { + if (field.type === "string-list") { + return fieldValueArray.length > 0; + } + if (field.type === "select-key-select-value") { + return fieldValueArray.length > 0; + } + if (String(fieldValue || "").trim()) { + return true; + } + } else if (condition === "><") { + if (fieldValueParsed >= valueCondition && fieldValueParsed <= valueConditionTwo) { + return true; + } + } + } + + return false; +} + +export default isConfigFieldVisible; diff --git a/packages/tcore-console/src/Helpers/isNumber.ts b/packages/tcore-console/src/Helpers/isNumber.ts new file mode 100644 index 00000000..af3020c0 --- /dev/null +++ b/packages/tcore-console/src/Helpers/isNumber.ts @@ -0,0 +1,11 @@ +/** + */ +function isNumber(s: any) { + const str = ("" + s).trim(); + if (str.length === 0) { + return false; + } + return !isNaN(+str); +} + +export default isNumber; diff --git a/packages/tcore-console/src/Helpers/localStorage.ts b/packages/tcore-console/src/Helpers/localStorage.ts new file mode 100644 index 00000000..b48df623 --- /dev/null +++ b/packages/tcore-console/src/Helpers/localStorage.ts @@ -0,0 +1,82 @@ +/** + * Sets a key in local storage. + */ +export function setLocalStorage(key: string, value: string) { + try { + localStorage.setItem(key, value); + } catch (ex) { + // ie11 doesn't support it sometimes. + } +} + +/** + * Gets a key in local storage. + */ +export function getLocalStorage(key: string, fallback?: string) { + try { + const value = localStorage.getItem(key); + return value || fallback; + } catch (ex) { + // ie11 doesn't support it sometimes. + return fallback; + } +} + +/** + * Gets a key in local storage as a boolean. + */ +export function getLocalStorageAsBoolean(key: string, fallback = false): boolean { + try { + const value = localStorage.getItem(key); + if (value === "false") { + return false; + } else if (value === "true") { + return true; + } + return fallback as boolean; + } catch (ex) { + // ie11 doesn't support it sometimes. + return fallback as boolean; + } +} + +/** + * Gets a key in local storage as a JSON. + */ +export function getLocalStorageAsJSON(key: string) { + try { + const value = localStorage.getItem(key); + return JSON.parse(value as string) || {}; + } catch (ex) { + // ie11 doesn't support it sometimes. + return {}; + } +} + +/** + * Gets a key in local storage as an array. + */ +export function getLocalStorageAsArray(key: string) { + try { + const value = localStorage.getItem(key); + const response = JSON.parse(value as string) || []; + if (Array.isArray(response)) { + return response; + } + return []; + } catch (ex) { + // ie11 doesn't support it sometimes. + return []; + } +} + +/** + * Sets a key in local storage as a JSON. + */ +export function setLocalStorageAsJSON(key: string, json: object) { + try { + localStorage.setItem(key, JSON.stringify(json)); + } catch (ex) { + // ie11 doesn't support it sometimes. + } +} diff --git a/packages/tcore-console/src/Helpers/normalizeTags.ts b/packages/tcore-console/src/Helpers/normalizeTags.ts new file mode 100644 index 00000000..3edf4a0d --- /dev/null +++ b/packages/tcore-console/src/Helpers/normalizeTags.ts @@ -0,0 +1,25 @@ +import { ITag } from "@tago-io/tcore-sdk/types"; + +/** + * Normalizes the tags array to return a consistent output free of small errors. + */ +function normalizeTags(params: ITag[]) { + if (!params) { + return []; + } + + if (params.length === 1) { + if (!params[0].key && !params[0].value) { + return []; + } + } + + const normalized = params.map((x) => ({ + key: x.key, + value: x.value, + })); + + return normalized; +} + +export default normalizeTags; diff --git a/packages/tcore-console/src/Helpers/removeEmptyKeys.ts b/packages/tcore-console/src/Helpers/removeEmptyKeys.ts new file mode 100644 index 00000000..d19d82b0 --- /dev/null +++ b/packages/tcore-console/src/Helpers/removeEmptyKeys.ts @@ -0,0 +1,9 @@ +function removeEmptyKeys(obj: any): any { + return Object.fromEntries( + Object.entries(obj) + .filter(([_, v]) => v !== "") + .map(([k, v]) => [k, v === Object(v) ? removeEmptyKeys(v) : v]) + ); +} + +export default removeEmptyKeys; diff --git a/packages/tcore-console/src/Helpers/setDocumentTitle.ts b/packages/tcore-console/src/Helpers/setDocumentTitle.ts new file mode 100644 index 00000000..b762c06f --- /dev/null +++ b/packages/tcore-console/src/Helpers/setDocumentTitle.ts @@ -0,0 +1,10 @@ +/** + * Sets the document.title with a prefix. + */ +function setDocumentTitle(title: string) { + if (title) { + document.title = `${title} | TCore`; + } +} + +export default setDocumentTitle; diff --git a/packages/tcore-console/src/Helpers/useApiRequest.ts b/packages/tcore-console/src/Helpers/useApiRequest.ts new file mode 100644 index 00000000..6afbdc9e --- /dev/null +++ b/packages/tcore-console/src/Helpers/useApiRequest.ts @@ -0,0 +1,29 @@ +import axios from "axios"; +import useSWR from "swr"; + +const fetcher = async (url: string) => { + return axios.get(url).then((r) => r.data); +}; + +/** + * Custom hook implementing an API request. + */ +function useApiRequest(url: string): { + data: T; + error?: Error; + revalidate: any; + mutate: any; +} { + const { data, error, revalidate, mutate } = useSWR(url, fetcher, { + revalidateOnFocus: false, + revalidateOnReconnect: false, + }); + + if ((data as any)?.result !== undefined) { + return { data: (data as any).result, error, revalidate, mutate }; + } else { + return { data: data as T, error, revalidate, mutate }; + } +} + +export default useApiRequest; diff --git a/packages/tcore-console/src/Helpers/useDarkMode.ts b/packages/tcore-console/src/Helpers/useDarkMode.ts new file mode 100644 index 00000000..fc2a3e01 --- /dev/null +++ b/packages/tcore-console/src/Helpers/useDarkMode.ts @@ -0,0 +1,29 @@ +import { useState } from "react"; + +/** + * Custom hook implementing dark mode. + */ +const useDarkMode = () => { + const [theme, setTheme] = useState(() => "light"); + + /** + */ + const setMode = (mode: string) => { + window.localStorage.setItem("theme", mode); + setTheme(mode); + }; + + /** + */ + const themeToggler = () => { + if (theme === "light") { + setMode("dark"); + } else { + setMode("light"); + } + }; + + return [theme, themeToggler]; +}; + +export default useDarkMode; diff --git a/packages/tcore-console/src/Helpers/useForceUpdate.ts b/packages/tcore-console/src/Helpers/useForceUpdate.ts new file mode 100644 index 00000000..2399ff0f --- /dev/null +++ b/packages/tcore-console/src/Helpers/useForceUpdate.ts @@ -0,0 +1,11 @@ +import { useState, useCallback } from "react"; + +export function useForceUpdate() { + const [, setTick] = useState(0); + + const update = useCallback(() => { + setTick((tick) => tick + 1); + }, []); + + return update; +} diff --git a/packages/tcore-console/src/Helpers/validateConfigFields.ts b/packages/tcore-console/src/Helpers/validateConfigFields.ts new file mode 100644 index 00000000..85c22f57 --- /dev/null +++ b/packages/tcore-console/src/Helpers/validateConfigFields.ts @@ -0,0 +1,64 @@ +import { IPluginConfigField } from "@tago-io/tcore-sdk/types"; +import isConfigFieldVisible from "./isConfigFieldVisible"; +import validateStringField from "./validateStringField"; +import validateStringListField from "./validateStringListField"; + +/** + * Helper to validate all the config fields of a plugin and + * return all the errors of the required fields. + */ +function validateConfigFields(configs: IPluginConfigField[], values: any, errors: any = {}) { + let hasError = false; + + for (const field of configs) { + const visible = isConfigFieldVisible(configs, field, values); + if (!visible) { + continue; + } + + if ("required" in field && field.required) { + const value = values[field.field]; + let error = null; + + if (field.type === "string-list") { + error = validateStringListField(field, value); + } else if (field.type === "select-key-select-value") { + error = value.map((x: any) => ({ key: !x?.key, value: !x?.value })); + error = error.find((x: any) => x.key || x.value) ? error : null; + } else { + error = validateStringField(field, value); + } + + if (error) { + hasError = true; + errors[field.field] = error; + } + } + + if ("options" in field && field.options) { + // radio has options, each option has configs + for (const option of field.options) { + if ("configs" in option && option.configs) { + const newErrors = validateConfigFields(option.configs, values); + if (newErrors) { + hasError = true; + errors = newErrors; + } + } + } + } + + if ("configs" in field && field.configs) { + // row, group, and other fields have a `configs` option + const newErrors = validateConfigFields(field.configs, values); + if (newErrors) { + hasError = true; + errors = newErrors; + } + } + } + + return hasError ? errors : null; +} + +export default validateConfigFields; diff --git a/packages/tcore-console/src/Helpers/validateStringField.ts b/packages/tcore-console/src/Helpers/validateStringField.ts new file mode 100644 index 00000000..f63f5109 --- /dev/null +++ b/packages/tcore-console/src/Helpers/validateStringField.ts @@ -0,0 +1,10 @@ +import { IPluginConfigField } from "@tago-io/tcore-sdk/types"; + +/** + * Validates a `string` plugin field. + */ +function validateStringField(field: IPluginConfigField, value: string) { + return !value || !String(value).trim(); +} + +export default validateStringField; diff --git a/packages/tcore-console/src/Helpers/validateStringListField.ts b/packages/tcore-console/src/Helpers/validateStringListField.ts new file mode 100644 index 00000000..17ec1384 --- /dev/null +++ b/packages/tcore-console/src/Helpers/validateStringListField.ts @@ -0,0 +1,15 @@ +import { IPluginConfigField } from "@tago-io/tcore-sdk/types"; + +/** + * Validates a `string-list` plugin field. + */ +function validateStringListField(field: IPluginConfigField, value: string[]) { + if (!value) { + return [true]; + } + const listErrors = value.map((item) => !item); + const hasError = listErrors.some((x) => x === true); + return hasError ? listErrors : null; +} + +export default validateStringListField; diff --git a/packages/tcore-console/src/Requests/createAction/createAction.ts b/packages/tcore-console/src/Requests/createAction/createAction.ts new file mode 100644 index 00000000..cc91730e --- /dev/null +++ b/packages/tcore-console/src/Requests/createAction/createAction.ts @@ -0,0 +1,12 @@ +import { IActionCreate, TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function createAction(action: Omit): Promise { + const response = await axios.post("/action", action); + const { data } = response; + return data.result; +} + +export default createAction; diff --git a/packages/tcore-console/src/Requests/createAnalysis.ts b/packages/tcore-console/src/Requests/createAnalysis.ts new file mode 100644 index 00000000..9380cb44 --- /dev/null +++ b/packages/tcore-console/src/Requests/createAnalysis.ts @@ -0,0 +1,14 @@ +import { IAnalysisCreate, TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function createAnalysis( + analysis: Omit +): Promise { + const response = await axios.post("/analysis", analysis); + const { data } = response; + return data.result; +} + +export default createAnalysis; diff --git a/packages/tcore-console/src/Requests/createDevice.ts b/packages/tcore-console/src/Requests/createDevice.ts new file mode 100644 index 00000000..d72835d9 --- /dev/null +++ b/packages/tcore-console/src/Requests/createDevice.ts @@ -0,0 +1,12 @@ +import { ICreateDeviceResponse, IDeviceCreate } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function createDevice(device: IDeviceCreate): Promise { + const response = await axios.post("/device", device); + const { data } = response; + return data.result; +} + +export default createDevice; diff --git a/packages/tcore-console/src/Requests/createDeviceToken.ts b/packages/tcore-console/src/Requests/createDeviceToken.ts new file mode 100644 index 00000000..60c072a0 --- /dev/null +++ b/packages/tcore-console/src/Requests/createDeviceToken.ts @@ -0,0 +1,21 @@ +import { + IDeviceTokenCreate, + IDeviceTokenCreateResponse, + TGenericID, +} from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function createDeviceToken( + deviceID: TGenericID, + token: Omit +): Promise { + const response = await axios.post("/device/token", { + ...token, + device: deviceID, + }); + return response.data.result; +} + +export default createDeviceToken; diff --git a/packages/tcore-console/src/Requests/deleteAction.ts b/packages/tcore-console/src/Requests/deleteAction.ts new file mode 100644 index 00000000..78a2c556 --- /dev/null +++ b/packages/tcore-console/src/Requests/deleteAction.ts @@ -0,0 +1,10 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function deleteAction(id: TGenericID): Promise { + await axios.delete(`/action/${id}`); +} + +export default deleteAction; diff --git a/packages/tcore-console/src/Requests/deleteAnalysis.ts b/packages/tcore-console/src/Requests/deleteAnalysis.ts new file mode 100644 index 00000000..87a71841 --- /dev/null +++ b/packages/tcore-console/src/Requests/deleteAnalysis.ts @@ -0,0 +1,10 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function deleteAnalysis(id: TGenericID): Promise { + await axios.delete(`/analysis/${id}`); +} + +export default deleteAnalysis; diff --git a/packages/tcore-console/src/Requests/deleteBucketVariables.ts b/packages/tcore-console/src/Requests/deleteBucketVariables.ts new file mode 100644 index 00000000..c3b3b086 --- /dev/null +++ b/packages/tcore-console/src/Requests/deleteBucketVariables.ts @@ -0,0 +1,11 @@ +import { Account } from "@tago-io/sdk"; +import { TGenericID } from "@tago-io/tcore-sdk/types"; + +/** + */ +async function deleteBucketVariables(id: TGenericID, params: any): Promise { + const account = new Account({ token: "TMP_TOKEN" }); + await account.buckets.deleteVariable(id, params); +} + +export default deleteBucketVariables; diff --git a/packages/tcore-console/src/Requests/deleteDevice.ts b/packages/tcore-console/src/Requests/deleteDevice.ts new file mode 100644 index 00000000..896bdc51 --- /dev/null +++ b/packages/tcore-console/src/Requests/deleteDevice.ts @@ -0,0 +1,10 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function deleteDevice(id: TGenericID): Promise { + await axios.delete(`/device/${id}`); +} + +export default deleteDevice; diff --git a/packages/tcore-console/src/Requests/deleteDeviceData.ts b/packages/tcore-console/src/Requests/deleteDeviceData.ts new file mode 100644 index 00000000..2793087e --- /dev/null +++ b/packages/tcore-console/src/Requests/deleteDeviceData.ts @@ -0,0 +1,11 @@ +import { IDeviceDataQuery } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + * Deletes data from a device. + */ +async function deleteDeviceData(deviceID: string, params: IDeviceDataQuery) { + await axios.delete(`/device/${deviceID}/data`, { params }); +} + +export default deleteDeviceData; diff --git a/packages/tcore-console/src/Requests/deleteDeviceToken.ts b/packages/tcore-console/src/Requests/deleteDeviceToken.ts new file mode 100644 index 00000000..14ad9f7e --- /dev/null +++ b/packages/tcore-console/src/Requests/deleteDeviceToken.ts @@ -0,0 +1,10 @@ +import { TGenericToken } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function deleteDeviceToken(token: TGenericToken): Promise { + await axios.delete(`/device/token/${token}`); +} + +export default deleteDeviceToken; diff --git a/packages/tcore-console/src/Requests/disablePlugin.ts b/packages/tcore-console/src/Requests/disablePlugin.ts new file mode 100644 index 00000000..7c2ed382 --- /dev/null +++ b/packages/tcore-console/src/Requests/disablePlugin.ts @@ -0,0 +1,10 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function disablePlugin(id: TGenericID) { + await axios.post(`/plugin/${id}/disable`); +} + +export default disablePlugin; diff --git a/packages/tcore-console/src/Requests/editAction/editAction.test.ts b/packages/tcore-console/src/Requests/editAction/editAction.test.ts new file mode 100644 index 00000000..13abe50a --- /dev/null +++ b/packages/tcore-console/src/Requests/editAction/editAction.test.ts @@ -0,0 +1,18 @@ +import axios from "axios"; +import editAction from "./editAction"; + +beforeEach(() => { + jest.clearAllMocks(); +}); + +test("calls correct route", async () => { + const fn = jest.spyOn(axios, "put").mockResolvedValue({}); + await editAction("61264520fee2db1b98b6a37c", { active: false }); + expect(fn).toHaveBeenCalledWith("/action/61264520fee2db1b98b6a37c", { active: false }); +}); + +test("returns correct value", async () => { + jest.spyOn(axios, "put").mockResolvedValue({}); + const response = await editAction("61264520fee2db1b98b6a37c", { active: false }); + expect(response).toBeUndefined(); +}); diff --git a/packages/tcore-console/src/Requests/editAction/editAction.ts b/packages/tcore-console/src/Requests/editAction/editAction.ts new file mode 100644 index 00000000..2f84a24c --- /dev/null +++ b/packages/tcore-console/src/Requests/editAction/editAction.ts @@ -0,0 +1,10 @@ +import { IActionEdit, TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function editAction(id: TGenericID, action: IActionEdit): Promise { + await axios.put(`/action/${id}`, action); +} + +export default editAction; diff --git a/packages/tcore-console/src/Requests/editAnalysis.ts b/packages/tcore-console/src/Requests/editAnalysis.ts new file mode 100644 index 00000000..7b802068 --- /dev/null +++ b/packages/tcore-console/src/Requests/editAnalysis.ts @@ -0,0 +1,10 @@ +import { IAnalysisEdit, TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function editAnalysis(id: TGenericID, analysis: IAnalysisEdit): Promise { + await axios.put(`/analysis/${id}`, analysis); +} + +export default editAnalysis; diff --git a/packages/tcore-console/src/Requests/editDevice.ts b/packages/tcore-console/src/Requests/editDevice.ts new file mode 100644 index 00000000..c1b31967 --- /dev/null +++ b/packages/tcore-console/src/Requests/editDevice.ts @@ -0,0 +1,10 @@ +import { IDeviceEdit, TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function editDevice(id: TGenericID, device: IDeviceEdit): Promise { + await axios.put(`/device/${id}`, device); +} + +export default editDevice; diff --git a/packages/tcore-console/src/Requests/editDeviceData.ts b/packages/tcore-console/src/Requests/editDeviceData.ts new file mode 100644 index 00000000..64c869eb --- /dev/null +++ b/packages/tcore-console/src/Requests/editDeviceData.ts @@ -0,0 +1,11 @@ +import { IDeviceData } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + * Edits data from a device. + */ +async function editDeviceData(deviceID: string, data: IDeviceData) { + await axios.put(`/device/${deviceID}/data`, data); +} + +export default editDeviceData; diff --git a/packages/tcore-console/src/Requests/editPluginSettings.ts b/packages/tcore-console/src/Requests/editPluginSettings.ts new file mode 100644 index 00000000..fa0b110a --- /dev/null +++ b/packages/tcore-console/src/Requests/editPluginSettings.ts @@ -0,0 +1,10 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function editPluginSettings(id: TGenericID, data: any) { + await axios.put(`/plugin/${id}`, data); +} + +export default editPluginSettings; diff --git a/packages/tcore-console/src/Requests/editSettings.ts b/packages/tcore-console/src/Requests/editSettings.ts new file mode 100644 index 00000000..7d18e87e --- /dev/null +++ b/packages/tcore-console/src/Requests/editSettings.ts @@ -0,0 +1,10 @@ +import { ISettings } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function editSettings(data: ISettings): Promise { + await axios.put("/settings", data); +} + +export default editSettings; diff --git a/packages/tcore-console/src/Requests/enablePlugin.ts b/packages/tcore-console/src/Requests/enablePlugin.ts new file mode 100644 index 00000000..c89bf716 --- /dev/null +++ b/packages/tcore-console/src/Requests/enablePlugin.ts @@ -0,0 +1,10 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function enablePlugin(id: TGenericID) { + await axios.post(`/plugin/${id}/enable`); +} + +export default enablePlugin; diff --git a/packages/tcore-console/src/Requests/getActionList.ts b/packages/tcore-console/src/Requests/getActionList.ts new file mode 100644 index 00000000..5df45f9f --- /dev/null +++ b/packages/tcore-console/src/Requests/getActionList.ts @@ -0,0 +1,25 @@ +import { IAction, IActionListQuery } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + * Retrieves a list of actions. + */ +async function getActionList(page: number, amount: number, filter: any): Promise { + const params: IActionListQuery = { + page: page + 1, + amount, + filter: { + active: filter.active ?? undefined, + name: filter.name ? `*${filter.name}*` : undefined, + tags: filter.tags, + }, + fields: ["name", "active", "action", "last_triggered", "created_at"], + }; + + const response = await axios.get("/action", { params }); + const { data } = response; + + return data.result || []; +} + +export default getActionList; diff --git a/packages/tcore-console/src/Requests/getAnalysisInfo.ts b/packages/tcore-console/src/Requests/getAnalysisInfo.ts new file mode 100644 index 00000000..7b756eff --- /dev/null +++ b/packages/tcore-console/src/Requests/getAnalysisInfo.ts @@ -0,0 +1,13 @@ +import { IAnalysis, TGenericID } from "@tago-io/tcore-sdk/types"; +import { Account } from "@tago-io/sdk"; + +/** + * Retrieves all information of a single analysis. + */ +async function getAnalysisInfo(id: TGenericID): Promise { + const account = new Account({ token: "TMP_TOKEN" }); + const analysis = await account.analysis.info(id); + return analysis as any as IAnalysis; +} + +export default getAnalysisInfo; diff --git a/packages/tcore-console/src/Requests/getAnalysisList.ts b/packages/tcore-console/src/Requests/getAnalysisList.ts new file mode 100644 index 00000000..0edca863 --- /dev/null +++ b/packages/tcore-console/src/Requests/getAnalysisList.ts @@ -0,0 +1,25 @@ +import { Account } from "@tago-io/sdk"; +import { AnalysisQuery } from "@tago-io/sdk/out/modules/Account/analysis.types"; +import { IAnalysis } from "@tago-io/tcore-sdk/types"; + +/** + * Retrieves a list of analyses. + */ +async function getAnalysisList(page: number, amount: number, filter: any): Promise { + const account = new Account({ token: "TMP_TOKEN" }); + const query = { + page, + amount, + filter: { + active: filter.active ?? undefined, + name: filter.name ? `*${filter.name}*` : undefined, + tags: filter.tags, + }, + fields: ["name", "active", "last_run", "created_at"], + }; + + const analyses = await account.analysis.list(query as AnalysisQuery); + return analyses as any as IAnalysis[]; +} + +export default getAnalysisList; diff --git a/packages/tcore-console/src/Requests/getDeviceData.ts b/packages/tcore-console/src/Requests/getDeviceData.ts new file mode 100644 index 00000000..d64374fe --- /dev/null +++ b/packages/tcore-console/src/Requests/getDeviceData.ts @@ -0,0 +1,34 @@ +import { IDeviceData } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + * Retrieves data from a device. + */ +async function getDeviceData( + deviceID: string, + page: number, + amount: number, + filter: any, + endDate: any +): Promise { + const params: any = { + qty: amount, + id: filter.id || undefined, + location: filter.location || undefined, + metadata: filter.metadata || undefined, + ordination: "desc", + skip: page * amount, + time: filter.time || undefined, + group: filter.group || undefined, + value: filter.value || undefined, + variable: filter.variable || undefined, + end_date: endDate || undefined, + }; + + const response = await axios.get(`/device/${deviceID}/data`, { params }); + const { data } = response; + + return data.result || []; +} + +export default getDeviceData; diff --git a/packages/tcore-console/src/Requests/getDeviceDataAmount.ts b/packages/tcore-console/src/Requests/getDeviceDataAmount.ts new file mode 100644 index 00000000..0604af8f --- /dev/null +++ b/packages/tcore-console/src/Requests/getDeviceDataAmount.ts @@ -0,0 +1,12 @@ +import { Account } from "@tago-io/sdk"; +import { TGenericID } from "@tago-io/tcore-sdk/types"; + +/** + */ +async function getDeviceDataAmount(id: TGenericID) { + const account = new Account({ token: "TMP_TOKEN" }); + const amount = await account.buckets.amount(id); + return amount; +} + +export default getDeviceDataAmount; diff --git a/packages/tcore-console/src/Requests/getDeviceInfo.ts b/packages/tcore-console/src/Requests/getDeviceInfo.ts new file mode 100644 index 00000000..82258fce --- /dev/null +++ b/packages/tcore-console/src/Requests/getDeviceInfo.ts @@ -0,0 +1,13 @@ +import { IDevice, TGenericID } from "@tago-io/tcore-sdk/types"; +import { Account } from "@tago-io/sdk"; + +/** + * Retrieves all information of a single device. + */ +async function getDeviceInfo(id: TGenericID): Promise { + const account = new Account({ token: "TMP_TOKEN" }); + const device = await account.devices.info(id); + return device as any as IDevice; +} + +export default getDeviceInfo; diff --git a/packages/tcore-console/src/Requests/getDeviceList.ts b/packages/tcore-console/src/Requests/getDeviceList.ts new file mode 100644 index 00000000..932c621d --- /dev/null +++ b/packages/tcore-console/src/Requests/getDeviceList.ts @@ -0,0 +1,25 @@ +import { Account } from "@tago-io/sdk"; +import { DeviceQuery } from "@tago-io/sdk/out/modules/Account/devices.types"; +import { IDevice } from "@tago-io/tcore-sdk/types"; + +/** + * Retrieves a list of devices. + */ +async function getDeviceList(page: number, amount: number, filter: any) { + const account = new Account({ token: "TMP_TOKEN" }); + const query = { + page, + amount, + filter: { + active: filter.active, + name: filter.name ? `*${filter.name}*` : undefined, + tags: filter.tags, + }, + fields: ["name", "last_input", "last_output", "active", "created_at", "type", "data_retention"], + }; + + const devices = await account.devices.list(query as DeviceQuery); + return devices as any as IDevice[]; +} + +export default getDeviceList; diff --git a/packages/tcore-console/src/Requests/installPlugin.ts b/packages/tcore-console/src/Requests/installPlugin.ts new file mode 100644 index 00000000..3e85b1ab --- /dev/null +++ b/packages/tcore-console/src/Requests/installPlugin.ts @@ -0,0 +1,11 @@ +import axios from "axios"; + +/** + */ +async function installPlugin(source: string): Promise { + const response = await axios.post("/install-plugin", { source }); + const { data } = response; + return data.result; +} + +export default installPlugin; diff --git a/packages/tcore-console/src/Requests/runAnalysis.ts b/packages/tcore-console/src/Requests/runAnalysis.ts new file mode 100644 index 00000000..3b034beb --- /dev/null +++ b/packages/tcore-console/src/Requests/runAnalysis.ts @@ -0,0 +1,11 @@ +import { Account } from "@tago-io/sdk"; +import { TGenericID } from "@tago-io/tcore-sdk/types"; + +/** + */ +async function runAnalysis(id: TGenericID): Promise { + const account = new Account({ token: "TMP_TOKEN" }); + await account.analysis.run(id); +} + +export default runAnalysis; diff --git a/packages/tcore-console/src/Requests/setDeviceParams.ts b/packages/tcore-console/src/Requests/setDeviceParams.ts new file mode 100644 index 00000000..0a74cf30 --- /dev/null +++ b/packages/tcore-console/src/Requests/setDeviceParams.ts @@ -0,0 +1,13 @@ +import { IDeviceParameterCreate, TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function setDeviceParams( + deviceID: TGenericID, + parameters: IDeviceParameterCreate[] +): Promise { + await axios.post(`/device/${deviceID}/params`, parameters); +} + +export default setDeviceParams; diff --git a/packages/tcore-console/src/Requests/startPluginModule.ts b/packages/tcore-console/src/Requests/startPluginModule.ts new file mode 100644 index 00000000..60d6c5fb --- /dev/null +++ b/packages/tcore-console/src/Requests/startPluginModule.ts @@ -0,0 +1,10 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function startPluginModule(id: TGenericID, moduleID: any) { + await axios.post(`/plugin/${id}/${moduleID}/start`); +} + +export default startPluginModule; diff --git a/packages/tcore-console/src/Requests/stopPluginModule.ts b/packages/tcore-console/src/Requests/stopPluginModule.ts new file mode 100644 index 00000000..f40a643b --- /dev/null +++ b/packages/tcore-console/src/Requests/stopPluginModule.ts @@ -0,0 +1,10 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function stopPluginModule(id: TGenericID, moduleID: any) { + await axios.post(`/plugin/${id}/${moduleID}/stop`); +} + +export default stopPluginModule; diff --git a/packages/tcore-console/src/Requests/uninstallPlugin.ts b/packages/tcore-console/src/Requests/uninstallPlugin.ts new file mode 100644 index 00000000..56b134e5 --- /dev/null +++ b/packages/tcore-console/src/Requests/uninstallPlugin.ts @@ -0,0 +1,10 @@ +import { TGenericID } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; + +/** + */ +async function uninstallPlugin(id: TGenericID, keepData?: boolean) { + await axios.get(`/plugin-uninstall/${id}?keep_data=${keepData}`); +} + +export default uninstallPlugin; diff --git a/packages/tcore-console/src/System/Socket.ts b/packages/tcore-console/src/System/Socket.ts new file mode 100644 index 00000000..94b153f8 --- /dev/null +++ b/packages/tcore-console/src/System/Socket.ts @@ -0,0 +1,17 @@ +import { io } from "socket.io-client"; +import { runInAction } from "mobx"; +import store from "./Store"; + +export const socket = io("/"); + +socket.on("connect", () => { + runInAction(() => { + store.socketConnected = true; + }); +}); + +socket.on("disconnect", () => { + runInAction(() => { + store.socketConnected = false; + }); +}); diff --git a/packages/tcore-console/src/System/Store.ts b/packages/tcore-console/src/System/Store.ts new file mode 100644 index 00000000..8a167c5c --- /dev/null +++ b/packages/tcore-console/src/System/Store.ts @@ -0,0 +1,11 @@ +import { observable, makeObservable } from "mobx"; + +const store = { + socketConnected: false, +}; + +makeObservable(store, { + socketConnected: observable, +}); + +export default store; diff --git a/packages/tcore-console/src/System/__mocks__/Socket.ts b/packages/tcore-console/src/System/__mocks__/Socket.ts new file mode 100644 index 00000000..9e6052aa --- /dev/null +++ b/packages/tcore-console/src/System/__mocks__/Socket.ts @@ -0,0 +1,5 @@ +export const socket = { + on: () => 1, + off: () => 1, + emit: () => 1, +}; diff --git a/packages/tcore-console/src/ThemeUpdateContext.tsx b/packages/tcore-console/src/ThemeUpdateContext.tsx new file mode 100644 index 00000000..afa3ee22 --- /dev/null +++ b/packages/tcore-console/src/ThemeUpdateContext.tsx @@ -0,0 +1,10 @@ +import { createContext } from "react"; + +/** + * Theme update context. + */ +const ThemeUpdateContext = createContext((_theme: string) => { + // +}); + +export default ThemeUpdateContext; diff --git a/packages/tcore-console/src/Validation/Name.ts b/packages/tcore-console/src/Validation/Name.ts new file mode 100644 index 00000000..4f2150bc --- /dev/null +++ b/packages/tcore-console/src/Validation/Name.ts @@ -0,0 +1,5 @@ +import { z } from "zod"; + +const zName = z.string().min(3).max(100); + +export { zName }; diff --git a/packages/tcore-console/src/Validation/Tags.ts b/packages/tcore-console/src/Validation/Tags.ts new file mode 100644 index 00000000..00d994f4 --- /dev/null +++ b/packages/tcore-console/src/Validation/Tags.ts @@ -0,0 +1,5 @@ +import { z } from "zod"; + +const zTags = z.array(z.object({ key: z.string().nonempty(), value: z.string().nonempty() })); + +export { zTags }; diff --git a/packages/tcore-console/src/Validation/buildZodError.ts b/packages/tcore-console/src/Validation/buildZodError.ts new file mode 100644 index 00000000..9117ea60 --- /dev/null +++ b/packages/tcore-console/src/Validation/buildZodError.ts @@ -0,0 +1,25 @@ +import { ZodIssueBase } from "zod"; + +function buildZodError(errors: ZodIssueBase[]) { + const e: any = {}; + + for (const data of errors) { + if (data.path.length === 3) { + // array path + const arrayName = data.path[0]; + const index = data.path[1]; + const key = data.path[2]; + + e[arrayName] = e[arrayName] || []; + e[arrayName][index] = e[arrayName][index] || {}; + e[arrayName][index][key] = true; + } else { + // single property + e[data.path[0]] = true; + } + } + + return e; +} + +export default buildZodError; diff --git a/packages/tcore-console/src/index.ts b/packages/tcore-console/src/index.ts new file mode 100644 index 00000000..191589e7 --- /dev/null +++ b/packages/tcore-console/src/index.ts @@ -0,0 +1,72 @@ +// This component exports all component, themes, and usable resources to the outside world. + +// These components are used to build first-class plugins that need to have the look +// and feel of the default UI. + +import Accordion from "./Components/Accordion/Accordion"; +import Icon from "./Components/Icon/Icon"; +import Tooltip from "./Components/Tooltip/Tooltip"; +import FormGroup from "./Components/FormGroup/FormGroup"; +import Row from "./Components/Row/Row"; +import Col from "./Components/Col/Col"; +import Switch from "./Components/Switch/Switch"; +import Input from "./Components/Input/Input"; +import Link from "./Components/Link/Link"; +import Button from "./Components/Button/Button"; +import InnerNav from "./Components/InnerNav/InnerNav"; +import Loading from "./Components/Loading/Loading"; +import EmptyMessage from "./Components/EmptyMessage/EmptyMessage"; +import GlobalStyles from "./Components/Styles/GlobalStyles"; +import Publisher from "./Components/Plugins/Common/Publisher/Publisher"; +import PluginImage from "./Components/PluginImage/PluginImage"; +import Modal from "./Components/Modal/Modal"; +import Tabs from "./Components/Tabs/Tabs"; +import Footer from "./Components/Footer/Footer"; +import Markdown from "./Components/Markdown/Markdown"; +import useApiRequest from "./Helpers/useApiRequest"; +import ModalUninstallPlugin from "./Components/Plugins/Common/ModalUninstallPlugin/ModalUninstallPlugin"; +import ClassTypes from "./Components/Plugins/Common/ClassTypes/ClassTypes"; +import MainInformation from "./Components/Plugins/Common/MainInformation/MainInformation"; +import Permissions from "./Components/Plugins/Common/Permissions/Permissions"; +import Platforms from "./Components/Plugins/Common/Platforms/Platforms"; +import * as LinkStyle from "./Components/Link/Link.style"; +import * as ButtonStyle from "./Components/Button/Button.style"; +import * as PluginImageStyle from "./Components/PluginImage/PluginImage.style"; +import * as PublisherStyle from "./Components/Plugins/Common/Publisher/Publisher.style"; +import * as theme from "./theme"; + +export { + Accordion, + Button, + ButtonStyle, + ClassTypes, + Col, + EmptyMessage, + Footer, + FormGroup, + GlobalStyles, + Icon, + InnerNav, + Input, + Link, + LinkStyle, + Loading, + MainInformation, + Markdown, + Modal, + ModalUninstallPlugin, + Permissions, + Platforms, + PluginImage, + PluginImageStyle, + Publisher, + PublisherStyle, + Row, + Switch, + Tabs, + theme, + Tooltip, + useApiRequest, +}; +export * from "./Components/Icon/Icon.types"; +export * from "./Components/Button/Button.types"; diff --git a/packages/tcore-console/src/theme.ts b/packages/tcore-console/src/theme.ts new file mode 100644 index 00000000..5b7f79be --- /dev/null +++ b/packages/tcore-console/src/theme.ts @@ -0,0 +1,78 @@ +/** + * The fonts of the application. + */ +const fonts = { + small: ".73rem", + default: ".88rem", + medium: "1.1rem", + large: "1.3rem", + xlarge: "1.6rem", + xxlarge: "1.8rem", + xxxlarge: "2.3rem", + fontFamily: + '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"', + fontMono: "SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace", +}; + +/** + * This is the light theme of the application. + */ +const lightTheme = { + action: "hsl(11, 80%, 50%)", + actionTriggerByMQTT: "hsl(296, 32%, 43%)", + actionTriggerByResource: "hsl(208, 56%, 45%)", + actionTriggerByVariable: "rgb(85, 107, 47)", + analysis: "hsl(214, 51%, 33%)", + background1: "hsl(0, 0%, 100%)", + background2: "hsl(240, 4%, 95%)", + background3: "rgb(246, 246, 246)", + bucket: "hsl(82, 38%, 30%)", + buttonDanger: "hsl(0, 100%, 44%)", + buttonDangerFont: "hsl(0, 0%, 100%)", + buttonDefault: "hsl(0, 100%, 100%)", + buttonDefaultFont: "hsl(0, 0%, 27%)", + buttonDisabled: "hsl(0, 0%, 90%)", + buttonDisabledFont: "hsl(0, 0%, 27%)", + buttonPrimary: "hsl(0, 0%, 0%)", + buttonPrimaryFont: "rgb(255, 255, 255)", + buttonSuccess: "hsl(122, 100%, 24%)", + buttonWarning: "hsl(31, 92%, 66%)", + buttonWarningText: "hsl(0, 0%, 100%)", + connector: "hsl(208, 56%, 46%)", + device: "hsl(180, 78%, 30%)", + deviceInputOutput1Day: "hsl(298, 74%, 37%)", + deviceInputOutput3Days: "hsl(341, 74%, 36%)", + deviceInputOutput3Hours: "hsl(121, 84%, 40%)", + deviceInputOutput6Hours: "hsl(29, 98%, 48%)", + errorStatus: "hsla(0, 100%, 44%, 0.1)", + errorStatusIcon: "hsl(0, 100%, 44%)", + extension: "hsl(207, 85%, 40%)", + fieldsetBorder: "rgb(0, 0, 0, 0.1)", + files: "hsl(34, 84%, 49%)", + font: "hsl(0, 4%, 29%)", + font2: "rgba(0, 0, 0, .5)", + font3: "rgba(0, 0, 0, .4)", + formControlBackground: "hsl(0, 0%, 99%)", + formControlDisabled: "hsl(0, 0%, 95%)", + formControlDisabledFont: "rgba(0, 0, 0, 0.5)", + formControlFocus: "hsl(0, 0%, 0%)", + formControlFont: "hsl(0, 0%, 11%)", + home: "hsl(0, 0%, 0%)", + link: "hsl(208, 56%, 46%)", + liveInspectorCircle: "rgba(0, 0, 0, 0.5)", + logs: "hsl(0, 100%, 50%)", + navBar: "hsl(0, 0%, 100%)", + navBarButton: "hsl(0, 0%, 100%)", + navBarIcon: "hsl(0, 0%, 0%)", + settings: "hsl(110, 20%, 40%)", + switchBigSelected: "rgb(209, 161, 49)", + switchBigUnselected: "rgb(190, 190, 190)", + tableHeader: "hsla(0, 0%, 95%)", + tableOddRow: "hsla(0, 0%, 0%, 0.03)", + tabTitleActive: "rgba(0, 0, 0, 0.08)", + tabTitleBackground: "hsl(240, 4%, 95%)", + tabTitleHover: "rgba(0, 0, 0, 0.04)", + tabTitleSelected: "rgb(255, 255, 255)", +}; + +export { fonts, lightTheme }; diff --git a/packages/tcore-console/tsconfig-tsc.json b/packages/tcore-console/tsconfig-tsc.json new file mode 100644 index 00000000..1ab0cdd8 --- /dev/null +++ b/packages/tcore-console/tsconfig-tsc.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "outDir": "./build-tsc", + "rootDir": "./src", + "baseUrl": ".", + "jsx": "react-jsx", + "noImplicitAny": true, + "declaration": true + }, + "include": [ + "types/styled.d.ts", + "types/index.d.ts", + "src/**/*" + ], + "exclude": [ + "src/**/*.test.tsx", + "src/**/__mocks__/*", + "node_modules" + ] +} diff --git a/packages/tcore-console/tsconfig.json b/packages/tcore-console/tsconfig.json new file mode 100644 index 00000000..079b0f04 --- /dev/null +++ b/packages/tcore-console/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "jsx": "react-jsx", + "noImplicitAny": true, + }, + "include": [ + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/packages/tcore-console/types/index.d.ts b/packages/tcore-console/types/index.d.ts new file mode 100644 index 00000000..b732311d --- /dev/null +++ b/packages/tcore-console/types/index.d.ts @@ -0,0 +1,23 @@ +/** + * PNG Imports will return a string containing the path to the image. + */ +declare module "*.png" { + const content: string; + export default content; +} + +/** + * GIF Imports will return a string containing the path to the image. + */ +declare module "*.gif" { + const content: string; + export default content; +} + +/** + * SVG Imports will return the actual tag in a react component. + */ +declare module "*.svg" { + const content: ReactSVGElement; + export default content; +} diff --git a/packages/tcore-console/types/styled.d.ts b/packages/tcore-console/types/styled.d.ts new file mode 100644 index 00000000..e9838859 --- /dev/null +++ b/packages/tcore-console/types/styled.d.ts @@ -0,0 +1,62 @@ +import "styled-components"; + +declare module "styled-components" { + export interface DefaultTheme { + files: string; + settings: string; + action: string; + analysis: string; + bucket: string; + buttonDanger: string; + buttonDangerFont: string; + buttonDefault: string; + buttonDefaultFont: string; + buttonDisabled: string; + buttonDisabledFont: string; + buttonPrimary: string; + buttonPrimaryFont: string; + buttonSuccess: string; + connector: string; + device: string; + deviceInputOutput1Day: string; + deviceInputOutput3Days: string; + deviceInputOutput3Hours: string; + deviceInputOutput6Hours: string; + deviceInputOutputRest: string; + extension: string; + font: string; + font2: string; + font3: string; + formControlBackground: string; + formControlDisabled: string; + formControlFocus: string; + home: string; + navBar: string; + tabTitleBackground: string; + tabTitleSelected: string; + tabTitleHover: string; + tabTitleActive: string; + formControlFont: string; + buttonWarning: string; + buttonWarningText: string; + actionTriggerByVariable: string; + actionTriggerByMQTT: string; + actionTriggerByResource: string; + tableHeader: string; + tableOddRow: string; + formControlDisabledFont: string; + fieldsetBorder: string; + switchBigSelected: string; + switchBigUnselected: string; + link: string; + logs: string; + background1: string; + background2: string; + background3: string; + liveInspectorCircle: string; + errorStatusIcon: string; + errorStatus: string; + navBarButton: string; + navBarIcon: string; + } +} diff --git a/packages/tcore-console/utils/setup-jest.tsx b/packages/tcore-console/utils/setup-jest.tsx new file mode 100644 index 00000000..f60c5297 --- /dev/null +++ b/packages/tcore-console/utils/setup-jest.tsx @@ -0,0 +1,4 @@ +import * as React from "react"; + +// jest needs to have react globally in order to render JSX in the test units. +global.React = React; diff --git a/packages/tcore-console/utils/test-utils.tsx b/packages/tcore-console/utils/test-utils.tsx new file mode 100644 index 00000000..d53b9746 --- /dev/null +++ b/packages/tcore-console/utils/test-utils.tsx @@ -0,0 +1,44 @@ +jest.mock("../src/Helpers/useApiRequest.ts"); +jest.mock("../src/System/Socket.ts"); + +import { FC, ReactElement } from "react"; +import "@testing-library/jest-dom"; +import { render, RenderOptions } from "@testing-library/react"; +import { ThemeProvider } from "styled-components"; +import { MemoryRouter, Route, Switch } from "react-router-dom"; +import { lightTheme } from "../src/theme"; +import { icons } from "../src/Components/Icon/Icon.types"; + +const AllTheProviders: FC = ({ children }) => { + return ( + + + + {children} + + + + ); +}; + +const customRender = (ui: ReactElement, options?: Omit) => + render(ui, { wrapper: AllTheProviders, ...options }); + +/** + * Manually iterates through all of the icons and mocks each one to return + * another element in order to avoid `lazy` imports from react. + */ +const manuallyMockIcons = () => { + for (const key in icons) { + if (key in icons) { + (icons as any)[key] = { + ReactComponent: () => {key}-icon-mock, + } + } + } +}; + +manuallyMockIcons(); + +export { fireEvent, act, waitFor, screen } from "@testing-library/react"; +export { customRender as render }; diff --git a/packages/tcore-sdk/.eslintignore b/packages/tcore-sdk/.eslintignore new file mode 100644 index 00000000..729abf75 --- /dev/null +++ b/packages/tcore-sdk/.eslintignore @@ -0,0 +1,10 @@ +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +__build__* +.eslintrc.js +jest.config.js +esbuild/* diff --git a/packages/tcore-sdk/.eslintrc.js b/packages/tcore-sdk/.eslintrc.js new file mode 100644 index 00000000..d6aa3f56 --- /dev/null +++ b/packages/tcore-sdk/.eslintrc.js @@ -0,0 +1,31 @@ +module.exports = { + env: { + node: true, + jest: true + }, + root: true, + parserOptions: { + ecmaVersion: 6, + sourceType: "module", + ecmaFeatures: { + jsx: false, + }, + tsconfigRootDir: __dirname, + project: ["./tsconfig.json"], + }, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "import"], + ignorePatterns: ['.eslintrc.js', 'types.js', 'types.d.ts'], + extends: [ + "plugin:prettier/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript", + "eslint:recommended" + ], + rules: { + "import/order": 1, + "no-unused-vars": 0 + }, +}; diff --git a/packages/tcore-sdk/.prettierrc b/packages/tcore-sdk/.prettierrc new file mode 100644 index 00000000..3ae934c4 --- /dev/null +++ b/packages/tcore-sdk/.prettierrc @@ -0,0 +1,11 @@ +{ + "trailingComma": "es5", + "printWidth": 120, + "useTabs": false, + "tabWidth": 2, + "semi": true, + "singleQuote": false, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/packages/tcore-sdk/README.md b/packages/tcore-sdk/README.md new file mode 100644 index 00000000..fc5c0e9f --- /dev/null +++ b/packages/tcore-sdk/README.md @@ -0,0 +1 @@ +TCore SDK for creating plugins. diff --git a/packages/tcore-sdk/jest.config.js b/packages/tcore-sdk/jest.config.js new file mode 100644 index 00000000..27c177bb --- /dev/null +++ b/packages/tcore-sdk/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + roots: ['/src'], + testRegex: '(/__tests__/.*|(\\.|/)test)\\.ts?$' +}; diff --git a/packages/tcore-sdk/package.json b/packages/tcore-sdk/package.json new file mode 100644 index 00000000..954cdf9a --- /dev/null +++ b/packages/tcore-sdk/package.json @@ -0,0 +1,83 @@ +{ + "name": "@tago-io/tcore-sdk", + "version": "0.3.3", + "private": false, + "main": "./build/Lib/index.js", + "description": "TCore SDK for creating plugins", + "author": "Tago LLC", + "homepage": "https://github.com/tago-io/tcore", + "bin": { + "tcore-plugin": "./build/Bin/Bin.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/tago-io/tcore" + }, + "keywords": [ + "iot", + "device", + "tcore", + "sdk", + "edge", + "computing", + "platform", + "tagoio" + ], + "exports": { + ".": { + "import": "./build/Lib/index.js", + "require": "./build/Lib/index.js" + }, + "./types": { + "import": "./types.js", + "require": "./types.js" + } + }, + "files": [ + "/build", + "/types.d.ts", + "/types.js" + ], + "scripts": { + "clean": "rm -rf node_modules; rm -rf package-lock.json", + "build": "rm -rf ./build; tsc", + "test": "TZ=UTC jest", + "test:watch": "TZ=UTC jest --watch", + "tsc:watch": "npm run watch", + "watch": "tsc --watch --preserveWatchOutput" + }, + "dependencies": { + "commander": "9.1.0", + "luxon": "2.3.0", + "ora": "5.4.1", + "nanoid": "^3.1.32", + "uuid": "^8.3.2", + "zod": "3.13.4", + "tar": "6.1.11", + "glob": "7.2.0", + "chalk": "4.1.2", + "semver": "7.3.5", + "image-size": "1.0.1" + }, + "devDependencies": { + "@types/semver": "7.3.9", + "@types/commander": "2.12.2", + "@types/glob": "7.2.0", + "@types/tar": "6.1.1", + "@types/luxon": "2.0.9", + "@types/jest": "27.0.1", + "@types/node": "16.7.1", + "@types/uuid": "^8.3.1", + "@typescript-eslint/eslint-plugin": "4.31.2", + "@typescript-eslint/parser": "4.29.3", + "eslint": "7.32.0", + "eslint-config-prettier": "8.3.0", + "eslint-import-resolver-typescript": "2.4.0", + "eslint-plugin-import": "2.24.1", + "eslint-plugin-prettier": "3.4.1", + "jest": "27.0.6", + "prettier": "2.3.2", + "ts-jest": "27.0.5", + "typescript": "4.3.5" + } +} diff --git a/packages/tcore-sdk/src/Bin/Bin.ts b/packages/tcore-sdk/src/Bin/Bin.ts new file mode 100644 index 00000000..b95f205a --- /dev/null +++ b/packages/tcore-sdk/src/Bin/Bin.ts @@ -0,0 +1,226 @@ +#!/usr/bin/env node + +import fs from "fs"; +import path from "path"; +import crypto from "crypto"; +import chalk from "chalk"; +import ora from "ora"; +import tar from "tar"; +import glob from "glob"; +import semver from "semver"; +import { program } from "commander"; +import getImageData from "image-size"; +import { z } from "zod"; +import { zPluginPermission, zPluginType } from "../Types"; + +const cwd = process.cwd(); +const pkg = require(path.join(cwd, "package.json")); +const pkgName = pkg.name.replace("@", "").replace(/\//g, "-"); + +/** + * Glob of patterns to ignore. Acquired from the .tcoreignore file. + */ +let tcoreIgnore: string[] = []; + +/** + * The name of the output file. + */ +const OUTPUT_FILE = `${pkgName}-${pkg.version}.tcore`; + +/** + * Formats the bytes into a more readable format. + */ +function formatBytes(bytes: number) { + if (bytes === 0) { + return "0 B"; + } + + const k = 1024; + const dm = 2; + const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`; +} + +/** + */ +function getSha256OutputFile() { + return new Promise((resolve) => { + const stream = crypto.createHash("sha1").setEncoding("hex"); + fs.createReadStream(path.join(cwd, OUTPUT_FILE)) + .pipe(stream) + .on("finish", () => resolve(stream.read())); + }); +} + +/** + */ +async function printDetails(spinner: ora.Ora, amountOfFiles: number) { + const filePath = path.join(cwd, OUTPUT_FILE); + const stat = await fs.promises.stat(filePath).catch(() => null); + const size = stat?.size || 0; + + console.log(`${chalk.magentaBright("[TCore SDK]")} ${chalk.magenta(`====== Details ======`)}`); + + const shasum = await getSha256OutputFile(); + + spinner.succeed(`name: ${pkg.name}`); + spinner.succeed(`version: ${pkg.version}`); + spinner.succeed(`filename: ${OUTPUT_FILE}`); + spinner.succeed(`size: ${formatBytes(size)}`); + spinner.succeed(`shasum: ${shasum}`); + spinner.succeed(`files: ${amountOfFiles}`); +} + +/** + */ +async function pack(spinner: ora.Ora): Promise { + const files: string[] = []; + + if (pkg.files) { + for (const item of pkg.files) { + const ignore = [OUTPUT_FILE, "node_modules", "node_modules/**", ".DS_Store", ...tcoreIgnore]; + const globFiles = glob.sync(item, { cwd, ignore, dot: true }); + files.push(...globFiles); + } + } else { + const ignore = [OUTPUT_FILE, ".gitignore", "node_modules", "node_modules/**", ".git", ".git/**/*", ...tcoreIgnore]; + const globFiles = glob.sync("**/*", { cwd, ignore, dot: true }); + files.push(...globFiles); + } + + if (!files.includes("package.json")) { + // package.json is necessary, cannot remove it + files.push("package.json"); + } + + if (!files.includes("README.md")) { + // README.md is necessary, cannot remove it + files.push("README.md"); + } + + let amount = 0; + + for (const file of files) { + const stat = fs.statSync(path.join(cwd, file)); + const size = stat.size; + if (!stat.isDirectory()) { + spinner.succeed(`Added ${chalk.cyan(file)} (${formatBytes(size)})`); + amount++; + } + } + + spinner.start("Generating .tcore file"); + + return await new Promise((resolve, reject) => { + const opts = { + cwd, + gzip: true, + file: path.join(cwd, OUTPUT_FILE), + }; + + tar.c(opts, files, (err) => { + if (err) { + reject(err); + } else { + spinner.succeed("Generated .tcore file"); + resolve(amount); + } + }); + }); +} + +/** + */ +function validate(spinner: ora.Ora): boolean { + let error = false; + + const setMessage = (m: string) => { + spinner.fail(chalk.redBright(m)); + error = true; + }; + + // ------------------------------ + // engine, not required but must be a valid semver if present + const engine = pkg.engines?.tcore; + if (engine && !semver.validRange(engine)) { + setMessage(`'package.engines.tcore' has an invalid TCore range (${engine})`); + } + + // ------------------------------ + // types must exist and have valid values + const types = pkg.tcore?.types || []; + if (types.length === 0) { + setMessage("'package.tcore.types' should contain at least one module type"); + } + if (!z.array(zPluginType).safeParse(types).success) { + setMessage("'package.tcore.types' contains one or more invalid values"); + } + + // ------------------------------ + // permissions must have valid values if it exists + const permissions = pkg.tcore?.permissions || []; + if (!z.array(zPluginPermission).safeParse(permissions).success) { + setMessage("'package.tcore.permissions' contains one or more invalid values"); + } + + // ------------------------------ + // icon validation, required + const icon = pkg.tcore?.icon || ""; + const iconPath = path.join(cwd, icon); + const iconExists = fs.existsSync(iconPath); + if (icon && iconExists) { + const data = getImageData(iconPath); + const ratio = ((data.width || 0) / (data.height || 1)).toFixed(2); + const valid = data.type === "png" && ratio === "1.35"; + if (!valid) { + setMessage("'package.tcore.icon' should be a PNG image with aspect ratio of 7:5"); + } + } else { + setMessage("'package.tcore.icon' file not found"); + } + + // ------------------------------ + // full description, not required + const fd = pkg.tcore?.full_description || ""; + const fdPath = path.join(cwd, fd); + const fdExists = fs.existsSync(fdPath); + if (fd && !fdExists) { + setMessage("'package.tcore.full_description' file not found"); + } + + return error; +} + +/** + */ +async function generate(opts: any) { + tcoreIgnore = await fs.promises + .readFile(path.join(cwd, ".tcoreignore"), "utf-8") + .then((r) => r.split("\n").filter((x) => x)) + .catch(() => []); + + const spinner = ora("Validating package.json"); + spinner.prefixText = chalk.magentaBright("[TCore SDK]"); + + try { + const error = validate(spinner); + if (error && !opts.force) { + spinner.fail("Process aborted due to errors"); + return; + } + + const amountOfFiles = await pack(spinner); + await printDetails(spinner, amountOfFiles); + } catch (ex: any) { + spinner.fail(`${spinner.text} - ${chalk.redBright(ex?.message || ex)}`); + } +} + +program + .command("pack") + .option("-f, --force", "Forces creation even with errors") + .description("Creates a .tcore file from a package") + .action(generate); + +program.parse(); diff --git a/packages/tcore-sdk/src/Lib/APIBridge/APIBridge.ts b/packages/tcore-sdk/src/Lib/APIBridge/APIBridge.ts new file mode 100644 index 00000000..922edabf --- /dev/null +++ b/packages/tcore-sdk/src/Lib/APIBridge/APIBridge.ts @@ -0,0 +1,84 @@ +import { parentPort } from "worker_threads"; +import { nanoid } from "nanoid"; +import { IPluginMessage } from "../../Types"; + +/** + * A single callback waiting to be triggered from one of the API responses. + */ +interface ICallback { + resolve: (...args: any[]) => void; + reject: (...args: any[]) => void; + method: string; + time: number; +} + +/** + * This class provides methods to communicate with the API (outside of the worker environment). + */ +class APIBridge { + private callbacks = new Map(); + + constructor() { + this.onAPIMessage = this.onAPIMessage.bind(this); + this.attachEvents(); + } + + /** + * Attaches the events to listen to message from the API. + */ + private attachEvents() { + parentPort?.on("message", this.onAPIMessage); + } + + /** + */ + private destroy() { + parentPort?.removeListener("message", this.onAPIMessage); + } + + /** + * Called when a message arrives from the API. + */ + private onAPIMessage(message: IPluginMessage) { + if (message.event === "apiMethodResponse") { + if (this.callbacks.has(message.connectionID)) { + const { error } = message; + if (error) { + // there was an error while executing a method in the plugin, we must reject the callback. + this.callbacks.get(message.connectionID)?.reject(error); + } else { + // no errors during the method execution in the plugin. We must resolve the callback. + this.callbacks.get(message.connectionID)?.resolve(message.params); + } + + // remove the callback + this.callbacks.delete(message.connectionID); + } + } + } + + /** + * Invokes a method from one of the services of the API. + */ + protected invokeApiMethod(method: string, ...args: any[]): any { + return new Promise((resolve, reject) => { + const connectionID = nanoid(10); + + this.callbacks.set(connectionID, { + resolve, + reject, + method, + time: Date.now(), + }); + + parentPort?.postMessage({ + connectionID, + event: "executeApiMethod", + method, + params: args, + }); + }); + } +} + +export default APIBridge; diff --git a/packages/tcore-sdk/src/Lib/ActionTriggerModule/ActionTriggerModule.ts b/packages/tcore-sdk/src/Lib/ActionTriggerModule/ActionTriggerModule.ts new file mode 100644 index 00000000..50270b25 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/ActionTriggerModule/ActionTriggerModule.ts @@ -0,0 +1,28 @@ +import { IActionTriggerModuleSetup, TGenericID } from "../../Types"; +import TCoreModule from "../TCoreModule/TCoreModule"; + +/** + * This module allows the creation of a new Action type. + */ +class ActionTriggerModule extends TCoreModule { + constructor(protected setup: IActionTriggerModuleSetup) { + super(setup, "action-trigger"); + } + + /** + * Called when this action type is triggered. + * This will decide if the action should be executed or not. + */ + public async onCall(actionID: TGenericID, values: any, data: any): Promise { + return Promise.resolve(); + } + + /** + * Called when the triggers of an action change. + */ + public async onTriggerChange(actionID: TGenericID, trigger: any): Promise { + // + } +} + +export default ActionTriggerModule; diff --git a/packages/tcore-sdk/src/Lib/ActionTypeModule/ActionTypeModule.ts b/packages/tcore-sdk/src/Lib/ActionTypeModule/ActionTypeModule.ts new file mode 100644 index 00000000..a8e12bf2 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/ActionTypeModule/ActionTypeModule.ts @@ -0,0 +1,20 @@ +import { IActionTypeModuleSetup, TGenericID } from "../../Types"; +import TCoreModule from "../TCoreModule/TCoreModule"; + +/** + * This module allows the creation of a new Action type. + */ +class ActionTypeModule extends TCoreModule { + constructor(protected setup: IActionTypeModuleSetup) { + super(setup, "action-type"); + } + + /** + * Called when this action type is executed. + */ + public async onCall(actionID: TGenericID, values: any, data: any): Promise { + return Promise.resolve(); + } +} + +export default ActionTypeModule; diff --git a/packages/tcore-sdk/src/Lib/Core/Core.test.ts b/packages/tcore-sdk/src/Lib/Core/Core.test.ts new file mode 100644 index 00000000..22072631 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/Core/Core.test.ts @@ -0,0 +1,279 @@ +import core from "./Core"; + +afterEach(() => { + jest.clearAllMocks(); +}); + +test("getDeviceList works without query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); + const response = await core.getDeviceList(); + expect(fn).toHaveBeenCalledWith("getDeviceList", undefined); + expect(response).toEqual([]); +}); + +test("getDeviceList works with query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); + const response = await core.getDeviceList({}); + expect(fn).toHaveBeenCalledWith("getDeviceList", {}); + expect(response).toEqual([]); +}); + +test("getDeviceInfo", async () => { + const mockDevice = { name: "Device #1" }; + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue(mockDevice); + const response = await core.getDeviceInfo("6126ff702e576dd238e1da3e"); + expect(fn).toHaveBeenCalledWith("getDeviceInfo", "6126ff702e576dd238e1da3e"); + expect(response).toEqual(mockDevice); +}); + +test("getDeviceByToken", async () => { + const mockDevice = { name: "Device #2" }; + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue(mockDevice); + const response = await core.getDeviceByToken("b24afe36-33ff-4f48-9bbd-b10d446d779d"); + expect(fn).toHaveBeenCalledWith("getDeviceByToken", "b24afe36-33ff-4f48-9bbd-b10d446d779d"); + expect(response).toEqual(mockDevice); +}); + +test("editDevice", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod"); + await core.editDevice("6126ff702e576dd238e1da3e", { active: false }); + expect(fn).toHaveBeenCalledWith("editDevice", "6126ff702e576dd238e1da3e", { active: false }); +}); + +test("deleteDevice", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod"); + const response = await core.deleteDevice("6126ff702e576dd238e1da3e"); + expect(response).toEqual(undefined); + expect(fn).toHaveBeenCalledWith("deleteDevice", "6126ff702e576dd238e1da3e"); +}); + +test("createDevice", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue({ device_id: 1, token: 3 }); + const response = await core.createDevice({ name: "My new device" }); + expect(response.device_id).toEqual(1); + expect(response.token).toEqual(3); + expect(fn).toHaveBeenCalledWith("createDevice", { name: "My new device" }); +}); + +test("createDeviceToken", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue({ token: "123" }); + const response = await core.createDeviceToken("6126ff702e576dd238e1da3e", { + name: "Token #1", + permission: "full", + expire_time: "1 day", + }); + expect(response).toEqual({ token: "123" }); + expect(fn).toHaveBeenCalledWith("createDeviceToken", "6126ff702e576dd238e1da3e", { + name: "Token #1", + permission: "full", + expire_time: "1 day", + }); +}); + +test("getDeviceTokenList works without query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([1, 2, 3]); + const response = await core.getDeviceTokenList("6126ff702e576dd238e1da3e"); + expect(response).toEqual([1, 2, 3]); + expect(fn).toHaveBeenCalledWith("getDeviceTokenList", "6126ff702e576dd238e1da3e", undefined); +}); + +test("getDeviceTokenList works with query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([1, 2]); + const response = await core.getDeviceTokenList("6126ff702e576dd238e1da3e", {}); + expect(response).toEqual([1, 2]); + expect(fn).toHaveBeenCalledWith("getDeviceTokenList", "6126ff702e576dd238e1da3e", {}); +}); + +test("deleteDeviceToken", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([1, 2]); + const response = await core.deleteDeviceToken("6126ff702e576dd238e1da3e"); + expect(response).toEqual(undefined); + expect(fn).toHaveBeenCalledWith("deleteDeviceToken", "6126ff702e576dd238e1da3e"); +}); + +test("getDeviceParamList works without sentStatus", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ key: "key", value: "value" }]); + const response = await core.getDeviceParamList("6126ff702e576dd238e1da3e"); + expect(response).toEqual([{ key: "key", value: "value" }]); + expect(fn).toHaveBeenCalledWith("getDeviceParamList", "6126ff702e576dd238e1da3e", undefined); +}); + +test("getDeviceParamList works with sentStatus", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ key: "key", value: "value" }]); + const response = await core.getDeviceParamList("6126ff702e576dd238e1da3e", true); + expect(response).toEqual([{ key: "key", value: "value" }]); + expect(fn).toHaveBeenCalledWith("getDeviceParamList", "6126ff702e576dd238e1da3e", true); +}); + +test("deleteDeviceParam", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue("abc"); + const response = await core.deleteDeviceParam("6126ff702e576dd238e1da3e"); + expect(response).toEqual(undefined); + expect(fn).toHaveBeenCalledWith("deleteDeviceParam", "6126ff702e576dd238e1da3e"); +}); + +test("setDeviceParams", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue("abc"); + const response = await core.setDeviceParams("6126ff702e576dd238e1da3e", []); + expect(response).toEqual(undefined); + expect(fn).toHaveBeenCalledWith("setDeviceParams", "6126ff702e576dd238e1da3e", []); +}); + +test("getDeviceDataAmount", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue(1337); + const response = await core.getDeviceDataAmount("61261ef1f87480ff318b7bcb"); + expect(response).toEqual(1337); + expect(fn).toHaveBeenCalledWith("getDeviceDataAmount", "61261ef1f87480ff318b7bcb"); +}); + +test("getActionTypes", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); + const response = await core.getActionTypes(); + expect(response).toEqual([]); + expect(fn).toHaveBeenCalledWith("getActionTypes"); +}); + +test("getActionList works without query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ name: "Action #1" }]); + const response = await core.getActionList(); + expect(response).toEqual([{ name: "Action #1" }]); + expect(fn).toHaveBeenCalledWith("getActionList", undefined); +}); + +test("getActionList works with query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); + const response = await core.getActionList({}); + expect(response).toEqual([]); + expect(fn).toHaveBeenCalledWith("getActionList", {}); +}); + +test("getActionInfo", async () => { + const mockAction = { name: "Action #1" }; + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue(mockAction); + const response = await core.getActionInfo("6126ff702e576dd238e1da3e"); + expect(fn).toHaveBeenCalledWith("getActionInfo", "6126ff702e576dd238e1da3e"); + expect(response).toEqual(mockAction); +}); + +test("editAction", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod"); + await core.editAction("6126ff702e576dd238e1da3e", { name: "New name" }); + expect(fn).toHaveBeenCalledWith("editAction", "6126ff702e576dd238e1da3e", { name: "New name" }); +}); + +test("deleteAction", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod"); + const response = await core.deleteAction("6126ff702e576dd238e1da3e"); + expect(response).toEqual(undefined); + expect(fn).toHaveBeenCalledWith("deleteAction", "6126ff702e576dd238e1da3e"); +}); + +test("createAction", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue("61261ef1f87480ff318b7bcb"); + const response = await core.createAction({ name: "My new Action", active: false, type: "" } as any); + expect(response).toEqual("61261ef1f87480ff318b7bcb"); + expect(fn).toHaveBeenCalledWith("createAction", { name: "My new Action", active: false, type: "" }); +}); + +test("triggerAction works without data", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); + const response = await core.triggerAction("6126ff702e576dd238e1da3e"); + expect(response).toEqual([]); + expect(fn).toHaveBeenCalledWith("triggerAction", "6126ff702e576dd238e1da3e", undefined); +}); + +test("triggerAction works with data", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); + const response = await core.triggerAction("6126ff702e576dd238e1da3e", {}); + expect(response).toEqual([]); + expect(fn).toHaveBeenCalledWith("triggerAction", "6126ff702e576dd238e1da3e", {}); +}); + +test("getAnalysisList works without query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ name: "Analysis #1" }]); + const response = await core.getAnalysisList(); + expect(response).toEqual([{ name: "Analysis #1" }]); + expect(fn).toHaveBeenCalledWith("getAnalysisList", undefined); +}); + +test("getAnalysisList works with query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); + const response = await core.getAnalysisList({}); + expect(response).toEqual([]); + expect(fn).toHaveBeenCalledWith("getAnalysisList", {}); +}); + +test("getAnalysisInfo", async () => { + const mockAnalysis = { name: "Analysis #1" }; + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue(mockAnalysis); + const response = await core.getAnalysisInfo("6126ff702e576dd238e1da3e"); + expect(fn).toHaveBeenCalledWith("getAnalysisInfo", "6126ff702e576dd238e1da3e"); + expect(response).toEqual(mockAnalysis); +}); + +test("editAnalysis", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod"); + await core.editAnalysis("6126ff702e576dd238e1da3e", { name: "New name" }); + expect(fn).toHaveBeenCalledWith("editAnalysis", "6126ff702e576dd238e1da3e", { name: "New name" }); +}); + +test("deleteAnalysis", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod"); + const response = await core.deleteAnalysis("6126ff702e576dd238e1da3e"); + expect(response).toEqual(undefined); + expect(fn).toHaveBeenCalledWith("deleteAnalysis", "6126ff702e576dd238e1da3e"); +}); + +test("createAnalysis", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue("61261ef1f87480ff318b7bcb"); + const response = await core.createAnalysis({ name: "My new Analysis", active: false, tags: [] }); + expect(response).toEqual("61261ef1f87480ff318b7bcb"); + expect(fn).toHaveBeenCalledWith("createAnalysis", { name: "My new Analysis", active: false, tags: [] }); +}); + +test("getSummary", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue({ device: 20 }); + const response = await core.getSummary(); + expect(response).toEqual({ device: 20 }); + expect(fn).toHaveBeenCalledWith("getSummary"); +}); + +test("addDeviceData", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue(true); + const response = await core.addDeviceData("61261ef1f87480ff318b7bcb", { + variable: "temperature", + value: 10, + }); + expect(response).toEqual(undefined); + expect(fn).toHaveBeenCalledWith("addDeviceData", "61261ef1f87480ff318b7bcb", { + variable: "temperature", + value: 10, + }); +}); + +test("getDeviceData works without query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); + const response = await core.getDeviceData("61261ef1f87480ff318b7bcb"); + expect(response).toEqual([]); + expect(fn).toHaveBeenCalledWith("getDeviceData", "61261ef1f87480ff318b7bcb", undefined); +}); + +test("getDeviceData works with query", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ variable: "temperature", value: 10 }]); + const response = await core.getDeviceData("61261ef1f87480ff318b7bcb", {}); + expect(response).toEqual([{ variable: "temperature", value: 10 }]); + expect(fn).toHaveBeenCalledWith("getDeviceData", "61261ef1f87480ff318b7bcb", {}); +}); + +test("getTagKeys works for all types of resources", async () => { + const fn = jest.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); + const response = await Promise.all([ + core.getTagKeys("action"), + core.getTagKeys("analysis"), + core.getTagKeys("device"), + ]); + expect(response).toEqual([[], [], []]); + expect(fn).toHaveBeenNthCalledWith(1, "getTagKeys", "action"); + expect(fn).toHaveBeenNthCalledWith(2, "getTagKeys", "analysis"); + expect(fn).toHaveBeenNthCalledWith(3, "getTagKeys", "device"); +}); diff --git a/packages/tcore-sdk/src/Lib/Core/Core.ts b/packages/tcore-sdk/src/Lib/Core/Core.ts new file mode 100644 index 00000000..ce36f022 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/Core/Core.ts @@ -0,0 +1,285 @@ +import { + IAction, + IActionCreate, + IActionEdit, + IActionList, + IActionListQuery, + IActionOption, + IAnalysis, + IAnalysisCreate, + IAnalysisEdit, + IAnalysisList, + IAnalysisListQuery, + IDeviceData, + IDeviceDataQuery, + ICreateDeviceResponse, + IDevice, + IDeviceCreate, + IDeviceEdit, + IDeviceList, + IDeviceListQuery, + IDeviceParameter, + IDeviceParameterCreate, + IDeviceToken, + IDeviceTokenCreate, + IDeviceTokenCreateResponse, + IDeviceTokenListQuery, + ISummary, + TGenericID, + TGenericToken, + ILiveInspectorMessageCreate, + TLiveInspectorConnectionID, +} from "../../Types"; +import APIBridge from "../APIBridge/APIBridge"; + +/** + * Class to manage communication between a plugin and the API. + */ +class Core extends APIBridge { + /** + * Retrieves a list of devices. + * Additional filters can be passed via the query argument. + */ + public async getDeviceList(query?: IDeviceListQuery): Promise { + const response = await this.invokeApiMethod("getDeviceList", query); + return response; + } + + /** + * Retrieves all the information of a single device. + */ + public async getDeviceInfo(id: TGenericID): Promise { + const response = await this.invokeApiMethod("getDeviceInfo", id); + return response; + } + + /** + * Retrieves all the information of a single device via its token. + */ + public async getDeviceByToken(token: TGenericToken): Promise { + const response = await this.invokeApiMethod("getDeviceByToken", token); + return response; + } + + /** + * Edits the information of a single device. + */ + public async editDevice(id: TGenericID, device: IDeviceEdit): Promise { + await this.invokeApiMethod("editDevice", id, device); + } + + /** + * Deletes a device. + */ + public async deleteDevice(id: TGenericID): Promise { + await this.invokeApiMethod("deleteDevice", id); + } + + /** + * Creates a new device. + */ + public async createDevice(params: Omit): Promise { + const response = await this.invokeApiMethod("createDevice", params); + return response; + } + + /** + * Generates and retrieves a new device token. + */ + public async createDeviceToken( + deviceID: TGenericID, + token: Omit + ): Promise { + const response = await this.invokeApiMethod("createDeviceToken", deviceID, token); + return response; + } + + /** + * Retrieves a list of device tokens. + * Additional filters can be passed via the query argument. + */ + public async getDeviceTokenList(deviceID: TGenericID, query?: IDeviceTokenListQuery): Promise { + const response = await this.invokeApiMethod("getDeviceTokenList", deviceID, query); + return response; + } + + /** + * Deletes a device's token. + */ + public async deleteDeviceToken(token: TGenericToken): Promise { + await this.invokeApiMethod("deleteDeviceToken", token); + } + + /** + * Gets all the parameters of a device. + */ + public async getDeviceParamList(deviceID: TGenericID, sentStatus?: Boolean): Promise { + const response = await this.invokeApiMethod("getDeviceParamList", deviceID, sentStatus); + return response; + } + + /** + * Deletes a device's param. + */ + public async deleteDeviceParam(id: TGenericID): Promise { + await this.invokeApiMethod("deleteDeviceParam", id); + } + + /** + * Overrides or edits device parameters. If you want to edit a device parameter, pass the ID + * property inside of an object in the array. + */ + public async setDeviceParams(deviceID: TGenericID, parameters: IDeviceParameterCreate[]): Promise { + await this.invokeApiMethod("setDeviceParams", deviceID, parameters); + } + + /** + * Retrieves the amount of data in a device. + */ + public async getDeviceDataAmount(id: TGenericID): Promise { + const response = await this.invokeApiMethod("getDeviceDataAmount", id); + return response; + } + + /** + * Retrieves a list of all action options. + */ + public async getActionTypes(): Promise { + const response = await this.invokeApiMethod("getActionTypes"); + return response; + } + + /** + * Retrieves a list of actions. + * Additional filters can be passed via the query argument. + */ + public async getActionList(query?: IActionListQuery): Promise { + const response = await this.invokeApiMethod("getActionList", query); + return response; + } + + /** + * Retrieves all the information of a single action. + */ + public async getActionInfo(id: TGenericID): Promise { + const response = await this.invokeApiMethod("getActionInfo", id); + return response; + } + + /** + * Edits the information of a single action. + */ + public async editAction(id: TGenericID, action: IActionEdit): Promise { + const response = await this.invokeApiMethod("editAction", id, action); + return response; + } + + /** + * Deletes a action. + */ + public async deleteAction(id: TGenericID): Promise { + await this.invokeApiMethod("deleteAction", id); + } + + /** + * Creates a new action. + */ + public async createAction(params: Omit): Promise { + const response = await this.invokeApiMethod("createAction", params); + return response; + } + + /** + * Triggers an action. + */ + public async triggerAction(id: TGenericID, data?: any): Promise { + const response = await this.invokeApiMethod("triggerAction", id, data); + return response; + } + + /** + * Retrieves a list of analyses. + * Additional filters can be passed via the query argument. + */ + public async getAnalysisList(query?: IAnalysisListQuery): Promise { + const response = await this.invokeApiMethod("getAnalysisList", query); + return response; + } + + /** + * Retrieves all the information of a single analysis. + */ + public async getAnalysisInfo(id: TGenericID): Promise { + const response = await this.invokeApiMethod("getAnalysisInfo", id); + return response; + } + + /** + * Edits the information of a single analysis. + */ + public async editAnalysis(id: TGenericID, analysis: IAnalysisEdit): Promise { + const response = await this.invokeApiMethod("editAnalysis", id, analysis); + return response; + } + + /** + * Deletes a analysis. + */ + public async deleteAnalysis(id: TGenericID): Promise { + await this.invokeApiMethod("deleteAnalysis", id); + } + + /** + * Creates a new analysis. + */ + public async createAnalysis(params: Omit): Promise { + const response = await this.invokeApiMethod("createAnalysis", params); + return response; + } + + /** + * Retrieves the summary information. + */ + public async getSummary(): Promise { + const response = await this.invokeApiMethod("getSummary"); + return response; + } + + /** + * Adds a data item into a device. + */ + public async addDeviceData(deviceID: TGenericID, data: any): Promise { + await this.invokeApiMethod("addDeviceData", deviceID, data); + } + + /** + * Retrieves data from a device. + * Additional filters can be passed via the query argument. + */ + public async getDeviceData(deviceID: TGenericID, query?: IDeviceDataQuery): Promise { + const response = await this.invokeApiMethod("getDeviceData", deviceID, query); + return response; + } + + /** + * Retrieves all the tag keys of a resource type. + */ + public async getTagKeys(type: "device" | "analysis" | "action"): Promise { + const response = await this.invokeApiMethod("getTagKeys", type); + return response; + } + + /** + * Retrieves all the tag keys of a resource type. + */ + public async emitToLiveInspector( + deviceID: TGenericID, + msg: ILiveInspectorMessageCreate | ILiveInspectorMessageCreate[], + liveInspectorID?: TLiveInspectorConnectionID + ): Promise { + await this.invokeApiMethod("emitToLiveInspector", deviceID, msg, liveInspectorID); + } +} + +const instance = new Core(); +export default instance; diff --git a/packages/tcore-sdk/src/Lib/DatabaseModule/DatabaseModule.ts b/packages/tcore-sdk/src/Lib/DatabaseModule/DatabaseModule.ts new file mode 100644 index 00000000..baaf668b --- /dev/null +++ b/packages/tcore-sdk/src/Lib/DatabaseModule/DatabaseModule.ts @@ -0,0 +1,471 @@ +import { + IAction, + IActionList, + IAnalysis, + IAnalysisList, + IDeviceData, + IDatabaseActionListQuery, + IDatabaseAddAnalysisLogData, + IDatabaseAddStatisticData, + IDatabaseAnalysisListQuery, + IDatabaseDeviceDataCreate, + IDatabaseCreateActionData, + IDatabaseCreateAnalysisData, + IDatabaseCreateDeviceData, + IDatabaseCreateDeviceTokenData, + IDatabaseDeviceListQuery, + IDatabaseEditActionData, + IDatabaseEditAnalysisData, + IDatabaseEditDeviceData, + IDatabaseGetDeviceDataQuery, + IDatabaseGetDeviceTokenListQuery, + IDatabaseSetDeviceParamsData, + IDatabaseSetPluginStorageData, + IDevice, + IDeviceList, + IDeviceParameter, + IDeviceTokenList, + ILog, + IModuleSetupWithoutType, + IStatistic, + ISummary, + TDatabaseGetTagKeysType, + TGenericID, + TGenericToken, + TDeviceType, + IDatabaseDeviceDataEdit, +} from "../../Types"; +import TCoreModule from "../TCoreModule/TCoreModule"; + +/** + * This module allows the creation of a new database connection. + */ +class DatabaseModule extends TCoreModule { + constructor(protected setup: IModuleSetupWithoutType) { + super(setup, "database"); + } + + /** + * Adds data into a device. + */ + public async addDeviceData( + deviceID: TGenericID, + type: TDeviceType, + data: IDatabaseDeviceDataCreate[] + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Edits a device data point. + */ + public async editDeviceData(deviceID: TGenericID, type: TDeviceType, data: IDatabaseDeviceDataEdit[]): Promise { + throw new Error("Method not implemented"); + } + + /** + * Deletes data from a device. + */ + public async deleteDeviceData(deviceID: TGenericID, type: TDeviceType, ids: string[]): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves data from a device using the default query. + */ + public async getDeviceDataDefaultQ( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves from a device the last data item that contains a value. + */ + public async getDeviceDataLastValue( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves from a device the last data item that contains a location. + */ + public async getDeviceDataLastLocation( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves from a device the last data item sorted by descending `time`. + */ + public async getDeviceDataLastItem( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves from a device the last data item sorted by descending `created_at`. + */ + public async getDeviceDataLastInsert( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves from a device the first data item that contains a value. + */ + public async getDeviceDataFirstValue( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves from a device the first data item that contains a location. + */ + public async getDeviceDataFirstLocation( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves from a device the first data item sorted by descending `time`. + */ + public async getDeviceDataFirstItem( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves from a device the first data item sorted by descending `created_at`. + */ + public async getDeviceDataFirstInsert( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves a custom count of the amount of data in a device. + */ + public async getDeviceDataCount( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves the item with the biggest value in a device. + */ + public async getDeviceDataMax( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves the item with the lowest value in a device. + */ + public async getDeviceDataMin( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves the average value of all items in a device. + */ + public async getDeviceDataAvg( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves the sum of all items in a device. + */ + public async getDeviceDataSum( + deviceID: TGenericID, + type: TDeviceType, + query: IDatabaseGetDeviceDataQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves a list of devices. + * Additional filters can be passed via the query argument. + */ + public async getDeviceList(query: IDatabaseDeviceListQuery): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves all the information of a single device. + */ + public async getDeviceInfo(deviceID: TGenericID): Promise { + throw new Error("Method not implemented"); + } + + /** + * Edits the information of a single device. + */ + public async editDevice(deviceID: TGenericID, data: IDatabaseEditDeviceData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Deletes a device. + */ + public async deleteDevice(deviceID: TGenericID): Promise { + throw new Error("Method not implemented"); + } + + /** + * Creates a new device. + */ + public async createDevice(data: IDatabaseCreateDeviceData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves all the information of a single device via its token. + */ + public async getDeviceByToken(token: TGenericToken): Promise { + throw new Error("Method not implemented"); + } + + /** + * Generates and retrieves a new device token. + */ + public async createDeviceToken(deviceID: TGenericID, data: IDatabaseCreateDeviceTokenData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves a list of device tokens.z + * Additional filters can be passed via the query argument. + */ + public async getDeviceTokenList( + deviceID: TGenericID, + query: IDatabaseGetDeviceTokenListQuery + ): Promise { + throw new Error("Method not implemented"); + } + + /** + * Deletes a device's token. + */ + public async deleteDeviceToken(token: TGenericToken): Promise { + throw new Error("Method not implemented"); + } + + /** + * Gets all the parameters of a device. + */ + public async getDeviceParamList(deviceID: TGenericID, sentStatus?: Boolean): Promise { + throw new Error("Method not implemented"); + } + + /** + * Deletes a device's param. + */ + public async deleteDeviceParam(deviceID: TGenericID): Promise { + throw new Error("Method not implemented"); + } + + /** + * Overrides the device parameters. + */ + public async setDeviceParams(deviceID: TGenericID, data: IDatabaseSetDeviceParamsData[]): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves the amount of data in a device. + */ + public async getDeviceDataAmount(deviceID: TGenericID, type: TDeviceType): Promise { + throw new Error("Method not implemented"); + } + + /** + * Empties a device. + */ + public async emptyDevice(deviceID: TGenericID, type: TDeviceType): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves a list of actions. + */ + public async getActionList(query: IDatabaseActionListQuery): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves all the information of an action. + */ + public async getActionInfo(actionID: TGenericID): Promise { + throw new Error("Method not implemented"); + } + + /** + * Edits the information of a single action. + */ + public async editAction(actionID: TGenericID, data: IDatabaseEditActionData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Deletes an action. + */ + public async deleteAction(actionID: TGenericID): Promise { + throw new Error("Method not implemented"); + } + + /** + * Creates a new action. + */ + public async createAction(query: IDatabaseCreateActionData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves a list of analyses. + */ + public async getAnalysisList(query: IDatabaseAnalysisListQuery): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves all the information of an analysis. + */ + public async getAnalysisInfo(analysisID: TGenericID): Promise { + throw new Error("Method not implemented"); + } + + /** + * Edits the information of a single analysis. + */ + public async editAnalysis(analysisID: TGenericID, data: IDatabaseEditAnalysisData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Deletes a analysis. + */ + public async deleteAnalysis(analysisID: TGenericID): Promise { + throw new Error("Method not implemented"); + } + + /** + * Creates a new analysis. + */ + public async createAnalysis(data: IDatabaseCreateAnalysisData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Creates/adds a new log for an analysis. + */ + public async addAnalysisLog(analysisID: TGenericID, data: IDatabaseAddAnalysisLogData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves all the logs of an analysis. + */ + public async getAnalysisLogs(analysisID: TGenericID): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves the summary information. + */ + public async getSummary(): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves a storage item of a plugin. + */ + public async getPluginStorageItem(pluginID: string, key: string): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves all storage item of a plugin. + */ + public async getAllPluginStorageItems(pluginID: string): Promise { + throw new Error("Method not implemented"); + } + + /** + * Creates/edits a storage item of a plugin. + */ + public async setPluginStorageItem(pluginID: string, data: IDatabaseSetPluginStorageData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Deletes a storage item of a plugin. + */ + public async deletePluginStorageItem(pluginID: string, key: string): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves all the tag keys of a resource type. + */ + public async getTagKeys(type: TDatabaseGetTagKeysType): Promise { + throw new Error("Method not implemented"); + } + + /** + * Adds a statistic. + */ + public async addStatistic(isoTime: string, data: IDatabaseAddStatisticData): Promise { + throw new Error("Method not implemented"); + } + + /** + * Retrieves all statistics from the last hour. + */ + public async getHourlyStatistics(): Promise { + throw new Error("Method not implemented"); + } +} + +export default DatabaseModule; diff --git a/packages/tcore-sdk/src/Lib/FileSystemModule/FileSystemModule.ts b/packages/tcore-sdk/src/Lib/FileSystemModule/FileSystemModule.ts new file mode 100644 index 00000000..e61bc628 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/FileSystemModule/FileSystemModule.ts @@ -0,0 +1,26 @@ +import TCoreModule from "../TCoreModule/TCoreModule"; + +/** + * TODO + */ +class FileSystemModule extends TCoreModule { + constructor(protected setup: any) { + super(setup, "filesystem"); + } + + /** + * TODO + */ + public async resolveFile(path: string): Promise { + return Promise.resolve(null); + } + + /** + * TODO + */ + public async resolveFolder(path: string): Promise { + return Promise.resolve([]); + } +} + +export default FileSystemModule; diff --git a/packages/tcore-sdk/src/Lib/Helpers/Helpers.ts b/packages/tcore-sdk/src/Lib/Helpers/Helpers.ts new file mode 100644 index 00000000..ad3304a4 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/Helpers/Helpers.ts @@ -0,0 +1,101 @@ +import { WriteFileOptions } from "fs"; +import { nanoid } from "nanoid"; +import { IComputerUsage } from "../../Types"; +import { generateResourceID, validateResourceID } from "../../Shared/ResourceID"; +import APIBridge from "../APIBridge/APIBridge"; + +/** + * Helper class containing useful functions available to plugin publishers. + */ +class Helpers extends APIBridge { + /** + * Generate a Hex Format ID with 24 characters for resources. + * The ID will be unique and can be used to identify a resource uniquely. + */ + public generateResourceID(): string { + return generateResourceID(); + } + + /** + * Generate a unique live inspector ID to group messages. + */ + public generateLiveInspectorID(): string { + return nanoid(10); + } + + /** + * Checks if a resource ID is valid or not. + */ + public validateResourceID(resourceID: string): boolean { + return validateResourceID(resourceID); + } + + /** + * Retrieves information about the OS. + */ + public async getOSInfo(): Promise<{ arch: string; name: string; platform: string; version: string }> { + return await this.invokeApiMethod("getOSInfo"); + } + + /** + * Checks if a file exists. Returns `true` if it does, `false` if it doesn't. + */ + public async doesFileOrFolderExist(filename: string): Promise { + return await this.invokeApiMethod("doesFileOrFolderExist", filename); + } + + /** + * Creates a new sub-folder in the plugins settings folder. + * This function will recursively create each folder in the path until the last one, which means + * that it will not throw an error if a folder is already created. + */ + public async createFolder(folderPath: string): Promise { + await this.invokeApiMethod("createFolder", folderPath); + } + + /** + * Deletes a file or folder. + */ + public async deleteFileOrFolder(path: string): Promise { + await this.invokeApiMethod("deleteFileOrFolder", path); + } + + /** + * Writes data to the file, replacing the file if it already exists. + * `data` can be a string or a buffer. + */ + public async writeFile(filename: string, data: string, options?: WriteFileOptions): Promise { + await this.invokeApiMethod("writeFile", filename, data, options); + } + + /** + * Reads the entire contents of a file. + */ + public async readFile(filename: string, options?: any): Promise { + return await this.invokeApiMethod("readFile", filename, options); + } + + /** + * Gets the full path of a file via its filename. + */ + public async getFileURI(filename: string): Promise { + return await this.invokeApiMethod("getFileURI", filename); + } + + /** + * Gets the full path of the plugin settings folder. + */ + public async getFolderURI(): Promise { + return await this.invokeApiMethod("getFolderURI"); + } + + /** + * Gets the usage statistics of the computer. + */ + public async getComputerUsage(): Promise { + return await this.invokeApiMethod("getComputerUsage"); + } +} + +const instance = new Helpers(); +export default instance; diff --git a/packages/tcore-sdk/src/Lib/PayloadDecoderModule/PayloadDecoderModule.ts b/packages/tcore-sdk/src/Lib/PayloadDecoderModule/PayloadDecoderModule.ts new file mode 100644 index 00000000..def8c3d3 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/PayloadDecoderModule/PayloadDecoderModule.ts @@ -0,0 +1,20 @@ +import { IModuleSetupWithoutType } from "../../Types"; +import TCoreModule from "../TCoreModule/TCoreModule"; + +/** + * This module allows data to be decoded after it is retrieved from a bucket. + */ +class PayloadDecoderModule extends TCoreModule { + constructor(protected setup: IModuleSetupWithoutType) { + super(setup, "decoder"); + } + + /** + * Called when this payload decoder needs to decode a data structure. + */ + public async onCall(data: any): Promise { + return data; + } +} + +export default PayloadDecoderModule; diff --git a/packages/tcore-sdk/src/Lib/PayloadEncoderModule/PayloadEncoderModule.ts b/packages/tcore-sdk/src/Lib/PayloadEncoderModule/PayloadEncoderModule.ts new file mode 100644 index 00000000..a77fe0f7 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/PayloadEncoderModule/PayloadEncoderModule.ts @@ -0,0 +1,19 @@ +import TCoreModule from "../TCoreModule/TCoreModule"; + +/** + * This module allows data to be encoded before it is inserted into a bucket. + */ +class PayloadEncoderModule extends TCoreModule { + constructor(protected setup: any) { + super(setup, "encoder"); + } + + /** + * Called when this payload encoder needs to encode a data structure. + */ + public async onCall(data: any): Promise { + return data; + } +} + +export default PayloadEncoderModule; diff --git a/packages/tcore-sdk/src/Lib/PluginStorage/PluginStorage.ts b/packages/tcore-sdk/src/Lib/PluginStorage/PluginStorage.ts new file mode 100644 index 00000000..98dd833e --- /dev/null +++ b/packages/tcore-sdk/src/Lib/PluginStorage/PluginStorage.ts @@ -0,0 +1,39 @@ +import APIBridge from "../APIBridge/APIBridge"; + +/** + * Class to manage data storage of your plugin. + */ +class PluginStorage extends APIBridge { + /** + * Retrieves a storage item. + */ + public async get(key: string): Promise { + const response = await this.invokeApiMethod("getPluginStorageItem", key); + return response; + } + + /** + * Creates/edits a storage item. + */ + public async set(key: string, value: any): Promise { + await this.invokeApiMethod("setPluginStorageItem", key, value); + } + + /** + * Deletes a storage item. + */ + public async delete(key: string): Promise { + await this.invokeApiMethod("deletePluginStorageItem", key); + } + + /** + * Retrieves all storage items. + */ + public async getAllItems(): Promise { + const response = await this.invokeApiMethod("getAllPluginStorageItems"); + return response; + } +} + +const instance = new PluginStorage(); +export default instance; diff --git a/packages/tcore-sdk/src/Lib/ServiceModule/ServiceModule.ts b/packages/tcore-sdk/src/Lib/ServiceModule/ServiceModule.ts new file mode 100644 index 00000000..066824c7 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/ServiceModule/ServiceModule.ts @@ -0,0 +1,13 @@ +import { IModuleSetupWithoutType } from "../../Types"; +import TCoreModule from "../TCoreModule/TCoreModule"; + +/** + * This module allows the creation of a service that runs code. + */ +class ServiceModule extends TCoreModule { + constructor(setup: IModuleSetupWithoutType) { + super(setup, "service"); + } +} + +export default ServiceModule; diff --git a/packages/tcore-sdk/src/Lib/TCoreModule/TCoreModule.ts b/packages/tcore-sdk/src/Lib/TCoreModule/TCoreModule.ts new file mode 100644 index 00000000..11bca165 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/TCoreModule/TCoreModule.ts @@ -0,0 +1,179 @@ +import { parentPort } from "worker_threads"; +import { + IModuleMessageOptions, + IModuleSetupWithoutType, + IPluginMessage, + TModuleMessageType, + TPluginType, +} from "../../Types"; +import APIBridge from "../APIBridge/APIBridge"; + +const moduleIDs = new Map(); + +/** + * This is the base module for all modules. + * It contains the communication between the API and this worker. + */ +abstract class TCoreModule { + private started = false; + + constructor(protected setup: IModuleSetupWithoutType, protected type: TPluginType) { + this.attachEvents(); + this.validateSetupID(); + + // sends the init event to the API + const params = { ...this.setup, type: this.type }; + parentPort?.postMessage({ event: "init", params }); + } + + /** + * Shows a message in the module's configuration page. + */ + public async showMessage(type: TModuleMessageType, message: string): Promise { + if (type === "info") { + const color = "hsl(208, 96%, 75%, 0.2)"; + const iconColor = "hsl(208, 96%, 35%, 1)"; + const icon = "exclamation-circle"; + await this.showCustomMessage({ message, icon, iconColor, color }); + } else if (type === "error") { + const color = "hsla(0, 100%, 44%, 0.1)"; + const iconColor = "hsl(0, 100%, 40%)"; + const icon = "warning"; + await this.showCustomMessage({ message, icon, iconColor, color }); + } else if (type === "warning") { + const color = "hsla(44, 100%, 50%, 0.2)"; + const iconColor = "hsl(44, 100%, 21%)"; + const icon = "warning"; + await this.showCustomMessage({ message, icon, iconColor, color }); + } + } + + /** + * Shows a custom message in the module's configuration page. + */ + public async showCustomMessage(args?: IModuleMessageOptions): Promise { + const bridge = new APIBridge(); + try { + await (bridge as any).invokeApiMethod("showMessage", this.setup.id, args); + } finally { + (bridge as any).destroy(); + } + } + + /** + * Hides the custom message in the module's configuration page. + */ + public async hideMessage(): Promise { + const bridge = new APIBridge(); + try { + await (bridge as any).invokeApiMethod("hideMessage", this.setup.id); + } finally { + (bridge as any).destroy(); + } + } + + /** + */ + public async onLoad(configValues: IConfigValues): Promise { + // can be overridden + } + + /** + */ + public async onDestroy(): Promise { + // can be overridden + } + + /** + * Starts or restarts the current plugin. + * This may be called more than once if the user decides to change the settings of the plugin. + */ + protected async start(configValues: IConfigValues) { + if (this.started) { + // already started, let's clean up first + await this.onDestroy(); + } + + await this.onLoad(configValues); + + if (!this.started) { + // module has fully loaded for the first time + const params = { id: this.setup.id }; + parentPort?.postMessage({ event: "firstLoad", params }); + } + + this.started = true; + } + + /** + * Stops this plugin and then sends a message notifying the API. + * + * This function is called by the API. + */ + protected async stop() { + await this.onDestroy(); + this.started = false; + } + + /** + * Attaches the events to listen to messages from the API. + */ + private attachEvents() { + parentPort?.on("message", this.onAPIMessage.bind(this)); + } + + /** + * Called when a message arrives from the API. + * @event + */ + private onAPIMessage(message: IPluginMessage) { + const { method, event, setupID, params, connectionID } = message; + + if (setupID && setupID !== this.setup.id) { + // this message is not for this plugin module, ignore it. + return; + } + + if (event === "executePluginMethod" && method) { + // API wants to invoke a method of this plugin + this.executeMethod(method, params, connectionID); + } + } + + /** + * Executes a method from this module with the given parameters. + * The connectionID must be informed in order to sync the result in the API. + */ + private async executeMethod(method: string, params: any[], connectionID: string) { + const event = "pluginMethodResponse"; + const methodExists = !!this[method]; + + try { + if (methodExists) { + // execute the method and send its result + const result = await this[method](...params); + parentPort?.postMessage({ event, method, params: result, connectionID }); + } else { + // return no message because method doesn't exist + parentPort?.postMessage({ event, method, connectionID }); + } + } catch (error) { + // error while invoking method + const err = error || "Unhandled error"; + parentPort?.postMessage({ event, method, connectionID, error: err }); + } + } + + /** + * Validates if this setup ID is not already being used by another plugin. + * If it is, an error will be thrown. If it's not, then nothing will happen. + */ + private validateSetupID() { + if (moduleIDs.has(this.setup.id)) { + throw new Error(`Setup ID already in use (${this.setup.id})`); + } + moduleIDs.set(this.setup.id, true); + } +} + +export default TCoreModule; diff --git a/packages/tcore-sdk/src/Lib/index.ts b/packages/tcore-sdk/src/Lib/index.ts new file mode 100644 index 00000000..d95ad841 --- /dev/null +++ b/packages/tcore-sdk/src/Lib/index.ts @@ -0,0 +1,23 @@ +import ActionTypeModule from "./ActionTypeModule/ActionTypeModule"; +import ActionTriggerModule from "./ActionTriggerModule/ActionTriggerModule"; +import core from "./Core/Core"; +import DatabaseModule from "./DatabaseModule/DatabaseModule"; +import helpers from "./Helpers/Helpers"; +import PayloadEncoderModule from "./PayloadEncoderModule/PayloadEncoderModule"; +import pluginStorage from "./PluginStorage/PluginStorage"; +import ServiceModule from "./ServiceModule/ServiceModule"; +import FileSystemModule from "./FileSystemModule/FileSystemModule"; +import TCoreModule from "./TCoreModule/TCoreModule"; + +export { + ActionTriggerModule, + ActionTypeModule, + core, + DatabaseModule, + FileSystemModule, + helpers, + PayloadEncoderModule, + pluginStorage, + ServiceModule, + TCoreModule, +}; diff --git a/packages/tcore-sdk/src/Shared/ResourceID.ts b/packages/tcore-sdk/src/Shared/ResourceID.ts new file mode 100644 index 00000000..db809930 --- /dev/null +++ b/packages/tcore-sdk/src/Shared/ResourceID.ts @@ -0,0 +1,29 @@ +import { customAlphabet } from "nanoid"; + +const hexAlphabet = "1234567890abcdef"; +const nanoid = customAlphabet(hexAlphabet, 20); + +/** + * Generate a Hex Format ID with 24 characters for resources. + * The ID will be unique and can be used to identify a resource uniquely. + */ +export function generateResourceID(): string { + const firstCase = String(Date.now()).slice(0, 2).split("").reverse().join(""); + const secondCase = Buffer.from([Number(String(Date.now()).slice(2, 4))]).toString("hex"); + return `${firstCase}${secondCase}${nanoid()}`; +} + +/** + * Checks if a resource ID is valid or not. + * @param id ResourceID + * @returns Boolean + */ +export function validateResourceID(id?: string): boolean { + const idSafe = String(id); + + if (idSafe.length != 24) { + return false; + } + + return true; +} diff --git a/packages/tcore-sdk/src/Types/Action.types.ts b/packages/tcore-sdk/src/Types/Action.types.ts new file mode 100644 index 00000000..ce59b9f1 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Action.types.ts @@ -0,0 +1,153 @@ +import { z } from "zod"; +import { generateResourceID } from "../Shared/ResourceID"; +import { zPluginConfigField, IPluginConfigField } from "./Plugin.types"; +import { zQuery, zName, zObjectID, zActiveAutoGen, zTagsAutoGen } from "./Common/Common.types"; +import { zTags } from "./Tag.types"; +import preprocessBoolean from "./Helpers/preprocessBoolean"; +import preprocessObject from "./Helpers/preprocessObject"; +import removeNullValues from "./Helpers/removeNullValues"; + +/** + * Base configuration of an action. + */ +export const zAction = z.object({ + action: z.any(), + active: z.boolean(), + created_at: z.date(), + description: z.string().nullish(), + device_info: z + .object({ id: zObjectID }) + .or(z.object({ tag_key: z.string().nonempty(), tag_value: z.string().nonempty() })) + .optional() + .nullish(), + id: zObjectID, + last_triggered: z.date().nullish(), + name: zName, + tags: zTags, + trigger: z.any().optional(), + type: z.string(), + updated_at: z.date().nullish(), +}); + +/** + * Configuration to create a new action. + */ +export const zActionCreate = zAction + .omit({ + last_triggered: true, + created_at: true, + id: true, + updated_at: true, + }) + .extend({ + active: zActiveAutoGen, + tags: zTagsAutoGen, + }) + .transform((x) => + removeNullValues({ + ...x, + created_at: new Date(), + id: generateResourceID(), + }) + ); + +/** + * Configuration to edit an existing Action. + */ +export const zActionEdit = zAction + .omit({ + id: true, + created_at: true, + }) + .extend({ + active: zAction.shape.active.nullish(), + tags: zAction.shape.tags.nullish(), + }) + .partial(); + +/** + * Configuration of the action list. + */ +export const zActionList = z.array( + zAction.partial().extend({ + id: zObjectID, + tags: zTags, + }) +); + +/** + * Allowed fields in an action list query. + */ +const zActionListQueryFields = z.enum([ + "id", + "name", + "tags", + "active", + "trigger", + "action", + "last_triggered", + "created_at", + "updated_at", + "type", + "device_info", + "*", +]); + +/** + * Configuration to query the action list. + */ +export const zActionListQuery = zQuery.extend({ + filter: z.preprocess( + preprocessObject, + z + .object({ + id: zObjectID.or(z.array(zObjectID)), + tags: zTags, + name: z.string(), + active: z.preprocess(preprocessBoolean, z.boolean()), + type: z.string(), + }) + .partial() + .nullish() + .transform((x) => x ?? {}) + ), + fields: z + .array(zActionListQueryFields) + .nullish() + .transform((x) => { + const values = x || ["id", "name", "tags"]; + if (!values.includes("id")) values.push("id"); + if (!values.includes("tags")) values.push("tags"); + return values; + }), + orderBy: z + .tuple([zActionListQueryFields, z.enum(["asc", "desc"])]) + .nullish() + .transform((x) => x ?? ["name", "asc"]), +}); + +/** + * Action types from plugins. + */ +export const zActionType = z.object({ + configs: z.array(zPluginConfigField), + description: z.string(), + id: z.string(), + name: z.string(), + showDeviceSelector: z.boolean(), +}); + +export type IAction = z.infer; +export type IActionCreate = z.infer; +export type IActionEdit = z.infer; +export type IActionType = z.infer; +export type IActionList = z.infer; +export type IActionListQuery = z.input; + +export interface IActionOption { + description?: string; + icon: string; + name: string; + configs?: IPluginConfigField[]; + id: string; +} diff --git a/packages/tcore-sdk/src/Types/Analysis.types.ts b/packages/tcore-sdk/src/Types/Analysis.types.ts new file mode 100644 index 00000000..b32e1735 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Analysis.types.ts @@ -0,0 +1,149 @@ +import { z } from "zod"; +import { zTags } from "./Tag.types"; +import { + zDateAutoGen, + zActiveAutoGen, + zName, + zObjectID, + zTagsAutoGen, + zQuery, + zObjectIDAutoGen, +} from "./Common/Common.types"; +import { zLog } from "./Log.types"; +import preprocessBoolean from "./Helpers/preprocessBoolean"; +import preprocessObject from "./Helpers/preprocessObject"; +import createQueryOrderBy from "./Helpers/createQueryOrderBy"; + +export interface IAnalysisVariable { + key: string; + value: string; +} + +/** + * Configuration of a single environment variable. + */ +export const zEnvironmentVariable = z.object({ + key: z.string().nonempty(), + value: z.string().nonempty(), +}); + +/** + * Base configuration of an analysis. + */ +export const zAnalysis = z.object({ + active: z.boolean(), + binary_path: z.string().nullable(), + console: z.array(zLog), + created_at: z.date(), + file_path: z.string().nullable(), + id: zObjectID, + last_run: z.date().nullish(), + name: zName, + options: z.any(), + tags: zTags, + updated_at: z.date().nullish(), + variables: z.array(zEnvironmentVariable), +}); + +/** + * Configuration to create a new analysis. + */ +export const zAnalysisCreate = zAnalysis + .partial() + .omit({ console: true, id: true, last_run: true }) + .extend({ + active: zActiveAutoGen, + created_at: zDateAutoGen, + id: zObjectIDAutoGen, + tags: zTagsAutoGen, + variables: z + .array(zEnvironmentVariable) + .optional() + .transform((x) => x ?? []) + .or(z.undefined()), + }); + +/** + * Configuration to edit an existing analysis. + */ +export const zAnalysisEdit = zAnalysis + .partial() + .omit({ + id: true, + console: true, + updated_at: true, + created_at: true, + }) + .extend({ + updated_at: zDateAutoGen.or(z.undefined()), + }); + +/** + * Configuration of the analysis list. + */ +export const zAnalysisList = z.array( + zAnalysis.partial().extend({ + id: zObjectID, + tags: zTags, + }) +); + +/** + * Configuration of the analysis log list. + */ +export const zAnalysisLogList = z.array(zLog.extend({ analysis_id: zObjectID })); + +/** + * Allowed fields in an analysis list query. + */ +const zAnalysisListQueryFields = z.enum([ + "id", + "name", + "tags", + "active", + "last_run", + "binary_path", + "file_path", + "created_at", + "updated_at", + "variables", + "*", +]); + +/** + * Configuration to query the analysis list. + */ +export const zAnalysisListQuery = zQuery.extend({ + filter: z.preprocess( + preprocessObject, + z + .object({ + id: zObjectID.or(z.array(zObjectID)), + tags: zTags, + name: z.string(), + active: z.preprocess(preprocessBoolean, z.boolean()), + binary_path: z.string(), + file_path: z.string(), + }) + .partial() + .nullish() + .transform((x) => x ?? {}) + ), + fields: z + .array(zAnalysisListQueryFields) + .nullish() + .transform((x) => { + const values = x || ["id", "name", "tags"]; + if (!values.includes("id")) values.push("id"); + if (!values.includes("tags")) values.push("tags"); + return values; + }), + orderBy: createQueryOrderBy(zAnalysisListQueryFields), +}); + +export type IAnalysis = z.infer; +export type IAnalysisCreate = z.infer; +export type IAnalysisEdit = z.infer; +export type IAnalysisList = z.infer; +export type IAnalysisListQuery = z.input; +export type IAnalysisLogList = z.infer; diff --git a/packages/tcore-sdk/src/Types/Common/Common.types.test.ts b/packages/tcore-sdk/src/Types/Common/Common.types.test.ts new file mode 100644 index 00000000..c398ec46 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Common/Common.types.test.ts @@ -0,0 +1,335 @@ +import { validateResourceID } from ".."; +import { IQuery, zActiveAutoGen, zDateAutoGen, zObjectIDAutoGen, zQuery, zTagsAutoGen } from "./Common.types"; + +describe("zTagsAutoGen", () => { + test("parses null", () => { + const parsed = zTagsAutoGen.parse(null); + expect(parsed).toEqual([]); + }); + + test("parses undefined", () => { + const parsed = zTagsAutoGen.parse(undefined); + expect(parsed).toEqual([]); + }); + + test("parses empty array", () => { + const parsed = zTagsAutoGen.parse([]); + expect(parsed).toEqual([]); + }); + + test("parses correct array", () => { + const parsed = zTagsAutoGen.parse([{ key: "hello", value: "world" }]); + expect(parsed).toEqual([{ key: "hello", value: "world" }]); + }); + + test("throws error if key is missing", () => { + const fn = () => zTagsAutoGen.parse([{ value: "world" }]); + expect(fn).toThrowError(); + }); + + test("throws error if value is missing", () => { + const fn = () => zTagsAutoGen.parse([{ key: "hello" }]); + expect(fn).toThrowError(); + }); + + test("doesn't throw if key is empty", () => { + const parsed = zTagsAutoGen.parse([{ key: "", value: "world" }]); + expect(parsed).toEqual([{ key: "", value: "world" }]); + }); + + test("doesn't throw if value is empty", () => { + const parsed = zTagsAutoGen.parse([{ key: "hello", value: "" }]); + expect(parsed).toEqual([{ key: "hello", value: "" }]); + }); +}); + +describe("zActiveAutoGen", () => { + test("parses null", () => { + const parsed = zActiveAutoGen.parse(null); + expect(parsed).toEqual(true); + }); + + test("parses undefined", () => { + const parsed = zActiveAutoGen.parse(undefined); + expect(parsed).toEqual(true); + }); + + test("parses false", () => { + const parsed = zActiveAutoGen.parse(false); + expect(parsed).toEqual(false); + }); + + test("parses true", () => { + const parsed = zActiveAutoGen.parse(true); + expect(parsed).toEqual(true); + }); + + test("throws error if value is a number", () => { + const fn = () => zTagsAutoGen.parse(1); + expect(fn).toThrowError(); + }); + + test("throws error if value is a string", () => { + const fn = () => zTagsAutoGen.parse("true"); + expect(fn).toThrowError(); + }); +}); + +describe("zDateAutoGen", () => { + test("parses null", () => { + const parsed = zDateAutoGen.parse(null); + const diffNow = Date.now() - parsed.getTime(); + expect(diffNow).toBeLessThan(100); + }); + + test("parses undefined", () => { + const parsed = zDateAutoGen.parse(undefined); + const diffNow = Date.now() - parsed.getTime(); + expect(diffNow).toBeLessThan(100); + }); + + test("always generates a new date", () => { + const parsed = zDateAutoGen.parse(new Date("2020-01-01")); + const diffNow = Date.now() - parsed.getTime(); + expect(diffNow).toBeLessThan(100); + }); +}); + +describe("zDateAutoGen", () => { + test("parses null", () => { + const parsed = zDateAutoGen.parse(null); + const diffNow = Date.now() - parsed.getTime(); + expect(diffNow).toBeLessThan(100); + }); + + test("parses undefined", () => { + const parsed = zDateAutoGen.parse(undefined); + const diffNow = Date.now() - parsed.getTime(); + expect(diffNow).toBeLessThan(100); + }); + + test("always generates a new date", () => { + const parsed = zDateAutoGen.parse(new Date("2020-01-01")); + const diffNow = Date.now() - parsed.getTime(); + expect(diffNow).toBeLessThan(100); + }); +}); + +describe("zObjectIDAutoGen", () => { + test("parses null", () => { + const parsed = zObjectIDAutoGen.parse(null); + expect(validateResourceID(parsed)).toEqual(true); + }); + + test("parses undefined", () => { + const parsed = zObjectIDAutoGen.parse(null); + expect(validateResourceID(parsed)).toEqual(true); + }); + + test("always generates a new date", () => { + const parsed = zObjectIDAutoGen.parse(null); + expect(validateResourceID(parsed)).toEqual(true); + }); +}); + +describe("zQuery", () => { + test("parses empty object", () => { + const data: IQuery = {}; + const parsed = zQuery.parse(data); + expect(parsed).toEqual({ page: 1, amount: 20, fields: [], filter: {}, orderBy: ["name", "asc"] }); + }); + + test("parses page correctly", () => { + const data: IQuery = { page: 10 }; + const parsed = zQuery.parse(data); + expect(parsed.page).toEqual(10); + }); + + test("parses empty page", () => { + const data: IQuery = {}; + const parsed = zQuery.parse(data); + expect(parsed.page).toEqual(1); + }); + + test("parses page as null", () => { + const data: IQuery = { page: null }; + const parsed = zQuery.parse(data); + expect(parsed.page).toEqual(1); + }); + + test("parses page as undefined", () => { + const data: IQuery = { page: undefined }; + const parsed = zQuery.parse(data); + expect(parsed.page).toEqual(1); + }); + + test("parses page as string", () => { + const data = { page: "12" }; + const parsed = zQuery.parse(data); + expect(parsed.page).toEqual(12); + }); + + test("throws error if page is not a number", () => { + expect(() => zQuery.parse({ page: "abc" })).toThrowError(); + expect(() => zQuery.parse({ page: true })).toThrowError(); + expect(() => zQuery.parse({ page: false })).toThrowError(); + }); + + test("parses amount correctly", () => { + const data: IQuery = { amount: 10 }; + const parsed = zQuery.parse(data); + expect(parsed.amount).toEqual(10); + }); + + test("parses empty amount", () => { + const data: IQuery = {}; + const parsed = zQuery.parse(data); + expect(parsed.amount).toEqual(20); + }); + + test("parses amount as null", () => { + const data: IQuery = { amount: null }; + const parsed = zQuery.parse(data); + expect(parsed.amount).toEqual(20); + }); + + test("parses amount as undefined", () => { + const data: IQuery = { amount: undefined }; + const parsed = zQuery.parse(data); + expect(parsed.amount).toEqual(20); + }); + + test("parses amount as string", () => { + const data = { amount: "12" }; + const parsed = zQuery.parse(data); + expect(parsed.amount).toEqual(12); + }); + + test("throws error if amount is not a number", () => { + expect(() => zQuery.parse({ amount: "abc" })).toThrowError(); + expect(() => zQuery.parse({ amount: true })).toThrowError(); + expect(() => zQuery.parse({ amount: false })).toThrowError(); + }); + + test("parses fields correctly", () => { + const data: IQuery = { fields: ["id", "last_input"] }; + const parsed = zQuery.parse(data); + expect(parsed.fields).toEqual(["id", "last_input"]); + }); + + test("parses empty fields", () => { + const data: IQuery = {}; + const parsed = zQuery.parse(data); + expect(parsed.fields).toEqual([]); + }); + + test("parses fields as null", () => { + const data: IQuery = { fields: null }; + const parsed = zQuery.parse(data); + expect(parsed.fields).toEqual([]); + }); + + test("parses fields as undefined", () => { + const data: IQuery = { fields: undefined }; + const parsed = zQuery.parse(data); + expect(parsed.fields).toEqual([]); + }); + + test("throws error if fields is not an array", () => { + expect(() => zQuery.parse({ fields: "abc" })).toThrowError(); + expect(() => zQuery.parse({ fields: true })).toThrowError(); + expect(() => zQuery.parse({ fields: false })).toThrowError(); + expect(() => zQuery.parse({ fields: 1234 })).toThrowError(); + }); + + test("parses filter correctly", () => { + const data: IQuery = { filter: { name: "myDevice" } }; + const parsed = zQuery.parse(data); + expect(parsed.filter).toEqual({ name: "myDevice" }); + }); + + test("parses empty filter", () => { + const data: IQuery = {}; + const parsed = zQuery.parse(data); + expect(parsed.filter).toEqual({}); + }); + + test("parses filter as null", () => { + const data: IQuery = { filter: null }; + const parsed = zQuery.parse(data); + expect(parsed.filter).toEqual({}); + }); + + test("parses filter as undefined", () => { + const data: IQuery = { filter: undefined }; + const parsed = zQuery.parse(data); + expect(parsed.filter).toEqual({}); + }); + + test("throws error if filter is not an object", () => { + expect(() => zQuery.parse({ filter: [] })).toThrowError(); + expect(() => zQuery.parse({ filter: "abc" })).toThrowError(); + expect(() => zQuery.parse({ filter: true })).toThrowError(); + expect(() => zQuery.parse({ filter: false })).toThrowError(); + expect(() => zQuery.parse({ filter: 1234 })).toThrowError(); + }); + + test("parses orderBy correctly", () => { + const data: IQuery = { orderBy: ["id", "asc"] }; + const parsed = zQuery.parse(data); + expect(parsed.orderBy).toEqual(["id", "asc"]); + }); + + test("parses orderBy as string", () => { + const data: IQuery = { orderBy: "name,asc" }; + const parsed = zQuery.parse(data); + expect(parsed.orderBy).toEqual(["name", "asc"]); + }); + + test("parses orderBy with descending order", () => { + const data: IQuery = { orderBy: ["id", "desc"] }; + const parsed = zQuery.parse(data); + expect(parsed.orderBy).toEqual(["id", "desc"]); + }); + + test("parses empty orderBy", () => { + const data: IQuery = {}; + const parsed = zQuery.parse(data); + expect(parsed.orderBy).toEqual(["name", "asc"]); + }); + + test("parses orderBy as null", () => { + const data: IQuery = { orderBy: null }; + const parsed = zQuery.parse(data); + expect(parsed.orderBy).toEqual(["name", "asc"]); + }); + + test("parses orderBy as undefined", () => { + const data: IQuery = { orderBy: undefined }; + const parsed = zQuery.parse(data); + expect(parsed.orderBy).toEqual(["name", "asc"]); + }); + + test("throws error if orderBy is not a tuple", () => { + expect(() => zQuery.parse({ orderBy: {} })).toThrowError(); + expect(() => zQuery.parse({ orderBy: [] })).toThrowError(); + expect(() => zQuery.parse({ orderBy: "abc" })).toThrowError(); + expect(() => zQuery.parse({ orderBy: "name,ASC" })).toThrowError(); + expect(() => zQuery.parse({ orderBy: "name,DESC" })).toThrowError(); + expect(() => zQuery.parse({ orderBy: "name, asc" })).toThrowError(); + expect(() => zQuery.parse({ orderBy: "name, desc" })).toThrowError(); + expect(() => zQuery.parse({ orderBy: ",asc" })).toThrowError(); + expect(() => zQuery.parse({ orderBy: ",desc" })).toThrowError(); + expect(() => zQuery.parse({ orderBy: true })).toThrowError(); + expect(() => zQuery.parse({ orderBy: false })).toThrowError(); + expect(() => zQuery.parse({ orderBy: 1234 })).toThrowError(); + }); + + test("throws error if orderBy configuration is incorrect", () => { + expect(() => zQuery.parse({ orderBy: [123, "asc"] })).toThrowError(); + expect(() => zQuery.parse({ orderBy: ["name", "ASC"] })).toThrowError(); + expect(() => zQuery.parse({ orderBy: ["name", "DESC"] })).toThrowError(); + expect(() => zQuery.parse({ orderBy: [true, "asc"] })).toThrowError(); + expect(() => zQuery.parse({ orderBy: ["name"] })).toThrowError(); + }); +}); diff --git a/packages/tcore-sdk/src/Types/Common/Common.types.ts b/packages/tcore-sdk/src/Types/Common/Common.types.ts new file mode 100644 index 00000000..55bbbb8b --- /dev/null +++ b/packages/tcore-sdk/src/Types/Common/Common.types.ts @@ -0,0 +1,86 @@ +import { z } from "zod"; +import preprocessNumber from "../Helpers/preprocessNumber"; +import { generateResourceID } from "../../Shared/ResourceID"; +import { zTag } from "../Tag.types"; +import { parseSafe } from "../Helpers"; +import createQueryOrderBy from "../Helpers/createQueryOrderBy"; + +/** + * Configuration to query a list. + */ +export const zQuery = z.object({ + page: z + .preprocess(preprocessNumber, z.number()) + .nullish() + .transform((x) => x ?? 1), + amount: z + .preprocess(preprocessNumber, z.number()) + .nullish() + .transform((x) => x ?? 20), + fields: z + .array(z.string()) + .nullish() + .transform((x) => x ?? []), + filter: z + .any() + .nullish() + .refine((x) => x === null || x === undefined || typeof x === "object", "Filter must be an object") + .transform((x) => parseSafe(x, {})) + .refine((x) => !Array.isArray(x), "Filter must be an object"), + orderBy: createQueryOrderBy(z.string()), +}); + +/** + * Configuration of a name field. + */ +export const zName = z.string().min(3).max(100); + +/** + * Configuration of an ID field. + */ +export const zObjectID = z.string(); + +/** + * Configuration of an auto-generated id when parsed. + */ +export const zObjectIDAutoGen = z + .string() + .nullish() + .transform(() => generateResourceID()); + +/** + * Configuration of a token field. + */ +export const zToken = z.string(); + +/** + * For auto-generated date fields. + * This zod field will acquire the current date when parsed. + */ +export const zDateAutoGen = z + .date() + .nullish() + .transform(() => new Date()); // use transform instead of `default` because `default` doesn't apply to `null`. + +/** + * For `active` fields. + * This zod field will set `false` as default if the active is null or undefined. + */ +export const zActiveAutoGen = z + .boolean() + .nullish() + .transform((e) => e ?? true); // use transform instead of `default` because `default` doesn't apply to `null`. + +/** + * For `tags` fields. + * This zod field will set [] as default if the tags are null or undefined. + */ +export const zTagsAutoGen = z + .array(zTag) + .nullish() + .transform((e) => e ?? []); // use transform instead of `default` because `default` doesn't apply to `null`. + +export type TGenericID = string; +export type TGenericToken = string; +export type TDate = Date | number | null; +export type IQuery = z.input; diff --git a/packages/tcore-sdk/src/Types/Common/Icon.types.ts b/packages/tcore-sdk/src/Types/Common/Icon.types.ts new file mode 100644 index 00000000..3f1ba506 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Common/Icon.types.ts @@ -0,0 +1,106 @@ +import { z } from "zod"; + +// ! This file is automatically generated. Please don't change it. + +/** + * Types of icons available in the system. + * Each one must match the corresponding filename in the tcore-console/assets/icons folder. + */ +export const zIcon = z.enum([ + "action", + "analysis", + "apple", + "ban", + "bars", + "battery-full", + "brackets", + "brush", + "bucket", + "bullhorn", + "caret-down", + "caret-right", + "caret-up", + "certificate", + "check", + "chevron-left", + "chevron-right", + "circle", + "clock", + "cloud", + "cog", + "comment-dots", + "computer", + "connector", + "copy", + "cube", + "cubes", + "database", + "device-union", + "device", + "dice-d20", + "download", + "drive", + "ellipsis-v", + "envelope", + "exclamation-circle", + "external-link-alt", + "eye", + "file-import", + "file", + "floppy", + "folder", + "github", + "globe-americas", + "globe", + "grip-horizontal", + "hashtag", + "home", + "image", + "io", + "key", + "link", + "linux", + "list", + "lock", + "markdown", + "memory", + "microchip", + "minus", + "mobile-alt", + "moon-dark", + "moon-light", + "mountain", + "network", + "pause", + "pencil", + "play", + "plugin", + "plus-circle", + "plus", + "question-circle", + "raspberry-pi", + "redo", + "scroll", + "search", + "shapes", + "sign-out", + "snowflake", + "spinner", + "star", + "stopwatch", + "store", + "sync", + "tag", + "tcore", + "temperature-high", + "th-large", + "times", + "trash", + "user-alt", + "warning", + "wifi", + "window", + "windows", +]); + +export type TIcon = z.infer; diff --git a/packages/tcore-sdk/src/Types/Connector.types.ts b/packages/tcore-sdk/src/Types/Connector.types.ts new file mode 100644 index 00000000..ace74f89 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Connector.types.ts @@ -0,0 +1,42 @@ +import { INetworkDeviceParameter, TGenericID } from "./index"; + +export interface IConnectorCreate { + name?: string; + description?: string; + logo_url?: string; + device_parameters?: INetworkDeviceParameter[]; + networks?: string[]; + payload_decoder?: string; + install_text?: string; + install_end_text?: string; + device_annotation?: string; +} + +export interface IConnector extends IConnectorCreate { + id: TGenericID; + public: boolean; + description?: string; + logo_url?: string; + created_at: Date; + updated_at: Date; + device_parameters?: INetworkDeviceParameter[]; + networks?: string[]; + install_text?: string; + install_end_text?: string; + device_annotation?: string; +} + +export type IConnectorListQuery = any; + +// export type IConnectorListQuery = Query< +// IConnector, +// | "name" +// | "id" +// | "description" +// | "logo_url" +// | "install_text" +// | "install_end_text" +// | "device_annotation" +// | "payload_decoder" +// | "networks" +// >; diff --git a/packages/tcore-sdk/src/Types/DatabaseModule/DatabaseModule.types.ts b/packages/tcore-sdk/src/Types/DatabaseModule/DatabaseModule.types.ts new file mode 100644 index 00000000..ae8d62cf --- /dev/null +++ b/packages/tcore-sdk/src/Types/DatabaseModule/DatabaseModule.types.ts @@ -0,0 +1,116 @@ +import { z } from "zod"; +import { + ILog, + IStatisticCreate, + zActionCreate, + zActionEdit, + zActionListQuery, + zAnalysisCreate, + zAnalysisEdit, + zAnalysisListQuery, + zDeviceDataCreate, + zDeviceDataQuery, + zDeviceCreate, + zDeviceEdit, + zDeviceListQuery, + zDeviceParameterCreate, + zDeviceTokenCreate, + zDeviceTokenListQuery, + zPluginStorageItemSet, + zDeviceDataUpdate, +} from ".."; + +/** + * Data parameter of the `addDeviceData` function. + */ +export type IDatabaseDeviceDataCreate = z.output; + +/** + * Data parameter of the `editDeviceData` function. + */ +export type IDatabaseDeviceDataEdit = z.output; + +/** + * Data parameter of the `getDeviceData` functions. + */ +export type IDatabaseGetDeviceDataQuery = Omit, "details">; + +/** + * Data parameter of the `addStatistic` function. + */ +export type IDatabaseAddStatisticData = IStatisticCreate; + +/** + * Data parameter of the `setPluginStorageItem` function. + */ +export type IDatabaseSetPluginStorageData = z.output; + +/** + * Data parameter of the `addAnalysisLog` function. + */ +export type IDatabaseAddAnalysisLogData = ILog; + +/** + * Data parameter of the `createAnalysis` function. + */ +export type IDatabaseCreateAnalysisData = z.infer; + +/** + * Data parameter of the `editAnalysis` function. + */ +export type IDatabaseEditAnalysisData = z.infer; + +/** + * Data parameter of the `getAnalysisList` function. + */ +export type IDatabaseAnalysisListQuery = z.infer; + +/** + * Data parameter of the `createAction` function. + */ +export type IDatabaseCreateActionData = z.infer; + +/** + * Data parameter of the `editAction` function. + */ +export type IDatabaseEditActionData = z.infer; + +/** + * Data parameter of the `getActionList` function. + */ +export type IDatabaseActionListQuery = z.infer; + +/** + * Data parameter of the `createDevice` function. + */ +export type IDatabaseCreateDeviceData = z.infer; + +/** + * Data parameter of the `editDevice` function. + */ +export type IDatabaseEditDeviceData = z.infer; + +/** + * Data parameter of the `getDeviceList` function. + */ +export type IDatabaseDeviceListQuery = z.infer; + +/** + * Data parameter of the `setDeviceParams` function. + */ +export type IDatabaseSetDeviceParamsData = z.infer; + +/** + * Query parameter of the `getDeviceTokenList` function. + */ +export type IDatabaseGetDeviceTokenListQuery = z.infer; + +/** + * Data parameter of the `createDeviceToken` function. + */ +export type IDatabaseCreateDeviceTokenData = Omit, "device_id">; + +/** + * Type parameter of the `getTagKeys` function. + */ +export type TDatabaseGetTagKeysType = "action" | "analysis" | "device"; diff --git a/packages/tcore-sdk/src/Types/Device/Device.types.test.ts b/packages/tcore-sdk/src/Types/Device/Device.types.test.ts new file mode 100644 index 00000000..fa6a5aac --- /dev/null +++ b/packages/tcore-sdk/src/Types/Device/Device.types.test.ts @@ -0,0 +1,343 @@ +import { generateResourceID, validateResourceID } from "../../Shared/ResourceID"; +import { + IDeviceEdit, + IDeviceCreate, + zDeviceEdit, + zDeviceCreate, + IDeviceListQuery, + zDeviceListQuery, + zDeviceParameter, + IDeviceParameter, +} from "./Device.types"; + +describe("zDeviceParameter", () => { + test("parses simple object", () => { + const data: IDeviceParameter = { id: "123", key: "", value: "" }; + const parsed = zDeviceParameter.parse(data); + expect(parsed.key).toEqual(""); + }); +}); + +describe("zDeviceCreate", () => { + test("parses object with only name", () => { + const data: IDeviceCreate = { name: "Device #1" }; + const parsed = zDeviceCreate.parse(data); + expect(validateResourceID(parsed.id)).toEqual(true); + expect(parsed.name).toEqual("Device #1"); + expect(parsed.tags).toEqual([]); + expect(parsed.active).toEqual(true); + expect(parsed.payload_parser).toBeUndefined(); + expect(parsed.created_at).toBeInstanceOf(Date); + }); + + test("throws error if name has less than 3 characters", () => { + const data: IDeviceCreate = { name: "AB" }; + const fn = () => zDeviceCreate.parse(data); + expect(fn).toThrowError(); + }); + + test("parses active as false", () => { + const data: IDeviceCreate = { name: "Device #1", active: false }; + const parsed = zDeviceCreate.parse(data); + expect(parsed.active).toEqual(false); + }); + + test("parses active as undefined", () => { + const data: IDeviceCreate = { name: "Device #1", active: undefined }; + const parsed = zDeviceCreate.parse(data); + expect(parsed.active).toEqual(true); + }); + + test("parses active as null", () => { + const data: IDeviceCreate = { name: "Device #1", active: null }; + const parsed = zDeviceCreate.parse(data); + expect(parsed.active).toEqual(true); + }); + + test("throws error if active is not boolean", () => { + expect(() => zDeviceCreate.parse({ name: "ABC", active: "abc" })).toThrowError(); + expect(() => zDeviceCreate.parse({ name: "ABC", active: 123 })).toThrowError(); + }); + + test("ignores created_at", () => { + const created_at = new Date("2020-01-01T15:00:00Z"); + const data = { name: "Device #1", created_at }; + const parsed = zDeviceCreate.parse(data); + const diffNow = Date.now() - parsed.created_at.getTime(); + expect(diffNow).toBeLessThan(100); + }); + + test("ignores id", () => { + const id = generateResourceID(); + const data = { name: "Device #1", id }; + const parsed = zDeviceCreate.parse(data); + expect(parsed.id).not.toEqual(id); + }); + + test("parses tags", () => { + const data: IDeviceCreate = { name: "Device #1", tags: [{ key: "hello", value: "world" }] }; + const parsed = zDeviceCreate.parse(data); + expect(parsed.tags).toEqual([{ key: "hello", value: "world" }]); + }); + + test("parses tags as undefined", () => { + const data: IDeviceCreate = { name: "Device #1", tags: undefined }; + const parsed = zDeviceCreate.parse(data); + expect(parsed.tags).toEqual([]); + }); + + test("parses tags as null", () => { + const data: IDeviceCreate = { name: "Device #1", tags: null }; + const parsed = zDeviceCreate.parse(data); + expect(parsed.tags).toEqual([]); + }); + + test("parses payload_parser", () => { + const data: IDeviceCreate = { name: "Device #1", payload_parser: "/parser.js" }; + const parsed = zDeviceCreate.parse(data); + expect(parsed.payload_parser).toEqual("/parser.js"); + }); +}); + +describe("zDeviceEdit", () => { + test("parses object with only name", () => { + const data: IDeviceEdit = { name: "Device #1" }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.name).toEqual("Device #1"); + expect(parsed.active).toBeUndefined(); + expect(parsed.last_input).toBeUndefined(); + expect(parsed.last_output).toBeUndefined(); + expect(parsed.payload_parser).toBeUndefined(); + expect(parsed.tags).toBeUndefined(); + expect(parsed.updated_at).toBeUndefined(); + }); + + test("parses active as false", () => { + const data: IDeviceEdit = { active: false }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.active).toEqual(false); + }); + + test("parses active as undefined", () => { + const data: IDeviceEdit = { active: undefined }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.active).toBeUndefined(); + }); + + test("parses active as null", () => { + const data: IDeviceEdit = { active: null }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.active).toBeNull(); + }); + + test("throws error if active is not boolean", () => { + expect(() => zDeviceEdit.parse({ active: "abc" })).toThrowError(); + expect(() => zDeviceEdit.parse({ active: 123 })).toThrowError(); + }); + + test("ignores id", () => { + const id = generateResourceID(); + const data = { id }; + const parsed = zDeviceEdit.parse(data); + expect(parsed).not.toHaveProperty("id"); + }); + + test("parses tags", () => { + const data: IDeviceEdit = { tags: [{ key: "hello", value: "world" }] }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.tags).toEqual([{ key: "hello", value: "world" }]); + }); + + test("parses tags as undefined", () => { + const data: IDeviceEdit = { tags: undefined }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.tags).toBeUndefined(); + }); + + test("parses tags as null", () => { + const data: IDeviceEdit = { tags: null }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.tags).toBeNull(); + }); + + test("throws error if tags is not array", () => { + expect(() => zDeviceEdit.parse({ tags: false })).toThrowError(); + expect(() => zDeviceEdit.parse({ tags: 123 })).toThrowError(); + expect(() => zDeviceEdit.parse({ tags: "abc" })).toThrowError(); + }); + + test("parses payload_parser", () => { + const data: IDeviceEdit = { name: "Device #1", payload_parser: "/parser.js" }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.payload_parser).toEqual("/parser.js"); + }); + + test("parses payload_parser as undefined", () => { + const data: IDeviceEdit = { payload_parser: undefined }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.payload_parser).toBeUndefined(); + }); + + test("parses payload_parser as null", () => { + const data: IDeviceEdit = { payload_parser: null }; + const parsed = zDeviceEdit.parse(data); + expect(parsed.payload_parser).toBeNull(); + }); + + test("throws error if payload_parser is not a string", () => { + expect(() => zDeviceEdit.parse({ payload_parser: false })).toThrowError(); + expect(() => zDeviceEdit.parse({ payload_parser: 123 })).toThrowError(); + }); +}); + +describe("zDeviceListQuery", () => { + test("parses empty object", () => { + const data: IDeviceListQuery = {}; + const parsed = zDeviceListQuery.parse(data); + expect(parsed).toEqual({ + page: 1, + amount: 20, + fields: ["id", "name", "tags"], + filter: {}, + orderBy: ["name", "asc"], + }); + }); + + test("parses filter", () => { + const data: IDeviceListQuery = { filter: { name: "abc" } }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.filter).toEqual({ name: "abc" }); + }); + + test("parses filter as empty object", () => { + const data: IDeviceListQuery = { filter: {} }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.filter).toEqual({}); + }); + + test("parses filter as undefined", () => { + const data: IDeviceListQuery = { filter: undefined }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.filter).toEqual({}); + }); + + test("parses filter as null", () => { + const data: IDeviceListQuery = { filter: null }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.filter).toEqual({}); + }); + + test("throws error if filter is not an object", () => { + expect(() => zDeviceListQuery.parse({ filter: [] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ filter: false })).toThrowError(); + expect(() => zDeviceListQuery.parse({ filter: true })).toThrowError(); + expect(() => zDeviceListQuery.parse({ filter: 123 })).toThrowError(); + }); + + test("parses fields", () => { + const data: IDeviceListQuery = { fields: ["active"] }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.fields).toEqual(["active", "id", "tags"]); + }); + + test("parses all fields available", () => { + const data: IDeviceListQuery = { + fields: [ + "id", + "name", + "active", + "payload_parser", + "last_output", + "last_input", + "inspected_at", + "created_at", + "updated_at", + "tags", + ], + }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.fields).toEqual(data.fields); + }); + + test("parses fields as empty array", () => { + const data: IDeviceListQuery = { fields: [] }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.fields).toEqual(["id", "tags"]); + }); + + test("parses fields as undefined", () => { + const data: IDeviceListQuery = { fields: undefined }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.fields).toEqual(["id", "name", "tags"]); + }); + + test("parses fields as null", () => { + const data: IDeviceListQuery = { fields: null }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.fields).toEqual(["id", "name", "tags"]); + }); + + test("throws error if filter is not an array", () => { + expect(() => zDeviceListQuery.parse({ fields: {} })).toThrowError(); + expect(() => zDeviceListQuery.parse({ fields: false })).toThrowError(); + expect(() => zDeviceListQuery.parse({ fields: true })).toThrowError(); + expect(() => zDeviceListQuery.parse({ fields: 123 })).toThrowError(); + }); + + test("throws error if filter fields are invalid", () => { + expect(() => zDeviceListQuery.parse({ fields: ["temp"] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ fields: ["abc", "hello"] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ fields: [123] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ fields: [null] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ fields: [undefined] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ fields: [{}] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ fields: [1, "name"] })).toThrowError(); + }); + + test("parses orderBy", () => { + const data: IDeviceListQuery = { orderBy: ["active", "asc"] }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.orderBy).toEqual(["active", "asc"]); + }); + + test("parses all orderBy available", () => { + expect(zDeviceListQuery.parse({ orderBy: ["id", "asc"] }).orderBy).toEqual(["id", "asc"]); + expect(zDeviceListQuery.parse({ orderBy: ["name", "asc"] }).orderBy).toEqual(["name", "asc"]); + expect(zDeviceListQuery.parse({ orderBy: ["active", "asc"] }).orderBy).toEqual(["active", "asc"]); + expect(zDeviceListQuery.parse({ orderBy: ["payload_parser", "desc"] }).orderBy).toEqual(["payload_parser", "desc"]); + expect(zDeviceListQuery.parse({ orderBy: ["last_output", "desc"] }).orderBy).toEqual(["last_output", "desc"]); + expect(zDeviceListQuery.parse({ orderBy: ["last_input", "desc"] }).orderBy).toEqual(["last_input", "desc"]); + expect(zDeviceListQuery.parse({ orderBy: ["created_at", "desc"] }).orderBy).toEqual(["created_at", "desc"]); + expect(zDeviceListQuery.parse({ orderBy: ["updated_at", "desc"] }).orderBy).toEqual(["updated_at", "desc"]); + expect(zDeviceListQuery.parse({ orderBy: ["tags", "desc"] }).orderBy).toEqual(["tags", "desc"]); + }); + + test("parses orderBy as null", () => { + const data: IDeviceListQuery = { orderBy: null }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.orderBy).toEqual(["name", "asc"]); + }); + + test("parses orderBy as undefined", () => { + const data: IDeviceListQuery = { orderBy: undefined }; + const parsed = zDeviceListQuery.parse(data); + expect(parsed.orderBy).toEqual(["name", "asc"]); + }); + + test("throws error if orderBy is not a tuple", () => { + expect(() => zDeviceListQuery.parse({ orderBy: {} })).toThrowError(); + expect(() => zDeviceListQuery.parse({ orderBy: [] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ orderBy: "abc" })).toThrowError(); + expect(() => zDeviceListQuery.parse({ orderBy: true })).toThrowError(); + expect(() => zDeviceListQuery.parse({ orderBy: false })).toThrowError(); + expect(() => zDeviceListQuery.parse({ orderBy: 1234 })).toThrowError(); + }); + + test("throws error if orderBy configuration is incorrect", () => { + expect(() => zDeviceListQuery.parse({ orderBy: [123, "asc"] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ orderBy: ["name", "ASC"] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ orderBy: ["name", "DESC"] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ orderBy: [true, "asc"] })).toThrowError(); + expect(() => zDeviceListQuery.parse({ orderBy: ["name"] })).toThrowError(); + }); +}); diff --git a/packages/tcore-sdk/src/Types/Device/Device.types.ts b/packages/tcore-sdk/src/Types/Device/Device.types.ts new file mode 100644 index 00000000..f39183cb --- /dev/null +++ b/packages/tcore-sdk/src/Types/Device/Device.types.ts @@ -0,0 +1,242 @@ +import { z } from "zod"; +import { v4 as uuid } from "uuid"; +import preprocessObject from "../Helpers/preprocessObject"; +import preprocessBoolean from "../Helpers/preprocessBoolean"; +import removeNullValues from "../Helpers/removeNullValues"; +import { generateResourceID } from "../../Shared/ResourceID"; +import { zTags } from "../Tag.types"; +import { zToken, TGenericID, zName, zObjectID, zQuery, zActiveAutoGen, zTagsAutoGen } from "../Common/Common.types"; +import createQueryOrderBy from "../Helpers/createQueryOrderBy"; + +/** + */ +export const zDeviceType = z.enum(["mutable", "immutable"]); + +/** + * Configuration of a device parameter. + */ +export const zDeviceParameter = z.object({ + key: z.string(), + sent: z.preprocess(preprocessBoolean, z.boolean()).nullish(), + value: z.string(), + id: zObjectID, +}); + +/** + * Configuration of the device param list. + */ +export const zDeviceParameterList = z.array(zDeviceParameter); + +/** + * Configuration to create a new device param. + */ +export const zDeviceParameterCreate = zDeviceParameter.omit({ id: true }).transform((x) => ({ + ...x, + id: generateResourceID(), +})); + +/** + * Base configuration of a device. + */ +export const zDevice = z.object({ + active: z.boolean(), + created_at: z.date(), + id: zObjectID, + inspected_at: z.date().nullish(), + last_input: z.date().nullish(), + last_output: z.date().nullish(), + name: zName, + payload_parser: z.string().nullish(), + tags: zTags, + encoder_stack: z.array(z.string()).nullish(), + updated_at: z.date().nullish(), + data_retention: z.string().nullish(), + type: zDeviceType.nullish(), +}); + +/** + * Configuration to create a new device. + */ +export const zDeviceCreate = zDevice + .omit({ + created_at: true, + id: true, + inspected_at: true, + last_input: true, + last_output: true, + updated_at: true, + }) + .extend({ + active: zActiveAutoGen, + tags: zTagsAutoGen, + data_retention: z + .string() + .nullish() + .transform((x) => x || "forever"), + type: zDevice.shape.type.transform((x) => x || "immutable"), + }) + .transform((x) => + removeNullValues({ + ...x, + created_at: new Date(), + id: generateResourceID(), + }) + ); + +/** + * Configuration to edit an existing device. + */ +export const zDeviceEdit = zDevice + .omit({ + created_at: true, + id: true, + }) + .extend({ + active: zDevice.shape.active.nullish(), + tags: zDevice.shape.tags.nullish(), + data_retention: z.string(), + }) + .partial(); + +/** + * Configuration of the device list. + */ +export const zDeviceList = z.array( + zDevice.partial().extend({ + id: zObjectID, + tags: zTags, + }) +); + +/** + * Configuration of a device token. + */ +export const zDeviceToken = z.object({ + token: zToken, + device_id: zObjectID, + name: zName, + permission: z.enum(["read", "write", "full"]), + serie_number: z.string().nullish(), + last_authorization: z.string().nullish(), + verification_code: z.string().nullish(), + expire_time: z.string(), + created_at: z.date(), +}); + +/** + * Configuration of the device token list. + */ +export const zDeviceTokenList = z.array(zDeviceToken); + +/** + * Configuration to create a new device token. + */ +export const zDeviceTokenCreate = zDeviceToken + .omit({ device_id: true, created_at: true, token: true }) + .extend({ + permission: z + .enum(["read", "write", "full"]) + .nullish() + .transform((x) => x || "full"), + expire_time: z + .string() + .nullish() + .transform((e) => e || "1 month"), + }) + .transform((x) => ({ + ...x, + token: uuid(), + created_at: new Date(), + })); + +/** + * Response of the create token function. + */ +export const zDeviceTokenCreateResponse = z.object({ + token: z.string(), + expire_time: z.string(), + permission: z.enum(["full", "read", "write"]), +}); + +/** + */ +export interface ICreateDeviceResponse { + device_id: TGenericID; + token: TGenericID; +} + +/** + * Allowed fields in a device list query. + */ +const zDeviceListQueryField = z.enum([ + "id", + "name", + "active", + "payload_parser", + "data_retention", + "type", + "last_output", + "last_input", + "inspected_at", + "created_at", + "updated_at", + "tags", + "encoder_stack", +]); + +/** + * Configuration to query the device list. + */ +export const zDeviceListQuery = zQuery.extend({ + filter: z.preprocess( + preprocessObject, + z + .object({ + id: zObjectID.or(z.array(zObjectID)), + tags: zTags, + name: z.string(), + active: z.preprocess(preprocessBoolean, z.boolean()), + }) + .partial() + .nullish() + .transform((x) => x ?? {}) + ), + fields: z + .array(zDeviceListQueryField) + .nullish() + .transform((x) => { + const values = x || ["id", "name", "tags"]; + if (!values.includes("id")) values.push("id"); + if (!values.includes("tags")) values.push("tags"); + return values; + }), + orderBy: createQueryOrderBy(zDeviceListQueryField), +}); + +/** + */ +export const zDeviceTokenListQuery = zQuery.extend({ + fields: z + .array(z.enum(["name", "permission", "serie_number", "last_authorization", "created_at", "expire_time"])) + .nullish() + .transform((x) => { + const values: string[] = x || ["name", "permission", "token", "serie_number", "last_authorization", "created_at"]; + if (!values.includes("expire_time")) values.push("expire_time"); + return values; + }), +}); + +export type IDevice = z.infer; +export type IDeviceCreate = z.input; +export type IDeviceEdit = z.infer; +export type IDeviceList = z.infer; +export type IDeviceListQuery = z.input; +export type IDeviceParameter = z.input; +export type IDeviceParameterCreate = z.input; +export type IDeviceParameterList = z.infer; +export type IDeviceToken = z.infer; +export type IDeviceTokenCreate = z.input; +export type IDeviceTokenCreateResponse = z.infer; +export type IDeviceTokenList = z.input; +export type IDeviceTokenListQuery = z.input; +export type TDeviceType = z.input; diff --git a/packages/tcore-sdk/src/Types/DeviceData/DeviceData.types.test.ts b/packages/tcore-sdk/src/Types/DeviceData/DeviceData.types.test.ts new file mode 100644 index 00000000..83cc09a3 --- /dev/null +++ b/packages/tcore-sdk/src/Types/DeviceData/DeviceData.types.test.ts @@ -0,0 +1,561 @@ +import { + IDeviceDataCreate, + IDeviceDataCreateLocation, + IDeviceDataLocationCoordinates, + IDeviceDataQuery, + validateResourceID, + zDeviceDataQuery, +} from ".."; +import { IDeviceData, zDeviceData, zDeviceDataCreate } from "./DeviceData.types"; + +describe("zDeviceData", () => { + const data: IDeviceData = { + created_at: new Date(), + id: "6126af42599b57a4e91ec706", + time: new Date(), + variable: "temperature", + }; + + test("requires ID property", () => { + const copy: IDeviceData = { ...data }; + delete (copy as any).id; + const fn = () => zDeviceData.parse(copy); + expect(fn).toThrow(); + }); + + test("requires time property", () => { + const copy: any = { ...data }; + delete copy.time; + const fn = () => zDeviceData.parse(copy); + expect(fn).toThrow(); + }); + + test("requires variable property", () => { + const copy: IDeviceData = { ...data }; + delete (copy as any).variable; + const fn = () => zDeviceData.parse(copy); + expect(fn).toThrow(); + }); + + test("parses simple object", () => { + const parsed = zDeviceData.parse(data); + expect(parsed).toEqual(data); + }); +}); + +describe("zDeviceDataCreate", () => { + test("parses object with only variable", () => { + const data: IDeviceDataCreate = { variable: "temperature" }; + const parsed = zDeviceDataCreate.parse(data); + expect(validateResourceID(parsed.id)).toEqual(true); + expect(parsed.location).toBeUndefined(); + expect(parsed.metadata).toBeUndefined(); + expect(parsed.unit).toBeUndefined(); + expect(parsed.serie).toBeUndefined(); + expect(parsed.time).toBeInstanceOf(Date); + }); + + test("uses time from object if it was informed", () => { + const data: IDeviceDataCreate = { time: new Date("2020-01-01T15:00:00Z"), variable: "temperature" }; + const parsed = zDeviceDataCreate.parse(data); + expect(parsed.time).toEqual(new Date("2020-01-01T15:00:00Z")); + }); + + test("supports different time strings", () => { + const fn = () => { + zDeviceDataCreate.parse({ time: "2021", variable: "temperature" }); + zDeviceDataCreate.parse({ time: "2021/01", variable: "temperature" }); + zDeviceDataCreate.parse({ time: "2021/01/20", variable: "temperature" }); + zDeviceDataCreate.parse({ time: "2021T15:00:00Z", variable: "temperature" }); + }; + expect(fn).not.toThrow(); + }); + + test("throws error if time is invalid", () => { + const data: IDeviceDataCreate = { time: new Date("2020-01-01ABC15:00:00Z"), variable: "temperature" }; + const fn = () => zDeviceDataCreate.parse(data); + expect(fn).toThrow(); + }); + + test("parses location with lat && lng", () => { + const location = { lat: 10, lng: 20 }; + const data: IDeviceDataCreate = { variable: "location", location }; + const parsed = zDeviceDataCreate.parse(data); + expect(parsed.location).toEqual({ type: "Point", coordinates: [20, 10] }); + }); + + test("parses location with coordinates", () => { + const location: IDeviceDataCreateLocation = { type: "Point", coordinates: [20, 10] }; + const data: IDeviceDataCreate = { variable: "location", location }; + const parsed = zDeviceDataCreate.parse(data); + expect(parsed.location).toEqual(location); + }); + + test("throws if object has invalid location", () => { + const location: any = {}; + const data: IDeviceDataCreate = { variable: "location", location }; + const fn = () => zDeviceDataCreate.parse(data); + expect(fn).toThrow(); + }); + + test("throws if object has location.lat < -90", () => { + const location: IDeviceDataCreateLocation = { lat: -300, lng: 10 }; + const data: IDeviceDataCreate = { variable: "location", location }; + const fn = () => zDeviceDataCreate.parse(data); + expect(fn).toThrow(); + }); + + test("throws if object has location.lat > 90", () => { + const location: IDeviceDataCreateLocation = { lat: 90.1, lng: 10 }; + const data: IDeviceDataCreate = { variable: "location", location }; + const fn = () => zDeviceDataCreate.parse(data); + expect(fn).toThrow(); + }); + + test("autofills `type` in location object", () => { + const location: IDeviceDataLocationCoordinates = { coordinates: [30, 45] }; + const data: IDeviceDataCreate = { variable: "location", location }; + const parsed = zDeviceDataCreate.parse(data); + expect(parsed.location).toEqual({ type: "Point", coordinates: [30, 45] }); + }); +}); + +describe("zDeviceDataQuery", () => { + test("parses empty object", () => { + const data: IDeviceDataQuery = {}; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).toEqual({ + query: "defaultQ", + skip: 0, + qty: 15, + ordination: "desc", + }); + }); + + test("parses end_date as actual date", () => { + const data: IDeviceDataQuery = { end_date: new Date() }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.end_date).toEqual(data.end_date); + }); + + test("parses end_date as null", () => { + const data: IDeviceDataQuery = { end_date: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("end_date"); + }); + + test("parses end_date as undefined", () => { + const data: IDeviceDataQuery = { end_date: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("end_date"); + }); + + test("parses end_date as valid strings and numbers", () => { + const fn = () => { + zDeviceDataQuery.parse({ end_date: 1639320965378 }); + zDeviceDataQuery.parse({ end_date: "2021" }); + zDeviceDataQuery.parse({ end_date: "2021/01" }); + zDeviceDataQuery.parse({ end_date: "2021/01/20" }); + zDeviceDataQuery.parse({ end_date: "2021T15:00:00Z" }); + zDeviceDataQuery.parse({ end_date: "2021-01-01T15:00:00Z" }); + zDeviceDataQuery.parse({ end_date: "2021-01-01" }); + zDeviceDataQuery.parse({ end_date: "1999-01-01T15:00" }); + zDeviceDataQuery.parse({ end_date: "1999-01-01T15:00:00.123Z" }); + zDeviceDataQuery.parse({ end_date: "1999-01-01T15:00:00.123456Z" }); + }; + expect(fn).not.toThrow(); + }); + + test("throws error if end_date has invalid dates", () => { + const fn = () => { + zDeviceDataQuery.parse({ end_date: new Date("abc") }); + zDeviceDataQuery.parse({ end_date: true }); + zDeviceDataQuery.parse({ end_date: false }); + zDeviceDataQuery.parse({ end_date: {} }); + zDeviceDataQuery.parse({ end_date: [] }); + }; + expect(fn).toThrow(); + }); + + test("parses start_date as actual date", () => { + const data: IDeviceDataQuery = { start_date: new Date() }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.start_date).toEqual(data.start_date); + }); + + test("parses start_date as null", () => { + const data: IDeviceDataQuery = { start_date: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("start_date"); + }); + + test("parses start_date as undefined", () => { + const data: IDeviceDataQuery = { start_date: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("start_date"); + }); + + test("parses start_date as valid strings and numbers", () => { + const fn = () => { + zDeviceDataQuery.parse({ start_date: 1639320965378 }); + zDeviceDataQuery.parse({ start_date: "2021" }); + zDeviceDataQuery.parse({ start_date: "2021/01" }); + zDeviceDataQuery.parse({ start_date: "2021/01/20" }); + zDeviceDataQuery.parse({ start_date: "2021T15:00:00Z" }); + zDeviceDataQuery.parse({ start_date: "2021-01-01T15:00:00Z" }); + zDeviceDataQuery.parse({ start_date: "2021-01-01" }); + zDeviceDataQuery.parse({ start_date: "1999-01-01T15:00" }); + zDeviceDataQuery.parse({ start_date: "1999-01-01T15:00:00.123Z" }); + zDeviceDataQuery.parse({ start_date: "1999-01-01T15:00:00.123456Z" }); + }; + expect(fn).not.toThrow(); + }); + + test("throws error if start_date has invalid dates", () => { + expect(() => zDeviceDataQuery.parse({ start_date: new Date("abc") })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ start_date: true })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ start_date: false })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ start_date: {} })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ start_date: [] })).toThrowError(); + }); + + test("parses ids as empty array", () => { + const data: IDeviceDataQuery = { ids: [] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ids).toEqual([]); + }); + + test("parses ids as filled array", () => { + const data: IDeviceDataQuery = { ids: ["61b2517991639c00197811e2", "11b2517991639c00197811e2"] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ids).toEqual(["61b2517991639c00197811e2", "11b2517991639c00197811e2"]); + }); + + test("parses ids as null", () => { + const data: IDeviceDataQuery = { ids: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("ids"); + }); + + test("parses ids as undefined", () => { + const data: IDeviceDataQuery = { ids: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("ids"); + }); + + test("transfers string id property to ids", () => { + const data = { id: "11b2517991639c00197811e2" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ids).toEqual(["11b2517991639c00197811e2"]); + expect(parsed).not.toHaveProperty("id"); + }); + + test("transfers array id property to ids", () => { + const data = { id: ["11b2517991639c00197811e2"] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ids).toEqual(["11b2517991639c00197811e2"]); + expect(parsed).not.toHaveProperty("id"); + }); + + test("prefers ids property over id property", () => { + const data = { ids: ["61b251e291639c0019781ec2"], id: "11b2517991639c00197811e2" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ids).toEqual(["61b251e291639c0019781ec2"]); + expect(parsed).not.toHaveProperty("id"); + }); + + test("throws error if ids property is not a string array", () => { + expect(() => zDeviceDataQuery.parse({ ids: 1 })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ ids: true })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ ids: false })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ ids: {} })).toThrowError(); + }); + + test("parses values as empty array", () => { + const data: IDeviceDataQuery = { values: [] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.values).toEqual([]); + }); + + test("parses values as filled array", () => { + const data: IDeviceDataQuery = { values: ["61b2517991639c00197811e2", "11b2517991639c00197811e2"] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.values).toEqual(["61b2517991639c00197811e2", "11b2517991639c00197811e2"]); + }); + + test("parses values as null", () => { + const data: IDeviceDataQuery = { values: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("values"); + }); + + test("parses values as undefined", () => { + const data: IDeviceDataQuery = { values: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("values"); + }); + + test("parses values as boolean", () => { + const data: IDeviceDataQuery = { values: [true] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.values).toEqual([true]); + }); + + test("parses values as number", () => { + const data: IDeviceDataQuery = { values: [123] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.values).toEqual([123]); + }); + + test("transfers string value property to values", () => { + const data = { value: "11b2517991639c00197811e2" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.values).toEqual(["11b2517991639c00197811e2"]); + expect(parsed).not.toHaveProperty("value"); + }); + + test("transfers array value property to values", () => { + const data = { value: ["11b2517991639c00197811e2"] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.values).toEqual(["11b2517991639c00197811e2"]); + expect(parsed).not.toHaveProperty("value"); + }); + + test("prefers values property over value property", () => { + const data = { values: ["61b251e291639c0019781ec2"], value: "11b2517991639c00197811e2" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.values).toEqual(["61b251e291639c0019781ec2"]); + expect(parsed).not.toHaveProperty("value"); + }); + + test("throws error if values property is not a primitive type", () => { + expect(() => zDeviceDataQuery.parse({ values: {} })).toThrowError(); + }); + + test("parses groups as empty array", () => { + const data: IDeviceDataQuery = { groups: [] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.groups).toEqual([]); + }); + + test("parses groups as filled array", () => { + const data: IDeviceDataQuery = { groups: ["abc", "foo"] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.groups).toEqual(["abc", "foo"]); + }); + + test("parses groups as null", () => { + const data: IDeviceDataQuery = { groups: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("groups"); + }); + + test("parses groups as undefined", () => { + const data: IDeviceDataQuery = { groups: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("groups"); + }); + + test("transfers string serie property to groups", () => { + const data = { serie: "foo" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.groups).toEqual(["foo"]); + expect(parsed).not.toHaveProperty("serie"); + }); + + test("transfers array serie property to groups", () => { + const data = { serie: ["foo"] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.groups).toEqual(["foo"]); + expect(parsed).not.toHaveProperty("serie"); + }); + + test("prefers groups property over serie property", () => { + const data = { groups: ["temp"], serie: "test" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.groups).toEqual(["temp"]); + expect(parsed).not.toHaveProperty("serie"); + }); + + test("throws error if groups property is not a string array", () => { + expect(zDeviceDataQuery.safeParse({ groups: 1 }).success).toBeFalsy(); + expect(zDeviceDataQuery.safeParse({ groups: true }).success).toBeFalsy(); + expect(zDeviceDataQuery.safeParse({ groups: false }).success).toBeFalsy(); + expect(zDeviceDataQuery.safeParse({ groups: {} }).success).toBeFalsy(); + }); + + test("parses variables as empty array", () => { + const data: IDeviceDataQuery = { variables: [] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.variables).toEqual([]); + }); + + test("parses variables as filled array", () => { + const data: IDeviceDataQuery = { variables: ["temperature", "humidity"] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.variables).toEqual(["temperature", "humidity"]); + }); + + test("parses variables as null", () => { + const data: IDeviceDataQuery = { variables: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("variables"); + }); + + test("parses variables as undefined", () => { + const data: IDeviceDataQuery = { variables: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed).not.toHaveProperty("variables"); + }); + + test("transfers string variable property to variables", () => { + const data = { variable: "weight" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.variables).toEqual(["weight"]); + expect(parsed).not.toHaveProperty("variable"); + }); + + test("transfers array variable property to variables", () => { + const data = { variable: ["weight"] }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.variables).toEqual(["weight"]); + expect(parsed).not.toHaveProperty("variable"); + }); + + test("prefers variables property over variable property", () => { + const data = { variables: ["height"], variable: "width" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.variables).toEqual(["height"]); + expect(parsed).not.toHaveProperty("variable"); + }); + + test("throws error if variables property is not a string array", () => { + expect(() => zDeviceDataQuery.parse({ variables: 1 })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ variables: true })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ variables: false })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ variables: {} })).toThrowError(); + }); + + test("parses skip", () => { + const data: IDeviceDataQuery = { skip: 22 }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.skip).toEqual(22); + }); + + test("parses skip as string", () => { + const data = { skip: "22" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.skip).toEqual(22); + }); + + test("parses skip as null", () => { + const data: IDeviceDataQuery = { skip: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.skip).toEqual(0); + }); + + test("parses skip as undefined", () => { + const data: IDeviceDataQuery = { skip: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.skip).toEqual(0); + }); + + test("throws error if skip is not a valid number", () => { + expect(() => zDeviceDataQuery.parse({ skip: "hello" })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ skip: true })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ skip: false })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ skip: {} })).toThrowError(); + }); + + test("parses qty", () => { + const data: IDeviceDataQuery = { qty: 15 }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.qty).toEqual(15); + }); + + test("parses qty as string", () => { + const data = { qty: "15" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.qty).toEqual(15); + }); + + test("parses qty as null", () => { + const data: IDeviceDataQuery = { qty: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.qty).toEqual(15); + }); + + test("parses qty as undefined", () => { + const data: IDeviceDataQuery = { qty: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.qty).toEqual(15); + }); + + test("throws error if qty is not a valid number", () => { + expect(() => zDeviceDataQuery.parse({ qty: "hello" })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ qty: true })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ qty: false })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ qty: {} })).toThrowError(); + }); + + test("parses ordination as asc", () => { + const data: IDeviceDataQuery = { ordination: "asc" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ordination).toEqual("asc"); + }); + + test("parses ordination as desc", () => { + const data: IDeviceDataQuery = { ordination: "desc" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ordination).toEqual("desc"); + }); + + test("parses ordination as ASC", () => { + const data: IDeviceDataQuery = { ordination: "ASC" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ordination).toEqual("asc"); + }); + + test("parses ordination as DESC", () => { + const data: IDeviceDataQuery = { ordination: "DESC" }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ordination).toEqual("desc"); + }); + + test("parses ordination as null", () => { + const data: IDeviceDataQuery = { ordination: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ordination).toEqual("desc"); + }); + + test("parses ordination as undefined", () => { + const data: IDeviceDataQuery = { ordination: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.ordination).toEqual("desc"); + }); + + test("throws error if ordination is not a valid value", () => { + expect(() => zDeviceDataQuery.parse({ ordination: "hello" })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ ordination: true })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ ordination: false })).toThrowError(); + expect(() => zDeviceDataQuery.parse({ ordination: {} })).toThrowError(); + }); + + test("parses details", () => { + const data: IDeviceDataQuery = { details: true }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.details).toEqual(true); + }); + + test("parses details as null", () => { + const data: IDeviceDataQuery = { details: null }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.details).toBeUndefined(); + }); + + test("parses details as undefined", () => { + const data: IDeviceDataQuery = { details: undefined }; + const parsed = zDeviceDataQuery.parse(data); + expect(parsed.details).toBeUndefined(); + }); +}); diff --git a/packages/tcore-sdk/src/Types/DeviceData/DeviceData.types.ts b/packages/tcore-sdk/src/Types/DeviceData/DeviceData.types.ts new file mode 100644 index 00000000..3f122910 --- /dev/null +++ b/packages/tcore-sdk/src/Types/DeviceData/DeviceData.types.ts @@ -0,0 +1,241 @@ +import { z } from "zod"; +import { DateTime } from "luxon"; +import { generateResourceID } from "../../Shared/ResourceID"; +import { zObjectID } from "../Common/Common.types"; +import { parseRelativeDate, convertDateToISO } from "../Helpers/parseRelativeDate"; +import removeNullValues from "../Helpers/removeNullValues"; + +/** + * Checks if a given value is indeed a date or not. + */ +function isDate(date: any) { + return date instanceof Date && !Number.isNaN(date.getTime()); +} + +/** + * Handles absolute/relative dates. + * @returns {Date} a date object. + */ +function handleDates(rawDate: Date | string, timezone: string, type: "start" | "end"): Date { + let date: any = new Date(rawDate); + + if (!isDate(date)) { + try { + date = parseRelativeDate(rawDate, type === "start"); + } catch (ex) { + throw new Error(`Invalid ${type} date`); + } + } else { + try { + if (String(rawDate).length <= 10) { + if (type === "start") { + date = DateTime.fromJSDate(new Date(date)).startOf("day").toJSDate(); + } else { + date = DateTime.fromJSDate(new Date(date)).endOf("day").toJSDate(); + } + } + } catch (error) { + throw new Error(`Invalid ${type} date`); + } + + if (timezone) { + date = new Date(convertDateToISO(date, timezone)); + } + } + + if (!isDate(date)) { + throw new Error(`Invalid ${type} date`); + } + + return date; +} + +/** + * Configuration of location with array coordinates. + */ +const zDeviceDataLocationCoordinates = z.object({ + type: z + .string() + .nullish() + .transform((x) => x || "Point"), + coordinates: z.tuple([z.number().min(-180).max(180), z.number().min(-90).max(90)]), +}); + +/** + * Configuration of location with object coordinates. + */ +const zDeviceDataLocationLatLng = z.object({ + lat: z.number().min(-90).max(90), + lng: z.number().min(-180).max(180), +}); + +/** + * Configuration of a single device data. + */ +export const zDeviceData = z.object({ + created_at: z.date().optional(), + id: zObjectID, + device: zObjectID.nullish(), + location: zDeviceDataLocationCoordinates.optional(), + metadata: z.object({}).catchall(z.any()).or(z.array(z.any())).optional(), + group: z.string().max(24).nullish(), + serie: z.number().or(z.string()).optional(), + time: z.date(), + unit: z.string().optional(), + value: z.string().or(z.boolean()).or(z.number()).optional(), + variable: z.string(), +}); + +/** + * Configuration to set a location to create a new device data. + */ +const zDeviceDataCreateLocation = zDeviceDataLocationCoordinates + .or(zDeviceDataLocationLatLng) + .nullish() + .transform((x: any): IDeviceDataLocationCoordinates | undefined => { + if (!x) { + return undefined; + } else if (Array.isArray(x.coordinates)) { + return x; + } else { + return { type: "Point", coordinates: [x.lng, x.lat] }; + } + }); + +/** + * Configuration to create a new device data. + */ +export const zDeviceDataCreate = zDeviceData + .omit({ created_at: true, id: true, device: true }) + .extend({ + location: zDeviceDataCreateLocation, + time: z.preprocess((x) => (x ? new Date(x as string) : undefined), z.date().nullish()), + }) + .transform((data) => { + const now = new Date(); + return removeNullValues({ + ...data, + created_at: now, + id: generateResourceID(), + time: data.time || now, + }); + }); + +/** + * Configuration to update a device data. + */ +export const zDeviceDataUpdate = zDeviceData.omit({ created_at: true, variable: true, device: true }).extend({ + location: zDeviceDataCreateLocation, + time: z.preprocess((x) => (x ? new Date(x as string) : undefined), z.date().nullish()), +}); + +/** + * Configuration to query the device data list. + */ +export const zDeviceDataQuery = z.preprocess( + (x: any) => { + const data: any = { + end_date: x.end_date, + ids: x.ids, + ordination: x.ordination, + qty: x.qty, + query: x.query, + skip: x.skip, + groups: x.groups, + start_date: x.start_date, + values: x.values, + variables: x.variables, + timezone: x.timezone, + }; + + if (x.detail || x.details) { + data.details = true; + } + if (x.skip && typeof x.skip !== "boolean") { + data.skip = Number(x.skip); + } + if (x.qty && typeof x.qty !== "boolean") { + data.qty = Number(x.qty); + } + if (x.start_date && typeof x.start_date !== "boolean") { + data.start_date = handleDates(x.start_date, data.timezone, "start"); + } + if (x.end_date && typeof x.end_date !== "boolean") { + data.end_date = handleDates(x.end_date, data.timezone, "end"); + } + if (x.variables || x.variable) { + data.variables = [x.variables || x.variable].flat(); + } + if (x.series || x.serie) { + data.groups = [x.series || x.serie].flat(); + } + if (x.groups || x.group) { + data.groups = [x.groups || x.group].flat(); + } + if (x.values || x.value) { + data.values = [x.values || x.value].flat(); + } + if (x.ids || x.id) { + data.ids = [x.ids || x.id].flat(); + } + + return removeNullValues(data); + }, + z.object({ + details: z.boolean().nullish(), + end_date: z.date().nullish(), + ids: z.array(z.string()).nullish(), + query: z + .enum([ + "last_value", + "last_location", + "last_item", + "last_insert", + "first_value", + "first_location", + "first_item", + "first_insert", + "count", + "max", + "min", + "avg", + "sum", + "defaultQ", + ]) + .nullish() + .transform((x) => x || "defaultQ"), + groups: z.array(z.string()).nullish(), + start_date: z.date().nullish(), + values: z.array(z.string()).or(z.array(z.boolean())).or(z.array(z.number())).nullish(), + variables: z.array(z.string()).nullish(), + skip: z + .number() + .min(0) + .nullish() + .transform((x) => x ?? 0), + qty: z + .number() + .min(0) + .max(10000) + .nullish() + .transform((x) => x ?? 15), + ordination: z + .enum(["ASC", "DESC", "asc", "desc"]) + .nullish() + .transform((x) => String(x || "DESC").toLowerCase()), + }) +); + +const zDeviceAddDataOptions = z.object({ + rawPayload: z.any().nullish(), + liveInspectorID: z.string().nullish(), +}); + +export type IDeviceAddDataOptions = z.infer; +export type IDeviceData = z.infer; +export type IDeviceDataCreate = z.input; +export type IDeviceDataCreateLocation = z.input; +export type IDeviceDataLocationCoordinates = z.input; +export type IDeviceDataLocationLatLng = z.input; +export type IDeviceDataQuery = z.input; +export type IDeviceDataUpdate = z.input; diff --git a/packages/tcore-sdk/src/Types/GraphqlAPI.types.ts b/packages/tcore-sdk/src/Types/GraphqlAPI.types.ts new file mode 100644 index 00000000..a4574f42 --- /dev/null +++ b/packages/tcore-sdk/src/Types/GraphqlAPI.types.ts @@ -0,0 +1,12 @@ +import { z } from "zod"; + +/** + * Configuration of a version item of TCore. + */ +export const zTCoreVersionListItem = z.object({ + released_at: z.date(), + version: z.string(), + platforms: z.array(z.string()), +}); + +export type ITCoreVersionListItem = z.infer; diff --git a/packages/tcore-sdk/src/Types/Hardware.types.ts b/packages/tcore-sdk/src/Types/Hardware.types.ts new file mode 100644 index 00000000..6156d14e --- /dev/null +++ b/packages/tcore-sdk/src/Types/Hardware.types.ts @@ -0,0 +1,38 @@ +import { z } from "zod"; + +/** + * Configuration of the main OS info. + */ +export const zOSInfo = z.object({ + version: z.string(), + arch: z.string(), + name: z.string(), + code: z.enum(["windows", "mac", "linux", "raspberry-pi", "other"]), + hardware: z.string(), +}); + +/** + * Configuration of the main network info. + */ +export const zNetworkInfo = z.object({ + ip: z.string(), + name: z.string(), + bytesTransferred: z.number(), + bytesDropped: z.number(), +}); + +/** + * Configuration of a single computer usage statistic. + */ +export const zComputerUsage = z.object({ + total: z.number(), + used: z.number(), + description: z.string().optional(), + title: z.string(), + type: z.string(), + detail: z.string().optional(), +}); + +export type IOSInfo = z.infer; +export type IComputerUsage = z.infer; +export type INetworkInfo = z.infer; diff --git a/packages/tcore-sdk/src/Types/Helpers.ts b/packages/tcore-sdk/src/Types/Helpers.ts new file mode 100644 index 00000000..9ad82fb4 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Helpers.ts @@ -0,0 +1,35 @@ +/** + * Refines (validates) the order by field of a query. + */ +export function refineOrderBy(enumValues: any): any { + const validator = (value: any) => { + try { + const valueJSON = parseSafe(value, []); + if (valueJSON.length === 2) { + enumValues.parse(valueJSON[0]); + if (valueJSON[1] === "asc" || valueJSON[1] === "desc") { + return true; + } + } + return false; + } catch (ex) { + return false; + } + }; + return validator; +} + +/** + * Parses a JSON safely. + */ +export function parseSafe(value: any, fallback: any = {}) { + try { + if (value && typeof value === "object") { + return value; + } + const result = JSON.parse(value); + return result || fallback; + } catch (ex) { + return fallback; + } +} diff --git a/packages/tcore-sdk/src/Types/Helpers/createQueryOrderBy.ts b/packages/tcore-sdk/src/Types/Helpers/createQueryOrderBy.ts new file mode 100644 index 00000000..927b1156 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Helpers/createQueryOrderBy.ts @@ -0,0 +1,23 @@ +import { z } from "zod"; + +/** + * Allows the following configurations: + * + * - tuples such as ["name", "asc"] + * - strings with field and order such as "name,asc" + */ +function createQueryOrderBy(value: T) { + const errorMsg = "Invalid orderBy parameter"; + return z + .tuple([value, z.enum(["asc", "desc"])]) + .or( + z + .string() + .transform((x) => x.split(",")) + .refine((x) => x[0] && (x[1] === "asc" || x[1] === "desc"), errorMsg) + ) + .nullish() + .transform((x) => x ?? ["name", "asc"]); +} + +export default createQueryOrderBy; diff --git a/packages/tcore-sdk/src/Types/Helpers/parseRelativeDate.ts b/packages/tcore-sdk/src/Types/Helpers/parseRelativeDate.ts new file mode 100644 index 00000000..f1d3ea9a --- /dev/null +++ b/packages/tcore-sdk/src/Types/Helpers/parseRelativeDate.ts @@ -0,0 +1,73 @@ +import { DateTime } from "luxon"; + +/** + */ +export function convertDateToISO(date: Date | string, timezone?: string) { + const rawDate = DateTime.fromJSDate(new Date(date)); + if (timezone) { + return rawDate.setZone(timezone, { keepLocalTime: true }).toISO() || rawDate.toISO() || DateTime.utc().toISO(); + } else { + return rawDate.setZone("UTC", { keepLocalTime: true }).toISO() || DateTime.utc().toISO(); + } +} + +/** + */ +const durationLabelsStandard = { + S: "millisecond", + SS: "milliseconds", + s: "second", + ss: "seconds", + sec: "seconds", + m: "minute", + mm: "minutes", + min: "minutes", + h: "hour", + hh: "hours", + d: "day", + dd: "days", + w: "week", + ww: "weeks", + M: "month", + MM: "months", + y: "year", + yy: "years", +}; + +/** + */ +function fixDuration(duration: string) { + duration = String(duration || "").trim(); + return durationLabelsStandard[duration] || duration; +} + +/** + */ +export function parseRelativeDate(expire_time, bool_minus, date = new Date()) { + if (!expire_time) { + return; + } + if (expire_time.toLowerCase() === "never") { + return "never"; + } + + const regex = /(\d+)/g; + const split = expire_time.split(regex); + + if (split.length !== 3 || !split[1] || !split[2]) { + throw new Error("Invalid date"); + } + + let time: DateTime; + if (bool_minus) { + time = DateTime.fromJSDate(new Date(date)).minus({ [fixDuration(split[2])]: Number(split[1]) }); + } else { + time = DateTime.fromJSDate(new Date(date)).plus({ [fixDuration(split[2])]: Number(split[1]) }); + } + + if (!time.isValid) { + throw new Error("Invalid date"); + } + + return time.toJSDate(); +} diff --git a/packages/tcore-sdk/src/Types/Helpers/preprocessBoolean.ts b/packages/tcore-sdk/src/Types/Helpers/preprocessBoolean.ts new file mode 100644 index 00000000..8b29be14 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Helpers/preprocessBoolean.ts @@ -0,0 +1,19 @@ +/** + * Preprocesses a boolean field. + * @param {unknown} value The value to preprocess. + * @return {any} The processed value. + */ +function preprocessBoolean(value: unknown): boolean { + if (value === "true" || value === "false") { + return value === "true"; + } + if (String(value) === "1") { + return true; + } + if (value === true || value === false) { + return value; + } + return !!value; +} + +export default preprocessBoolean; diff --git a/packages/tcore-sdk/src/Types/Helpers/preprocessNumber.ts b/packages/tcore-sdk/src/Types/Helpers/preprocessNumber.ts new file mode 100644 index 00000000..078c8851 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Helpers/preprocessNumber.ts @@ -0,0 +1,8 @@ +function preprocessNumber(value: any): any { + if (value === true || value === false) { + return ""; + } + return Number(value); +} + +export default preprocessNumber; diff --git a/packages/tcore-sdk/src/Types/Helpers/preprocessObject.ts b/packages/tcore-sdk/src/Types/Helpers/preprocessObject.ts new file mode 100644 index 00000000..20ad0d5e --- /dev/null +++ b/packages/tcore-sdk/src/Types/Helpers/preprocessObject.ts @@ -0,0 +1,18 @@ +/** + * Preprocesses an object field. + * @param {unknown} value The value to preprocess. + * @return {any} The processed value. + */ +function preprocessObject(value: unknown): any { + if (typeof value === "object") { + return value; + } else { + try { + return JSON.parse(value as string); + } catch (ex) { + return null; + } + } +} + +export default preprocessObject; diff --git a/packages/tcore-sdk/src/Types/Helpers/removeNullValues.ts b/packages/tcore-sdk/src/Types/Helpers/removeNullValues.ts new file mode 100644 index 00000000..e3e4a4f5 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Helpers/removeNullValues.ts @@ -0,0 +1,14 @@ +/** + * Removes all null and undefined values from an object. + */ +function removeNullValues(value: T): T { + for (const key in value) { + if (value[key] === null || value[key] === undefined) { + delete value[key]; + } + } + + return value; +} + +export default removeNullValues; diff --git a/packages/tcore-sdk/src/Types/LiveInspector.types.ts b/packages/tcore-sdk/src/Types/LiveInspector.types.ts new file mode 100644 index 00000000..9aa6b68c --- /dev/null +++ b/packages/tcore-sdk/src/Types/LiveInspector.types.ts @@ -0,0 +1,30 @@ +import { z } from "zod"; +import { zObjectID } from "./Common/Common.types"; + +/** + * Configuration of a inspector connection ID. + */ +export const zLiveInspectorConnectionID = z.string().nullish(); + +/** + * Configuration of a message from the device's inspector. + */ +const zLiveInspectorMessage = z.object({ + connection_id: z.string(), + content: z.any(), + device_id: zObjectID, + timestamp: z.number(), + title: z.string(), +}); + +/** + * Configuration to create a message in the device's inspector. + */ +const zLiveInspectorMessageCreate = z.object({ + content: z.any(), + title: z.string(), +}); + +export type ILiveInspectorMessageCreate = z.infer; +export type ILiveInspectorMessage = z.infer; +export type TLiveInspectorConnectionID = z.infer; diff --git a/packages/tcore-sdk/src/Types/Log.types.ts b/packages/tcore-sdk/src/Types/Log.types.ts new file mode 100644 index 00000000..c50f77a8 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Log.types.ts @@ -0,0 +1,27 @@ +import { z } from "zod"; +import { zDateAutoGen } from "./Common/Common.types"; + +/** + * Configuration of a log. + */ +export const zLog = z.object({ + timestamp: z.date(), + message: z.string(), + error: z.boolean(), +}); + +/** + * Configuration to create a log. + */ +export const zLogCreate = zLog.extend({ + timestamp: zDateAutoGen, +}); + +/** + * Configuration of the log list. + */ +export const zLogList = z.array(zLog); + +export type ILog = z.infer; +export type ILogList = z.infer; +export type ILogCreate = z.infer; diff --git a/packages/tcore-sdk/src/Types/Network.types.ts b/packages/tcore-sdk/src/Types/Network.types.ts new file mode 100644 index 00000000..6bb604f1 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Network.types.ts @@ -0,0 +1,76 @@ +import { TGenericID } from "./Common/Common.types"; + +export interface INetworkDeviceParameter { + name?: string; + label?: string; + type?: "text" | "dropdown" | "switch" | "number"; + default?: any; + group?: "default" | "main" | "advanced" | "hide"; + options?: any[]; // optional, only for dropdown +} + +export interface INetworkCreate { + name?: string; + description?: string; + logo_url?: string; + icon_url?: string; + banner_url?: string; + device_parameters?: INetworkDeviceParameter[]; + middleware_endpoint?: string; + payload_encoder?: string; + payload_decoder?: string; + public?: boolean; + documentation_url?: string; + serial_number?: { + mask?: string; + label?: string; + image?: string; + case?: string; + help?: string; + required?: boolean; + }; + require_devices_access?: boolean; +} + +export interface INetwork extends INetworkCreate { + id: TGenericID; + name?: string; + description?: string; + logo_url?: string; + icon_url?: string; + banner_url?: string; + device_parameters?: INetworkDeviceParameter[]; + middleware_endpoint?: string; + payload_encoder?: string; + payload_decoder?: string; + public?: boolean; + documentation_url?: string; + serial_number?: { + mask?: string; + label?: string; + image?: string; + case?: string; + help?: string; + required?: boolean; + }; +} + +export type INetworkListQuery = any; + +// export type INetworkListQuery = Query< +// INetwork, +// | "name" +// | "description" +// | "logo_url" +// | "icon_url" +// | "banner_url" +// | "device_parameters" +// | "middleware_endpoint" +// | "payload_encoder" +// | "payload_decoder" +// | "serial_number" +// | "documentation_url" +// | "public" +// | "created_at" +// | "updated_at" +// >; diff --git a/packages/tcore-sdk/src/Types/Plugin.types.ts b/packages/tcore-sdk/src/Types/Plugin.types.ts new file mode 100644 index 00000000..364e6144 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Plugin.types.ts @@ -0,0 +1,536 @@ +/* eslint-disable no-unused-vars */ +import { z } from "zod"; +import { zIcon } from "./Common/Icon.types"; + +/** + * Types of plugins available. + */ +export const zPluginType = z.enum([ + "database", + "service", + "encoder", + "decoder", + "action-trigger", + "action-type", + "sidebar-button", + "page", + "navbar-button", + "hook", + "filesystem", +]); + +/** + * Configuration for when installing plugins. + */ +export const zPluginInstallOptions = z.object({ + start: z.boolean().optional(), + log: z.boolean().optional(), + restoreBackup: z.boolean().optional(), +}); + +/** + * Types of permissions available. + */ +export const zPluginPermission = z.enum(["device", "analysis", "action", "device-data", "cli"]); + +/** + */ +export const zPluginManifestCliOption = z.object({ + flags: z.string(), + description: z.string().nullish(), +}); + +/** + */ +export const zPluginManifestCliCommand = z.object({ + name: z.string(), + description: z.string().nullish(), + arguments: z.array(zPluginManifestCliOption).nullish(), + options: z.array(zPluginManifestCliOption).nullish(), + file: z.string(), +}); + +/** + * Configuration of the `tcore` object in the package.json files of plugins. + */ +export const zPluginPackageTCore = z.object({ + name: z.string(), + description: z.string().optional(), + full_description: z.string().nullish(), + icon: z.string().optional(), + screenshots: z.array(z.string()).optional(), + types: z.array(zPluginType), + permissions: z.array(zPluginPermission).nullish(), + cli_commands: z.array(zPluginManifestCliCommand).nullish(), +}); + +/** + * Configuration of a log channel of a plugin. + */ +const zPluginLogChannel = z.object({ + name: z.string(), + channel: z.string(), + plugin: z.boolean(), +}); + +/** + * Configuration of a plugin class item in a list. + */ +const zPluginClassListItem = z.object({ + pluginID: z.string(), + pluginName: z.string(), + setupID: z.string(), + setupName: z.string(), +}); + +/** + * Configuration of a button in the plugin list ite. + */ +const zPluginListItemButton = z.object({ + color: z.string(), + icon: zIcon, + name: z.string(), + route: z.string(), + type: z.enum(["sidebar-button", "navbar-button"]), +}); + +/** + * Configuration of visibility condition. + */ +const zPluginConfigVisibilityCondition = z.object({ + condition: z.enum(["", "!", "<", ">", "=", "><", "*", "ne"]), + field: z.string(), + value: z.any(), + valueTwo: z.any().nullish(), +}); + +/** + * A single configuration field of a plugin. + */ +const zGenericConfigField = z.object({ + defaultValue: z.any(), + field: z.string(), + icon: zIcon.nullish(), + name: z.string().nullish(), + placeholder: z.string().nullish(), + required: z.boolean().nullish(), + tooltip: z.string().nullish(), + type: z.string(), + visibility_conditions: z.array(zPluginConfigVisibilityCondition).nullish(), +}); + +/** + * The configuration for a basic option field (label and value). + */ +const zBasicOption = z.object({ + label: z.string(), + value: z.string(), +}); + +/** + * The configuration for a "option" field. + */ +const zPluginConfigFieldOption = zGenericConfigField.extend({ + type: z.literal("option"), + options: z.array(zBasicOption), +}); + +/** + * The configuration for a "string" field. + */ +const zPluginConfigFieldString = zGenericConfigField.extend({ + type: z.literal("string"), + defaultValue: z.string().nullish(), +}); + +/** + * The configuration for a "number" field. + */ +const zPluginConfigFieldNumber = zGenericConfigField.extend({ + type: z.literal("number"), + defaultValue: z.number().nullish(), + min: z.number().nullish(), + max: z.number().nullish(), +}); + +/** + * The configuration for a "password" field. + */ +const zPluginConfigFieldPassword = zGenericConfigField.extend({ + type: z.literal("password"), + defaultValue: z.string().nullish(), +}); + +/** + * The configuration for a "boolean" field. + */ +const zPluginConfigFieldBoolean = zGenericConfigField.omit({ placeholder: true, required: true }).extend({ + type: z.literal("boolean"), + defaultValue: z.boolean().nullish(), +}); + +/** + * The configuration for a "divisor" field. + */ +const zPluginConfigFieldDivisor = z.object({ + visibility_conditions: z.array(zPluginConfigVisibilityCondition).nullish(), + type: z.literal("divisor"), +}); + +/** + * The configuration for a "file" field. + */ +const zPluginConfigFieldFile = zGenericConfigField.extend({ + type: z.literal("file"), + defaultValue: z.string().nullish(), +}); + +/** + * The configuration for a "folder" field. + */ +const zPluginConfigFieldFolder = zGenericConfigField.extend({ + type: z.literal("folder"), + defaultValue: z.string().nullish(), +}); + +/** + * The configuration for a "string-list" field. + */ +const zPluginConfigFieldStringList = zGenericConfigField.extend({ + type: z.literal("string-list"), + title: z.string().optional(), + description: z.string().optional(), + defaultValue: z.array(z.string()).nullish(), +}); + +/** + * The configuration for a "select-key-select-value" field. + */ +const zPluginConfigFieldSelectKeySelectValue = zGenericConfigField.extend({ + type: z.literal("select-key-select-value"), + title: z.string().optional(), + description: z.string().optional(), + key: z.object({ + options: z.array(zBasicOption), + }), + value: z.object({ + options: z.array(zBasicOption), + }), +}); + +/** + * Configuration for non-recursive fields (without a .configs array). + */ +const zNonRecursiveFields = z.discriminatedUnion("type", [ + zPluginConfigFieldNumber, + zPluginConfigFieldStringList, + zPluginConfigFieldSelectKeySelectValue, + zPluginConfigFieldOption, + zPluginConfigFieldString, + zPluginConfigFieldPassword, + zPluginConfigFieldBoolean, + zPluginConfigFieldFile, + zPluginConfigFieldFolder, + zPluginConfigFieldDivisor, +]); + +// ! Attention: +// These types exist because zod doesn't auto-infer types on recursive objects. +// The "row" and "group" don't automatically have types because they use +// the `configs` property recursively, so we have to manually provide the types +// to them via Typescript and using the z.lazy(() => {}) function. + +type INonRecursiveFields = z.infer; + +export type IShallowGroupField = { + type: "group"; + icon?: string | null; + name?: string | null; + field: string; + configs: (INonRecursiveFields | IShallowGroupField | IShallowRowField | IShallowRadioField)[]; + visibility_conditions?: z.infer[] | null; +}; + +export type IShallowRowField = { + type: "row"; + configs: (INonRecursiveFields | IShallowGroupField | IShallowRowField | IShallowRadioField)[]; + visibility_conditions?: z.infer[] | null; +}; + +export type IShallowRadioField = { + type: "radio"; + field: string; + defaultValue?: string | null; + options: Array<{ + label?: string | null; + value: string; + color?: string | null; + icon?: string | null; + description?: string | null; + configs: (INonRecursiveFields | IShallowGroupField | IShallowRowField | IShallowRadioField)[]; + }>; + visibility_conditions?: z.infer[] | null; +}; + +/** + * The configuration for a "row" field. + */ +const zPluginConfigFieldRow: z.ZodType = z.lazy(() => + zGenericConfigField.extend({ + type: z.literal("row"), + configs: z.array( + zNonRecursiveFields.or(zPluginConfigFieldRow).or(zPluginConfigFieldGroup).or(zPluginConfigFieldRadio) + ), + }) +); + +/** + * The configuration for a "group" field. + */ +const zPluginConfigFieldGroup: z.ZodType = z.lazy(() => + zGenericConfigField.extend({ + type: z.literal("group"), + configs: z.array( + zNonRecursiveFields.or(zPluginConfigFieldRow).or(zPluginConfigFieldGroup).or(zPluginConfigFieldRadio) + ), + }) +); + +/** + * The configuration for a "radio" field. + */ +const zPluginConfigFieldRadio: z.ZodType = z.lazy(() => + zGenericConfigField.omit({ icon: true, name: true }).extend({ + type: z.literal("radio"), + defaultValue: z.string().nullish(), + options: z.array( + z.object({ + label: z.string().nullish(), + value: z.string(), + color: z.string().nullish(), + icon: zIcon.nullish(), + description: z.string().nullish(), + configs: z.array( + zNonRecursiveFields.or(zPluginConfigFieldRow).or(zPluginConfigFieldGroup).or(zPluginConfigFieldRadio) + ), + }) + ), + }) +); + +/** + * All field configurations. + */ +export const zPluginConfigField = zPluginConfigFieldRadio + .or(zPluginConfigFieldNumber) + .or(zPluginConfigFieldStringList) + .or(zPluginConfigFieldSelectKeySelectValue) + .or(zPluginConfigFieldOption) + .or(zPluginConfigFieldString) + .or(zPluginConfigFieldPassword) + .or(zPluginConfigFieldBoolean) + .or(zPluginConfigFieldFile) + .or(zPluginConfigFieldFolder) + .or(zPluginConfigFieldDivisor) + .or(zPluginConfigFieldRow) + .or(zPluginConfigFieldGroup); + +/** + * This is an exchanged message between the main API thread + * and the plugin worker thread. + */ +const zPluginMessage = z.object({ + connectionID: z.string(), + error: z.any().optional(), + event: z.string().optional(), + method: z.string(), + params: z.any(), + setupID: z.string().optional(), + type: z.enum(["pluginRequest", "pluginResponse", "apiRequest", "apiResponse"]).optional(), +}); + +/** + * Generic setup configuration of a plugin. + * Other types of plugin may inherit this interface and expand on it. + */ +const zPluginSetup = z.object({ + id: z.string(), + name: z.string(), + configs: z.array(zPluginConfigField).optional(), + type: zPluginType, +}); + +/** + * Setup configuration for "action-trigger" plugins. + */ +const zActionTriggerModuleSetup = zPluginSetup.omit({ type: true }).extend({ + option: z.object({ + configs: z.array(zPluginConfigField).optional(), + description: z.string(), + name: z.string(), + showDeviceSelector: z.boolean().optional(), + }), +}); + +/** + * Setup configuration for "action-type" plugins. + */ +const zActionTypeModuleSetup = zPluginSetup.omit({ type: true }).extend({ + option: z.object({ + configs: z.array(zPluginConfigField).optional(), + description: z.string().optional(), + icon: zIcon.optional(), + name: z.string(), + }), +}); + +/** + * Storage item of a plugin. + */ +const zPluginStorageItem = z.object({ + key: z.string(), + type: z.enum(["string", "number", "boolean", "object", "null"]), + value: z.any(), +}); + +/** + * Configuration to set a plugin storage item. + */ +export const zPluginStorageItemSet = zPluginStorageItem.omit({ created_at: true, type: true }).transform((x) => { + let type = "string"; + if (x.value === null) { + type = "null"; + } else if (typeof x.value === "boolean") { + type = "boolean"; + } else if (typeof x.value === "string") { + type = "string"; + } else if (typeof x.value === "number") { + type = "number"; + } else if (typeof x.value === "object") { + type = "object"; + } + return { + ...x, + type, + }; +}); + +/** + */ +export const zModuleState = z.enum(["idle", "stopping", "starting", "started", "stopped"]); + +/** + */ +export const zPluginState = z.enum(["idle", "disabled", "stopping", "starting", "started", "stopped"]); + +/** + */ +export const zPluginModule = zPluginSetup.extend({ + error: z.string().nullish(), + state: zModuleState, + message: z.any(), +}); + +/** + */ +export const zPlugin = z.object({ + publisher: z.object({ + name: z.string(), + domain: z.string().nullish(), + }), + slug: z.string(), + state: zPluginState, + id: z.string(), + full_description: z.string(), + short_description: z.string(), + name: z.string(), + modules: z.array(zPluginModule), + version: z.string(), + error: z.string().nullish(), +}); + +/** + * Configuration to show a message in the module. + */ +export const zModuleMessageOptions = z.object({ + icon: zIcon.nullish(), + color: z.string().nullish(), + message: z.string(), + iconColor: z.string().nullish(), +}); + +/** + * Configuration of a type of message in a module. + */ +export const zModuleMessageType = z.enum(["info", "error", "warning"]); + +/** + * Configuration of item in a plugin list. + */ +const zPluginListItem = z.object({ + buttons: z.array(zPluginListItemButton).nullish(), + error: z.boolean().nullish(), + hidden: z.boolean().nullish(), + id: z.string(), + name: z.string(), + version: z.string(), + state: zPluginState, +}); + +/** + * Configuration of the list of plugins. + */ +const zPluginList = z.array(zPluginListItem); + +/** + * Settings file content of the plugin. + */ +const zPluginSettingsModule = z.object({ + id: z.string(), + values: z.any(), +}); + +/** + * Settings file content of the plugin. + */ +const zPluginSettings = z.object({ + disabled: z.boolean(), + modules: z.array(zPluginSettingsModule), +}); + +export type IActionTriggerModuleSetup = z.infer; +export type IActionTypeModuleSetup = z.infer; +export type IModuleMessageOptions = z.infer; +export type IModuleSetup = z.infer; +export type IModuleSetupWithoutType = Omit; +export type IPlugin = z.infer; +export type IPluginClassListItem = z.infer; +export type IPluginConfigField = z.infer; +export type IPluginConfigFieldBoolean = z.infer; +export type IPluginConfigFieldDivisor = z.infer; +export type IPluginConfigFieldFile = z.infer; +export type IPluginConfigFieldFolder = z.infer; +export type IPluginConfigFieldGroup = z.infer; +export type IPluginConfigFieldNumber = z.infer; +export type IPluginConfigFieldOption = z.infer; +export type IPluginConfigFieldPassword = z.infer; +export type IPluginConfigFieldRadio = z.infer; +export type IPluginConfigFieldRow = z.infer; +export type IPluginConfigFieldString = z.infer; +export type IPluginConfigFieldStringList = z.infer; +export type IPluginInstallOptions = z.infer; +export type IPluginList = z.infer; +export type IPluginListItem = z.infer; +export type IPluginLogChannel = z.infer; +export type IPluginMessage = z.infer; +export type IPluginModule = z.infer; +export type IPluginPayloadEncoderList = {}; +export type IPluginSettings = z.infer; +export type IPluginSettingsModule = z.infer; +export type IPluginStorageItem = z.infer; +export type IPluginStorageItemSet = z.infer; +export type TModuleMessageType = z.infer; +export type TModuleState = z.infer; +export type TPluginState = z.infer; +export type TPluginType = z.infer; +export type TPluginPermission = z.infer; diff --git a/packages/tcore-sdk/src/Types/ResourceID.ts b/packages/tcore-sdk/src/Types/ResourceID.ts new file mode 100644 index 00000000..db809930 --- /dev/null +++ b/packages/tcore-sdk/src/Types/ResourceID.ts @@ -0,0 +1,29 @@ +import { customAlphabet } from "nanoid"; + +const hexAlphabet = "1234567890abcdef"; +const nanoid = customAlphabet(hexAlphabet, 20); + +/** + * Generate a Hex Format ID with 24 characters for resources. + * The ID will be unique and can be used to identify a resource uniquely. + */ +export function generateResourceID(): string { + const firstCase = String(Date.now()).slice(0, 2).split("").reverse().join(""); + const secondCase = Buffer.from([Number(String(Date.now()).slice(2, 4))]).toString("hex"); + return `${firstCase}${secondCase}${nanoid()}`; +} + +/** + * Checks if a resource ID is valid or not. + * @param id ResourceID + * @returns Boolean + */ +export function validateResourceID(id?: string): boolean { + const idSafe = String(id); + + if (idSafe.length != 24) { + return false; + } + + return true; +} diff --git a/packages/tcore-sdk/src/Types/Settings/Settings.types.test.ts b/packages/tcore-sdk/src/Types/Settings/Settings.types.test.ts new file mode 100644 index 00000000..9f6aafc7 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Settings/Settings.types.test.ts @@ -0,0 +1,15 @@ +import { zSettings } from "./Settings.types"; + +test("requires `plugin_folder` property", async () => { + const data = {}; + const fn = () => zSettings.parse(data); + expect(fn).toThrow(); +}); + +// test("parses object with `plugin_folder`", async () => { +// const data: ISettings = { plugin_folder: "./" }; +// const parsed = await zSettings.parseAsync(data); +// expect(parsed.database_plugin).toBeUndefined(); +// expect(parsed.port).toEqual(8888); +// expect(parsed.settings_folder).toBeUndefined(); +// }); diff --git a/packages/tcore-sdk/src/Types/Settings/Settings.types.ts b/packages/tcore-sdk/src/Types/Settings/Settings.types.ts new file mode 100644 index 00000000..addab948 --- /dev/null +++ b/packages/tcore-sdk/src/Types/Settings/Settings.types.ts @@ -0,0 +1,29 @@ +import { z } from "zod"; +import preprocessNumber from "../Helpers/preprocessNumber"; + +/** + * Configuration of the application settings. + */ +export const zSettings = z.object({ + database_plugin: z.string().optional(), + filesystem_plugin: z.string().optional(), + plugin_folder: z.string().nonempty(), + plugin_auto_update_enable: z.boolean().optional(), + plugin_auto_update_check_time: z.preprocess(preprocessNumber, z.number().nullish()), + plugin_auto_update_last_checked_time: z.string().optional(), + port: z + .preprocess((x) => Number(x), z.number()) + .optional() + .default(8888) + .or(z.undefined()), + settings_folder: z.string().optional(), +}); + +export const zSettingsMetadata = z.object({ + database_plugin_disabled: z.boolean(), + plugin_folder_disabled: z.boolean(), + port_disabled: z.boolean(), +}); + +export type ISettings = z.infer; +export type ISettingsMetadata = z.infer; diff --git a/packages/tcore-sdk/src/Types/Socket.types.ts b/packages/tcore-sdk/src/Types/Socket.types.ts new file mode 100644 index 00000000..6e40cfbd --- /dev/null +++ b/packages/tcore-sdk/src/Types/Socket.types.ts @@ -0,0 +1,21 @@ +/* eslint-disable no-unused-vars */ + +export enum ESocketResource { + pluginInstall = 1, + deviceInspection = 2, + log = 3, + statistic = 4, + analysis = 5, + plugin = 5, + module = 6, +} + +export enum ESocketRoom { + statistic = "room::statistic", + deviceInspection = "room::device::inspection", + log = "room::log", + pluginInstall = "room::plugin::install", + analysis = "room::analysis", + plugin = "room::plugin", + module = "room::plugin::module", +} diff --git a/packages/tcore-sdk/src/Types/Statistic.types.ts b/packages/tcore-sdk/src/Types/Statistic.types.ts new file mode 100644 index 00000000..58b83c1e --- /dev/null +++ b/packages/tcore-sdk/src/Types/Statistic.types.ts @@ -0,0 +1,18 @@ +import { z } from "zod"; + +/** + * Base configuration of a statistic. + */ +export const zStatistic = z.object({ + input: z.number(), + output: z.number(), + time: z.date(), +}); + +/** + * Configuration to create a statistic. + */ +export const zStatisticCreate = zStatistic.omit({ time: true }).partial(); + +export type IStatistic = z.infer; +export type IStatisticCreate = z.infer; diff --git a/packages/tcore-sdk/src/Types/Summary.types.ts b/packages/tcore-sdk/src/Types/Summary.types.ts new file mode 100644 index 00000000..2dcfa55e --- /dev/null +++ b/packages/tcore-sdk/src/Types/Summary.types.ts @@ -0,0 +1,9 @@ +import { z } from "zod"; + +export const zSummary = z.object({ + device: z.number(), + analysis: z.number(), + action: z.number(), +}); + +export type ISummary = z.infer; diff --git a/packages/tcore-sdk/src/Types/Tag.types.ts b/packages/tcore-sdk/src/Types/Tag.types.ts new file mode 100644 index 00000000..c3b0ff6e --- /dev/null +++ b/packages/tcore-sdk/src/Types/Tag.types.ts @@ -0,0 +1,10 @@ +import { z } from "zod"; + +export const zTag = z.object({ + key: z.string(), + value: z.string(), +}); + +export const zTags = z.array(zTag); + +export type ITag = z.infer; diff --git a/packages/tcore-sdk/src/Types/index.ts b/packages/tcore-sdk/src/Types/index.ts new file mode 100644 index 00000000..db4346bd --- /dev/null +++ b/packages/tcore-sdk/src/Types/index.ts @@ -0,0 +1,18 @@ +export * from "./Action.types"; +export * from "./Analysis.types"; +export * from "./DeviceData/DeviceData.types"; +export * from "./Common/Common.types"; +export * from "./Connector.types"; +export * from "./DatabaseModule/DatabaseModule.types"; +export * from "./Device/Device.types"; +export * from "./LiveInspector.types"; +export * from "./Hardware.types"; +export * from "./Log.types"; +export * from "./Network.types"; +export * from "./Plugin.types"; +export * from "./ResourceID"; +export * from "./Settings/Settings.types"; +export * from "./Socket.types"; +export * from "./Statistic.types"; +export * from "./Summary.types"; +export * from "./Tag.types"; diff --git a/packages/tcore-sdk/tsconfig.json b/packages/tcore-sdk/tsconfig.json new file mode 100644 index 00000000..1f15187a --- /dev/null +++ b/packages/tcore-sdk/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "allowJs": true, + "sourceMap": false, + "outDir": "./build", + "strict": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": false, + "rootDir": "./src", + "baseUrl": ".", + "declaration": true, + "skipLibCheck": true, + }, + "exclude": [ + "node_module", + "jest.config.js" + ], + "include": [ + "src/**/*" + ], + "ts-node": { + "transpileOnly": true + }, +} diff --git a/packages/tcore-sdk/types.d.ts b/packages/tcore-sdk/types.d.ts new file mode 100644 index 00000000..ed3738e4 --- /dev/null +++ b/packages/tcore-sdk/types.d.ts @@ -0,0 +1 @@ +export * from "./build/Types"; diff --git a/packages/tcore-sdk/types.js b/packages/tcore-sdk/types.js new file mode 100644 index 00000000..d86a1f31 --- /dev/null +++ b/packages/tcore-sdk/types.js @@ -0,0 +1 @@ +module.exports = require("./build/Types"); diff --git a/packages/tcore-shared/.eslintignore b/packages/tcore-shared/.eslintignore new file mode 100644 index 00000000..729abf75 --- /dev/null +++ b/packages/tcore-shared/.eslintignore @@ -0,0 +1,10 @@ +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +__build__* +.eslintrc.js +jest.config.js +esbuild/* diff --git a/packages/tcore-shared/.eslintrc.js b/packages/tcore-shared/.eslintrc.js new file mode 100644 index 00000000..d6aa3f56 --- /dev/null +++ b/packages/tcore-shared/.eslintrc.js @@ -0,0 +1,31 @@ +module.exports = { + env: { + node: true, + jest: true + }, + root: true, + parserOptions: { + ecmaVersion: 6, + sourceType: "module", + ecmaFeatures: { + jsx: false, + }, + tsconfigRootDir: __dirname, + project: ["./tsconfig.json"], + }, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "import"], + ignorePatterns: ['.eslintrc.js', 'types.js', 'types.d.ts'], + extends: [ + "plugin:prettier/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript", + "eslint:recommended" + ], + rules: { + "import/order": 1, + "no-unused-vars": 0 + }, +}; diff --git a/packages/tcore-shared/.prettierrc b/packages/tcore-shared/.prettierrc new file mode 100644 index 00000000..3ae934c4 --- /dev/null +++ b/packages/tcore-shared/.prettierrc @@ -0,0 +1,11 @@ +{ + "trailingComma": "es5", + "printWidth": 120, + "useTabs": false, + "tabWidth": 2, + "semi": true, + "singleQuote": false, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/packages/tcore-shared/README.md b/packages/tcore-shared/README.md new file mode 100644 index 00000000..606990d0 --- /dev/null +++ b/packages/tcore-shared/README.md @@ -0,0 +1 @@ +Shared functions and helpers for all tcore-related packages. diff --git a/packages/tcore-shared/jest.config.js b/packages/tcore-shared/jest.config.js new file mode 100644 index 00000000..27c177bb --- /dev/null +++ b/packages/tcore-shared/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + roots: ['/src'], + testRegex: '(/__tests__/.*|(\\.|/)test)\\.ts?$' +}; diff --git a/packages/tcore-shared/package.json b/packages/tcore-shared/package.json new file mode 100644 index 00000000..81a355e0 --- /dev/null +++ b/packages/tcore-shared/package.json @@ -0,0 +1,13 @@ +{ + "name": "@tago-io/tcore-shared", + "version": "0.3.3", + "private": true, + "main": "./build/index.js", + "scripts": { + "clean": "rm -rf node_modules; rm -rf package-lock.json", + "build": "rm -rf ./build; tsc" + }, + "dependencies": { + "@tago-io/tcore-sdk": "*" + } +} diff --git a/packages/tcore-shared/src/Plugin/flattenConfigFields.ts b/packages/tcore-shared/src/Plugin/flattenConfigFields.ts new file mode 100644 index 00000000..0a6157e4 --- /dev/null +++ b/packages/tcore-shared/src/Plugin/flattenConfigFields.ts @@ -0,0 +1,33 @@ +import { IPluginConfigField } from "@tago-io/tcore-sdk/types"; + +/** + */ +function flattenConfigFields(configs: IPluginConfigField[]): IPluginConfigField[] { + const data: IPluginConfigField[] = []; + + for (const field of configs) { + if ("field" in field && field.field) { + data.push(field); + } + + if ("options" in field && field.options) { + // radio has options, each option has configs + for (const option of field.options) { + if ("configs" in option && option.configs) { + const subData = flattenConfigFields(option.configs); + data.push(...subData); + } + } + } + + if ("configs" in field && field.configs) { + // row, group, and other fields have a `configs` option + const subData = flattenConfigFields(field.configs); + data.push(...subData); + } + } + + return data; +} + +export default flattenConfigFields; diff --git a/packages/tcore-shared/src/System/System.ts b/packages/tcore-shared/src/System/System.ts new file mode 100644 index 00000000..7f7fc955 --- /dev/null +++ b/packages/tcore-shared/src/System/System.ts @@ -0,0 +1,16 @@ +// @ts-ignore +import data from "../../../../data.json"; + +/** + */ +function getSystemSlug() { + return data.slug; +} + +/** + */ +function getSystemName() { + return data.name; +} + +export { getSystemSlug, getSystemName }; diff --git a/packages/tcore-shared/src/index.ts b/packages/tcore-shared/src/index.ts new file mode 100644 index 00000000..f17026c6 --- /dev/null +++ b/packages/tcore-shared/src/index.ts @@ -0,0 +1,3 @@ +import flattenConfigFields from "./Plugin/flattenConfigFields"; + +export { flattenConfigFields }; diff --git a/packages/tcore-shared/tsconfig.json b/packages/tcore-shared/tsconfig.json new file mode 100644 index 00000000..1f15187a --- /dev/null +++ b/packages/tcore-shared/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "allowJs": true, + "sourceMap": false, + "outDir": "./build", + "strict": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": false, + "rootDir": "./src", + "baseUrl": ".", + "declaration": true, + "skipLibCheck": true, + }, + "exclude": [ + "node_module", + "jest.config.js" + ], + "include": [ + "src/**/*" + ], + "ts-node": { + "transpileOnly": true + }, +}
+ {isForever ? null : ( + onChangeRetention({ ...retention, value: e.target.value })} + ref={input} + type="number" + value={retention.value || ""} + error={error} + /> + )} + + setValue(e.target.value)} + placeholder="empty bucket" + value={value} + /> + + + ); +} + +export default ModalEmptyDevice; diff --git a/packages/tcore-console/src/Components/Bucket/Common/VariablesTable/VariablesTable.style.ts b/packages/tcore-console/src/Components/Bucket/Common/VariablesTable/VariablesTable.style.ts new file mode 100644 index 00000000..f93f767f --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Common/VariablesTable/VariablesTable.style.ts @@ -0,0 +1,129 @@ +import styled from "styled-components"; +import { ButtonStyle } from "../../../.."; +import { fonts } from "../../../../theme"; +import * as PaginatedTableStyle from "../../../PaginatedTable/PaginatedTable.style"; + +export const Container = styled.div` + flex: 1; + display: flex; + height: 100%; + min-height: 0; + + ${PaginatedTableStyle.Container} { + flex: 1; + margin: -15px; + margin-top: 0; + border-radius: 0; + border-left: 0; + border-right: 0; + border-bottom: 0; + } +`; + +export const Checkbox = styled.div` + margin: -5px 0px; + cursor: pointer; +`; + +export const Pencil = styled.div` + cursor: pointer; + padding: 5px 7px; + border-radius: 5px; + display: none; + margin: -5px 0px; + margin-left: 5px; + + &:hover { + background: rgba(0, 0, 0, 0.1); + } + + &:active { + background: rgba(0, 0, 0, 0.15); + } + + i { + opacity: 0.8; + top: 1px; + position: relative; + } +`; + +export const CopyButtonContainer = styled.div` + position: absolute; + left: 50%; + transform: translate(-50%, 0); + + ${ButtonStyle.Container} { + padding: 7px; + width: 35px; + background: transparent; + + &:hover { + background: rgba(0, 0, 0, 0.1); + } + + &:active { + background: rgba(0, 0, 0, 0.15); + } + } +`; + +export const LocationContainer = styled.div` + text-overflow: ellipsis; + width: 100%; + display: flex; + + > span { + overflow: hidden; + text-overflow: ellipsis; + } + + a { + cursor: pointer; + + &:hover { + opacity: 0.8; + } + &:active { + opacity: 0.5; + } + } +`; + +export const IDContainer = styled.div` + text-overflow: ellipsis; + overflow: hidden; + width: 40px; + display: flex; + cursor: pointer; + direction: rtl; + text-align: left; + + * { + font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; + } + + &:hover { + opacity: 0.8; + } + &:active { + opacity: 0.5; + } +`; + +export const ValueContainer = styled.div` + display: flex; + align-items: center; + width: 100%; + + > .value { + margin-right: 5px; + overflow: hidden; + text-overflow: ellipsis; + } + + > .type { + font-size: ${() => fonts.small}; + opacity: 0.6; + } +`; diff --git a/packages/tcore-console/src/Components/Bucket/Common/VariablesTable/VariablesTable.tsx b/packages/tcore-console/src/Components/Bucket/Common/VariablesTable/VariablesTable.tsx new file mode 100644 index 00000000..c0c72357 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Common/VariablesTable/VariablesTable.tsx @@ -0,0 +1,419 @@ +import { useCallback, useEffect, useState } from "react"; +import { useRouteMatch } from "react-router"; +import { IDeviceData, IDevice } from "@tago-io/tcore-sdk/types"; +import RelativeDate from "../../../RelativeDate/RelativeDate"; +import CopyButton from "../../../CopyButton/CopyButton"; +import TooltipText from "../../../TooltipText/TooltipText"; +import Checkbox from "../../../Checkbox/Checkbox"; +import { EIcon } from "../../../Icon/Icon.types"; +import { IFilter } from "../../../PaginatedTable/PaginatedTable.types"; +import PaginatedTable from "../../../PaginatedTable/PaginatedTable"; +import getDeviceData from "../../../../Requests/getDeviceData"; +import ModalListConfiguration from "../../../ModalListConfiguration/ModalListConfiguration"; +import getDateTimeObject from "../../../../Helpers/getDateTimeObject"; +import { getLocalStorageAsJSON } from "../../../../Helpers/localStorage"; +import { Icon } from "../../../.."; +import copyToClipboard from "../../../../Helpers/copyToClipboard"; +import ModalEditValue from "../../Edit/ModalEditValue/ModalEditValue"; +import ModalEditGroup from "../../Edit/ModalEditGroup/ModalEditGroup"; +import ModalEditMetadata from "../../Edit/ModalEditMetadata/ModalEditMetadata"; +import ModalEditLocation from "../../Edit/ModalEditLocation/ModalEditLocation"; +import * as Style from "./VariablesTable.style"; + +/** + * Props. + */ +interface IVariablesTableProps { + /** + * Device info. + */ + data: IDevice; + /** + */ + onChangeSelected: (selected: IDeviceData[]) => void; + /** + */ + onReloadTable: () => void; + /** + */ + onReloadDataAmount: () => void; + /** + * Data amount in the bucket. + */ + dataAmount: number; + /** + */ + refetchID?: number; +} + +/** + * The variables table of the bucket page. + */ +function VariablesTable(props: IVariablesTableProps) { + const { dataAmount, onReloadDataAmount, onReloadTable, onChangeSelected, refetchID, data } = + props; + + const [dateFormat, setDateFormat] = useState(() => { + const dd = getLocalStorageAsJSON(`${data.id}::data::settings`); + return dd?.dateFormat || ""; + }); + const [enabledColumns, setEnabledColumns] = useState(() => { + const dd = getLocalStorageAsJSON(`${data.id}::data::settings`); + return dd?.enabledColumns || {}; + }); + + /** + * End date for pinning the requests. + * + * Handles the user paginating through the table while new data is arriving in the device, + * making the requests never return data more recent than the pinned date until a page reload + * or the `refreshData` function is used. + */ + const [currentEndDate, setCurrentEndDate] = useState(() => new Date().toISOString()); + + const [edit, setEdit] = useState(null); + const [modalListConfiguration, setModalListConfiguration] = useState(false); + const [amountOfRecords, setAmountOfRecords] = useState(0); + const [selectedVariables, setSelectedVariables] = useState({}); + const [hasLocation, setHasLocation] = useState(false); + const [hasMetadata, setHasMetadata] = useState(false); + const [page, setPage] = useState(0); + const match = useRouteMatch<{ id: string }>(); + const { id } = match.params; + + /** + * Called by the table to retrieve data for a page. + */ + const onGetData = async (_page: number, amount: number, filter: IFilter) => { + const result = await getDeviceData(id, page, amount, filter, currentEndDate); + setAmountOfRecords(result.length); + setHasLocation(result.some((x) => x.location)); + setHasMetadata(result.some((x) => x.metadata)); + return result; + }; + + /** + * Copies the json. + */ + const copyJSON = (item: IDeviceData) => { + copyToClipboard(JSON.stringify(item, null, 2)); + }; + + /** + */ + const refresh = useCallback(() => { + onReloadDataAmount(); + setCurrentEndDate(new Date().toISOString()); + if (page === 0) { + onReloadTable(); + } else { + setPage(0); + } + }, [onReloadDataAmount, onReloadTable, page]); + + /** + * Renders the metadata of the item. + */ + const renderMetadata = (item: IDeviceData) => { + const keys = Object.keys(item.metadata || {}).length; + const tooltip =
{JSON.stringify(item.metadata, null, 2)}
; + + return ( +
+ + {`${keys} Item${keys === 1 ? "" : "s"}`} + + {renderPencil(item, "metadata")} +
+ ); + }; + + /** + */ + const renderLocation = (item: IDeviceData) => { + if (!item.location || !item.location.coordinates) { + return {renderPencil(item, "location")}; + } + + const lat = item.location.coordinates[1]; + const lng = item.location.coordinates[0]; + const link = `https://www.google.com/maps/search/?api=1&query=${lat},${lng}&zoom=20`; + const label = latLngToDms(lat, lng); + + return ( + + +
+ {label} + + + {renderPencil(item, "location")} + + ); + }; + + /** + */ + const renderID = (item: IDeviceData) => { + return ( + copyToClipboard(item.id)}> + + {item.id.substring(item.id.length - 5)} + + + ); + }; + + /** + */ + const renderCheck = (item: IDeviceData) => { + return ( + + { + if (e.target.checked) { + selectedVariables[item.id] = item; + } else { + delete selectedVariables[item.id]; + } + setSelectedVariables(selectedVariables); + onChangeSelected(Object.keys(selectedVariables).map((x) => selectedVariables[x])); + }} + /> + + ); + }; + + /** + */ + const renderPencil = (item: IDeviceData, type: string) => { + if (data.type === "immutable") { + return null; + } + return ( + setEdit({ item, type })}> + + + ); + }; + + /** + */ + const renderValue = (item: IDeviceData) => { + const type = typeof item.value; + return ( + +
{type === "boolean" ? String(item.value) : item.value}
+
({type})
+ {renderPencil(item, "value")} +
+ ); + }; + + /** + */ + const renderGroup = (item: IDeviceData) => { + return ( + +
{item.group}
+ {renderPencil(item, "group")} +
+ ); + }; + + /** + */ + const renderCopyButton = (item: IDeviceData) => { + return ( + + copyJSON(item)} + /> + + ); + }; + + /** + */ + const renderTime = (item: IDeviceData) => { + if (!dateFormat || dateFormat === "relative") { + return ; + } else { + return getDateTimeObject(item.time)?.toFormat(dateFormat); + } + }; + + /** + * Clears the amount of records. + */ + useEffect(() => { + if (!dataAmount) { + // this will make the paginated table refresh the data by calling `onGetData` + setAmountOfRecords(0); + } + }, [dataAmount]); + + const showLocationColumn = enabledColumns.location === true ? true : hasLocation; + const showMetadataColumn = enabledColumns.metadata === true ? true : hasMetadata; + + return ( + + {modalListConfiguration && ( + { + const dd = getLocalStorageAsJSON(`${data.id}::data::settings`); + setEnabledColumns(dd?.enabledColumns || {}); + setDateFormat(dd?.dateFormat || ""); + setModalListConfiguration(false); + }} + deviceID={data.id} + /> + )} + + + amountOfRecords={amountOfRecords} + refetchID={refetchID} + columns={[ + data.type === "immutable" + ? null + : { + label: "", + onRender: renderCheck, + filterVisible: false, + type: "icon", + flex: "none", + width: 30, + id: "check", + }, + enabledColumns.id === false + ? null + : { + flex: "none", + id: "id", + label: "ID", + onRender: renderID, + tooltip: "ID of the data item", + width: 80, + filterDisabled: data.type === "immutable", + }, + enabledColumns.variable === false + ? null + : { + label: "Variable", + onRender: (item) => item.variable, + tooltip: "Name of the variable", + id: "variable", + }, + enabledColumns.value === false + ? null + : { + label: "Value", + onRender: renderValue, + tooltip: "Value of the data item", + id: "value", + }, + enabledColumns.group === false + ? null + : { + label: "Group", + onRender: renderGroup, + tooltip: "Group of this item", + id: "group", + }, + showLocationColumn + ? { + label: "Location", + onRender: renderLocation, + tooltip: "Location of the data item", + id: "location", + filterDisabled: true, + } + : null, + showMetadataColumn + ? { + label: "Metadata", + onRender: renderMetadata, + tooltip: "Metadata of the data item", + width: 90, + flex: "none", + id: "metadata", + filterDisabled: true, + } + : null, + enabledColumns.time === false + ? null + : { + label: "Time", + onRender: renderTime, + tooltip: "Time of the data item", + width: 190, + flex: "none", + id: "time", + type: "date", + }, + { + label: "", + onRender: renderCopyButton, + filterVisible: false, + type: "icon", + flex: "none", + width: 60, + id: "copy", + }, + ]} + emptyMessage="No data found." + emptyMessageIcon={EIcon.cube} + onChangePage={setPage} + onGetData={onGetData} + infinitePages + page={page} + showConfigButton + showRefreshButton + onConfigButtonClick={() => setModalListConfiguration(true)} + onRefreshButtonClick={refresh} + /> + + {edit?.type === "value" ? ( + setEdit(null)} /> + ) : edit?.type === "group" ? ( + setEdit(null)} /> + ) : edit?.type === "metadata" ? ( + setEdit(null)} /> + ) : edit?.type === "location" ? ( + setEdit(null)} device={data} data={edit.item} /> + ) : null} + + ); +} + +/** + * Converts lat/lng into into degrees minutes seconds. + * { "lat": 35.770723, "lng": -78.677328 } becomes 35°46'14.6"N 78°40'38.4"W. + */ +function latLngToDms(lat: number, lng: number) { + const separate = (data: number) => { + const split = String(data).split("."); + const a1 = Number(split[0]); + const a2 = Number(`0.${split[1] || 0}`); + return [a1, a2]; + }; + + const [latT, latD] = separate(lat); // latitude separated into thousand and decimal + const [latM, latMD] = separate(latD * 60); // converts decimals of lat into minutes and decimal minutes + const latS = latMD * 60; // converts the decimals of lat minutes into seconds and decimal seconds + + const [lngT, lngD] = separate(lng); // longitude separated into thousand and decimal + const [lngM, lngMD] = separate(lngD * 60); // converts decimals of lng into minutes and decimal minutes + const lngS = lngMD * 60; // converts the decimals of lng minutes into seconds and decimal seconds + + const latDms = `${Math.abs(latT)}°${latM}'${Math.round(latS * 10) / 10}"${lat < 0 ? "S" : "N"}`; + const lngDms = `${Math.abs(lngT)}°${lngM}'${Math.round(lngS * 10) / 10}"${lng < 0 ? "W" : "E"}`; + const full = `${latDms} ${lngDms}`; + + return full; +} + +export default VariablesTable; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/BucketEdit.test.tsx b/packages/tcore-console/src/Components/Bucket/Edit/BucketEdit.test.tsx new file mode 100644 index 00000000..7c46eb5f --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/BucketEdit.test.tsx @@ -0,0 +1,9 @@ +jest.mock("../../../Helpers/useApiRequest.ts"); + +import { render } from "../../../../utils/test-utils"; +import BucketEdit from "./BucketEdit"; + +test("renders without crashing", () => { + const fn = () => render(); + expect(fn).not.toThrowError(); +}); diff --git a/packages/tcore-console/src/Components/Bucket/Edit/BucketEdit.tsx b/packages/tcore-console/src/Components/Bucket/Edit/BucketEdit.tsx new file mode 100644 index 00000000..c75e4c7d --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/BucketEdit.tsx @@ -0,0 +1,206 @@ +import { IDevice } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { useRouteMatch } from "react-router"; +import { useTheme } from "styled-components"; +import { formatDataAmount } from "../../../Helpers/formatDataAmount"; +import getDeviceTypeName from "../../../Helpers/getDeviceTypeName"; +import useApiRequest from "../../../Helpers/useApiRequest"; +import deleteDeviceData from "../../../Requests/deleteDeviceData"; +import editDevice from "../../../Requests/editDevice"; +import buildZodError from "../../../Validation/buildZodError"; +import EditPage from "../../EditPage/EditPage"; +import { EIcon } from "../../Icon/Icon.types"; +import joinBucketDataRetention from "../Helpers/joinDataRetention"; +import separateDataRetention from "../Helpers/separateDataRetention"; +import GeneralInformationTab from "./GeneralInformationTab/GeneralInformationTab"; +import MoreTab from "./MoreTab/MoreTab"; +import VariablesTab from "./VariablesTab/VariablesTab"; + +/** + * The bucket's edit page. + */ +function BucketEdit() { + const match = useRouteMatch<{ id: string }>(); + const { id } = match.params; + + const theme = useTheme(); + const [data, setData] = useState({} as IDevice); + const [tabIndex, setTabIndex] = useState(0); + const [errors, setErrors] = useState({}); + const { data: dataAmount, mutate: mutateDataAmount } = useApiRequest( + `/device/${id}/data_amount` + ); + const [retention, setRetention] = useState({ value: "1", unit: "day" }); + + const initialRetention = useRef(); + + const loading = !data.id || dataAmount === undefined; + + /** + * Called when the record was fetched by the edit page. + * We use this to set the data state to manipulate the object. + */ + const onFetch = useCallback((bucket: IDevice) => { + setData(bucket); + const ret = separateDataRetention(bucket); + initialRetention.current = { ...ret }; + setRetention({ ...ret }); + }, []); + + /** + * Validates the form data to make sure the object is not faulty. + * This should return a boolean to indicate if the data is correct or not. + */ + const validate = useCallback(async () => { + try { + setErrors({}); + return true; + } catch (ex: any) { + const err = buildZodError(ex.issues); + if (err.tags) { + setTabIndex(2); + } else { + setTabIndex(0); + } + setErrors(err); + return false; + } + }, []); + + /** + * Saves the bucket. + */ + const save = useCallback(async () => { + await editDevice(id, { + data_retention: joinBucketDataRetention(retention), + }); + initialRetention.current = { ...retention }; + }, [retention, id]); + + /** + * Empties the bucket. + */ + const emptyBucket = useCallback(async () => { + await axios.post(`/device/${id}/empty`); + window.location.reload(); + await new Promise(() => { + /* to get stuck until reload */ + }); + }, [id]); + + /** + * Deletes certain data points. + */ + const deleteData = useCallback( + async (ids: string[]) => { + await deleteDeviceData(id, { ids }); + mutateDataAmount(Math.max(dataAmount - ids.length, 0)); + }, + [mutateDataAmount, dataAmount, id] + ); + + /** + * Renders the `Variables` tab's content. + */ + const renderVariables = () => { + return ( + mutateDataAmount(dataAmount, true)} + data={data} + dataAmount={dataAmount} + onDeleteData={deleteData} + /> + ); + }; + + /** + * Renders the `General Information` tab's content. + */ + const renderGeneralInformationTab = () => { + return ( + + ); + }; + + /** + * Renders the page's nav description. + */ + const renderDescription = () => { + return ( + <> + Data retention + {data.data_retention || "Forever"} +  |  + Amount of data records + {formatDataAmount(dataAmount)} + +  |  + Type + {getDeviceTypeName(data.type)} + + ); + }; + + /** + * Renders the `More` tab. + */ + const renderMoreTab = useCallback(() => { + return ; + }, [emptyBucket, data, dataAmount]); + + /** + * Should return if the initial data is different from the current data. + */ + const checkIfDataChanged = useCallback(() => { + return JSON.stringify(initialRetention.current) !== JSON.stringify(retention); + }, [retention]); + + /** + */ + useEffect(() => { + if (tabIndex === 1) { + mutateDataAmount(dataAmount, true); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [mutateDataAmount, tabIndex]); + + return ( + + color={theme.bucket} + description={renderDescription()} + documentTitle="Bucket" + icon={EIcon.bucket} + innerNavTitle={data.name || ""} + loading={loading} + onChangeTabIndex={setTabIndex} + onCheckIfDataChanged={checkIfDataChanged} + onFetch={onFetch} + onSave={save} + onValidate={validate} + requestPath="device" + tabIndex={tabIndex} + tabs={[ + { + label: "General Information", + content: renderGeneralInformationTab(), + }, + { + label: "Variables", + content: renderVariables(), + }, + { + label: "More", + content: renderMoreTab(), + }, + ]} + /> + ); +} + +export default BucketEdit; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/GeneralInformationTab/GeneralInformationTab.tsx b/packages/tcore-console/src/Components/Bucket/Edit/GeneralInformationTab/GeneralInformationTab.tsx new file mode 100644 index 00000000..84f3abfb --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/GeneralInformationTab/GeneralInformationTab.tsx @@ -0,0 +1,81 @@ +import { IDevice } from "@tago-io/tcore-sdk/types"; +import Col from "../../../Col/Col"; +import FormDivision from "../../../FormDivision/FormDivision"; +import FormGroup from "../../../FormGroup/FormGroup"; +import { EIcon } from "../../../Icon/Icon.types"; +import Input from "../../../Input/Input"; +import Row from "../../../Row/Row"; +import DataRetention from "../../Common/DataRetention/DataRetention"; +import ResourceLinkField from "../../../ResourceLinkField/ResourceLinkField"; + +/** + * Props. + */ +interface IGeneralInformationTabProps { + /** + * Bucket form data. + */ + data: IDevice; + /** + * Bucket's form errors. + */ + errors: any; + /** + * Retention information. + */ + retention: any; + /** + * Called when a data retention field changes. + */ + onChangeRetention: (newRetention: any) => void; +} + +/** + * The bucket's general information tab. + */ +function GeneralInformationTab(props: IGeneralInformationTabProps) { + const { data, onChangeRetention, retention } = props; + + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ ); +} + +export default GeneralInformationTab; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/ModalEditGroup/ModalEditGroup.style.tsx b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditGroup/ModalEditGroup.style.tsx new file mode 100644 index 00000000..51876222 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditGroup/ModalEditGroup.style.tsx @@ -0,0 +1,13 @@ +import styled from "styled-components"; + +export const Characters = styled.div` + color: rgba(0, 0, 0, 0.6); + display: inline-block; + text-align: right; + font-size: 0.73rem; + position: absolute; + right: 10px; + top: 50%; + transform: translate(0%, -50%); + z-index: 12; +`; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/ModalEditGroup/ModalEditGroup.tsx b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditGroup/ModalEditGroup.tsx new file mode 100644 index 00000000..0ea2d31b --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditGroup/ModalEditGroup.tsx @@ -0,0 +1,68 @@ +import { IDevice, IDeviceData } from "@tago-io/tcore-sdk/types"; +import { useCallback, useState } from "react"; +import { EIcon } from "../../../Icon/Icon.types"; +import { FormGroup, Input, Modal } from "../../../.."; +import editDeviceData from "../../../../Requests/editDeviceData"; +import * as Style from "./ModalEditGroup.style"; + +/** + * Props. + */ +interface IModalEditGroupProps { + /** + * Device. + */ + device: IDevice; + /** + * Data item to be edited. + */ + data: IDeviceData; + /** + * Called when the modal closes. + */ + onClose: () => void; +} + +/** + */ +function ModalEditGroup(props: IModalEditGroupProps) { + const { data, device, onClose } = props; + const [value, setValue] = useState(() => String(data.group || "")); + + /** + */ + const confirm = useCallback(async () => { + data.group = String(value); + await editDeviceData(device.id, data); + }, [value, device?.id, data]); + + return ( + + +
+ setValue(e.target.value.substring(0, 24))} + value={value} + placeholder="Enter the group for the data item" + spellCheck="false" + /> + {String(value).length} / 24 +
+
+
+ ); +} + +export default ModalEditGroup; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/ModalEditLocation/ModalEditLocation.tsx b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditLocation/ModalEditLocation.tsx new file mode 100644 index 00000000..d88da0d6 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditLocation/ModalEditLocation.tsx @@ -0,0 +1,88 @@ +import { IDevice, IDeviceData } from "@tago-io/tcore-sdk/types"; +import { useCallback, useState } from "react"; +import { EIcon } from "../../../Icon/Icon.types"; +import { Col, FormGroup, Input, Modal, Row } from "../../../.."; +import editDeviceData from "../../../../Requests/editDeviceData"; + +/** + * Props. + */ +interface IModalEditLocationProps { + /** + * Device. + */ + device: IDevice; + /** + * Data item to be edited. + */ + data: IDeviceData; + /** + * Called when the modal closes. + */ + onClose: () => void; +} + +/** + */ +function ModalEditLocation(props: IModalEditLocationProps) { + const { data, device, onClose } = props; + const [lat, setLat] = useState(() => data.location?.coordinates?.[1] || ""); + const [lng, setLng] = useState(() => data.location?.coordinates?.[0] || ""); + + /** + */ + const confirm = useCallback(async () => { + data.location = { + type: "Point", + coordinates: [Number(lng), Number(lat)], + }; + await editDeviceData(device.id, data); + }, [lat, lng, device?.id, data]); + + return ( + + + + + setLat(e.target.value)} + value={lat} + placeholder="Enter the latitude for the data item" + /> + + + + + + setLng(e.target.value)} + value={lng} + placeholder="Enter the longitude for the data item" + /> + + + + + ); +} + +export default ModalEditLocation; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/ModalEditMetadata/ModalEditMetadata.style.tsx b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditMetadata/ModalEditMetadata.style.tsx new file mode 100644 index 00000000..b3788aa2 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditMetadata/ModalEditMetadata.style.tsx @@ -0,0 +1,9 @@ +import styled from "styled-components"; +import FormControlStyles from "../../../Styles/FormControlStyles"; + +export const TextArea = styled.textarea` + ${FormControlStyles} + resize: none; + height: 300px; + font-family: Monospace; +`; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/ModalEditMetadata/ModalEditMetadata.tsx b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditMetadata/ModalEditMetadata.tsx new file mode 100644 index 00000000..3af421dc --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditMetadata/ModalEditMetadata.tsx @@ -0,0 +1,75 @@ +import { IDevice, IDeviceData } from "@tago-io/tcore-sdk/types"; +import { useCallback, useState } from "react"; +import { EIcon } from "../../../Icon/Icon.types"; +import { FormGroup, Modal } from "../../../.."; +import editDeviceData from "../../../../Requests/editDeviceData"; +import * as Style from "./ModalEditMetadata.style"; + +/** + * Props. + */ +interface IModalEditMetadataProps { + /** + * Device. + */ + device: IDevice; + /** + * Data item to be edited. + */ + data: IDeviceData; + /** + * Called when the modal closes. + */ + onClose: () => void; +} + +/** + */ +function ModalEditMetadata(props: IModalEditMetadataProps) { + const { data, device, onClose } = props; + const [value, setValue] = useState(() => + data.metadata ? JSON.stringify(data.metadata, null, 2) : "" + ); + + /** + */ + const confirm = useCallback(async () => { + data.metadata = JSON.parse(value); + await editDeviceData(device.id, data); + }, [value, device?.id, data]); + + let validJSON = true; + try { + JSON.parse(value); + validJSON = true; + } catch (ex) { + validJSON = false; + } + + return ( + + + setValue(e.target.value)} + placeholder="Insert a valid JSON" + value={value} + /> + + + ); +} + +export default ModalEditMetadata; diff --git a/packages/tcore-console/src/Components/Bucket/Edit/ModalEditValue/ModalEditValue.tsx b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditValue/ModalEditValue.tsx new file mode 100644 index 00000000..17d56d19 --- /dev/null +++ b/packages/tcore-console/src/Components/Bucket/Edit/ModalEditValue/ModalEditValue.tsx @@ -0,0 +1,108 @@ +import { IDeviceData, IDevice } from "@tago-io/tcore-sdk/types"; +import { useCallback, useState } from "react"; +import { EIcon } from "../../../Icon/Icon.types"; +import { Col, FormGroup, Input, Modal, Row } from "../../../.."; +import Select from "../../../Select/Select"; +import editDeviceData from "../../../../Requests/editDeviceData"; + +/** + * Props. + */ +interface IModalEditValueProps { + /** + * Device. + */ + device: IDevice; + /** + * Data item to be edited. + */ + data: IDeviceData; + /** + * Called when the modal closes. + */ + onClose: () => void; +} + +/** + */ +function ModalEditValue(props: IModalEditValueProps) { + const { data, device, onClose } = props; + const [value, setValue] = useState(() => { + const v = data.value; + const t = typeof data.value; + if (t !== "string" && t !== "number" && t !== "boolean") { + return ""; + } else { + return String(v); + } + }); + const [type, setType] = useState(() => { + const t = typeof data.value; + if (t !== "string" && t !== "number" && t !== "boolean") { + return "string"; + } + return t; + }); + + /** + */ + const confirm = useCallback(async () => { + if (type === "string") { + data.value = String(value); + } else if (type === "number") { + data.value = Number(value); + } else if (type === "boolean") { + data.value = value.trim() === "true" || value.trim() === "1"; + } + await editDeviceData(device.id, data); + }, [data, device?.id, type, value]); + + return ( + + + + + setValue(e.target.value)} + value={value} + placeholder="Enter the value for the data item" + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {modalEmpty && } +