@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,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;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
const createRouteScopeGenerator = namespace => route => {
|
|
6
|
+
const prefix = namespace.endsWith('::') ? namespace : `${namespace}.`;
|
|
7
|
+
|
|
8
|
+
if (typeof route.handler === 'string') {
|
|
9
|
+
_.defaultsDeep(route, {
|
|
10
|
+
config: {
|
|
11
|
+
auth: {
|
|
12
|
+
scope: [`${route.handler.startsWith(prefix) ? '' : prefix}${route.handler}`],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Register all routes
|
|
21
|
+
* @param {import('../../').Strapi} strapi
|
|
22
|
+
*/
|
|
23
|
+
module.exports = strapi => {
|
|
24
|
+
registerAdminRoutes(strapi);
|
|
25
|
+
registerAPIRoutes(strapi);
|
|
26
|
+
registerPluginRoutes(strapi);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Register admin routes
|
|
31
|
+
* @param {import('../../').Strapi} strapi
|
|
32
|
+
*/
|
|
33
|
+
const registerAdminRoutes = strapi => {
|
|
34
|
+
const generateRouteScope = createRouteScopeGenerator(`admin::`);
|
|
35
|
+
|
|
36
|
+
strapi.admin.routes.forEach(route => {
|
|
37
|
+
generateRouteScope(route);
|
|
38
|
+
route.info = { pluginName: 'admin' };
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
strapi.server.routes({
|
|
42
|
+
type: 'admin',
|
|
43
|
+
prefix: '/admin',
|
|
44
|
+
routes: strapi.admin.routes,
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Register plugin routes
|
|
50
|
+
* @param {import('../../').Strapi} strapi
|
|
51
|
+
*/
|
|
52
|
+
const registerPluginRoutes = strapi => {
|
|
53
|
+
for (const pluginName in strapi.plugins) {
|
|
54
|
+
const plugin = strapi.plugins[pluginName];
|
|
55
|
+
|
|
56
|
+
const generateRouteScope = createRouteScopeGenerator(`plugin::${pluginName}`);
|
|
57
|
+
|
|
58
|
+
if (Array.isArray(plugin.routes)) {
|
|
59
|
+
plugin.routes.forEach(route => {
|
|
60
|
+
generateRouteScope(route);
|
|
61
|
+
route.info = { pluginName };
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
strapi.server.routes({
|
|
65
|
+
type: 'admin',
|
|
66
|
+
prefix: `/${pluginName}`,
|
|
67
|
+
routes: plugin.routes,
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
_.forEach(plugin.routes, router => {
|
|
71
|
+
router.type = router.type || 'admin';
|
|
72
|
+
router.prefix = `/${pluginName}`;
|
|
73
|
+
router.routes.forEach(route => {
|
|
74
|
+
generateRouteScope(route);
|
|
75
|
+
route.info = { pluginName };
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
strapi.server.routes(router);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Register api routes
|
|
86
|
+
* @param {import('../../').Strapi} strapi
|
|
87
|
+
*/
|
|
88
|
+
const registerAPIRoutes = strapi => {
|
|
89
|
+
for (const apiName in strapi.api) {
|
|
90
|
+
const api = strapi.api[apiName];
|
|
91
|
+
|
|
92
|
+
const generateRouteScope = createRouteScopeGenerator(`api::${apiName}`);
|
|
93
|
+
|
|
94
|
+
_.forEach(api.routes, router => {
|
|
95
|
+
// TODO: remove once auth setup
|
|
96
|
+
// pass meta down to compose endpoint
|
|
97
|
+
router.type = 'content-api';
|
|
98
|
+
router.routes.forEach(route => {
|
|
99
|
+
generateRouteScope(route);
|
|
100
|
+
route.info = { apiName };
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return strapi.server.routes(router);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Router = require('@koa/router');
|
|
4
|
+
const _ = require('lodash');
|
|
5
|
+
const { has } = require('lodash/fp');
|
|
6
|
+
const { yup } = require('@strapi/utils');
|
|
7
|
+
|
|
8
|
+
const createEndpointComposer = require('./compose-endpoint');
|
|
9
|
+
|
|
10
|
+
const policyOrMiddlewareSchema = yup.lazy(value => {
|
|
11
|
+
if (typeof value === 'string') {
|
|
12
|
+
return yup.string().required();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (typeof value === 'function') {
|
|
16
|
+
return yup.mixed().isFunction();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return yup.object({
|
|
20
|
+
name: yup.string().required(),
|
|
21
|
+
options: yup.object().notRequired(), // any options
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const routeSchema = yup.object({
|
|
26
|
+
method: yup
|
|
27
|
+
.string()
|
|
28
|
+
.oneOf(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'ALL'])
|
|
29
|
+
.required(),
|
|
30
|
+
path: yup.string().required(),
|
|
31
|
+
handler: yup.lazy(value => {
|
|
32
|
+
if (typeof value === 'string') {
|
|
33
|
+
return yup.string().required();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
return yup.array().required();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return yup
|
|
41
|
+
.mixed()
|
|
42
|
+
.isFunction()
|
|
43
|
+
.required();
|
|
44
|
+
}),
|
|
45
|
+
config: yup
|
|
46
|
+
.object({
|
|
47
|
+
auth: yup.lazy(value => {
|
|
48
|
+
if (value === false) {
|
|
49
|
+
return yup.boolean().required();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return yup.object({
|
|
53
|
+
scope: yup
|
|
54
|
+
.array()
|
|
55
|
+
.of(yup.string())
|
|
56
|
+
.required(),
|
|
57
|
+
});
|
|
58
|
+
}),
|
|
59
|
+
policies: yup
|
|
60
|
+
.array()
|
|
61
|
+
.of(policyOrMiddlewareSchema)
|
|
62
|
+
.notRequired(),
|
|
63
|
+
middlewares: yup
|
|
64
|
+
.array()
|
|
65
|
+
.of(policyOrMiddlewareSchema)
|
|
66
|
+
.notRequired(),
|
|
67
|
+
})
|
|
68
|
+
.notRequired(),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const validateRouteConfig = routeConfig => {
|
|
72
|
+
try {
|
|
73
|
+
return routeSchema.validateSync(routeConfig, {
|
|
74
|
+
strict: true,
|
|
75
|
+
abortEarly: false,
|
|
76
|
+
stripUnknown: true,
|
|
77
|
+
});
|
|
78
|
+
} catch (error) {
|
|
79
|
+
throw new Error('Invalid route config', error.message);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const createRouteManager = (strapi, opts = {}) => {
|
|
84
|
+
const { type } = opts;
|
|
85
|
+
|
|
86
|
+
const composeEndpoint = createEndpointComposer(strapi);
|
|
87
|
+
|
|
88
|
+
const createRoute = (route, router) => {
|
|
89
|
+
validateRouteConfig(route);
|
|
90
|
+
|
|
91
|
+
// NOTE: the router type is used to tag controller actions and for authentication / authorization so we need to pass this info down to the route level
|
|
92
|
+
_.set(route, 'info.type', type || 'admin');
|
|
93
|
+
|
|
94
|
+
composeEndpoint(route, { router });
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const addRoutes = (routes, router) => {
|
|
98
|
+
if (Array.isArray(routes)) {
|
|
99
|
+
routes.forEach(route => createRoute(route, router));
|
|
100
|
+
} else if (routes.routes) {
|
|
101
|
+
const subRouter = new Router({ prefix: routes.prefix });
|
|
102
|
+
|
|
103
|
+
routes.routes.forEach(route => {
|
|
104
|
+
const hasPrefix = has('prefix', route.config);
|
|
105
|
+
createRoute(route, hasPrefix ? router : subRouter);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return router.use(subRouter.routes(), subRouter.allowedMethods());
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
addRoutes,
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
module.exports = {
|
|
118
|
+
validateRouteConfig,
|
|
119
|
+
createRouteManager,
|
|
120
|
+
};
|
|
@@ -16,7 +16,7 @@ module.exports = async (uid, entity, files) => {
|
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const uploadService = strapi.
|
|
19
|
+
const uploadService = strapi.plugin('upload').service('upload');
|
|
20
20
|
|
|
21
21
|
const findModelFromUploadPath = path => {
|
|
22
22
|
if (path.length === 0) {
|
package/lib/utils/ee.js
CHANGED
|
@@ -78,7 +78,7 @@ module.exports = ({ dir, logger = noLog }) => {
|
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
Object.defineProperty(module.exports, 'licenseInfo', {
|
|
81
|
-
get
|
|
81
|
+
get() {
|
|
82
82
|
mustHaveKey('licenseInfo');
|
|
83
83
|
return internals.licenseInfo;
|
|
84
84
|
},
|
|
@@ -87,7 +87,7 @@ Object.defineProperty(module.exports, 'licenseInfo', {
|
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
Object.defineProperty(module.exports, 'isEE', {
|
|
90
|
-
get
|
|
90
|
+
get() {
|
|
91
91
|
mustHaveKey('isEE');
|
|
92
92
|
return internals.isEE;
|
|
93
93
|
},
|
|
@@ -96,7 +96,7 @@ Object.defineProperty(module.exports, 'isEE', {
|
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
Object.defineProperty(module.exports, 'features', {
|
|
99
|
-
get
|
|
99
|
+
get() {
|
|
100
100
|
mustHaveKey('licenseInfo');
|
|
101
101
|
|
|
102
102
|
const { type: licenseType } = module.exports.licenseInfo;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { join } = require('path');
|
|
4
|
+
|
|
5
|
+
const getDirs = root => ({
|
|
6
|
+
root,
|
|
7
|
+
src: join(root, 'src'),
|
|
8
|
+
api: join(root, 'src', 'api'),
|
|
9
|
+
components: join(root, 'src', 'components'),
|
|
10
|
+
extensions: join(root, 'src', 'extensions'),
|
|
11
|
+
policies: join(root, 'src', 'policies'),
|
|
12
|
+
middlewares: join(root, 'src', 'middlewares'),
|
|
13
|
+
config: join(root, 'config'),
|
|
14
|
+
public: join(root, 'public'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
module.exports = getDirs;
|
package/lib/utils/index.js
CHANGED
|
@@ -14,7 +14,7 @@ module.exports = async function isInitialized(strapi) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// test if there is at least one admin
|
|
17
|
-
const anyAdministrator = await strapi.query('
|
|
17
|
+
const anyAdministrator = await strapi.query('admin::user').findOne({ select: ['id'] });
|
|
18
18
|
|
|
19
19
|
return !isNil(anyAdministrator);
|
|
20
20
|
} catch (err) {
|
package/lib/utils/run-checks.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const fs = require('fs-extra');
|
|
5
|
-
const _ = require('lodash');
|
|
6
5
|
|
|
7
6
|
const requiredPaths = ['api', 'extensions', 'plugins', 'config', 'public'];
|
|
8
7
|
const checkFoldersExist = ({ appPath }) => {
|
|
@@ -18,20 +17,6 @@ const checkFoldersExist = ({ appPath }) => {
|
|
|
18
17
|
}
|
|
19
18
|
};
|
|
20
19
|
|
|
21
|
-
const checkPluginsConflicts = ({ appPath, installedPlugins }) => {
|
|
22
|
-
const localPluginNames = fs.readdirSync(path.resolve(appPath, 'plugins'));
|
|
23
|
-
const pluginsIntersection = _.intersection(localPluginNames, installedPlugins);
|
|
24
|
-
|
|
25
|
-
if (pluginsIntersection.length > 0) {
|
|
26
|
-
throw new Error(
|
|
27
|
-
`You have some local plugins with the same name as npm installed plugins:\n${pluginsIntersection
|
|
28
|
-
.map(p => `- ${p}`)
|
|
29
|
-
.join('\n')}`
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
20
|
module.exports = config => {
|
|
35
21
|
checkFoldersExist(config);
|
|
36
|
-
checkPluginsConflicts(config);
|
|
37
22
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const destroyOnSignal = strapi => {
|
|
4
|
+
let signalReceived = false;
|
|
5
|
+
|
|
6
|
+
// For unknown reasons, we receive signals 2 times.
|
|
7
|
+
// As a temporary fix, we ignore the signals received after the first one.
|
|
8
|
+
|
|
9
|
+
const terminateStrapi = async () => {
|
|
10
|
+
if (!signalReceived) {
|
|
11
|
+
signalReceived = true;
|
|
12
|
+
await strapi.destroy();
|
|
13
|
+
process.exit();
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
['SIGTERM', 'SIGINT'].forEach(signal => {
|
|
18
|
+
process.on(signal, terminateStrapi);
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
destroyOnSignal,
|
|
24
|
+
};
|
|
@@ -72,7 +72,7 @@ module.exports = app => {
|
|
|
72
72
|
console.log();
|
|
73
73
|
},
|
|
74
74
|
|
|
75
|
-
logStartupMessage(isInitialized) {
|
|
75
|
+
logStartupMessage({ isInitialized } = {}) {
|
|
76
76
|
// Should the startup message be displayed?
|
|
77
77
|
const hideStartupMessage = process.env.STRAPI_HIDE_STARTUP_MESSAGE
|
|
78
78
|
? process.env.STRAPI_HIDE_STARTUP_MESSAGE === 'true'
|
|
@@ -82,7 +82,7 @@ module.exports = app => {
|
|
|
82
82
|
if (!isInitialized) {
|
|
83
83
|
this.logFirstStartupMessage();
|
|
84
84
|
} else {
|
|
85
|
-
this.
|
|
85
|
+
this.logDefaultStartupMessage();
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
},
|
|
@@ -27,7 +27,7 @@ const geUpdatetMessage = (newVersion, currentVersion) => {
|
|
|
27
27
|
|
|
28
28
|
return `
|
|
29
29
|
A new version of Strapi is available ${currentVersionLog} → ${newVersionLog}
|
|
30
|
-
Check out the new
|
|
30
|
+
Check out the new releases at: ${releaseLink}
|
|
31
31
|
`.trim();
|
|
32
32
|
};
|
|
33
33
|
|
|
@@ -38,7 +38,7 @@ const createUpdateNotifier = strapi => {
|
|
|
38
38
|
config = new Configstore(
|
|
39
39
|
pkg.name,
|
|
40
40
|
{},
|
|
41
|
-
{ configPath: path.join(strapi.
|
|
41
|
+
{ configPath: path.join(strapi.dirs.root, '.strapi-updater.json') }
|
|
42
42
|
);
|
|
43
43
|
} catch {
|
|
44
44
|
// we don't have write access to the file system
|
|
@@ -67,6 +67,7 @@ const createUpdateNotifier = strapi => {
|
|
|
67
67
|
const now = Date.now();
|
|
68
68
|
const latestVersion = config.get('latest');
|
|
69
69
|
const lastNotification = config.get('lastNotification') || 0;
|
|
70
|
+
|
|
70
71
|
if (
|
|
71
72
|
!process.stdout.isTTY ||
|
|
72
73
|
lastNotification + notifInterval > now ||
|