@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.
Files changed (166) hide show
  1. package/README.md +12 -12
  2. package/bin/strapi.js +41 -60
  3. package/lib/Strapi.js +234 -114
  4. package/lib/commands/build.js +16 -6
  5. package/lib/commands/console.js +1 -1
  6. package/lib/commands/content-types/list.js +22 -0
  7. package/lib/commands/develop.js +17 -18
  8. package/lib/commands/generate-template.js +4 -5
  9. package/lib/commands/hooks/list.js +22 -0
  10. package/lib/commands/middlewares/list.js +22 -0
  11. package/lib/commands/new.js +3 -1
  12. package/lib/commands/policies/list.js +22 -0
  13. package/lib/commands/routes/list.js +28 -0
  14. package/lib/commands/services/list.js +22 -0
  15. package/lib/commands/watchAdmin.js +18 -8
  16. package/lib/container.js +6 -6
  17. package/lib/core/app-configuration/config-loader.js +1 -37
  18. package/lib/core/app-configuration/index.js +6 -46
  19. package/lib/core/app-configuration/load-config-file.js +43 -0
  20. package/lib/core/bootstrap.js +5 -117
  21. package/lib/core/domain/component/index.js +24 -0
  22. package/lib/core/domain/component/validator.js +29 -0
  23. package/lib/core/domain/content-type/index.js +140 -0
  24. package/lib/core/domain/content-type/validator.js +64 -0
  25. package/lib/core/domain/module/index.js +108 -0
  26. package/lib/core/domain/module/validation.js +33 -0
  27. package/lib/core/loaders/admin.js +16 -0
  28. package/lib/core/loaders/apis.js +159 -0
  29. package/lib/core/{load-components.js → loaders/components.js} +5 -7
  30. package/lib/core/loaders/index.js +11 -0
  31. package/lib/core/loaders/middlewares.js +36 -0
  32. package/lib/core/loaders/plugins/get-enabled-plugins.js +116 -0
  33. package/lib/core/loaders/plugins/index.js +123 -0
  34. package/lib/core/loaders/policies.js +28 -0
  35. package/lib/core/loaders/src-index.js +39 -0
  36. package/lib/core/registries/apis.js +29 -0
  37. package/lib/core/{app-configuration/config-provider.js → registries/config.js} +4 -11
  38. package/lib/core/registries/content-types.js +97 -0
  39. package/lib/core/registries/controllers.d.ts +7 -0
  40. package/lib/core/registries/controllers.js +114 -0
  41. package/lib/core/registries/hooks.d.ts +20 -0
  42. package/lib/core/registries/hooks.js +87 -0
  43. package/lib/core/registries/middlewares.d.ts +5 -0
  44. package/lib/core/registries/middlewares.js +89 -0
  45. package/lib/core/registries/modules.js +44 -0
  46. package/lib/core/registries/plugins.js +28 -0
  47. package/lib/core/registries/policies.d.ts +9 -0
  48. package/lib/core/registries/policies.js +89 -0
  49. package/lib/core/registries/services.d.ts +7 -0
  50. package/lib/core/registries/services.js +114 -0
  51. package/lib/core/utils.js +35 -0
  52. package/lib/core-api/controller/collection-type.js +45 -26
  53. package/lib/core-api/controller/index.d.ts +25 -0
  54. package/lib/core-api/controller/index.js +33 -11
  55. package/lib/core-api/controller/single-type.js +29 -15
  56. package/lib/core-api/controller/transform.js +62 -6
  57. package/lib/core-api/routes/index.js +71 -0
  58. package/lib/core-api/service/collection-type.js +43 -21
  59. package/lib/core-api/service/index.d.ts +21 -0
  60. package/lib/core-api/service/index.js +8 -67
  61. package/lib/core-api/service/pagination.js +130 -0
  62. package/lib/core-api/service/single-type.js +17 -19
  63. package/lib/factories.d.ts +48 -0
  64. package/lib/factories.js +84 -0
  65. package/lib/index.d.ts +10 -31
  66. package/lib/index.js +5 -1
  67. package/lib/middlewares/body.js +33 -0
  68. package/lib/middlewares/compression.js +8 -0
  69. package/lib/middlewares/cors.js +58 -0
  70. package/lib/middlewares/errors.js +40 -0
  71. package/lib/middlewares/favicon.js +19 -0
  72. package/lib/middlewares/index.d.ts +5 -0
  73. package/lib/middlewares/index.js +30 -117
  74. package/lib/middlewares/ip.js +8 -0
  75. package/lib/middlewares/logger.js +27 -0
  76. package/lib/middlewares/powered-by.js +20 -0
  77. package/lib/middlewares/public/index.js +98 -73
  78. package/lib/middlewares/query.js +46 -0
  79. package/lib/middlewares/response-time.js +15 -0
  80. package/lib/middlewares/responses.js +19 -0
  81. package/lib/middlewares/security.js +51 -0
  82. package/lib/middlewares/session/index.js +6 -6
  83. package/lib/migrations/draft-publish.js +57 -0
  84. package/lib/services/auth/index.js +87 -0
  85. package/lib/services/core-store.js +64 -51
  86. package/lib/services/cron.js +54 -0
  87. package/lib/services/entity-service/attributes/index.js +31 -0
  88. package/lib/services/entity-service/attributes/transforms.js +20 -0
  89. package/lib/services/entity-service/components.js +39 -15
  90. package/lib/services/entity-service/index.d.ts +91 -0
  91. package/lib/services/entity-service/index.js +120 -59
  92. package/lib/services/entity-service/params.js +52 -94
  93. package/lib/services/entity-validator/index.js +76 -43
  94. package/lib/services/entity-validator/validators.js +129 -43
  95. package/lib/services/errors.js +77 -0
  96. package/lib/{core → services}/fs.js +10 -2
  97. package/lib/services/metrics/index.js +41 -38
  98. package/lib/services/metrics/sender.js +2 -2
  99. package/lib/services/server/admin-api.js +14 -0
  100. package/lib/services/server/api.js +36 -0
  101. package/lib/services/server/compose-endpoint.js +141 -0
  102. package/lib/services/server/content-api.js +16 -0
  103. package/lib/{server.js → services/server/http-server.js} +0 -0
  104. package/lib/services/server/index.js +127 -0
  105. package/lib/services/server/koa.js +64 -0
  106. package/lib/services/server/middleware.js +122 -0
  107. package/lib/services/server/policy.js +32 -0
  108. package/lib/services/server/register-middlewares.js +110 -0
  109. package/lib/services/server/register-routes.js +106 -0
  110. package/lib/services/server/routing.js +120 -0
  111. package/lib/services/utils/upload-files.js +1 -1
  112. package/lib/services/webhook-runner.js +1 -1
  113. package/lib/utils/ee.js +3 -3
  114. package/lib/utils/get-dirs.js +17 -0
  115. package/lib/utils/index.js +2 -0
  116. package/lib/utils/is-initialized.js +1 -1
  117. package/lib/utils/run-checks.js +0 -15
  118. package/lib/utils/signals.js +24 -0
  119. package/lib/utils/startup-logger.js +2 -2
  120. package/lib/utils/update-notifier/index.js +3 -2
  121. package/package.json +93 -96
  122. package/lib/commands/generate.js +0 -76
  123. package/lib/core/index.js +0 -17
  124. package/lib/core/load-apis.js +0 -20
  125. package/lib/core/load-extensions.js +0 -71
  126. package/lib/core/load-functions.js +0 -21
  127. package/lib/core/load-middlewares.js +0 -130
  128. package/lib/core/load-modules.js +0 -55
  129. package/lib/core/load-plugins.js +0 -68
  130. package/lib/core/load-policies.js +0 -36
  131. package/lib/core/walk.js +0 -27
  132. package/lib/core-api/index.js +0 -39
  133. package/lib/load/check-reserved-filename.js +0 -10
  134. package/lib/load/load-config-files.js +0 -22
  135. package/lib/load/require-file-parse.js +0 -15
  136. package/lib/middlewares/boom/defaults.json +0 -5
  137. package/lib/middlewares/boom/index.js +0 -147
  138. package/lib/middlewares/cors/index.js +0 -66
  139. package/lib/middlewares/cron/defaults.json +0 -5
  140. package/lib/middlewares/cron/index.js +0 -43
  141. package/lib/middlewares/favicon/defaults.json +0 -7
  142. package/lib/middlewares/favicon/index.js +0 -32
  143. package/lib/middlewares/gzip/defaults.json +0 -6
  144. package/lib/middlewares/gzip/index.js +0 -19
  145. package/lib/middlewares/helmet/defaults.json +0 -18
  146. package/lib/middlewares/helmet/index.js +0 -9
  147. package/lib/middlewares/ip/defaults.json +0 -7
  148. package/lib/middlewares/ip/index.js +0 -25
  149. package/lib/middlewares/language/defaults.json +0 -9
  150. package/lib/middlewares/language/index.js +0 -40
  151. package/lib/middlewares/logger/defaults.json +0 -5
  152. package/lib/middlewares/logger/index.js +0 -37
  153. package/lib/middlewares/parser/defaults.json +0 -11
  154. package/lib/middlewares/parser/index.js +0 -71
  155. package/lib/middlewares/poweredBy/defaults.json +0 -5
  156. package/lib/middlewares/poweredBy/index.js +0 -16
  157. package/lib/middlewares/public/defaults.json +0 -8
  158. package/lib/middlewares/responseTime/defaults.json +0 -5
  159. package/lib/middlewares/responseTime/index.js +0 -25
  160. package/lib/middlewares/responses/defaults.json +0 -5
  161. package/lib/middlewares/responses/index.js +0 -18
  162. package/lib/middlewares/router/defaults.json +0 -7
  163. package/lib/middlewares/router/index.js +0 -64
  164. package/lib/middlewares/router/utils/composeEndpoint.js +0 -25
  165. package/lib/middlewares/router/utils/routerChecker.js +0 -92
  166. package/lib/utils/get-prefixed-dependencies.js +0 -7
