@strapi/strapi 4.0.0-next.8 → 4.0.2

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 (147) hide show
  1. package/README.md +14 -14
  2. package/bin/strapi.js +46 -60
  3. package/lib/Strapi.js +152 -74
  4. package/lib/commands/build.js +19 -8
  5. package/lib/commands/console.js +1 -1
  6. package/lib/commands/content-types/list.js +22 -0
  7. package/lib/commands/controllers/list.js +22 -0
  8. package/lib/commands/develop.js +22 -27
  9. package/lib/commands/generate-template.js +4 -5
  10. package/lib/commands/hooks/list.js +22 -0
  11. package/lib/commands/middlewares/list.js +22 -0
  12. package/lib/commands/new.js +3 -1
  13. package/lib/commands/policies/list.js +22 -0
  14. package/lib/commands/routes/list.js +28 -0
  15. package/lib/commands/services/list.js +22 -0
  16. package/lib/commands/watchAdmin.js +18 -9
  17. package/lib/core/app-configuration/index.js +3 -19
  18. package/lib/core/bootstrap.js +3 -95
  19. package/lib/core/domain/content-type/index.js +5 -11
  20. package/lib/core/domain/module/index.js +42 -11
  21. package/lib/core/domain/module/validation.js +16 -19
  22. package/lib/core/loaders/admin.js +2 -2
  23. package/lib/core/loaders/apis.js +148 -9
  24. package/lib/core/loaders/components.js +4 -6
  25. package/lib/core/loaders/index.js +1 -0
  26. package/lib/core/loaders/middlewares.js +23 -123
  27. package/lib/core/loaders/plugins/get-enabled-plugins.js +55 -19
  28. package/lib/core/loaders/plugins/get-user-plugins-config.js +37 -0
  29. package/lib/core/loaders/plugins/index.js +30 -16
  30. package/lib/core/loaders/policies.js +1 -1
  31. package/lib/core/loaders/src-index.js +39 -0
  32. package/lib/core/registries/apis.js +29 -0
  33. package/lib/core/registries/content-types.js +61 -12
  34. package/lib/core/registries/controllers.d.ts +7 -0
  35. package/lib/core/registries/controllers.js +91 -7
  36. package/lib/core/registries/hooks.d.ts +20 -0
  37. package/lib/core/registries/hooks.js +87 -0
  38. package/lib/core/registries/middlewares.d.ts +5 -0
  39. package/lib/core/registries/middlewares.js +64 -5
  40. package/lib/core/registries/modules.js +3 -3
  41. package/lib/core/registries/plugins.js +2 -2
  42. package/lib/core/registries/policies.d.ts +9 -0
  43. package/lib/core/registries/policies.js +64 -5
  44. package/lib/core/registries/services.d.ts +7 -0
  45. package/lib/core/registries/services.js +86 -17
  46. package/lib/core/utils.js +22 -0
  47. package/lib/core-api/controller/collection-type.js +45 -26
  48. package/lib/core-api/controller/index.d.ts +25 -0
  49. package/lib/core-api/controller/index.js +33 -11
  50. package/lib/core-api/controller/single-type.js +29 -15
  51. package/lib/core-api/controller/transform.js +62 -6
  52. package/lib/core-api/routes/index.js +71 -0
  53. package/lib/core-api/service/collection-type.js +43 -21
  54. package/lib/core-api/service/index.d.ts +21 -0
  55. package/lib/core-api/service/index.js +8 -67
  56. package/lib/core-api/service/pagination.js +125 -0
  57. package/lib/core-api/service/single-type.js +17 -19
  58. package/lib/factories.d.ts +48 -0
  59. package/lib/factories.js +84 -0
  60. package/lib/index.d.ts +10 -31
  61. package/lib/index.js +5 -1
  62. package/lib/middlewares/body.js +33 -0
  63. package/lib/middlewares/compression.js +8 -0
  64. package/lib/middlewares/cors.js +58 -0
  65. package/lib/middlewares/errors.js +40 -0
  66. package/lib/middlewares/favicon.js +19 -0
  67. package/lib/middlewares/index.d.ts +5 -0
  68. package/lib/middlewares/index.js +30 -116
  69. package/lib/middlewares/ip.js +8 -0
  70. package/lib/middlewares/logger.js +27 -0
  71. package/lib/middlewares/powered-by.js +20 -0
  72. package/lib/middlewares/public/index.js +72 -77
  73. package/lib/middlewares/query.js +46 -0
  74. package/lib/middlewares/response-time.js +15 -0
  75. package/lib/middlewares/responses.js +19 -0
  76. package/lib/middlewares/security.js +51 -0
  77. package/lib/middlewares/session/index.js +6 -6
  78. package/lib/migrations/draft-publish.js +57 -0
  79. package/lib/services/auth/index.js +87 -0
  80. package/lib/services/core-store.js +64 -49
  81. package/lib/services/cron.js +54 -0
  82. package/lib/services/entity-service/attributes/index.js +31 -0
  83. package/lib/services/entity-service/attributes/transforms.js +20 -0
  84. package/lib/services/entity-service/components.js +39 -15
  85. package/lib/services/entity-service/index.d.ts +91 -0
  86. package/lib/services/entity-service/index.js +118 -60
  87. package/lib/services/entity-service/params.js +52 -94
  88. package/lib/services/entity-validator/index.js +76 -43
  89. package/lib/services/entity-validator/validators.js +131 -43
  90. package/lib/services/errors.js +77 -0
  91. package/lib/services/fs.js +1 -1
  92. package/lib/services/metrics/index.js +38 -36
  93. package/lib/services/server/admin-api.js +14 -0
  94. package/lib/services/server/api.js +36 -0
  95. package/lib/services/server/compose-endpoint.js +141 -0
  96. package/lib/services/server/content-api.js +16 -0
  97. package/lib/{server.js → services/server/http-server.js} +0 -0
  98. package/lib/services/server/index.js +127 -0
  99. package/lib/services/server/koa.js +64 -0
  100. package/lib/services/server/middleware.js +122 -0
  101. package/lib/services/server/policy.js +32 -0
  102. package/lib/services/server/register-middlewares.js +110 -0
  103. package/lib/services/server/register-routes.js +106 -0
  104. package/lib/services/server/routing.js +120 -0
  105. package/lib/services/webhook-runner.js +1 -1
  106. package/lib/utils/ee.js +3 -3
  107. package/lib/utils/get-dirs.js +17 -0
  108. package/lib/utils/index.js +2 -0
  109. package/lib/utils/signals.js +24 -0
  110. package/lib/utils/update-notifier/index.js +2 -1
  111. package/package.json +94 -97
  112. package/lib/commands/generate.js +0 -76
  113. package/lib/core/app-configuration/load-functions.js +0 -28
  114. package/lib/core-api/index.js +0 -39
  115. package/lib/load/check-reserved-filename.js +0 -10
  116. package/lib/load/load-config-files.js +0 -22
  117. package/lib/load/require-file-parse.js +0 -15
  118. package/lib/middlewares/boom/defaults.json +0 -5
  119. package/lib/middlewares/boom/index.js +0 -147
  120. package/lib/middlewares/cors/index.js +0 -66
  121. package/lib/middlewares/cron/defaults.json +0 -5
  122. package/lib/middlewares/cron/index.js +0 -43
  123. package/lib/middlewares/favicon/defaults.json +0 -7
  124. package/lib/middlewares/favicon/index.js +0 -32
  125. package/lib/middlewares/gzip/defaults.json +0 -6
  126. package/lib/middlewares/gzip/index.js +0 -19
  127. package/lib/middlewares/helmet/defaults.json +0 -18
  128. package/lib/middlewares/helmet/index.js +0 -9
  129. package/lib/middlewares/ip/defaults.json +0 -7
  130. package/lib/middlewares/ip/index.js +0 -25
  131. package/lib/middlewares/language/defaults.json +0 -9
  132. package/lib/middlewares/language/index.js +0 -40
  133. package/lib/middlewares/logger/defaults.json +0 -5
  134. package/lib/middlewares/logger/index.js +0 -37
  135. package/lib/middlewares/parser/defaults.json +0 -11
  136. package/lib/middlewares/parser/index.js +0 -71
  137. package/lib/middlewares/poweredBy/defaults.json +0 -5
  138. package/lib/middlewares/poweredBy/index.js +0 -16
  139. package/lib/middlewares/public/defaults.json +0 -8
  140. package/lib/middlewares/responseTime/defaults.json +0 -5
  141. package/lib/middlewares/responseTime/index.js +0 -25
  142. package/lib/middlewares/responses/defaults.json +0 -5
  143. package/lib/middlewares/responses/index.js +0 -18
  144. package/lib/middlewares/router/defaults.json +0 -7
  145. package/lib/middlewares/router/index.js +0 -58
  146. package/lib/middlewares/router/utils/composeEndpoint.js +0 -177
  147. package/lib/utils/get-prefixed-dependencies.js +0 -7
