@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.
Files changed (143) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +144 -0
  3. package/bin/strapi.js +186 -0
  4. package/lib/Strapi.js +470 -0
  5. package/lib/commands/admin-reset.js +51 -0
  6. package/lib/commands/build.js +56 -0
  7. package/lib/commands/configurationDump.js +50 -0
  8. package/lib/commands/configurationRestore.js +169 -0
  9. package/lib/commands/console.js +26 -0
  10. package/lib/commands/develop.js +157 -0
  11. package/lib/commands/generate-template.js +97 -0
  12. package/lib/commands/install.js +48 -0
  13. package/lib/commands/new.js +11 -0
  14. package/lib/commands/start.js +8 -0
  15. package/lib/commands/uninstall.js +68 -0
  16. package/lib/commands/watchAdmin.js +45 -0
  17. package/lib/container.js +45 -0
  18. package/lib/core/app-configuration/config-loader.js +20 -0
  19. package/lib/core/app-configuration/index.js +75 -0
  20. package/lib/core/app-configuration/load-config-file.js +43 -0
  21. package/lib/core/app-configuration/load-functions.js +28 -0
  22. package/lib/core/bootstrap.js +60 -0
  23. package/lib/core/domain/component/index.js +24 -0
  24. package/lib/core/domain/component/validator.js +29 -0
  25. package/lib/core/domain/content-type/index.js +140 -0
  26. package/lib/core/domain/content-type/validator.js +64 -0
  27. package/lib/core/domain/module/index.js +106 -0
  28. package/lib/core/domain/module/validation.js +36 -0
  29. package/lib/core/loaders/admin.js +16 -0
  30. package/lib/core/loaders/apis.js +157 -0
  31. package/lib/core/loaders/components.js +41 -0
  32. package/lib/core/loaders/index.js +11 -0
  33. package/lib/core/loaders/middlewares.js +86 -0
  34. package/lib/core/loaders/plugins/get-enabled-plugins.js +100 -0
  35. package/lib/core/loaders/plugins/index.js +109 -0
  36. package/lib/core/loaders/policies.js +28 -0
  37. package/lib/core/loaders/src-index.js +38 -0
  38. package/lib/core/registries/apis.js +43 -0
  39. package/lib/core/registries/config.js +21 -0
  40. package/lib/core/registries/content-types.js +53 -0
  41. package/lib/core/registries/controllers.js +43 -0
  42. package/lib/core/registries/hooks.js +37 -0
  43. package/lib/core/registries/middlewares.js +30 -0
  44. package/lib/core/registries/modules.js +44 -0
  45. package/lib/core/registries/plugins.js +28 -0
  46. package/lib/core/registries/policies.js +38 -0
  47. package/lib/core/registries/services.js +58 -0
  48. package/lib/core/utils.js +35 -0
  49. package/lib/core-api/controller/collection-type.js +84 -0
  50. package/lib/core-api/controller/index.js +26 -0
  51. package/lib/core-api/controller/single-type.js +44 -0
  52. package/lib/core-api/controller/transform.js +97 -0
  53. package/lib/core-api/index.js +39 -0
  54. package/lib/core-api/service/collection-type.js +84 -0
  55. package/lib/core-api/service/index.js +55 -0
  56. package/lib/core-api/service/pagination.js +125 -0
  57. package/lib/core-api/service/single-type.js +58 -0
  58. package/lib/index.d.ts +26 -0
  59. package/lib/index.js +3 -0
  60. package/lib/load/filepath-to-prop-path.js +22 -0
  61. package/lib/load/glob.js +15 -0
  62. package/lib/load/index.js +9 -0
  63. package/lib/load/load-files.js +56 -0
  64. package/lib/load/package-path.js +9 -0
  65. package/lib/middlewares/cors/index.js +66 -0
  66. package/lib/middlewares/error/defaults.json +5 -0
  67. package/lib/middlewares/error/index.js +147 -0
  68. package/lib/middlewares/favicon/defaults.json +7 -0
  69. package/lib/middlewares/favicon/index.js +31 -0
  70. package/lib/middlewares/gzip/defaults.json +6 -0
  71. package/lib/middlewares/gzip/index.js +19 -0
  72. package/lib/middlewares/helmet/defaults.json +18 -0
  73. package/lib/middlewares/helmet/index.js +9 -0
  74. package/lib/middlewares/index.js +120 -0
  75. package/lib/middlewares/ip/defaults.json +7 -0
  76. package/lib/middlewares/ip/index.js +25 -0
  77. package/lib/middlewares/logger/defaults.json +5 -0
  78. package/lib/middlewares/logger/index.js +37 -0
  79. package/lib/middlewares/parser/defaults.json +11 -0
  80. package/lib/middlewares/parser/index.js +75 -0
  81. package/lib/middlewares/poweredBy/defaults.json +5 -0
  82. package/lib/middlewares/poweredBy/index.js +16 -0
  83. package/lib/middlewares/public/assets/images/group_people_1.png +0 -0
  84. package/lib/middlewares/public/assets/images/group_people_2.png +0 -0
  85. package/lib/middlewares/public/assets/images/group_people_3.png +0 -0
  86. package/lib/middlewares/public/assets/images/logo_login.png +0 -0
  87. package/lib/middlewares/public/defaults.json +8 -0
  88. package/lib/middlewares/public/index.html +66 -0
  89. package/lib/middlewares/public/index.js +130 -0
  90. package/lib/middlewares/public/serve-static.js +23 -0
  91. package/lib/middlewares/responseTime/defaults.json +5 -0
  92. package/lib/middlewares/responseTime/index.js +25 -0
  93. package/lib/middlewares/responses/defaults.json +5 -0
  94. package/lib/middlewares/responses/index.js +19 -0
  95. package/lib/middlewares/router/defaults.json +7 -0
  96. package/lib/middlewares/router/index.js +97 -0
  97. package/lib/middlewares/session/defaults.json +18 -0
  98. package/lib/middlewares/session/index.js +140 -0
  99. package/lib/migrations/draft-publish.js +57 -0
  100. package/lib/services/auth/index.js +92 -0
  101. package/lib/services/core-store.js +145 -0
  102. package/lib/services/cron.js +54 -0
  103. package/lib/services/entity-service/components.js +365 -0
  104. package/lib/services/entity-service/index.d.ts +91 -0
  105. package/lib/services/entity-service/index.js +244 -0
  106. package/lib/services/entity-service/params.js +145 -0
  107. package/lib/services/entity-validator/index.js +187 -0
  108. package/lib/services/entity-validator/validators.js +123 -0
  109. package/lib/services/event-hub.js +15 -0
  110. package/lib/services/fs.js +58 -0
  111. package/lib/services/metrics/index.js +104 -0
  112. package/lib/services/metrics/is-truthy.js +9 -0
  113. package/lib/services/metrics/middleware.js +33 -0
  114. package/lib/services/metrics/rate-limiter.js +27 -0
  115. package/lib/services/metrics/sender.js +76 -0
  116. package/lib/services/metrics/stringify-deep.js +22 -0
  117. package/lib/services/server/admin-api.js +14 -0
  118. package/lib/services/server/api.js +32 -0
  119. package/lib/services/server/compose-endpoint.js +112 -0
  120. package/lib/services/server/content-api.js +16 -0
  121. package/lib/services/server/http-server.js +64 -0
  122. package/lib/services/server/index.js +108 -0
  123. package/lib/services/server/middleware.js +28 -0
  124. package/lib/services/server/policy.js +34 -0
  125. package/lib/services/server/routing.js +107 -0
  126. package/lib/services/utils/upload-files.js +79 -0
  127. package/lib/services/webhook-runner.js +155 -0
  128. package/lib/services/webhook-store.js +91 -0
  129. package/lib/services/worker-queue.js +58 -0
  130. package/lib/utils/addSlash.js +10 -0
  131. package/lib/utils/ee.js +123 -0
  132. package/lib/utils/get-dirs.js +15 -0
  133. package/lib/utils/get-prefixed-dependencies.js +7 -0
  134. package/lib/utils/index.js +11 -0
  135. package/lib/utils/is-initialized.js +23 -0
  136. package/lib/utils/open-browser.js +12 -0
  137. package/lib/utils/resources/key.pub +9 -0
  138. package/lib/utils/run-checks.js +22 -0
  139. package/lib/utils/startup-logger.js +90 -0
  140. package/lib/utils/success.js +31 -0
  141. package/lib/utils/update-notifier/index.js +97 -0
  142. package/lib/utils/url-from-segments.js +12 -0
  143. package/package.json +133 -0
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+
5
+ const {
6
+ isSingleType,
7
+ getNonWritableAttributes,
8
+ constants: { DP_PUB_STATE_LIVE },
9
+ } = require('@strapi/utils').contentTypes;
10
+
11
+ const createSingleTypeService = require('./single-type');
12
+ const createCollectionTypeService = require('./collection-type');
13
+
14
+ /**
15
+ * Returns a core api for the provided model
16
+ * @param {{ model: object, strapi: object }} context
17
+ * @returns {object}
18
+ */
19
+ const createService = ({ model, strapi }) => {
20
+ const utils = createUtils({ model });
21
+
22
+ if (isSingleType(model)) {
23
+ return createSingleTypeService({ model, strapi, utils });
24
+ }
25
+
26
+ return createCollectionTypeService({ model, strapi, utils });
27
+ };
28
+
29
+ /**
30
+ * Create default fetch params
31
+ * @param {*} params
32
+ * @returns
33
+ */
34
+ const getFetchParams = (params = {}) => {
35
+ return {
36
+ publicationState: DP_PUB_STATE_LIVE,
37
+ ...params,
38
+ };
39
+ };
40
+
41
+ /**
42
+ * Mixins
43
+ */
44
+ const createUtils = ({ model }) => {
45
+ return {
46
+ // make sure to keep the call to getNonWritableAttributes dynamic
47
+ sanitizeInput: data => _.omit(data, getNonWritableAttributes(model)),
48
+ getFetchParams,
49
+ };
50
+ };
51
+
52
+ module.exports = {
53
+ createService,
54
+ getFetchParams,
55
+ };
@@ -0,0 +1,125 @@
1
+ 'use strict';
2
+
3
+ const { has, toNumber, isUndefined } = require('lodash/fp');
4
+
5
+ /**
6
+ * Default limit values from config
7
+ * @return {{maxLimit: number, defaultLimit: number}}
8
+ */
9
+ const getLimitConfigDefaults = () => ({
10
+ defaultLimit: toNumber(strapi.config.get('api.rest.defaultLimit', 25)),
11
+ maxLimit: toNumber(strapi.config.get('api.rest.maxLimit')) || null,
12
+ });
13
+
14
+ /**
15
+ * if there is max limit set and limit exceeds this number, return configured max limit
16
+ * @param {number} limit - limit you want to cap
17
+ * @param {number?} maxLimit - maxlimit used has capping
18
+ * @returns {number}
19
+ */
20
+ const applyMaxLimit = (limit, maxLimit) => {
21
+ if (maxLimit && (limit === -1 || limit > maxLimit)) {
22
+ return maxLimit;
23
+ }
24
+
25
+ return limit;
26
+ };
27
+
28
+ const shouldCount = params => {
29
+ if (has('pagination.withCount', params)) {
30
+ const { withCount } = params.pagination;
31
+
32
+ if (typeof withCount === 'boolean') {
33
+ return withCount;
34
+ }
35
+
36
+ if (['true', 't', '1', 1].includes(withCount)) {
37
+ return true;
38
+ }
39
+
40
+ if (['false', 'f', '0', 0].includes(withCount)) {
41
+ return false;
42
+ }
43
+
44
+ throw new Error('Invalid withCount parameter. Expected "t","1","true","false","0","f"');
45
+ }
46
+
47
+ return Boolean(strapi.config.get('api.rest.withCount', true));
48
+ };
49
+
50
+ const isOffsetPagination = pagination => has('start', pagination) || has('limit', pagination);
51
+ const isPagedPagination = pagination => has('page', pagination) || has('pageSize', pagination);
52
+
53
+ const getPaginationInfo = params => {
54
+ const { defaultLimit, maxLimit } = getLimitConfigDefaults();
55
+
56
+ const { pagination } = params;
57
+
58
+ const isPaged = isPagedPagination(pagination);
59
+ const isOffset = isOffsetPagination(pagination);
60
+
61
+ if (!isPaged && !isOffset) {
62
+ return {
63
+ page: 1,
64
+ pageSize: defaultLimit,
65
+ };
66
+ }
67
+
68
+ if (isOffset && isPaged) {
69
+ throw new Error('Invalid pagination parameters. Expected either start/limit or page/pageSize');
70
+ }
71
+
72
+ if (isPagedPagination(pagination)) {
73
+ const pageSize = isUndefined(pagination.pageSize)
74
+ ? defaultLimit
75
+ : Math.max(1, toNumber(pagination.pageSize));
76
+
77
+ return {
78
+ page: Math.max(1, toNumber(pagination.page || 1)),
79
+ pageSize: applyMaxLimit(pageSize, maxLimit),
80
+ };
81
+ }
82
+
83
+ const limit = isUndefined(pagination.limit)
84
+ ? defaultLimit
85
+ : Math.max(1, toNumber(pagination.limit));
86
+
87
+ return {
88
+ start: Math.max(0, toNumber(pagination.start || 0)),
89
+ limit: applyMaxLimit(limit, maxLimit),
90
+ };
91
+ };
92
+
93
+ const convertPagedToStartLimit = pagination => {
94
+ if (isPagedPagination(pagination)) {
95
+ const { page, pageSize } = pagination;
96
+ return {
97
+ start: (page - 1) * pageSize,
98
+ limit: pageSize,
99
+ };
100
+ }
101
+
102
+ return pagination;
103
+ };
104
+
105
+ const transformPaginationResponse = (paginationInfo, count) => {
106
+ if (paginationInfo.page) {
107
+ return {
108
+ ...paginationInfo,
109
+ pageCount: Math.ceil(count / paginationInfo.pageSize),
110
+ total: count,
111
+ };
112
+ }
113
+
114
+ return {
115
+ ...paginationInfo,
116
+ total: count,
117
+ };
118
+ };
119
+
120
+ module.exports = {
121
+ getPaginationInfo,
122
+ convertPagedToStartLimit,
123
+ transformPaginationResponse,
124
+ shouldCount,
125
+ };
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Returns a single type service to handle default core-api actions
5
+ */
6
+ const createSingleTypeService = ({ model, strapi, utils }) => {
7
+ const { uid } = model;
8
+ const { sanitizeInput, getFetchParams } = utils;
9
+
10
+ return {
11
+ /**
12
+ * Returns singleType content
13
+ *
14
+ * @return {Promise}
15
+ */
16
+ find(params = {}) {
17
+ return strapi.entityService.findMany(uid, getFetchParams(params));
18
+ },
19
+
20
+ /**
21
+ * Creates or updates a singleType content
22
+ *
23
+ * @return {Promise}
24
+ */
25
+ async createOrUpdate(params = {}) {
26
+ const entity = await this.find(params);
27
+
28
+ const { data } = params;
29
+ const sanitizedData = sanitizeInput(data);
30
+
31
+ if (!entity) {
32
+ const count = await strapi.query(uid).count();
33
+ if (count >= 1) {
34
+ throw strapi.errors.badRequest('singleType.alreadyExists');
35
+ }
36
+
37
+ return strapi.entityService.create(uid, { ...params, data: sanitizedData });
38
+ }
39
+
40
+ return strapi.entityService.update(uid, entity.id, { ...params, data: sanitizedData });
41
+ },
42
+
43
+ /**
44
+ * Deletes the singleType content
45
+ *
46
+ * @return {Promise}
47
+ */
48
+ async delete(params = {}) {
49
+ const entity = await this.find(params);
50
+
51
+ if (!entity) return;
52
+
53
+ return strapi.entityService.delete(uid, entity.id);
54
+ },
55
+ };
56
+ };
57
+
58
+ module.exports = createSingleTypeService;
package/lib/index.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { Database } from '@strapi/database';
2
+ import { EntityService } from './services/entity-service';
3
+ import { Strapi as StrapiClass } from './Strapi';
4
+
5
+ interface StrapiInterface extends StrapiClass {
6
+ query: Database['query'];
7
+ entityService: EntityService;
8
+ }
9
+
10
+ export type Strapi = StrapiInterface;
11
+
12
+ declare global {
13
+ interface AllTypes {}
14
+ }
15
+
16
+ declare global {
17
+ export interface Global {
18
+ strapi: StrapiInterface;
19
+ }
20
+
21
+ export type Strapi = StrapiInterface;
22
+
23
+ const strapi: StrapiInterface;
24
+ }
25
+
26
+ export default function(opts): Strapi;
package/lib/index.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./Strapi');
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+
5
+ /**
6
+ * Returns a path (as an array) from a file path
7
+ * @param {string} filePath - a file path
8
+ * @param {boolean} useFileNameAsKey - wethear to skip the last path key
9
+ */
10
+ module.exports = (filePath, useFileNameAsKey = true) => {
11
+ let cleanPath = filePath.startsWith('./') ? filePath.slice(2) : filePath;
12
+
13
+ const prop = cleanPath
14
+ .replace(/(\.settings|\.json|\.js)/g, '')
15
+ .toLowerCase()
16
+ .split('/')
17
+ .map(p => _.trimStart(p, '.'))
18
+ .join('.')
19
+ .split('.');
20
+
21
+ return useFileNameAsKey === true ? prop : prop.slice(0, -1);
22
+ };
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ const glob = require('glob');
4
+
5
+ /**
6
+ * Promise based glob
7
+ */
8
+ module.exports = (...args) => {
9
+ return new Promise((resolve, reject) => {
10
+ glob(...args, (err, files) => {
11
+ if (err) return reject(err);
12
+ resolve(files);
13
+ });
14
+ });
15
+ };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const loadFiles = require('./load-files');
4
+ const findPackagePath = require('./package-path');
5
+
6
+ module.exports = {
7
+ loadFiles,
8
+ findPackagePath,
9
+ };
@@ -0,0 +1,56 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const _ = require('lodash');
5
+ const fse = require('fs-extra');
6
+ const glob = require('./glob');
7
+ const filePathToPath = require('./filepath-to-prop-path');
8
+
9
+ /**
10
+ * Returns an Object build from a list of files matching a glob pattern in a directory
11
+ * It builds a tree structure resembling the folder structure in dir
12
+ * @param {string} dir - Directory to load
13
+ * @param {string} pattern - Glob pattern to search for
14
+ * @param {Object} options - Options
15
+ * @param {Function} options.requireFn - Function that will require the matches files
16
+ * @param {Function} options.shouldUseFileNameAsKey - Weather to use the filename as a key in the Object path or not
17
+ * @param {Object} options.globArgs - extra glob function arguments
18
+ */
19
+ const loadFiles = async (
20
+ dir,
21
+ pattern,
22
+ { requireFn = require, shouldUseFileNameAsKey = () => true, globArgs = {} } = {}
23
+ ) => {
24
+ const root = {};
25
+ const files = await glob(pattern, { cwd: dir, ...globArgs });
26
+
27
+ for (let file of files) {
28
+ const absolutePath = path.resolve(dir, file);
29
+
30
+ // load module
31
+ delete require.cache[absolutePath];
32
+ let mod;
33
+
34
+ if (path.extname(absolutePath) === '.json') {
35
+ mod = await fse.readJson(absolutePath);
36
+ } else {
37
+ mod = requireFn(absolutePath);
38
+ }
39
+
40
+ Object.defineProperty(mod, '__filename__', {
41
+ enumerable: true,
42
+ configurable: false,
43
+ writable: false,
44
+ value: path.basename(file),
45
+ });
46
+
47
+ const propPath = filePathToPath(file, shouldUseFileNameAsKey(file));
48
+
49
+ if (propPath.length === 0) _.merge(root, mod);
50
+ _.merge(root, _.setWith({}, propPath, mod, Object));
51
+ }
52
+
53
+ return root;
54
+ };
55
+
56
+ module.exports = loadFiles;
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+
5
+ /**
6
+ * Returns the path to a node modules root directory (not the main file path)
7
+ * @param {string} moduleName - name of a node module
8
+ */
9
+ module.exports = moduleName => path.dirname(require.resolve(`${moduleName}/package.json`));
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+ const cors = require('@koa/cors');
7
+
8
+ const defaults = {
9
+ origin: '*',
10
+ maxAge: 31536000,
11
+ credentials: true,
12
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
13
+ headers: ['Content-Type', 'Authorization', 'Origin', 'Accept'],
14
+ keepHeadersOnError: false,
15
+ };
16
+
17
+ module.exports = strapi => {
18
+ return {
19
+ /**
20
+ * Initialize the hook
21
+ */
22
+ initialize() {
23
+ const {
24
+ origin,
25
+ expose,
26
+ maxAge,
27
+ credentials,
28
+ methods,
29
+ headers,
30
+ keepHeadersOnError,
31
+ } = Object.assign({}, defaults, strapi.config.get('middleware.settings.cors'));
32
+
33
+ strapi.server.use(
34
+ cors({
35
+ async origin(ctx) {
36
+ let originList;
37
+
38
+ if (typeof origin === 'function') {
39
+ originList = await origin(ctx);
40
+ } else {
41
+ originList = origin;
42
+ }
43
+
44
+ const whitelist = Array.isArray(originList) ? originList : originList.split(/\s*,\s*/);
45
+
46
+ const requestOrigin = ctx.accept.headers.origin;
47
+ if (whitelist.includes('*')) {
48
+ return '*';
49
+ }
50
+
51
+ if (!whitelist.includes(requestOrigin)) {
52
+ return ctx.throw(`${requestOrigin} is not a valid origin`);
53
+ }
54
+ return requestOrigin;
55
+ },
56
+ exposeHeaders: expose,
57
+ maxAge,
58
+ credentials,
59
+ allowMethods: methods,
60
+ allowHeaders: headers,
61
+ keepHeadersOnError,
62
+ })
63
+ );
64
+ },
65
+ };
66
+ };
@@ -0,0 +1,5 @@
1
+ {
2
+ "error": {
3
+ "enabled": true
4
+ }
5
+ }
@@ -0,0 +1,147 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Boom hook
5
+ */
6
+
7
+ // Public node modules.
8
+ const _ = require('lodash');
9
+ const Boom = require('@hapi/boom');
10
+ const delegate = require('delegates');
11
+
12
+ const boomMethods = [
13
+ 'badRequest',
14
+ 'unauthorized',
15
+ 'paymentRequired',
16
+ 'forbidden',
17
+ 'notFound',
18
+ 'methodNotAllowed',
19
+ 'notAcceptable',
20
+ 'proxyAuthRequired',
21
+ 'clientTimeout',
22
+ 'conflict',
23
+ 'resourceGone',
24
+ 'lengthRequired',
25
+ 'preconditionFailed',
26
+ 'entityTooLarge',
27
+ 'uriTooLong',
28
+ 'unsupportedMediaType',
29
+ 'rangeNotSatisfiable',
30
+ 'expectationFailed',
31
+ 'teapot',
32
+ 'badData',
33
+ 'locked',
34
+ 'failedDependency',
35
+ 'preconditionRequired',
36
+ 'tooManyRequests',
37
+ 'illegal',
38
+ 'badImplementation',
39
+ 'notImplemented',
40
+ 'badGateway',
41
+ 'serverUnavailable',
42
+ 'gatewayTimeout',
43
+ ];
44
+
45
+ const formatBoomPayload = boomError => {
46
+ if (!Boom.isBoom(boomError)) {
47
+ boomError = Boom.boomify(boomError, {
48
+ statusCode: boomError.status || 500,
49
+ });
50
+ }
51
+
52
+ const { output } = boomError;
53
+
54
+ if (output.statusCode < 500 && !_.isNil(boomError.data)) {
55
+ output.payload.data = boomError.data;
56
+ }
57
+
58
+ return { status: output.statusCode, body: output.payload };
59
+ };
60
+
61
+ module.exports = strapi => {
62
+ return {
63
+ /**
64
+ * Initialize the hook
65
+ */
66
+
67
+ initialize() {
68
+ this.delegator = delegate(strapi.server.app.context, 'response');
69
+ this.createResponses();
70
+
71
+ strapi.errors = Boom;
72
+ strapi.server.use(async (ctx, next) => {
73
+ try {
74
+ // App logic.
75
+ await next();
76
+ } catch (error) {
77
+ // emit error if configured
78
+ if (strapi.config.get('server.emitErrors', false)) {
79
+ strapi.server.app.emit('error', error, ctx);
80
+ }
81
+
82
+ // Log error.
83
+
84
+ const { status, body } = formatBoomPayload(error);
85
+
86
+ if (status >= 500) {
87
+ strapi.log.error(error);
88
+ }
89
+
90
+ ctx.body = body;
91
+ ctx.status = status;
92
+ }
93
+ });
94
+
95
+ strapi.server.use(async (ctx, next) => {
96
+ await next();
97
+ // Empty body is considered as `notFound` response.
98
+ if (_.isNil(ctx.body) && (_.isNil(ctx.status) || ctx.status === 404)) {
99
+ ctx.notFound();
100
+ }
101
+ });
102
+ },
103
+
104
+ // Custom function to avoid ctx.body repeat
105
+ createResponses() {
106
+ boomMethods.forEach(method => {
107
+ strapi.server.app.response[method] = function(msg, ...rest) {
108
+ const boomError = Boom[method](msg, ...rest) || {};
109
+
110
+ const { status, body } = formatBoomPayload(boomError);
111
+
112
+ // keep retro-compatibility for old error formats
113
+ body.message = msg || body.data || body.message;
114
+
115
+ this.body = body;
116
+ this.status = status;
117
+ };
118
+
119
+ this.delegator.method(method);
120
+ });
121
+
122
+ strapi.server.app.response.send = function(data, status = 200) {
123
+ this.status = status;
124
+ this.body = data;
125
+ };
126
+
127
+ strapi.server.app.response.created = function(data) {
128
+ this.status = 201;
129
+ this.body = data;
130
+ };
131
+
132
+ strapi.server.app.response.deleted = function(data) {
133
+ if (_.isNil(data)) {
134
+ this.status = 204;
135
+ } else {
136
+ this.status = 200;
137
+ this.body = data;
138
+ }
139
+ };
140
+
141
+ this.delegator
142
+ .method('send')
143
+ .method('created')
144
+ .method('deleted');
145
+ },
146
+ };
147
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "favicon": {
3
+ "enabled": true,
4
+ "path": "favicon.ico",
5
+ "maxAge": 86400000
6
+ }
7
+ }
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Node.js core.
8
+ const { resolve } = require('path');
9
+ const favicon = require('koa-favicon');
10
+
11
+ /**
12
+ * Favicon hook
13
+ */
14
+
15
+ module.exports = strapi => {
16
+ return {
17
+ /**
18
+ * Initialize the hook
19
+ */
20
+
21
+ initialize() {
22
+ const { maxAge, path: faviconPath } = strapi.config.middleware.settings.favicon;
23
+
24
+ strapi.server.use(
25
+ favicon(resolve(strapi.dirs.root, faviconPath), {
26
+ maxAge,
27
+ })
28
+ );
29
+ },
30
+ };
31
+ };
@@ -0,0 +1,6 @@
1
+ {
2
+ "gzip": {
3
+ "enabled": false,
4
+ "options": {}
5
+ }
6
+ }
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Gzip hook
5
+ */
6
+ const compress = require('koa-compress');
7
+
8
+ module.exports = strapi => {
9
+ return {
10
+ /**
11
+ * Initialize the hook
12
+ */
13
+
14
+ initialize() {
15
+ const { options = {} } = strapi.config.middleware.settings.gzip;
16
+ strapi.server.use(compress(options));
17
+ },
18
+ };
19
+ };
@@ -0,0 +1,18 @@
1
+ {
2
+ "helmet": {
3
+ "enabled": true,
4
+ "crossOriginEmbedderPolicy": false,
5
+ "crossOriginOpenerPolicy": false,
6
+ "crossOriginResourcePolicy": false,
7
+ "originAgentCluster": false,
8
+ "contentSecurityPolicy": false,
9
+ "xssFilter": false,
10
+ "hsts": {
11
+ "maxAge": 31536000,
12
+ "includeSubDomains": true
13
+ },
14
+ "frameguard": {
15
+ "action": "sameorigin"
16
+ }
17
+ }
18
+ }