@strapi/strapi 4.0.0-next.6 → 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.
- package/README.md +12 -12
- package/bin/strapi.js +41 -60
- package/lib/Strapi.js +234 -114
- package/lib/commands/build.js +16 -6
- package/lib/commands/console.js +1 -1
- package/lib/commands/content-types/list.js +22 -0
- package/lib/commands/develop.js +17 -18
- 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 -8
- package/lib/container.js +6 -6
- package/lib/core/app-configuration/config-loader.js +1 -37
- package/lib/core/app-configuration/index.js +6 -46
- package/lib/core/app-configuration/load-config-file.js +43 -0
- package/lib/core/bootstrap.js +5 -117
- package/lib/core/domain/component/index.js +24 -0
- package/lib/core/domain/component/validator.js +29 -0
- package/lib/core/domain/content-type/index.js +140 -0
- package/lib/core/domain/content-type/validator.js +64 -0
- package/lib/core/domain/module/index.js +108 -0
- package/lib/core/domain/module/validation.js +33 -0
- package/lib/core/loaders/admin.js +16 -0
- package/lib/core/loaders/apis.js +159 -0
- package/lib/core/{load-components.js → loaders/components.js} +5 -7
- package/lib/core/loaders/index.js +11 -0
- package/lib/core/loaders/middlewares.js +36 -0
- package/lib/core/loaders/plugins/get-enabled-plugins.js +116 -0
- package/lib/core/loaders/plugins/index.js +123 -0
- 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/{app-configuration/config-provider.js → registries/config.js} +4 -11
- package/lib/core/registries/content-types.js +97 -0
- package/lib/core/registries/controllers.d.ts +7 -0
- package/lib/core/registries/controllers.js +114 -0
- 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 +89 -0
- package/lib/core/registries/modules.js +44 -0
- package/lib/core/registries/plugins.js +28 -0
- package/lib/core/registries/policies.d.ts +9 -0
- package/lib/core/registries/policies.js +89 -0
- package/lib/core/registries/services.d.ts +7 -0
- package/lib/core/registries/services.js +114 -0
- 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 +130 -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 -117
- 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 +98 -73
- 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 +129 -43
- package/lib/services/errors.js +77 -0
- package/lib/{core → services}/fs.js +10 -2
- package/lib/services/metrics/index.js +41 -38
- package/lib/services/metrics/sender.js +2 -2
- 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/utils/upload-files.js +1 -1
- 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/run-checks.js +0 -15
- 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 +93 -96
- package/lib/commands/generate.js +0 -76
- package/lib/core/index.js +0 -17
- package/lib/core/load-apis.js +0 -20
- package/lib/core/load-extensions.js +0 -71
- package/lib/core/load-functions.js +0 -21
- package/lib/core/load-middlewares.js +0 -130
- package/lib/core/load-modules.js +0 -55
- package/lib/core/load-plugins.js +0 -68
- package/lib/core/load-policies.js +0 -36
- package/lib/core/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 -64
- package/lib/middlewares/router/utils/composeEndpoint.js +0 -25
- package/lib/middlewares/router/utils/routerChecker.js +0 -92
- package/lib/utils/get-prefixed-dependencies.js +0 -7
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { dirname, join, resolve } = require('path');
|
|
4
|
+
const { statSync, existsSync } = require('fs');
|
|
5
|
+
const _ = require('lodash');
|
|
6
|
+
const { get, has, pick, pickBy, defaultsDeep, map, prop, pipe } = require('lodash/fp');
|
|
7
|
+
const { isKebabCase } = require('@strapi/utils');
|
|
8
|
+
const loadConfigFile = require('../../app-configuration/load-config-file');
|
|
9
|
+
|
|
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
|
+
];
|
|
17
|
+
|
|
18
|
+
const validatePluginName = pluginName => {
|
|
19
|
+
if (!isKebabCase(pluginName)) {
|
|
20
|
+
throw new Error(`Plugin name "${pluginName}" is not in kebab (an-example-of-kebab-case)`);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const toDetailedDeclaration = declaration => {
|
|
25
|
+
if (typeof declaration === 'boolean') {
|
|
26
|
+
return { enabled: declaration };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let detailedDeclaration = pick(['enabled'], declaration);
|
|
30
|
+
if (has('resolve', declaration)) {
|
|
31
|
+
let pathToPlugin = '';
|
|
32
|
+
try {
|
|
33
|
+
pathToPlugin = dirname(require.resolve(declaration.resolve));
|
|
34
|
+
} catch (e) {
|
|
35
|
+
pathToPlugin = resolve(strapi.dirs.root, declaration.resolve);
|
|
36
|
+
|
|
37
|
+
if (!existsSync(pathToPlugin) || !statSync(pathToPlugin).isDirectory()) {
|
|
38
|
+
throw new Error(`${declaration.resolve} couldn't be resolved`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
detailedDeclaration.pathToPlugin = pathToPlugin;
|
|
43
|
+
}
|
|
44
|
+
return detailedDeclaration;
|
|
45
|
+
};
|
|
46
|
+
|
|
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
|
+
|
|
60
|
+
const installedPlugins = {};
|
|
61
|
+
for (const dep in strapi.config.get('info.dependencies', {})) {
|
|
62
|
+
const packagePath = join(dep, 'package.json');
|
|
63
|
+
const packageInfo = require(packagePath);
|
|
64
|
+
|
|
65
|
+
if (isStrapiPlugin(packageInfo)) {
|
|
66
|
+
validatePluginName(packageInfo.strapi.name);
|
|
67
|
+
installedPlugins[packageInfo.strapi.name] = {
|
|
68
|
+
...toDetailedDeclaration({ enabled: true, resolve: packagePath }),
|
|
69
|
+
info: packageInfo.strapi,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const declaredPlugins = {};
|
|
75
|
+
const userPluginConfigPath = join(strapi.dirs.config, 'plugins.js');
|
|
76
|
+
const userPluginsConfig = existsSync(userPluginConfigPath)
|
|
77
|
+
? loadConfigFile(userPluginConfigPath)
|
|
78
|
+
: {};
|
|
79
|
+
|
|
80
|
+
_.forEach(userPluginsConfig, (declaration, pluginName) => {
|
|
81
|
+
validatePluginName(pluginName);
|
|
82
|
+
|
|
83
|
+
declaredPlugins[pluginName] = {
|
|
84
|
+
...toDetailedDeclaration(declaration),
|
|
85
|
+
info: {},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const { pathToPlugin } = declaredPlugins[pluginName];
|
|
89
|
+
|
|
90
|
+
// for manually resolved plugins
|
|
91
|
+
if (pathToPlugin) {
|
|
92
|
+
const packagePath = join(pathToPlugin, 'package.json');
|
|
93
|
+
const packageInfo = require(packagePath);
|
|
94
|
+
|
|
95
|
+
if (isStrapiPlugin(packageInfo)) {
|
|
96
|
+
declaredPlugins[pluginName].info = packageInfo.strapi || {};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const declaredPluginsResolves = map(prop('pathToPlugin'), declaredPlugins);
|
|
102
|
+
const installedPluginsNotAlreadyUsed = pickBy(
|
|
103
|
+
p => !declaredPluginsResolves.includes(p.pathToPlugin),
|
|
104
|
+
installedPlugins
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const enabledPlugins = pipe(
|
|
108
|
+
defaultsDeep(declaredPlugins),
|
|
109
|
+
defaultsDeep(installedPluginsNotAlreadyUsed),
|
|
110
|
+
pickBy(p => p.enabled)
|
|
111
|
+
)(internalPlugins);
|
|
112
|
+
|
|
113
|
+
return enabledPlugins;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
module.exports = getEnabledPlugins;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { join } = require('path');
|
|
4
|
+
const fse = require('fs-extra');
|
|
5
|
+
const { defaultsDeep, getOr, get } = require('lodash/fp');
|
|
6
|
+
const { env } = require('@strapi/utils');
|
|
7
|
+
const loadConfigFile = require('../../app-configuration/load-config-file');
|
|
8
|
+
const loadFiles = require('../../../load/load-files');
|
|
9
|
+
const getEnabledPlugins = require('./get-enabled-plugins');
|
|
10
|
+
|
|
11
|
+
const defaultPlugin = {
|
|
12
|
+
bootstrap() {},
|
|
13
|
+
destroy() {},
|
|
14
|
+
register() {},
|
|
15
|
+
config: {
|
|
16
|
+
default: {},
|
|
17
|
+
validator() {},
|
|
18
|
+
},
|
|
19
|
+
routes: [],
|
|
20
|
+
controllers: {},
|
|
21
|
+
services: {},
|
|
22
|
+
policies: {},
|
|
23
|
+
middlewares: {},
|
|
24
|
+
contentTypes: {},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const applyUserExtension = async plugins => {
|
|
28
|
+
const extensionsDir = strapi.dirs.extensions;
|
|
29
|
+
if (!(await fse.pathExists(extensionsDir))) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const extendedSchemas = await loadFiles(extensionsDir, '**/content-types/**/schema.json');
|
|
34
|
+
const strapiServers = await loadFiles(extensionsDir, '**/strapi-server.js');
|
|
35
|
+
|
|
36
|
+
for (const pluginName in plugins) {
|
|
37
|
+
const plugin = plugins[pluginName];
|
|
38
|
+
// first: load json schema
|
|
39
|
+
for (const ctName in plugin.contentTypes) {
|
|
40
|
+
const extendedSchema = get([pluginName, 'content-types', ctName, 'schema'], extendedSchemas);
|
|
41
|
+
if (extendedSchema) {
|
|
42
|
+
plugin.contentTypes[ctName].schema = Object.assign(
|
|
43
|
+
{},
|
|
44
|
+
plugin.contentTypes[ctName].schema,
|
|
45
|
+
extendedSchema
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// second: execute strapi-server extension
|
|
50
|
+
const strapiServer = get([pluginName, 'strapi-server'], strapiServers);
|
|
51
|
+
if (strapiServer) {
|
|
52
|
+
plugins[pluginName] = await strapiServer(plugin);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const formatContentTypes = plugins => {
|
|
58
|
+
for (const pluginName in plugins) {
|
|
59
|
+
const plugin = plugins[pluginName];
|
|
60
|
+
for (const contentTypeName in plugin.contentTypes) {
|
|
61
|
+
const ctSchema = plugin.contentTypes[contentTypeName].schema;
|
|
62
|
+
ctSchema.plugin = pluginName;
|
|
63
|
+
ctSchema.uid = `plugin::${pluginName}.${ctSchema.singularName}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const applyUserConfig = async plugins => {
|
|
69
|
+
const userPluginConfigPath = join(strapi.dirs.config, 'plugins.js');
|
|
70
|
+
const userPluginsConfig = (await fse.pathExists(userPluginConfigPath))
|
|
71
|
+
? loadConfigFile(userPluginConfigPath)
|
|
72
|
+
: {};
|
|
73
|
+
|
|
74
|
+
for (const pluginName in plugins) {
|
|
75
|
+
const plugin = plugins[pluginName];
|
|
76
|
+
const userPluginConfig = getOr({}, `${pluginName}.config`, userPluginsConfig);
|
|
77
|
+
const defaultConfig =
|
|
78
|
+
typeof plugin.config.default === 'function'
|
|
79
|
+
? plugin.config.default({ env })
|
|
80
|
+
: plugin.config.default;
|
|
81
|
+
|
|
82
|
+
const config = defaultsDeep(defaultConfig, userPluginConfig);
|
|
83
|
+
try {
|
|
84
|
+
plugin.config.validator(config);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
throw new Error(`Error regarding ${pluginName} config: ${e.message}`);
|
|
87
|
+
}
|
|
88
|
+
plugin.config = config;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const loadPlugins = async strapi => {
|
|
93
|
+
const plugins = {};
|
|
94
|
+
|
|
95
|
+
const enabledPlugins = await getEnabledPlugins(strapi);
|
|
96
|
+
|
|
97
|
+
strapi.config.set('enabledPlugins', enabledPlugins);
|
|
98
|
+
|
|
99
|
+
for (const pluginName in enabledPlugins) {
|
|
100
|
+
const enabledPlugin = enabledPlugins[pluginName];
|
|
101
|
+
|
|
102
|
+
const serverEntrypointPath = join(enabledPlugin.pathToPlugin, 'strapi-server.js');
|
|
103
|
+
|
|
104
|
+
// only load plugins with a server entrypoint
|
|
105
|
+
if (!(await fse.pathExists(serverEntrypointPath))) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const pluginServer = loadConfigFile(serverEntrypointPath);
|
|
110
|
+
plugins[pluginName] = defaultsDeep(defaultPlugin, pluginServer);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// TODO: validate plugin format
|
|
114
|
+
await applyUserConfig(plugins);
|
|
115
|
+
await applyUserExtension(plugins);
|
|
116
|
+
formatContentTypes(plugins);
|
|
117
|
+
|
|
118
|
+
for (const pluginName in plugins) {
|
|
119
|
+
strapi.container.get('plugins').add(pluginName, plugins[pluginName]);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
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;
|
|
@@ -1,28 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const assert = require('assert');
|
|
4
3
|
const _ = require('lodash');
|
|
5
4
|
|
|
6
5
|
module.exports = (initialConfig = {}) => {
|
|
7
|
-
|
|
8
|
-
typeof initialConfig === 'object' && initialConfig !== null,
|
|
9
|
-
'Initial config must be an object'
|
|
10
|
-
);
|
|
6
|
+
const _config = Object.assign({}, initialConfig); // not deep clone because it would break some config
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return Object.assign(_config, {
|
|
8
|
+
return {
|
|
9
|
+
..._config, // TODO: to remove
|
|
15
10
|
get(path, defaultValue) {
|
|
16
11
|
return _.get(_config, path, defaultValue);
|
|
17
12
|
},
|
|
18
|
-
|
|
19
13
|
set(path, val) {
|
|
20
14
|
_.set(_config, path, val);
|
|
21
15
|
return this;
|
|
22
16
|
},
|
|
23
|
-
|
|
24
17
|
has(path) {
|
|
25
18
|
return _.has(_config, path);
|
|
26
19
|
},
|
|
27
|
-
}
|
|
20
|
+
};
|
|
28
21
|
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { pickBy, has } = require('lodash/fp');
|
|
4
|
+
const { createContentType } = require('../domain/content-type');
|
|
5
|
+
const { addNamespace, hasNamespace } = require('../utils');
|
|
6
|
+
|
|
7
|
+
const validateKeySameToSingularName = contentTypes => {
|
|
8
|
+
for (const ctName in contentTypes) {
|
|
9
|
+
const contentType = contentTypes[ctName];
|
|
10
|
+
|
|
11
|
+
if (ctName !== contentType.schema.info.singularName) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
`The key of the content-type should be the same as its singularName. Found ${ctName} and ${contentType.schema.info.singularName}.`
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const contentTypesRegistry = () => {
|
|
20
|
+
const contentTypes = {};
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
/**
|
|
24
|
+
* Returns this list of registered contentTypes uids
|
|
25
|
+
* @returns {string[]}
|
|
26
|
+
*/
|
|
27
|
+
keys() {
|
|
28
|
+
return Object.keys(contentTypes);
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns the instance of a contentType. Instantiate the contentType if not already done
|
|
33
|
+
* @param {string} uid
|
|
34
|
+
* @returns
|
|
35
|
+
*/
|
|
36
|
+
get(uid) {
|
|
37
|
+
return contentTypes[uid];
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Returns a map with all the contentTypes in a namespace
|
|
42
|
+
* @param {string} namespace
|
|
43
|
+
*/
|
|
44
|
+
getAll(namespace) {
|
|
45
|
+
return pickBy((_, uid) => hasNamespace(uid, namespace))(contentTypes);
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Registers a contentType
|
|
50
|
+
* @param {string} uid
|
|
51
|
+
* @param {Object} contentType
|
|
52
|
+
*/
|
|
53
|
+
set(uid, contentType) {
|
|
54
|
+
contentTypes[uid] = contentType;
|
|
55
|
+
return this;
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Registers a map of contentTypes for a specific namespace
|
|
60
|
+
* @param {string} namespace
|
|
61
|
+
* @param {{ [key: string]: Object }} newContentTypes
|
|
62
|
+
*/
|
|
63
|
+
add(namespace, newContentTypes) {
|
|
64
|
+
validateKeySameToSingularName(newContentTypes);
|
|
65
|
+
|
|
66
|
+
for (const rawCtName in newContentTypes) {
|
|
67
|
+
const uid = addNamespace(rawCtName, namespace);
|
|
68
|
+
|
|
69
|
+
if (has(uid, contentTypes)) {
|
|
70
|
+
throw new Error(`Content-type ${uid} has already been registered.`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
contentTypes[uid] = createContentType(uid, newContentTypes[rawCtName]);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Wraps a contentType to extend it
|
|
79
|
+
* @param {string} uid
|
|
80
|
+
* @param {(contentType: Object) => Object} extendFn
|
|
81
|
+
*/
|
|
82
|
+
extend(ctUID, extendFn) {
|
|
83
|
+
const currentContentType = this.get(ctUID);
|
|
84
|
+
|
|
85
|
+
if (!currentContentType) {
|
|
86
|
+
throw new Error(`Content-Type ${ctUID} doesn't exist`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const newContentType = extendFn(currentContentType);
|
|
90
|
+
contentTypes[ctUID] = newContentType;
|
|
91
|
+
|
|
92
|
+
return this;
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
module.exports = contentTypesRegistry;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { pickBy, has } = require('lodash/fp');
|
|
4
|
+
const { addNamespace, hasNamespace } = require('../utils');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {import('./controllers').Controller} Controller
|
|
8
|
+
* @typedef {import('./controllers').ControllerFactory} ControllerFactory
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const controllersRegistry = () => {
|
|
12
|
+
const controllers = {};
|
|
13
|
+
const instances = {};
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
/**
|
|
17
|
+
* Returns this list of registered controllers uids
|
|
18
|
+
* @returns {string[]}
|
|
19
|
+
*/
|
|
20
|
+
keys() {
|
|
21
|
+
return Object.keys(controllers);
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns the instance of a controller. Instantiate the controller if not already done
|
|
26
|
+
* @param {string} uid
|
|
27
|
+
* @returns {Controller}
|
|
28
|
+
*/
|
|
29
|
+
get(uid) {
|
|
30
|
+
if (instances[uid]) {
|
|
31
|
+
return instances[uid];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const controller = controllers[uid];
|
|
35
|
+
|
|
36
|
+
if (controller) {
|
|
37
|
+
instances[uid] = typeof controller === 'function' ? controller({ strapi }) : controller;
|
|
38
|
+
return instances[uid];
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Returns a map with all the controller in a namespace
|
|
44
|
+
* @param {string} namespace
|
|
45
|
+
* @returns {{ [key: string]: Controller }}
|
|
46
|
+
*/
|
|
47
|
+
getAll(namespace) {
|
|
48
|
+
const filteredControllers = pickBy((_, uid) => hasNamespace(uid, namespace))(controllers);
|
|
49
|
+
|
|
50
|
+
const map = {};
|
|
51
|
+
for (const uid in filteredControllers) {
|
|
52
|
+
Object.defineProperty(map, uid, {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
get: () => {
|
|
55
|
+
return this.get(uid);
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return map;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Registers a controller
|
|
65
|
+
* @param {string} uid
|
|
66
|
+
* @param {Controller} controller
|
|
67
|
+
*/
|
|
68
|
+
set(uid, value) {
|
|
69
|
+
controllers[uid] = value;
|
|
70
|
+
delete instances[uid];
|
|
71
|
+
return this;
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Registers a map of controllers for a specific namespace
|
|
76
|
+
* @param {string} namespace
|
|
77
|
+
* @param {{ [key: string]: Controller|ControllerFactory }} newControllers
|
|
78
|
+
* @returns
|
|
79
|
+
*/
|
|
80
|
+
add(namespace, newControllers) {
|
|
81
|
+
for (const controllerName in newControllers) {
|
|
82
|
+
const controller = newControllers[controllerName];
|
|
83
|
+
const uid = addNamespace(controllerName, namespace);
|
|
84
|
+
|
|
85
|
+
if (has(uid, controllers)) {
|
|
86
|
+
throw new Error(`Controller ${uid} has already been registered.`);
|
|
87
|
+
}
|
|
88
|
+
controllers[uid] = controller;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return this;
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Wraps a controller to extend it
|
|
96
|
+
* @param {string} uid
|
|
97
|
+
* @param {(controller: Controller) => Controller} extendFn
|
|
98
|
+
*/
|
|
99
|
+
extend(controllerUID, extendFn) {
|
|
100
|
+
const currentController = this.get(controllerUID);
|
|
101
|
+
|
|
102
|
+
if (!currentController) {
|
|
103
|
+
throw new Error(`Controller ${controllerUID} doesn't exist`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const newController = extendFn(currentController);
|
|
107
|
+
instances[controllerUID] = newController;
|
|
108
|
+
|
|
109
|
+
return this;
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
module.exports = controllersRegistry;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
type Handler = (context: any) => any;
|
|
3
|
+
|
|
4
|
+
type AsyncHook = {
|
|
5
|
+
handlers: Handler[];
|
|
6
|
+
register(handler: Handler): this;
|
|
7
|
+
delete(handler: Handler): this;
|
|
8
|
+
call(): Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
type SyncHook = {
|
|
13
|
+
get handlers(): Handler[];
|
|
14
|
+
register(handler: Handler): this;
|
|
15
|
+
delete(handler: Handler): this;
|
|
16
|
+
call(): void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export type Hook = AsyncHook|SyncHook
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { pickBy } = require('lodash/fp');
|
|
4
|
+
const { addNamespace, hasNamespace } = require('../utils');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {import('./hooks').Hook} Hook
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const hooksRegistry = () => {
|
|
11
|
+
const hooks = {};
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
/**
|
|
15
|
+
* Returns this list of registered hooks uids
|
|
16
|
+
* @returns {string[]}
|
|
17
|
+
*/
|
|
18
|
+
keys() {
|
|
19
|
+
return Object.keys(hooks);
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Returns the instance of a hook.
|
|
24
|
+
* @param {string} uid
|
|
25
|
+
* @returns {Hook}
|
|
26
|
+
*/
|
|
27
|
+
get(uid) {
|
|
28
|
+
return hooks[uid];
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns a map with all the hooks in a namespace
|
|
33
|
+
* @param {string} namespace
|
|
34
|
+
* @returns {{ [key: string]: Hook }}
|
|
35
|
+
*/
|
|
36
|
+
getAll(namespace) {
|
|
37
|
+
return pickBy((_, uid) => hasNamespace(uid, namespace))(hooks);
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Registers a hook
|
|
42
|
+
* @param {string} uid
|
|
43
|
+
* @param {Hook} hook
|
|
44
|
+
*/
|
|
45
|
+
set(uid, hook) {
|
|
46
|
+
hooks[uid] = hook;
|
|
47
|
+
return this;
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Registers a map of hooks for a specific namespace
|
|
52
|
+
* @param {string} namespace
|
|
53
|
+
* @param {{ [key: string]: Hook }} newHooks
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
add(namespace, hooks) {
|
|
57
|
+
for (const hookName in hooks) {
|
|
58
|
+
const hook = hooks[hookName];
|
|
59
|
+
const uid = addNamespace(hookName, namespace);
|
|
60
|
+
|
|
61
|
+
this.set(uid, hook);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return this;
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Wraps a hook to extend it
|
|
69
|
+
* @param {string} uid
|
|
70
|
+
* @param {(hook: Hook) => Hook} extendFn
|
|
71
|
+
*/
|
|
72
|
+
extend(uid, extendFn) {
|
|
73
|
+
const currentHook = this.get(uid);
|
|
74
|
+
|
|
75
|
+
if (!currentHook) {
|
|
76
|
+
throw new Error(`Hook ${uid} doesn't exist`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const newHook = extendFn(currentHook);
|
|
80
|
+
hooks[uid] = newHook;
|
|
81
|
+
|
|
82
|
+
return this;
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
module.exports = hooksRegistry;
|