@akemona-org/strapi 3.7.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 (125) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +163 -0
  3. package/bin/strapi.js +239 -0
  4. package/index.d.ts +13 -0
  5. package/lib/Strapi.js +498 -0
  6. package/lib/commands/admin-reset.js +51 -0
  7. package/lib/commands/build.js +47 -0
  8. package/lib/commands/configurationDump.js +50 -0
  9. package/lib/commands/configurationRestore.js +160 -0
  10. package/lib/commands/console.js +26 -0
  11. package/lib/commands/develop.js +155 -0
  12. package/lib/commands/generate-template.js +97 -0
  13. package/lib/commands/generate.js +66 -0
  14. package/lib/commands/install.js +48 -0
  15. package/lib/commands/new.js +11 -0
  16. package/lib/commands/start.js +8 -0
  17. package/lib/commands/uninstall.js +68 -0
  18. package/lib/commands/watchAdmin.js +35 -0
  19. package/lib/core/app-configuration/config-loader.js +56 -0
  20. package/lib/core/app-configuration/config-provider.js +28 -0
  21. package/lib/core/app-configuration/index.js +99 -0
  22. package/lib/core/bootstrap.js +166 -0
  23. package/lib/core/fs.js +52 -0
  24. package/lib/core/index.js +21 -0
  25. package/lib/core/load-admin.js +36 -0
  26. package/lib/core/load-apis.js +22 -0
  27. package/lib/core/load-components.js +43 -0
  28. package/lib/core/load-extensions.js +71 -0
  29. package/lib/core/load-functions.js +21 -0
  30. package/lib/core/load-hooks.js +117 -0
  31. package/lib/core/load-middlewares.js +130 -0
  32. package/lib/core/load-modules.js +61 -0
  33. package/lib/core/load-plugins.js +68 -0
  34. package/lib/core/load-policies.js +36 -0
  35. package/lib/core/walk.js +27 -0
  36. package/lib/core-api/controller.js +158 -0
  37. package/lib/core-api/index.js +33 -0
  38. package/lib/core-api/service/collection-type.js +122 -0
  39. package/lib/core-api/service/index.js +81 -0
  40. package/lib/core-api/service/single-type.js +68 -0
  41. package/lib/hooks/index.js +97 -0
  42. package/lib/index.js +3 -0
  43. package/lib/load/check-reserved-filename.js +18 -0
  44. package/lib/load/filepath-to-prop-path.js +22 -0
  45. package/lib/load/glob.js +15 -0
  46. package/lib/load/index.js +9 -0
  47. package/lib/load/load-config-files.js +22 -0
  48. package/lib/load/load-files.js +56 -0
  49. package/lib/load/package-path.js +9 -0
  50. package/lib/load/require-file-parse.js +15 -0
  51. package/lib/middlewares/boom/defaults.json +5 -0
  52. package/lib/middlewares/boom/index.js +147 -0
  53. package/lib/middlewares/cors/index.js +66 -0
  54. package/lib/middlewares/cron/defaults.json +5 -0
  55. package/lib/middlewares/cron/index.js +43 -0
  56. package/lib/middlewares/csp/defaults.json +5 -0
  57. package/lib/middlewares/csp/index.js +26 -0
  58. package/lib/middlewares/favicon/defaults.json +7 -0
  59. package/lib/middlewares/favicon/index.js +35 -0
  60. package/lib/middlewares/gzip/defaults.json +6 -0
  61. package/lib/middlewares/gzip/index.js +19 -0
  62. package/lib/middlewares/hsts/defaults.json +7 -0
  63. package/lib/middlewares/hsts/index.js +30 -0
  64. package/lib/middlewares/index.js +120 -0
  65. package/lib/middlewares/ip/defaults.json +7 -0
  66. package/lib/middlewares/ip/index.js +25 -0
  67. package/lib/middlewares/language/defaults.json +9 -0
  68. package/lib/middlewares/language/index.js +40 -0
  69. package/lib/middlewares/logger/defaults.json +8 -0
  70. package/lib/middlewares/logger/index.js +63 -0
  71. package/lib/middlewares/p3p/defaults.json +6 -0
  72. package/lib/middlewares/p3p/index.js +29 -0
  73. package/lib/middlewares/parser/defaults.json +10 -0
  74. package/lib/middlewares/parser/index.js +71 -0
  75. package/lib/middlewares/poweredBy/defaults.json +5 -0
  76. package/lib/middlewares/poweredBy/index.js +16 -0
  77. package/lib/middlewares/public/assets/images/group_people_1.png +0 -0
  78. package/lib/middlewares/public/assets/images/group_people_2.png +0 -0
  79. package/lib/middlewares/public/assets/images/group_people_3.png +0 -0
  80. package/lib/middlewares/public/assets/images/logo_login.png +0 -0
  81. package/lib/middlewares/public/defaults.json +8 -0
  82. package/lib/middlewares/public/index.html +66 -0
  83. package/lib/middlewares/public/index.js +98 -0
  84. package/lib/middlewares/public/serve-static.js +23 -0
  85. package/lib/middlewares/responseTime/defaults.json +5 -0
  86. package/lib/middlewares/responseTime/index.js +25 -0
  87. package/lib/middlewares/responses/defaults.json +5 -0
  88. package/lib/middlewares/responses/index.js +18 -0
  89. package/lib/middlewares/router/defaults.json +7 -0
  90. package/lib/middlewares/router/index.js +64 -0
  91. package/lib/middlewares/router/utils/composeEndpoint.js +25 -0
  92. package/lib/middlewares/router/utils/routerChecker.js +92 -0
  93. package/lib/middlewares/session/defaults.json +18 -0
  94. package/lib/middlewares/session/index.js +140 -0
  95. package/lib/middlewares/xframe/defaults.json +6 -0
  96. package/lib/middlewares/xframe/index.js +33 -0
  97. package/lib/middlewares/xss/defaults.json +6 -0
  98. package/lib/middlewares/xss/index.js +30 -0
  99. package/lib/services/core-store.js +144 -0
  100. package/lib/services/entity-service.js +260 -0
  101. package/lib/services/entity-validator/index.js +199 -0
  102. package/lib/services/entity-validator/validators.js +125 -0
  103. package/lib/services/event-hub.js +15 -0
  104. package/lib/services/metrics/index.js +103 -0
  105. package/lib/services/metrics/is-truthy.js +9 -0
  106. package/lib/services/metrics/middleware.js +33 -0
  107. package/lib/services/metrics/rate-limiter.js +27 -0
  108. package/lib/services/metrics/sender.js +76 -0
  109. package/lib/services/metrics/stringify-deep.js +22 -0
  110. package/lib/services/utils/upload-files.js +70 -0
  111. package/lib/services/webhook-runner.js +159 -0
  112. package/lib/services/webhook-store.js +97 -0
  113. package/lib/services/worker-queue.js +58 -0
  114. package/lib/utils/addSlash.js +10 -0
  115. package/lib/utils/ee.js +123 -0
  116. package/lib/utils/get-prefixed-dependencies.js +7 -0
  117. package/lib/utils/index.js +25 -0
  118. package/lib/utils/openBrowser.js +145 -0
  119. package/lib/utils/resources/key.pub +9 -0
  120. package/lib/utils/resources/openChrome.applescript +83 -0
  121. package/lib/utils/run-checks.js +37 -0
  122. package/lib/utils/success.js +31 -0
  123. package/lib/utils/update-notifier/index.js +96 -0
  124. package/lib/utils/url-from-segments.js +13 -0
  125. package/package.json +143 -0
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ const { propOr } = require('lodash/fp');
4
+
5
+ const {
6
+ hasDraftAndPublish,
7
+ constants: { PUBLISHED_AT_ATTRIBUTE },
8
+ } = require('@akemona-org/strapi-utils').contentTypes;
9
+
10
+ const setPublishedAt = (data) => {
11
+ data[PUBLISHED_AT_ATTRIBUTE] = propOr(new Date(), PUBLISHED_AT_ATTRIBUTE, data);
12
+ };
13
+
14
+ /**
15
+ *
16
+ * Returns a collection type service to handle default core-api actions
17
+ */
18
+ const createCollectionTypeService = ({ model, strapi, utils }) => {
19
+ const { modelName } = model;
20
+
21
+ const { sanitizeInput, getFetchParams } = utils;
22
+
23
+ return {
24
+ /**
25
+ * Promise to fetch all records
26
+ *
27
+ * @return {Promise}
28
+ */
29
+ find(params, populate) {
30
+ return strapi.entityService.find(
31
+ { params: getFetchParams(params), populate },
32
+ { model: modelName }
33
+ );
34
+ },
35
+
36
+ /**
37
+ * Promise to fetch record
38
+ *
39
+ * @return {Promise}
40
+ */
41
+
42
+ findOne(params, populate) {
43
+ return strapi.entityService.findOne(
44
+ { params: getFetchParams(params), populate },
45
+ { model: modelName }
46
+ );
47
+ },
48
+
49
+ /**
50
+ * Promise to count record
51
+ *
52
+ * @return {Promise}
53
+ */
54
+
55
+ count(params) {
56
+ return strapi.entityService.count({ params: getFetchParams(params) }, { model: modelName });
57
+ },
58
+
59
+ /**
60
+ * Promise to add record
61
+ *
62
+ * @return {Promise}
63
+ */
64
+
65
+ create(data, { files } = {}) {
66
+ const sanitizedData = sanitizeInput(data);
67
+ if (hasDraftAndPublish(model)) {
68
+ setPublishedAt(sanitizedData);
69
+ }
70
+
71
+ return strapi.entityService.create({ data: sanitizedData, files }, { model: modelName });
72
+ },
73
+
74
+ /**
75
+ * Promise to edit record
76
+ *
77
+ * @return {Promise}
78
+ */
79
+
80
+ update(params, data, { files } = {}) {
81
+ const sanitizedData = sanitizeInput(data);
82
+ return strapi.entityService.update(
83
+ { params, data: sanitizedData, files },
84
+ { model: modelName }
85
+ );
86
+ },
87
+
88
+ /**
89
+ * Promise to delete a record
90
+ *
91
+ * @return {Promise}
92
+ */
93
+
94
+ delete(params) {
95
+ return strapi.entityService.delete({ params }, { model: modelName });
96
+ },
97
+
98
+ /**
99
+ * Promise to search records
100
+ *
101
+ * @return {Promise}
102
+ */
103
+
104
+ search(params) {
105
+ return strapi.entityService.search({ params: getFetchParams(params) }, { model: modelName });
106
+ },
107
+
108
+ /**
109
+ * Promise to count searched records
110
+ *
111
+ * @return {Promise}
112
+ */
113
+ countSearch(params) {
114
+ return strapi.entityService.countSearch(
115
+ { params: getFetchParams(params) },
116
+ { model: modelName }
117
+ );
118
+ },
119
+ };
120
+ };
121
+
122
+ module.exports = createCollectionTypeService;
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+
5
+ const {
6
+ isSingleType,
7
+ getNonWritableAttributes,
8
+ constants: { DP_PUB_STATE_LIVE },
9
+ } = require('@akemona-org/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
+ * Default limit values from config
31
+ * @return {{maxLimit: number, defaultLimit: number}}
32
+ */
33
+ const getLimitConfigDefaults = () => ({
34
+ defaultLimit: _.toNumber(strapi.config.get('api.rest.defaultLimit', 100)),
35
+ maxLimit: _.toNumber(strapi.config.get('api.rest.maxLimit')) || null,
36
+ });
37
+
38
+ const getLimitParam = (params) => {
39
+ const { defaultLimit, maxLimit } = getLimitConfigDefaults();
40
+
41
+ if (params._limit === undefined) {
42
+ return defaultLimit;
43
+ }
44
+
45
+ const limit = _.toNumber(params._limit);
46
+ // if there is max limit set and params._limit exceeds this number, return configured max limit
47
+ if (maxLimit && (limit === -1 || limit > maxLimit)) {
48
+ return maxLimit;
49
+ }
50
+
51
+ return limit;
52
+ };
53
+
54
+ /**
55
+ * Create default fetch params
56
+ * @param {*} params
57
+ * @returns
58
+ */
59
+ const getFetchParams = (params = {}) => {
60
+ return {
61
+ _publicationState: DP_PUB_STATE_LIVE,
62
+ ...params,
63
+ _limit: getLimitParam(params),
64
+ };
65
+ };
66
+
67
+ /**
68
+ * Mixins
69
+ */
70
+ const createUtils = ({ model }) => {
71
+ return {
72
+ // make sure to keep the call to getNonWritableAttributes dynamic
73
+ sanitizeInput: (data) => _.omit(data, getNonWritableAttributes(model)),
74
+ getFetchParams,
75
+ };
76
+ };
77
+
78
+ module.exports = {
79
+ createService,
80
+ getFetchParams,
81
+ };
@@ -0,0 +1,68 @@
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 { modelName } = model;
8
+ const { sanitizeInput, getFetchParams } = utils;
9
+
10
+ return {
11
+ /**
12
+ * Returns singleType content
13
+ *
14
+ * @return {Promise}
15
+ */
16
+ find(params, populate) {
17
+ return strapi.entityService.find(
18
+ { params: getFetchParams(params), populate },
19
+ { model: modelName }
20
+ );
21
+ },
22
+
23
+ /**
24
+ * Creates or updates a singleType content
25
+ *
26
+ * @return {Promise}
27
+ */
28
+ async createOrUpdate(data, { files, query } = {}) {
29
+ const entity = await this.find(query);
30
+ const sanitizedData = sanitizeInput(data);
31
+
32
+ if (!entity) {
33
+ const count = await strapi.query(modelName).count();
34
+ if (count >= 1) {
35
+ throw strapi.errors.badRequest('singleType.alreadyExists');
36
+ }
37
+
38
+ return strapi.entityService.create({ data: sanitizedData, files }, { model: modelName });
39
+ } else {
40
+ return strapi.entityService.update(
41
+ {
42
+ params: {
43
+ id: entity.id,
44
+ },
45
+ data: sanitizedData,
46
+ files,
47
+ },
48
+ { model: modelName }
49
+ );
50
+ }
51
+ },
52
+
53
+ /**
54
+ * Deletes the singleType content
55
+ *
56
+ * @return {Promise}
57
+ */
58
+ async delete(params) {
59
+ const entity = await this.find(params);
60
+
61
+ if (!entity) return;
62
+
63
+ return strapi.entityService.delete({ params: { id: entity.id } }, { model: modelName });
64
+ },
65
+ };
66
+ };
67
+
68
+ module.exports = createSingleTypeService;
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ const { uniq, difference, get, isUndefined, merge } = require('lodash');
4
+
5
+ module.exports = async function() {
6
+ /** Utils */
7
+
8
+ const hookConfig = this.config.hook;
9
+
10
+ // check if a hook exists
11
+ const hookExists = key => {
12
+ return !isUndefined(this.hook[key]);
13
+ };
14
+
15
+ // check if a hook is enabled
16
+ const hookEnabled = key => get(hookConfig, ['settings', key, 'enabled'], false) === true;
17
+
18
+ // list of enabled hooks
19
+ const enableddHook = Object.keys(this.hook).filter(hookEnabled);
20
+
21
+ // Method to initialize hooks and emit an event.
22
+ const initialize = hookKey => {
23
+ if (this.hook[hookKey].loaded === true) return;
24
+
25
+ const module = this.hook[hookKey].load;
26
+ const hookTimeout = get(hookConfig, ['settings', hookKey, 'timeout'], hookConfig.timeout);
27
+
28
+ return new Promise((resolve, reject) => {
29
+ const timeout = setTimeout(
30
+ () => reject(`(hook: ${hookKey}) is taking too long to load.`),
31
+ hookTimeout || 1000
32
+ );
33
+
34
+ this.hook[hookKey] = merge(this.hook[hookKey], module);
35
+
36
+ Promise.resolve()
37
+ .then(() => module.initialize())
38
+ .then(() => {
39
+ clearTimeout(timeout);
40
+ this.hook[hookKey].loaded = true;
41
+ resolve();
42
+ })
43
+ .catch(err => {
44
+ clearTimeout(timeout);
45
+
46
+ if (err) {
47
+ return reject(err);
48
+ }
49
+ });
50
+ });
51
+ };
52
+
53
+ /**
54
+ * Run init functions
55
+ */
56
+
57
+ // Run beforeInitialize of every hook
58
+ await Promise.all(
59
+ enableddHook.map(key => {
60
+ const { beforeInitialize } = this.hook[key].load;
61
+ if (typeof beforeInitialize === 'function') {
62
+ return beforeInitialize();
63
+ }
64
+ })
65
+ );
66
+
67
+ // run the initialization of an array of hooks sequentially
68
+ const initdHookSeq = async hookArr => {
69
+ for (let key of uniq(hookArr)) {
70
+ await initialize(key);
71
+ }
72
+ };
73
+
74
+ const hooksBefore = get(hookConfig, 'load.before', [])
75
+ .filter(hookExists)
76
+ .filter(hookEnabled);
77
+
78
+ const hooksAfter = get(hookConfig, 'load.after', [])
79
+ .filter(hookExists)
80
+ .filter(hookEnabled);
81
+
82
+ const hooksOrder = get(hookConfig, 'load.order', [])
83
+ .filter(hookExists)
84
+ .filter(hookEnabled);
85
+
86
+ const unspecifieddHook = difference(enableddHook, hooksBefore, hooksOrder, hooksAfter);
87
+
88
+ // before
89
+ await initdHookSeq(hooksBefore);
90
+
91
+ // ordered // rest of hooks
92
+ await initdHookSeq(hooksOrder);
93
+ await initdHookSeq(unspecifieddHook);
94
+
95
+ // after
96
+ await initdHookSeq(hooksAfter);
97
+ };
package/lib/index.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./Strapi');
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+
5
+ // files to load with filename key
6
+ const prefixedPaths = [
7
+ 'functions',
8
+ 'policies',
9
+ 'locales',
10
+ 'hook',
11
+ 'middleware',
12
+ 'language',
13
+ 'layout',
14
+ ];
15
+
16
+ module.exports = function checkReservedFilenames(file) {
17
+ return _.some(prefixedPaths, e => file.indexOf(`config/${e}`) >= 0) ? true : false;
18
+ };
@@ -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,22 @@
1
+ 'use strict';
2
+
3
+ const loadFiles = require('./load-files');
4
+ const requireFileAndParse = require('./require-file-parse');
5
+ const checkReservedFilename = require('./check-reserved-filename');
6
+
7
+ /**
8
+ * @param {string} dir - directory from which to load configs
9
+ * @param {string} pattern - glob pattern to search for config files
10
+ */
11
+ const loadConfigFiles = (dir, pattern = 'config/**/*.+(js|json)') =>
12
+ loadFiles(dir, pattern, {
13
+ requireFn: requireFileAndParse,
14
+ shouldUseFileNameAsKey: checkReservedFilename,
15
+ globArgs: {
16
+ // used to load .init.json at first startup
17
+ dot: true,
18
+ ignore: ['config/**/*.test.js'],
19
+ },
20
+ });
21
+
22
+ module.exports = loadConfigFiles;
@@ -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,15 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { templateConfiguration } = require('@akemona-org/strapi-utils');
5
+
6
+ /**
7
+ * Requires a file and eval expression if it is a json
8
+ * @param {string} filePath - file path
9
+ */
10
+ module.exports = (filePath) => {
11
+ if (path.extname(filePath) === '.json') {
12
+ return templateConfiguration(require(filePath));
13
+ }
14
+ return require(filePath);
15
+ };
@@ -0,0 +1,5 @@
1
+ {
2
+ "boom": {
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('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.app.context, 'response');
69
+ this.createResponses();
70
+
71
+ strapi.errors = Boom;
72
+ strapi.app.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.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.app.use(async (ctx, next) => {
96
+ await next();
97
+ // Empty body is considered as `notFound` response.
98
+ if (_.isNil(ctx.body) && _.isNil(ctx.status)) {
99
+ ctx.notFound();
100
+ }
101
+ });
102
+ },
103
+
104
+ // Custom function to avoid ctx.body repeat
105
+ createResponses() {
106
+ boomMethods.forEach(method => {
107
+ strapi.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.app.response.send = function(data, status = 200) {
123
+ this.status = status;
124
+ this.body = data;
125
+ };
126
+
127
+ strapi.app.response.created = function(data) {
128
+ this.status = 201;
129
+ this.body = data;
130
+ };
131
+
132
+ strapi.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
+ };