@@ -1,12 +1,33 @@
1
1
  'use strict';
2
2
 
3
+ const _ = require('lodash');
4
+ const { removeNamespace } = require('../../utils');
3
5
  const { validateModule } = require('./validation');
4
6
 
7
+ const uidToPath = uid => uid.replace('::', '.');
8
+
9
+ // Removes the namespace from a map with keys prefixed with a namespace
10
+ const removeNamespacedKeys = (map, namespace) => {
11
+ return _.mapKeys(map, (value, key) => removeNamespace(key, namespace));
12
+ };
13
+
14
+ const defaultModule = {
15
+ config: {},
16
+ routes: [],
17
+ controllers: {},
18
+ services: {},
19
+ contentTypes: {},
20
+ policies: {},
21
+ middlewares: {},
22
+ };
23
+
5
24
  const createModule = (namespace, rawModule, strapi) => {
25
+ _.defaults(rawModule, defaultModule);
26
+
6
27
  try {
7
28
  validateModule(rawModule);
8
29
  } catch (e) {
9
- throw new Error(`strapi-server.js is invalid for plugin ${namespace}.\n${e.errors.join('\n')}`);
30
+ throw new Error(`strapi-server.js is invalid for '${namespace}'.\n${e.errors.join('\n')}`);
10
31
  }
11
32
 
12
33
  const called = {};
@@ -16,21 +37,21 @@ const createModule = (namespace, rawModule, strapi) => {
16
37
  throw new Error(`Bootstrap for ${namespace} has already been called`);
17
38
  }
18
39
  called.bootstrap = true;
19
- await rawModule.bootstrap(strapi);
40
+ await (rawModule.bootstrap && rawModule.bootstrap({ strapi }));
20
41
  },
