From a9552a70bf44abf3e4aa8173f6e36c62c3063170 Mon Sep 17 00:00:00 2001
From: Jamie Howard <48524071+jhoward1994@users.noreply.github.com>
Date: Thu, 12 Oct 2023 17:10:45 +0100
Subject: [PATCH] [Email] Migrate to typescript (#18136)
Co-authored-by: Josh <37798644+joshuaellis@users.noreply.github.com>
---
.../core/admin/admin/src/utils/createRoute.js | 5 +-
packages/core/email/.editorconfig | 12 +-
packages/core/email/.eslintignore | 3 +-
packages/core/email/.eslintrc.js | 2 +-
packages/core/email/admin/.eslintrc.js | 4 +
.../admin/src/{constants.js => constants.ts} | 0
.../email/admin/src/{index.js => index.ts} | 18 +-
.../core/email/admin/src/pages/Settings.tsx | 324 ++++++++++++++++++
.../email/admin/src/pages/Settings/index.js | 314 -----------------
.../tests/{plural.test.js => plural.test.ts} | 8 +-
.../admin/src/utils/{schema.js => schema.ts} | 4 +-
packages/core/email/admin/tsconfig.json | 8 +
packages/core/email/package.json | 36 +-
packages/core/email/packup.config.ts | 27 ++
packages/core/email/server/.eslintrc.js | 7 +
packages/core/email/server/bootstrap.js | 43 ---
.../core/email/server/controllers/email.js | 68 ----
.../core/email/server/controllers/index.js | 7 -
packages/core/email/server/routes/index.js | 6 -
packages/core/email/server/services/index.js | 7 -
packages/core/email/server/src/bootstrap.ts | 57 +++
.../email/server/{config.js => src/config.ts} | 4 +-
.../email/server/src/controllers/email.ts | 77 +++++
.../email/server/src/controllers/index.ts | 3 +
packages/core/email/server/src/index.ts | 13 +
.../{routes/admin.js => src/routes/admin.ts} | 4 +-
.../routes/content-api.ts} | 4 +-
.../core/email/server/src/routes/index.ts | 7 +
.../email.js => src/services/email.ts} | 38 +-
.../core/email/server/src/services/index.ts | 3 +
packages/core/email/server/src/types.ts | 43 +++
.../core/email/server/tsconfig.build.json | 9 +
.../email/server}/tsconfig.eslint.json | 3 +
packages/core/email/server/tsconfig.json | 8 +
packages/core/email/shared/types.ts | 11 +
packages/core/email/strapi-admin.js | 3 -
packages/core/email/strapi-server.js | 16 +-
packages/core/email/tsconfig.build.json | 8 +
.../src/components/CheckPagePermissions.tsx | 9 +-
.../src/components/CheckPermissions.tsx | 6 +-
.../strapi/src/core/loaders/plugins/index.ts | 20 +-
.../core/plugins/config/strapi-admin/index.ts | 2 +-
.../plugins/config/strapi-server/config.ts | 6 +-
.../types/src/types/core/plugins/index.ts | 21 +-
yarn.lock | 6 +
45 files changed, 752 insertions(+), 532 deletions(-)
create mode 100644 packages/core/email/admin/.eslintrc.js
rename packages/core/email/admin/src/{constants.js => constants.ts} (100%)
rename packages/core/email/admin/src/{index.js => index.ts} (76%)
create mode 100644 packages/core/email/admin/src/pages/Settings.tsx
delete mode 100644 packages/core/email/admin/src/pages/Settings/index.js
rename packages/core/email/admin/src/translations/tests/{plural.test.js => plural.test.ts} (68%)
rename packages/core/email/admin/src/utils/{schema.js => schema.ts} (75%)
create mode 100644 packages/core/email/admin/tsconfig.json
create mode 100644 packages/core/email/packup.config.ts
create mode 100644 packages/core/email/server/.eslintrc.js
delete mode 100644 packages/core/email/server/bootstrap.js
delete mode 100644 packages/core/email/server/controllers/email.js
delete mode 100644 packages/core/email/server/controllers/index.js
delete mode 100644 packages/core/email/server/routes/index.js
delete mode 100644 packages/core/email/server/services/index.js
create mode 100644 packages/core/email/server/src/bootstrap.ts
rename packages/core/email/server/{config.js => src/config.ts} (66%)
create mode 100644 packages/core/email/server/src/controllers/email.ts
create mode 100644 packages/core/email/server/src/controllers/index.ts
create mode 100644 packages/core/email/server/src/index.ts
rename packages/core/email/server/{routes/admin.js => src/routes/admin.ts} (95%)
rename packages/core/email/server/{routes/content-api.js => src/routes/content-api.ts} (78%)
create mode 100644 packages/core/email/server/src/routes/index.ts
rename packages/core/email/server/{services/email.js => src/services/email.ts} (66%)
create mode 100644 packages/core/email/server/src/services/index.ts
create mode 100644 packages/core/email/server/src/types.ts
create mode 100644 packages/core/email/server/tsconfig.build.json
rename packages/{plugins/color-picker/admin => core/email/server}/tsconfig.eslint.json (65%)
create mode 100644 packages/core/email/server/tsconfig.json
create mode 100644 packages/core/email/shared/types.ts
delete mode 100644 packages/core/email/strapi-admin.js
create mode 100644 packages/core/email/tsconfig.build.json
diff --git a/packages/core/admin/admin/src/utils/createRoute.js b/packages/core/admin/admin/src/utils/createRoute.js
index 3481a7e456..c8818946b1 100644
--- a/packages/core/admin/admin/src/utils/createRoute.js
+++ b/packages/core/admin/admin/src/utils/createRoute.js
@@ -12,7 +12,10 @@ const LazyCompo = ({ loadComponent }) => {
try {
const loadedCompo = await loadComponent();
- setCompo(() => loadedCompo.default);
+ // TODO the loaded component provided can currently come from a default or named export
+ // We will move the entire codebase to use named exports only
+ // Until then we support both cases with priority given to the existing default exports
+ setCompo(() => loadedCompo?.default ?? loadedCompo);
} catch (err) {
// TODO return the error component
console.log(err);
diff --git a/packages/core/email/.editorconfig b/packages/core/email/.editorconfig
index d4eed8406b..d452b351df 100644
--- a/packages/core/email/.editorconfig
+++ b/packages/core/email/.editorconfig
@@ -2,6 +2,16 @@ root = true
[*]
end_of_line = lf
-insert_final_newline = false
indent_style = space
indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+charset = utf-8
+
+
+[{package.json,*.yml}]
+indent_style = space
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/packages/core/email/.eslintignore b/packages/core/email/.eslintignore
index 24c11109a2..728eb86d30 100644
--- a/packages/core/email/.eslintignore
+++ b/packages/core/email/.eslintignore
@@ -1,3 +1,4 @@
node_modules/
.eslintrc.js
-index.d.ts
\ No newline at end of file
+index.d.ts
+dist/
diff --git a/packages/core/email/.eslintrc.js b/packages/core/email/.eslintrc.js
index a6c2c1e76d..6f2604d0b1 100644
--- a/packages/core/email/.eslintrc.js
+++ b/packages/core/email/.eslintrc.js
@@ -7,7 +7,7 @@ module.exports = {
},
{
files: ['**/*'],
- excludedFiles: ['admin/**/*'],
+ excludedFiles: ['admin/**/*', 'server/**/*'],
extends: ['custom/back'],
},
],
diff --git a/packages/core/email/admin/.eslintrc.js b/packages/core/email/admin/.eslintrc.js
new file mode 100644
index 0000000000..5b585ac0ad
--- /dev/null
+++ b/packages/core/email/admin/.eslintrc.js
@@ -0,0 +1,4 @@
+module.exports = {
+ root: true,
+ extends: ['custom/front/typescript'],
+};
diff --git a/packages/core/email/admin/src/constants.js b/packages/core/email/admin/src/constants.ts
similarity index 100%
rename from packages/core/email/admin/src/constants.js
rename to packages/core/email/admin/src/constants.ts
diff --git a/packages/core/email/admin/src/index.js b/packages/core/email/admin/src/index.ts
similarity index 76%
rename from packages/core/email/admin/src/index.js
rename to packages/core/email/admin/src/index.ts
index f861c89c73..8649f0b98d 100644
--- a/packages/core/email/admin/src/index.js
+++ b/packages/core/email/admin/src/index.ts
@@ -9,8 +9,12 @@ import { prefixPluginTranslations } from '@strapi/helper-plugin';
import { PERMISSIONS } from './constants';
-export default {
- register(app) {
+import type { Plugin } from '@strapi/types';
+
+const admin: Plugin.Config.AdminInput = {
+ // TODO typing app in strapi/types as every plugin needs it
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ register(app: any) {
// Create the email settings section
app.createSettingSection(
{
@@ -26,11 +30,11 @@ export default {
id: 'settings',
to: `/settings/email`,
async Component() {
- const component = await import(
+ const { ProtectedSettingsPage } = await import(
/* webpackChunkName: "email-settings-page" */ './pages/Settings'
);
- return component;
+ return ProtectedSettingsPage;
},
permissions: PERMISSIONS.settings,
},
@@ -41,8 +45,9 @@ export default {
name: 'email',
});
},
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
bootstrap() {},
- async registerTrads({ locales }) {
+ async registerTrads({ locales }: { locales: string[] }) {
const importedTrads = await Promise.all(
locales.map((locale) => {
return import(
@@ -66,3 +71,6 @@ export default {
return Promise.resolve(importedTrads);
},
};
+
+// eslint-disable-next-line import/no-default-export
+export default admin;
diff --git a/packages/core/email/admin/src/pages/Settings.tsx b/packages/core/email/admin/src/pages/Settings.tsx
new file mode 100644
index 0000000000..7c05ea58b7
--- /dev/null
+++ b/packages/core/email/admin/src/pages/Settings.tsx
@@ -0,0 +1,324 @@
+import * as React from 'react';
+
+import {
+ Box,
+ Button,
+ ContentLayout,
+ Flex,
+ Grid,
+ GridItem,
+ HeaderLayout,
+ Main,
+ Option,
+ Select,
+ TextInput,
+ Typography,
+} from '@strapi/design-system';
+import {
+ CheckPagePermissions,
+ getYupInnerErrors,
+ LoadingIndicatorPage,
+ SettingsPageTitle,
+ useFetchClient,
+ useFocusWhenNavigate,
+ useNotification,
+ useOverlayBlocker,
+} from '@strapi/helper-plugin';
+import { Envelop } from '@strapi/icons';
+import { useIntl } from 'react-intl';
+import { useQuery, useMutation } from 'react-query';
+import styled from 'styled-components';
+import { ValidationError } from 'yup';
+
+import { PERMISSIONS } from '../constants';
+import { schema } from '../utils/schema';
+
+import type { EmailSettings } from '../../../shared/types';
+
+const DocumentationLink = styled.a`
+ color: ${({ theme }) => theme.colors.primary600};
+`;
+
+interface MutationBody {
+ to: string;
+}
+
+export const ProtectedSettingsPage = () => (
+
+
+
+);
+
+const SettingsPage = () => {
+ const toggleNotification = useNotification();
+ const { formatMessage } = useIntl();
+ const { lockApp, unlockApp } = useOverlayBlocker();
+ const { get, post } = useFetchClient();
+
+ const [testAddress, setTestAddress] = React.useState('');
+ const [isTestAddressValid, setIsTestAddressValid] = React.useState(false);
+
+ // TODO: I'm not sure how to type this. I think it should be Record but that type is defined in the helper-plugin
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const [formErrors, setFormErrors] = React.useState>({});
+
+ const { data, isLoading } = useQuery(['email', 'settings'], async () => {
+ const res = await get('/email/settings');
+ const {
+ data: { config },
+ } = res;
+
+ return config;
+ });
+
+ const mutation = useMutation(
+ async (body) => {
+ await post('/email/test', body);
+ },
+ {
+ onError() {
+ toggleNotification!({
+ type: 'warning',
+ message: formatMessage(
+ {
+ id: 'email.Settings.email.plugin.notification.test.error',
+ defaultMessage: 'Failed to send a test mail to {to}',
+ },
+ { to: testAddress }
+ ),
+ });
+ },
+ onSuccess() {
+ toggleNotification!({
+ type: 'success',
+ message: formatMessage(
+ {
+ id: 'email.Settings.email.plugin.notification.test.success',
+ defaultMessage: 'Email test succeeded, check the {to} mailbox',
+ },
+ { to: testAddress }
+ ),
+ });
+ },
+ retry: false,
+ }
+ );
+
+ useFocusWhenNavigate();
+
+ React.useEffect(() => {
+ schema
+ .validate({ email: testAddress }, { abortEarly: false })
+ .then(() => setIsTestAddressValid(true))
+ .catch(() => setIsTestAddressValid(false));
+ }, [testAddress]);
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setTestAddress(() => event.target.value);
+ };
+
+ const handleSubmit = async (event: React.FormEvent) => {
+ event.preventDefault();
+
+ try {
+ await schema.validate({ email: testAddress }, { abortEarly: false });
+ } catch (error) {
+ if (error instanceof ValidationError) {
+ setFormErrors(getYupInnerErrors(error));
+ }
+ }
+
+ lockApp!();
+
+ mutation.mutate({ to: testAddress });
+
+ unlockApp!();
+ };
+
+ return (
+
+
+
+
+
+
+ {isLoading ? (
+
+ ) : (
+ data && (
+
+ )
+ )}
+
+
+ );
+};
diff --git a/packages/core/email/admin/src/pages/Settings/index.js b/packages/core/email/admin/src/pages/Settings/index.js
deleted file mode 100644
index df66bb164b..0000000000
--- a/packages/core/email/admin/src/pages/Settings/index.js
+++ /dev/null
@@ -1,314 +0,0 @@
-import * as React from 'react';
-
-import {
- Box,
- Button,
- ContentLayout,
- Flex,
- Grid,
- GridItem,
- HeaderLayout,
- Main,
- Option,
- Select,
- TextInput,
- Typography,
-} from '@strapi/design-system';
-import {
- CheckPagePermissions,
- getYupInnerErrors,
- LoadingIndicatorPage,
- SettingsPageTitle,
- useFetchClient,
- useFocusWhenNavigate,
- useNotification,
- useOverlayBlocker,
-} from '@strapi/helper-plugin';
-import { Envelop } from '@strapi/icons';
-import { useIntl } from 'react-intl';
-import { useQuery, useMutation } from 'react-query';
-import styled from 'styled-components';
-
-import { PERMISSIONS } from '../../constants';
-import schema from '../../utils/schema';
-
-const DocumentationLink = styled.a`
- color: ${({ theme }) => theme.colors.primary600};
-`;
-
-const ProtectedSettingsPage = () => (
-
-
-
-);
-
-const SettingsPage = () => {
- const toggleNotification = useNotification();
- const { formatMessage } = useIntl();
- const { lockApp, unlockApp } = useOverlayBlocker();
- const { get, post } = useFetchClient();
- const { data, isLoading } = useQuery(['email', 'settings'], async () => {
- const {
- data: { config },
- } = await get('/email/settings');
-
- return config;
- });
-
- const mutation = useMutation(
- (body) => post('/email/test', body),
- {
- onError() {
- toggleNotification({
- type: 'warning',
- message: formatMessage(
- {
- id: 'email.Settings.email.plugin.notification.test.error',
- defaultMessage: 'Failed to send a test mail to {to}',
- },
- { to: testAddress }
- ),
- });
- },
-
- onSuccess() {
- toggleNotification({
- type: 'success',
- message: formatMessage(
- {
- id: 'email.Settings.email.plugin.notification.test.success',
- defaultMessage: 'Email test succeeded, check the {to} mailbox',
- },
- { to: testAddress }
- ),
- });
- },
- },
- {
- retry: false,
- }
- );
-
- useFocusWhenNavigate();
-
- const [formErrors, setFormErrors] = React.useState({});
- const [testAddress, setTestAddress] = React.useState('');
- const [isTestAddressValid, setIsTestAddressValid] = React.useState(false);
-
- React.useEffect(() => {
- schema
- .validate({ email: testAddress }, { abortEarly: false })
- .then(() => setIsTestAddressValid(true))
- .catch(() => setIsTestAddressValid(false));
- }, [testAddress]);
-
- const handleChange = (e) => {
- setTestAddress(() => e.target.value);
- };
-
- const handleSubmit = async (event) => {
- event.preventDefault();
-
- try {
- await schema.validate({ email: testAddress }, { abortEarly: false });
- } catch (error) {
- setFormErrors(getYupInnerErrors(error));
- }
-
- lockApp();
-
- mutation.mutate({ to: testAddress });
-
- unlockApp();
- };
-
- return (
-
-
-
-
-
-
- {isLoading ? (
-
- ) : (
-
- )}
-
-
- );
-};
-
-export default ProtectedSettingsPage;
diff --git a/packages/core/email/admin/src/translations/tests/plural.test.js b/packages/core/email/admin/src/translations/tests/plural.test.ts
similarity index 68%
rename from packages/core/email/admin/src/translations/tests/plural.test.js
rename to packages/core/email/admin/src/translations/tests/plural.test.ts
index a02247e0f5..5ee59d6b17 100644
--- a/packages/core/email/admin/src/translations/tests/plural.test.js
+++ b/packages/core/email/admin/src/translations/tests/plural.test.ts
@@ -1,9 +1,11 @@
-const translations = require('../en.json');
+import translations from '../en.json';
+
+const typedTranslations: Record = translations;
describe('translations', () => {
describe('plural syntax', () => {
it('should avoid .plural/.singular syntax', () => {
- Object.keys(translations).forEach((translationKey) => {
+ Object.keys(typedTranslations).forEach((translationKey) => {
const keyParts = translationKey.split('.');
const lastKeyPart = keyParts.pop();
@@ -13,7 +15,7 @@ describe('translations', () => {
keyParts.push('plural');
const pluralKey = keyParts.join('.');
- expect(translations[pluralKey]).toBeUndefined();
+ expect(typedTranslations[pluralKey]).toBeUndefined();
}
});
});
diff --git a/packages/core/email/admin/src/utils/schema.js b/packages/core/email/admin/src/utils/schema.ts
similarity index 75%
rename from packages/core/email/admin/src/utils/schema.js
rename to packages/core/email/admin/src/utils/schema.ts
index c2b870cd2f..e67dcff644 100644
--- a/packages/core/email/admin/src/utils/schema.js
+++ b/packages/core/email/admin/src/utils/schema.ts
@@ -1,8 +1,6 @@
import { translatedErrors } from '@strapi/helper-plugin';
import * as yup from 'yup';
-const schema = yup.object().shape({
+export const schema = yup.object().shape({
email: yup.string().email(translatedErrors.email).required(translatedErrors.required),
});
-
-export default schema;
diff --git a/packages/core/email/admin/tsconfig.json b/packages/core/email/admin/tsconfig.json
new file mode 100644
index 0000000000..fdbb2a4fb5
--- /dev/null
+++ b/packages/core/email/admin/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "tsconfig/client.json",
+ "include": ["./src", "../shared/types.ts"],
+ "compilerOptions": {
+ "rootDir": "../",
+ }
+}
+
\ No newline at end of file
diff --git a/packages/core/email/package.json b/packages/core/email/package.json
index 5641871201..78de8f0a13 100644
--- a/packages/core/email/package.json
+++ b/packages/core/email/package.json
@@ -19,15 +19,42 @@
"url": "https://strapi.io"
}
],
+ "exports": {
+ "./strapi-admin": {
+ "types": "./dist/admin/src/index.d.ts",
+ "source": "./admin/src/index.ts",
+ "import": "./dist/admin/index.mjs",
+ "require": "./dist/admin/index.js",
+ "default": "./dist/admin/index.js"
+ },
+ "./strapi-server": {
+ "types": "./dist/server/src/index.d.ts",
+ "source": "./server/src/index.ts",
+ "import": "./dist/server/index.mjs",
+ "require": "./dist/server/index.js",
+ "default": "./dist/server/index.js"
+ },
+ "./package.json": "./package.json"
+ },
+ "files": [
+ "./dist",
+ "strapi-server.js"
+ ],
"scripts": {
+ "build": "pack-up build",
+ "clean": "run -T rimraf ./dist",
"lint": "run -T eslint .",
+ "prepublishOnly": "yarn clean && yarn build",
"test:front": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js",
"test:front:ce": "run -T cross-env IS_EE=false jest --config ./jest.config.front.js",
"test:front:watch": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js --watchAll",
- "test:front:watch:ce": "run -T cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll"
+ "test:front:watch:ce": "run -T cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll",
+ "test:ts:front": "run -T tsc -p admin/tsconfig.json",
+ "watch": "pack-up watch"
},
"dependencies": {
"@strapi/design-system": "1.12.0",
+ "@strapi/helper-plugin": "4.14.4",
"@strapi/icons": "1.12.0",
"@strapi/provider-email-sendmail": "4.14.4",
"@strapi/utils": "4.14.4",
@@ -38,8 +65,12 @@
"yup": "0.32.9"
},
"devDependencies": {
- "@strapi/helper-plugin": "4.14.4",
+ "@strapi/pack-up": "workspace:*",
+ "@strapi/types": "workspace:*",
"@testing-library/react": "14.0.0",
+ "@types/koa": "2.13.4",
+ "@types/lodash": "^4.14.191",
+ "koa": "2.13.4",
"msw": "1.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -47,6 +78,7 @@
"styled-components": "5.3.3"
},
"peerDependencies": {
+ "koa": "2.13.4",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
"react-router-dom": "5.3.4",
diff --git a/packages/core/email/packup.config.ts b/packages/core/email/packup.config.ts
new file mode 100644
index 0000000000..bc1f2e55a6
--- /dev/null
+++ b/packages/core/email/packup.config.ts
@@ -0,0 +1,27 @@
+import { defineConfig } from '@strapi/pack-up';
+
+export default defineConfig({
+ bundles: [
+ {
+ source: './admin/src/index.ts',
+ import: './dist/admin/index.mjs',
+ require: './dist/admin/index.js',
+ types: './dist/admin/src/index.d.ts',
+ runtime: 'web',
+ },
+ {
+ source: './server/src/index.ts',
+ import: './dist/server/index.mjs',
+ require: './dist/server/index.js',
+ types: './dist/server/src/index.d.ts',
+ runtime: 'node',
+ },
+ ],
+ dist: './dist',
+ /**
+ * Because we're exporting a server & client package
+ * which have different runtimes we want to ignore
+ * what they look like in the package.json
+ */
+ exports: {},
+});
diff --git a/packages/core/email/server/.eslintrc.js b/packages/core/email/server/.eslintrc.js
new file mode 100644
index 0000000000..81357fb6e7
--- /dev/null
+++ b/packages/core/email/server/.eslintrc.js
@@ -0,0 +1,7 @@
+module.exports = {
+ root: true,
+ extends: ['custom/back/typescript'],
+ parserOptions: {
+ project: ['./server/tsconfig.eslint.json'],
+ },
+};
diff --git a/packages/core/email/server/bootstrap.js b/packages/core/email/server/bootstrap.js
deleted file mode 100644
index cb635d26bd..0000000000
--- a/packages/core/email/server/bootstrap.js
+++ /dev/null
@@ -1,43 +0,0 @@
-'use strict';
-
-const createProvider = (emailConfig) => {
- const providerName = emailConfig.provider?.toLowerCase();
- let provider;
-
- let modulePath;
- try {
- modulePath = require.resolve(`@strapi/provider-email-${providerName}`);
- } catch (error) {
- if (error.code === 'MODULE_NOT_FOUND') {
- modulePath = providerName;
- } else {
- throw error;
- }
- }
-
- try {
- provider = require(modulePath);
- } catch (err) {
- throw new Error(`Could not load email provider "${providerName}".`);
- }
-
- return provider.init(emailConfig.providerOptions, emailConfig.settings);
-};
-
-module.exports = async ({ strapi }) => {
- const emailConfig = strapi.config.get('plugin.email');
- strapi.plugin('email').provider = createProvider(emailConfig);
-
- // Add permissions
- const actions = [
- {
- section: 'settings',
- category: 'email',
- displayName: 'Access the Email Settings page',
- uid: 'settings.read',
- pluginName: 'email',
- },
- ];
-
- await strapi.admin.services.permission.actionProvider.registerMany(actions);
-};
diff --git a/packages/core/email/server/controllers/email.js b/packages/core/email/server/controllers/email.js
deleted file mode 100644
index 3aebf30a5d..0000000000
--- a/packages/core/email/server/controllers/email.js
+++ /dev/null
@@ -1,68 +0,0 @@
-'use strict';
-
-const { pick } = require('lodash/fp');
-const { ApplicationError } = require('@strapi/utils').errors;
-
-/**
- * Email.js controller
- *
- * @description: A set of functions called "actions" of the `email` plugin.
- */
-module.exports = {
- async send(ctx) {
- const options = ctx.request.body;
-
- try {
- await strapi.plugin('email').service('email').send(options);
- } catch (e) {
- if (e.statusCode === 400) {
- throw new ApplicationError(e.message);
- } else {
- throw new Error(`Couldn't send email: ${e.message}.`);
- }
- }
-
- // Send 200 `ok`
- ctx.send({});
- },
-
- async test(ctx) {
- const { to } = ctx.request.body;
-
- if (!to) {
- throw new ApplicationError('No recipient(s) are given');
- }
-
- const email = {
- to,
- subject: `Strapi test mail to: ${to}`,
- text: `Great! You have correctly configured the Strapi email plugin with the ${strapi.config.get(
- 'plugin.email.provider'
- )} provider. \r\nFor documentation on how to use the email plugin checkout: https://docs.strapi.io/developer-docs/latest/plugins/email.html`,
- };
-
- try {
- await strapi.plugin('email').service('email').send(email);
- } catch (e) {
- if (e.statusCode === 400) {
- throw new ApplicationError(e.message);
- } else {
- throw new Error(`Couldn't send test email: ${e.message}.`);
- }
- }
-
- // Send 200 `ok`
- ctx.send({});
- },
-
- async getSettings(ctx) {
- const config = strapi.plugin('email').service('email').getProviderSettings();
-
- ctx.send({
- config: pick(
- ['provider', 'settings.defaultFrom', 'settings.defaultReplyTo', 'settings.testAddress'],
- config
- ),
- });
- },
-};
diff --git a/packages/core/email/server/controllers/index.js b/packages/core/email/server/controllers/index.js
deleted file mode 100644
index 913aea1c3b..0000000000
--- a/packages/core/email/server/controllers/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-const email = require('./email');
-
-module.exports = {
- email,
-};
diff --git a/packages/core/email/server/routes/index.js b/packages/core/email/server/routes/index.js
deleted file mode 100644
index 6939f2d012..0000000000
--- a/packages/core/email/server/routes/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict';
-
-module.exports = {
- admin: require('./admin'),
- 'content-api': require('./content-api'),
-};
diff --git a/packages/core/email/server/services/index.js b/packages/core/email/server/services/index.js
deleted file mode 100644
index 913aea1c3b..0000000000
--- a/packages/core/email/server/services/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-const email = require('./email');
-
-module.exports = {
- email,
-};
diff --git a/packages/core/email/server/src/bootstrap.ts b/packages/core/email/server/src/bootstrap.ts
new file mode 100644
index 0000000000..508743f807
--- /dev/null
+++ b/packages/core/email/server/src/bootstrap.ts
@@ -0,0 +1,57 @@
+import type { Strapi } from '@strapi/types';
+import type { EmailConfig, SendOptions } from './types';
+
+interface EmailProvider {
+ send: (options: SendOptions) => Promise;
+}
+
+interface EmailProviderModule {
+ init: (
+ options: EmailConfig['providerOptions'],
+ settings: EmailConfig['settings']
+ ) => EmailProvider;
+ name?: string;
+ provider?: string;
+}
+
+const createProvider = (emailConfig: EmailConfig) => {
+ const providerName = emailConfig.provider.toLowerCase();
+ let provider: EmailProviderModule;
+
+ let modulePath: string;
+ try {
+ modulePath = require.resolve(`@strapi/provider-email-${providerName}`);
+ } catch (error) {
+ if (error instanceof Error && 'code' in error && error.code === 'MODULE_NOT_FOUND') {
+ modulePath = providerName;
+ } else {
+ throw error;
+ }
+ }
+
+ try {
+ provider = require(modulePath);
+ } catch (err) {
+ throw new Error(`Could not load email provider "${providerName}".`);
+ }
+
+ return provider.init(emailConfig.providerOptions, emailConfig.settings);
+};
+
+export const bootstrap = async ({ strapi }: { strapi: Strapi }) => {
+ const emailConfig: EmailConfig = strapi.config.get('plugin.email');
+ strapi.plugin('email').provider = createProvider(emailConfig);
+
+ // Add permissions
+ const actions = [
+ {
+ section: 'settings',
+ category: 'email',
+ displayName: 'Access the Email Settings page',
+ uid: 'settings.read',
+ pluginName: 'email',
+ },
+ ];
+
+ await strapi.admin!.services.permission.actionProvider.registerMany(actions);
+};
diff --git a/packages/core/email/server/config.js b/packages/core/email/server/src/config.ts
similarity index 66%
rename from packages/core/email/server/config.js
rename to packages/core/email/server/src/config.ts
index 655340321c..81518d1bc5 100644
--- a/packages/core/email/server/config.js
+++ b/packages/core/email/server/src/config.ts
@@ -1,6 +1,6 @@
-'use strict';
+import type { StrapiConfig } from './types';
-module.exports = {
+export const config: StrapiConfig = {
default: {
provider: 'sendmail',
providerOptions: {},
diff --git a/packages/core/email/server/src/controllers/email.ts b/packages/core/email/server/src/controllers/email.ts
new file mode 100644
index 0000000000..cd1a2d45a4
--- /dev/null
+++ b/packages/core/email/server/src/controllers/email.ts
@@ -0,0 +1,77 @@
+import { pick } from 'lodash/fp';
+import { errors } from '@strapi/utils';
+
+import type Koa from 'koa';
+import type { EmailConfig, SendOptions } from '../types';
+
+const { ApplicationError } = errors;
+
+/**
+ * Email.js controller
+ *
+ * @description: A set of functions called "actions" of the `email` plugin.
+ */
+const emailController = {
+ async send(ctx: Koa.Context) {
+ const options: SendOptions = ctx.request.body;
+
+ try {
+ await strapi.plugin('email').service('email').send(options);
+ } catch (error) {
+ if (error instanceof Error) {
+ if ('statusCode' in error && error.statusCode === 400) {
+ throw new ApplicationError(error.message);
+ } else {
+ throw new Error(`Couldn't send email: ${error.message}.`);
+ }
+ }
+ }
+
+ // Send 200 `ok`
+ ctx.send({});
+ },
+
+ async test(ctx: Koa.Context) {
+ const { to } = ctx.request.body;
+
+ if (!to) {
+ throw new ApplicationError('No recipient(s) are given');
+ }
+
+ const email: SendOptions = {
+ to,
+ subject: `Strapi test mail to: ${to}`,
+ text: `Great! You have correctly configured the Strapi email plugin with the ${strapi.config.get(
+ 'plugin.email.provider'
+ )} provider. \r\nFor documentation on how to use the email plugin checkout: https://docs.strapi.io/developer-docs/latest/plugins/email.html`,
+ };
+
+ try {
+ await strapi.plugin('email').service('email').send(email);
+ } catch (error) {
+ if (error instanceof Error) {
+ if ('statusCode' in error && error.statusCode === 400) {
+ throw new ApplicationError(error.message);
+ } else {
+ throw new Error(`Couldn't send test email: ${error.message}.`);
+ }
+ }
+ }
+
+ // Send 200 `ok`
+ ctx.send({});
+ },
+
+ async getSettings(ctx: Koa.Context) {
+ const config: EmailConfig = strapi.plugin('email').service('email').getProviderSettings();
+
+ ctx.send({
+ config: pick(
+ ['provider', 'settings.defaultFrom', 'settings.defaultReplyTo', 'settings.testAddress'],
+ config
+ ),
+ });
+ },
+};
+
+export default emailController;
diff --git a/packages/core/email/server/src/controllers/index.ts b/packages/core/email/server/src/controllers/index.ts
new file mode 100644
index 0000000000..755626a727
--- /dev/null
+++ b/packages/core/email/server/src/controllers/index.ts
@@ -0,0 +1,3 @@
+import email from './email';
+
+export const controllers = { email };
diff --git a/packages/core/email/server/src/index.ts b/packages/core/email/server/src/index.ts
new file mode 100644
index 0000000000..68f5164189
--- /dev/null
+++ b/packages/core/email/server/src/index.ts
@@ -0,0 +1,13 @@
+import { bootstrap } from './bootstrap';
+import { services } from './services';
+import { routes } from './routes';
+import { controllers } from './controllers';
+import { config } from './config';
+
+export default {
+ bootstrap,
+ services,
+ routes,
+ controllers,
+ config,
+};
diff --git a/packages/core/email/server/routes/admin.js b/packages/core/email/server/src/routes/admin.ts
similarity index 95%
rename from packages/core/email/server/routes/admin.js
rename to packages/core/email/server/src/routes/admin.ts
index 8b14aefed6..3d5362d83a 100644
--- a/packages/core/email/server/routes/admin.js
+++ b/packages/core/email/server/src/routes/admin.ts
@@ -1,6 +1,4 @@
-'use strict';
-
-module.exports = {
+export default {
type: 'admin',
routes: [
{
diff --git a/packages/core/email/server/routes/content-api.js b/packages/core/email/server/src/routes/content-api.ts
similarity index 78%
rename from packages/core/email/server/routes/content-api.js
rename to packages/core/email/server/src/routes/content-api.ts
index 23f1764864..ee0ecf5eb8 100644
--- a/packages/core/email/server/routes/content-api.js
+++ b/packages/core/email/server/src/routes/content-api.ts
@@ -1,6 +1,4 @@
-'use strict';
-
-module.exports = {
+export default {
type: 'content-api',
routes: [
{
diff --git a/packages/core/email/server/src/routes/index.ts b/packages/core/email/server/src/routes/index.ts
new file mode 100644
index 0000000000..d6b08414d6
--- /dev/null
+++ b/packages/core/email/server/src/routes/index.ts
@@ -0,0 +1,7 @@
+import admin from './admin';
+import contentApi from './content-api';
+
+export const routes = {
+ admin,
+ 'content-api': contentApi,
+};
diff --git a/packages/core/email/server/services/email.js b/packages/core/email/server/src/services/email.ts
similarity index 66%
rename from packages/core/email/server/services/email.js
rename to packages/core/email/server/src/services/email.ts
index bff1c7f867..a054f1d21e 100644
--- a/packages/core/email/server/services/email.js
+++ b/packages/core/email/server/src/services/email.ts
@@ -1,18 +1,19 @@
-'use strict';
+import * as _ from 'lodash';
+import { keysDeep, template } from '@strapi/utils';
-const _ = require('lodash');
-const {
- template: { createStrictInterpolationRegExp },
- keysDeep,
-} = require('@strapi/utils');
+import type {
+ EmailConfig,
+ EmailOptions,
+ EmailTemplate,
+ EmailTemplateData,
+ SendOptions,
+} from '../types';
-const getProviderSettings = () => {
- return strapi.config.get('plugin.email');
-};
+const { createStrictInterpolationRegExp } = template;
-const send = async (options) => {
- return strapi.plugin('email').provider.send(options);
-};
+const getProviderSettings = (): EmailConfig => strapi.config.get('plugin.email');
+
+const send = async (options: SendOptions) => strapi.plugin('email').provider.send(options);
/**
* fill subject, text and html using lodash template
@@ -21,9 +22,14 @@ const send = async (options) => {
* @param {object} data - data used to fill the template
* @returns {{ subject, text, subject }}
*/
-const sendTemplatedEmail = (emailOptions = {}, emailTemplate = {}, data = {}) => {
+const sendTemplatedEmail = (
+ emailOptions: EmailOptions,
+ emailTemplate: EmailTemplate,
+ data: EmailTemplateData
+) => {
const attributes = ['subject', 'text', 'html'];
const missingAttributes = _.difference(attributes, Object.keys(emailTemplate));
+
if (missingAttributes.length > 0) {
throw new Error(
`Following attributes are missing from your email template : ${missingAttributes.join(', ')}`
@@ -39,8 +45,6 @@ const sendTemplatedEmail = (emailOptions = {}, emailTemplate = {}, data = {}) =>
? Object.assign(compiled, {
[attribute]: _.template(emailTemplate[attribute], {
interpolate,
- evaluate: false,
- escape: false,
})(data),
})
: compiled,
@@ -50,8 +54,10 @@ const sendTemplatedEmail = (emailOptions = {}, emailTemplate = {}, data = {}) =>
return strapi.plugin('email').provider.send({ ...emailOptions, ...templatedAttributes });
};
-module.exports = () => ({
+const emailService = () => ({
getProviderSettings,
send,
sendTemplatedEmail,
});
+
+export default emailService;
diff --git a/packages/core/email/server/src/services/index.ts b/packages/core/email/server/src/services/index.ts
new file mode 100644
index 0000000000..535c46e0a2
--- /dev/null
+++ b/packages/core/email/server/src/services/index.ts
@@ -0,0 +1,3 @@
+import email from './email';
+
+export const services = { email };
diff --git a/packages/core/email/server/src/types.ts b/packages/core/email/server/src/types.ts
new file mode 100644
index 0000000000..c00cddf2b6
--- /dev/null
+++ b/packages/core/email/server/src/types.ts
@@ -0,0 +1,43 @@
+import type { Plugin } from '@strapi/types';
+
+export interface EmailConfig extends Record {
+ provider: string;
+ providerOptions?: object;
+ settings?: {
+ defaultFrom?: string;
+ };
+}
+
+type LoadedPluginConfig = Plugin.LoadedPlugin['config'];
+
+export interface StrapiConfig extends LoadedPluginConfig {
+ default: EmailConfig;
+}
+
+export interface EmailTemplateData {
+ url?: string;
+ user?: {
+ email: string;
+ firstname: string;
+ lastname: string;
+ username: string;
+ };
+}
+
+export interface EmailOptions {
+ from?: string;
+ to: string;
+ cc?: string;
+ bcc?: string;
+ replyTo?: string;
+ [key: string]: string | undefined; // to allow additional template attributes if needed
+}
+
+export interface EmailTemplate {
+ subject: string;
+ text: string;
+ html?: string;
+ [key: string]: string | undefined; // to allow additional template attributes if needed
+}
+
+export type SendOptions = EmailOptions & EmailTemplate;
diff --git a/packages/core/email/server/tsconfig.build.json b/packages/core/email/server/tsconfig.build.json
new file mode 100644
index 0000000000..49d94a869f
--- /dev/null
+++ b/packages/core/email/server/tsconfig.build.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["./src"],
+ "exclude": ["./src/**/*.test.ts"],
+ "compilerOptions": {
+ "rootDir": "./src",
+ "outDir": "./dist/server"
+ }
+}
diff --git a/packages/plugins/color-picker/admin/tsconfig.eslint.json b/packages/core/email/server/tsconfig.eslint.json
similarity index 65%
rename from packages/plugins/color-picker/admin/tsconfig.eslint.json
rename to packages/core/email/server/tsconfig.eslint.json
index 9b62409191..b531808514 100644
--- a/packages/plugins/color-picker/admin/tsconfig.eslint.json
+++ b/packages/core/email/server/tsconfig.eslint.json
@@ -1,5 +1,8 @@
{
"extends": "./tsconfig.json",
+ "compilerOptions": {
+ "noEmit": true
+ },
"include": ["src"],
"exclude": ["node_modules"]
}
diff --git a/packages/core/email/server/tsconfig.json b/packages/core/email/server/tsconfig.json
new file mode 100644
index 0000000000..9cf449b4cd
--- /dev/null
+++ b/packages/core/email/server/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "tsconfig/base.json",
+ "include": ["src"],
+ "exclude": ["node_modules"],
+ "compilerOptions": {
+ "esModuleInterop": true
+ },
+}
diff --git a/packages/core/email/shared/types.ts b/packages/core/email/shared/types.ts
new file mode 100644
index 0000000000..2beb7e1111
--- /dev/null
+++ b/packages/core/email/shared/types.ts
@@ -0,0 +1,11 @@
+export interface EmailSettings {
+ config: ConfigSettings;
+}
+
+export interface ConfigSettings {
+ provider: string;
+ settings: {
+ defaultFrom: string;
+ defaultReplyTo: string;
+ };
+}
diff --git a/packages/core/email/strapi-admin.js b/packages/core/email/strapi-admin.js
deleted file mode 100644
index 2d1a3d93ac..0000000000
--- a/packages/core/email/strapi-admin.js
+++ /dev/null
@@ -1,3 +0,0 @@
-'use strict';
-
-module.exports = require('./admin/src').default;
diff --git a/packages/core/email/strapi-server.js b/packages/core/email/strapi-server.js
index 08262d070a..bf55958861 100644
--- a/packages/core/email/strapi-server.js
+++ b/packages/core/email/strapi-server.js
@@ -1,17 +1,3 @@
'use strict';
-const bootstrap = require('./server/bootstrap');
-const services = require('./server/services');
-const routes = require('./server/routes');
-const controllers = require('./server/controllers');
-const config = require('./server/config');
-
-module.exports = () => {
- return {
- bootstrap,
- config,
- routes,
- controllers,
- services,
- };
-};
+module.exports = require('./dist/server');
diff --git a/packages/core/email/tsconfig.build.json b/packages/core/email/tsconfig.build.json
new file mode 100644
index 0000000000..e1a56f65d3
--- /dev/null
+++ b/packages/core/email/tsconfig.build.json
@@ -0,0 +1,8 @@
+{
+ "extends": "tsconfig/client.json",
+ "include": ["./admin", "./shared", "./server"],
+ "compilerOptions": {
+ "declarationDir": "./dist",
+ "outDir": "./dist"
+ }
+}
diff --git a/packages/core/helper-plugin/src/components/CheckPagePermissions.tsx b/packages/core/helper-plugin/src/components/CheckPagePermissions.tsx
index 6802ecfc73..4c0f7ea417 100644
--- a/packages/core/helper-plugin/src/components/CheckPagePermissions.tsx
+++ b/packages/core/helper-plugin/src/components/CheckPagePermissions.tsx
@@ -12,12 +12,15 @@ import type { domain } from '@strapi/permissions';
type Permission = domain.permission.Permission;
-export interface CheckPagePermissions {
+export interface CheckPagePermissionsProps {
children: React.ReactNode;
permissions?: Permission[];
}
-const CheckPagePermissions = ({ permissions = [], children }: CheckPagePermissions) => {
+const CheckPagePermissions = ({
+ permissions = [],
+ children,
+}: CheckPagePermissionsProps): React.JSX.Element => {
const abortController = new AbortController();
const { signal } = abortController;
const { allPermissions } = useRBACProvider();
@@ -73,7 +76,7 @@ const CheckPagePermissions = ({ permissions = [], children }: CheckPagePermissio
return ;
}
- return children;
+ return <>{children}>;
};
export { CheckPagePermissions };
diff --git a/packages/core/helper-plugin/src/components/CheckPermissions.tsx b/packages/core/helper-plugin/src/components/CheckPermissions.tsx
index 8fb9bf1cde..f2d294237d 100644
--- a/packages/core/helper-plugin/src/components/CheckPermissions.tsx
+++ b/packages/core/helper-plugin/src/components/CheckPermissions.tsx
@@ -11,12 +11,12 @@ type Permission = domain.permission.Permission;
// NOTE: this component is very similar to the CheckPagePermissions
// except that it does not handle redirections nor loading state
-export interface CheckPagePermissions {
+export interface CheckPermissionsProps {
children: React.ReactNode;
permissions?: Permission[];
}
-const CheckPermissions = ({ permissions = [], children }: CheckPagePermissions) => {
+const CheckPermissions = ({ permissions = [], children }: CheckPermissionsProps) => {
const { allPermissions } = useRBACProvider();
const toggleNotification = useNotification();
const [state, setState] = React.useState({ isLoading: true, canAccess: false });
@@ -69,7 +69,7 @@ const CheckPermissions = ({ permissions = [], children }: CheckPagePermissions)
return null;
}
- return children;
+ return <>{children}>;
};
export { CheckPermissions };
diff --git a/packages/core/strapi/src/core/loaders/plugins/index.ts b/packages/core/strapi/src/core/loaders/plugins/index.ts
index 6bed582b54..e380045ca7 100644
--- a/packages/core/strapi/src/core/loaders/plugins/index.ts
+++ b/packages/core/strapi/src/core/loaders/plugins/index.ts
@@ -2,30 +2,14 @@ import { join } from 'path';
import fse from 'fs-extra';
import { defaultsDeep, defaults, getOr, get } from 'lodash/fp';
import { env } from '@strapi/utils';
-import type { Strapi, Common, Schema } from '@strapi/types';
+import type { Strapi, Plugin } from '@strapi/types';
import { loadFile } from '../../app-configuration/load-config-file';
import loadFiles from '../../../load/load-files';
import { getEnabledPlugins } from './get-enabled-plugins';
import { getUserPluginsConfig } from './get-user-plugins-config';
-type LoadedPlugin = {
- config: {
- default: Record | ((opts: { env: typeof env }) => Record);
- validator: (config: Record) => void;
- };
- bootstrap: ({ strapi }: { strapi: Strapi }) => void | Promise;
- destroy: ({ strapi }: { strapi: Strapi }) => void | Promise;
- register: ({ strapi }: { strapi: Strapi }) => void | Promise;
- routes: Record;
- controllers: Record;
- services: Record;
- policies: Record;
- middlewares: Record;
- contentTypes: Record;
-};
-
interface Plugins {
- [key: string]: LoadedPlugin;
+ [key: string]: Plugin.LoadedPlugin;
}
const defaultPlugin = {
diff --git a/packages/core/types/src/types/core/plugins/config/strapi-admin/index.ts b/packages/core/types/src/types/core/plugins/config/strapi-admin/index.ts
index 95eabab9ff..38953eb3b0 100644
--- a/packages/core/types/src/types/core/plugins/config/strapi-admin/index.ts
+++ b/packages/core/types/src/types/core/plugins/config/strapi-admin/index.ts
@@ -3,5 +3,5 @@
export interface AdminInput {
register: unknown;
bootstrap: unknown;
- registerTrads: unknown;
+ registerTrads: ({ locales }: { locales: string[] }) => Promise;
}
diff --git a/packages/core/types/src/types/core/plugins/config/strapi-server/config.ts b/packages/core/types/src/types/core/plugins/config/strapi-server/config.ts
index f7f8ae9075..027c0bc48b 100644
--- a/packages/core/types/src/types/core/plugins/config/strapi-server/config.ts
+++ b/packages/core/types/src/types/core/plugins/config/strapi-server/config.ts
@@ -1,4 +1,6 @@
+import { env } from '@strapi/utils';
+
export interface Config {
- validator: () => unknown;
- default: object | (() => object);
+ validator: (config: Record) => void;
+ default: Record | ((opts: { env: typeof env }) => Record);
}
diff --git a/packages/core/types/src/types/core/plugins/index.ts b/packages/core/types/src/types/core/plugins/index.ts
index cb1ab1deb7..03151d13cb 100644
--- a/packages/core/types/src/types/core/plugins/index.ts
+++ b/packages/core/types/src/types/core/plugins/index.ts
@@ -1,4 +1,7 @@
-import type { Common, Shared, Utils } from '../..';
+import { env } from '@strapi/utils';
+
+import type { Common, Shared, Utils, Schema } from '../..';
+import type { Strapi } from '../../..';
export type IsEnabled<
TName extends keyof any,
@@ -15,4 +18,20 @@ export type IsEnabled<
: false
: false;
+export type LoadedPlugin = {
+ config: {
+ default: Record | ((opts: { env: typeof env }) => Record);
+ validator: (config: Record) => void;
+ };
+ bootstrap: ({ strapi }: { strapi: Strapi }) => void | Promise;
+ destroy: ({ strapi }: { strapi: Strapi }) => void | Promise;
+ register: ({ strapi }: { strapi: Strapi }) => void | Promise;
+ routes: Record;
+ controllers: Record;
+ services: Record;
+ policies: Record;
+ middlewares: Record;
+ contentTypes: Record;
+};
+
export * as Config from './config';
diff --git a/yarn.lock b/yarn.lock
index 7daa6b73f3..5013280f4f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7934,9 +7934,14 @@ __metadata:
"@strapi/design-system": 1.12.0
"@strapi/helper-plugin": 4.14.4
"@strapi/icons": 1.12.0
+ "@strapi/pack-up": "workspace:*"
"@strapi/provider-email-sendmail": 4.14.4
+ "@strapi/types": "workspace:*"
"@strapi/utils": 4.14.4
"@testing-library/react": 14.0.0
+ "@types/koa": 2.13.4
+ "@types/lodash": ^4.14.191
+ koa: 2.13.4
lodash: 4.17.21
msw: 1.3.0
prop-types: ^15.8.1
@@ -7948,6 +7953,7 @@ __metadata:
styled-components: 5.3.3
yup: 0.32.9
peerDependencies:
+ koa: 2.13.4
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
react-router-dom: 5.3.4