Просмотр исходного кода

Merge branch 'master' into imprv/94973-fix-sidebartag-layout

ryoji-s 3 лет назад
Родитель
Сommit
ee3869a9be
71 измененных файлов с 1550 добавлено и 498 удалено
  1. 8 2
      .github/workflows/reusable-app-prod.yml
  2. 15 1
      CHANGELOG.md
  3. 1 12
      THIRD-PARTY-NOTICES.md
  4. 1 1
      lerna.json
  5. 1 1
      package.json
  6. 0 1
      packages/app/.eslintrc.js
  7. 1 0
      packages/app/config/ci/.env.local.for-auto-install-with-allowing-guest
  8. 3 3
      packages/app/config/webpack.common.js
  9. 2 2
      packages/app/docker/README.md
  10. 9 7
      packages/app/package.json
  11. 1 0
      packages/app/resource/Contributor.js
  12. 2 1
      packages/app/resource/locales/en_US/translation.json
  13. 2 1
      packages/app/resource/locales/ja_JP/translation.json
  14. 1 0
      packages/app/resource/locales/zh_CN/translation.json
  15. 0 4
      packages/app/src/client/app.jsx
  16. 4 0
      packages/app/src/client/base.jsx
  17. 0 27
      packages/app/src/client/services/AppContainer.js
  18. 3 11
      packages/app/src/client/services/PageContainer.js
  19. 1 1
      packages/app/src/client/util/GrowiRenderer.js
  20. 2 8
      packages/app/src/client/util/interceptor/detach-code-blocks.js
  21. 6 10
      packages/app/src/client/util/interceptor/drawio-interceptor.js
  22. 1 1
      packages/app/src/client/util/markdown-it/table-with-handsontable-button.js
  23. 5 12
      packages/app/src/client/util/markdown-it/toc-and-anchor.js
  24. 5 5
      packages/app/src/components/CreateTemplateModal.jsx
  25. 11 3
      packages/app/src/components/DescendantsPageList.tsx
  26. 0 108
      packages/app/src/components/Drawio.jsx
  27. 97 0
      packages/app/src/components/Drawio.tsx
  28. 5 6
      packages/app/src/components/Me/PasswordSettings.jsx
  29. 25 25
      packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  30. 7 9
      packages/app/src/components/NotAvailableForGuest.jsx
  31. 32 5
      packages/app/src/components/Page.jsx
  32. 7 5
      packages/app/src/components/Page/FixPageGrantAlert.tsx
  33. 0 72
      packages/app/src/components/Page/NotFoundAlert.tsx
  34. 2 6
      packages/app/src/components/Page/RevisionRenderer.jsx
  35. 1 0
      packages/app/src/components/PageAccessoriesModal.tsx
  36. 7 3
      packages/app/src/components/PageAttachment.jsx
  37. 5 1
      packages/app/src/components/PageDeleteModal.tsx
  38. 1 1
      packages/app/src/components/PageHistory.jsx
  39. 8 1
      packages/app/src/components/PagePresentationModal.jsx
  40. 11 2
      packages/app/src/components/SearchPage2/SearchPageBase.tsx
  41. 1 1
      packages/app/src/components/Sidebar/CustomSidebar.tsx
  42. 1 1
      packages/app/src/components/Sidebar/Tag.tsx
  43. 13 4
      packages/app/src/components/TableOfContents.jsx
  44. 5 1
      packages/app/src/server/crowi/index.js
  45. 5 2
      packages/app/src/server/routes/apiv3/forgot-password.js
  46. 6 4
      packages/app/src/server/routes/apiv3/personal-setting.js
  47. 13 1
      packages/app/src/server/service/config-loader.ts
  48. 71 71
      packages/app/src/server/service/file-uploader/aws.ts
  49. 20 8
      packages/app/src/server/service/installer.ts
  50. 1 1
      packages/app/src/server/service/page.ts
  51. 0 1
      packages/app/src/server/views/layout-growi/not_found.html
  52. 1 1
      packages/app/src/styles/theme/_apply-colors-dark.scss
  53. 7 0
      packages/app/src/styles/theme/_apply-colors-light.scss
  54. 0 4
      packages/app/src/styles/theme/_apply-colors.scss
  55. 0 0
      packages/app/test/cypress/integration/10-install/install.spec.ts
  56. 148 0
      packages/app/test/cypress/integration/20-basic-features/access-to-page.spec.ts
  57. 36 0
      packages/app/test/cypress/integration/20-basic-features/use-tools.spec.ts
  58. 6 30
      packages/app/test/cypress/integration/21-basic-features-for-guest/access-to-page.spec.ts
  59. 0 0
      packages/app/test/cypress/integration/30-search/search.spec.ts
  60. 0 0
      packages/app/test/cypress/integration/40-admin/access-to-admin-page.spec.ts
  61. 0 0
      packages/app/test/cypress/integration/50-switch-sidebar-mode/switching-sidebar-mode.spec.ts
  62. 0 0
      packages/app/test/cypress/integration/60-home/home.spec.ts
  63. 1 1
      packages/codemirror-textlint/package.json
  64. 1 1
      packages/core/package.json
  65. 1 1
      packages/plugin-attachment-refs/package.json
  66. 1 1
      packages/plugin-lsx/package.json
  67. 1 1
      packages/plugin-pukiwiki-like-linker/package.json
  68. 1 1
      packages/slack/package.json
  69. 2 2
      packages/slackbot-proxy/package.json
  70. 1 1
      packages/ui/package.json
  71. 914 1
      yarn.lock

+ 8 - 2
.github/workflows/reusable-app-prod.yml

@@ -180,7 +180,7 @@ jobs:
       fail-fast: false
       matrix:
         # List string expressions that is comma separated ids of tests in "test/cypress/integration"
-        spec-group: ['1', '2', '3', '4', '6']
+        spec-group: ['10', '20', '21', '30', '40', '60']
 
     services:
       mongodb:
@@ -239,11 +239,17 @@ jobs:
         cat config/ci/.env.local.for-ci >> .env.production.local
 
     - name: Copy dotenv file for automatic installation
-      if: ${{ matrix.spec-group != '1' }}
+      if: ${{ matrix.spec-group != '10' }}
       working-directory: ./packages/app
       run: |
         cat config/ci/.env.local.for-auto-install >> .env.production.local
 
+    - name: Copy dotenv file for automatic installation with allowing guest mode
+      if: ${{ matrix.spec-group == '21' }}
+      working-directory: ./packages/app
+      run: |
+        cat config/ci/.env.local.for-auto-install-with-allowing-guest >> .env.production.local
+
     - name: Cypress Run
       uses: cypress-io/github-action@v3
       with:

+ 15 - 1
CHANGELOG.md