21
42
  async register() {
22
43
  if (called.register) {
23
44
  throw new Error(`Register for ${namespace} has already been called`);
24
45
  }
25
46
  called.register = true;
26
- await rawModule.register(strapi);
47
+ await (rawModule.register && rawModule.register({ strapi }));
27
48
  },
28
49
  async destroy() {
29
50
  if (called.destroy) {
30
51
  throw new Error(`Destroy for ${namespace} has already been called`);
31
52
  }
32
53
  called.destroy = true;
33
- await rawModule.destroy(strapi);
54
+ await (rawModule.destroy && rawModule.destroy({ strapi }));
34
55
  },
35
56
  load() {
36
57
  strapi.container.get('content-types').add(namespace, rawModule.contentTypes);
@@ -38,38 +59,48 @@ const createModule = (namespace, rawModule, strapi) => {
38
59
  strapi.container.get('policies').add(namespace, rawModule.policies);
39
60
  strapi.container.get('middlewares').add(namespace, rawModule.middlewares);
40
61
  strapi.container.get('controllers').add(namespace, rawModule.controllers);
41
- strapi.container.get('config').set(namespace.replace('::', '.'), rawModule.config);
62
+ strapi.container.get('config').set(uidToPath(namespace), rawModule.config);
63
+ },
64
+ get routes() {
65
+ return rawModule.routes;
66
+ },
67
+ config(path, defaultValue) {
68
+ return strapi.container.get('config').get(`${uidToPath(namespace)}.${path}`, defaultValue);
42
69
  },
43
- routes: rawModule.routes, // TODO: to remove v3
44
70
  contentType(ctName) {
45
71
  return strapi.container.get('content-types').get(`${namespace}.${ctName}`);
46
72
  },
47
73
  get contentTypes() {
48
- return strapi.container.get('content-types').getAll(namespace);
74
+ const contentTypes = strapi.container.get('content-types').getAll(namespace);
75
+ return removeNamespacedKeys(contentTypes, namespace);
49
76
  },
50
77
  service(serviceName) {
51
78
  return strapi.container.get('services').get(`${namespace}.${serviceName}`);
52
79
  },
53
80
  get services() {
54
- return strapi.container.get('services').getAll(namespace);
81
+ const services = strapi.container.get('services').getAll(namespace);
82
+ return removeNamespacedKeys(services, namespace);
55
83
  },
56
84
  policy(policyName) {
57
85
  return strapi.container.get('policies').get(`${namespace}.${policyName}`);
58
86
  },
59
87
  get policies() {
60
- return rawModule.policies;
88
+ const policies = strapi.container.get('policies').getAll(namespace);
89
+ return removeNamespacedKeys(policies, namespace);
61
90
  },
62
91
  middleware(middlewareName) {
63
92
  return strapi.container.get('middlewares').get(`${namespace}.${middlewareName}`);
64
93
  },
65
94
  get middlewares() {
66
- return strapi.container.get('middlewares').getAll(namespace);
95
+ const middlewares = strapi.container.get('middlewares').getAll(namespace);
96
+ return removeNamespacedKeys(middlewares, namespace);
67
97
  },
68
98
  controller(controllerName) {
69
99
  return strapi.container.get('controllers').get(`${namespace}.${controllerName}`);
70
100
  },
71
101
  get controllers() {
72
- return rawModule.controllers;
102
+ const controllers = strapi.container.get('controllers').getAll(namespace);
103
+ return removeNamespacedKeys(controllers, namespace);
73
104
  },
74
105
  };
