@strapi/strapi 4.0.0-next.9 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +12 -12
  2. package/bin/strapi.js +32 -5
  3. package/lib/Strapi.js +140 -72
  4. package/lib/commands/build.js +16 -6
  5. package/lib/commands/console.js +1 -1
  6. package/lib/commands/content-types/list.js +22 -0
  7. package/lib/commands/develop.js +14 -15
  8. package/lib/commands/generate-template.js +4 -5
  9. package/lib/commands/hooks/list.js +22 -0
  10. package/lib/commands/middlewares/list.js +22 -0
  11. package/lib/commands/new.js +3 -1
  12. package/lib/commands/policies/list.js +22 -0
  13. package/lib/commands/routes/list.js +28 -0
  14. package/lib/commands/services/list.js +22 -0
  15. package/lib/commands/watchAdmin.js +18 -9
  16. package/lib/core/app-configuration/index.js +3 -19
  17. package/lib/core/bootstrap.js +3 -34
  18. package/lib/core/domain/content-type/index.js +3 -7
  19. package/lib/core/domain/module/index.js +8 -6
  20. package/lib/core/domain/module/validation.js +1 -4
  21. package/lib/core/loaders/admin.js +2 -2
  22. package/lib/core/loaders/apis.js +7 -7
  23. package/lib/core/loaders/components.js +3 -5
  24. package/lib/core/loaders/index.js +1 -0
  25. package/lib/core/loaders/middlewares.js +23 -123
  26. package/lib/core/loaders/plugins/get-enabled-plugins.js +48 -14
  27. package/lib/core/loaders/plugins/index.js +30 -14
  28. package/lib/core/loaders/policies.js +1 -1
  29. package/lib/core/loaders/src-index.js +39 -0
  30. package/lib/core/registries/apis.js +2 -16
  31. package/lib/core/registries/content-types.js +50 -6
  32. package/lib/core/registries/controllers.d.ts +7 -0
  33. package/lib/core/registries/controllers.js +74 -3
  34. package/lib/core/registries/hooks.d.ts +20 -0
  35. package/lib/core/registries/hooks.js +87 -0
  36. package/lib/core/registries/middlewares.d.ts +5 -0
  37. package/lib/core/registries/middlewares.js +61 -2
  38. package/lib/core/registries/modules.js +3 -3
  39. package/lib/core/registries/plugins.js +2 -2
  40. package/lib/core/registries/policies.d.ts +9 -0
  41. package/lib/core/registries/policies.js +57 -6
  42. package/lib/core/registries/services.d.ts +7 -0
  43. package/lib/core/registries/services.js +71 -15
  44. package/lib/core-api/controller/collection-type.js +38 -11
  45. package/lib/core-api/controller/index.d.ts +25 -0
  46. package/lib/core-api/controller/index.js +30 -11
  47. package/lib/core-api/controller/single-type.js +26 -7
  48. package/lib/core-api/controller/transform.js +28 -3
  49. package/lib/core-api/routes/index.js +71 -0
  50. package/lib/core-api/service/collection-type.js +22 -27
  51. package/lib/core-api/service/index.d.ts +21 -0
  52. package/lib/core-api/service/index.js +9 -19
  53. package/lib/core-api/service/pagination.js +7 -2
  54. package/lib/core-api/service/single-type.js +17 -20
  55. package/lib/factories.d.ts +48 -0
  56. package/lib/factories.js +84 -0
  57. package/lib/index.d.ts +10 -31
  58. package/lib/index.js +5 -1
  59. package/lib/middlewares/body.js +33 -0
  60. package/lib/middlewares/compression.js +8 -0
  61. package/lib/middlewares/cors.js +58 -0
  62. package/lib/middlewares/errors.js +40 -0
  63. package/lib/middlewares/favicon.js +19 -0
  64. package/lib/middlewares/index.d.ts +5 -0
  65. package/lib/middlewares/index.js +30 -116
  66. package/lib/middlewares/ip.js +8 -0
  67. package/lib/middlewares/logger.js +27 -0
  68. package/lib/middlewares/powered-by.js +20 -0
  69. package/lib/middlewares/public/index.js +98 -73
  70. package/lib/middlewares/query.js +46 -0
  71. package/lib/middlewares/response-time.js +15 -0
  72. package/lib/middlewares/responses.js +19 -0
  73. package/lib/middlewares/security.js +51 -0
  74. package/lib/middlewares/session/index.js +6 -6
  75. package/lib/migrations/draft-publish.js +57 -0
  76. package/lib/services/auth/index.js +87 -0
  77. package/lib/services/core-store.js +64 -49
  78. package/lib/services/cron.js +54 -0
  79. package/lib/services/entity-service/attributes/index.js +31 -0
  80. package/lib/services/entity-service/attributes/transforms.js +20 -0
  81. package/lib/services/entity-service/components.js +39 -15
  82. package/lib/services/entity-service/index.d.ts +91 -0
  83. package/lib/services/entity-service/index.js +118 -60
  84. package/lib/services/entity-service/params.js +48 -81
  85. package/lib/services/entity-validator/index.js +76 -43
  86. package/lib/services/entity-validator/validators.js +129 -43
  87. package/lib/services/errors.js +77 -0
  88. package/lib/services/fs.js +1 -1
  89. package/lib/services/metrics/index.js +38 -36
  90. package/lib/services/server/admin-api.js +14 -0
  91. package/lib/services/server/api.js +36 -0
  92. package/lib/services/server/compose-endpoint.js +141 -0
  93. package/lib/services/server/content-api.js +16 -0
  94. package/lib/{server.js → services/server/http-server.js} +0 -0
  95. package/lib/services/server/index.js +127 -0
  96. package/lib/services/server/koa.js +64 -0
  97. package/lib/services/server/middleware.js +122 -0
  98. package/lib/services/server/policy.js +32 -0
  99. package/lib/services/server/register-middlewares.js +110 -0
  100. package/lib/services/server/register-routes.js +106 -0
  101. package/lib/services/server/routing.js +120 -0
  102. package/lib/services/webhook-runner.js +1 -1
  103. package/lib/utils/ee.js +3 -3
  104. package/lib/utils/get-dirs.js +17 -0
  105. package/lib/utils/index.js +2 -0
  106. package/lib/utils/signals.js +24 -0
  107. package/lib/utils/update-notifier/index.js +2 -1
  108. package/package.json +93 -93
  109. package/lib/core/app-configuration/load-functions.js +0 -28
  110. package/lib/core-api/index.js +0 -39
  111. package/lib/middlewares/boom/defaults.json +0 -5
  112. package/lib/middlewares/boom/index.js +0 -147
  113. package/lib/middlewares/cors/index.js +0 -66
  114. package/lib/middlewares/cron/defaults.json +0 -5
  115. package/lib/middlewares/cron/index.js +0 -43
  116. package/lib/middlewares/favicon/defaults.json +0 -7
  117. package/lib/middlewares/favicon/index.js +0 -32
  118. package/lib/middlewares/gzip/defaults.json +0 -6
  119. package/lib/middlewares/gzip/index.js +0 -19
  120. package/lib/middlewares/helmet/defaults.json +0 -18
  121. package/lib/middlewares/helmet/index.js +0 -9
  122. package/lib/middlewares/ip/defaults.json +0 -7
  123. package/lib/middlewares/ip/index.js +0 -25
  124. package/lib/middlewares/language/defaults.json +0 -9
  125. package/lib/middlewares/language/index.js +0 -40
  126. package/lib/middlewares/logger/defaults.json +0 -5
  127. package/lib/middlewares/logger/index.js +0 -37
  128. package/lib/middlewares/parser/defaults.json +0 -11
  129. package/lib/middlewares/parser/index.js +0 -72
  130. package/lib/middlewares/poweredBy/defaults.json +0 -5
  131. package/lib/middlewares/poweredBy/index.js +0 -16
  132. package/lib/middlewares/public/defaults.json +0 -8
  133. package/lib/middlewares/responseTime/defaults.json +0 -5
  134. package/lib/middlewares/responseTime/index.js +0 -25
  135. package/lib/middlewares/responses/defaults.json +0 -5
  136. package/lib/middlewares/responses/index.js +0 -18
  137. package/lib/middlewares/router/defaults.json +0 -7
  138. package/lib/middlewares/router/index.js +0 -72
  139. package/lib/middlewares/router/utils/compose-endpoint.js +0 -169
  140. package/lib/utils/get-prefixed-dependencies.js +0 -7
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ const Router = require('@koa/router');
4
+
5
+ const { createRouteManager } = require('./routing');
6
+
7
+ const createAPI = (strapi, opts = {}) => {
8
+ const { prefix, type } = opts;
9
+
10
+ const api = new Router({ prefix });
11
+
12
+ const routeManager = createRouteManager(strapi, { type });
13
+
14
+ return {
15
+ listRoutes() {
16
+ return [...api.stack];
17
+ },
18
+
19
+ use(fn) {
20
+ api.use(fn);
21
+ return this;
22
+ },
23
+
24
+ routes(routes) {
25
+ routeManager.addRoutes(routes, api);
26
+ return this;
27
+ },
28
+
29
+ mount(router) {
30
+ router.use(api.routes(), api.allowedMethods());
31
+ return this;
32
+ },
33
+ };
34
+ };
35
+
36
+ module.exports = { createAPI };
@@ -0,0 +1,141 @@
1
+ 'use strict';
2
+
3
+ const { has, toLower, castArray, trim, prop, isNil } = require('lodash/fp');
4
+ const { UnauthorizedError, ForbiddenError } = require('@strapi/utils').errors;
5
+
6
+ const compose = require('koa-compose');
7
+ const { resolveRouteMiddlewares } = require('./middleware');
8
+ const { resolvePolicies } = require('./policy');
9
+
10
+ const getMethod = route => trim(toLower(route.method));
11
+ const getPath = route => trim(route.path);
12
+
13
+ const createRouteInfoMiddleware = routeInfo => (ctx, next) => {
14
+ const route = {
15
+ ...routeInfo,
16
+ config: routeInfo.config || {},
17
+ };
18
+
19
+ ctx.state.route = route;
20
+ return next();
21
+ };
22
+
23
+ const getAuthConfig = prop('config.auth');
24
+
25
+ const createAuthorizeMiddleware = strapi => async (ctx, next) => {
26
+ const { auth, route } = ctx.state;
27
+
28
+ const authService = strapi.container.get('auth');
29
+
30
+ try {
31
+ await authService.verify(auth, getAuthConfig(route));
32
+
33
+ return next();
34
+ } catch (error) {
35
+ if (error instanceof UnauthorizedError) {
36
+ return ctx.unauthorized();
37
+ }
38
+
39
+ if (error instanceof ForbiddenError) {
40
+ return ctx.forbidden();
41
+ }
42
+
43
+ throw error;
44
+ }
45
+ };
46
+
47
+ const createAuthenticateMiddleware = strapi => async (ctx, next) => {
48
+ return strapi.container.get('auth').authenticate(ctx, next);
49
+ };
50
+
51
+ const returnBodyMiddleware = async (ctx, next) => {
52
+ const values = await next();
53
+
54
+ if (isNil(ctx.body) && !isNil(values)) {
55
+ ctx.body = values;
56
+ }
57
+ };
58
+
59
+ module.exports = strapi => {
60
+ const authenticate = createAuthenticateMiddleware(strapi);
61
+ const authorize = createAuthorizeMiddleware(strapi);
62
+
63
+ return (route, { router }) => {
64
+ try {
65
+ const method = getMethod(route);
66
+ const path = getPath(route);
67
+
68
+ const middlewares = resolveRouteMiddlewares(route, strapi);
69
+ const policies = resolvePolicies(route);
70
+
71
+ const action = getAction(route, strapi);
72
+
73
+ const routeHandler = compose([
74
+ createRouteInfoMiddleware(route),
75
+ authenticate,
76
+ authorize,
77
+ ...policies,
78
+ ...middlewares,
79
+ returnBodyMiddleware,
80
+ ...castArray(action),
81
+ ]);
82
+
83
+ router[method](path, routeHandler);
84
+ } catch (error) {
85
+ error.message = `Error creating endpoint ${route.method} ${route.path}: ${error.message}`;
86
+ throw error;
87
+ }
88
+ };
89
+ };
90
+
91
+ const getController = (name, { pluginName, apiName }, strapi) => {
92
+ let ctrl;
93
+
94
+ if (pluginName) {
95
+ if (pluginName === 'admin') {
96
+ ctrl = strapi.controller(`admin::${name}`);
97
+ } else {
98
+ ctrl = strapi.plugin(pluginName).controller(name);
99
+ }
100
+ } else if (apiName) {
101
+ ctrl = strapi.controller(`api::${apiName}.${name}`);
102
+ }
103
+
104
+ if (!ctrl) {
105
+ return strapi.controller(name);
106
+ }
107
+
108
+ return ctrl;
109
+ };
110
+
111
+ const extractHandlerParts = name => {
112
+ const controllerName = name.slice(0, name.lastIndexOf('.'));
113
+ const actionName = name.slice(name.lastIndexOf('.') + 1);
114
+
115
+ return { controllerName, actionName };
116
+ };
117
+
118
+ const getAction = (route, strapi) => {
119
+ const { handler, info = {} } = route;
120
+ const { pluginName, apiName, type } = info;
121
+
122
+ if (Array.isArray(handler) || typeof handler === 'function') {
123
+ return handler;
124
+ }
125
+
126
+ const { controllerName, actionName } = extractHandlerParts(trim(handler));
127
+
128
+ const controller = getController(controllerName, { pluginName, apiName }, strapi);
129
+
130
+ if (typeof controller[actionName] !== 'function') {
131
+ throw new Error(`Handler not found "${handler}"`);
132
+ }
133
+
134
+ if (has(Symbol.for('__type__'), controller[actionName])) {
135
+ controller[actionName][Symbol.for('__type__')].push(type);
136
+ } else {
137
+ controller[actionName][Symbol.for('__type__')] = [type];
138
+ }
139
+
140
+ return controller[actionName].bind(controller);
141
+ };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const { createAPI } = require('./api');
4
+
5
+ const createContentAPI = strapi => {
6
+ const opts = {
7
+ prefix: strapi.config.get('api.rest.prefix', '/api'),
8
+ type: 'content-api',
9
+ };
10
+
11
+ return createAPI(strapi, opts);
12
+ };
13
+
14
+ module.exports = {
15
+ createContentAPI,
16
+ };
@@ -0,0 +1,127 @@
1
+ 'use strict';
2
+
3
+ const Router = require('@koa/router');
4
+
5
+ const { createHTTPServer } = require('./http-server');
6
+ const { createRouteManager } = require('./routing');
7
+ const { createAdminAPI } = require('./admin-api');
8
+ const { createContentAPI } = require('./content-api');
9
+ const registerAllRoutes = require('./register-routes');
10
+ const registerApplicationMiddlewares = require('./register-middlewares');
11
+ const createKoaApp = require('./koa');
12
+
13
+ const healthCheck = async ctx => {
14
+ ctx.set('strapi', 'You are so French!');
15
+ ctx.status = 204;
16
+ };
17
+
18
+ /**
19
+ * @typedef Server
20
+ *
21
+ * @property {Koa} app
22
+ * @property {http.Server} app
23
+ */
24
+
25
+ /**
26
+ *
27
+ * @param {Strapi} strapi
28
+ * @returns {Server}
29
+ */
30
+ const createServer = strapi => {
31
+ const app = createKoaApp({ proxy: strapi.config.get('server.proxy') });
32
+
33
+ const router = new Router();
34
+
35
+ const routeManager = createRouteManager(strapi);
36
+
37
+ const httpServer = createHTTPServer(strapi, app);
38
+
39
+ const apis = {
40
+ 'content-api': createContentAPI(strapi),
41
+ admin: createAdminAPI(strapi),
42
+ };
43
+
44
+ // init health check
45
+ router.all('/_health', healthCheck);
46
+
47
+ const state = {
48
+ mounted: false,
49
+ };
50
+
51
+ return {
52
+ app,
53
+ router,
54
+ httpServer,
55
+
56
+ api(name) {
57
+ return apis[name];
58
+ },
59
+
60
+ use(...args) {
61
+ app.use(...args);
62
+ return this;
63
+ },
64
+
65
+ routes(routes) {
66
+ if (routes.type) {
67
+ const api = apis[routes.type];
68
+ if (!api) {
69
+ throw new Error(`API ${routes.type} not found. Possible APIs are ${Object.keys(apis)}`);
70
+ }
71
+
72
+ apis[routes.type].routes(routes);
73
+ return this;
74
+ }
75
+
76
+ routeManager.addRoutes(routes, router);
77
+ return this;
78
+ },
79
+
80
+ mount() {
81
+ state.mounted = true;
82
+
83
+ Object.values(apis).forEach(api => api.mount(router));
84
+ app.use(router.routes()).use(router.allowedMethods());
85
+
86
+ return this;
87
+ },
88
+
89
+ async initRouting() {
90
+ await registerAllRoutes(strapi);
91
+
92
+ return this;
93
+ },
94
+
95
+ async initMiddlewares() {
96
+ await registerApplicationMiddlewares(strapi);
97
+
98
+ return this;
99
+ },
100
+
101
+ listRoutes() {
102
+ const allRoutes = [...router.stack];
103
+
104
+ Object.values(apis).forEach(api => {
105
+ allRoutes.push(...api.listRoutes());
106
+ });
107
+
108
+ return allRoutes;
109
+ },
110
+
111
+ listen(...args) {
112
+ if (!state.mounted) {
113
+ this.mount();
114
+ }
115
+
116
+ return httpServer.listen(...args);
117
+ },
118
+
119
+ async destroy() {
120
+ await httpServer.destroy();
121
+ },
122
+ };
123
+ };
124
+
125
+ module.exports = {
126
+ createServer,
127
+ };
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+
3
+ const { isNil, camelCase } = require('lodash/fp');
4
+ const Koa = require('koa');
5
+ const createError = require('http-errors');
6
+ const delegate = require('delegates');
7
+ var statuses = require('statuses');
8
+ const { formatHttpError } = require('../errors');
9
+
10
+ const addCustomMethods = app => {
11
+ const delegator = delegate(app.context, 'response');
12
+
13
+ /* errors */
14
+ statuses.codes
15
+ .filter(code => code >= 400 && code < 600)
16
+ .forEach(code => {
17
+ const name = statuses(code);
18
+ const camelCasedName = camelCase(name);
19
+ app.response[camelCasedName] = function(message, details = {}) {
20
+ const httpError = createError(code, message, { details });
21
+ const { status, body } = formatHttpError(httpError);
22
+ this.status = status;
23
+ this.body = body;
24
+ };
25
+ delegator.method(camelCasedName);
26
+ });
27
+
28
+ /* send, created, deleted */
29
+ app.response.send = function(data, status = 200) {
30
+ this.status = status;
31
+ this.body = data;
32
+ };
33
+
34
+ app.response.created = function(data) {
35
+ this.status = 201;
36
+ this.body = data;
37
+ };
38
+
39
+ app.response.deleted = function(data) {
40
+ if (isNil(data)) {
41
+ this.status = 204;
42
+ } else {
43
+ this.status = 200;
44
+ this.body = data;
45
+ }
46
+ };
47
+
48
+ delegator
49
+ .method('send')
50
+ .method('created')
51
+ .method('deleted');
52
+
53
+ return app;
54
+ };
55
+
56
+ const createKoaApp = ({ proxy }) => {
57
+ const app = new Koa({ proxy });
58
+
59
+ addCustomMethods(app);
60
+
61
+ return app;
62
+ };
63
+
64
+ module.exports = createKoaApp;
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { propOr, isArray, isNil } = require('lodash/fp');
5
+
6
+ const getMiddlewareConfig = propOr([], 'config.middlewares');
7
+
8
+ const resolveRouteMiddlewares = (route, strapi) => {
9
+ const middlewaresConfig = getMiddlewareConfig(route);
10
+
11
+ if (!isArray(middlewaresConfig)) {
12
+ throw new Error('Route middlewares config must be an array');
13
+ }
14
+
15
+ const middlewares = resolveMiddlewares(middlewaresConfig, strapi);
16
+
17
+ return middlewares.map(({ handler }) => handler);
18
+ };
19
+
20
+ /**
21
+ * Initialize every configured middlewares
22
+ * @param {MiddlewaresConfig} config
23
+ * @param {Strapi} strapi
24
+ * @returns {Middlewares}
25
+ */
26
+ const resolveMiddlewares = (config, strapi) => {
27
+ const middlewares = [];
28
+
29
+ for (const item of config) {
30
+ if (typeof item === 'function') {
31
+ middlewares.push({
32
+ name: null,
33
+ handler: item,
34
+ });
35
+
36
+ continue;
37
+ }
38
+
39
+ if (typeof item === 'string') {
40
+ const middlewareFactory = strapi.middleware(item);
41
+
42
+ if (!middlewareFactory) {
43
+ throw new Error(`Middleware ${item} not found.`);
44
+ }
45
+
46
+ middlewares.push({
47
+ name: item,
48
+ handler: middlewareFactory({}, { strapi }),
49
+ });
50
+
51
+ continue;
52
+ }
53
+
54
+ if (typeof item === 'object' && item !== null) {
55
+ const { name, resolve, config = {} } = item;
56
+
57
+ if (name) {
58
+ const middlewareFactory = strapi.middleware(name);
59
+ middlewares.push({
60
+ name,
61
+ handler: middlewareFactory(config, { strapi }),
62
+ });
63
+
64
+ continue;
65
+ }
66
+
67
+ if (resolve) {
68
+ middlewares.push({
69
+ name: resolve,
70
+ handler: resolveCustomMiddleware(resolve, strapi)(config, { strapi }),
71
+ });
72
+
73
+ continue;
74
+ }
75
+
76
+ throw new Error('Invalid middleware configuration. Missing name or resolve properties.');
77
+ }
78
+
79
+ throw new Error(
80
+ 'Middleware config must either be a string or an object {name?: string, resolve?: string, config: any}.'
81
+ );
82
+ }
83
+
84
+ middlewares.forEach(middleware => {
85
+ // NOTE: we replace null middlewares by a dumb one to avoid having to filter later on
86
+ if (isNil(middleware.handler)) {
87
+ middleware.handler = (_, next) => next();
88
+ }
89
+ });
90
+
91
+ return middlewares;
92
+ };
93
+
94
+ /**
95
+ * Resolve middleware from package name or path
96
+ * @param {string} resolve
97
+ * @param {Strapi} strapi
98
+ */
99
+ const resolveCustomMiddleware = (resolve, strapi) => {
100
+ let modulePath;
101
+
102
+ try {
103
+ modulePath = require.resolve(resolve);
104
+ } catch (error) {
105
+ if (error.code === 'MODULE_NOT_FOUND') {
106
+ modulePath = path.resolve(strapi.dirs.root, resolve);
107
+ } else {
108
+ throw error;
109
+ }
110
+ }
111
+
112
+ try {
113
+ return require(modulePath);
114
+ } catch (err) {
115
+ throw new Error(`Could not load middleware "${modulePath}".`);
116
+ }
117
+ };
118
+
119
+ module.exports = {
120
+ resolveRouteMiddlewares,
121
+ resolveMiddlewares,
122
+ };
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ const { propOr } = require('lodash/fp');
4
+ const { ForbiddenError } = require('@strapi/utils').errors;
5
+ const { policy: policyUtils } = require('@strapi/utils');
6
+
7
+ const getPoliciesConfig = propOr([], 'config.policies');
8
+
9
+ const resolvePolicies = route => {
10
+ const policiesConfig = getPoliciesConfig(route);
11
+ const resolvedPolicies = policyUtils.resolve(policiesConfig, route.info);
12
+
13
+ const policiesMiddleware = async (ctx, next) => {
14
+ const context = policyUtils.createPolicyContext('koa', ctx);
15
+
16
+ for (const { handler, config } of resolvedPolicies) {
17
+ const result = await handler(context, config, { strapi });
18
+
19
+ if (![true, undefined].includes(result)) {
20
+ throw new ForbiddenError('Policies failed.');
21
+ }
22
+ }
23
+
24
+ await next();
25
+ };
26
+
27
+ return [policiesMiddleware];
28
+ };
29
+
30
+ module.exports = {
31
+ resolvePolicies,
32
+ };
@@ -0,0 +1,110 @@
1
+ 'use strict';
2
+
3
+ const { yup } = require('@strapi/utils');
4
+
5
+ const { resolveMiddlewares } = require('./middleware');
6
+
7
+ /**
8
+ * @typedef {import('../../').Strapi} Strapi
9
+ * @typedef {Array<string|{name?: string, resolve?: string, config: any}>} MiddlewaresConfig
10
+ * @typedef {Array<{name: string, hanlder: Function}>} Middlewares
11
+ */
12
+
13
+ const defaultConfig = [
14
+ 'strapi::errors',
15
+ 'strapi::security',
16
+ 'strapi::cors',
17
+ 'strapi::poweredBy',
18
+ 'strapi::logger',
19
+ 'strapi::query',
20
+ 'strapi::body',
21
+ 'strapi::favicon',
22
+ 'strapi::public',
23
+ ];
24
+
25
+ const requiredMiddlewares = [
26
+ 'strapi::errors',
27
+ 'strapi::security',
28
+ 'strapi::cors',
29
+ 'strapi::query',
30
+ 'strapi::body',
31
+ 'strapi::public',
32
+ 'strapi::favicon',
33
+ ];
34
+
35
+ const middlewareConfigSchema = yup.array().of(
36
+ yup.lazy(value => {
37
+ if (typeof value === 'string') {
38
+ return yup.string().required();
39
+ }
40
+
41
+ if (typeof value === 'object') {
42
+ return yup
43
+ .object({
44
+ name: yup.string(),
45
+ resolve: yup.string(),
46
+ config: yup.mixed(),
47
+ })
48
+ .required()
49
+ .noUnknown();
50
+ }
51
+
52
+ return yup.test(() => false);
53
+ })
54
+ );
55
+
56
+ /**
57
+ * Register middlewares in router
58
+ * @param {Strapi} strapi
59
+ */
60
+ const registerApplicationMiddlewares = async strapi => {
61
+ const middlewareConfig = strapi.config.get('middlewares', defaultConfig);
62
+
63
+ await validateMiddlewareConfig(middlewareConfig);
64
+
65
+ const middlewares = await resolveMiddlewares(middlewareConfig, strapi);
66
+
67
+ checkRequiredMiddlewares(middlewares);
68
+
69
+ // NOTE: exclude middlewares that return nothing.
70
+ // this is used for middlewares that only extend the app only need to be added in certain conditions
71
+ for (const middleware of middlewares) {
72
+ strapi.server.use(middleware.handler);
73
+ }
74
+ };
75
+
76
+ /**
77
+ *
78
+ * @param {MiddlewaresConfig} config
79
+ */
80
+ const validateMiddlewareConfig = async config => {
81
+ try {
82
+ await middlewareConfigSchema.validate(config, { strict: true, abortEarly: false });
83
+ } catch (error) {
84
+ throw new Error(
85
+ 'Invalid middleware configuration. Expected Array<string|{name?: string, resolve?: string, config: any}.'
86
+ );
87
+ }
88
+ };
89
+
90
+ /**
91
+ * Check if some required middlewares are missing in configure middlewares
92
+ * @param {Middlewares} middlewares
93
+ */
94
+ const checkRequiredMiddlewares = middlewares => {
95
+ const missingMiddlewares = requiredMiddlewares.filter(name => {
96
+ return middlewares.findIndex(mdl => mdl.name === name) === -1;
97
+ });
98
+
99
+ if (missingMiddlewares.length > 0) {
100
+ throw new Error(
101
+ `Missing required middlewares in configuration. Add the following middlewares: "${missingMiddlewares.join(
102
+ ', '
103
+ )}".`
104
+ );
105
+ }
106
+
107
+ return;
108
+ };
109
+
110
+ module.exports = registerApplicationMiddlewares;