@strapi/strapi 4.0.0-next.7 → 4.0.1
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.
- package/README.md +14 -14
- package/bin/strapi.js +46 -60
- package/lib/Strapi.js +193 -98
- package/lib/commands/build.js +19 -8
- package/lib/commands/console.js +1 -1
- package/lib/commands/content-types/list.js +22 -0
- package/lib/commands/controllers/list.js +22 -0
- package/lib/commands/develop.js +22 -27
- package/lib/commands/generate-template.js +4 -5
- package/lib/commands/hooks/list.js +22 -0
- package/lib/commands/middlewares/list.js +22 -0
- package/lib/commands/new.js +3 -1
- package/lib/commands/policies/list.js +22 -0
- package/lib/commands/routes/list.js +28 -0
- package/lib/commands/services/list.js +22 -0
- package/lib/commands/watchAdmin.js +18 -9
- package/lib/core/app-configuration/index.js +3 -36
- package/lib/core/bootstrap.js +25 -0
- package/lib/core/domain/content-type/index.js +26 -29
- package/lib/core/domain/content-type/validator.js +22 -3
- package/lib/core/domain/module/index.js +42 -11
- package/lib/core/domain/module/validation.js +16 -19
- package/lib/core/loaders/admin.js +16 -0
- package/lib/core/loaders/apis.js +159 -0
- package/lib/core/loaders/{load-components.js → components.js} +5 -6
- package/lib/core/loaders/index.js +11 -0
- package/lib/core/loaders/middlewares.js +36 -0
- package/lib/core/{load-plugins → loaders/plugins}/get-enabled-plugins.js +55 -19
- package/lib/core/loaders/plugins/get-user-plugins-config.js +37 -0
- package/lib/core/{load-plugins → loaders/plugins}/index.js +35 -19
- package/lib/core/loaders/policies.js +28 -0
- package/lib/core/loaders/src-index.js +39 -0
- package/lib/core/registries/apis.js +29 -0
- package/lib/core/registries/content-types.js +66 -10
- package/lib/core/registries/controllers.d.ts +7 -0
- package/lib/core/registries/controllers.js +92 -7
- package/lib/core/registries/hooks.d.ts +20 -0
- package/lib/core/registries/hooks.js +87 -0
- package/lib/core/registries/middlewares.d.ts +5 -0
- package/lib/core/registries/middlewares.js +65 -5
- package/lib/core/registries/modules.js +3 -3
- package/lib/core/registries/plugins.js +2 -2
- package/lib/core/registries/policies.d.ts +9 -0
- package/lib/core/registries/policies.js +65 -5
- package/lib/core/registries/services.d.ts +7 -0
- package/lib/core/registries/services.js +88 -17
- package/lib/core/utils.js +35 -0
- package/lib/core-api/controller/collection-type.js +45 -26
- package/lib/core-api/controller/index.d.ts +25 -0
- package/lib/core-api/controller/index.js +33 -11
- package/lib/core-api/controller/single-type.js +29 -15
- package/lib/core-api/controller/transform.js +62 -6
- package/lib/core-api/routes/index.js +71 -0
- package/lib/core-api/service/collection-type.js +43 -21
- package/lib/core-api/service/index.d.ts +21 -0
- package/lib/core-api/service/index.js +8 -67
- package/lib/core-api/service/pagination.js +125 -0
- package/lib/core-api/service/single-type.js +17 -19
- package/lib/factories.d.ts +48 -0
- package/lib/factories.js +84 -0
- package/lib/index.d.ts +10 -31
- package/lib/index.js +5 -1
- package/lib/middlewares/body.js +33 -0
- package/lib/middlewares/compression.js +8 -0
- package/lib/middlewares/cors.js +58 -0
- package/lib/middlewares/errors.js +40 -0
- package/lib/middlewares/favicon.js +19 -0
- package/lib/middlewares/index.d.ts +5 -0
- package/lib/middlewares/index.js +30 -116
- package/lib/middlewares/ip.js +8 -0
- package/lib/middlewares/logger.js +27 -0
- package/lib/middlewares/powered-by.js +20 -0
- package/lib/middlewares/public/index.js +72 -77
- package/lib/middlewares/query.js +46 -0
- package/lib/middlewares/response-time.js +15 -0
- package/lib/middlewares/responses.js +19 -0
- package/lib/middlewares/security.js +51 -0
- package/lib/middlewares/session/index.js +6 -6
- package/lib/migrations/draft-publish.js +57 -0
- package/lib/services/auth/index.js +87 -0
- package/lib/services/core-store.js +64 -51
- package/lib/services/cron.js +54 -0
- package/lib/services/entity-service/attributes/index.js +31 -0
- package/lib/services/entity-service/attributes/transforms.js +20 -0
- package/lib/services/entity-service/components.js +39 -15
- package/lib/services/entity-service/index.d.ts +91 -0
- package/lib/services/entity-service/index.js +120 -59
- package/lib/services/entity-service/params.js +52 -94
- package/lib/services/entity-validator/index.js +76 -43
- package/lib/services/entity-validator/validators.js +131 -43
- package/lib/services/errors.js +77 -0
- package/lib/{core → services}/fs.js +1 -1
- package/lib/services/metrics/index.js +38 -36
- package/lib/services/server/admin-api.js +14 -0
- package/lib/services/server/api.js +36 -0
- package/lib/services/server/compose-endpoint.js +141 -0
- package/lib/services/server/content-api.js +16 -0
- package/lib/{server.js → services/server/http-server.js} +0 -0
- package/lib/services/server/index.js +127 -0
- package/lib/services/server/koa.js +64 -0
- package/lib/services/server/middleware.js +122 -0
- package/lib/services/server/policy.js +32 -0
- package/lib/services/server/register-middlewares.js +110 -0
- package/lib/services/server/register-routes.js +106 -0
- package/lib/services/server/routing.js +120 -0
- package/lib/services/webhook-runner.js +1 -1
- package/lib/utils/ee.js +3 -3
- package/lib/utils/get-dirs.js +17 -0
- package/lib/utils/index.js +2 -0
- package/lib/utils/is-initialized.js +1 -1
- package/lib/utils/signals.js +24 -0
- package/lib/utils/startup-logger.js +2 -2
- package/lib/utils/update-notifier/index.js +3 -2
- package/package.json +94 -97
- package/lib/commands/generate.js +0 -76
- package/lib/core/loaders/bootstrap.js +0 -176
- package/lib/core/loaders/load-apis.js +0 -20
- package/lib/core/loaders/load-functions.js +0 -21
- package/lib/core/loaders/load-middlewares.js +0 -136
- package/lib/core/loaders/load-modules.js +0 -21
- package/lib/core/loaders/load-policies.js +0 -36
- package/lib/core/loaders/walk.js +0 -27
- package/lib/core-api/index.js +0 -39
- package/lib/load/check-reserved-filename.js +0 -10
- package/lib/load/load-config-files.js +0 -22
- package/lib/load/require-file-parse.js +0 -15
- package/lib/middlewares/boom/defaults.json +0 -5
- package/lib/middlewares/boom/index.js +0 -147
- package/lib/middlewares/cors/index.js +0 -66
- package/lib/middlewares/cron/defaults.json +0 -5
- package/lib/middlewares/cron/index.js +0 -43
- package/lib/middlewares/favicon/defaults.json +0 -7
- package/lib/middlewares/favicon/index.js +0 -32
- package/lib/middlewares/gzip/defaults.json +0 -6
- package/lib/middlewares/gzip/index.js +0 -19
- package/lib/middlewares/helmet/defaults.json +0 -18
- package/lib/middlewares/helmet/index.js +0 -9
- package/lib/middlewares/ip/defaults.json +0 -7
- package/lib/middlewares/ip/index.js +0 -25
- package/lib/middlewares/language/defaults.json +0 -9
- package/lib/middlewares/language/index.js +0 -40
- package/lib/middlewares/logger/defaults.json +0 -5
- package/lib/middlewares/logger/index.js +0 -37
- package/lib/middlewares/parser/defaults.json +0 -11
- package/lib/middlewares/parser/index.js +0 -71
- package/lib/middlewares/poweredBy/defaults.json +0 -5
- package/lib/middlewares/poweredBy/index.js +0 -16
- package/lib/middlewares/public/defaults.json +0 -8
- package/lib/middlewares/responseTime/defaults.json +0 -5
- package/lib/middlewares/responseTime/index.js +0 -25
- package/lib/middlewares/responses/defaults.json +0 -5
- package/lib/middlewares/responses/index.js +0 -18
- package/lib/middlewares/router/defaults.json +0 -7
- package/lib/middlewares/router/index.js +0 -56
- package/lib/middlewares/router/utils/composeEndpoint.js +0 -25
- package/lib/middlewares/router/utils/routerChecker.js +0 -96
- package/lib/utils/get-prefixed-dependencies.js +0 -7
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { join, extname, basename } = require('path');
|
|
4
|
+
const { existsSync } = require('fs-extra');
|
|
5
|
+
const _ = require('lodash');
|
|
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
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports = async strapi => {
|
|
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
|
+
};
|
|
98
|
+
|
|
99
|
+
const loadIndex = async dir => {
|
|
100
|
+
if (await fse.pathExists(join(dir, 'index.js'))) {
|
|
101
|
+
return loadFile(join(dir, 'index.js'));
|
|
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
|
+
}
|
|
118
|
+
|
|
119
|
+
const contentTypeName = normalizeName(fd.name);
|
|
120
|
+
const contentType = await loadDir(join(dir, fd.name));
|
|
121
|
+
|
|
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
|
+
}
|
|
159
|
+
};
|
|
@@ -2,23 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
const { join } = require('path');
|
|
4
4
|
const _ = require('lodash');
|
|
5
|
-
const {
|
|
5
|
+
const { pathExists } = require('fs-extra');
|
|
6
6
|
const loadFiles = require('../../load/load-files');
|
|
7
7
|
|
|
8
8
|
module.exports = async strapi => {
|
|
9
|
-
|
|
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(
|
|
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(
|
|
19
|
+
const filePath = join(strapi.dirs.components, category, schema.__filename__);
|
|
22
20
|
|
|
23
21
|
if (!schema.collectionName) {
|
|
24
22
|
return strapi.stopWithError(
|
|
@@ -32,6 +30,7 @@ module.exports = async strapi => {
|
|
|
32
30
|
__schema__: _.cloneDeep(schema),
|
|
33
31
|
uid,
|
|
34
32
|
category,
|
|
33
|
+
modelType: 'component',
|
|
35
34
|
modelName: key,
|
|
36
35
|
globalId: schema.globalId || _.upperFirst(_.camelCase(`component_${uid}`)),
|
|
37
36
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
loadSrcIndex: require('./src-index'),
|
|
5
|
+
loadAPIs: require('./apis'),
|
|
6
|
+
loadMiddlewares: require('./middlewares'),
|
|
7
|
+
loadComponents: require('./components'),
|
|
8
|
+
loadPolicies: require('./policies'),
|
|
9
|
+
loadPlugins: require('./plugins'),
|
|
10
|
+
loadAdmin: require('./admin'),
|
|
11
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { join, extname, basename } = require('path');
|
|
4
|
+
const fse = require('fs-extra');
|
|
5
|
+
|
|
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');
|
|
10
|
+
|
|
11
|
+
strapi.container.get('middlewares').add(`global::`, localMiddlewares);
|
|
12
|
+
strapi.container.get('middlewares').add(`strapi::`, internalMiddlewares);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const loadLocalMiddlewares = async strapi => {
|
|
16
|
+
const dir = strapi.dirs.middlewares;
|
|
17
|
+
|
|
18
|
+
if (!(await fse.pathExists(dir))) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const middlewares = {};
|
|
23
|
+
const paths = await fse.readdir(dir, { withFileTypes: true });
|
|
24
|
+
|
|
25
|
+
for (const fd of paths) {
|
|
26
|
+
const { name } = fd;
|
|
27
|
+
const fullPath = join(dir, name);
|
|
28
|
+
|
|
29
|
+
if (fd.isFile() && extname(name) === '.js') {
|
|
30
|
+
const key = basename(name, '.js');
|
|
31
|
+
middlewares[key] = require(fullPath);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return middlewares;
|
|
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
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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] =
|
|
53
|
-
enabled: true,
|
|
54
|
-
|
|
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
|
|
61
|
-
|
|
62
|
-
? loadConfigFile(userPluginConfigPath)
|
|
63
|
-
: {};
|
|
80
|
+
const userPluginsConfig = await getUserPluginsConfig();
|
|
81
|
+
|
|
64
82
|
_.forEach(userPluginsConfig, (declaration, pluginName) => {
|
|
65
83
|
validatePluginName(pluginName);
|
|
66
|
-
|
|
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
|
-
)(
|
|
113
|
+
)(internalPlugins);
|
|
78
114
|
|
|
79
115
|
return enabledPlugins;
|
|
80
116
|
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { join } = require('path');
|
|
4
|
+
const fse = require('fs-extra');
|
|
5
|
+
const { merge } = require('lodash/fp');
|
|
6
|
+
const loadConfigFile = require('../../app-configuration/load-config-file');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Return user defined plugins' config
|
|
10
|
+
* first load config from `config/plugins.js`
|
|
11
|
+
* and then merge config from `config/env/{env}/plugins.js`
|
|
12
|
+
* @return {Promise<{}>}
|
|
13
|
+
*/
|
|
14
|
+
const getUserPluginsConfig = async () => {
|
|
15
|
+
const globalUserConfigPath = join(strapi.dirs.config, 'plugins.js');
|
|
16
|
+
const currentEnvUserConfigPath = join(
|
|
17
|
+
strapi.dirs.config,
|
|
18
|
+
'env',
|
|
19
|
+
process.env.NODE_ENV,
|
|
20
|
+
'plugins.js'
|
|
21
|
+
);
|
|
22
|
+
let config = {};
|
|
23
|
+
|
|
24
|
+
// assign global user config if exists
|
|
25
|
+
if (await fse.pathExists(globalUserConfigPath)) {
|
|
26
|
+
config = loadConfigFile(globalUserConfigPath);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// and merge user config by environment if exists
|
|
30
|
+
if (await fse.pathExists(currentEnvUserConfigPath)) {
|
|
31
|
+
config = merge(config, loadConfigFile(currentEnvUserConfigPath));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return config;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = getUserPluginsConfig;
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { join
|
|
4
|
-
const
|
|
3
|
+
const { join } = require('path');
|
|
4
|
+
const fse = require('fs-extra');
|
|
5
5
|
const { defaultsDeep, getOr, get } = require('lodash/fp');
|
|
6
6
|
const { env } = require('@strapi/utils');
|
|
7
|
-
const loadConfigFile = require('
|
|
8
|
-
const loadFiles = require('
|
|
7
|
+
const loadConfigFile = require('../../app-configuration/load-config-file');
|
|
8
|
+
const loadFiles = require('../../../load/load-files');
|
|
9
9
|
const getEnabledPlugins = require('./get-enabled-plugins');
|
|
10
|
+
const getUserPluginsConfig = require('./get-user-plugins-config');
|
|
10
11
|
|
|
11
12
|
const defaultPlugin = {
|
|
12
|
-
bootstrap
|
|
13
|
-
destroy
|
|
14
|
-
register
|
|
13
|
+
bootstrap() {},
|
|
14
|
+
destroy() {},
|
|
15
|
+
register() {},
|
|
15
16
|
config: {
|
|
16
17
|
default: {},
|
|
17
|
-
validator
|
|
18
|
+
validator() {},
|
|
18
19
|
},
|
|
19
20
|
routes: [],
|
|
20
21
|
controllers: {},
|
|
@@ -25,8 +26,8 @@ const defaultPlugin = {
|
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
const applyUserExtension = async plugins => {
|
|
28
|
-
const extensionsDir =
|
|
29
|
-
if (!
|
|
29
|
+
const extensionsDir = strapi.dirs.extensions;
|
|
30
|
+
if (!(await fse.pathExists(extensionsDir))) {
|
|
30
31
|
return;
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -39,7 +40,11 @@ const applyUserExtension = async plugins => {
|
|
|
39
40
|
for (const ctName in plugin.contentTypes) {
|
|
40
41
|
const extendedSchema = get([pluginName, 'content-types', ctName, 'schema'], extendedSchemas);
|
|
41
42
|
if (extendedSchema) {
|
|
42
|
-
plugin.contentTypes[ctName].schema =
|
|
43
|
+
plugin.contentTypes[ctName].schema = Object.assign(
|
|
44
|
+
{},
|
|
45
|
+
plugin.contentTypes[ctName].schema,
|
|
46
|
+
extendedSchema
|
|
47
|
+
);
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
// second: execute strapi-server extension
|
|
@@ -61,11 +66,8 @@ const formatContentTypes = plugins => {
|
|
|
61
66
|
}
|
|
62
67
|
};
|
|
63
68
|
|
|
64
|
-
const applyUserConfig = plugins => {
|
|
65
|
-
const
|
|
66
|
-
const userPluginsConfig = existsSync(userPluginConfigPath)
|
|
67
|
-
? loadConfigFile(userPluginConfigPath)
|
|
68
|
-
: {};
|
|
69
|
+
const applyUserConfig = async plugins => {
|
|
70
|
+
const userPluginsConfig = await getUserPluginsConfig();
|
|
69
71
|
|
|
70
72
|
for (const pluginName in plugins) {
|
|
71
73
|
const plugin = plugins[pluginName];
|
|
@@ -87,19 +89,33 @@ const applyUserConfig = plugins => {
|
|
|
87
89
|
|
|
88
90
|
const loadPlugins = async strapi => {
|
|
89
91
|
const plugins = {};
|
|
92
|
+
|
|
90
93
|
const enabledPlugins = await getEnabledPlugins(strapi);
|
|
91
94
|
|
|
95
|
+
strapi.config.set('enabledPlugins', enabledPlugins);
|
|
96
|
+
|
|
92
97
|
for (const pluginName in enabledPlugins) {
|
|
93
98
|
const enabledPlugin = enabledPlugins[pluginName];
|
|
94
|
-
|
|
99
|
+
|
|
100
|
+
const serverEntrypointPath = join(enabledPlugin.pathToPlugin, 'strapi-server.js');
|
|
101
|
+
|
|
102
|
+
// only load plugins with a server entrypoint
|
|
103
|
+
if (!(await fse.pathExists(serverEntrypointPath))) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const pluginServer = loadConfigFile(serverEntrypointPath);
|
|
95
108
|
plugins[pluginName] = defaultsDeep(defaultPlugin, pluginServer);
|
|
96
109
|
}
|
|
110
|
+
|
|
97
111
|
// TODO: validate plugin format
|
|
98
|
-
applyUserConfig(plugins);
|
|
112
|
+
await applyUserConfig(plugins);
|
|
99
113
|
await applyUserExtension(plugins);
|
|
100
114
|
formatContentTypes(plugins);
|
|
101
115
|
|
|
102
|
-
|
|
116
|
+
for (const pluginName in plugins) {
|
|
117
|
+
strapi.container.get('plugins').add(pluginName, plugins[pluginName]);
|
|
118
|
+
}
|
|
103
119
|
};
|
|
104
120
|
|
|
105
121
|
module.exports = loadPlugins;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { join, extname, basename } = require('path');
|
|
4
|
+
const fse = require('fs-extra');
|
|
5
|
+
|
|
6
|
+
// TODO:: allow folders with index.js inside for bigger policies
|
|
7
|
+
module.exports = async function loadPolicies(strapi) {
|
|
8
|
+
const dir = strapi.dirs.policies;
|
|
9
|
+
|
|
10
|
+
if (!(await fse.pathExists(dir))) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const policies = {};
|
|
15
|
+
const paths = await fse.readdir(dir, { withFileTypes: true });
|
|
16
|
+
|
|
17
|
+
for (const fd of paths) {
|
|
18
|
+
const { name } = fd;
|
|
19
|
+
const fullPath = join(dir, name);
|
|
20
|
+
|
|
21
|
+
if (fd.isFile() && extname(name) === '.js') {
|
|
22
|
+
const key = basename(name, '.js');
|
|
23
|
+
policies[key] = require(fullPath);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
strapi.container.get('policies').add(`global::`, policies);
|
|
28
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { resolve } = require('path');
|
|
4
|
+
const { statSync, existsSync } = require('fs');
|
|
5
|
+
const { yup } = require('@strapi/utils');
|
|
6
|
+
|
|
7
|
+
const srcSchema = yup
|
|
8
|
+
.object()
|
|
9
|
+
.shape({
|
|
10
|
+
bootstrap: yup.mixed().isFunction(),
|
|
11
|
+
register: yup.mixed().isFunction(),
|
|
12
|
+
destroy: yup.mixed().isFunction(),
|
|
13
|
+
})
|
|
14
|
+
.noUnknown();
|
|
15
|
+
|
|
16
|
+
const validateSrcIndex = srcIndex => {
|
|
17
|
+
return srcSchema.validateSync(srcIndex, { strict: true, abortEarly: false });
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
module.exports = strapi => {
|
|
21
|
+
if (!existsSync(strapi.dirs.src)) {
|
|
22
|
+
throw new Error('Missing src folder. Please create one at `./src`');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const pathToSrcIndex = resolve(strapi.dirs.src, 'index.js');
|
|
26
|
+
if (!existsSync(pathToSrcIndex) || statSync(pathToSrcIndex).isDirectory()) {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const srcIndex = require(pathToSrcIndex);
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
validateSrcIndex(srcIndex);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
strapi.stopWithError({ message: `Invalid file \`./src/index.js\`: ${e.message}` });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return srcIndex;
|
|
39
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { has } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const apisRegistry = strapi => {
|
|
6
|
+
const apis = {};
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
get(name) {
|
|
10
|
+
return apis[name];
|
|
11
|
+
},
|
|
12
|
+
getAll() {
|
|
13
|
+
return apis;
|
|
14
|
+
},
|
|
15
|
+
add(apiName, apiConfig) {
|
|
16
|
+
if (has(apiName, apis)) {
|
|
17
|
+
throw new Error(`API ${apiName} has already been registered.`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const api = strapi.container.get('modules').add(`api::${apiName}`, apiConfig);
|
|
21
|
+
|
|
22
|
+
apis[apiName] = api;
|
|
23
|
+
|
|
24
|
+
return apis[apiName];
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
module.exports = apisRegistry;
|