75
106
  };
@@ -5,25 +5,22 @@ const { yup } = require('@strapi/utils');
5
5
  const strapiServerSchema = yup
6
6
  .object()
7
7
  .shape({
8
- bootstrap: yup
9
- .mixed()
10
- .isFunction()
11
- .required(),
12
- destroy: yup
13
- .mixed()
14
- .isFunction()
15
- .required(),
16
- register: yup
17
- .mixed()
18
- .isFunction()
19
- .required(),
20
- config: yup.object().required(),
21
- routes: yup.array().required(), // may be removed later
22
- controllers: yup.object().required(), // may be removed later
23
- services: yup.object().required(),
24
- policies: yup.object().required(),
25
- middlewares: yup.object().required(), // may be removed later
26
- contentTypes: yup.object().required(),
8
+ bootstrap: yup.mixed().isFunction(),
9
+ destroy: yup.mixed().isFunction(),
10
+ register: yup.mixed().isFunction(),
11
+ config: yup.object(),
12
+ routes: yup.lazy(value => {
13
+ if (Array.isArray(value)) {
14
+ return yup.array();
15
+ } else {
16
+ return yup.object();
17
+ }
18
+ }),
19
+ controllers: yup.object(),
20
+ services: yup.object(),
21
+ policies: yup.object(),
22
+ middlewares: yup.object(),
23
+ contentTypes: yup.object(),
27
24
  })
28
25
  .noUnknown();
29
26
 
@@ -11,6 +11,6 @@ module.exports = strapi => {
11
11
  strapi.container.get('policies').add(`admin::`, strapi.admin.policies);
12
12
  strapi.container.get('middlewares').add(`admin::`, strapi.admin.middlewares);
13
13
 
14
- const userAdminConfig = strapi.config.get('server.admin');
15
- strapi.container.get('config').set('server.admin', _.merge(strapi.admin.config, userAdminConfig));
14
+ const userAdminConfig = strapi.config.get('admin');
15
+ strapi.container.get('config').set('admin', _.merge(strapi.admin.config, userAdminConfig));
16
16
  };
@@ -1,20 +1,159 @@
1
1
  'use strict';
2
2
 
3
- const { join } = require('path');
3
+ const { join, extname, basename } = require('path');
4
4
  const { existsSync } = require('fs-extra');
5
5
  const _ = require('lodash');
6
- const loadFiles = require('../../load/load-files');
7
- const loadConfig = require('../../load/load-config-files');
6
+ const fse = require('fs-extra');
7
+ const { isKebabCase } = require('@strapi/utils');
8
+
9
+ // to handle names with numbers in it we first check if it is already in kebabCase
10
+ const normalizeName = name => (isKebabCase(name) ? name : _.kebabCase(name));
11
+
12
+ const DEFAULT_CONTENT_TYPE = {
13
+ schema: {},
14
+ actions: {},
15
+ lifecycles: {},
16
+ };
8
17
 