@@ -1,9 +1,23 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v5.0.6...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v5.0.7...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v5.0.7](https://github.com/weseek/growi/compare/v5.0.6...v5.0.7) - 2022-05-30
+
+### 💎 Features
+
+- feat: Set the min length of passwords by environment variable (#5899) @Shunm634-source
+- feat: API to find username (#5907) @miya
+
+### 🐛 Bug Fixes
+
+- fix: Page is not rendered for guest (#5930) @yuki-takei
+- fix: Server error due to the canDeleteLogic method (#5927) @hakumizuki
+- fix: Show pagename on toastr when page deleted (#5772) @hirokei-camel
+- fix: Search result screen is broken under content 100% setting (#5917) @jam411
+
 ## [v5.0.6](https://github.com/weseek/growi/compare/v5.0.5...v5.0.6) - 2022-05-27
 
 ### 💎 Features

+ 1 - 12
THIRD-PARTY-NOTICES.md

@@ -16,8 +16,7 @@ https://github.com/weseek/growi.
 2. crowi/crowi (https://github.com/crowi/crowi)
 3. Microsoft/vscode (https://github.com/Microsoft/vscode)
 4. stephenhutchings/typicons.font (https://github.com/stephenhutchings/typicons.font)
-5. EmojiOne Version 3 (https://github.com/joypixels/emojione/tree/v3.1.1)
-6. Kuromoji.js (https://github.com/takuyaa/kuromoji.js)
+5. Kuromoji.js (https://github.com/takuyaa/kuromoji.js)
 
 
 License Notice for Apache License, Version 2.0 Derivative Works
@@ -101,16 +100,6 @@ Copyright (c) 2018 Stephen Hutchings
 ```
 
 
-License Notice for EmojiOne
-------------------------
-
-https://creativecommons.org/licenses/by/4.0/
-
-```
-author: "EmojiOne <ryan@emojione.com> (http://emojione.com)"
-```
-
-
 License Notice for Kuromoji.js
 ------------------------
 

+ 1 - 1
lerna.json

@@ -1,7 +1,7 @@
 {
   "npmClient": "yarn",
   "useWorkspaces": true,
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "packages": [
     "packages/*"
   ]

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "description": "Team collaboration software using markdown",
   "tags": [
     "wiki",

+ 0 - 1
packages/app/.eslintrc.js

@@ -12,7 +12,6 @@ module.exports = {
   globals: {
     $: true,
     jquery: true,
-    emojione: true,
     hljs: true,
     ScrollPosStyler: true,
     window: true,

+ 1 - 0
packages/app/config/ci/.env.local.for-auto-install-with-allowing-guest

@@ -0,0 +1 @@
+AUTO_INSTALL_ALLOW_GUEST_MODE=true

+ 3 - 3
packages/app/config/webpack.common.js

@@ -2,14 +2,15 @@
  * @author: Yuki Takei <yuki@weseek.co.jp>
  */
 const path = require('path');
+
+const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
+const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
 const webpack = require('webpack');
 
 /*
   * Webpack Plugins
   */
 const WebpackAssetsManifest = require('webpack-assets-manifest');
-const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
-const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
 
 /*
   * Webpack configuration
@@ -60,7 +61,6 @@ module.exports = (options) => {
       // require("jquery") is external and available
       //  on the global var jQuery
       jquery: 'jQuery',
-      emojione: 'emojione',
       hljs: 'hljs',
       'dtrace-provider': 'dtrace-provider',
     },

+ 2 - 2
packages/app/docker/README.md

@@ -10,8 +10,8 @@ GROWI Official docker image
 Supported tags and respective Dockerfile links
 ------------------------------------------------
 
-* [`5.0.6`, `5.0`, `5`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v5.0.6/docker/Dockerfile)
-* [`5.0.6-nocdn`, `5.0-nocdn`, `5-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v5.0.6/docker/Dockerfile)
+* [`5.0.7`, `5.0`, `5`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v5.0.7/docker/Dockerfile)
+* [`5.0.7-nocdn`, `5.0-nocdn`, `5-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v5.0.7/docker/Dockerfile)
 * [`4.5.15`, `4.5`, `4`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v4.5.15/docker/Dockerfile)
 * [`4.5.15-nocdn`, `4.5-nocdn`, `4-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v4.5.15/docker/Dockerfile)
 * [`4.4.13`, `4.4` (Dockerfile)](https://github.com/weseek/growi/blob/v4.4.13/docker/Dockerfile)

+ 9 - 7
packages/app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/app",
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "license": "MIT",
   "scripts": {
     "//// for production": "",
@@ -57,16 +57,18 @@
     "string-width": "5.0.0 or above exports only ESM."
   },
   "dependencies": {
+    "@aws-sdk/client-s3": "^3.58.0",
+    "@aws-sdk/s3-request-presigner": "^3.58.0",
     "@browser-bunyan/console-formatted-stream": "^1.6.2",
     "@elastic/elasticsearch6": "npm:@elastic/elasticsearch@^6.8.8",
     "@elastic/elasticsearch7": "npm:@elastic/elasticsearch@^7.17.0",
     "@godaddy/terminus": "^4.9.0",
     "@google-cloud/storage": "^5.8.5",
-    "@growi/codemirror-textlint": "^5.0.7-RC.0",
-    "@growi/plugin-attachment-refs": "^5.0.7-RC.0",
-    "@growi/plugin-lsx": "^5.0.7-RC.0",
-    "@growi/plugin-pukiwiki-like-linker": "^5.0.7-RC.0",
-    "@growi/slack": "^5.0.7-RC.0",
+    "@growi/codemirror-textlint": "^5.0.8-RC.0",
+    "@growi/plugin-attachment-refs": "^5.0.8-RC.0",
+    "@growi/plugin-lsx": "^5.0.8-RC.0",
+    "@growi/plugin-pukiwiki-like-linker": "^5.0.8-RC.0",
+    "@growi/slack": "^5.0.8-RC.0",
     "@promster/express": "^7.0.2",
     "@promster/server": "^7.0.4",
     "@slack/events-api": "^3.0.0",
@@ -166,7 +168,7 @@
   },
   "devDependencies": {
     "@alienfast/i18next-loader": "^1.1.4",
-    "@growi/ui": "^5.0.7-RC.0",
+    "@growi/ui": "^5.0.8-RC.0",
     "@handsontable/react": "=2.1.0",
     "@types/compression": "^1.7.0",
     "@types/express": "^4.17.11",

+ 1 - 0
packages/app/resource/Contributor.js

@@ -41,6 +41,7 @@ const contributors = [
           { name: 'N1koge' },
           { name: 'Ertai87' },
           { name: 'takayuki-t' },
+          { name: 'ayaka0417' },
           { name: 'zahmis' },
           { name: 'takeru0001' },
           { name: 'Shu Katabe' },

+ 2 - 1
packages/app/resource/locales/en_US/translation.json

@@ -213,7 +213,7 @@
     },
     "form_help": {
       "email": "You must have email address which listed below to sign up to this wiki.",
-      "password": "Your password must be at least 8 characters long.",
+      "password": "Your password must be at least {{target}} characters long.",
       "user_id": "The URL of pages you create will contain your User ID. Your User ID can consist of letters, numbers, and some symbols."
     }
   },
@@ -438,6 +438,7 @@
     "recursively": "Delete pages under this path recursively.",
     "completely": "Delete completely instead of putting it into trash."
   },
+  "deleted_page": "Moved to the trash",
   "deleted_pages": "{{path}} has been deleted",
   "deleted_pages_completely": "{{path}} has been deleted completely",
   "renamed_pages": "{{path}} has been renamed",

+ 2 - 1
packages/app/resource/locales/ja_JP/translation.json

@@ -215,7 +215,7 @@
     },
     "form_help": {
       "email": "この Wiki では以下のメールアドレスのみ登録可能です。",
-      "password": "パスワードには、8文字以上の半角英数字または記号等を設定してください。",
+      "password": "パスワードには、{{target}}文字以上の半角英数字または記号等を設定してください。",
       "user_id": "ユーザーIDは、ユーザーページのURLなどに利用されます。半角英数字と一部の記号のみ利用できます。"
     }
   },
@@ -438,6 +438,7 @@
     "recursively": "配下のページも削除します",
     "completely": "ゴミ箱を経由せず、完全に削除します"
   },
+  "deleted_page": "ゴミ箱に入れました",
   "deleted_pages": "{{path}} をゴミ箱に入れました",
   "deleted_pages_completely": "{{path}} を完全に削除しました",
   "renamed_pages": "{{path}} を移動/名前変更しました",

+ 1 - 0
packages/app/resource/locales/zh_CN/translation.json

@@ -417,6 +417,7 @@
 		"recursively": "Delete children of <code>%s</code> recursively.",
 		"completely": "Delete completely instead of putting it into trash."
   },
+  "deleted_page": "移到了垃圾箱。",
   "deleted_pages": "将 {{path}} 放入垃圾箱",
   "deleted_pages_completely": "{{path}} 已被完全删除",
   "renamed_pages": "移动/重命名 {{path}}",

+ 0 - 4
packages/app/src/client/app.jsx

@@ -34,7 +34,6 @@ import NotFoundPage from '../components/NotFoundPage';
 import Page from '../components/Page';
 import DisplaySwitcher from '../components/Page/DisplaySwitcher';
 import FixPageGrantAlert from '../components/Page/FixPageGrantAlert';
-import NotFoundAlert from '../components/Page/NotFoundAlert';
 import RedirectedAlert from '../components/Page/RedirectedAlert';
 import ShareLinkAlert from '../components/Page/ShareLinkAlert';
 import TrashPageAlert from '../components/Page/TrashPageAlert';
@@ -117,9 +116,6 @@ Object.assign(componentMappings, {
 
   'share-link-alert': <ShareLinkAlert />,
   'redirected-alert': <RedirectedAlert />,
-  'not-found-alert': <NotFoundAlert
-    isGuestUserMode={appContainer.isGuestUser}
-  />,
 });
 
 // additional definitions if data exists

+ 4 - 0
packages/app/src/client/base.jsx

@@ -1,5 +1,7 @@
 import React from 'react';
 
+import EventEmitter from 'events';
+
 import AppContainer from '~/client/services/AppContainer';
 import SocketIoContainer from '~/client/services/SocketIoContainer';
 import { DescendantsPageListModal } from '~/components/DescendantsPageListModal';
@@ -28,6 +30,8 @@ if (!window) {
 const xss = new Xss();
 window.xss = xss;
 
+window.globalEmitter = new EventEmitter();
+
 // create unstated container instance
 const appContainer = new AppContainer();
 // eslint-disable-next-line no-unused-vars

+ 0 - 27
packages/app/src/client/services/AppContainer.js

@@ -26,12 +26,6 @@ export default class AppContainer extends Container {
       this.currentUser = JSON.parse(currentUserElem.textContent);
     }
 
-    const isSharedPageElem = document.getElementById('is-shared-page');
-
-    // check what kind of user
-    this.isGuestUser = this.currentUser == null;
-    this.isSharedUser = isSharedPageElem != null && this.currentUser == null;
-
     const userLocaleId = this.currentUser?.lang;
     this.i18n = i18nFactory(userLocaleId);
 
@@ -186,25 +180,4 @@ export default class AppContainer extends Container {
     return renderer;
   }
 
-
-  launchHandsontableModal(componentKind, beginLineNumber, endLineNumber) {
-    let targetComponent;
-    switch (componentKind) {
-      case 'page':
-        targetComponent = this.getComponentInstance('Page');
-        break;
-    }
-    targetComponent.launchHandsontableModal(beginLineNumber, endLineNumber);
-  }
-
-  launchDrawioModal(componentKind, beginLineNumber, endLineNumber) {
-    let targetComponent;
-    switch (componentKind) {
-      case 'page':
-        targetComponent = this.getComponentInstance('Page');
-        break;
-    }
-    targetComponent.launchDrawioModal(beginLineNumber, endLineNumber);
-  }
-
 }

+ 3 - 11
packages/app/src/client/services/PageContainer.js

@@ -52,7 +52,6 @@ export default class PageContainer extends Container {
       revisionId,
       revisionCreatedAt: +mainContent.getAttribute('data-page-revision-created'),
       path,
-      tocHtml: '',
 
       createdAt: mainContent.getAttribute('data-page-created-at'),
       // please use useCurrentUpdatedAt instead
@@ -101,13 +100,12 @@ export default class PageContainer extends Container {
     }
 
     const { interceptorManager } = this.appContainer;
-    interceptorManager.addInterceptor(new DetachCodeBlockInterceptor(appContainer), 10); // process as soon as possible
-    interceptorManager.addInterceptor(new DrawioInterceptor(appContainer), 20);
-    interceptorManager.addInterceptor(new RestoreCodeBlockInterceptor(appContainer), 900); // process as late as possible
+    interceptorManager.addInterceptor(new DetachCodeBlockInterceptor(), 10); // process as soon as possible
+    interceptorManager.addInterceptor(new DrawioInterceptor(), 20);
+    interceptorManager.addInterceptor(new RestoreCodeBlockInterceptor(), 900); // process as late as possible
 
     this.initStateMarkdown();
 
-    this.setTocHtml = this.setTocHtml.bind(this);
     this.save = this.save.bind(this);
 
     this.emitJoinPageRoomRequest = this.emitJoinPageRoomRequest.bind(this);
@@ -194,12 +192,6 @@ export default class PageContainer extends Container {
     this.setState(newState);
   }
 
-  async setTocHtml(tocHtml) {
-    if (this.state.tocHtml !== tocHtml) {
-      this.setState({ tocHtml });
-    }
-  }
-
   /**
    * save success handler
    * @param {object} page Page instance

+ 1 - 1
packages/app/src/client/util/GrowiRenderer.js

@@ -85,7 +85,7 @@ export default class GrowiRenderer {
 
         this.markdownItConfigurers = this.markdownItConfigurers.concat([
           new FooternoteConfigurer(appContainer),
-          new TocAndAnchorConfigurer(appContainer, pageContainer.setTocHtml),
+          new TocAndAnchorConfigurer(),
           new HeaderLineNumberConfigurer(appContainer),
           new HeaderWithEditLinkConfigurer(appContainer),
           new TableWithHandsontableButtonConfigurer(appContainer),

+ 2 - 8
packages/app/src/client/util/interceptor/detach-code-blocks.js

@@ -15,12 +15,9 @@ class DetachCodeBlockUtil {
  */
 export class DetachCodeBlockInterceptor extends BasicInterceptor {
 
-  constructor(crowi) {
+  constructor() {
     super();
     this.logger = loggerFactory('growi:interceptor:DetachCodeBlockInterceptor');
-
-    this.crowi = crowi;
-    this.crowiForJquery = crowi.getCrowiForJquery();
   }
 
   /**
@@ -94,12 +91,9 @@ export class DetachCodeBlockInterceptor extends BasicInterceptor {
  */
 export class RestoreCodeBlockInterceptor extends BasicInterceptor {
 
-  constructor(crowi) {
+  constructor() {
     super();
     this.logger = loggerFactory('growi:interceptor:DetachCodeBlockInterceptor');
-
-    this.crowi = crowi;
-    this.crowiForJquery = crowi.getCrowiForJquery();
   }
 
   /**

+ 6 - 10
packages/app/src/client/util/interceptor/drawio-interceptor.js

@@ -3,7 +3,6 @@ import React from 'react';
 
 import { BasicInterceptor } from '@growi/core';
 import ReactDOM from 'react-dom';
-import { Provider } from 'unstated';
 
 import Drawio from '~/components/Drawio';
 
@@ -14,11 +13,10 @@ import Drawio from '~/components/Drawio';
  */
 export class DrawioInterceptor extends BasicInterceptor {
 
-  constructor(appContainer) {
+  constructor() {
     super();
 
     this.previousPreviewContext = null;
-    this.appContainer = appContainer;
   }
 
   /**
@@ -125,13 +123,11 @@ export class DrawioInterceptor extends BasicInterceptor {
   renderReactDOM(drawioMapEntry, elem, isPreview) {
     ReactDOM.render(
       // eslint-disable-next-line react/jsx-filename-extension
-      <Provider inject={[this.appContainer]}>
-        <Drawio
-          drawioContent={drawioMapEntry.contentHtml}
-          isPreview={isPreview}
-          rangeLineNumberOfMarkdown={drawioMapEntry.rangeLineNumberOfMarkdown}
-        />
-      </Provider>,
+      <Drawio
+        drawioContent={drawioMapEntry.contentHtml}
+        isPreview={isPreview}
+        rangeLineNumberOfMarkdown={drawioMapEntry.rangeLineNumberOfMarkdown}
+      />,
       elem,
     );
   }

+ 1 - 1
packages/app/src/client/util/markdown-it/table-with-handsontable-button.js

@@ -9,7 +9,7 @@ export default class TableWithHandsontableButtonConfigurer {
       const beginLine = tokens[idx].map[0] + 1;
       const endLine = tokens[idx].map[1];
       // eslint-disable-next-line max-len
-      return `<div class="editable-with-handsontable"><button class="handsontable-modal-trigger" onClick="crowi.launchHandsontableModal('page', ${beginLine}, ${endLine})"><i class="icon-note"></i></button><table class="table table-bordered">`;
+      return `<div class="editable-with-handsontable"><button class="handsontable-modal-trigger" onClick="globalEmitter.emit('launchHandsontableModal', ${beginLine}, ${endLine})"><i class="icon-note"></i></button><table class="table table-bordered">`;
     };
 
     md.renderer.rules.table_close = (tokens, idx) => {

+ 5 - 12
packages/app/src/client/util/markdown-it/toc-and-anchor.js

@@ -5,11 +5,6 @@ import { emojiMartData } from './emoji-mart-data';
 
 export default class TocAndAnchorConfigurer {
 
-  constructor(crowi, setHtml) {
-    this.crowi = crowi;
-    this.setHtml = setHtml;
-  }
-
   configure(md) {
     md.use(markdownItEmojiMart, { defs: emojiMartData })
       .use(markdownItToc, {
@@ -21,13 +16,11 @@ export default class TocAndAnchorConfigurer {
       });
 
     // set toc render function
-    if (this.setHtml != null) {
-      md.set({
-        tocCallback: (tocMarkdown, tocArray, tocHtml) => {
-          this.setHtml(tocHtml);
-        },
-      });
-    }
+    md.set({
+      tocCallback: (tocMarkdown, tocArray, tocHtml) => {
+        window.globalEmitter.emit('renderTocHtml', tocHtml);
+      },
+    });
   }
 
 }

+ 5 - 5
packages/app/src/components/CreateTemplateModal.jsx

@@ -1,10 +1,9 @@
 import React from 'react';
-import PropTypes from 'prop-types';
-
-import { Modal, ModalHeader, ModalBody } from 'reactstrap';
 
-import { withTranslation } from 'react-i18next';
 import { pathUtils } from '@growi/core';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+import { Modal, ModalHeader, ModalBody } from 'reactstrap';
 import urljoin from 'url-join';
 
 
@@ -30,6 +29,7 @@ const CreateTemplateModal = (props) => {
         </div>
         <div className="card-footer text-center">
           <a
+            data-testid={`template-button-${target}`}
             href={generateUrl(label)}
             className="btn btn-sm btn-primary"
             id={`template-button-${target}`}
@@ -42,7 +42,7 @@ const CreateTemplateModal = (props) => {
   }
 
   return (
-    <Modal isOpen={props.isOpen} toggle={props.onClose} className="grw-create-page">
+    <Modal isOpen={props.isOpen} toggle={props.onClose} data-testid="page-template-modal" className="grw-create-page">
       <ModalHeader tag="h4" toggle={props.onClose} className="bg-primary text-light">
         {t('template.modal_label.Create/Edit Template Page')}
       </ModalHeader>

+ 11 - 3
packages/app/src/components/DescendantsPageList.tsx

@@ -1,5 +1,7 @@
 import React, { useCallback, useState } from 'react';
+
 import { useTranslation } from 'react-i18next';
+
 import { toastSuccess } from '~/client/util/apiNotification';
 import {
   IDataWithMeta,
@@ -9,13 +11,12 @@ import {
 import { IPagingResult } from '~/interfaces/paging-result';
 import { OnDeletedFunction, OnPutBackedFunction } from '~/interfaces/ui';
 import { useIsGuestUser, useIsSharedUser, useIsTrashPage } from '~/stores/context';
-
 import {
   useSWRxDescendantsPageListForCurrrentPath, useSWRxPageInfoForList, useSWRxPageList, useDescendantsPageListForCurrentPathTermManager,
 } from '~/stores/page';
 import { usePageTreeTermManager } from '~/stores/page-listing';
-import { ForceHideMenuItems, MenuItemType } from './Common/Dropdown/PageItemControl';
 
+import { ForceHideMenuItems, MenuItemType } from './Common/Dropdown/PageItemControl';
 import PageList from './PageList/PageList';
 import PaginationWrapper from './PaginationWrapper';
 
@@ -61,7 +62,14 @@ export const DescendantsPageListSubstance = (props: SubstanceProps): JSX.Element
   }
 
   const pageDeletedHandler: OnDeletedFunction = useCallback((...args) => {
-    toastSuccess(args[2] ? t('deleted_pages_completely') : t('deleted_pages'));
+    const path = args[0];
+    const isCompletely = args[2];
+    if (path == null || isCompletely == null) {
+      toastSuccess(t('deleted_page'));
+    }
+    else {
+      toastSuccess(t('deleted_pages_completely', { path }));
+    }
 
     advancePt();
 

+ 0 - 108
packages/app/src/components/Drawio.jsx

@@ -1,108 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import { debounce } from 'throttle-debounce';
-
-import { withTranslation } from 'react-i18next';
-
-import AppContainer from '~/client/services/AppContainer';
-
-import { withUnstatedContainers } from './UnstatedUtils';
-
-import NotAvailableForGuest from './NotAvailableForGuest';
-
-class Drawio extends React.Component {
-
-  constructor(props) {
-    super(props);
-
-    this.drawioContainer = React.createRef();
-
-    this.style = {
-      borderRadius: 3,
-      border: '1px solid #d7d7d7',
-      margin: '20px 0',
-    };
-
-    this.isPreview = this.props.isPreview;
-    this.drawioContent = this.props.drawioContent;
-
-    this.onEdit = this.onEdit.bind(this);
-
-    // create debounced method for rendering Drawio
-    this.renderDrawioWithDebounce = debounce(200, this.renderDrawio);
-  }
-
-  onEdit() {
-    const { appContainer, rangeLineNumberOfMarkdown } = this.props;
-    const { beginLineNumber, endLineNumber } = rangeLineNumberOfMarkdown;
-    appContainer.launchDrawioModal('page', beginLineNumber, endLineNumber);
-  }
-
-  componentDidMount() {
-    const DrawioViewer = window.GraphViewer;
-    if (DrawioViewer != null) {
-      this.renderDrawio();
-    }
-    else {
-      this.renderDrawioWithDebounce();
-    }
-  }
-
-  renderDrawio() {
-    const DrawioViewer = window.GraphViewer;
-    if (DrawioViewer != null) {
-      const mxgraphs = this.drawioContainer.getElementsByClassName('mxgraph');
-      if (mxgraphs.length > 0) {
-        // GROWI では、mxgraph element は最初のものをレンダリングする前提とする
-        const div = mxgraphs[0];
-
-        if (div != null) {
-          div.innerHTML = '';
-          DrawioViewer.createViewerForElement(div);
-        }
-      }
-    }
-    else {
-      this.renderDrawioWithDebounce();
-    }
-  }
-
-  renderContents() {
-    return this.drawioContent;
-  }
-
-  render() {
-    return (
-      <div className="editable-with-drawio position-relative">
-        { !this.isPreview && (
-          <NotAvailableForGuest>
-            <button type="button" className="drawio-iframe-trigger position-absolute btn btn-outline-secondary" onClick={this.onEdit}>
-              <i className="icon-note mr-1"></i>{this.props.t('Edit')}
-            </button>
-          </NotAvailableForGuest>
-        ) }
-        <div
-          className="drawio"
-          style={this.style}
-          ref={(c) => { this.drawioContainer = c }}
-          // eslint-disable-next-line react/no-danger
-          dangerouslySetInnerHTML={{ __html: this.renderContents() }}
-        >
-        </div>
-      </div>
-    );
-  }
-
-}
-
-Drawio.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.object.isRequired,
-
-  drawioContent: PropTypes.any.isRequired,
-  isPreview: PropTypes.bool,
-  rangeLineNumberOfMarkdown: PropTypes.object.isRequired,
-};
-
-export default withTranslation()(withUnstatedContainers(Drawio, [AppContainer]));

+ 97 - 0
packages/app/src/components/Drawio.tsx

@@ -0,0 +1,97 @@
+import React, {
+  useCallback, useEffect, useMemo, useRef,
+} from 'react';
+
+import EventEmitter from 'events';
+
+import { useTranslation } from 'react-i18next';
+import { debounce } from 'throttle-debounce';
+
+import NotAvailableForGuest from './NotAvailableForGuest';
+
+
+declare let window: {
+  globalEmitter: EventEmitter,
+  GraphViewer: {
+    createViewerForElement: (Element) => void,
+  };
+};
+
+type Props = {
+  drawioContent: string,
+  rangeLineNumberOfMarkdown: { beginLineNumber: number, endLineNumber: number },
+  isPreview?: boolean,
+}
+
+const Drawio = (props: Props): JSX.Element => {
+
+  const { t } = useTranslation();
+
+  const { drawioContent, rangeLineNumberOfMarkdown, isPreview } = props;
+
+  // const { open: openDrawioModal } = useDrawioModalForPage();
+
+  const drawioContainerRef = useRef<HTMLDivElement>(null);
+
+  const editButtonClickHandler = useCallback(() => {
+    const { beginLineNumber, endLineNumber } = rangeLineNumberOfMarkdown;
+    window.globalEmitter.emit('launchDrawioModal', beginLineNumber, endLineNumber);
+  }, [rangeLineNumberOfMarkdown]);
+
+  const renderDrawio = useCallback(() => {
+    if (drawioContainerRef.current == null) {
+      return;
+    }
+
+    const mxgraphs = drawioContainerRef.current.getElementsByClassName('mxgraph');
+    if (mxgraphs.length > 0) {
+      // GROWI では、mxgraph element は最初のものをレンダリングする前提とする
+      const div = mxgraphs[0];
+
+      if (div != null) {
+        div.innerHTML = '';
+        window.GraphViewer.createViewerForElement(div);
+      }
+    }
+  }, []);
+
+  const renderDrawioWithDebounce = useMemo(() => debounce(200, renderDrawio), [renderDrawio]);
+
+  const { GraphViewer } = window;
+  useEffect(() => {
+    if (GraphViewer == null) {
+      return;
+    }
+
+    renderDrawioWithDebounce();
+  }, [GraphViewer, renderDrawioWithDebounce]);
+
+  return (
+    <div className="editable-with-drawio position-relative">
+      { !isPreview && (
+        <NotAvailableForGuest>
+          <button type="button" className="drawio-iframe-trigger position-absolute btn btn-outline-secondary" onClick={editButtonClickHandler}>
+            <i className="icon-note mr-1"></i>{t('Edit')}
+          </button>
+        </NotAvailableForGuest>
+      ) }
+      <div
+        className="drawio"
+        style={
+          {
+            borderRadius: 3,
+            border: '1px solid #d7d7d7',
+            margin: '20px 0',
+          }
+        }
+        ref={drawioContainerRef}
+        // eslint-disable-next-line react/no-danger
+        dangerouslySetInnerHTML={{ __html: drawioContent }}
+      >
+      </div>
+    </div>
+  );
+
+};
+
+export default Drawio;

+ 5 - 6
packages/app/src/components/Me/PasswordSettings.jsx

@@ -10,7 +10,6 @@ import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
 
 import { withUnstatedContainers } from '../UnstatedUtils';
 
-
 class PasswordSettings extends React.Component {
 
   constructor() {
@@ -22,6 +21,7 @@ class PasswordSettings extends React.Component {
       newPassword: '',
       newPasswordConfirm: '',
       isPasswordSet: false,
+      minPasswordLength: null,
     };
 
     this.onClickSubmit = this.onClickSubmit.bind(this);
@@ -32,8 +32,8 @@ class PasswordSettings extends React.Component {
   async componentDidMount() {
     try {
       const res = await apiv3Get('/personal-setting/is-password-set');
-      const { isPasswordSet } = res.data;
-      this.setState({ isPasswordSet });
+      const { isPasswordSet, minPasswordLength } = res.data;
+      this.setState({ isPasswordSet, minPasswordLength });
     }
     catch (err) {
       toastError(err);
@@ -74,9 +74,8 @@ class PasswordSettings extends React.Component {
 
   render() {
     const { t } = this.props;
-    const { newPassword, newPasswordConfirm } = this.state;
+    const { newPassword, newPasswordConfirm, minPasswordLength } = this.state;
     const isIncorrectConfirmPassword = (newPassword !== newPasswordConfirm);
-
     if (this.state.retrieveError != null) {
       throw new Error(this.state.retrieveError.message);
     }
@@ -131,7 +130,7 @@ class PasswordSettings extends React.Component {
               onChange={(e) => { this.onChangeNewPasswordConfirm(e.target.value) }}
             />
 
-            <p className="form-text text-muted">{t('page_register.form_help.password') }</p>
+            <p className="form-text text-muted">{t('page_register.form_help.password', { target: minPasswordLength }) }</p>
           </div>
         </div>
 

+ 25 - 25
packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -1,45 +1,42 @@
 import React, { useState, useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
-import PropTypes from 'prop-types';
-
 
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
 import { DropdownItem } from 'reactstrap';
 
-import { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
-import { IPageHasId, IPageToRenameWithMeta, IPageWithMeta } from '~/interfaces/page';
-
-import { withUnstatedContainers } from '../UnstatedUtils';
 import EditorContainer from '~/client/services/EditorContainer';
+import { exportAsMarkdown } from '~/client/services/page-operation';
+import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiPost } from '~/client/util/apiv1-client';
+import { IPageHasId, IPageToRenameWithMeta, IPageWithMeta } from '~/interfaces/page';
+import { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import {
-  EditorMode, useDrawerMode, useEditorMode, useIsDeviceSmallerThanMd, useIsAbleToShowPageManagement, useIsAbleToShowTagLabel,
-  useIsAbleToShowPageEditorModeManager, useIsAbleToShowPageAuthors,
-} from '~/stores/ui';
+  useCurrentCreatedAt, useCurrentUpdatedAt, useCurrentPageId, useRevisionId, useCurrentPagePath,
+  useCreator, useRevisionAuthor, useCurrentUser, useIsGuestUser, useIsSharedUser, useShareLinkId,
+} from '~/stores/context';
 import {
   usePageAccessoriesModal, PageAccessoriesModalContents, IPageForPageDuplicateModal,
   usePageDuplicateModal, usePageRenameModal, usePageDeleteModal, usePagePresentationModal,
 } from '~/stores/modal';
-
-
-import {
-  useCurrentCreatedAt, useCurrentUpdatedAt, useCurrentPageId, useRevisionId, useCurrentPagePath,
-  useCreator, useRevisionAuthor, useCurrentUser, useIsGuestUser, useIsSharedUser, useShareLinkId,
-} from '~/stores/context';
 import { useSWRTagsInfo } from '~/stores/page';
+import {
+  EditorMode, useDrawerMode, useEditorMode, useIsDeviceSmallerThanMd, useIsAbleToShowPageManagement, useIsAbleToShowTagLabel,
+  useIsAbleToShowPageEditorModeManager, useIsAbleToShowPageAuthors,
+} from '~/stores/ui';
 
-
-import { toastSuccess, toastError } from '~/client/util/apiNotification';
-import { apiPost } from '~/client/util/apiv1-client';
-
-import HistoryIcon from '../Icons/HistoryIcon';
+import { AdditionalMenuItemsRendererProps } from '../Common/Dropdown/PageItemControl';
 import AttachmentIcon from '../Icons/AttachmentIcon';
+import HistoryIcon from '../Icons/HistoryIcon';
+import { withUnstatedContainers } from '../UnstatedUtils';
+
 import ShareLinkIcon from '../Icons/ShareLinkIcon';
-import { AdditionalMenuItemsRendererProps } from '../Common/Dropdown/PageItemControl';
-import { SubNavButtons } from './SubNavButtons';
-import PageEditorModeManager from './PageEditorModeManager';
+
 import { GrowiSubNavigation } from './GrowiSubNavigation';
+import PageEditorModeManager from './PageEditorModeManager';
+import { SubNavButtons } from './SubNavButtons';
+
 import PresentationIcon from '../Icons/PresentationIcon';
 import CreateTemplateModal from '../CreateTemplateModal';
-import { exportAsMarkdown } from '~/client/services/page-operation';
 
 
 type AdditionalMenuItemsProps = AdditionalMenuItemsRendererProps & {
@@ -101,6 +98,7 @@ const AdditionalMenuItems = (props: AdditionalMenuItemsProps): JSX.Element => {
       <DropdownItem
         onClick={() => openAccessoriesModal(PageAccessoriesModalContents.PageHistory)}
         disabled={isGuestUser || isSharedUser}
+        data-testid="open-page-accessories-modal-btn-with-history-tab"
         className="grw-page-control-dropdown-item"
       >
         <span className="grw-page-control-dropdown-icon">
@@ -111,6 +109,7 @@ const AdditionalMenuItems = (props: AdditionalMenuItemsProps): JSX.Element => {
 
       <DropdownItem
         onClick={() => openAccessoriesModal(PageAccessoriesModalContents.Attachment)}
+        data-testid="open-page-accessories-modal-btn-with-attachment-data-tab"
         className="grw-page-control-dropdown-item"
       >
         <span className="grw-page-control-dropdown-icon">
@@ -136,6 +135,7 @@ const AdditionalMenuItems = (props: AdditionalMenuItemsProps): JSX.Element => {
       <DropdownItem
         onClick={openPageTemplateModalHandler}
         className="grw-page-control-dropdown-item"
+        data-testid="open-page-template-modal-btn"
       >
         <i className="icon-fw icon-magic-wand grw-page-control-dropdown-icon"></i>
         { t('template.option_label.create/edit') }

+ 7 - 9
packages/app/src/components/NotAvailableForGuest.jsx

@@ -1,17 +1,16 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
+import PropTypes from 'prop-types';
 import { UncontrolledTooltip } from 'reactstrap';
 
-import AppContainer from '~/client/services/AppContainer';
-
-import { withUnstatedContainers } from './UnstatedUtils';
+import { useIsGuestUser } from '~/stores/context';
 
 const NotAvailableForGuest = (props) => {
-  const { appContainer, children } = props;
-  const isLoggedin = appContainer.currentUser != null;
+  const { children } = props;
+
+  const { data: isGuestUser } = useIsGuestUser();
 
-  if (isLoggedin) {
+  if (!isGuestUser) {
     return props.children;
   }
 
@@ -34,8 +33,7 @@ const NotAvailableForGuest = (props) => {
 };
 
 NotAvailableForGuest.propTypes = {
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   children: PropTypes.node.isRequired,
 };
 
-export default withUnstatedContainers(NotAvailableForGuest, [AppContainer]);
+export default NotAvailableForGuest;

+ 32 - 5
packages/app/src/components/Page.jsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useEffect, useRef } from 'react';
 
 import PropTypes from 'prop-types';
 
@@ -49,10 +49,6 @@ class Page extends React.Component {
     this.saveHandlerForDrawioModal = this.saveHandlerForDrawioModal.bind(this);
   }
 
-  componentWillMount() {
-    this.props.appContainer.registerComponentInstance('Page', this);
-  }
-
   /**
    * launch HandsontableModal with data specified by arguments
    * @param beginLineNumber
@@ -197,6 +193,36 @@ const PageWrapper = (props) => {
   const { data: grantGroupId } = useSelectedGrantGroupId();
   const { data: grantGroupName } = useSelectedGrantGroupName();
 
+  const pageRef = useRef(null);
+
+  // set handler to open DrawioModal
+  useEffect(() => {
+    const handler = (beginLineNumber, endLineNumber) => {
+      if (pageRef?.current != null) {
+        pageRef.current.launchDrawioModal(beginLineNumber, endLineNumber);
+      }
+    };
+    window.globalEmitter.on('launchDrawioModal', handler);
+
+    return function cleanup() {
+      window.globalEmitter.removeListener('launchDrawioModal', handler);
+    };
+  }, []);
+
+  // set handler to open HandsontableModal
+  useEffect(() => {
+    const handler = (beginLineNumber, endLineNumber) => {
+      if (pageRef?.current != null) {
+        pageRef.current.launchHandsontableModal(beginLineNumber, endLineNumber);
+      }
+    };
+    window.globalEmitter.on('launchHandsontableModal', handler);
+
+    return function cleanup() {
+      window.globalEmitter.removeListener('launchHandsontableModal', handler);
+    };
+  }, []);
+
   if (currentPagePath == null || editorMode == null || isGuestUser == null) {
     return null;
   }
@@ -204,6 +230,7 @@ const PageWrapper = (props) => {
   return (
     <Page
       {...props}
+      ref={pageRef}
       pagePath={currentPagePath}
       editorMode={editorMode}
       isGuestUser={isGuestUser}

+ 7 - 5
packages/app/src/components/Page/FixPageGrantAlert.tsx

@@ -9,7 +9,7 @@ import { toastError, toastSuccess } from '~/client/util/apiNotification';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { PageGrant, IPageGrantData } from '~/interfaces/page';
 import { IRecordApplicableGrant, IResIsGrantNormalizedGrantData } from '~/interfaces/page-grant';
-import { useCurrentPageId, useHasParent } from '~/stores/context';
+import { useCurrentPageId, useCurrentUser, useHasParent } from '~/stores/context';
 import { useSWRxApplicableGrant, useSWRxIsGrantNormalized } from '~/stores/page';
 
 type ModalProps = {
@@ -231,12 +231,14 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
 const FixPageGrantAlert = (): JSX.Element => {
   const { t } = useTranslation();
 
-  const [isOpen, setOpen] = useState<boolean>(false);
-
+  const { data: currentUser } = useCurrentUser();
   const { data: pageId } = useCurrentPageId();
   const { data: hasParent } = useHasParent();
-  const { data: dataIsGrantNormalized } = useSWRxIsGrantNormalized(pageId);
-  const { data: dataApplicableGrant } = useSWRxApplicableGrant(pageId);
+
+  const [isOpen, setOpen] = useState<boolean>(false);
+
+  const { data: dataIsGrantNormalized } = useSWRxIsGrantNormalized(currentUser != null ? pageId : null);
+  const { data: dataApplicableGrant } = useSWRxApplicableGrant(currentUser != null ? pageId : null);
 
   // Dependencies
   if (!hasParent) {

+ 0 - 72
packages/app/src/components/Page/NotFoundAlert.tsx

@@ -1,72 +0,0 @@
-import React, { useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
-import { UncontrolledTooltip } from 'reactstrap';
-import { useIsNotFoundPermalink } from '~/stores/context';
-
-import { EditorMode, useEditorMode } from '~/stores/ui';
-
-
-type Props = {
-  isGuestUserMode?: boolean,
-}
-
-const NotFoundAlert = (props: Props): JSX.Element => {
-  const { t } = useTranslation();
-  const { isGuestUserMode } = props;
-
-  const { data: editorMode, mutate: mutateEditorMode } = useEditorMode();
-  const { data: isNotFoundPermalink } = useIsNotFoundPermalink(); // TODO: Remove this when renaming on editor is implemented
-
-  const isEditorMode = editorMode !== EditorMode.View;
-
-  const clickHandler = useCallback(() => {
-    // check guest user,
-    // disabled of button cannot be used for using tooltip.
-    if (isGuestUserMode) {
-      return;
-    }
-
-    mutateEditorMode(EditorMode.Editor);
-
-  }, [isGuestUserMode, mutateEditorMode]);
-
-  if (isEditorMode) {
-    return <></>;
-  }
-
-  return (
-    <div className="border border-info p-3">
-      <div
-        className="col-md-12 p-0"
-      >
-        <h2 className="text-info lead">
-          <i className="icon-info pr-2 font-weight-bold" aria-hidden="true"></i>
-          {t('not_found_page.page_not_exist_alert')}
-        </h2>
-        {
-          !isNotFoundPermalink && (
-            <div id="create-page-btn-wrapper-for-tooltip" className="d-inline-block">
-              <button
-                type="button"
-                className={`pl-3 pr-3 btn bg-info text-white ${isGuestUserMode ? 'disabled' : ''}`}
-                onClick={clickHandler}
-              >
-                <i className="icon-note icon-fw" />
-                {t('not_found_page.Create Page')}
-              </button>
-            </div>
-          )
-        }
-
-        {!isNotFoundPermalink && isGuestUserMode && (
-          <UncontrolledTooltip placement="bottom" target="create-page-btn-wrapper-for-tooltip" fade={false}>
-            {t('Not available for guest')}
-          </UncontrolledTooltip>
-        )}
-      </div>
-    </div>
-  );
-};
-
-
-export default NotFoundAlert;

+ 2 - 6
packages/app/src/components/Page/RevisionRenderer.jsx

@@ -33,7 +33,7 @@ class LegacyRevisionRenderer extends React.PureComponent {
     this.currentRenderingContext = {
       markdown: this.props.markdown,
       pagePath: this.props.pagePath,
-      renderDrawioInRealtime: this.props.editorSettings.renderDrawioInRealtime,
+      renderDrawioInRealtime: this.props.editorSettings?.renderDrawioInRealtime,
       currentPathname: decodeURIComponent(window.location.pathname),
     };
   }
@@ -178,7 +178,7 @@ LegacyRevisionRenderer.propTypes = {
   pagePath: PropTypes.string.isRequired,
   highlightKeywords: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
   additionalClassName: PropTypes.string,
-  editorSettings: PropTypes.any.isRequired,
+  editorSettings: PropTypes.any,
 };
 
 /**
@@ -191,10 +191,6 @@ const LegacyRevisionRendererWrapper = withUnstatedContainers(LegacyRevisionRende
 const RevisionRenderer = (props) => {
   const { data: editorSettings } = useEditorSettings();
 
-  if (editorSettings == null) {
-    return <></>;
-  }
-
   return <LegacyRevisionRendererWrapper {...props} editorSettings={editorSettings} />;
 };
 

+ 1 - 0
packages/app/src/components/PageAccessoriesModal.tsx

@@ -106,6 +106,7 @@ const PageAccessoriesModal = (props: Props): JSX.Element => {
       size="xl"
       isOpen={isOpened}
       toggle={close}
+      data-testid="page-accessories-modal"
       className={`grw-page-accessories-modal ${isWindowExpanded ? 'grw-modal-expanded' : ''} `}
     >
       <ModalHeader className="p-0" toggle={close} close={buttons}>

+ 7 - 3
packages/app/src/components/PageAttachment.jsx

@@ -118,7 +118,11 @@ class PageAttachment extends React.Component {
   render() {
     const { t } = this.props;
     if (this.state.attachments.length === 0) {
-      return t('No_attachments_yet');
+      return (
+        <div data-testid="page-attachment">
+          {t('No_attachments_yet')}
+        </div>
+      );
     }
 
     let deleteAttachmentModal = '';
@@ -149,7 +153,7 @@ class PageAttachment extends React.Component {
     }
 
     return (
-      <>
+      <div data-testid="page-attachment">
         <PageAttachmentList
           attachments={this.state.attachments}
           inUse={this.state.inUse}
@@ -166,7 +170,7 @@ class PageAttachment extends React.Component {
           pagingLimit={this.state.limit}
           align="center"
         />
-      </>
+      </div>
     );
   }
 

+ 5 - 1
packages/app/src/components/PageDeleteModal.tsx

@@ -1,5 +1,5 @@
 import React, {
-  useState, FC, useMemo,
+  useState, FC, useMemo, useEffect,
 } from 'react';
 
 import { useTranslation } from 'react-i18next';
@@ -83,6 +83,10 @@ const PageDeleteModal: FC = () => {
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
   const [errs, setErrs] = useState<Error[] | null>(null);
 
+  useEffect(() => {
+    setIsDeleteCompletely(forceDeleteCompletelyMode);
+  }, [forceDeleteCompletelyMode]);
+
   function changeIsDeleteRecursivelyHandler() {
     setIsDeleteRecursively(!isDeleteRecursively);
   }

+ 1 - 1
packages/app/src/components/PageHistory.jsx

@@ -68,7 +68,7 @@ function PageHistory(props) {
   }
 
   return (
-    <div className="revision-history">
+    <div className="revision-history" data-testid="page-history">
       <PageRevisionTable
         pageHistoryContainer={pageHistoryContainer}
         revisionComparerContainer={revisionComparerContainer}

+ 8 - 1
packages/app/src/components/PagePresentationModal.jsx

@@ -1,4 +1,5 @@
 import React from 'react';
+
 import {
   Modal, ModalBody,
 } from 'reactstrap';
@@ -10,7 +11,13 @@ const PagePresentationModal = () => {
   const { data: presentationData, close: closePresentationModal } = usePagePresentationModal();
 
   return (
-    <Modal isOpen={presentationData.isOpened} toggle={closePresentationModal} className="grw-presentation-modal" unmountOnClose={false}>
+    <Modal
+      isOpen={presentationData.isOpened}
+      toggle={closePresentationModal}
+      data-testid="page-presentation-modal"
+      className="grw-presentation-modal"
+      unmountOnClose={false}
+    >
       <ModalBody className="modal-body">
         <iframe src={presentationData.href} />
       </ModalBody>

+ 11 - 2
packages/app/src/components/SearchPage2/SearchPageBase.tsx

@@ -1,7 +1,9 @@
 import React, {
   forwardRef, ForwardRefRenderFunction, useEffect, useImperativeHandle, useRef, useState,
 } from 'react';
+
 import { useTranslation } from 'react-i18next';
+
 import { ISelectableAll } from '~/client/interfaces/selectable-all';
 import AppContainer from '~/client/services/AppContainer';
 import { toastSuccess } from '~/client/util/apiNotification';
@@ -11,8 +13,8 @@ import { OnDeletedFunction } from '~/interfaces/ui';
 import { useIsGuestUser, useIsSearchServiceConfigured, useIsSearchServiceReachable } from '~/stores/context';
 import { usePageDeleteModal } from '~/stores/modal';
 import { usePageTreeTermManager } from '~/stores/page-listing';
-import { ForceHideMenuItems } from '../Common/Dropdown/PageItemControl';
 
+import { ForceHideMenuItems } from '../Common/Dropdown/PageItemControl';
 import { SearchResultContent } from '../SearchPage/SearchResultContent';
 import { SearchResultList } from '../SearchPage/SearchResultList';
 
@@ -253,7 +255,14 @@ export const usePageDeleteModalForBulkDeletion = (
 
     openDeleteModal(selectedPages, {
       onDeleted: (...args) => {
-        toastSuccess(args[2] ? t('deleted_pages_completely') : t('deleted_pages'));
+        const path = args[0];
+        const isCompletely = args[2];
+        if (path == null || isCompletely == null) {
+          toastSuccess(t('deleted_page'));
+        }
+        else {
+          toastSuccess(t('deleted_pages_completely', { path }));
+        }
         advancePt();
 
         if (onDeleted != null) {

+ 1 - 1
packages/app/src/components/Sidebar/CustomSidebar.tsx

@@ -43,7 +43,7 @@ const CustomSidebar: FC<Props> = (props: Props) => {
           Custom Sidebar
           <a className="h6 ml-2" href="/Sidebar"><i className="icon-pencil"></i></a>
         </h3>
-        <button type="button" className="btn btn-sm btn-outline-secondary ml-auto" onClick={() => mutate()}>
+        <button type="button" className="btn btn-sm ml-auto grw-btn-reload" onClick={() => mutate()}>
           <i className="icon icon-reload"></i>
         </button>
       </div>

+ 1 - 1
packages/app/src/components/Sidebar/Tag.tsx

@@ -42,7 +42,7 @@ const Tag: FC = () => {
         <h3 className="mb-0">{t('Tags')}</h3>
         <button
           type="button"
-          className="btn btn-sm ml-auto grw-btn-reload-rc"
+          className="btn btn-sm ml-auto grw-btn-reload"
           onClick={onReload}
         >
           <i className="icon icon-reload"></i>

+ 13 - 4
packages/app/src/components/TableOfContents.jsx

@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
 
 import PropTypes from 'prop-types';
 
@@ -25,6 +25,8 @@ const TableOfContents = (props) => {
   const { pageUser } = pageContainer.state;
   const isUserPage = pageUser != null;
 
+  const [tocHtml, setTocHtml] = useState('');
+
   const calcViewHeight = useCallback(() => {
     // calculate absolute top of '#revision-toc' element
     const parentElem = document.querySelector('.grw-side-contents-container');
@@ -45,15 +47,22 @@ const TableOfContents = (props) => {
     return bottom - (containerTop + containerPaddingTop);
   }, [isUserPage]);
 
-  const { tocHtml } = pageContainer.state;
-
-  // execute after generation toc html
   useEffect(() => {
     const tocDom = document.getElementById('revision-toc-content');
     const anchorsInToc = Array.from(tocDom.getElementsByTagName('a'));
     addSmoothScrollEvent(anchorsInToc, blinkElem);
   }, [tocHtml]);
 
+  // set handler to render ToC
+  useEffect(() => {
+    const handler = html => setTocHtml(html);
+    window.globalEmitter.on('renderTocHtml', handler);
+
+    return function cleanup() {
+      window.globalEmitter.removeListener('renderTocHtml', handler);
+    };
+  }, []);
+
   return (
     <StickyStretchableScroller
       stickyElemSelector=".grw-side-contents-sticky-container"

+ 5 - 1
packages/app/src/server/crowi/index.js

@@ -400,12 +400,16 @@ Crowi.prototype.autoInstall = function() {
     admin: true,
   };
   const globalLang = this.configManager.getConfig('crowi', 'autoInstall:globalLang');
+  const allowGuestMode = this.configManager.getConfig('crowi', 'autoInstall:allowGuestMode');
   const serverDate = this.configManager.getConfig('crowi', 'autoInstall:serverDate');
 
   const installerService = new InstallerService(this);
 
   try {
-    installerService.install(firstAdminUserToSave, globalLang ?? 'en_US', serverDate);
+    installerService.install(firstAdminUserToSave, globalLang ?? 'en_US', {
+      allowGuestMode,
+      serverDate,
+    });
   }
   catch (err) {
     logger.warn('Automatic installation failed.', err);

+ 5 - 2
packages/app/src/server/routes/apiv3/forgot-password.js

@@ -10,6 +10,7 @@ import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
 import httpErrorHandler from '../../middlewares/http-error-handler';
 import { checkForgotPasswordEnabledMiddlewareFactory } from '../forgot-password';
 
+
 const logger = loggerFactory('growi:routes:apiv3:forgotPassword'); // eslint-disable-line no-unused-vars
 
 const express = require('express');
@@ -25,11 +26,13 @@ module.exports = (crowi) => {
   const path = require('path');
   const csrf = require('../../middlewares/csrf')(crowi);
 
+  const minPasswordLength = crowi.configManager.getConfig('crowi', 'app:minPasswordLength');
+
   const validator = {
     password: [
       body('newPassword').isString().not().isEmpty()
-        .isLength({ min: 8 })
-        .withMessage('password must be at least 8 characters long'),
+        .isLength({ min: minPasswordLength })
+        .withMessage(`password must be at least ${minPasswordLength} characters long`),
       // checking if password confirmation matches password
       body('newPasswordConfirm').isString().not().isEmpty()
         .custom((value, { req }) => {

+ 6 - 4
packages/app/src/server/routes/apiv3/personal-setting.js

@@ -72,6 +72,8 @@ module.exports = (crowi) => {
 
   const { User, ExternalAccount } = crowi.models;
 
+  const minPasswordLength = crowi.configManager.getConfig('crowi', 'app:minPasswordLength');
+
   const validator = {
     personal: [
       body('name').isString().not().isEmpty(),
@@ -91,8 +93,8 @@ module.exports = (crowi) => {
     password: [
       body('oldPassword').isString(),
       body('newPassword').isString().not().isEmpty()
-        .isLength({ min: 8 })
-        .withMessage('password must be at least 8 characters long'),
+        .isLength({ min: minPasswordLength })
+        .withMessage(`password must be at least ${minPasswordLength} characters long`),
       body('newPasswordConfirm').isString().not().isEmpty()
         .custom((value, { req }) => {
           return (value === req.body.newPassword);
@@ -146,7 +148,6 @@ module.exports = (crowi) => {
    */
   router.get('/', accessTokenParser, loginRequiredStrictly, async(req, res) => {
     const { username } = req.user;
-
     try {
       const user = await User.findUserByUsername(username);
 
@@ -189,7 +190,8 @@ module.exports = (crowi) => {
     try {
       const user = await User.findUserByUsername(username);
       const isPasswordSet = user.isPasswordSet();
-      return res.apiv3({ isPasswordSet });
+      const minPasswordLength = crowi.configManager.getConfig('crowi', 'app:minPasswordLength');
+      return res.apiv3({ isPasswordSet, minPasswordLength });
     }
     catch (err) {
       logger.error(err);

+ 13 - 1
packages/app/src/server/service/config-loader.ts

@@ -1,6 +1,6 @@
+import { envUtils } from '@growi/core';
 import { parseISO } from 'date-fns';
 
-import { envUtils } from '@growi/core';
 
 import loggerFactory from '~/utils/logger';
 
@@ -217,6 +217,12 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = {
     type:    ValueType.STRING,
     default: null,
   },
+  AUTO_INSTALL_ALLOW_GUEST_MODE: {
+    ns:      'crowi',
+    key:     'autoInstall:allowGuestMode',
+    type:    ValueType.BOOLEAN,
+    default: false,
+  },
   AUTO_INSTALL_SERVER_DATE: {
     ns:      'crowi',
     key:     'autoInstall:serverDate',
@@ -610,6 +616,12 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = {
     type:    ValueType.STRING,
     default: null,
   },
+  MIN_PASSWORD_LENGTH: {
+    ns: 'crowi',
+    key: 'app:minPasswordLength',
+    type: ValueType.NUMBER,
+    default: 8,
+  },
 };
 
 

+ 71 - 71
packages/app/src/server/service/file-uploader/aws.js → packages/app/src/server/service/file-uploader/aws.ts

@@ -1,41 +1,57 @@
+import {
+  S3Client,
+  HeadObjectCommand,
+  GetObjectCommand,
+  DeleteObjectsCommand,
+  PutObjectCommand,
+  DeleteObjectCommand,
+  GetObjectCommandOutput,
+} from '@aws-sdk/client-s3';
+import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
+import urljoin from 'url-join';
+
 import loggerFactory from '~/utils/logger';
 
-const logger = loggerFactory('growi:service:fileUploaderAws');
 
-const urljoin = require('url-join');
-const aws = require('aws-sdk');
+const logger = loggerFactory('growi:service:fileUploaderAws');
 
-module.exports = function(crowi) {
+type AwsCredential = {
+  accessKeyId: string,
+  secretAccessKey: string
+}
+type AwsConfig = {
+  credentials: AwsCredential,
+  region: string,
+  endpoint: string,
+  bucket: string,
+  forcePathStyle?: boolean
+}
+
+module.exports = (crowi) => {
   const Uploader = require('./uploader');
   const { configManager } = crowi;
   const lib = new Uploader(crowi);
 
-  function getAwsConfig() {
+  const getAwsConfig = (): AwsConfig => {
     return {
-      accessKeyId: configManager.getConfig('crowi', 'aws:s3AccessKeyId'),
-      secretAccessKey: configManager.getConfig('crowi', 'aws:s3SecretAccessKey'),
+      credentials: {
+        accessKeyId: configManager.getConfig('crowi', 'aws:s3AccessKeyId'),
+        secretAccessKey: configManager.getConfig('crowi', 'aws:s3SecretAccessKey'),
+      },
       region: configManager.getConfig('crowi', 'aws:s3Region'),
+      endpoint: configManager.getConfig('crowi', 'aws:s3CustomEndpoint'),
       bucket: configManager.getConfig('crowi', 'aws:s3Bucket'),
-      customEndpoint: configManager.getConfig('crowi', 'aws:s3CustomEndpoint'),
+      forcePathStyle: configManager.getConfig('crowi', 'aws:s3CustomEndpoint') != null, // s3ForcePathStyle renamed to forcePathStyle in v3
     };
-  }
-
-  function S3Factory() {
-    const awsConfig = getAwsConfig();
-
-    aws.config.update({
-      accessKeyId: awsConfig.accessKeyId,
-      secretAccessKey: awsConfig.secretAccessKey,
-      region: awsConfig.region,
-      s3ForcePathStyle: awsConfig.customEndpoint ? true : undefined,
-    });
+  };
 
-    // undefined & null & '' => default endpoint (genuine S3)
-    return new aws.S3({ endpoint: awsConfig.customEndpoint || undefined });
-  }
+  const S3Factory = (): S3Client => {
+    const config = getAwsConfig();
+    return new S3Client(config);
+  };
 
-  function getFilePathOnStorage(attachment) {
-    if (attachment.filePath != null) { // backward compatibility for v3.3.x or below
+  const getFilePathOnStorage = (attachment) => {
+    if (attachment.filePath != null) {
       return attachment.filePath;
     }
 
@@ -45,41 +61,37 @@ module.exports = function(crowi) {
     const filePath = urljoin(dirName, attachment.fileName);
 
     return filePath;
-  }
+  };
 
-  async function isFileExists(s3, params) {
-    // check file exists
+  const isFileExists = async(s3: S3Client, params) => {
     try {
-      await s3.headObject(params).promise();
+      await s3.send(new HeadObjectCommand(params));
     }
     catch (err) {
       if (err != null && err.code === 'NotFound') {
         return false;
       }
-
-      // error except for 'NotFound
       throw err;
     }
-
     return true;
-  }
+  };
 
-  lib.isValidUploadSettings = function() {
-    return this.configManager.getConfig('crowi', 'aws:s3AccessKeyId') != null
-      && this.configManager.getConfig('crowi', 'aws:s3SecretAccessKey') != null
+  lib.isValidUploadSettings = () => {
+    return configManager.getConfig('crowi', 'aws:s3AccessKeyId') != null
+      && configManager.getConfig('crowi', 'aws:s3SecretAccessKey') != null
       && (
-        this.configManager.getConfig('crowi', 'aws:s3Region') != null
-          || this.configManager.getConfig('crowi', 'aws:s3CustomEndpoint') != null
+        configManager.getConfig('crowi', 'aws:s3Region') != null
+          || configManager.getConfig('crowi', 'aws:s3CustomEndpoint') != null
       )
-      && this.configManager.getConfig('crowi', 'aws:s3Bucket') != null;
+      && configManager.getConfig('crowi', 'aws:s3Bucket') != null;
   };
 
-  lib.canRespond = function() {
-    return !this.configManager.getConfig('crowi', 'aws:referenceFileWithRelayMode');
+  lib.canRespond = () => {
+    return !configManager.getConfig('crowi', 'aws:referenceFileWithRelayMode');
   };
 
-  lib.respond = async function(res, attachment) {
-    if (!this.getIsUploadable()) {
+  lib.respond = async(res, attachment) => {
+    if (!lib.getIsUploadable()) {
       throw new Error('AWS is not configured.');
     }
     const temporaryUrl = attachment.getValidTemporaryUrl();
@@ -90,16 +102,16 @@ module.exports = function(crowi) {
     const s3 = S3Factory();
     const awsConfig = getAwsConfig();
     const filePath = getFilePathOnStorage(attachment);
-    const lifetimeSecForTemporaryUrl = this.configManager.getConfig('crowi', 'aws:lifetimeSecForTemporaryUrl');
+    const lifetimeSecForTemporaryUrl = configManager.getConfig('crowi', 'aws:lifetimeSecForTemporaryUrl');
 
     // issue signed url (default: expires 120 seconds)
     // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property
     const params = {
       Bucket: awsConfig.bucket,
       Key: filePath,
-      Expires: lifetimeSecForTemporaryUrl,
     };
-    const signedUrl = s3.getSignedUrl('getObject', params);
+    const signedUrl = await getSignedUrl(s3, new GetObjectCommand(params), { expiresIn: lifetimeSecForTemporaryUrl });
+
 
     res.redirect(signedUrl);
 
@@ -112,13 +124,13 @@ module.exports = function(crowi) {
 
   };
 
-  lib.deleteFile = async function(attachment) {
+  lib.deleteFile = async(attachment) => {
     const filePath = getFilePathOnStorage(attachment);
     return lib.deleteFileByFilePath(filePath);
   };
 
-  lib.deleteFiles = async function(attachments) {
-    if (!this.getIsUploadable()) {
+  lib.deleteFiles = async(attachments) => {
+    if (!lib.getIsUploadable()) {
       throw new Error('AWS is not configured.');
     }
     const s3 = S3Factory();
@@ -132,11 +144,11 @@ module.exports = function(crowi) {
       Bucket: awsConfig.bucket,
       Delete: { Objects: filePaths },
     };
-    return s3.deleteObjects(totalParams).promise();
+    return s3.send(new DeleteObjectsCommand(totalParams));
   };
 
-  lib.deleteFileByFilePath = async function(filePath) {
-    if (!this.getIsUploadable()) {
+  lib.deleteFileByFilePath = async(filePath) => {
+    if (!lib.getIsUploadable()) {
       throw new Error('AWS is not configured.');
     }
     const s3 = S3Factory();
@@ -154,11 +166,11 @@ module.exports = function(crowi) {
       return;
     }
 
-    return s3.deleteObject(params).promise();
+    return s3.send(new DeleteObjectCommand(params));
   };
 
-  lib.uploadFile = function(fileStream, attachment) {
-    if (!this.getIsUploadable()) {
+  lib.uploadFile = async(fileStream, attachment) => {
+    if (!lib.getIsUploadable()) {
       throw new Error('AWS is not configured.');
     }
 
@@ -176,17 +188,11 @@ module.exports = function(crowi) {
       ACL: 'public-read',
     };
 
-    return s3.upload(params).promise();
+    return s3.send(new PutObjectCommand(params));
   };
 
-  /**
-   * Find data substance
-   *
-   * @param {Attachment} attachment
-   * @return {stream.Readable} readable stream
-   */
-  lib.findDeliveryFile = async function(attachment) {
-    if (!this.getIsReadable()) {
+  lib.findDeliveryFile = async(attachment) => {
+    if (!lib.getIsReadable()) {
       throw new Error('AWS is not configured.');
     }
 
@@ -205,9 +211,9 @@ module.exports = function(crowi) {
       throw new Error(`Any object that relate to the Attachment (${filePath}) does not exist in AWS S3`);
     }
 
-    let stream;
+    let stream : GetObjectCommandOutput['Body'];
     try {
-      stream = s3.getObject(params).createReadStream();
+      stream = (await s3.send(new GetObjectCommand(params))).Body;
     }
     catch (err) {
       logger.error(err);
@@ -218,12 +224,6 @@ module.exports = function(crowi) {
     return stream;
   };
 
-  /**
-   * check the file size limit
-   *
-   * In detail, the followings are checked.
-   * - per-file size limit (specified by MAX_FILE_SIZE)
-   */
   lib.checkLimit = async(uploadFileSize) => {
     const maxFileSize = crowi.configManager.getConfig('crowi', 'app:maxFileSize');
     const totalLimit = crowi.configManager.getConfig('crowi', 'app:fileUploadTotalLimit');

+ 20 - 8
packages/app/src/server/service/installer.ts

@@ -1,23 +1,30 @@
-import mongoose from 'mongoose';
-import fs from 'graceful-fs';
 import path from 'path';
+
 import ExtensibleCustomError from 'extensible-custom-error';
+import fs from 'graceful-fs';
+import mongoose from 'mongoose';
+
 
+import { Lang } from '~/interfaces/lang';
 import { IPage } from '~/interfaces/page';
 import { IUser } from '~/interfaces/user';
-import { Lang } from '~/interfaces/lang';
 import loggerFactory from '~/utils/logger';
 
 import { generateConfigsForInstalling } from '../models/config';
 
-import SearchService from './search';
 import ConfigManager from './config-manager';
+import SearchService from './search';
 
 const logger = loggerFactory('growi:service:installer');
 
 export class FailedToCreateAdminUserError extends ExtensibleCustomError {
 }
 
+export type AutoInstallOptions = {
+  allowGuestMode?: boolean,
+  serverDate?: Date,
+}
+
 export class InstallerService {
 
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -90,16 +97,21 @@ export class InstallerService {
   /**
    * Execute only once for installing application
    */
-  private async initDB(globalLang: Lang): Promise<void> {
+  private async initDB(globalLang: Lang, options?: AutoInstallOptions): Promise<void> {
     const configManager: ConfigManager = this.crowi.configManager;
 
     const initialConfig = generateConfigsForInstalling();
     initialConfig['app:globalLang'] = globalLang;
+
+    if (options?.allowGuestMode) {
+      initialConfig['security:restrictGuestMode'] = 'Readonly';
+    }
+
     return configManager.updateConfigsInTheSameNamespace('crowi', initialConfig, true);
   }
 
-  async install(firstAdminUserToSave: IUser, globalLang: Lang, initialPagesCreatedAt?: Date): Promise<IUser> {
-    await this.initDB(globalLang);
+  async install(firstAdminUserToSave: IUser, globalLang: Lang, options?: AutoInstallOptions): Promise<IUser> {
+    await this.initDB(globalLang, options);
 
     // TODO typescriptize models/user.js and remove eslint-disable-next-line
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -137,7 +149,7 @@ export class InstallerService {
     await Promise.all([rootPage.save(), rootRevision.save()]);
 
     // create initial pages
-    await this.createInitialPages(adminUser, globalLang, initialPagesCreatedAt);
+    await this.createInitialPages(adminUser, globalLang, options?.serverDate);
 
     return adminUser;
   }

+ 1 - 1
packages/app/src/server/service/page.ts

@@ -262,7 +262,7 @@ class PageService {
       authority: IPageDeleteConfigValueToProcessValidation | null,
       recursiveAuthority: IPageDeleteConfigValueToProcessValidation | null,
   ): boolean {
-    const isAdmin = operator.admin;
+    const isAdmin = operator?.admin ?? false;
     const isOperator = operator?._id == null ? false : operator._id.equals(creatorId);
 
     if (isRecursively) {

+ 0 - 1
packages/app/src/server/views/layout-growi/not_found.html

@@ -15,7 +15,6 @@
   </div>
   <div class="grw-container-convertible">
     {% include '../widget/page_alerts.html' %}
-    <div id="not-found-alert"></div>
   </div>
 {% endblock %}
 

+ 1 - 1
packages/app/src/styles/theme/_apply-colors-dark.scss

@@ -234,7 +234,7 @@ ul.pagination {
       background-color: $bgcolor-list-hover;
     }
     .page-list-snippet {
-      color: theme-color('light');
+      color: darken($body-color, 10%);
     }
   }
 }

+ 7 - 0
packages/app/src/styles/theme/_apply-colors-light.scss

@@ -224,6 +224,13 @@ $dropdown-link-active-bg: $bgcolor-dropdown-link-active;
       }
     }
   }
+  // List group
+  .list-group-item {
+    // TODO: fix color light theme
+    .page-list-snippet {
+      color: $gray-600;
+    }
+  }
 }
 
 /*

+ 0 - 4
packages/app/src/styles/theme/_apply-colors.scss

@@ -500,10 +500,6 @@ ul.pagination {
         }
       }
 
-      .page-list-snippet {
-        color: $gray-600;
-      }
-
       &.list-group-item-action {
         &.active {
           background-color: $bgcolor-page-list-group-item-active;

+ 0 - 0
packages/app/test/cypress/integration/1-install/install.spec.ts → packages/app/test/cypress/integration/10-install/install.spec.ts


+ 148 - 0
packages/app/test/cypress/integration/20-basic-features/access-to-page.spec.ts

@@ -0,0 +1,148 @@
+context('Access to page', () => {
+  const ssPrefix = 'access-to-page-';
+
+  beforeEach(() => {
+    // login
+    cy.fixture("user-admin.json").then(user => {
+      cy.login(user.username, user.password);
+    });
+    // collapse sidebar
+    cy.collapseSidebar(true);
+  });
+
+  it('/Sandbox is successfully loaded', () => {
+    cy.visit('/Sandbox', {  });
+    cy.screenshot(`${ssPrefix}-sandbox`);
+  });
+
+  it('/Sandbox with anchor hash is successfully loaded', () => {
+    cy.visit('/Sandbox#Headers');
+
+    // hide fab
+    cy.getByTestid('grw-fab-container').invoke('attr', 'style', 'display: none');
+
+    cy.screenshot(`${ssPrefix}-sandbox-headers`);
+  });
+
+  it('/Sandbox/Math is successfully loaded', () => {
+    cy.visit('/Sandbox/Math');
+    cy.screenshot(`${ssPrefix}-sandbox-math`);
+  });
+
+  it('/Sandbox with edit is successfully loaded', () => {
+    cy.visit('/Sandbox#edit');
+    cy.screenshot(`${ssPrefix}-sandbox-edit-page`);
+  })
+
+  it('/user/admin is successfully loaded', () => {
+    cy.visit('/user/admin', {  });
+    cy.screenshot(`${ssPrefix}-user-admin`);
+  });
+
+});
+
+
+context('Access to /me page', () => {
+  const ssPrefix = 'access-to-me-page-';
+
+  beforeEach(() => {
+    // login
+    cy.fixture("user-admin.json").then(user => {
+      cy.login(user.username, user.password);
+    });
+    // collapse sidebar
+    cy.collapseSidebar(true);
+  });
+
+  it('/me is successfully loaded', () => {
+    cy.visit('/me', {  });
+    cy.screenshot(`${ssPrefix}-me`);
+  });
+
+  it('Draft page is successfully shown', () => {
+    cy.visit('/me/drafts');
+    cy.screenshot(`${ssPrefix}-draft-page`);
+  });
+
+});
+
+
+
+context('Access to special pages', () => {
+  const ssPrefix = 'access-to-special-pages-';
+
+  beforeEach(() => {
+    // login
+    cy.fixture("user-admin.json").then(user => {
+      cy.login(user.username, user.password);
+    });
+    // collapse sidebar
+    cy.collapseSidebar(true);
+  });
+
+  it('/trash is successfully loaded', () => {
+    cy.visit('/trash', {  });
+    cy.getByTestid('trash-page-list').should('be.visible');
+    cy.screenshot(`${ssPrefix}-trash`);
+  });
+
+  it('/tags is successfully loaded', () => {
+    cy.visit('/tags');
+
+    // open sidebar
+    cy.collapseSidebar(false);
+    // select tags
+    cy.getByTestid('grw-sidebar-nav-primary-tags').click();
+    cy.getByTestid('grw-sidebar-content-tags').should('be.visible');
+    cy.getByTestid('grw-tags-list').should('be.visible');
+    cy.getByTestid('grw-tags-list').contains('You have no tag, You can set tags on pages');
+
+    cy.getByTestid('tags-page').should('be.visible');
+    cy.screenshot(`${ssPrefix}-tags`);
+  });
+
+});
+
+context('Access to Template Editing Mode', () => {
+  const ssPrefix = 'access-to-modal-';
+
+  beforeEach(() => {
+    // login
+    cy.fixture("user-admin.json").then(user => {
+      cy.login(user.username, user.password);
+    });
+    // collapse sidebar
+    cy.collapseSidebar(true);
+  });
+
+
+  it('Access to Template Editor mode for only child pages successfully', () => {
+     cy.visit('/Sandbox/Bootstrap4', {  });
+     cy.get('#grw-subnav-container').within(() => {
+       cy.getByTestid('open-page-item-control-btn').click();
+       cy.getByTestid('open-page-template-modal-btn').click();
+    });
+
+     cy.getByTestid('page-template-modal').should('be.visible')
+     cy.screenshot(`${ssPrefix}-open-page-template-bootstrap4`);
+     cy.getByTestid('template-button-children').click();
+     cy.url().should('include', '/_template#edit');
+     cy.screenshot();
+  });
+
+  it('Access to Template Editor mode including decendants successfully', () => {
+    cy.visit('/Sandbox/Bootstrap4', {  });
+    cy.get('#grw-subnav-container').within(() => {
+      cy.getByTestid('open-page-item-control-btn').click();
+      cy.getByTestid('open-page-template-modal-btn').click();
+   });
+
+    cy.getByTestid('page-template-modal').should('be.visible')
+    // cy.screenshot(`${ssPrefix}-open-page-template-bootstrap4`);
+    cy.getByTestid('template-button-decendants').click();
+    cy.url().should('include', '/__template#edit');
+    cy.screenshot();
+ });
+
+});
+

+ 36 - 0
packages/app/test/cypress/integration/2-basic-features/use-tools.spec.ts → packages/app/test/cypress/integration/20-basic-features/use-tools.spec.ts

@@ -105,3 +105,39 @@ context('Open presentation modal', () => {
   });
 
 });
+
+context('Page Accessories Modal', () => {
+
+  const ssPrefix = 'access-to-page-accessories-modal';
+
+  beforeEach(() => {
+    // login
+    cy.fixture("user-admin.json").then(user => {
+      cy.login(user.username, user.password);
+    });
+  });
+
+  it('Page History is shown successfully', () => {
+     cy.visit('/Sandbox/Bootstrap4', {  });
+     cy.get('#grw-subnav-container').within(() => {
+       cy.getByTestid('open-page-item-control-btn').click();
+       cy.getByTestid('open-page-accessories-modal-btn-with-history-tab').click();
+    });
+
+     cy.getByTestid('page-accessories-modal').should('be.visible')
+     cy.getByTestid('page-history').should('be.visible')
+     cy.screenshot(`${ssPrefix}-open-page-history-bootstrap4`);
+  });
+  it('Page Attachment Data is shown successfully', () => {
+     cy.visit('/Sandbox/Bootstrap4', {  });
+     cy.get('#grw-subnav-container').within(() => {
+       cy.getByTestid('open-page-item-control-btn').click();
+       cy.getByTestid('open-page-accessories-modal-btn-with-attachment-data-tab').click();
+    });
+
+     cy.getByTestid('page-accessories-modal').should('be.visible')
+     cy.getByTestid('page-attachment').should('be.visible')
+     cy.screenshot(`${ssPrefix}-open-page-attachment-data-bootstrap4`);
+  });
+
+});

+ 6 - 30
packages/app/test/cypress/integration/2-basic-features/access-to-page.spec.ts → packages/app/test/cypress/integration/21-basic-features-for-guest/access-to-page.spec.ts

@@ -1,12 +1,7 @@
-
-context('Access to page', () => {
-  const ssPrefix = 'access-to-page-';
+context('Access to page by guest', () => {
+  const ssPrefix = 'access-to-page-by-guest-';
 
   beforeEach(() => {
-    // login
-    cy.fixture("user-admin.json").then(user => {
-      cy.login(user.username, user.password);
-    });
     // collapse sidebar
     cy.collapseSidebar(true);
   });
@@ -35,48 +30,29 @@ context('Access to page', () => {
     cy.screenshot(`${ssPrefix}-sandbox-edit-page`);
   })
 
-  it('/user/admin is successfully loaded', () => {
-    cy.visit('/user/admin', {  });
-    cy.screenshot(`${ssPrefix}-user-admin`);
-  });
-
 });
 
 
 context('Access to /me page', () => {
-  const ssPrefix = 'access-to-me-page-';
+  const ssPrefix = 'access-to-me-page-by-guest-';
 
   beforeEach(() => {
-    // login
-    cy.fixture("user-admin.json").then(user => {
-      cy.login(user.username, user.password);
-    });
     // collapse sidebar
     cy.collapseSidebar(true);
   });
 
-  it('/me is successfully loaded', () => {
+  it('/me should be redirected to /login', () => {
     cy.visit('/me', {  });
     cy.screenshot(`${ssPrefix}-me`);
   });
 
-  it('Draft page is successfully shown', () => {
-    cy.visit('/me/drafts');
-    cy.screenshot(`${ssPrefix}-draft-page`);
-  });
-
 });
 
 
-
-context('Access to special pages', () => {
-  const ssPrefix = 'access-to-special-pages-';
+context('Access to special pages by guest', () => {
+  const ssPrefix = 'access-to-special-pages-by-guest-';
 
   beforeEach(() => {
-    // login
-    cy.fixture("user-admin.json").then(user => {
-      cy.login(user.username, user.password);
-    });
     // collapse sidebar
     cy.collapseSidebar(true);
   });

+ 0 - 0
packages/app/test/cypress/integration/3-search/search.spec.ts → packages/app/test/cypress/integration/30-search/search.spec.ts


+ 0 - 0
packages/app/test/cypress/integration/4-admin/access-to-admin-page.spec.ts → packages/app/test/cypress/integration/40-admin/access-to-admin-page.spec.ts


+ 0 - 0
packages/app/test/cypress/integration/5-switch-sidebar-mode/switching-sidebar-mode.spec.ts → packages/app/test/cypress/integration/50-switch-sidebar-mode/switching-sidebar-mode.spec.ts


+ 0 - 0
packages/app/test/cypress/integration/6-home/home.spec.ts → packages/app/test/cypress/integration/60-home/home.spec.ts


+ 1 - 1
packages/codemirror-textlint/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/codemirror-textlint",
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "license": "MIT",
   "main": "dist/index.js",
   "scripts": {

+ 1 - 1
packages/core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/core",
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "description": "GROWI Core Libraries",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/plugin-attachment-refs/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-attachment-refs",
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "description": "GROWI Plugin to add ref/refimg/refs/refsimg tags",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/plugin-lsx/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-lsx",
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "description": "GROWI plugin to list pages",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/plugin-pukiwiki-like-linker/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-pukiwiki-like-linker",
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "description": "GROWI plugin to add PukiwikiLikeLinker",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/slack/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slack",
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "license": "MIT",
   "main": "dist/index.js",
   "typings": "dist/index.d.ts",

+ 2 - 2
packages/slackbot-proxy/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slackbot-proxy",
-  "version": "5.0.7-slackbot-proxy.0",
+  "version": "5.0.8-slackbot-proxy.0",
   "license": "MIT",
   "scripts": {
     "build": "yarn tsc && tsc-alias -p tsconfig.build.json",
@@ -25,7 +25,7 @@
   },
   "dependencies": {
     "@godaddy/terminus": "^4.9.0",
-    "@growi/slack": "^5.0.7-RC.0",
+    "@growi/slack": "^5.0.8-RC.0",
     "@slack/oauth": "^2.0.1",
     "@slack/web-api": "^6.2.4",
     "@tsed/common": "^6.43.0",

+ 1 - 1
packages/ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/ui",
-  "version": "5.0.7-RC.0",
+  "version": "5.0.8-RC.0",
   "description": "GROWI UI Libraries",
   "license": "MIT",
   "keywords": [

+ 914 - 1
yarn.lock

@@ -44,6 +44,904 @@
     call-me-maybe "^1.0.1"
     z-schema "^4.2.3"
 
+"@aws-crypto/crc32@2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-2.0.0.tgz#4ad432a3c03ec3087c5540ff6e41e6565d2dc153"
+  integrity sha512-TvE1r2CUueyXOuHdEigYjIZVesInd9KN+K/TFFNfkkxRThiNxO6i4ZqqAVMoEjAamZZ1AA8WXJkjCz7YShHPQA==
+  dependencies:
+    "@aws-crypto/util" "^2.0.0"
+    "@aws-sdk/types" "^3.1.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/crc32c@2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/crc32c/-/crc32c-2.0.0.tgz#4235336ef78f169f6a05248906703b9b78da676e"
+  integrity sha512-vF0eMdMHx3O3MoOXUfBZry8Y4ZDtcuskjjKgJz8YfIDjLStxTZrYXk+kZqtl6A0uCmmiN/Eb/JbC/CndTV1MHg==
+  dependencies:
+    "@aws-crypto/util" "^2.0.0"
+    "@aws-sdk/types" "^3.1.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/ie11-detection@^2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/ie11-detection/-/ie11-detection-2.0.0.tgz#bb6c2facf8f03457e949dcf0921477397ffa4c6e"
+  integrity sha512-pkVXf/dq6PITJ0jzYZ69VhL8VFOFoPZLZqtU/12SGnzYuJOOGNfF41q9GxdI1yqC8R13Rq3jOLKDFpUJFT5eTA==
+  dependencies:
+    tslib "^1.11.1"
+
+"@aws-crypto/sha1-browser@2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/sha1-browser/-/sha1-browser-2.0.0.tgz#71e735df20ea1d38f59259c4b1a2e00ca74a0eea"
+  integrity sha512-3fIVRjPFY8EG5HWXR+ZJZMdWNRpwbxGzJ9IH9q93FpbgCH8u8GHRi46mZXp3cYD7gealmyqpm3ThZwLKJjWJhA==
+  dependencies:
+    "@aws-crypto/ie11-detection" "^2.0.0"
+    "@aws-crypto/supports-web-crypto" "^2.0.0"
+    "@aws-sdk/types" "^3.1.0"
+    "@aws-sdk/util-locate-window" "^3.0.0"
+    "@aws-sdk/util-utf8-browser" "^3.0.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/sha256-browser@2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-2.0.0.tgz#741c9024df55ec59b51e5b1f5d806a4852699fb5"
+  integrity sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==
+  dependencies:
+    "@aws-crypto/ie11-detection" "^2.0.0"
+    "@aws-crypto/sha256-js" "^2.0.0"
+    "@aws-crypto/supports-web-crypto" "^2.0.0"
+    "@aws-crypto/util" "^2.0.0"
+    "@aws-sdk/types" "^3.1.0"
+    "@aws-sdk/util-locate-window" "^3.0.0"
+    "@aws-sdk/util-utf8-browser" "^3.0.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/sha256-js@2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-2.0.0.tgz#f1f936039bdebd0b9e2dd834d65afdc2aac4efcb"
+  integrity sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==
+  dependencies:
+    "@aws-crypto/util" "^2.0.0"
+    "@aws-sdk/types" "^3.1.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/sha256-js@^2.0.0":
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-2.0.1.tgz#79e1e6cf61f652ef2089c08d471c722ecf1626a9"
+  integrity sha512-mbHTBSPBvg6o/mN/c18Z/zifM05eJrapj5ggoOIeHIWckvkv5VgGi7r/wYpt+QAO2ySKXLNvH2d8L7bne4xrMQ==
+  dependencies:
+    "@aws-crypto/util" "^2.0.1"
+    "@aws-sdk/types" "^3.1.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/supports-web-crypto@^2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-2.0.0.tgz#fd6cde30b88f77d5a4f57b2c37c560d918014f9e"
+  integrity sha512-Ge7WQ3E0OC7FHYprsZV3h0QIcpdyJLvIeg+uTuHqRYm8D6qCFJoiC+edSzSyFiHtZf+NOQDJ1q46qxjtzIY2nA==
+  dependencies:
+    tslib "^1.11.1"
+
+"@aws-crypto/util@^2.0.0", "@aws-crypto/util@^2.0.1":
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-2.0.1.tgz#976cf619cf85084ca85ec5eb947a6ac6b8b5c98c"
+  integrity sha512-JJmFFwvbm08lULw4Nm5QOLg8+lAQeC8aCXK5xrtxntYzYXCGfHwUJ4Is3770Q7HmICsXthGQ+ZsDL7C2uH3yBQ==
+  dependencies:
+    "@aws-sdk/types" "^3.1.0"
+    "@aws-sdk/util-utf8-browser" "^3.0.0"
+    tslib "^1.11.1"
+
+"@aws-sdk/abort-controller@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/abort-controller/-/abort-controller-3.55.0.tgz#779f487cceab7804f2d542925a1918fbe91b42ac"
+  integrity sha512-rCcTxJDEFnmvo/PgbhCRv24/Uv03lEGfRslKZq7SjaMcOubflS/ZXYaMEgsjYHgAT0zlpSsyCIkJXmhFaM7H7w==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/chunked-blob-reader-native@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/chunked-blob-reader-native/-/chunked-blob-reader-native-3.58.0.tgz#1db413c5c80b32e24f1b62b22e15e9ad74d75cda"
+  integrity sha512-+D3xnPD5985iphgAqgUerBDs371a2WzzoEVi7eHJUMMsP/gEnSTdSH0HNxsqhYv6CW4EdKtvDAQdAwA1VtCf2A==
+  dependencies:
+    "@aws-sdk/util-base64-browser" "3.58.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/chunked-blob-reader@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/chunked-blob-reader/-/chunked-blob-reader-3.55.0.tgz#db240c78e7c4c826e707f0ca32a4d221c41cf6a0"
+  integrity sha512-o/xjMCq81opAjSBjt7YdHJwIJcGVG5XIV9+C2KXcY5QwVimkOKPybWTv0mXPvSwSilSx+EhpLNhkcJuXdzhw4w==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/client-s3@^3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.58.0.tgz#7cf9c43a2060346333e74cbc6e7ef44a83391ec4"
+  integrity sha512-7TAqYFpFeaahLCdIxsdWLz3uRrzITFFFitbfVxQ+eaR6EMuH3VEhbGEZ66+zieWns9a1UXc11918vpwgu0zTtw==
+  dependencies:
+    "@aws-crypto/sha1-browser" "2.0.0"
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/client-sts" "3.58.0"
+    "@aws-sdk/config-resolver" "3.58.0"
+    "@aws-sdk/credential-provider-node" "3.58.0"
+    "@aws-sdk/eventstream-serde-browser" "3.58.0"
+    "@aws-sdk/eventstream-serde-config-resolver" "3.55.0"
+    "@aws-sdk/eventstream-serde-node" "3.58.0"
+    "@aws-sdk/fetch-http-handler" "3.58.0"
+    "@aws-sdk/hash-blob-browser" "3.58.0"
+    "@aws-sdk/hash-node" "3.55.0"
+    "@aws-sdk/hash-stream-node" "3.58.0"
+    "@aws-sdk/invalid-dependency" "3.55.0"
+    "@aws-sdk/md5-js" "3.58.0"
+    "@aws-sdk/middleware-bucket-endpoint" "3.58.0"
+    "@aws-sdk/middleware-content-length" "3.58.0"
+    "@aws-sdk/middleware-expect-continue" "3.58.0"
+    "@aws-sdk/middleware-flexible-checksums" "3.58.0"
+    "@aws-sdk/middleware-host-header" "3.58.0"
+    "@aws-sdk/middleware-location-constraint" "3.55.0"
+    "@aws-sdk/middleware-logger" "3.55.0"
+    "@aws-sdk/middleware-retry" "3.58.0"
+    "@aws-sdk/middleware-sdk-s3" "3.58.0"
+    "@aws-sdk/middleware-serde" "3.55.0"
+    "@aws-sdk/middleware-signing" "3.58.0"
+    "@aws-sdk/middleware-ssec" "3.55.0"
+    "@aws-sdk/middleware-stack" "3.55.0"
+    "@aws-sdk/middleware-user-agent" "3.58.0"
+    "@aws-sdk/node-config-provider" "3.58.0"
+    "@aws-sdk/node-http-handler" "3.58.0"
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/smithy-client" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/url-parser" "3.55.0"
+    "@aws-sdk/util-base64-browser" "3.58.0"
+    "@aws-sdk/util-base64-node" "3.55.0"
+    "@aws-sdk/util-body-length-browser" "3.55.0"
+    "@aws-sdk/util-body-length-node" "3.55.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.55.0"
+    "@aws-sdk/util-defaults-mode-node" "3.58.0"
+    "@aws-sdk/util-stream-browser" "3.55.0"
+    "@aws-sdk/util-stream-node" "3.55.0"
+    "@aws-sdk/util-user-agent-browser" "3.58.0"
+    "@aws-sdk/util-user-agent-node" "3.58.0"
+    "@aws-sdk/util-utf8-browser" "3.55.0"
+    "@aws-sdk/util-utf8-node" "3.55.0"
+    "@aws-sdk/util-waiter" "3.55.0"
+    "@aws-sdk/xml-builder" "3.55.0"
+    entities "2.2.0"
+    fast-xml-parser "3.19.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/client-sso@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.58.0.tgz#0cc5152cf1246ddc726016aa8964c39237e2ad78"
+  integrity sha512-nS5G/OX8Bg4ajBa6+jLcbbr4PpEO+l5eJfGUzoJQwS4Zqa0lF/wC0kyjKm61gLp4JuvhrQskxIC/3IXUqB1XVQ==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/config-resolver" "3.58.0"
+    "@aws-sdk/fetch-http-handler" "3.58.0"
+    "@aws-sdk/hash-node" "3.55.0"
+    "@aws-sdk/invalid-dependency" "3.55.0"
+    "@aws-sdk/middleware-content-length" "3.58.0"
+    "@aws-sdk/middleware-host-header" "3.58.0"
+    "@aws-sdk/middleware-logger" "3.55.0"
+    "@aws-sdk/middleware-retry" "3.58.0"
+    "@aws-sdk/middleware-serde" "3.55.0"
+    "@aws-sdk/middleware-stack" "3.55.0"
+    "@aws-sdk/middleware-user-agent" "3.58.0"
+    "@aws-sdk/node-config-provider" "3.58.0"
+    "@aws-sdk/node-http-handler" "3.58.0"
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/smithy-client" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/url-parser" "3.55.0"
+    "@aws-sdk/util-base64-browser" "3.58.0"
+    "@aws-sdk/util-base64-node" "3.55.0"
+    "@aws-sdk/util-body-length-browser" "3.55.0"
+    "@aws-sdk/util-body-length-node" "3.55.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.55.0"
+    "@aws-sdk/util-defaults-mode-node" "3.58.0"
+    "@aws-sdk/util-user-agent-browser" "3.58.0"
+    "@aws-sdk/util-user-agent-node" "3.58.0"
+    "@aws-sdk/util-utf8-browser" "3.55.0"
+    "@aws-sdk/util-utf8-node" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/client-sts@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.58.0.tgz#31d03eecccac63bd572b252b53c64338f742fe99"
+  integrity sha512-2cHZsG2eXv/Zl0hvsG9+rdHEuAclMFfkma/3LC3RRwSuZXo1rXoIhFkzHfGfIbivdk738YAo7FT3ZYGlrsK4ow==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/config-resolver" "3.58.0"
+    "@aws-sdk/credential-provider-node" "3.58.0"
+    "@aws-sdk/fetch-http-handler" "3.58.0"
+    "@aws-sdk/hash-node" "3.55.0"
+    "@aws-sdk/invalid-dependency" "3.55.0"
+    "@aws-sdk/middleware-content-length" "3.58.0"
+    "@aws-sdk/middleware-host-header" "3.58.0"
+    "@aws-sdk/middleware-logger" "3.55.0"
+    "@aws-sdk/middleware-retry" "3.58.0"
+    "@aws-sdk/middleware-sdk-sts" "3.58.0"
+    "@aws-sdk/middleware-serde" "3.55.0"
+    "@aws-sdk/middleware-signing" "3.58.0"
+    "@aws-sdk/middleware-stack" "3.55.0"
+    "@aws-sdk/middleware-user-agent" "3.58.0"
+    "@aws-sdk/node-config-provider" "3.58.0"
+    "@aws-sdk/node-http-handler" "3.58.0"
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/smithy-client" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/url-parser" "3.55.0"
+    "@aws-sdk/util-base64-browser" "3.58.0"
+    "@aws-sdk/util-base64-node" "3.55.0"
+    "@aws-sdk/util-body-length-browser" "3.55.0"
+    "@aws-sdk/util-body-length-node" "3.55.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.55.0"
+    "@aws-sdk/util-defaults-mode-node" "3.58.0"
+    "@aws-sdk/util-user-agent-browser" "3.58.0"
+    "@aws-sdk/util-user-agent-node" "3.58.0"
+    "@aws-sdk/util-utf8-browser" "3.55.0"
+    "@aws-sdk/util-utf8-node" "3.55.0"
+    entities "2.2.0"
+    fast-xml-parser "3.19.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/config-resolver@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/config-resolver/-/config-resolver-3.58.0.tgz#c990541276ecdc76acf25f68f58cdb0d0d7eb07e"
+  integrity sha512-NXEwYw0JrXcvenu42QpNMQXK+6pgZ+6bDGfCgOfCC0FmyI+w/CuF36lApwm7InHvHazOaDlwArXm2pfntErKoA==
+  dependencies:
+    "@aws-sdk/signature-v4" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-config-provider" "3.55.0"
+    "@aws-sdk/util-middleware" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/credential-provider-env@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.55.0.tgz#5a1f5ddff54ea3f58f4a1a824b5b19a1f3618fc6"
+  integrity sha512-4AIIXEdvinLlWNFtrUbUgoB7dkuV04RTcTruVWI4Ub4WSsuSCa72ZU1vqyvcEAOgGGLBmcSaGTWByjiD2sGcGA==
+  dependencies:
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/credential-provider-imds@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.58.0.tgz#89d3963895f5e6150b74b5ba2010158d8576b95e"
+  integrity sha512-CdtnTQ9zqLx1FbXdbgjijLbMcIWOyQM03TFaLSCjI3FNbUwyt3T7StBU9tj/LtbypHhSdXyQBpzUtXTOMWCEhg==
+  dependencies:
+    "@aws-sdk/node-config-provider" "3.58.0"
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/url-parser" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/credential-provider-ini@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.58.0.tgz#16144b8a821766550fce4f96040c5e4ed115e77c"
+  integrity sha512-uM62hcHUVaHP1YFnbrjf2RlrRj1m/BvMPE+T5jdNRWdE3lvnunhEMawB26HZs9nQqCV6d25I8G9/fGWVL7g3Og==
+  dependencies:
+    "@aws-sdk/credential-provider-env" "3.55.0"
+    "@aws-sdk/credential-provider-imds" "3.58.0"
+    "@aws-sdk/credential-provider-sso" "3.58.0"
+    "@aws-sdk/credential-provider-web-identity" "3.55.0"
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/shared-ini-file-loader" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/credential-provider-node@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.58.0.tgz#f9816ce2c300edd102c0a43fd28274056452b70e"
+  integrity sha512-f0wzcgMYCQUrii6TLP2ggCxkQP4HH8PW8tbbWEgt4cdIXcjE9KEuxN5yOV6sFHzL3eJh0QM9Yaz8WzhWn6fT2A==
+  dependencies:
+    "@aws-sdk/credential-provider-env" "3.55.0"
+    "@aws-sdk/credential-provider-imds" "3.58.0"
+    "@aws-sdk/credential-provider-ini" "3.58.0"
+    "@aws-sdk/credential-provider-process" "3.58.0"
+    "@aws-sdk/credential-provider-sso" "3.58.0"
+    "@aws-sdk/credential-provider-web-identity" "3.55.0"
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/shared-ini-file-loader" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/credential-provider-process@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.58.0.tgz#ff6db03266428bb2074e9b32db8021efa1af6570"
+  integrity sha512-npgFqPUjMhUamf1FvJjBYUdpbWx8XWkKCwJsX73I7IYQAvAi2atCOkdtKq+4rds0VWAYu6vzlaI1tXgFxjOPNQ==
+  dependencies:
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/shared-ini-file-loader" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/credential-provider-sso@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.58.0.tgz#cc8bb71c41488e8be855fce7caf0a5dd1da79286"
+  integrity sha512-2qO34s9lJqvCC6zOF4UpopW6xURZpYfVC8xTUDpAUnvTOt4nS5hkx4vNyqPAXILoRHuFJsnlWsBH1UP5ZnBiZg==
+  dependencies:
+    "@aws-sdk/client-sso" "3.58.0"
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/shared-ini-file-loader" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/credential-provider-web-identity@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.55.0.tgz#21aebe5b4ad7a5b4abaf8df9aabfba0994ece357"
+  integrity sha512-aKnXfZNGohTuF9rCGYLg4JEIOvWIZ/sb66XMq7bOUrx13KRPDwL/eUQL8quS5jGRLpjXVNvrS17AFf65GbdUBg==
+  dependencies:
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/eventstream-marshaller@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-marshaller/-/eventstream-marshaller-3.58.0.tgz#32d83d006b26f1488e4001cfc1899800428c0dc2"
+  integrity sha512-vTdVFLIHGZTx/Anp9GpkTXVuvwSCNOecTutU5Py4i6fATgefWiSutc5Xc/FLujBSc0EhAXDGZIcTMpZC7jUpeg==
+  dependencies:
+    "@aws-crypto/crc32" "2.0.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-hex-encoding" "3.58.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/eventstream-serde-browser@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-3.58.0.tgz#ce9bf8060335743d66c9de2bb751cc506cc494a5"
+  integrity sha512-oR5yoOoJrTSUKwbxZSt37bZgMXUUSsOub96E6SOb8wh8TMq2f0wvqeO8A+aaxY487gKpzuVUClp7jSQ9LgiVcw==
+  dependencies:
+    "@aws-sdk/eventstream-marshaller" "3.58.0"
+    "@aws-sdk/eventstream-serde-universal" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/eventstream-serde-config-resolver@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.55.0.tgz#02fe0ea00b46d8a9fdb021946146d9cb2545dd0d"
+  integrity sha512-NTJHLq1sbXyXAaJucKvcdN3Svr/fM2TjHEC3l8P/torFjIsX1+Ykpi8tZt8KsX8RjoUTTfKylh41AjJq0K9X4Q==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/eventstream-serde-node@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-3.58.0.tgz#c0bf378827aef87e7a25f8e72f64911383af10a4"
+  integrity sha512-U1DnRVfvKOXty+Bei6oqhRWFzGWzxl0OFHtev9GzC7BE/E6s4Gn695o+NO+9IwQgjOlc/JsGyAcWevq3MDxymg==
+  dependencies:
+    "@aws-sdk/eventstream-marshaller" "3.58.0"
+    "@aws-sdk/eventstream-serde-universal" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/eventstream-serde-universal@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-3.58.0.tgz#c52090981acbb551c3bf30d4af0327e5f85a7f19"
+  integrity sha512-w7czmMNvCCspJi8Ij0lTByCiuYBhyNzYTM1wv33vtF7dL+FJgi4W4c5WFAOtvpsPulobY013TWCjPJG+V0IPGQ==
+  dependencies:
+    "@aws-sdk/eventstream-marshaller" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/fetch-http-handler@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.58.0.tgz#5e102283f0e9a29b5d4d5cf42508a79635b3779a"
+  integrity sha512-timF3FjPV5Bd+Kgph83LIKVlPCFObVYzious1a6doeLAT6YFwZpRrWbfP/HzS+DCoYiwUsH69oVJ91BoV66oyA==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/querystring-builder" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-base64-browser" "3.58.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/hash-blob-browser@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/hash-blob-browser/-/hash-blob-browser-3.58.0.tgz#03a4e78932d0e00ff1f452d528a9c3e64bc9fff3"
+  integrity sha512-fdp12BqypRxwvevbJSl/sUhXJRi4Ghv6JKEXAHI1klkR6xY1GRORO5SHWltVY/xl373ERMol5o/n+ra/7jcx/g==
+  dependencies:
+    "@aws-sdk/chunked-blob-reader" "3.55.0"
+    "@aws-sdk/chunked-blob-reader-native" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/hash-node@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/hash-node/-/hash-node-3.55.0.tgz#ea58e9b6f2147c59ad4e41e83bd6864df59b331e"
+  integrity sha512-2UdYwY/++AlzWEAFaK9wOed2QSxbzV527vmqKjReLHpPKPrSIlooUxlTH3LU6Y6WVDAzDRtLK43KUVXTLgGK1A==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-buffer-from" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/hash-stream-node@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/hash-stream-node/-/hash-stream-node-3.58.0.tgz#f0f3fc45e069834600264deed2fa4d0da42773b1"
+  integrity sha512-y7HEeC3OiuXCRqsHnKDn5yef8UAbnegD9r+OM9bdD+3e6FLAL8Rq7hQTOpwIAiPXuD7HKx8h98s9JLvkwTOBkg==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/invalid-dependency@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/invalid-dependency/-/invalid-dependency-3.55.0.tgz#5406c80e4be534700b92b61c21a74efd754c9492"
+  integrity sha512-delH0lV+78fdD/8MXIt9kTLS6IwHvdhqq9dw/ow5VjTUw+xBwUlfPfZplaai+3hKTKWh6a2WZCeDasNItBv9aA==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/is-array-buffer@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/is-array-buffer/-/is-array-buffer-3.55.0.tgz#c46122c5636f01d5895e5256a587768c3425ea7a"
+  integrity sha512-NbiPHVYuPxdqdFd6FxzzN3H1BQn/iWA3ri3Ry7AyLeP/tGs1yzEWMwf8BN8TSMALI0GXT6Sh0GDWy3Ok5xB6DA==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/md5-js@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/md5-js/-/md5-js-3.58.0.tgz#a7ecf5cc8a81ce247fd620f8c981802d0427737f"
+  integrity sha512-V5f4Re+CLn3aDF1nrmDqdUtcqBHCyxxD2s2Ot+hZ2JFit+OtJggo1cI03ldTrQpG79rwHG+bHqL2VvNQP7Aj9A==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-utf8-browser" "3.55.0"
+    "@aws-sdk/util-utf8-node" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-bucket-endpoint@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.58.0.tgz#cec84100ff776862e3bbd4bd596a1e869ad81e5e"
+  integrity sha512-zocLfFzj+NQjXLGZKPJBAYWWldAKBJkGzGVpTfrYx9bxxHTA70Gu+3sx+Xe+iOu8dtQT0OAnIX0wGudOPnTGNg==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-arn-parser" "3.55.0"
+    "@aws-sdk/util-config-provider" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-content-length@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-content-length/-/middleware-content-length-3.58.0.tgz#9418b8c5f4437c9f5f7860e85c36468e93a302f7"
+  integrity sha512-h/BypPkhjv2CpCUbXA8Fa2s7V2GPiz9l11XhYK+sKSuQvQ7Lbq6VhaKaLqfeD3gLVZHgJZSLGl2btdHV1qHNNA==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-expect-continue@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.58.0.tgz#92be232561ef27ab41bf46feb0f689e11f695516"
+  integrity sha512-nx6X6qLPwvbJrGoPxXSu4tsOek2eRnnjk78hhRUDfxFewpHJQLSPlyNKkXAo+C3syVALe6RJRmUYu5bShY6FfA==
+  dependencies:
+    "@aws-sdk/middleware-header-default" "3.58.0"
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-flexible-checksums@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.58.0.tgz#ff9f7d37e0261517d9abbff99d44940dad9c9865"
+  integrity sha512-R8S3U1boaIb7+kYhLJBks7rv/eaGj7I5T/2CgmcGY1BJBUU0h0arjPC7eeA/5wV29EHapoxVYQvJda//706rCw==
+  dependencies:
+    "@aws-crypto/crc32" "2.0.0"
+    "@aws-crypto/crc32c" "2.0.0"
+    "@aws-sdk/is-array-buffer" "3.55.0"
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-header-default@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-header-default/-/middleware-header-default-3.58.0.tgz#c72190df982601048126f452f3805858f1a11a4b"
+  integrity sha512-7F+CdLLauMmNbwFGYrE2pKsgTKY8G2PgazHmaE9s3FySEFcGPWmiEAG8sVImfZooj8gxGFQMLr97nanWjhSq2Q==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-host-header@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.58.0.tgz#c7fe87ed16306e328e780bbed282dbf31d605236"
+  integrity sha512-q/UKGcanm9e6DBRNN6UKhVqLvpRRdZWbmmPCeDNr4HqhCmgT6i1OvWdhAMOnT++hvCX8DpTsIXzNSlY6zWAxBg==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-location-constraint@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.55.0.tgz#cb7e91df4269bb2e64ee2d83a49973f152ef9094"
+  integrity sha512-OvCKwBFbl8Gbfk0HGX00pkdORJN8BPuH/O5l3+mOBWuwILPuckRP5WGnL+1HT/gu4hHS6h1lpxUrPxUOoeKIAg==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-logger@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.55.0.tgz#83adc985a3a98493519384565e0c1a06552b8704"
+  integrity sha512-PtRbVrxEzDmeV9prBIP4/9or7R5Dj66mjbFSvNRGZ0n+UBfBFfVRfNrhQPNzQpfV9A3KVl9YyWCVXDSW+/rk9Q==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-retry@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-retry/-/middleware-retry-3.58.0.tgz#967518e5b9e55546dcb5de0dfe5784df71807d72"
+  integrity sha512-sfSq+t0Yy47DQwrWGpA8iOx9sd26l4l1JDVTwHNi7+OKD4ClRPVCEdw3bTbbyYz/PV4f9AEfAZ6jwtSff4wkGw==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/service-error-classification" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-middleware" "3.55.0"
+    tslib "^2.3.1"
+    uuid "^8.3.2"
+
+"@aws-sdk/middleware-sdk-s3@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.58.0.tgz#8e9138d5f613df556b05fe3fb2094e6a49fd0085"
+  integrity sha512-vOTPOdhZpNJo4v54evg6JnFz14hK8IW2u8B+12iV5ZQ4zJom6VowzFmIOUn+KIsw/6SrwEX9tFb0aXLlVRw27Q==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/signature-v4" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-arn-parser" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-sdk-sts@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.58.0.tgz#5b433a49d2aeb10120805d0f13f6700153d55ec9"
+  integrity sha512-HUz7MhcsSDDTGygOwL61l4voc0pZco06J3z06JjTX19D5XxcQ7hSCtkHHHz0oMb9M1himVSiEon2tjhjsnB99g==
+  dependencies:
+    "@aws-sdk/middleware-signing" "3.58.0"
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/signature-v4" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-serde@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-serde/-/middleware-serde-3.55.0.tgz#326a0696255868a9dfca7c482a616897e9d54fdf"
+  integrity sha512-NkEbTDrSZcC2NhuvfjXHKJEl0xgI2B5tMAwi/rMOq/TEnARwVUL9qAy+5lgeiPCqebiNllWatARrFgAaYf0VeA==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-signing@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.58.0.tgz#996828122526ec5f95e6e898a6573791db4cd5e1"
+  integrity sha512-4FXubHB66GbhyZUlo6YPQoWpYfED15GNbEmHbJLSONzrVzZR3IkViSPLasDngVm1a050JqKuqNkFYGJBP4No/Q==
+  dependencies:
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/signature-v4" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-ssec@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.55.0.tgz#2f8c8593fb2a2719a0863d48b0ef6baecbd08011"
+  integrity sha512-HTdA23hksOphQe0TmYORsa/kMNnKRGbdh0VJcsDGHQScJXzJ+C//THwfcoklff0XZfC+vGh93PECBWqixMELZw==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-stack@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-stack/-/middleware-stack-3.55.0.tgz#e99ffb0bdd6861ec3b5a667561dc41dfcb44d36b"
+  integrity sha512-ouD+wFz8W2R0ZQ8HrbhgN8tg1jyINEg9lPEEXY79w1Q5sf94LJ90XKAMVk02rw3dJalUWjLHf0OQe1/qxZfHyA==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/middleware-user-agent@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.58.0.tgz#c60b83f61ed385989e0be5dc80b05a8d5626bbf8"
+  integrity sha512-1c69bIWM63JwXijXvb9IWwcwQ/gViKMZ1lhxv52NvdG5VSxWXXsFJ2jETEXZoAypwT97Hmf3xo9SYuaHcKoq+g==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/node-config-provider@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/node-config-provider/-/node-config-provider-3.58.0.tgz#1a138c571f6b2608cff49a64f4f2936971734f1e"
+  integrity sha512-AMcPqPhKxo/3/yOMS9PsKlI0GWp2/8eD6gSlhzdBpznPCKplyqXOSnSX7wS814Cyh373hFSjCaOrCOA9/EYtDg==
+  dependencies:
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/shared-ini-file-loader" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/node-http-handler@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/node-http-handler/-/node-http-handler-3.58.0.tgz#bb633b51a205181657bfc59b24b7bf1720b7e652"
+  integrity sha512-D9xVZG2nfo4GbPsby3JuBiAhpqXTFk1+CfuQU0AZv0gQvE3fFTCnB3za83jo7JV/pyRPU+s+/LHIpxCWUHzStg==
+  dependencies:
+    "@aws-sdk/abort-controller" "3.55.0"
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/querystring-builder" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/property-provider@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/property-provider/-/property-provider-3.55.0.tgz#0eabe5e84d9258c85c2c5e44bcb09379ae9429d2"
+  integrity sha512-o7cKFJSHq5WOhwPsspYrzNto35oKKZvESZuWDtLxaZKSI6l7zpA366BI4kDG6Tc9i2+teV553MbxyZ9eya5A8g==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/protocol-http@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/protocol-http/-/protocol-http-3.58.0.tgz#170798abcc97884d4beabc4dbbdfe3b41acd2d0a"
+  integrity sha512-0yFFRPbR+CCa9eOQBBQ2qtrIDLYqSMN0y7G4iqVM8wQdIw7n3QK1PsTI3RNPGJ3Oi2krFTw5uUKqQQZPZEBuVQ==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/querystring-builder@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-builder/-/querystring-builder-3.55.0.tgz#7d6d4e2c597eb3d636bd3a368b494dac175ba329"
+  integrity sha512-/ZAXNipt9nRR8k+eowwukE/YjXnQ49p5w/MkaQxsBk3IuIf7MAcgVg8glHr0igH84GfUQ7ZVP8v+G2S3tKUG+Q==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-uri-escape" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/querystring-parser@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-parser/-/querystring-parser-3.55.0.tgz#ea35642c1b8324dd896d45185f99ad9d6c3af6d2"
+  integrity sha512-e+2FLgo+eDx7oh7ap5HngN9XSVMxredAVztLHxCcSN0lFHHHzMa8b2SpXbaowUxQHh7ziymSqvOrPYFQ71Filg==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/s3-request-presigner@^3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.58.0.tgz#83a1bdf9fa4f2a7dc1e250da5356a4a58e301b1d"
+  integrity sha512-rkwRSLSuTJaW3+rJgfjtJ8VCbuUh3iXKeeml3QP7ldsHg/4knUxEMr/Ja0PIkVrbPts2g4KGr4ZlppvxC9b4lA==
+  dependencies:
+    "@aws-sdk/middleware-sdk-s3" "3.58.0"
+    "@aws-sdk/protocol-http" "3.58.0"
+    "@aws-sdk/signature-v4" "3.58.0"
+    "@aws-sdk/smithy-client" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-create-request" "3.58.0"
+    "@aws-sdk/util-format-url" "3.58.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/service-error-classification@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/service-error-classification/-/service-error-classification-3.55.0.tgz#4a85d2d947102c50076bd2af295f62abd74e26ab"
+  integrity sha512-HdjnDyarsa1Avq1MJurkLyEe9c3eRa76dPmK4TmRGgwJ+tInEzGHL0rBW7V8xBK+PDF+fJQ71hvm8jPYmzvBwQ==
+
+"@aws-sdk/shared-ini-file-loader@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.58.0.tgz#321f80f34ef3f15ab40b756fb5ee2797812748c7"
+  integrity sha512-ARDKQerIzgNs/MFNdCEuK2lgRJ1lneAaJw0p9O1LkJUvcSibvkSATwny7vwJMueOf+ae1Pf+8+54OMNIt0nTkQ==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/signature-v4@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4/-/signature-v4-3.58.0.tgz#0d81dd317f9bf35bc0de670c0e534d7793f8e170"
+  integrity sha512-flEo8p3XkzWoBDqnIUQre4jLuT5aLnmfQNI8c2uSjyJ3OBxpJ0iS1cDu3E++d1/pN6Q8o0KOmr2ypHeiyBOujw==
+  dependencies:
+    "@aws-sdk/is-array-buffer" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    "@aws-sdk/util-hex-encoding" "3.58.0"
+    "@aws-sdk/util-middleware" "3.55.0"
+    "@aws-sdk/util-uri-escape" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/smithy-client@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/smithy-client/-/smithy-client-3.55.0.tgz#bf1f5a64d1d2374c291338a52f6c75c6d67e8148"
+  integrity sha512-YgBpqg6R3Qg8CH9biOP1N1lYTvh8VLGD6AoDGgy/R1dQSqRQuxgKANLl3DOVcZnIZLsw4TdB0m7U+ZPtirPR1Q==
+  dependencies:
+    "@aws-sdk/middleware-stack" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/types@3.55.0", "@aws-sdk/types@^3.1.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.55.0.tgz#d524d567e2b2722f2d6be83e2417dd6d46ce1490"
+  integrity sha512-wrDZjuy1CVAYxDCbm3bWQIKMGfNs7XXmG0eG4858Ixgqmq2avsIn5TORy8ynBxcXn9aekV/+tGEQ7BBSYzIVNQ==
+
+"@aws-sdk/url-parser@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/url-parser/-/url-parser-3.55.0.tgz#03b47a45c591d52c9d00dc40c630b91094991fe7"
+  integrity sha512-qrTwN5xIgTLreqLnZ+x3cAudjNKfxi6srW1H/px2mk4lb2U9B4fpGjZ6VU+XV8U2kR+YlT8J6Jo5iwuVGfC91A==
+  dependencies:
+    "@aws-sdk/querystring-parser" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-arn-parser@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-arn-parser/-/util-arn-parser-3.55.0.tgz#6672eb2975e798a460bedfaf6b5618d4e4b262e1"
+  integrity sha512-76KJxp4MRWufHYWys7DFl64znr5yeJ3AIQNAPCKKw1sP0hzO7p6Kx0PaJnw9x+CPSzOrT4NbuApL6/srYhKDGg==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-base64-browser@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-base64-browser/-/util-base64-browser-3.58.0.tgz#e213f91a5d40dd2d048d340f1ab192ca86c1f40c"
+  integrity sha512-0ebsXIZNpu/fup9OgsFPnRKfCFbuuI9PPRzvP6twzLxUB0c/aix6Co7LGHFKcRKHZdaykoJMXArf8eHj2Nzv1Q==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-base64-node@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-base64-node/-/util-base64-node-3.55.0.tgz#da9a3fd6752be49163572144793e6b23d0186ff4"
+  integrity sha512-UQ/ZuNoAc8CFMpSiRYmevaTsuRKzLwulZTnM8LNlIt9Wx1tpNvqp80cfvVj7yySKROtEi20wq29h31dZf1eYNQ==
+  dependencies:
+    "@aws-sdk/util-buffer-from" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-body-length-browser@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.55.0.tgz#9c2637097501032f6a1afddb76687415fe9b44b6"
+  integrity sha512-Ei2OCzXQw5N6ZkTMZbamUzc1z+z1R1Ja5tMEagz5BxuX4vWdBObT+uGlSzL8yvTbjoPjnxWA2aXyEqaUP3JS8Q==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-body-length-node@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-body-length-node/-/util-body-length-node-3.55.0.tgz#67049bbb6c62d794a1bb5a13b9a678988c925489"
+  integrity sha512-lU1d4I+9wJwydduXs0SxSfd+mHKjxeyd39VwOv6i2KSwWkPbji9UQqpflKLKw+r45jL7+xU/zfeTUg5Tt/3Gew==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-buffer-from@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-buffer-from/-/util-buffer-from-3.55.0.tgz#e7c927974b07a29502aa1ad58509b91d0d7cf0f7"
+  integrity sha512-uVzKG1UgvnV7XX2FPTylBujYMKBPBaq/qFBxfl0LVNfrty7YjpfieQxAe6yRLD+T0Kir/WDQwGvYC+tOYG3IGA==
+  dependencies:
+    "@aws-sdk/is-array-buffer" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-config-provider@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-config-provider/-/util-config-provider-3.55.0.tgz#720c6c0ac1aa8d14be29d1dee25e01eb4925c0ce"
+  integrity sha512-30dzofQQfx6tp1jVZkZ0DGRsT0wwC15nEysKRiAcjncM64A0Cm6sra77d0os3vbKiKoPCI/lMsFr4o3533+qvQ==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-create-request@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-create-request/-/util-create-request-3.58.0.tgz#c104e158b94c11cf92de5aa7535214f0b1e5b2a3"
+  integrity sha512-EP6HLQHc8RxjSJ95Ca9Ppp5F0aS6QNSQg03hbjcpmKK42h8dtuXFp5qGAu35VxUg6IRztN2x7lpa+b3d/SdDoQ==
+  dependencies:
+    "@aws-sdk/middleware-stack" "3.55.0"
+    "@aws-sdk/smithy-client" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-defaults-mode-browser@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.55.0.tgz#c2dc19c908264f643f2f345017efd7addd3824e4"
+  integrity sha512-OS3gAwR84bHz7ObhjsSJM+grfeaBq3leGrj7xiX4BH3C8J+c10GMo3fqx1pV8Fq5F+9lMmhHpfOocD63SN5Q8A==
+  dependencies:
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    bowser "^2.11.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-defaults-mode-node@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.58.0.tgz#57bb445172f10b681f34a7d382d420b9053b2122"
+  integrity sha512-KNUCp0MXI+z3Z3pQCKDkx3Stdy1TXDjcUB+ZJFxRTJGIuBYwX4fV6G8s/zeFJi5Qv1ztR3CJ9fWJGsrx9mQ5EA==
+  dependencies:
+    "@aws-sdk/config-resolver" "3.58.0"
+    "@aws-sdk/credential-provider-imds" "3.58.0"
+    "@aws-sdk/node-config-provider" "3.58.0"
+    "@aws-sdk/property-provider" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-format-url@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-format-url/-/util-format-url-3.58.0.tgz#eed1eebddf124ce05fd376d4416f825d892777be"
+  integrity sha512-nhxomsG+OIBqpIyc2AU88J3+dTap0H5R1D2lNAsSZk07kuu2B1H4qAXIlWPkXyxTi9uL9aykBMuCosECD062NA==
+  dependencies:
+    "@aws-sdk/querystring-builder" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-hex-encoding@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.58.0.tgz#d999eb19329933a94563881540a06d7ac7f515f5"
+  integrity sha512-Rl+jXUzk/FJkOLYfUVYPhKa2aUmTpeobRP31l8IatQltSzDgLyRHO35f6UEs7Ztn5s1jbu/POatLAZ2WjbgVyg==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-locate-window@^3.0.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.55.0.tgz#a4136a20ee1bfcb73967a6614caf769ef79db070"
+  integrity sha512-0sPmK2JaJE2BbTcnvybzob/VrFKCXKfN4CUKcvn0yGg/me7Bz+vtzQRB3Xp+YSx+7OtWxzv63wsvHoAnXvgxgg==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-middleware@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-middleware/-/util-middleware-3.55.0.tgz#22acf3ae45e3bbe9c1cc39d84e14aafb842fdcf0"
+  integrity sha512-82fW2XV+rUalv8lkd4VlhpPp6xnXO5n9sckMp1N+TrQ+p8eqxqT0+o8n1/6s9Qsnkw64Y3m6+EfCdc8/uFOY2g==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-stream-browser@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-stream-browser/-/util-stream-browser-3.55.0.tgz#2a85bcbbe1b0645580d7bdb2c2d8242ac25e5435"
+  integrity sha512-3f/zQsAqexJpKssCL0adTjG8WO+NPQ63E3TingyKpnCnHQPEnqPdya5I5OLGzZ0WR0iUWRtpuW0MtuDabyLDWw==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-stream-node@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-stream-node/-/util-stream-node-3.55.0.tgz#2b8588d9a7f3c9fa582df706b01d0911b20f1b87"
+  integrity sha512-brCK3iENvXEL7BK5eDAdkZ2VuBSvXj7DH9EQezxl4Ntrj1lvb+McOk9WoU/o7yzE7A/bzEJEoNQAPi+VPNbb/w==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-uri-escape@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-uri-escape/-/util-uri-escape-3.55.0.tgz#ee57743c628a1c9f942dfe73205ce890ec011916"
+  integrity sha512-mmdDLUpFCN2nkfwlLdOM54lTD528GiGSPN1qb8XtGLgZsJUmg3uJSFIN2lPeSbEwJB3NFjVas/rnQC48i7mV8w==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-user-agent-browser@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.58.0.tgz#3f46000a3d9c18d1bef6ae88682defa0c3863832"
+  integrity sha512-aJpqCvT09giJRg5xFTBDBRAVF0k0yq3OEf6UTuiOVf5azlL2MGp6PJ/xkJp9Z06PuQQkwBJ/2nIQZemo02a5Sw==
+  dependencies:
+    "@aws-sdk/types" "3.55.0"
+    bowser "^2.11.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-user-agent-node@3.58.0":
+  version "3.58.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.58.0.tgz#ea821601b0d2c7d81239ad0de60964f3967f06ac"
+  integrity sha512-VlbY/nzWdN2pfLUHqKvnlGBQ6tEeV4jyK9ggAD2Szjj0bkYvaaKwpBKswQmuJpi5/J2v7Bo4ayBLnqDL7PgzLA==
+  dependencies:
+    "@aws-sdk/node-config-provider" "3.58.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-utf8-browser@3.55.0", "@aws-sdk/util-utf8-browser@^3.0.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.55.0.tgz#a045bf1a93f6e0ff9c846631b168ea55bbb37668"
+  integrity sha512-ljzqJcyjfJpEVSIAxwtIS8xMRUly84BdjlBXyp6cu4G8TUufgjNS31LWdhyGhgmW5vYBNr+LTz0Kwf6J+ou7Ug==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/util-utf8-node@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-node/-/util-utf8-node-3.55.0.tgz#44cf9f9c8624d144afd65ab8a1786e33134add15"
+  integrity sha512-FsFm7GFaC7j0tlPEm/ri8bU2QCwFW5WKjxUg8lm1oWaxplCpKGUsmcfPJ4sw58GIoyoGu4QXBK60oCWosZYYdQ==
+  dependencies:
+    "@aws-sdk/util-buffer-from" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/util-waiter@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-waiter/-/util-waiter-3.55.0.tgz#0e48a8ce98931f99cfbcad750222fd1f0b237fda"
+  integrity sha512-Do34MKPFSC/+zVN6vY+FZ+0WN61hzga4nPoAC590AOjs8rW6/H6sDN6Gz1KAZbPnuQUZfvsIJjMxN7lblXHJkQ==
+  dependencies:
+    "@aws-sdk/abort-controller" "3.55.0"
+    "@aws-sdk/types" "3.55.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/xml-builder@3.55.0":
+  version "3.55.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.55.0.tgz#8e14012ab3ed27cf68964abf1326d06c686b3511"
+  integrity sha512-BH+i5S2FLprmfSeIuGy3UbNtEoJPVjh8arl5+LV3i2KY/+TmrS4yT8JtztDlDxHF0cMtNLZNO0KEPtsACS6SOg==
+  dependencies:
+    tslib "^2.3.1"
+
 "@azu/format-text@^1.0.1":
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/@azu/format-text/-/format-text-1.0.1.tgz#6967350a94640f6b02855169bd897ce54d6cebe2"
@@ -4776,6 +5674,11 @@ bowser@^1.7.3:
   resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a"
   integrity sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==
 
+bowser@^2.11.0:
+  version "2.11.0"
+  resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f"
+  integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==
+
 brace-expansion@^1.1.7:
   version "1.1.11"
   resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -7788,6 +8691,11 @@ entities@1.0:
   resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26"
   integrity sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=
 
+entities@2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
+  integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
 entities@^2.0.0, entities@~2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
@@ -8796,6 +9704,11 @@ fast-text-encoding@^1.0.0:
   resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz#3e5ce8293409cfaa7177a71b9ca84e1b1e6f25ef"
   integrity sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==
 
+fast-xml-parser@3.19.0:
+  version "3.19.0"
+  resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz#cb637ec3f3999f51406dd8ff0e6fc4d83e520d01"
+  integrity sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==
+
 fastest-levenshtein@^1.0.12:
   version "1.0.12"
   resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
@@ -20380,7 +21293,7 @@ tslib@2.3.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
   integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
 
-tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
+tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0:
   version "1.14.1"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==