@@ -0,0 +1,77 @@
1
+ 'use strict';
2
+
3
+ const createError = require('http-errors');
4
+ const {
5
+ NotFoundError,
6
+ UnauthorizedError,
7
+ ForbiddenError,
8
+ PayloadTooLargeError,
9
+ } = require('@strapi/utils').errors;
10
+
11
+ const mapErrorsAndStatus = [
12
+ {
13
+ classError: UnauthorizedError,
14
+ status: 401,
15
+ },
16
+ {
17
+ classError: ForbiddenError,
18
+ status: 403,
19
+ },
20
+ {
21
+ classError: NotFoundError,
22
+ status: 404,
23
+ },
24
+ {
25
+ classError: PayloadTooLargeError,
26
+ status: 413,
27
+ },
28
+ ];
29
+
30
+ const formatApplicationError = error => {
31
+ const errorAndStatus = mapErrorsAndStatus.find(pair => error instanceof pair.classError);
32
+ const status = errorAndStatus ? errorAndStatus.status : 400;
33
+
34
+ return {
35
+ status,
36
+ body: {
37
+ data: null,
38
+ error: {
39
+ status,
40
+ name: error.name,
41
+ message: error.message,
42
+ details: error.details,
43
+ },
44
+ },
45
+ };
46
+ };
47
+
48
+ const formatHttpError = error => {
49
+ return {
50
+ status: error.status,
51
+ body: {
52
+ data: null,
53
+ error: {
54
+ status: error.status,
55
+ name: error.name,
56
+ message: error.message,
57
+ details: error.details,
58
+ },
59
+ },
60
+ };
61
+ };
62
+
63
+ const formatInternalError = error => {
64
+ const httpError = createError(error);
65
+
66
+ if (httpError.expose) {
67
+ return formatHttpError(httpError);
68
+ }
69
+
70
+ return formatHttpError(createError(httpError.status || 500));
71
+ };
72
+
73
+ module.exports = {
74
+ formatApplicationError,
75
+ formatHttpError,
76
+ formatInternalError,
77
+ };
@@ -10,9 +10,9 @@ module.exports = strapi => {
10
10
  function normalizePath(optPath) {
11
11
  const filePath = Array.isArray(optPath) ? optPath.join('/') : optPath;
12
12
 
13
- const normalizedPath = path.normalize(filePath).replace(/^(\/?\.\.?)+/, '');
13
+ const normalizedPath = path.normalize(filePath).replace(/^\/?(\.\/|\.\.\/)+/, '');
14
14
 
15
- return path.join(strapi.dir, normalizedPath);
15
+ return path.join(strapi.dirs.root, normalizedPath);
16
16
  }
17
17
 
18
18
  const strapiFS = {
@@ -44,6 +44,14 @@ module.exports = strapi => {
44
44
  const removePath = normalizePath(optPath);
45
45
  return fse.remove(removePath);
46
46
  },
47
+
48
+ /**
49
+ * Appends a file in strapi app
50
+ */
51
+ appendFile(optPath, data) {
52
+ const writePath = normalizePath(optPath);
53
+ return fse.appendFileSync(writePath, data);
54
+ },
47
55
  };
48
56
 
49
57
  return strapiFS;
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
  /**
3
3
  * Strapi telemetry package.
4
- * You can learn more at https://strapi.io/documentation/developer-docs/latest/getting-started/usage-information.html
4
+ * You can learn more at https://docs.strapi.io/developer-docs/latest/getting-started/usage-information.html
5
5
  */
6
6
 
7
7
  const crypto = require('crypto');
@@ -23,49 +23,51 @@ const LIMITED_EVENTS = [
23
23
  ];
24
24
 
25
25
  const createTelemetryInstance = strapi => {
26
- const { uuid } = strapi.config;
26
+ const uuid = strapi.config.get('uuid');
27
27
  const isDisabled = !uuid || isTruthy(process.env.STRAPI_TELEMETRY_DISABLED);
28
28
 
29
29
  const crons = [];
30
30
  const sender = createSender(strapi);
31
31
  const sendEvent = wrapWithRateLimit(sender, { limitedEvents: LIMITED_EVENTS });
32
32
 
33
- if (!isDisabled) {
34
- const pingCron = scheduleJob('0 0 12 * * *', () => sendEvent('ping'));
35
- crons.push(pingCron);
36
-
37
- strapi.app.use(createMiddleware({ sendEvent }));
38
- }
33
+ return {
34
+ register() {
35
+ if (!isDisabled) {
36
+ const pingCron = scheduleJob('0 0 12 * * *', () => sendEvent('ping'));
37
+ crons.push(pingCron);
39
38
 
40
- if (strapi.EE === true && ee.isEE === true) {
41
- const pingDisabled =
42
- isTruthy(process.env.STRAPI_LICENSE_PING_DISABLED) && ee.licenseInfo.type === 'gold';
43
-
44
- const sendLicenseCheck = () => {
45
- return sendEvent(
46
- 'didCheckLicense',
47
- {
48
- licenseInfo: {
49
- ...ee.licenseInfo,
50
- projectHash: hashProject(strapi),
51
- dependencyHash: hashDep(strapi),
52
- },
53
- },
54
- {
55
- headers: { 'x-strapi-project': 'enterprise' },
39
+ strapi.server.use(createMiddleware({ sendEvent }));
40
+ }
41
+ },
42
+ bootstrap() {
43
+ if (strapi.EE === true && ee.isEE === true) {
44
+ const pingDisabled =
45
+ isTruthy(process.env.STRAPI_LICENSE_PING_DISABLED) && ee.licenseInfo.type === 'gold';
46
+
47
+ const sendLicenseCheck = () => {
48
+ return sendEvent(
49
+ 'didCheckLicense',
50
+ {
51
+ licenseInfo: {
52
+ ...ee.licenseInfo,
53
+ projectHash: hashProject(strapi),
54
+ dependencyHash: hashDep(strapi),
55
+ },
56
+ },
57
+ {
58
+ headers: { 'x-strapi-project': 'enterprise' },
59
+ }
60
+ );
61
+ };
62
+
63
+ if (!pingDisabled) {
64
+ const licenseCron = scheduleJob('0 0 0 * * 7', () => sendLicenseCheck());
65
+ crons.push(licenseCron);
66
+
67
+ sendLicenseCheck();
56
68
  }
57
- );
58
- };
59
-
60
- if (!pingDisabled) {
61
- const licenseCron = scheduleJob('0 0 0 * * 7', () => sendLicenseCheck());
62
- crons.push(licenseCron);
63
-
64
- sendLicenseCheck();
65
- }
66
- }
67
-
68
- return {
69
+ }
70
+ },
69
71
  destroy() {
70
72
  // clear open handles
71
73
  crons.forEach(cron => cron.cancel());
@@ -83,11 +85,12 @@ const hash = str =>
83
85
  .update(str)
84
86
  .digest('hex');
85
87
 
86
- const hashProject = strapi => hash(`${strapi.config.info.name}${strapi.config.info.description}`);
88
+ const hashProject = strapi =>
89
+ hash(`${strapi.config.get('info.name')}${strapi.config.get('info.description')}`);
87
90
 
88
91
  const hashDep = strapi => {
89
92
  const depStr = JSON.stringify(strapi.config.info.dependencies);
90
- const readmePath = path.join(strapi.dir, 'README.md');
93
+ const readmePath = path.join(strapi.dirs.root, 'README.md');
91
94
 
92
95
  try {
93
96
  if (fs.existsSync(readmePath)) {
@@ -44,8 +44,8 @@ module.exports = strapi => {
44
44
  nodeVersion: process.version,
45
45
  docker: process.env.DOCKER || isDocker(),
46
46
  isCI: ciEnv.isCI,
47
- version: strapi.config.info.strapi,
48
- strapiVersion: strapi.config.info.strapi,
47
+ version: strapi.config.get('info.strapi'),
48
+ strapiVersion: strapi.config.get('info.strapi'),
49
49
  projectType: isEE ? 'Enterprise' : 'Community',
50
50
  };
51
51
 
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ const { createAPI } = require('./api');
4
+
5
+ const createAdminAPI = strapi => {
6
+ const opts = {
7
+ prefix: '', // '/admin';
8
+ type: 'admin',
9
+ };
10
+
11
+ return createAPI(strapi, opts);
12
+ };
13
+
14
+ module.exports = { createAdminAPI };
@@ -0,0 +1,36 @@
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
+ listRoutes() {
16
+ return [...api.stack];
17
+ },
18
+
19
+ use(fn) {
20
+ api.use(fn);
21
+ return this;
22
+ },
23
+
24
+ routes(routes) {
25
+ routeManager.addRoutes(routes, api);
26
+ return this;
27
+ },
28
+
29
+ mount(router) {
30
+ router.use(api.routes(), api.allowedMethods());
31
+ return this;
32
+ },
33
+ };
34
+ };
35
+
36
+ module.exports = { createAPI };
@@ -0,0 +1,141 @@
1
+ 'use strict';
2
+
3
+ const { has, toLower, castArray, trim, prop, isNil } = require('lodash/fp');
4
+ const { UnauthorizedError, ForbiddenError } = require('@strapi/utils').errors;
5
+
6
+ const compose = require('koa-compose');
7
+ const { resolveRouteMiddlewares } = require('./middleware');
8
+ const { resolvePolicies } = require('./policy');
9
+
10
+ const getMethod = route => trim(toLower(route.method));
11
+ const getPath = route => trim(route.path);
12
+
13
+ const createRouteInfoMiddleware = routeInfo => (ctx, next) => {
14
+ const route = {
15
+ ...routeInfo,
16
+ config: routeInfo.config || {},
17
+ };
18
+
19
+ ctx.state.route = route;
20
+ return next();
21
+ };
22
+
23
+ const getAuthConfig = prop('config.auth');
24
+
25
+ const createAuthorizeMiddleware = strapi => async (ctx, next) => {
26
+ const { auth, route } = ctx.state;
27
+
28
+ const authService = strapi.container.get('auth');
29
+
30
+ try {
31
+ await authService.verify(auth, getAuthConfig(route));
32
+
33
+ return next();
34
+ } catch (error) {
35
+ if (error instanceof UnauthorizedError) {
36
+ return ctx.unauthorized();
37
+ }
38
+
39
+ if (error instanceof ForbiddenError) {
40
+ return ctx.forbidden();
41
+ }
42
+
43
+ throw error;
44
+ }
45
+ };
46
+
47
+ const createAuthenticateMiddleware = strapi => async (ctx, next) => {
48
+ return strapi.container.get('auth').authenticate(ctx, next);
49
+ };
50
+
51
+ const returnBodyMiddleware = async (ctx, next) => {
52
+ const values = await next();
53
+
54
+ if (isNil(ctx.body) && !isNil(values)) {
55
+ ctx.body = values;
56
+ }
57
+ };
58
+
59
+ module.exports = strapi => {
60
+ const authenticate = createAuthenticateMiddleware(strapi);
61
+ const authorize = createAuthorizeMiddleware(strapi);
62
+
63
+ return (route, { router }) => {
64
+ try {
65
+ const method = getMethod(route);
66
+ const path = getPath(route);
67
+
68
+ const middlewares = resolveRouteMiddlewares(route, strapi);
69
+ const policies = resolvePolicies(route);
70
+
71
+ const action = getAction(route, strapi);
72
+
73
+ const routeHandler = compose([
74
+ createRouteInfoMiddleware(route),
75
+ authenticate,
76
+ authorize,
77
+ ...policies,
78
+ ...middlewares,
79
+ returnBodyMiddleware,
80
+ ...castArray(action),
81
+ ]);
82
+
83
+ router[method](path, routeHandler);
84
+ } catch (error) {
85
+ error.message = `Error creating endpoint ${route.method} ${route.path}: ${error.message}`;
86
+ throw error;
87
+ }
88
+ };
89
+ };
90
+
91
+ const getController = (name, { pluginName, apiName }, strapi) => {
92
+ let ctrl;
93
+
94
+ if (pluginName) {
95
+ if (pluginName === 'admin') {
96
+ ctrl = strapi.controller(`admin::${name}`);
97
+ } else {
98
+ ctrl = strapi.plugin(pluginName).controller(name);
99
+ }
100
+ } else if (apiName) {
101
+ ctrl = strapi.controller(`api::${apiName}.${name}`);
102
+ }
103
+
104
+ if (!ctrl) {
105
+ return strapi.controller(name);
106
+ }
107
+
108
+ return ctrl;
109
+ };
110
+
111
+ const extractHandlerParts = name => {
112
+ const controllerName = name.slice(0, name.lastIndexOf('.'));
113
+ const actionName = name.slice(name.lastIndexOf('.') + 1);
114
+
115
+ return { controllerName, actionName };
116
+ };
117
+
118
+ const getAction = (route, strapi) => {
119
+ const { handler, info = {} } = route;
120
+ const { pluginName, apiName, type } = info;
121
+
122
+ if (Array.isArray(handler) || typeof handler === 'function') {
123
+ return handler;
124
+ }
125
+
126
+ const { controllerName, actionName } = extractHandlerParts(trim(handler));
127
+
128
+ const controller = getController(controllerName, { pluginName, apiName }, strapi);
129
+
130
+ if (typeof controller[actionName] !== 'function') {
131
+ throw new Error(`Handler not found "${handler}"`);
132
+ }
133
+
134
+ if (has(Symbol.for('__type__'), controller[actionName])) {
135
+ controller[actionName][Symbol.for('__type__')].push(type);
136
+ } else {
137
+ controller[actionName][Symbol.for('__type__')] = [type];
138
+ }
139
+
140
+ return controller[actionName].bind(controller);
141
+ };
@@ -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.rest.prefix', '/api'),
8
+ type: 'content-api',
9
+ };
10
+
11
+ return createAPI(strapi, opts);
12
+ };
13
+
14
+ module.exports = {
15
+ createContentAPI,
16
+ };
@@ -0,0 +1,127 @@
1
+ 'use strict';
2
+
3
+ const Router = require('@koa/router');
4
+
5
+ const { createHTTPServer } = require('./http-server');
6
+ const { createRouteManager } = require('./routing');
7
+ const { createAdminAPI } = require('./admin-api');
8
+ const { createContentAPI } = require('./content-api');
9
+ const registerAllRoutes = require('./register-routes');
10
+ const registerApplicationMiddlewares = require('./register-middlewares');
11
+ const createKoaApp = require('./koa');
12
+
13
+ const healthCheck = async ctx => {
14
+ ctx.set('strapi', 'You are so French!');
15
+ ctx.status = 204;
16
+ };
17
+
18
+ /**
19
+ * @typedef Server
20
+ *
21
+ * @property {Koa} app
22
+ * @property {http.Server} app
23
+ */
24
+
25
+ /**
26
+ *
27
+ * @param {Strapi} strapi
28
+ * @returns {Server}
29
+ */
30
+ const createServer = strapi => {
31
+ const app = createKoaApp({ proxy: strapi.config.get('server.proxy') });
32
+
33
+ const router = new Router();
34
+
35
+ const routeManager = createRouteManager(strapi);
36
+
37
+ const httpServer = createHTTPServer(strapi, app);
38
+
39
+ const apis = {
40
+ 'content-api': createContentAPI(strapi),
41
+ admin: createAdminAPI(strapi),
42
+ };
43
+
44
+ // init health check
45
+ router.all('/_health', healthCheck);
46
+
47
+ const state = {
48
+ mounted: false,
49
+ };
50
+
51
+ return {
52
+ app,
53
+ router,
54
+ httpServer,
55
+
56
+ api(name) {
57
+ return apis[name];
58
+ },
59
+
60
+ use(...args) {
61
+ app.use(...args);
62
+ return this;
63
+ },
64
+
65
+ routes(routes) {
66
+ if (routes.type) {
67
+ const api = apis[routes.type];
68
+ if (!api) {
69
+ throw new Error(`API ${routes.type} not found. Possible APIs are ${Object.keys(apis)}`);
70
+ }
71
+
72
+ apis[routes.type].routes(routes);
73
+ return this;
74
+ }
75
+
76
+ routeManager.addRoutes(routes, router);
77
+ return this;
78
+ },
79
+
80
+ mount() {
81
+ state.mounted = true;
82
+
83
+ Object.values(apis).forEach(api => api.mount(router));
84
+ app.use(router.routes()).use(router.allowedMethods());
85
+
86
+ return this;
87
+ },
88
+
89
+ async initRouting() {
90
+ await registerAllRoutes(strapi);
91
+
92
+ return this;
93
+ },
94
+
95
+ async initMiddlewares() {
96
+ await registerApplicationMiddlewares(strapi);
97
+
98
+ return this;
99
+ },
100
+
101
+ listRoutes() {
102
+ const allRoutes = [...router.stack];
103
+
104
+ Object.values(apis).forEach(api => {
105
+ allRoutes.push(...api.listRoutes());
106
+ });
107
+
108
+ return allRoutes;
109
+ },
110
+
111
+ listen(...args) {
112
+ if (!state.mounted) {
113
+ this.mount();
114
+ }
115
+
116
+ return httpServer.listen(...args);
117
+ },
118
+
119
+ async destroy() {
120
+ await httpServer.destroy();
121
+ },
122
+ };
123
+ };
124
+
125
+ module.exports = {
126
+ createServer,
127
+ };
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+
3
+ const { isNil, camelCase } = require('lodash/fp');
4
+ const Koa = require('koa');
5
+ const createError = require('http-errors');
6
+ const delegate = require('delegates');
7
+ var statuses = require('statuses');
8
+ const { formatHttpError } = require('../errors');
9
+
10
+ const addCustomMethods = app => {
11
+ const delegator = delegate(app.context, 'response');
12
+
13
+ /* errors */
14
+ statuses.codes
15
+ .filter(code => code >= 400 && code < 600)
16
+ .forEach(code => {
17
+ const name = statuses(code);
18
+ const camelCasedName = camelCase(name);
19
+ app.response[camelCasedName] = function(message, details = {}) {
20
+ const httpError = createError(code, message, { details });
21
+ const { status, body } = formatHttpError(httpError);
22
+ this.status = status;
23
+ this.body = body;
24
+ };
25
+ delegator.method(camelCasedName);
26
+ });
27
+
28
+ /* send, created, deleted */
29
+ app.response.send = function(data, status = 200) {
30
+ this.status = status;
31
+ this.body = data;
32
+ };
33
+
34
+ app.response.created = function(data) {
35
+ this.status = 201;
36
+ this.body = data;
37
+ };
38
+
39
+ app.response.deleted = function(data) {
40
+ if (isNil(data)) {
41
+ this.status = 204;
42
+ } else {
43
+ this.status = 200;
44
+ this.body = data;
45
+ }
46
+ };
47
+
48
+ delegator
49
+ .method('send')
50
+ .method('created')
51
+ .method('deleted');
52
+
53
+ return app;
54
+ };
55
+
56
+ const createKoaApp = ({ proxy }) => {
57
+ const app = new Koa({ proxy });
58
+
59
+ addCustomMethods(app);
60
+
61
+ return app;
62
+ };
63
+
64
+ module.exports = createKoaApp;