9
18
  module.exports = async strapi => {
10
- const apiDir = join(strapi.dir, 'api');
19
+ if (!existsSync(strapi.dirs.api)) {
20
+ throw new Error('Missing api folder. Please create one at `./src/api`');
21
+ }
22
+
23
+ const apisFDs = await fse.readdir(strapi.dirs.api, { withFileTypes: true });
24
+ const apis = {};
25
+
26
+ // only load folders
27
+ for (const apiFD of apisFDs) {
28
+ if (apiFD.isDirectory()) {
29
+ const apiName = normalizeName(apiFD.name);
30
+ const api = await loadAPI(join(strapi.dirs.api, apiFD.name));
31
+
32
+ apis[apiName] = api;
33
+ }
34
+ }
35
+
36
+ validateContentTypesUnicity(apis);
37
+
38
+ for (const apiName in apis) {
39
+ strapi.container.get('apis').add(apiName, apis[apiName]);
40
+ }
41
+ };
42
+
43
+ const validateContentTypesUnicity = apis => {
44
+ const allApisSchemas = Object.values(apis).flatMap(api => Object.values(api.contentTypes));
45
+
46
+ const names = [];
47
+ allApisSchemas.forEach(({ schema }) => {
48
+ if (schema.info.singularName) {
49
+ const singularName = _.kebabCase(schema.info.singularName);
50
+ if (names.includes(singularName)) {
51
+ throw new Error(`The singular name "${schema.info.singularName}" should be unique`);
52
+ }
53
+ names.push(singularName);
54
+ }
55
+
56
+ if (schema.info.pluralName) {
57
+ const pluralName = _.kebabCase(schema.info.pluralName);
58
+ if (names.includes(pluralName)) {
59
+ throw new Error(`The plural name "${schema.info.pluralName}" should be unique`);
60
+ }
61
+ names.push(pluralName);
62
+ }
63
+ });
64
+ };
65
+
66
+ const loadAPI = async dir => {
67
+ const [
68
+ index,
69
+ config,
70
+ routes,
71
+ controllers,
72
+ services,
73
+ policies,
74
+ middlewares,
75
+ contentTypes,
76
+ ] = await Promise.all([
77
+ loadIndex(dir),
78
+ loadDir(join(dir, 'config')),
79
+ loadDir(join(dir, 'routes')),
80
+ loadDir(join(dir, 'controllers')),
81
+ loadDir(join(dir, 'services')),
82
+ loadDir(join(dir, 'policies')),
83
+ loadDir(join(dir, 'middlewares')),
84
+ loadContentTypes(join(dir, 'content-types')),
85
+ ]);
86
+
87
+ return {
88
+ ...(index || {}),
89
+ config: config || {},
90
+ routes: routes || [],
91
+ controllers: controllers || {},
92
+ services: services || {},
93
+ policies: policies || {},
94
+ middlewares: middlewares || {},
95
+ contentTypes: contentTypes || {},
96
+ };
97
+ };
11
98
 
