@strapi/strapi 4.0.0-next.8 → 4.0.2

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 (147) hide show
  1. package/README.md +14 -14
  2. package/bin/strapi.js +46 -60
  3. package/lib/Strapi.js +152 -74
  4. package/lib/commands/build.js +19 -8
  5. package/lib/commands/console.js +1 -1
  6. package/lib/commands/content-types/list.js +22 -0
  7. package/lib/commands/controllers/list.js +22 -0
  8. package/lib/commands/develop.js +22 -27
  9. package/lib/commands/generate-template.js +4 -5
  10. package/lib/commands/hooks/list.js +22 -0
  11. package/lib/commands/middlewares/list.js +22 -0
  12. package/lib/commands/new.js +3 -1
  13. package/lib/commands/policies/list.js +22 -0
  14. package/lib/commands/routes/list.js +28 -0
  15. package/lib/commands/services/list.js +22 -0
  16. package/lib/commands/watchAdmin.js +18 -9
  17. package/lib/core/app-configuration/index.js +3 -19
  18. package/lib/core/bootstrap.js +3 -95
  19. package/lib/core/domain/content-type/index.js +5 -11
  20. package/lib/core/domain/module/index.js +42 -11
  21. package/lib/core/domain/module/validation.js +16 -19
  22. package/lib/core/loaders/admin.js +2 -2
  23. package/lib/core/loaders/apis.js +148 -9
  24. package/lib/core/loaders/components.js +4 -6
  25. package/lib/core/loaders/index.js +1 -0
  26. package/lib/core/loaders/middlewares.js +23 -123
  27. package/lib/core/loaders/plugins/get-enabled-plugins.js +55 -19
  28. package/lib/core/loaders/plugins/get-user-plugins-config.js +37 -0
  29. package/lib/core/loaders/plugins/index.js +30 -16
  30. package/lib/core/loaders/policies.js +1 -1
  31. package/lib/core/loaders/src-index.js +39 -0
  32. package/lib/core/registries/apis.js +29 -0
  33. package/lib/core/registries/content-types.js +61 -12
  34. package/lib/core/registries/controllers.d.ts +7 -0
  35. package/lib/core/registries/controllers.js +91 -7
  36. package/lib/core/registries/hooks.d.ts +20 -0
  37. package/lib/core/registries/hooks.js +87 -0
  38. package/lib/core/registries/middlewares.d.ts +5 -0
  39. package/lib/core/registries/middlewares.js +64 -5
  40. package/lib/core/registries/modules.js +3 -3
  41. package/lib/core/registries/plugins.js +2 -2
  42. package/lib/core/registries/policies.d.ts +9 -0
  43. package/lib/core/registries/policies.js +64 -5
  44. package/lib/core/registries/services.d.ts +7 -0
  45. package/lib/core/registries/services.js +86 -17
  46. package/lib/core/utils.js +22 -0
  47. package/lib/core-api/controller/collection-type.js +45 -26
  48. package/lib/core-api/controller/index.d.ts +25 -0
  49. package/lib/core-api/controller/index.js +33 -11
  50. package/lib/core-api/controller/single-type.js +29 -15
  51. package/lib/core-api/controller/transform.js +62 -6
  52. package/lib/core-api/routes/index.js +71 -0
  53. package/lib/core-api/service/collection-type.js +43 -21
  54. package/lib/core-api/service/index.d.ts +21 -0
  55. package/lib/core-api/service/index.js +8 -67
  56. package/lib/core-api/service/pagination.js +125 -0
  57. package/lib/core-api/service/single-type.js +17 -19
  58. package/lib/factories.d.ts +48 -0
  59. package/lib/factories.js +84 -0
  60. package/lib/index.d.ts +10 -31
  61. package/lib/index.js +5 -1
  62. package/lib/middlewares/body.js +33 -0
  63. package/lib/middlewares/compression.js +8 -0
  64. package/lib/middlewares/cors.js +58 -0
  65. package/lib/middlewares/errors.js +40 -0
  66. package/lib/middlewares/favicon.js +19 -0
  67. package/lib/middlewares/index.d.ts +5 -0
  68. package/lib/middlewares/index.js +30 -116
  69. package/lib/middlewares/ip.js +8 -0
  70. package/lib/middlewares/logger.js +27 -0
  71. package/lib/middlewares/powered-by.js +20 -0
  72. package/lib/middlewares/public/index.js +72 -77
  73. package/lib/middlewares/query.js +46 -0
  74. package/lib/middlewares/response-time.js +15 -0
  75. package/lib/middlewares/responses.js +19 -0
  76. package/lib/middlewares/security.js +51 -0
  77. package/lib/middlewares/session/index.js +6 -6
  78. package/lib/migrations/draft-publish.js +57 -0
  79. package/lib/services/auth/index.js +87 -0
  80. package/lib/services/core-store.js +64 -49
  81. package/lib/services/cron.js +54 -0
  82. package/lib/services/entity-service/attributes/index.js +31 -0
  83. package/lib/services/entity-service/attributes/transforms.js +20 -0
  84. package/lib/services/entity-service/components.js +39 -15
  85. package/lib/services/entity-service/index.d.ts +91 -0
  86. package/lib/services/entity-service/index.js +118 -60
  87. package/lib/services/entity-service/params.js +52 -94
  88. package/lib/services/entity-validator/index.js +76 -43
  89. package/lib/services/entity-validator/validators.js +131 -43
  90. package/lib/services/errors.js +77 -0
  91. package/lib/services/fs.js +1 -1
  92. package/lib/services/metrics/index.js +38 -36
  93. package/lib/services/server/admin-api.js +14 -0
  94. package/lib/services/server/api.js +36 -0
  95. package/lib/services/server/compose-endpoint.js +141 -0
  96. package/lib/services/server/content-api.js +16 -0
  97. package/lib/{server.js → services/server/http-server.js} +0 -0
  98. package/lib/services/server/index.js +127 -0
  99. package/lib/services/server/koa.js +64 -0
  100. package/lib/services/server/middleware.js +122 -0
  101. package/lib/services/server/policy.js +32 -0
  102. package/lib/services/server/register-middlewares.js +110 -0
  103. package/lib/services/server/register-routes.js +106 -0
  104. package/lib/services/server/routing.js +120 -0
  105. package/lib/services/webhook-runner.js +1 -1
  106. package/lib/utils/ee.js +3 -3
  107. package/lib/utils/get-dirs.js +17 -0
  108. package/lib/utils/index.js +2 -0
  109. package/lib/utils/signals.js +24 -0
  110. package/lib/utils/update-notifier/index.js +2 -1
  111. package/package.json +94 -97
  112. package/lib/commands/generate.js +0 -76
  113. package/lib/core/app-configuration/load-functions.js +0 -28
  114. package/lib/core-api/index.js +0 -39
  115. package/lib/load/check-reserved-filename.js +0 -10
  116. package/lib/load/load-config-files.js +0 -22
  117. package/lib/load/require-file-parse.js +0 -15
  118. package/lib/middlewares/boom/defaults.json +0 -5
  119. package/lib/middlewares/boom/index.js +0 -147
  120. package/lib/middlewares/cors/index.js +0 -66
  121. package/lib/middlewares/cron/defaults.json +0 -5
  122. package/lib/middlewares/cron/index.js +0 -43
  123. package/lib/middlewares/favicon/defaults.json +0 -7
  124. package/lib/middlewares/favicon/index.js +0 -32
  125. package/lib/middlewares/gzip/defaults.json +0 -6
  126. package/lib/middlewares/gzip/index.js +0 -19
  127. package/lib/middlewares/helmet/defaults.json +0 -18
  128. package/lib/middlewares/helmet/index.js +0 -9
  129. package/lib/middlewares/ip/defaults.json +0 -7
  130. package/lib/middlewares/ip/index.js +0 -25
  131. package/lib/middlewares/language/defaults.json +0 -9
  132. package/lib/middlewares/language/index.js +0 -40
  133. package/lib/middlewares/logger/defaults.json +0 -5
  134. package/lib/middlewares/logger/index.js +0 -37
  135. package/lib/middlewares/parser/defaults.json +0 -11
  136. package/lib/middlewares/parser/index.js +0 -71
  137. package/lib/middlewares/poweredBy/defaults.json +0 -5
  138. package/lib/middlewares/poweredBy/index.js +0 -16
  139. package/lib/middlewares/public/defaults.json +0 -8
  140. package/lib/middlewares/responseTime/defaults.json +0 -5
  141. package/lib/middlewares/responseTime/index.js +0 -25
  142. package/lib/middlewares/responses/defaults.json +0 -5
  143. package/lib/middlewares/responses/index.js +0 -18
  144. package/lib/middlewares/router/defaults.json +0 -7
  145. package/lib/middlewares/router/index.js +0 -58
  146. package/lib/middlewares/router/utils/composeEndpoint.js +0 -177
  147. package/lib/utils/get-prefixed-dependencies.js +0 -7
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ const { defaultsDeep } = require('lodash/fp');
4
+ const body = require('koa-body');
5
+
6
+ const defaults = {
7
+ multipart: true,
8
+ patchKoa: true,
9
+ };
10
+
11
+ /**
12
+ * @type {import('./').MiddlewareFactory}
13
+ */
14
+ module.exports = config => {
15
+ const bodyConfig = defaultsDeep(defaults, config);
16
+
17
+ return async (ctx, next) => {
18
+ // TODO: find a better way later
19
+ if (ctx.url === '/graphql') {
20
+ return next();
21
+ }
22
+
23
+ try {
24
+ await body({ patchKoa: true, ...bodyConfig })(ctx, next);
25
+ } catch (e) {
26
+ if ((e || {}).message && e.message.includes('maxFileSize exceeded')) {
27
+ return ctx.payloadTooLarge('FileTooBig');
28
+ }
29
+
30
+ throw e;
31
+ }
32
+ };
33
+ };
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ const compress = require('koa-compress');
4
+
5
+ /**
6
+ * @type {import('./').MiddlewareFactory}
7
+ */
8
+ module.exports = config => compress(config);
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ const { defaultsDeep } = require('lodash/fp');
4
+ const cors = require('@koa/cors');
5
+
6
+ const defaults = {
7
+ origin: '*',
8
+ maxAge: 31536000,
9
+ credentials: true,
10
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
11
+ headers: ['Content-Type', 'Authorization', 'Origin', 'Accept'],
12
+ keepHeadersOnError: false,
13
+ };
14
+
15
+ /**
16
+ * @type {import('./').MiddlewareFactory}
17
+ */
18
+ module.exports = config => {
19
+ const {
20
+ origin,
21
+ expose,
22
+ maxAge,
23
+ credentials,
24
+ methods,
25
+ headers,
26
+ keepHeadersOnError,
27
+ } = defaultsDeep(defaults, config);
28
+
29
+ return cors({
30
+ async origin(ctx) {
31
+ let originList;
32
+
33
+ if (typeof origin === 'function') {
34
+ originList = await origin(ctx);
35
+ } else {
36
+ originList = origin;
37
+ }
38
+
39
+ const whitelist = Array.isArray(originList) ? originList : originList.split(/\s*,\s*/);
40
+
41
+ const requestOrigin = ctx.accept.headers.origin;
42
+ if (whitelist.includes('*')) {
43
+ return '*';
44
+ }
45
+
46
+ if (!whitelist.includes(requestOrigin)) {
47
+ return ctx.throw(`${requestOrigin} is not a valid origin`);
48
+ }
49
+ return requestOrigin;
50
+ },
51
+ exposeHeaders: expose,
52
+ maxAge,
53
+ credentials,
54
+ allowMethods: methods,
55
+ allowHeaders: headers,
56
+ keepHeadersOnError,
57
+ });
58
+ };
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ const { HttpError, ApplicationError } = require('@strapi/utils').errors;
4
+ const {
5
+ formatApplicationError,
6
+ formatHttpError,
7
+ formatInternalError,
8
+ } = require('../services/errors');
9
+
10
+ module.exports = (/* _, { strapi } */) => {
11
+ return async (ctx, next) => {
12
+ try {
13
+ await next();
14
+
15
+ if (!ctx.response._explicitStatus) {
16
+ return ctx.notFound();
17
+ }
18
+ } catch (error) {
19
+ if (error instanceof ApplicationError) {
20
+ const { status, body } = formatApplicationError(error);
21
+ ctx.status = status;
22
+ ctx.body = body;
23
+ return;
24
+ }
25
+
26
+ if (error instanceof HttpError) {
27
+ const { status, body } = formatHttpError(error);
28
+ ctx.status = status;
29
+ ctx.body = body;
30
+ return;
31
+ }
32
+
33
+ strapi.log.error(error);
34
+
35
+ const { status, body } = formatInternalError(error);
36
+ ctx.status = status;
37
+ ctx.body = body;
38
+ }
39
+ };
40
+ };
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const { resolve } = require('path');
4
+ const { defaultsDeep } = require('lodash/fp');
5
+ const favicon = require('koa-favicon');
6
+
7
+ const defaults = {
8
+ path: 'favicon.ico',
9
+ maxAge: 86400000,
10
+ };
11
+
12
+ /**
13
+ * @type {import('./').MiddlewareFactory}
14
+ */
15
+ module.exports = (config, { strapi }) => {
16
+ const { maxAge, path: faviconPath } = defaultsDeep(defaults, config);
17
+
18
+ return favicon(resolve(strapi.dirs.root, faviconPath), { maxAge });
19
+ };
@@ -0,0 +1,5 @@
1
+ import { Strapi } from '../';
2
+ import { Middleware } from 'koa';
3
+
4
+ export type MiddlewareFactory = (config: any, ctx: { strapi: Strapi }) => Middleware | null;
5
+ export type Middleware = Middleware;
@@ -1,119 +1,33 @@
1
1
  'use strict';
