@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,9 @@
1
+ 'use strict';
2
+
3
+ const helmet = require('koa-helmet');
4
+
5
+ module.exports = strapi => ({
6
+ initialize() {
7
+ strapi.server.use(helmet(strapi.config.middleware.settings.helmet));
8
+ },
9
+ });
@@ -0,0 +1,120 @@
1
+ 'use strict';
2
+
3
+ const { uniq, difference, get, isUndefined, merge } = require('lodash');
4
+
5
+ const requiredMiddlewares = [
6
+ 'auth',
7
+ 'responses',
8
+ 'router',
9
+ 'logger',
10
+ 'error',
11
+ 'cors',
12
+ 'cron',
13
+ 'xframe',
14
+ 'xss',
15
+ 'public',
16
+ 'favicon',
17
+ ];
18
+
19
+ module.exports = async function(strapi) {
20
+ /** Utils */
21
+ const middlewareConfig = strapi.config.middleware;
22
+
23
+ // check if a middleware exists
24
+ const middlewareExists = key => {
25
+ return !isUndefined(strapi.middleware[key]);
26
+ };
27
+
28
+ // check if a middleware is enabled
29
+ const middlewareEnabled = key => {
30
+ return (
31
+ requiredMiddlewares.includes(key) ||
32
+ get(middlewareConfig, ['settings', key, 'enabled'], false) === true
33
+ );
34
+ };
35
+
36
+ // list of enabled middlewares
37
+ const enabledMiddlewares = Object.keys(strapi.middleware).filter(middlewareEnabled);
38
+
39
+ // Method to initialize middlewares and emit an event.
40
+ const initialize = middlewareKey => {
41
+ if (strapi.middleware[middlewareKey].loaded === true) return;
42
+
43
+ const module = strapi.middleware[middlewareKey].load;
44
+
45
+ return new Promise((resolve, reject) => {
46
+ const timeout = setTimeout(
47
+ () => reject(`(middleware: ${middlewareKey}) is taking too long to load.`),
48
+ middlewareConfig.timeout || 1000
49
+ );
50
+ strapi.middleware[middlewareKey] = merge(strapi.middleware[middlewareKey], module);
51
+
52
+ Promise.resolve()
53
+ .then(() => module.initialize(strapi))
54
+ .then(() => {
55
+ clearTimeout(timeout);
56
+ strapi.middleware[middlewareKey].loaded = true;
57
+ resolve();
58
+ })
59
+ .catch(err => {
60
+ clearTimeout(timeout);
61
+
62
+ if (err) {
63
+ return reject(err);
64
+ }
65
+ });
66
+ });
67
+ };
68
+
69
+ /**
70
+ * Run init functions
71
+ */
72
+
73
+ // Run beforeInitialize of every middleware
74
+ await Promise.all(
75
+ enabledMiddlewares.map(key => {
76
+ const { beforeInitialize } = strapi.middleware[key].load;
77
+ if (typeof beforeInitialize === 'function') {
78
+ return beforeInitialize(strapi);
79
+ }
80
+ })
81
+ );
82
+
83
+ // run the initialization of an array of middlewares sequentially
84
+ const initMiddlewaresSeq = async middlewareArr => {
85
+ for (let key of uniq(middlewareArr)) {
86
+ await initialize(key);
87
+ }
88
+ };
89
+
90
+ const middlewaresBefore = get(middlewareConfig, 'load.before', [])
91
+ .filter(middlewareExists)
92
+ .filter(middlewareEnabled);
93
+
94
+ const middlewaresAfter = get(middlewareConfig, 'load.after', [])
95
+ .filter(middlewareExists)
96
+ .filter(middlewareEnabled);
97
+
98
+ const middlewaresOrder = get(middlewareConfig, 'load.order', [])
99
+ .filter(middlewareExists)
100
+ .filter(middlewareEnabled);
101
+
102
+ const unspecifiedMiddlewares = difference(
103
+ enabledMiddlewares,
104
+ middlewaresBefore,
105
+ middlewaresOrder,
106
+ middlewaresAfter
107
+ );
108
+
109
+ // before
110
+ await initMiddlewaresSeq(middlewaresBefore);
111
+
112
+ // ordered // rest of middlewares
113
+ await Promise.all([
114
+ initMiddlewaresSeq(middlewaresOrder),
115
+ Promise.all(unspecifiedMiddlewares.map(initialize)),
116
+ ]);
117
+
118
+ // after
119
+ await initMiddlewaresSeq(middlewaresAfter);
120
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "ip": {
3
+ "enabled": false,
4
+ "whiteList": [],
5
+ "blackList": []
6
+ }
7
+ }
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ const ip = require('koa-ip');
4
+ /**
5
+ * IP filter hook
6
+ */
7
+
8
+ module.exports = strapi => {
9
+ return {
10
+ /**
11
+ * Initialize the hook
12
+ */
13
+
14
+ initialize() {
15
+ const { whiteList, blackList } = strapi.config.middleware.settings.ip;
16
+
17
+ strapi.server.use(
18
+ ip({
19
+ whitelist: whiteList,
20
+ blacklist: blackList,
21
+ })
22
+ );
23
+ },
24
+ };
25
+ };
@@ -0,0 +1,5 @@
1
+ {
2
+ "logger": {
3
+ "enabled": true
4
+ }
5
+ }
@@ -0,0 +1,37 @@
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
+ * Logger hook
18
+ */
19
+
20
+ module.exports = strapi => {
21
+ return {
22
+ /**
23
+ * Initialize the hook
24
+ */
25
+ initialize() {
26
+ strapi.server.app.context.log = strapi.log;
27
+
28
+ strapi.server.use(async (ctx, next) => {
29
+ const start = Date.now();
30
+ await next();
31
+ const delta = Math.ceil(Date.now() - start);
32
+
33
+ strapi.log.http(`${ctx.method} ${ctx.url} (${delta} ms) ${codeToColor(ctx.status)}`);
34
+ });
35
+ },
36
+ };
37
+ };
@@ -0,0 +1,11 @@
1
+ {
2
+ "parser": {
3
+ "enabled": true,
4
+ "multipart": true,
5
+ "queryStringParser": {
6
+ "strictNullHandling": true,
7
+ "arrayLimit": 100,
8
+ "depth": 20
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+
3
+ const body = require('koa-body');
4
+ const qs = require('qs');
5
+ const { omit } = require('lodash');
6
+
7
+ /**
8
+ * Body parser hook
9
+ */
10
+ const addQsParser = (app, settings) => {
11
+ Object.defineProperty(app.request, 'query', {
12
+ configurable: false,
13
+ enumerable: true,
14
+ /*
15
+ * Get parsed query-string.
16
+ */
17
+ get() {
18
+ const qstr = this.querystring;
19
+ const cache = (this._querycache = this._querycache || {});
20
+ return cache[qstr] || (cache[qstr] = qs.parse(qstr, settings));
21
+ },
22
+
23
+ /*
24
+ * Set query-string as an object.
25
+ */
26
+ set(obj) {
27
+ this.querystring = qs.stringify(obj);
28
+ },
29
+ });
30
+
31
+ return app;
32
+ };
33
+
34
+ module.exports = strapi => {
35
+ return {
36
+ /**
37
+ * Initialize the hook
38
+ */
39
+ initialize() {
40
+ strapi.server.use(async (ctx, next) => {
41
+ // disable for graphql
42
+ // TODO: find a better way later
43
+ if (ctx.url === '/graphql') {
44
+ return next();
45
+ }
46
+
47
+ try {
48
+ const res = await body({
49
+ patchKoa: true,
50
+ ...omit(strapi.config.middleware.settings.parser, 'queryStringParser'),
51
+ })(ctx, next);
52
+ return res;
53
+ } catch (e) {
54
+ if ((e || {}).message && e.message.includes('maxFileSize exceeded')) {
55
+ throw strapi.errors.entityTooLarge('FileTooBig', {
56
+ errors: [
57
+ {
58
+ id: 'Upload.status.sizeLimit',
59
+ message: `file is bigger than the limit size!`,
60
+ },
61
+ ],
62
+ });
63
+ }
64
+
65
+ throw e;
66
+ }
67
+ });
68
+
69
+ addQsParser(
70
+ strapi.server.app,
71
+ strapi.config.get('middleware.settings.parser.queryStringParser')
72
+ );
73
+ },
74
+ };
75
+ };
@@ -0,0 +1,5 @@
1
+ {
2
+ "poweredBy": {
3
+ "enabled": true
4
+ }
5
+ }
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ module.exports = strapi => {
4
+ return {
5
+ initialize() {
6
+ strapi.server.use(async (ctx, next) => {
7
+ await next();
8
+
9
+ ctx.set(
10
+ 'X-Powered-By',
11
+ strapi.config.get('middleware.settings.poweredBy.value', 'Strapi <strapi.io>')
12
+ );
13
+ });
14
+ },
15
+ };
16
+ };
@@ -0,0 +1,8 @@
1
+ {
2
+ "public": {
3
+ "enabled": true,
4
+ "maxAge": 60000,
5
+ "path": "./public",
6
+ "defaultIndex": true
7
+ }
8
+ }
@@ -0,0 +1,66 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
6
+ <title>Welcome to your Strapi app</title>
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+ <meta name="robots" content="noindex, nofollow">
9
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css" rel="stylesheet" />
10
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" rel="stylesheet" />
11
+ <link href="https://fonts.googleapis.com/css?family=Lato:400,700&display=swap" rel="stylesheet" />
12
+ <style>
13
+ *{-webkit-box-sizing:border-box;text-decoration:none}body,html{margin:0;padding:0;font-size:62.5%;-webkit-font-smoothing:antialiased}body{font-size:1.3rem;font-family:Lato,Helvetica,Arial,Verdana,sans-serif;background:#fafafb;margin:0;padding:80px 0;color:#333740;line-height:1.8rem}strong{font-weight:700}.wrapper{width:684px;margin:auto}h1{text-align:center}h2{font-size:1.8rem;font-weight:700;margin-bottom:1px}.logo{height:40px;margin-bottom:74px}.informations{position:relative;overflow:hidden;display:flex;justify-content:space-between;width:100%;height:126px;margin-top:18px;padding:20px 30px;background:#fff;border-radius:2px;box-shadow:0 2px 4px 0 #e3e9f3}.informations:before{position:absolute;top:0;left:0;content:'';display:block;width:100%;height:2px;background:#007eff}.environment{display:inline-block;padding:0 10px;height:20px;margin-bottom:36px;background:#e6f0fb;border:1px solid #aed4fb;border-radius:2px;text-transform:uppercase;color:#007eff;font-size:1.2rem;font-weight:700;line-height:20px;letter-spacing:.05rem}.cta{display:inline-block;height:30px;padding:0 15px;margin-top:32px;border-radius:2px;color:#fff;font-weight:700;line-height:28px}.cta i{position:relative;display:inline-block;height:100%;vertical-align:middle;font-size:1rem;margin-right:20px}.cta i:before{position:absolute;top:8px}.cta-primary{background:#007eff}.cta-secondary{background:#6dbb1a}.text-align-right{text-align:right}.lets-started{position:relative;overflow:hidden;width:100%;height:144px;margin-top:18px;padding:20px 30px;background:#fff;border-radius:2px;box-shadow:0 2px 4px 0 #e3e9f3}.people-saying-hello{position:absolute;right:30px;bottom:-8px;width:113px;height:70px}.visible{opacity:1!important}.people-saying-hello img{position:absolute;max-width:100%;opacity:0;transition:opacity .2s ease-out}@media only screen and (max-width:768px){.wrapper{width:auto!important;margin:0 20px}.informations{flex-direction:column;height:auto}.environment{width:100%;text-align:center;margin-bottom:18px}.text-align-right{margin-top:18px;text-align:center}.cta{width:100%;text-align:center}.lets-started{height:auto}.people-saying-hello{display:none}}
14
+ </style>
15
+ </head>
16
+ <body lang="en">
17
+ <section class="wrapper">
18
+ <h1><img class="logo" src="<%= strapi.config.server.url %>/assets/images/logo_login.png" /></h1>
19
+ <% if (strapi.config.environment === 'development' && isInitialized) { %>
20
+ <div class="informations">
21
+ <div>
22
+ <span class="environment"><%= strapi.config.environment %></span>
23
+ <p>
24
+ The server is running successfully (<strong>v<%= strapi.config.info.version %>)</strong>
25
+ </p>
26
+ </div>
27
+ <div class="text-align-right">
28
+ <p><%= serverTime %></p>
29
+ <% if (strapi.config.serveAdminPanel) { %>
30
+ <a class="cta cta-primary" href="<%= strapi.config.admin.url %>" target="_blank" title="Click to open the administration" ><i class="fas fa-external-link-alt"></i>Open the administration</a>
31
+ <% } %>
32
+ </div>
33
+ </div>
34
+ <% } else if (strapi.config.environment === 'development' && !isInitialized) { %>
35
+ <div class="lets-started">
36
+ <h2>Let's get started!</h2>
37
+ <p>To discover the power provided by Strapi, you need to create an administrator.</p>
38
+ <a class="cta cta-secondary" href="<%= strapi.config.admin.url %>" target="_blank" title="Click to create the first administration" ><i class="fas fa-external-link-alt"></i>Create the first administrator</a>
39
+ <div class="people-saying-hello">
40
+ <img class="visible" src="<%= strapi.config.server.url %>/assets/images/group_people_1.png" alt="People saying hello" />
41
+ <img src="<%= strapi.config.server.url %>/assets/images/group_people_2.png" alt="People saying hello" />
42
+ <img src="<%= strapi.config.server.url %>/assets/images/group_people_3.png" alt="People saying hello" />
43
+ </div>
44
+ </div>
45
+ <% } else { %>
46
+ <div class="informations">
47
+ <div>
48
+ <span class="environment"><%= strapi.config.environment %></span>
49
+ <p>The server is running successfully.</p>
50
+ </div>
51
+ <div class="text-align-right">
52
+ <p><%= serverTime %></p>
53
+ </div>
54
+ </div>
55
+ <% } %>
56
+ </section>
57
+
58
+ <% if (strapi.config.environment === 'development' && !isInitialized) { %>
59
+ <script>
60
+ var images=document.querySelectorAll('.people-saying-hello img');var nextIndex=0;setInterval(function(){var currentIndex=0;images.forEach(function(image,index){if(image.className==='visible'){currentIndex=index}});nextIndex=currentIndex+1;if(nextIndex===images.length){nextIndex=0}
61
+ images.forEach(function(image){image.classList.remove('visible')})
62
+ images[nextIndex].classList.add('visible')},1500)
63
+ </script>
64
+ <% } %>
65
+ </body>
66
+ </html>
@@ -0,0 +1,130 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Node.js core.
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const stream = require('stream');
11
+ const _ = require('lodash');
12
+ const koaStatic = require('koa-static');
13
+ const utils = require('../../utils');
14
+ const serveStatic = require('./serve-static');
15
+
16
+ /**
17
+ * Public assets hook
18
+ */
19
+
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.dirs.root, publicPath || strapi.config.paths.static);
29
+
30
+ if (defaultIndex === true) {
31
+ const index = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
32
+
33
+ const serveIndexPage = async (ctx, next) => {
34
+ // defer rendering of strapi index page
35
+ await next();
36
+
37
+ if (ctx.body != null || ctx.status !== 404) return;
38
+
39
+ ctx.url = 'index.html';
40
+ const isInitialized = await utils.isInitialized(strapi);
41
+ const data = {
42
+ serverTime: new Date().toUTCString(),
43
+ isInitialized,
44
+ ..._.pick(strapi, [
45
+ 'config.info.version',
46
+ 'config.info.name',
47
+ 'config.admin.url',
48
+ 'config.server.url',
49
+ 'config.environment',
50
+ 'config.serveAdminPanel',
51
+ ]),
52
+ };
53
+ const content = _.template(index)(data);
54
+ const body = stream.Readable({
55
+ read() {
56
+ this.push(Buffer.from(content));
57
+ this.push(null);
58
+ },
59
+ });
60
+ // Serve static.
61
+ ctx.type = 'html';
62
+ ctx.body = body;
63
+ };
64
+
65
+ strapi.server.routes([
66
+ {
67
+ method: 'GET',
68
+ path: '/',
69
+ handler: serveIndexPage,
70
+ config: { auth: false },
71
+ },
72
+ {
73
+ method: 'GET',
74
+ path: '/index.html',
75
+ handler: serveIndexPage,
76
+ config: { auth: false },
77
+ },
78
+ {
79
+ method: 'GET',
80
+ path: '/assets/images/(.*)',
81
+ handler: serveStatic(path.resolve(__dirname, 'assets/images'), {
82
+ maxage: maxAge,
83
+ defer: true,
84
+ }),
85
+ config: { auth: false },
86
+ },
87
+ {
88
+ method: 'GET',
89
+ path: '/(.*)',
90
+ handler: koaStatic(staticDir, {
91
+ maxage: maxAge,
92
+ defer: true,
93
+ }),
94
+ config: { auth: false },
95
+ },
96
+ ]);
97
+ }
98
+
99
+ if (!strapi.config.serveAdminPanel) return;
100
+
101
+ const buildDir = path.resolve(strapi.dirs.root, 'build');
102
+ const serveAdmin = async (ctx, next) => {
103
+ await next();
104
+
105
+ if (ctx.method !== 'HEAD' && ctx.method !== 'GET') {
106
+ return;
107
+ }
108
+
109
+ if (ctx.body != null || ctx.status !== 404) {
110
+ return;
111
+ }
112
+
113
+ ctx.type = 'html';
114
+ ctx.body = fs.createReadStream(path.join(buildDir + '/index.html'));
115
+ };
116
+
117
+ strapi.server.routes([
118
+ {
119
+ method: 'GET',
120
+ path: `${strapi.config.admin.path}/:path*`,
121
+ handler: [
122
+ serveAdmin,
123
+ serveStatic(buildDir, { maxage: maxAge, defer: false, index: 'index.html' }),
124
+ ],
125
+ config: { auth: false },
126
+ },
127
+ ]);
128
+ },
129
+ };
130
+ };
@@ -0,0 +1,23 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const koaStatic = require('koa-static');
5
+
6
+ // serveStatic is not supposed to be used to serve a folder that have sub-folders
7
+ const serveStatic = (filesDir, koaStaticOptions = {}) => {
8
+ const serve = koaStatic(filesDir, koaStaticOptions);
9
+
10
+ return async (ctx, next) => {
11
+ const prev = ctx.path;
12
+ const newPath = path.basename(ctx.path);
13
+ ctx.path = newPath;
14
+ await serve(ctx, async () => {
15
+ ctx.path = prev;
16
+ await next();
17
+ ctx.path = newPath;
18
+ });
19
+ ctx.path = prev;
20
+ };
21
+ };
22
+
23
+ module.exports = serveStatic;
@@ -0,0 +1,5 @@
1
+ {
2
+ "responseTime": {
3
+ "enabled": true
4
+ }
5
+ }
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * X-Response-Time hook
5
+ */
6
+
7
+ module.exports = strapi => {
8
+ return {
9
+ /**
10
+ * Initialize the hook
11
+ */
12
+
13
+ initialize() {
14
+ strapi.server.use(async (ctx, next) => {
15
+ const start = Date.now();
16
+
17
+ await next();
18
+
19
+ const delta = Math.ceil(Date.now() - start);
20
+
21
+ ctx.set('X-Response-Time', delta + 'ms'); // eslint-disable-line prefer-template
22
+ });
23
+ },
24
+ };
25
+ };
@@ -0,0 +1,5 @@
1
+ {
2
+ "responses": {
3
+ "enabled": true
4
+ }
5
+ }
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+
5
+ module.exports = strapi => {
6
+ return {
7
+ initialize() {
8
+ strapi.server.use(async (ctx, next) => {
9
+ await next();
10
+
11
+ const status = ctx.status;
12
+ const responseFn = strapi.config.get(`middleware.settings.responses.handlers.${status}`);
13
+ if (_.isFunction(responseFn)) {
14
+ await responseFn(ctx);
15
+ }
16
+ });
17
+ },
18
+ };
19
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "router": {
3
+ "enabled": true,
4
+ "prefix": "",
5
+ "routes": {}
6
+ }
7
+ }