12
- if (!existsSync(apiDir)) {
13
- throw new Error(`Missing api folder. Please create one in your app root directory`);
99
+ const loadIndex = async dir => {
100
+ if (await fse.pathExists(join(dir, 'index.js'))) {
101
+ return loadFile(join(dir, 'index.js'));
14
102
  }
103
+ };
104
+
105
+ const loadContentTypes = async dir => {
106
+ if (!(await fse.pathExists(dir))) {
107
+ return;
108
+ }
109
+
110
+ const fds = await fse.readdir(dir, { withFileTypes: true });
111
+ const contentTypes = {};
112
+
113
+ // only load folders
114
+ for (const fd of fds) {
115
+ if (fd.isFile()) {
116
+ continue;
117
+ }
15
118
 
16
- const apis = await loadFiles(apiDir, '*/!(config)/**/*.*(js|json)');
17
- const apiConfigs = await loadConfig(apiDir, '*/config/**/*.*(js|json)');
119
+ const contentTypeName = normalizeName(fd.name);
120
+ const contentType = await loadDir(join(dir, fd.name));
18
121
 
19
- return _.merge(apis, apiConfigs);
122
+ contentTypes[normalizeName(contentTypeName)] = _.defaults(contentType, DEFAULT_CONTENT_TYPE);
123
+ }
124
+
125
+ return contentTypes;
126
+ };
127
+
128
+ const loadDir = async dir => {
129
+ if (!(await fse.pathExists(dir))) {
130
+ return;
131
+ }
132
+
133
+ const fds = await fse.readdir(dir, { withFileTypes: true });
134
+
135
+ const root = {};
136
+ for (const fd of fds) {
137
+ if (!fd.isFile()) {
138
+ continue;
139
+ }
140
+
141
+ const key = basename(fd.name, extname(fd.name));
142
+ root[normalizeName(key)] = await loadFile(join(dir, fd.name));
143
+ }
144
+
145
+ return root;
146
+ };
147
+
148
+ const loadFile = file => {
149
+ const ext = extname(file);
150
+
151
+ switch (ext) {
152
+ case '.js':
153
+ return require(file);
154
+ case '.json':
155
+ return fse.readJSON(file);
156
+ default:
157
+ return {};
158
+ }
20
159
  };
@@ -2,23 +2,21 @@
2
2
 
3
3
  const { join } = require('path');
4
4
  const _ = require('lodash');
5
- const { exists } = require('fs-extra');
5
+ const { pathExists } = require('fs-extra');
6
6
  const loadFiles = require('../../load/load-files');
7
7
 
8
8
  module.exports = async strapi => {
9
- const componentsDir = join(strapi.dir, 'components');
10
-
11
- if (!(await exists(componentsDir))) {
9
+ if (!(await pathExists(strapi.dirs.components))) {
12
10
  return {};
13
11
  }
14
12
 
15
- const map = await loadFiles(componentsDir, '*/*.*(js|json)');
13
+ const map = await loadFiles(strapi.dirs.components, '*/*.*(js|json)');
16
14
 
17
15
  return Object.keys(map).reduce((acc, category) => {
18
16
  Object.keys(map[category]).forEach(key => {
19
17
  const schema = map[category][key];
20
18
 
21
- const filePath = join(componentsDir, category, schema.__filename__);
19
+ const filePath = join(strapi.dirs.components, category, schema.__filename__);
22
20
 
23
21
  if (!schema.collectionName) {
24
22
  return strapi.stopWithError(
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  module.exports = {
4
+ loadSrcIndex: require('./src-index'),
4
5
  loadAPIs: require('./apis'),
5
6
  loadMiddlewares: require('./middlewares'),
6
7
  loadComponents: require('./components'),
@@ -1,136 +1,36 @@
1
1
  'use strict';
2
2
 
3
- // Dependencies.
4
- const path = require('path');
5
- const fs = require('fs-extra');
6
- const _ = require('lodash');
7
- const glob = require('../../load/glob');
8
- const findPackagePath = require('../../load/package-path');
3
+ const { join, extname, basename } = require('path');
4
+ const fse = require('fs-extra');
9
5
 
10
- /**
11
- * Load middlewares
12
- */
13
- module.exports = async function(strapi) {
14
- const installedMiddlewares = strapi.config.get('installedMiddlewares');
15
- const appPath = strapi.config.get('appPath');
6
+ // TODO:: allow folders with index.js inside for bigger policies
7
+ module.exports = async function loadMiddlewares(strapi) {
8
+ const localMiddlewares = await loadLocalMiddlewares(strapi);
9
+ const internalMiddlewares = require('../../middlewares');
16
10
 
17
- let middlewares = {};
18
-
19
- const loaders = createLoaders(strapi);
20
-
21
- await loaders.loadMiddlewareDependencies(installedMiddlewares, middlewares);
22
- // internal middlewares
23
- await loaders.loadInternalMiddlewares(middlewares);
24
- // local middleware
25
- await loaders.loadLocalMiddlewares(appPath, middlewares);
26
- // plugins middlewares
27
- await loaders.loadPluginsMiddlewares(strapi.plugins, middlewares);
28
- // local plugin middlewares
29
- await loaders.loadLocalPluginsMiddlewares(appPath, middlewares);
30
- // load admin middlewares
31
- await loaders.loadAdminMiddlewares(middlewares);
32
-
33
- return middlewares;
11
+ strapi.container.get('middlewares').add(`global::`, localMiddlewares);
12
+ strapi.container.get('middlewares').add(`strapi::`, internalMiddlewares);
34
13
  };
35
14
 
36
- /**
37
- * Build loader functions
38
- * @param {*} strapi - strapi instance
39
- */
40
- const createLoaders = strapi => {
41
- const loadMiddlewaresInDir = async (dir, middlewares) => {
42
- const files = await glob('*/*(index|defaults).*(js|json)', {
43
- cwd: dir,
44
- });
45
-
46
- files.forEach(f => {
47
- const name = f.split('/')[0];
48
- mountMiddleware(name, [path.resolve(dir, f)], middlewares);
49
- });
50
- };
15
+ const loadLocalMiddlewares = async strapi => {
16
+ const dir = strapi.dirs.middlewares;
51
17
 
52
- const loadInternalMiddlewares = middlewares =>
53
- loadMiddlewaresInDir(path.resolve(__dirname, '..', '..', 'middlewares'), middlewares);
18
+ if (!(await fse.pathExists(dir))) {
19
+ return {};
20
+ }
54
21
 
55
- const loadLocalMiddlewares = (appPath, middlewares) =>
56
- loadMiddlewaresInDir(path.resolve(appPath, 'middlewares'), middlewares);
22
+ const middlewares = {};
23
+ const paths = await fse.readdir(dir, { withFileTypes: true });
57
24
 
58
- const loadPluginsMiddlewares = async (plugins, middlewares) => {
59
- for (const pluginName in plugins) {
60
- const pluginMiddlewares = plugins[pluginName].middlewares;
61
- for (const middlewareName in pluginMiddlewares) {
62
- middlewares[middlewareName] = {
63
- loaded: false,
64
- ...pluginMiddlewares[middlewareName],
65
- };
66
- }
67
- }
68
- };
69
-
70
- const loadLocalPluginsMiddlewares = async (appPath, middlewares) => {
71
- const pluginsDir = path.resolve(appPath, 'plugins');
72
- if (!fs.existsSync(pluginsDir)) return;
73
-
74
- const pluginsNames = await fs.readdir(pluginsDir);
25
+ for (const fd of paths) {
26
+ const { name } = fd;
27
+ const fullPath = join(dir, name);
75
28
 
76
- for (let pluginFolder of pluginsNames) {
77
- // ignore files
78
- const stat = await fs.stat(path.resolve(pluginsDir, pluginFolder));
79
- if (!stat.isDirectory()) continue;
80
-
81
- const dir = path.resolve(pluginsDir, pluginFolder, 'middlewares');
82
- await loadMiddlewaresInDir(dir, middlewares);
29
+ if (fd.isFile() && extname(name) === '.js') {
30
+ const key = basename(name, '.js');
31
+ middlewares[key] = require(fullPath);
83
32
  }
84
- };
85
-
86
- const loadAdminMiddlewares = async middlewares => {
87
- const middlewaresDir = 'middlewares';
88
- const dir = path.resolve(findPackagePath(`@strapi/admin`), middlewaresDir);
89
- await loadMiddlewaresInDir(dir, middlewares);
33
+ }
90
34
 
91
- // load ee admin middlewares if they exist
92
- if (process.env.STRAPI_DISABLE_EE !== 'true' && strapi.EE) {
93
- await loadMiddlewaresInDir(`${dir}/../ee/${middlewaresDir}`, middlewares);
94
- }
95
- };
96
-
97
- const loadMiddlewareDependencies = async (packages, middlewares) => {
98
- for (let packageName of packages) {
99
- const baseDir = path.dirname(require.resolve(`@strapi/middleware-${packageName}`));
100
- const files = await glob('*(index|defaults).*(js|json)', {
101
- cwd: baseDir,
102
- absolute: true,
103
- });
104
-
105
- mountMiddleware(packageName, files, middlewares);
106
- }
107
- };
108
-
109
- const mountMiddleware = (name, files, middlewares) => {
110
- files.forEach(file => {
111
- middlewares[name] = middlewares[name] || { loaded: false };
112
-
113
- if (_.endsWith(file, 'index.js') && !middlewares[name].load) {
114
- return Object.defineProperty(middlewares[name], 'load', {
115
- configurable: false,
116
- enumerable: true,
117
- get: () => require(file)(strapi),
118
- });
119
- }
120
-
121
- if (_.endsWith(file, 'defaults.json')) {
122
- middlewares[name].defaults = require(file);
123
- return;
124
- }
125
- });
126
- };
127
-
128
- return {
129
- loadInternalMiddlewares,
130
- loadLocalMiddlewares,
131
- loadPluginsMiddlewares,
132
- loadLocalPluginsMiddlewares,
133
- loadMiddlewareDependencies,
134
- loadAdminMiddlewares,
135
- };
35
+ return middlewares;
136
36
  };
@@ -1,13 +1,19 @@
1
1
  'use strict';
2
2
 
3
- const { dirname, join } = require('path');
3
+ const { dirname, join, resolve } = require('path');
4
4
  const { statSync, existsSync } = require('fs');
5
5
  const _ = require('lodash');
6
6
  const { get, has, pick, pickBy, defaultsDeep, map, prop, pipe } = require('lodash/fp');
7
7
  const { isKebabCase } = require('@strapi/utils');
8
- const loadConfigFile = require('../../app-configuration/load-config-file');
8
+ const getUserPluginsConfig = require('./get-user-plugins-config');
9
9
 
10
10
  const isStrapiPlugin = info => get('strapi.kind', info) === 'plugin';
11
+ const INTERNAL_PLUGINS = [
12
+ '@strapi/plugin-content-manager',
13
+ '@strapi/plugin-content-type-builder',
14
+ '@strapi/plugin-email',
15
+ '@strapi/plugin-upload',
16
+ ];
11
17
 
12
18
  const validatePluginName = pluginName => {
13
19
  if (!isKebabCase(pluginName)) {
@@ -21,17 +27,14 @@ const toDetailedDeclaration = declaration => {
21
27
  }
22
28
 
23
29
  let detailedDeclaration = pick(['enabled'], declaration);
24
- if (has('config', declaration)) {
25
- detailedDeclaration.userConfig = declaration.config;
26
- }
27
30
  if (has('resolve', declaration)) {
28
31
  let pathToPlugin = '';
29
32
  try {
30
33
  pathToPlugin = dirname(require.resolve(declaration.resolve));
31
34
  } catch (e) {
32
- if (existsSync(declaration.resolve) && statSync(declaration.resolve).isDirectory()) {
33
- pathToPlugin = declaration.resolve;
34
- } else {
35
+ pathToPlugin = resolve(strapi.dirs.root, declaration.resolve);
36
+
37
+ if (!existsSync(pathToPlugin) || !statSync(pathToPlugin).isDirectory()) {
35
38
  throw new Error(`${declaration.resolve} couldn't be resolved`);
36
39
  }
37
40
  }
@@ -42,28 +45,59 @@ const toDetailedDeclaration = declaration => {
42
45
  };
43
46
 
44
47
  const getEnabledPlugins = async strapi => {
48
+ const internalPlugins = {};
49
+ for (const dep of INTERNAL_PLUGINS) {
50
+ const packagePath = join(dep, 'package.json');
51
+ const packageInfo = require(packagePath);
52
+
53
+ validatePluginName(packageInfo.strapi.name);
54
+ internalPlugins[packageInfo.strapi.name] = {
55
+ ...toDetailedDeclaration({ enabled: true, resolve: packagePath }),
56
+ info: packageInfo.strapi,
57
+ };
58
+ }
59
+
45
60
  const installedPlugins = {};
46
61
  for (const dep in strapi.config.get('info.dependencies', {})) {
47
62
  const packagePath = join(dep, 'package.json');
48
- const packageInfo = require(packagePath);
63
+ let packageInfo;
64
+ try {
65
+ packageInfo = require(packagePath);
66
+ } catch {
67
+ continue;
68
+ }
49
69
 
50
70
  if (isStrapiPlugin(packageInfo)) {
51
71
  validatePluginName(packageInfo.strapi.name);
52
- installedPlugins[packageInfo.strapi.name] = toDetailedDeclaration({
53
- enabled: true,
54
- resolve: packagePath,
55
- });
72
+ installedPlugins[packageInfo.strapi.name] = {
73
+ ...toDetailedDeclaration({ enabled: true, resolve: packagePath }),
74
+ info: packageInfo.strapi,
75
+ };
56
76
  }
57
77
  }
58
78
 
59
79
  const declaredPlugins = {};
60
- const userPluginConfigPath = join(strapi.dir, 'config', 'plugins.js');
61
- const userPluginsConfig = existsSync(userPluginConfigPath)
62
- ? loadConfigFile(userPluginConfigPath)
63
- : {};
80
+ const userPluginsConfig = await getUserPluginsConfig();
81
+
64
82
  _.forEach(userPluginsConfig, (declaration, pluginName) => {
65
83
  validatePluginName(pluginName);
66
- declaredPlugins[pluginName] = toDetailedDeclaration(declaration);
84
+
85
+ declaredPlugins[pluginName] = {
86
+ ...toDetailedDeclaration(declaration),
87
+ info: {},
88
+ };
89
+
90
+ const { pathToPlugin } = declaredPlugins[pluginName];
91
+
92
+ // for manually resolved plugins
93
+ if (pathToPlugin) {
94
+ const packagePath = join(pathToPlugin, 'package.json');
95
+ const packageInfo = require(packagePath);
96
+
97
+ if (isStrapiPlugin(packageInfo)) {
98
+ declaredPlugins[pluginName].info = packageInfo.strapi || {};
99
+ }
100
+ }
67
101
  });
68
102
 
69
103
  const declaredPluginsResolves = map(prop('pathToPlugin'), declaredPlugins);
@@ -71,10 +105,12 @@ const getEnabledPlugins = async strapi => {
71
105
  p => !declaredPluginsResolves.includes(p.pathToPlugin),
72
106
  installedPlugins
73
107
  );
108
+
74
109
  const enabledPlugins = pipe(
110
+ defaultsDeep(declaredPlugins),
75
111
  defaultsDeep(installedPluginsNotAlreadyUsed),
76
112
  pickBy(p => p.enabled)
77
- )(declaredPlugins);
113
+ )(internalPlugins);
78
114
 
79
115
  return enabledPlugins;
80
116
  };