2
2
 
3
- const { uniq, difference, get, isUndefined, merge } = require('lodash');
4
-
5
- const requiredMiddlewares = [
6
- 'responses',
7
- 'router',
8
- 'logger',
9
- 'boom',
10
- 'cors',
11
- 'cron',
12
- 'xframe',
13
- 'xss',
14
- 'public',
15
- 'favicon',
16
- ];
17
-
18
- module.exports = async function() {
19
- /** Utils */
20
- const middlewareConfig = this.config.middleware;
21
-
22
- // check if a middleware exists
23
- const middlewareExists = key => {
24
- return !isUndefined(this.middleware[key]);
25
- };
26
-
27
- // check if a middleware is enabled
28
- const middlewareEnabled = key => {
29
- return (
30
- requiredMiddlewares.includes(key) ||
31
- get(middlewareConfig, ['settings', key, 'enabled'], false) === true
32
- );
33
- };
34
-
35
- // list of enabled middlewares
36
- const enabledMiddlewares = Object.keys(this.middleware).filter(middlewareEnabled);
37
-
38
- // Method to initialize middlewares and emit an event.
39
- const initialize = middlewareKey => {
40
- if (this.middleware[middlewareKey].loaded === true) return;
41
-
42
- const module = this.middleware[middlewareKey].load;
43
-
44
- return new Promise((resolve, reject) => {
45
- const timeout = setTimeout(
46
- () => reject(`(middleware: ${middlewareKey}) is taking too long to load.`),
47
- middlewareConfig.timeout || 1000
48
- );
49
- this.middleware[middlewareKey] = merge(this.middleware[middlewareKey], module);
50
-
51
- Promise.resolve()
52
- .then(() => module.initialize())
53
- .then(() => {
54
- clearTimeout(timeout);
55
- this.middleware[middlewareKey].loaded = true;
56
- resolve();
57
- })
58
- .catch(err => {
59
- clearTimeout(timeout);
60
-
61
- if (err) {
62
- return reject(err);
63
- }
64
- });
65
- });
66
- };
67
-
68
- /**
69
- * Run init functions
70
- */
71
-
72
- // Run beforeInitialize of every middleware
73
- await Promise.all(
74
- enabledMiddlewares.map(key => {
75
- const { beforeInitialize } = this.middleware[key].load;
76
- if (typeof beforeInitialize === 'function') {
77
- return beforeInitialize();
78
- }
79
- })
80
- );
81
-
82
- // run the initialization of an array of middlewares sequentially
83
- const initMiddlewaresSeq = async middlewareArr => {
84
- for (let key of uniq(middlewareArr)) {
85
- await initialize(key);
86
- }
87
- };
88
-
89
- const middlewaresBefore = get(middlewareConfig, 'load.before', [])
90
- .filter(middlewareExists)
91
- .filter(middlewareEnabled);
92
-
93
- const middlewaresAfter = get(middlewareConfig, 'load.after', [])
94
- .filter(middlewareExists)
95
- .filter(middlewareEnabled);
96
-
97
- const middlewaresOrder = get(middlewareConfig, 'load.order', [])
98
- .filter(middlewareExists)
99
- .filter(middlewareEnabled);
100
-
101
- const unspecifiedMiddlewares = difference(
102
- enabledMiddlewares,
103
- middlewaresBefore,
104
- middlewaresOrder,
105
- middlewaresAfter
106
- );
107
-
108
- // before
109
- await initMiddlewaresSeq(middlewaresBefore);
110
-
111
- // ordered // rest of middlewares
112
- await Promise.all([
113
- initMiddlewaresSeq(middlewaresOrder),
114
- Promise.all(unspecifiedMiddlewares.map(initialize)),
115
- ]);
116
-
117
- // after
118
- await initMiddlewaresSeq(middlewaresAfter);
3
+ const compression = require('./compression');
4
+ const cors = require('./cors');
5
+ const errors = require('./errors');
6
+ const favicon = require('./favicon');
7
+ const ip = require('./ip');
8
+ const logger = require('./logger');
9
+ const poweredBy = require('./powered-by');
10
+ const body = require('./body');
11
+ const query = require('./query');
12
+ const responseTime = require('./response-time');
13
+ const responses = require('./responses');
14
+ const security = require('./security');
15
+ // TODO: add back ?
16
+ // session: require('./session'),
17
+ const publicStatic = require('./public');
18
+
19
+ module.exports = {
20
+ errors,
21
+ ip,
22
+ security,
23
+ cors,
24
+ responseTime,
25
+ poweredBy,
26
+ logger,
27
+ compression,
28
+ responses,
29
+ body,
30
+ query,
31
+ favicon,
32
+ public: publicStatic,
119
33
  };
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ const ip = require('koa-ip');
4
+
5
+ /**
6
+ * @type {import('./').MiddlewareFactory}
7
+ */
8
+ module.exports = config => ip(config);
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+ const chalk = require('chalk');
3
+
4
+ const codeToColor = code => {
5
+ return code >= 500
6
+ ? chalk.red(code)
7
+ : code >= 400
8
+ ? chalk.yellow(code)
9
+ : code >= 300
10
+ ? chalk.cyan(code)
11
+ : code >= 200
12
+ ? chalk.green(code)
13
+ : code;
14
+ };
15
+
16
+ /**
17
+ * @type {import('./').MiddlewareFactory}
18
+ */
19
+ module.exports = (_, { strapi }) => {
20
+ return async (ctx, next) => {
21
+ const start = Date.now();
22
+ await next();
23
+ const delta = Math.ceil(Date.now() - start);
24
+
25
+ strapi.log.http(`${ctx.method} ${ctx.url} (${delta} ms) ${codeToColor(ctx.status)}`);
26
+ };
27
+ };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const { defaultsDeep } = require('lodash/fp');
4
+
5
+ const defaults = {
6
+ poweredBy: 'Strapi <strapi.io>',
7
+ };
8
+
9
+ /**
10
+ * @type {import('./').MiddlewareFactory}
11
+ */
12
+ module.exports = config => {
13
+ const { poweredBy } = defaultsDeep(defaults, config);
14
+
15
+ return async (ctx, next) => {
16
+ await next();
17
+
18
+ ctx.set('X-Powered-By', poweredBy);
19
+ };
20
+ };
@@ -1,98 +1,93 @@
1
1
  'use strict';
2
2
 
3
- /**
4
- * Module dependencies
5
- */
6
-
7
- // Node.js core.
8
3
  const fs = require('fs');
9
4
  const path = require('path');
10
5
  const stream = require('stream');
11
6
  const _ = require('lodash');
7
+ const { defaultsDeep } = require('lodash/fp');
12
8
  const koaStatic = require('koa-static');
13
9
  const utils = require('../../utils');
14
10
  const serveStatic = require('./serve-static');
15
11
 
12
+ const defaults = {
13
+ maxAge: 60000,
14
+ defaultIndex: true,
15
+ };
16
+
16
17
  /**
17
- * Public assets hook
18
+ * @type {import('../').MiddlewareFactory}
18
19
  */
20
+ module.exports = (config, { strapi }) => {
21
+ const { defaultIndex, maxAge } = defaultsDeep(defaults, config);
19
22
 
20
- module.exports = strapi => {
21
- return {
22
- /**
23
- * Initialize the hook
24
- */
25
-
26
- async initialize() {
27
- const { defaultIndex, maxAge, path: publicPath } = strapi.config.middleware.settings.public;
28
- const staticDir = path.resolve(strapi.dir, publicPath || strapi.config.paths.static);
29
-
30
- if (defaultIndex === true) {
31
- const index = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
23
+ if (defaultIndex === true) {
24
+ const index = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
32
25
 
33
- const serveIndexPage = async (ctx, next) => {
34
- // defer rendering of strapi index page
35
- await next();
36
- if (ctx.body != null || ctx.status !== 404) return;
26
+ const serveIndexPage = async (ctx, next) => {
27
+ // defer rendering of strapi index page
28
+ await next();
37
29
 
38
- ctx.url = 'index.html';
39
- const isInitialized = await utils.isInitialized(strapi);
40
- const data = {
41
- serverTime: new Date().toUTCString(),
42
- isInitialized,
43
- ..._.pick(strapi, [
44
- 'config.info.version',
45
- 'config.info.name',
46
- 'config.admin.url',
47
- 'config.server.url',
48
- 'config.environment',
49
- 'config.serveAdminPanel',
50
- ]),
51
- };
52
- const content = _.template(index)(data);
53
- const body = stream.Readable({
54
- read() {
55
- this.push(Buffer.from(content));
56
- this.push(null);
57
- },
58
- });
59
- // Serve static.
60
- ctx.type = 'html';
61
- ctx.body = body;
62
- };
30
+ if (ctx.body != null || ctx.status !== 404) return;
63
31
 
64
- strapi.router.get('/', serveIndexPage);
65
- strapi.router.get('/index.html', serveIndexPage);
66
- strapi.router.get(
67
- '/assets/images/(.*)',
68
- serveStatic(path.resolve(__dirname, 'assets/images'), { maxage: maxAge, defer: true })
69
- );
70
- }
32
+ ctx.url = 'index.html';
33
+ const isInitialized = await utils.isInitialized(strapi);
34
+ const data = {
35
+ serverTime: new Date().toUTCString(),
36
+ isInitialized,
37
+ ..._.pick(strapi, [
38
+ 'config.info.version',
39
+ 'config.info.name',
40
+ 'config.admin.url',
41
+ 'config.server.url',
42
+ 'config.environment',
43
+ 'config.serveAdminPanel',
44
+ ]),
45
+ };
46
+ const content = _.template(index)(data);
47
+ const body = stream.Readable({
48
+ read() {
49
+ this.push(Buffer.from(content));
50
+ this.push(null);
51
+ },
52
+ });
53
+ // Serve static.
54
+ ctx.type = 'html';
55
+ ctx.body = body;
56
+ };
71
57
 
72
- // serve files in public folder unless a sub router renders something else
73
- strapi.router.get(
74
- '/(.*)',
75
- koaStatic(staticDir, {
58
+ strapi.server.routes([
59
+ {
60
+ method: 'GET',
61
+ path: '/',
62
+ handler: serveIndexPage,
63
+ config: { auth: false },
64
+ },
65
+ {
66
+ method: 'GET',
67
+ path: '/index.html',
68
+ handler: serveIndexPage,
69
+ config: { auth: false },
70
+ },
71
+ {
72
+ method: 'GET',
73
+ path: '/assets/images/(.*)',
74
+ handler: serveStatic(path.resolve(__dirname, 'assets/images'), {
76
75
  maxage: maxAge,
77
76
  defer: true,
78
- })
79
- );
80
-
81
- if (!strapi.config.serveAdminPanel) return;
82
-
83
- const buildDir = path.resolve(strapi.dir, 'build');
84
- const serveAdmin = ctx => {
85
- ctx.type = 'html';
86
- ctx.body = fs.createReadStream(path.join(buildDir + '/index.html'));
87
- };
88
-
89
- strapi.router.get(
90
- `${strapi.config.admin.path}/*`,
91
- serveStatic(buildDir, { maxage: maxAge, defer: false, index: 'index.html' })
92
- );
77
+ }),
78
+ config: { auth: false },
79
+ },
80
+ {
81
+ method: 'GET',
82
+ path: '/(.*)',
83
+ handler: koaStatic(strapi.dirs.public, {
84
+ maxage: maxAge,
85
+ defer: true,
86
+ }),
87
+ config: { auth: false },
88
+ },
89
+ ]);
90
+ }
93
91
 
94
- strapi.router.get(`${strapi.config.admin.path}`, serveAdmin);
95
- strapi.router.get(`${strapi.config.admin.path}/*`, serveAdmin);
96
- },
97
- };
92
+ return null;
98
93
  };
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ const { defaultsDeep } = require('lodash/fp');
4
+ const qs = require('qs');
5
+
6
+ const defaults = {
7
+ strictNullHandling: true,
8
+ arrayLimit: 100,
9
+ depth: 20,
10
+ };
11
+
12
+ /**
13
+ * Body parser hook
14
+ */
15
+ const addQsParser = (app, settings) => {
16
+ Object.defineProperty(app.request, 'query', {
17
+ configurable: false,
18
+ enumerable: true,
19
+ /*
20
+ * Get parsed query-string.
21
+ */
22
+ get() {
23
+ const qstr = this.querystring;
24
+ const cache = (this._querycache = this._querycache || {});
25
+ return cache[qstr] || (cache[qstr] = qs.parse(qstr, settings));
26
+ },
27
+
28
+ /*
29
+ * Set query-string as an object.
30
+ */
31
+ set(obj) {
32
+ this.querystring = qs.stringify(obj);
33
+ },
34
+ });
35
+
36
+ return app;
37
+ };
38
+
39
+ /**
40
+ * @type {import('./').MiddlewareFactory}
41
+ */
42
+ module.exports = (config, { strapi }) => {
43
+ addQsParser(strapi.server.app, defaultsDeep(defaults, config));
44
+
45
+ return null;
46
+ };
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @type {import('./').MiddlewareFactory}
5
+ */
6
+ module.exports = () => {
7
+ return async (ctx, next) => {
8
+ const start = Date.now();
9
+
10
+ await next();
11
+
12
+ const delta = Math.ceil(Date.now() - start);
13
+ ctx.set('X-Response-Time', delta + 'ms');
14
+ };
15
+ };
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const { prop, isFunction } = require('lodash/fp');
4
+
5
+ /**
6
+ * @type {import('./').MiddlewareFactory}
7
+ */
8
+ module.exports = (config = {}) => {
9
+ return async (ctx, next) => {
10
+ await next();
11
+
12
+ const status = ctx.status;
13
+ const handler = prop(`handlers.${status}`, config);
14
+
15
+ if (isFunction(handler)) {
16
+ await handler(ctx);
17
+ }
18
+ };
19
+ };
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ const { defaultsDeep, merge } = require('lodash/fp');
4
+ const helmet = require('koa-helmet');
5
+
6
+ const defaults = {
7
+ crossOriginEmbedderPolicy: false,
8
+ crossOriginOpenerPolicy: false,
9
+ crossOriginResourcePolicy: false,
10
+ originAgentCluster: false,
11
+ contentSecurityPolicy: {
12
+ useDefaults: true,
13
+ directives: {
14
+ 'connect-src': ["'self'", 'https:'],
15
+ 'img-src': ["'self'", 'data:', 'blob:'],
16
+ 'media-src': ["'self'", 'data:', 'blob:'],
17
+ upgradeInsecureRequests: null,
18
+ },
19
+ },
20
+ xssFilter: false,
21
+ hsts: {
22
+ maxAge: 31536000,
23
+ includeSubDomains: true,
24
+ },
25
+ frameguard: {
26
+ action: 'sameorigin',
27
+ },
28
+ };
29
+
30
+ /**
31
+ * @type {import('./').MiddlewareFactory}
32
+ */
33
+ module.exports = config => (ctx, next) => {
34
+ let helmetConfig = defaultsDeep(defaults, config);
35
+
36
+ if (
37
+ ctx.method === 'GET' &&
38
+ ['/graphql', '/documentation'].some(str => ctx.path.startsWith(str))
39
+ ) {
40
+ helmetConfig = merge(helmetConfig, {
41
+ contentSecurityPolicy: {
42
+ directives: {
43
+ 'script-src': ["'self'", "'unsafe-inline'", 'cdn.jsdelivr.net'],
44
+ 'img-src': ["'self'", 'data:', 'cdn.jsdelivr.net', 'strapi.io'],
45
+ },
46
+ },
47
+ });
48
+ }
49
+
50
+ return helmet(helmetConfig)(ctx, next);
51
+ };