@strapi/strapi 4.0.0-beta.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/LICENSE +22 -0
- package/README.md +144 -0
- package/bin/strapi.js +186 -0
- package/lib/Strapi.js +470 -0
- package/lib/commands/admin-reset.js +51 -0
- package/lib/commands/build.js +56 -0
- package/lib/commands/configurationDump.js +50 -0
- package/lib/commands/configurationRestore.js +169 -0
- package/lib/commands/console.js +26 -0
- package/lib/commands/develop.js +157 -0
- package/lib/commands/generate-template.js +97 -0
- package/lib/commands/install.js +48 -0
- package/lib/commands/new.js +11 -0
- package/lib/commands/start.js +8 -0
- package/lib/commands/uninstall.js +68 -0
- package/lib/commands/watchAdmin.js +45 -0
- package/lib/container.js +45 -0
- package/lib/core/app-configuration/config-loader.js +20 -0
- package/lib/core/app-configuration/index.js +75 -0
- package/lib/core/app-configuration/load-config-file.js +43 -0
- package/lib/core/app-configuration/load-functions.js +28 -0
- package/lib/core/bootstrap.js +60 -0
- 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 +106 -0
- package/lib/core/domain/module/validation.js +36 -0
- package/lib/core/loaders/admin.js +16 -0
- package/lib/core/loaders/apis.js +157 -0
- package/lib/core/loaders/components.js +41 -0
- package/lib/core/loaders/index.js +11 -0
- package/lib/core/loaders/middlewares.js +86 -0
- package/lib/core/loaders/plugins/get-enabled-plugins.js +100 -0
- package/lib/core/loaders/plugins/index.js +109 -0
- package/lib/core/loaders/policies.js +28 -0
- package/lib/core/loaders/src-index.js +38 -0
- package/lib/core/registries/apis.js +43 -0
- package/lib/core/registries/config.js +21 -0
- package/lib/core/registries/content-types.js +53 -0
- package/lib/core/registries/controllers.js +43 -0
- package/lib/core/registries/hooks.js +37 -0
- package/lib/core/registries/middlewares.js +30 -0
- package/lib/core/registries/modules.js +44 -0
- package/lib/core/registries/plugins.js +28 -0
- package/lib/core/registries/policies.js +38 -0
- package/lib/core/registries/services.js +58 -0
- package/lib/core/utils.js +35 -0
- package/lib/core-api/controller/collection-type.js +84 -0
- package/lib/core-api/controller/index.js +26 -0
- package/lib/core-api/controller/single-type.js +44 -0
- package/lib/core-api/controller/transform.js +97 -0
- package/lib/core-api/index.js +39 -0
- package/lib/core-api/service/collection-type.js +84 -0
- package/lib/core-api/service/index.js +55 -0
- package/lib/core-api/service/pagination.js +125 -0
- package/lib/core-api/service/single-type.js +58 -0
- package/lib/index.d.ts +26 -0
- package/lib/index.js +3 -0
- package/lib/load/filepath-to-prop-path.js +22 -0
- package/lib/load/glob.js +15 -0
- package/lib/load/index.js +9 -0
- package/lib/load/load-files.js +56 -0
- package/lib/load/package-path.js +9 -0
- package/lib/middlewares/cors/index.js +66 -0
- package/lib/middlewares/error/defaults.json +5 -0
- package/lib/middlewares/error/index.js +147 -0
- package/lib/middlewares/favicon/defaults.json +7 -0
- package/lib/middlewares/favicon/index.js +31 -0
- package/lib/middlewares/gzip/defaults.json +6 -0
- package/lib/middlewares/gzip/index.js +19 -0
- package/lib/middlewares/helmet/defaults.json +18 -0
- package/lib/middlewares/helmet/index.js +9 -0
- package/lib/middlewares/index.js +120 -0
- package/lib/middlewares/ip/defaults.json +7 -0
- package/lib/middlewares/ip/index.js +25 -0
- package/lib/middlewares/logger/defaults.json +5 -0
- package/lib/middlewares/logger/index.js +37 -0
- package/lib/middlewares/parser/defaults.json +11 -0
- package/lib/middlewares/parser/index.js +75 -0
- package/lib/middlewares/poweredBy/defaults.json +5 -0
- package/lib/middlewares/poweredBy/index.js +16 -0
- package/lib/middlewares/public/assets/images/group_people_1.png +0 -0
- package/lib/middlewares/public/assets/images/group_people_2.png +0 -0
- package/lib/middlewares/public/assets/images/group_people_3.png +0 -0
- package/lib/middlewares/public/assets/images/logo_login.png +0 -0
- package/lib/middlewares/public/defaults.json +8 -0
- package/lib/middlewares/public/index.html +66 -0
- package/lib/middlewares/public/index.js +130 -0
- package/lib/middlewares/public/serve-static.js +23 -0
- package/lib/middlewares/responseTime/defaults.json +5 -0
- package/lib/middlewares/responseTime/index.js +25 -0
- package/lib/middlewares/responses/defaults.json +5 -0
- package/lib/middlewares/responses/index.js +19 -0
- package/lib/middlewares/router/defaults.json +7 -0
- package/lib/middlewares/router/index.js +97 -0
- package/lib/middlewares/session/defaults.json +18 -0
- package/lib/middlewares/session/index.js +140 -0
- package/lib/migrations/draft-publish.js +57 -0
- package/lib/services/auth/index.js +92 -0
- package/lib/services/core-store.js +145 -0
- package/lib/services/cron.js +54 -0
- package/lib/services/entity-service/components.js +365 -0
- package/lib/services/entity-service/index.d.ts +91 -0
- package/lib/services/entity-service/index.js +244 -0
- package/lib/services/entity-service/params.js +145 -0
- package/lib/services/entity-validator/index.js +187 -0
- package/lib/services/entity-validator/validators.js +123 -0
- package/lib/services/event-hub.js +15 -0
- package/lib/services/fs.js +58 -0
- package/lib/services/metrics/index.js +104 -0
- package/lib/services/metrics/is-truthy.js +9 -0
- package/lib/services/metrics/middleware.js +33 -0
- package/lib/services/metrics/rate-limiter.js +27 -0
- package/lib/services/metrics/sender.js +76 -0
- package/lib/services/metrics/stringify-deep.js +22 -0
- package/lib/services/server/admin-api.js +14 -0
- package/lib/services/server/api.js +32 -0
- package/lib/services/server/compose-endpoint.js +112 -0
- package/lib/services/server/content-api.js +16 -0
- package/lib/services/server/http-server.js +64 -0
- package/lib/services/server/index.js +108 -0
- package/lib/services/server/middleware.js +28 -0
- package/lib/services/server/policy.js +34 -0
- package/lib/services/server/routing.js +107 -0
- package/lib/services/utils/upload-files.js +79 -0
- package/lib/services/webhook-runner.js +155 -0
- package/lib/services/webhook-store.js +91 -0
- package/lib/services/worker-queue.js +58 -0
- package/lib/utils/addSlash.js +10 -0
- package/lib/utils/ee.js +123 -0
- package/lib/utils/get-dirs.js +15 -0
- package/lib/utils/get-prefixed-dependencies.js +7 -0
- package/lib/utils/index.js +11 -0
- package/lib/utils/is-initialized.js +23 -0
- package/lib/utils/open-browser.js +12 -0
- package/lib/utils/resources/key.pub +9 -0
- package/lib/utils/run-checks.js +22 -0
- package/lib/utils/startup-logger.js +90 -0
- package/lib/utils/success.js +31 -0
- package/lib/utils/update-notifier/index.js +97 -0
- package/lib/utils/url-from-segments.js +12 -0
- package/package.json +133 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const _ = require('lodash');
|
|
5
|
+
const isDocker = require('is-docker');
|
|
6
|
+
const { machineIdSync } = require('node-machine-id');
|
|
7
|
+
const fetch = require('node-fetch');
|
|
8
|
+
const ciEnv = require('ci-info');
|
|
9
|
+
const ee = require('../../utils/ee');
|
|
10
|
+
const stringifyDeep = require('./stringify-deep');
|
|
11
|
+
|
|
12
|
+
const defaultQueryOpts = {
|
|
13
|
+
timeout: 1000,
|
|
14
|
+
headers: { 'Content-Type': 'application/json' },
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const ANALYTICS_URI = 'https://analytics.strapi.io';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Add properties from the package.json strapi key in the metadata
|
|
21
|
+
* @param {object} metadata
|
|
22
|
+
*/
|
|
23
|
+
const addPackageJsonStrapiMetadata = (metadata, strapi) => {
|
|
24
|
+
const { packageJsonStrapi = {} } = strapi.config;
|
|
25
|
+
|
|
26
|
+
_.defaults(metadata, packageJsonStrapi);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create a send function for event with all the necessary metadatas
|
|
31
|
+
* @param {Object} strapi strapi app
|
|
32
|
+
* @returns {Function} (event, payload) -> Promise{boolean}
|
|
33
|
+
*/
|
|
34
|
+
module.exports = strapi => {
|
|
35
|
+
const { uuid } = strapi.config;
|
|
36
|
+
const deviceId = machineIdSync();
|
|
37
|
+
const isEE = strapi.EE === true && ee.isEE === true;
|
|
38
|
+
|
|
39
|
+
const anonymous_metadata = {
|
|
40
|
+
environment: strapi.config.environment,
|
|
41
|
+
os: os.type(),
|
|
42
|
+
osPlatform: os.platform(),
|
|
43
|
+
osRelease: os.release(),
|
|
44
|
+
nodeVersion: process.version,
|
|
45
|
+
docker: process.env.DOCKER || isDocker(),
|
|
46
|
+
isCI: ciEnv.isCI,
|
|
47
|
+
version: strapi.config.get('info.strapi'),
|
|
48
|
+
strapiVersion: strapi.config.get('info.strapi'),
|
|
49
|
+
projectType: isEE ? 'Enterprise' : 'Community',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
addPackageJsonStrapiMetadata(anonymous_metadata, strapi);
|
|
53
|
+
|
|
54
|
+
return async (event, payload = {}, opts = {}) => {
|
|
55
|
+
const reqParams = {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
event,
|
|
59
|
+
uuid,
|
|
60
|
+
deviceId,
|
|
61
|
+
properties: stringifyDeep({
|
|
62
|
+
...payload,
|
|
63
|
+
...anonymous_metadata,
|
|
64
|
+
}),
|
|
65
|
+
}),
|
|
66
|
+
..._.merge({}, defaultQueryOpts, opts),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const res = await fetch(`${ANALYTICS_URI}/track`, reqParams);
|
|
71
|
+
return res.ok;
|
|
72
|
+
} catch (err) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { map, mapValues, isObject, isArray, toString } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Stringify all non object valutes before send them
|
|
7
|
+
* @param {object} obj
|
|
8
|
+
* @returns {object}
|
|
9
|
+
*/
|
|
10
|
+
const stringifyDeep = value => {
|
|
11
|
+
if (isArray(value)) {
|
|
12
|
+
return map(stringifyDeep, value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (isObject(value)) {
|
|
16
|
+
return mapValues(stringifyDeep, value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return toString(value);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
module.exports = stringifyDeep;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Router = require('@koa/router');
|
|
4
|
+
|
|
5
|
+
const { createRouteManager } = require('./routing');
|
|
6
|
+
|
|
7
|
+
const createAPI = (strapi, opts = {}) => {
|
|
8
|
+
const { prefix, type } = opts;
|
|
9
|
+
|
|
10
|
+
const api = new Router({ prefix });
|
|
11
|
+
|
|
12
|
+
const routeManager = createRouteManager(strapi, { type });
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
use(fn) {
|
|
16
|
+
api.use(fn);
|
|
17
|
+
return this;
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
routes(routes) {
|
|
21
|
+
routeManager.addRoutes(routes, api);
|
|
22
|
+
return this;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
mount(router) {
|
|
26
|
+
router.use(api.routes(), api.allowedMethods());
|
|
27
|
+
return this;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = { createAPI };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { toLower, castArray, trim, prop } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const compose = require('koa-compose');
|
|
6
|
+
const { resolveMiddlewares } = require('./middleware');
|
|
7
|
+
const { resolvePolicies } = require('./policy');
|
|
8
|
+
|
|
9
|
+
const getMethod = route => trim(toLower(route.method));
|
|
10
|
+
const getPath = route => trim(route.path);
|
|
11
|
+
|
|
12
|
+
const createRouteInfoMiddleware = routeInfo => (ctx, next) => {
|
|
13
|
+
const route = {
|
|
14
|
+
...routeInfo,
|
|
15
|
+
config: routeInfo.config || {},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
ctx.state.route = route;
|
|
19
|
+
return next();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const getAuthConfig = prop('config.auth');
|
|
23
|
+
|
|
24
|
+
const createAuthorizeMiddleware = strapi => async (ctx, next) => {
|
|
25
|
+
const { auth, route } = ctx.state;
|
|
26
|
+
|
|
27
|
+
const authService = strapi.container.get('auth');
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
await authService.verify(auth, getAuthConfig(route));
|
|
31
|
+
|
|
32
|
+
return next();
|
|
33
|
+
} catch (error) {
|
|
34
|
+
const { UnauthorizedError, ForbiddenError } = authService.errors;
|
|
35
|
+
|
|
36
|
+
if (error instanceof UnauthorizedError) {
|
|
37
|
+
return ctx.unauthorized();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (error instanceof ForbiddenError) {
|
|
41
|
+
return ctx.forbidden();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const createAuthenticateMiddleware = strapi => async (ctx, next) => {
|
|
49
|
+
return strapi.container.get('auth').authenticate(ctx, next);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
module.exports = strapi => {
|
|
53
|
+
const authenticate = createAuthenticateMiddleware(strapi);
|
|
54
|
+
const authorize = createAuthorizeMiddleware(strapi);
|
|
55
|
+
|
|
56
|
+
return (route, { router }) => {
|
|
57
|
+
try {
|
|
58
|
+
const method = getMethod(route);
|
|
59
|
+
const path = getPath(route);
|
|
60
|
+
|
|
61
|
+
const middlewares = resolveMiddlewares(route);
|
|
62
|
+
const policies = resolvePolicies(route);
|
|
63
|
+
|
|
64
|
+
const action = getAction(route, strapi);
|
|
65
|
+
|
|
66
|
+
const routeHandler = compose([
|
|
67
|
+
createRouteInfoMiddleware(route),
|
|
68
|
+
authenticate,
|
|
69
|
+
authorize,
|
|
70
|
+
...policies,
|
|
71
|
+
...middlewares,
|
|
72
|
+
...castArray(action),
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
router[method](path, routeHandler);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
throw new Error(`Error creating endpoint ${route.method} ${route.path}: ${error.message}`);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const getController = (name, { pluginName, apiName }, strapi) => {
|
|
83
|
+
if (pluginName) {
|
|
84
|
+
if (pluginName === 'admin') {
|
|
85
|
+
return strapi.controller(`admin::${name}`);
|
|
86
|
+
}
|
|
87
|
+
return strapi.plugin(pluginName).controller(name);
|
|
88
|
+
} else if (apiName) {
|
|
89
|
+
return strapi.controller(`api::${apiName}.${name}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return strapi.controller(name);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const getAction = (route, strapi) => {
|
|
96
|
+
const { handler, info = {} } = route;
|
|
97
|
+
const { pluginName, apiName } = info;
|
|
98
|
+
|
|
99
|
+
if (Array.isArray(handler) || typeof handler === 'function') {
|
|
100
|
+
return handler;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const [controllerName, actionName] = trim(handler).split('.');
|
|
104
|
+
|
|
105
|
+
const controller = getController(toLower(controllerName), { pluginName, apiName }, strapi);
|
|
106
|
+
|
|
107
|
+
if (typeof controller[actionName] !== 'function') {
|
|
108
|
+
throw new Error(`Handler not found "${handler}"`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return controller[actionName].bind(controller);
|
|
112
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createAPI } = require('./api');
|
|
4
|
+
|
|
5
|
+
const createContentAPI = strapi => {
|
|
6
|
+
const opts = {
|
|
7
|
+
prefix: strapi.config.get('api.prefix', '/api'),
|
|
8
|
+
type: 'content-api',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
return createAPI(strapi, opts);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
createContentAPI,
|
|
16
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const http = require('http');
|
|
4
|
+
|
|
5
|
+
const createHTTPServer = (strapi, koaApp) => {
|
|
6
|
+
const connections = new Set();
|
|
7
|
+
|
|
8
|
+
// lazy creation of the request listener
|
|
9
|
+
let handler;
|
|
10
|
+
const listener = function handleRequest(req, res) {
|
|
11
|
+
if (!handler) {
|
|
12
|
+
handler = koaApp.callback();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return handler(req, res);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const server = http.createServer(listener);
|
|
19
|
+
|
|
20
|
+
server.on('connection', connection => {
|
|
21
|
+
connections.add(connection);
|
|
22
|
+
|
|
23
|
+
connection.on('close', () => {
|
|
24
|
+
connections.delete(connection);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// handle port in use cleanly
|
|
29
|
+
server.on('error', err => {
|
|
30
|
+
if (err.code === 'EADDRINUSE') {
|
|
31
|
+
return strapi.stopWithError(`The port ${err.port} is already used by another application.`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
strapi.log.error(err);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
server.destroy = async () => {
|
|
38
|
+
for (const connection of connections) {
|
|
39
|
+
connection.destroy();
|
|
40
|
+
|
|
41
|
+
connections.delete(connection);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!server.listening) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return new Promise((resolve, reject) =>
|
|
49
|
+
server.close(error => {
|
|
50
|
+
if (error) {
|
|
51
|
+
return reject(error);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
resolve();
|
|
55
|
+
})
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return server;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
createHTTPServer,
|
|
64
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Koa = require('koa');
|
|
4
|
+
const Router = require('@koa/router');
|
|
5
|
+
|
|
6
|
+
const { createHTTPServer } = require('./http-server');
|
|
7
|
+
const { createRouteManager } = require('./routing');
|
|
8
|
+
const { createAdminAPI } = require('./admin-api');
|
|
9
|
+
const { createContentAPI } = require('./content-api');
|
|
10
|
+
|
|
11
|
+
const healthCheck = async ctx => {
|
|
12
|
+
ctx.set('strapi', 'You are so French!');
|
|
13
|
+
ctx.status = 204;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef Server
|
|
18
|
+
*
|
|
19
|
+
* @property {Koa} app
|
|
20
|
+
* @property {http.Server} app
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @param {Strapi} strapi
|
|
26
|
+
* @returns {Server}
|
|
27
|
+
*/
|
|
28
|
+
const createServer = strapi => {
|
|
29
|
+
const app = new Koa({
|
|
30
|
+
proxy: strapi.config.get('server.proxy'),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const router = new Router({
|
|
34
|
+
// FIXME: this prefix can break the admin if not specified in the admin url
|
|
35
|
+
prefix: strapi.config.get('middleware.settings.router.prefix', ''),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const routeManager = createRouteManager(strapi);
|
|
39
|
+
|
|
40
|
+
const httpServer = createHTTPServer(strapi, app);
|
|
41
|
+
|
|
42
|
+
const apis = {
|
|
43
|
+
'content-api': createContentAPI(strapi),
|
|
44
|
+
admin: createAdminAPI(strapi),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// init health check
|
|
48
|
+
router.all('/_health', healthCheck);
|
|
49
|
+
|
|
50
|
+
const state = {
|
|
51
|
+
mounted: false,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
app,
|
|
56
|
+
router,
|
|
57
|
+
httpServer,
|
|
58
|
+
|
|
59
|
+
api(name) {
|
|
60
|
+
return apis[name];
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
use(...args) {
|
|
64
|
+
app.use(...args);
|
|
65
|
+
return this;
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
routes(routes) {
|
|
69
|
+
if (routes.type) {
|
|
70
|
+
const api = apis[routes.type];
|
|
71
|
+
if (!api) {
|
|
72
|
+
throw new Error(`API ${routes.type} not found. Possible APIs are ${Object.keys(apis)}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
apis[routes.type].routes(routes);
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
routeManager.addRoutes(routes, router);
|
|
80
|
+
return this;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
mount() {
|
|
84
|
+
state.mounted = true;
|
|
85
|
+
|
|
86
|
+
Object.values(apis).forEach(api => api.mount(router));
|
|
87
|
+
app.use(router.routes()).use(router.allowedMethods());
|
|
88
|
+
|
|
89
|
+
return this;
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
listen(...args) {
|
|
93
|
+
if (!state.mounted) {
|
|
94
|
+
this.mount();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return httpServer.listen(...args);
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
async destroy() {
|
|
101
|
+
await httpServer.destroy();
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
module.exports = {
|
|
107
|
+
createServer,
|
|
108
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { propOr } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const getMiddlewareConfig = propOr([], 'config.middlewares');
|
|
6
|
+
|
|
7
|
+
const resolveMiddlewares = route => {
|
|
8
|
+
const middlewaresConfig = getMiddlewareConfig(route);
|
|
9
|
+
|
|
10
|
+
return middlewaresConfig.map(middlewareConfig => {
|
|
11
|
+
if (typeof middlewareConfig === 'function') {
|
|
12
|
+
return middlewareConfig;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// TODO: this won't work until we have the new middleware formats
|
|
16
|
+
const middleware = strapi.middleware(middlewareConfig);
|
|
17
|
+
|
|
18
|
+
if (!middleware) {
|
|
19
|
+
throw new Error(`Middleware ${middlewareConfig} not found.`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return middleware;
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
resolveMiddlewares,
|
|
28
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { propOr } = require('lodash/fp');
|
|
4
|
+
const policy = require('@strapi/utils/lib/policy');
|
|
5
|
+
|
|
6
|
+
const { bodyPolicy } = policy;
|
|
7
|
+
|
|
8
|
+
const getPoliciesConfig = propOr([], 'config.policies');
|
|
9
|
+
|
|
10
|
+
const resolvePolicies = route => {
|
|
11
|
+
const { pluginName, apiName } = route.info || {};
|
|
12
|
+
const policiesConfig = getPoliciesConfig(route);
|
|
13
|
+
|
|
14
|
+
const policiesMiddleware = async (ctx, next) => {
|
|
15
|
+
const context = policy.createPolicyContext('koa', ctx);
|
|
16
|
+
|
|
17
|
+
for (const policyName of policiesConfig) {
|
|
18
|
+
const resolvedPolicy = await policy.get(policyName, { pluginName, apiName });
|
|
19
|
+
const result = await resolvedPolicy({ ctx: context, strapi });
|
|
20
|
+
|
|
21
|
+
if (![true, undefined].includes(result)) {
|
|
22
|
+
throw new Error('Policies failed.');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
await next();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return [policiesMiddleware, bodyPolicy];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
resolvePolicies,
|
|
34
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
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
|
+
policies: yup
|
|
48
|
+
.array()
|
|
49
|
+
.of(policyOrMiddlewareSchema)
|
|
50
|
+
.notRequired(),
|
|
51
|
+
middlwares: yup
|
|
52
|
+
.array()
|
|
53
|
+
.of(policyOrMiddlewareSchema)
|
|
54
|
+
.notRequired(),
|
|
55
|
+
})
|
|
56
|
+
.notRequired(),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const validateRouteConfig = routeConfig => {
|
|
60
|
+
try {
|
|
61
|
+
return routeSchema.validateSync(routeConfig, {
|
|
62
|
+
strict: true,
|
|
63
|
+
abortEarly: false,
|
|
64
|
+
stripUnknown: true,
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
throw new Error('Invalid route config', error.message);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const createRouteManager = (strapi, opts = {}) => {
|
|
72
|
+
const { type } = opts;
|
|
73
|
+
|
|
74
|
+
const composeEndpoint = createEndpointComposer(strapi);
|
|
75
|
+
|
|
76
|
+
const createRoute = (route, router) => {
|
|
77
|
+
validateRouteConfig(route);
|
|
78
|
+
|
|
79
|
+
_.set(route, 'info.type', type || 'admin');
|
|
80
|
+
|
|
81
|
+
composeEndpoint(route, { router });
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const addRoutes = (routes, router) => {
|
|
85
|
+
if (Array.isArray(routes)) {
|
|
86
|
+
routes.forEach(route => createRoute(route, router));
|
|
87
|
+
} else if (routes.routes) {
|
|
88
|
+
const subRouter = new Router({ prefix: routes.prefix });
|
|
89
|
+
|
|
90
|
+
routes.routes.forEach(route => {
|
|
91
|
+
const hasPrefix = has('prefix', route.config);
|
|
92
|
+
createRoute(route, hasPrefix ? router : subRouter);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return router.use(subRouter.routes(), subRouter.allowedMethods());
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
addRoutes,
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
validateRouteConfig,
|
|
106
|
+
createRouteManager,
|
|
107
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Upload files and like them to an entity
|
|
7
|
+
* @param {string} uid model uid
|
|
8
|
+
* @param {object} entity entity created
|
|
9
|
+
* @param {object} files files to upload
|
|
10
|
+
* @returns {void}
|
|
11
|
+
*/
|
|
12
|
+
module.exports = async (uid, entity, files) => {
|
|
13
|
+
const modelDef = strapi.getModel(uid);
|
|
14
|
+
|
|
15
|
+
if (!_.has(strapi.plugins, 'upload')) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const uploadService = strapi.plugin('upload').service('upload');
|
|
20
|
+
|
|
21
|
+
const findModelFromUploadPath = path => {
|
|
22
|
+
if (path.length === 0) {
|
|
23
|
+
return uid;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let currentPath = [];
|
|
27
|
+
let tmpModel = modelDef;
|
|
28
|
+
let modelUID = uid;
|
|
29
|
+
|
|
30
|
+
for (let i = 0; i < path.length; i++) {
|
|
31
|
+
if (!tmpModel) return {};
|
|
32
|
+
const part = path[i];
|
|
33
|
+
const attr = tmpModel.attributes[part];
|
|
34
|
+
|
|
35
|
+
currentPath.push(part);
|
|
36
|
+
|
|
37
|
+
// ignore array indexes => handled in the dynamic zone section
|
|
38
|
+
if (_.isFinite(_.toNumber(path[i]))) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!attr) return {};
|
|
43
|
+
|
|
44
|
+
if (attr.type === 'component') {
|
|
45
|
+
modelUID = attr.component;
|
|
46
|
+
tmpModel = strapi.components[attr.component];
|
|
47
|
+
} else if (attr.type === 'dynamiczone') {
|
|
48
|
+
const entryIdx = path[i + 1]; // get component index
|
|
49
|
+
const value = _.get(entity, [...currentPath, entryIdx]);
|
|
50
|
+
|
|
51
|
+
if (!value) return {};
|
|
52
|
+
|
|
53
|
+
modelUID = value.__component; // get component type
|
|
54
|
+
tmpModel = strapi.components[modelUID];
|
|
55
|
+
} else if (attr.type === 'relation') {
|
|
56
|
+
modelUID = attr.target;
|
|
57
|
+
tmpModel = strapi.getModel(modelUID);
|
|
58
|
+
} else {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return modelUID;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const doUpload = async (key, files) => {
|
|
67
|
+
const parts = key.split('.');
|
|
68
|
+
const [path, field] = [_.initial(parts), _.last(parts)];
|
|
69
|
+
|
|
70
|
+
const modelUID = findModelFromUploadPath(path);
|
|
71
|
+
|
|
72
|
+
if (modelUID) {
|
|
73
|
+
const id = _.get(entity, path.concat('id'));
|
|
74
|
+
return uploadService.uploadToEntity({ id, model: modelUID, field }, files);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
await Promise.all(Object.keys(files).map(key => doUpload(key, files[key])));
|
|
79
|
+
};
|