@strapi/strapi 0.0.0-e6cac9fe30 → 0.0.0-eb69fb6b1facdfef907143ee63f1642a71eb4606

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 (56) hide show
  1. package/README.md +18 -9
  2. package/lib/Strapi.js +21 -3
  3. package/lib/commands/admin-create.js +1 -1
  4. package/lib/commands/builders/admin.js +1 -0
  5. package/lib/commands/configurationDump.js +2 -2
  6. package/lib/core/app-configuration/load-config-file.js +1 -3
  7. package/lib/core/domain/content-type/index.js +1 -1
  8. package/lib/core/loaders/apis.js +4 -4
  9. package/lib/core/loaders/middlewares.js +1 -2
  10. package/lib/core/loaders/plugins/get-enabled-plugins.js +3 -1
  11. package/lib/core/loaders/plugins/index.js +5 -5
  12. package/lib/core/loaders/policies.js +1 -2
  13. package/lib/core/loaders/src-index.js +1 -3
  14. package/lib/core/registries/content-types.js +2 -2
  15. package/lib/core/registries/controllers.js +2 -2
  16. package/lib/core/registries/custom-fields.js +72 -0
  17. package/lib/core/registries/hooks.js +1 -1
  18. package/lib/core/registries/middlewares.js +2 -2
  19. package/lib/core/registries/policies.js +1 -1
  20. package/lib/core/registries/services.js +2 -2
  21. package/lib/core-api/controller/transform.js +1 -1
  22. package/lib/core-api/service/index.d.ts +6 -3
  23. package/lib/load/load-files.js +1 -1
  24. package/lib/middlewares/body.js +9 -2
  25. package/lib/middlewares/cors.js +1 -1
  26. package/lib/middlewares/favicon.js +16 -3
  27. package/lib/middlewares/security.js +22 -16
  28. package/lib/services/auth/index.js +4 -1
  29. package/lib/services/content-api/index.js +74 -0
  30. package/lib/services/content-api/permissions/engine.js +5 -0
  31. package/lib/services/content-api/permissions/index.js +148 -0
  32. package/lib/services/content-api/permissions/providers/action.js +19 -0
  33. package/lib/services/content-api/permissions/providers/condition.js +19 -0
  34. package/lib/services/content-api/permissions/providers/index.js +9 -0
  35. package/lib/services/cron.js +1 -1
  36. package/lib/services/custom-fields.js +11 -0
  37. package/lib/services/entity-service/components.js +41 -38
  38. package/lib/services/entity-service/index.js +68 -46
  39. package/lib/services/entity-service/params.js +1 -87
  40. package/lib/services/entity-validator/index.js +166 -19
  41. package/lib/services/metrics/middleware.js +1 -1
  42. package/lib/services/metrics/sender.js +4 -2
  43. package/lib/services/request-context.js +17 -0
  44. package/lib/services/server/index.js +3 -0
  45. package/lib/services/server/middleware.js +2 -1
  46. package/lib/services/server/register-routes.js +2 -2
  47. package/lib/services/utils/upload-files.js +1 -1
  48. package/lib/services/worker-queue.js +2 -2
  49. package/lib/types/core/attributes/common.d.ts +3 -0
  50. package/lib/types/core/strapi/index.d.ts +45 -10
  51. package/lib/types/factories.d.ts +3 -3
  52. package/lib/utils/addSlash.js +6 -5
  53. package/lib/utils/convert-custom-field-type.js +22 -0
  54. package/lib/utils/index.js +0 -2
  55. package/package.json +18 -17
  56. package/lib/utils/import-default.js +0 -10
package/README.md CHANGED
@@ -1,8 +1,12 @@
1
1
  <p align="center">
2
- <a href="https://strapi.io">
2
+ <a href="https://strapi.io/#gh-light-mode-only">
3
3
  <img src="https://strapi.io/assets/strapi-logo-dark.svg" width="318px" alt="Strapi logo" />
4
4
  </a>
5
+ <a href="https://strapi.io/#gh-dark-mode-only">
6
+ <img src="https://strapi.io/assets/strapi-logo-light.svg" width="318px" alt="Strapi logo" />
7
+ </a>
5
8
  </p>
9
+
6
10
  <h3 align="center">API creation made simple, secure and fast.</h3>
7
11
  <p align="center">The most advanced open-source headless CMS to build powerful APIs with no effort.</p>
8
12
  <p align="center"><a href="https://strapi.io/demo">Try live demo</a></p>
@@ -13,11 +17,14 @@
13
17
  <img src="https://img.shields.io/npm/v/@strapi/strapi/latest.svg" alt="NPM Version" />
14
18
  </a>
15
19
  <a href="https://github.com/strapi/strapi/actions/workflows/tests.yml">
16
- <img src="https://github.com/strapi/strapi/actions/workflows/tests.yml/badge.svg?branch=master" alt="Tests" />
20
+ <img src="https://github.com/strapi/strapi/actions/workflows/tests.yml/badge.svg?branch=main" alt="Tests" />
17
21
  </a>
18
22
  <a href="https://discord.strapi.io">
19
23
  <img src="https://img.shields.io/discord/811989166782021633?label=Discord" alt="Strapi on Discord" />
20
24
  </a>
25
+ <a href="https://github.com/strapi/strapi/actions/workflows/nightly.yml">
26
+ <img src="https://github.com/strapi/strapi/actions/workflows/nightly.yml/badge.svg" alt="Strapi Nightly Release Build Status" />
27
+ </a>
21
28
  </p>
22
29
 
23
30
  <br>
@@ -79,15 +86,17 @@ Complete installation requirements can be found in the documentation under <a hr
79
86
 
80
87
  **Node:**
81
88
 
82
- - NodeJS >= 12 <= 16
89
+ - NodeJS >= 14 <= 18
83
90
  - NPM >= 6.x
84
91
 
85
92
  **Database:**
86
93
 
87
- - MySQL >= 5.7.8
88
- - MariaDB >= 10.2.7
89
- - PostgreSQL >= 10
90
- - SQLite >= 3
94
+ | Database | Minimum | Recommended |
95
+ | ---------- | ------- | ----------- |
96
+ | MySQL | 5.7.8 | 8.0 |
97
+ | MariaDB | 10.3 | 10.6 |
98
+ | PostgreSQL | 11.0 | 14.0 |
99
+ | SQLite | 3 | 3 |
91
100
 
92
101
  **We recommend always using the latest version of Strapi to start your new projects**.
93
102
 
@@ -114,7 +123,7 @@ For general help using Strapi, please refer to [the official Strapi documentatio
114
123
  - [Discord](https://discord.strapi.io) (For live discussion with the Community and Strapi team)
115
124
  - [GitHub](https://github.com/strapi/strapi) (Bug reports, Contributions)
116
125
  - [Community Forum](https://forum.strapi.io) (Questions and Discussions)
117
- - [Roadmap & Feature Requests](https://feedback.strapi.io/)
126
+ - [Feedback section](https://feedback.strapi.io) (Roadmap, Feature requests)
118
127
  - [Twitter](https://twitter.com/strapijs) (Get the news fast)
119
128
  - [Facebook](https://www.facebook.com/Strapi-616063331867161)
120
129
  - [YouTube Channel](https://www.youtube.com/strapi) (Learn from Video Tutorials)
@@ -125,7 +134,7 @@ Follow our [migration guides](https://docs.strapi.io/developer-docs/latest/updat
125
134
 
126
135
  ## Roadmap
127
136
 
128
- Check out our [roadmap](https://feedback.strapi.io/) to get informed of the latest features released and the upcoming ones. You may also give us insights and vote for a specific feature.
137
+ Check out our [roadmap](https://feedback.strapi.io) to get informed of the latest features released and the upcoming ones. You may also give us insights and vote for a specific feature.
129
138
 
130
139
  ## Documentation
131
140
 
package/lib/Strapi.js CHANGED
@@ -21,7 +21,10 @@ const createEntityService = require('./services/entity-service');
21
21
  const createCronService = require('./services/cron');
22
22
  const entityValidator = require('./services/entity-validator');
23
23
  const createTelemetry = require('./services/metrics');
24
+ const requestContext = require('./services/request-context');
24
25
  const createAuth = require('./services/auth');
26
+ const createCustomFields = require('./services/custom-fields');
27
+ const createContentAPI = require('./services/content-api');
25
28
  const createUpdateNotifier = require('./utils/update-notifier');
26
29
  const createStartupLogger = require('./utils/startup-logger');
27
30
  const { LIFECYCLES } = require('./utils/lifecycles');
@@ -34,12 +37,14 @@ const hooksRegistry = require('./core/registries/hooks');
34
37
  const controllersRegistry = require('./core/registries/controllers');
35
38
  const modulesRegistry = require('./core/registries/modules');
36
39
  const pluginsRegistry = require('./core/registries/plugins');
40
+ const customFieldsRegistry = require('./core/registries/custom-fields');
37
41
  const createConfigProvider = require('./core/registries/config');
38
42
  const apisRegistry = require('./core/registries/apis');
39
43
  const bootstrap = require('./core/bootstrap');
40
44
  const loaders = require('./core/loaders');
41
45
  const { destroyOnSignal } = require('./utils/signals');
42
46
  const sanitizersRegistry = require('./core/registries/sanitizers');
47
+ const convertCustomFieldType = require('./utils/convert-custom-field-type');
43
48
 
44
49
  // TODO: move somewhere else
45
50
  const draftAndPublishSync = require('./migrations/draft-publish');
@@ -74,7 +79,7 @@ class Strapi {
74
79
  // Load the app configuration from the dist directory
75
80
  const appConfig = loadConfiguration({ appDir: rootDirs.app, distDir: rootDirs.dist }, opts);
76
81
 
77
- // Instanciate the Strapi container
82
+ // Instantiate the Strapi container
78
83
  this.container = createContainer(this);
79
84
 
80
85
  // Register every Strapi registry in the container
@@ -87,8 +92,10 @@ class Strapi {
87
92
  this.container.register('controllers', controllersRegistry(this));
88
93
  this.container.register('modules', modulesRegistry(this));
89
94
  this.container.register('plugins', pluginsRegistry(this));
95
+ this.container.register('custom-fields', customFieldsRegistry(this));
90
96
  this.container.register('apis', apisRegistry(this));
91
97
  this.container.register('auth', createAuth(this));
98
+ this.container.register('content-api', createContentAPI(this));
92
99
  this.container.register('sanitizers', sanitizersRegistry(this));
93
100
 
94
101
  // Create a mapping of every useful directory (for the app, dist and static directories)
@@ -98,7 +105,7 @@ class Strapi {
98
105
  this.isLoaded = false;
99
106
  this.reload = this.reload();
100
107
 
101
- // Instanciate the Koa app & the HTTP server
108
+ // Instantiate the Koa app & the HTTP server
102
109
  this.server = createServer(this);
103
110
 
104
111
  // Strapi utils instanciation
@@ -108,6 +115,9 @@ class Strapi {
108
115
  this.log = createLogger(this.config.get('logger', {}));
109
116
  this.cron = createCronService();
110
117
  this.telemetry = createTelemetry(this);
118
+ this.requestContext = requestContext;
119
+
120
+ this.customFields = createCustomFields(this);
111
121
 
112
122
  createUpdateNotifier(this).notify();
113
123
  }
@@ -117,7 +127,7 @@ class Strapi {
117
127
  }
118
128
 
119
129
  get EE() {
120
- return ee({ dir: this.dirs.dist.root, logger: this.log });
130
+ return ee({ dir: this.dirs.app.root, logger: this.log });
121
131
  }
122
132
 
123
133
  get services() {
@@ -188,6 +198,10 @@ class Strapi {
188
198
  return this.container.get('auth');
189
199
  }
190
200
 
201
+ get contentAPI() {
202
+ return this.container.get('content-api');
203
+ }
204
+
191
205
  get sanitizers() {
192
206
  return this.container.get('sanitizers');
193
207
  }
@@ -377,6 +391,8 @@ class Strapi {
377
391
  this.telemetry.register();
378
392
 
379
393
  await this.runLifecyclesFunctions(LIFECYCLES.REGISTER);
394
+ // NOTE: Swap type customField for underlying data type
395
+ convertCustomFieldType(this);
380
396
 
381
397
  return this;
382
398
  }
@@ -445,6 +461,8 @@ class Strapi {
445
461
  await this.server.initMiddlewares();
446
462
  await this.server.initRouting();
447
463
 
464
+ await this.contentAPI.permissions.registerActions();
465
+
448
466
  await this.runLifecyclesFunctions(LIFECYCLES.BOOTSTRAP);
449
467
 
450
468
  this.cron.start();
@@ -17,7 +17,7 @@ const passwordValidator = yup
17
17
  const adminCreateSchema = yup.object().shape({
18
18
  email: emailValidator,
19
19
  password: passwordValidator,
20
- firstname: yup.string().required('First name is required'),
20
+ firstname: yup.string().trim().required('First name is required'),
21
21
  lastname: yup.string(),
22
22
  });
23
23
 
@@ -44,6 +44,7 @@ module.exports = async ({ buildDestDir, forceBuild = true, optimization, srcDir
44
44
  options: {
45
45
  backend: serverUrl,
46
46
  adminPath: addSlash(adminPath),
47
+ telemetryIsDisabled: strapiInstance.telemetry.isDisabled,
47
48
  },
48
49
  })
49
50
  .then(() => {
@@ -9,7 +9,7 @@ const CHUNK_SIZE = 100;
9
9
  * Will dump configurations to a file or stdout
10
10
  * @param {string} file filepath to use as output
11
11
  */
12
- module.exports = async function ({ file: filePath, pretty }) {
12
+ module.exports = async ({ file: filePath, pretty }) => {
13
13
  const output = filePath ? fs.createWriteStream(filePath) : process.stdout;
14
14
 
15
15
  const appContext = await strapi.compile();
@@ -21,7 +21,7 @@ module.exports = async function ({ file: filePath, pretty }) {
21
21
 
22
22
  const pageCount = Math.ceil(count / CHUNK_SIZE);
23
23
 
24
- for (let page = 0; page < pageCount; page++) {
24
+ for (let page = 0; page < pageCount; page += 1) {
25
25
  const results = await app
26
26
  .query('strapi::core-store')
27
27
  .findMany({ limit: CHUNK_SIZE, offset: page * CHUNK_SIZE, orderBy: 'key' });
@@ -2,9 +2,7 @@
2
2
 
3
3
  const path = require('path');
4
4
  const fs = require('fs');
5
- const { templateConfiguration, env } = require('@strapi/utils');
6
-
7
- const importDefault = require('../../utils/import-default');
5
+ const { templateConfiguration, env, importDefault } = require('@strapi/utils');
8
6
 
9
7
  const loadJsFile = (file) => {
10
8
  try {
@@ -54,7 +54,7 @@ const createContentType = (uid, definition) => {
54
54
  });
55
55
  } else {
56
56
  throw new Error(
57
- `Incorrect Content Type UID "${uid}". The UID should start with api::, plugin:: or strapi::.`
57
+ `Incorrect Content Type UID "${uid}". The UID should start with api::, plugin:: or admin::.`
58
58
  );
59
59
  }
60
60
 
@@ -4,8 +4,7 @@ const { join, extname, basename } = require('path');
4
4
  const { existsSync } = require('fs-extra');
5
5
  const _ = require('lodash');
6
6
  const fse = require('fs-extra');
7
- const { isKebabCase } = require('@strapi/utils');
8
- const { importDefault } = require('../../utils');
7
+ const { isKebabCase, importDefault } = require('@strapi/utils');
9
8
 
10
9
  const DEFAULT_CONTENT_TYPE = {
11
10
  schema: {},
@@ -40,7 +39,7 @@ module.exports = async (strapi) => {
40
39
 
41
40
  validateContentTypesUnicity(apis);
42
41
 
43
- for (const apiName in apis) {
42
+ for (const apiName of Object.keys(apis)) {
44
43
  strapi.container.get('apis').add(apiName, apis[apiName]);
45
44
  }
46
45
  };
@@ -131,11 +130,12 @@ const loadDir = async (dir) => {
131
130
 
132
131
  const root = {};
133
132
  for (const fd of fds) {
134
- if (!fd.isFile()) {
133
+ if (!fd.isFile() || extname(fd.name) === '.map') {
135
134
  continue;
136
135
  }
137
136
 
138
137
  const key = basename(fd.name, extname(fd.name));
138
+
139
139
  root[normalizeName(key)] = await loadFile(join(dir, fd.name));
140
140
  }
141
141
 
@@ -2,8 +2,7 @@
2
2
 
3
3
  const { join, extname, basename } = require('path');
4
4
  const fse = require('fs-extra');
5
-
6
- const { importDefault } = require('../../utils');
5
+ const { importDefault } = require('@strapi/utils');
7
6
 
8
7
  // TODO:: allow folders with index.js inside for bigger policies
9
8
  module.exports = async function loadMiddlewares(strapi) {
@@ -59,7 +59,9 @@ const getEnabledPlugins = async (strapi) => {
59
59
  }
60
60
 
61
61
  const installedPlugins = {};
62
- for (const dep in strapi.config.get('info.dependencies', {})) {
62
+ const dependencies = strapi.config.get('info.dependencies', {});
63
+
64
+ for (const dep of Object.keys(dependencies)) {
63
65
  const packagePath = join(dep, 'package.json');
64
66
  let packageInfo;
65
67
  try {
@@ -34,10 +34,10 @@ const applyUserExtension = async (plugins) => {
34
34
  const extendedSchemas = await loadFiles(extensionsDir, '**/content-types/**/schema.json');
35
35
  const strapiServers = await loadFiles(extensionsDir, '**/strapi-server.js');
36
36
 
37
- for (const pluginName in plugins) {
37
+ for (const pluginName of Object.keys(plugins)) {
38
38
  const plugin = plugins[pluginName];
39
39
  // first: load json schema
40
- for (const ctName in plugin.contentTypes) {
40
+ for (const ctName of Object.keys(plugin.contentTypes)) {
41
41
  const extendedSchema = get([pluginName, 'content-types', ctName, 'schema'], extendedSchemas);
42
42
  if (extendedSchema) {
43
43
  plugin.contentTypes[ctName].schema = {
@@ -57,7 +57,7 @@ const applyUserExtension = async (plugins) => {
57
57
  const applyUserConfig = async (plugins) => {
58
58
  const userPluginsConfig = await getUserPluginsConfig();
59
59
 
60
- for (const pluginName in plugins) {
60
+ for (const pluginName of Object.keys(plugins)) {
61
61
  const plugin = plugins[pluginName];
62
62
  const userPluginConfig = getOr({}, `${pluginName}.config`, userPluginsConfig);
63
63
  const defaultConfig =
@@ -82,7 +82,7 @@ const loadPlugins = async (strapi) => {
82
82
 
83
83
  strapi.config.set('enabledPlugins', enabledPlugins);
84
84
 
85
- for (const pluginName in enabledPlugins) {
85
+ for (const pluginName of Object.keys(enabledPlugins)) {
86
86
  const enabledPlugin = enabledPlugins[pluginName];
87
87
 
88
88
  const serverEntrypointPath = join(enabledPlugin.pathToPlugin, 'strapi-server.js');
@@ -100,7 +100,7 @@ const loadPlugins = async (strapi) => {
100
100
  await applyUserConfig(plugins);
101
101
  await applyUserExtension(plugins);
102
102
 
103
- for (const pluginName in plugins) {
103
+ for (const pluginName of Object.keys(plugins)) {
104
104
  strapi.container.get('plugins').add(pluginName, plugins[pluginName]);
105
105
  }
106
106
  };
@@ -2,8 +2,7 @@
2
2
 
3
3
  const { join, extname, basename } = require('path');
4
4
  const fse = require('fs-extra');
5
-
6
- const { importDefault } = require('../../utils');
5
+ const { importDefault } = require('@strapi/utils');
7
6
 
8
7
  // TODO:: allow folders with index.js inside for bigger policies
9
8
  module.exports = async function loadPolicies(strapi) {
@@ -2,9 +2,7 @@
2
2
 
3
3
  const { resolve } = require('path');
4
4
  const { statSync, existsSync } = require('fs');
5
- const { yup } = require('@strapi/utils');
6
-
7
- const { importDefault } = require('../../utils');
5
+ const { yup, importDefault } = require('@strapi/utils');
8
6
 
9
7
  const srcSchema = yup
10
8
  .object()
@@ -5,7 +5,7 @@ const { createContentType } = require('../domain/content-type');
5
5
  const { addNamespace, hasNamespace } = require('../utils');
6
6
 
7
7
  const validateKeySameToSingularName = (contentTypes) => {
8
- for (const ctName in contentTypes) {
8
+ for (const ctName of Object.keys(contentTypes)) {
9
9
  const contentType = contentTypes[ctName];
10
10
 
11
11
  if (ctName !== contentType.schema.info.singularName) {
@@ -63,7 +63,7 @@ const contentTypesRegistry = () => {
63
63
  add(namespace, newContentTypes) {
64
64
  validateKeySameToSingularName(newContentTypes);
65
65
 
66
- for (const rawCtName in newContentTypes) {
66
+ for (const rawCtName of Object.keys(newContentTypes)) {
67
67
  const uid = addNamespace(rawCtName, namespace);
68
68
 
69
69
  if (has(uid, contentTypes)) {
@@ -48,7 +48,7 @@ const controllersRegistry = () => {
48
48
  const filteredControllers = pickBy((_, uid) => hasNamespace(uid, namespace))(controllers);
49
49
 
50
50
  const map = {};
51
- for (const uid in filteredControllers) {
51
+ for (const uid of Object.keys(filteredControllers)) {
52
52
  Object.defineProperty(map, uid, {
53
53
  enumerable: true,
54
54
  get: () => {
@@ -78,7 +78,7 @@ const controllersRegistry = () => {
78
78
  * @returns
79
79
  */
80
80
  add(namespace, newControllers) {
81
- for (const controllerName in newControllers) {
81
+ for (const controllerName of Object.keys(newControllers)) {
82
82
  const controller = newControllers[controllerName];
83
83
  const uid = addNamespace(controllerName, namespace);
84
84
 
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ const { has } = require('lodash/fp');
4
+
5
+ const ALLOWED_TYPES = [
6
+ 'biginteger',
7
+ 'boolean',
8
+ 'date',
9
+ 'datetime',
10
+ 'decimal',
11
+ 'email',
12
+ 'enumeration',
13
+ 'float',
14
+ 'integer',
15
+ 'json',
16
+ 'password',
17
+ 'richtext',
18
+ 'string',
19
+ 'text',
20
+ 'time',
21
+ 'uid',
22
+ ];
23
+
24
+ const customFieldsRegistry = (strapi) => {
25
+ const customFields = {};
26
+
27
+ return {
28
+ getAll() {
29
+ return customFields;
30
+ },
31
+ get(customField) {
32
+ const registeredCustomField = customFields[customField];
33
+ if (!registeredCustomField) {
34
+ throw new Error(`Could not find Custom Field: ${customField}`);
35
+ }
36
+
37
+ return registeredCustomField;
38
+ },
39
+ add(customField) {
40
+ const customFieldList = Array.isArray(customField) ? customField : [customField];
41
+
42
+ for (const cf of customFieldList) {
43
+ if (!has('name', cf) || !has('type', cf)) {
44
+ throw new Error(`Custom fields require a 'name' and 'type' key`);
45
+ }
46
+
47
+ const { name, plugin, type } = cf;
48
+ if (!ALLOWED_TYPES.includes(type)) {
49
+ throw new Error(
50
+ `Custom field type: '${type}' is not a valid Strapi type or it can't be used with a Custom Field`
51
+ );
52
+ }
53
+
54
+ const isValidObjectKey = /^(?![0-9])[a-zA-Z0-9$_-]+$/g;
55
+ if (!isValidObjectKey.test(name)) {
56
+ throw new Error(`Custom field name: '${name}' is not a valid object key`);
57
+ }
58
+
59
+ // When no plugin is specified, or it isn't found in Strapi, default to global
60
+ const uid = strapi.plugin(plugin) ? `plugin::${plugin}.${name}` : `global::${name}`;
61
+
62
+ if (has(uid, customFields)) {
63
+ throw new Error(`Custom field: '${uid}' has already been registered`);
64
+ }
65
+
66
+ customFields[uid] = cf;
67
+ }
68
+ },
69
+ };
70
+ };
71
+
72
+ module.exports = customFieldsRegistry;
@@ -54,7 +54,7 @@ const hooksRegistry = () => {
54
54
  * @returns
55
55
  */
56
56
  add(namespace, hooks) {
57
- for (const hookName in hooks) {
57
+ for (const hookName of Object.keys(hooks)) {
58
58
  const hook = hooks[hookName];
59
59
  const uid = addNamespace(hookName, namespace);
60
60
 
@@ -54,8 +54,8 @@ const middlewaresRegistry = () => {
54
54
  * @param {{ [key: string]: Middleware }} newMiddlewares
55
55
  * @returns
56
56
  */
57
- add(namespace, rawMiddlewares) {
58
- for (const middlewareName in rawMiddlewares) {
57
+ add(namespace, rawMiddlewares = {}) {
58
+ for (const middlewareName of Object.keys(rawMiddlewares)) {
59
59
  const middleware = rawMiddlewares[middlewareName];
60
60
  const uid = addNamespace(middlewareName, namespace);
61
61
 
@@ -55,7 +55,7 @@ const policiesRegistry = () => {
55
55
  * @returns
56
56
  */
57
57
  add(namespace, newPolicies) {
58
- for (const policyName in newPolicies) {
58
+ for (const policyName of Object.keys(newPolicies)) {
59
59
  const policy = newPolicies[policyName];
60
60
  const uid = addNamespace(policyName, namespace);
61
61
 
@@ -48,7 +48,7 @@ const servicesRegistry = (strapi) => {
48
48
 
49
49
  // create lazy accessor to avoid instantiating the services;
50
50
  const map = {};
51
- for (const uid in filteredServices) {
51
+ for (const uid of Object.keys(filteredServices)) {
52
52
  Object.defineProperty(map, uid, {
53
53
  enumerable: true,
54
54
  get: () => {
@@ -78,7 +78,7 @@ const servicesRegistry = (strapi) => {
78
78
  * @returns
79
79
  */
80
80
  add(namespace, newServices) {
81
- for (const serviceName in newServices) {
81
+ for (const serviceName of Object.keys(newServices)) {
82
82
  const service = newServices[serviceName];
83
83
  const uid = addNamespace(serviceName, namespace);
84
84
 
@@ -56,7 +56,7 @@ const transformEntry = (entry, type) => {
56
56
 
57
57
  const attributeValues = {};
58
58
 
59
- for (const key in properties) {
59
+ for (const key of Object.keys(properties)) {
60
60
  const property = properties[key];
61
61
  const attribute = type && type.attributes[key];
62
62
 
@@ -12,11 +12,14 @@ export interface SingleTypeService extends BaseService {
12
12
 
13
13
  export interface CollectionTypeService extends BaseService {
14
14
  find?(params: object): Promise<Entity[]> | Entity;
15
- findOne?(entityId: string,params: object): Promise<Entity> | Entity;
15
+ findOne?(entityId: string, params: object): Promise<Entity> | Entity;
16
16
  create?(params: object): Promise<Entity> | Entity;
17
- update?(entityId: string,params: object): Promise<Entity> | Entity;
18
- delete?(entityId: string,params: object): Promise<Entity> | Entity;
17
+ update?(entityId: string, params: object): Promise<Entity> | Entity;
18
+ delete?(entityId: string, params: object): Promise<Entity> | Entity;
19
19
  }
20
20
 
21
21
  export type Service = SingleTypeService | CollectionTypeService;
22
22
 
23
+ export type GenericService = Partial<Service> & {
24
+ [method: string | number | symbol]: <T = any>(...args: any) => T;
25
+ };
@@ -4,7 +4,7 @@ const path = require('path');
4
4
  const _ = require('lodash');
5
5
  const fse = require('fs-extra');
6
6
 
7
- const { importDefault } = require('../utils');
7
+ const { importDefault } = require('@strapi/utils');
8
8
  const glob = require('./glob');
9
9
  const filePathToPath = require('./filepath-to-prop-path');
10
10
 
@@ -23,12 +23,19 @@ function getFiles(ctx) {
23
23
  /**
24
24
  * @type {import('./').MiddlewareFactory}
25
25
  */
26
- module.exports = (config) => {
26
+
27
+ module.exports = (config, { strapi }) => {
27
28
  const bodyConfig = defaultsDeep(defaults, config);
28
29
 
30
+ let gqlEndpoint;
31
+ if (strapi.plugin('graphql')) {
32
+ const { config: gqlConfig } = strapi.plugin('graphql');
33
+ gqlEndpoint = gqlConfig('endpoint');
34
+ }
35
+
29
36
  return async (ctx, next) => {
30
37
  // TODO: find a better way later
31
- if (ctx.url === '/graphql') {
38
+ if (gqlEndpoint && ctx.url === gqlEndpoint) {
32
39
  await next();
33
40
  } else {
34
41
  try {
@@ -33,7 +33,7 @@ module.exports = (config) => {
33
33
 
34
34
  const requestOrigin = ctx.accept.headers.origin;
35
35
  if (whitelist.includes('*')) {
36
- return '*';
36
+ return credentials ? requestOrigin : '*';
37
37
  }
38
38
 
39
39
  if (!whitelist.includes(requestOrigin)) {
@@ -1,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ const { existsSync } = require('fs');
3
4
  const { resolve } = require('path');
4
5
  const { defaultsDeep } = require('lodash/fp');
5
6
  const favicon = require('koa-favicon');
6
7
 
7
8
  const defaults = {
8
- path: 'favicon.ico',
9
+ path: 'favicon.png',
9
10
  maxAge: 86400000,
10
11
  };
11
12
 
@@ -13,7 +14,19 @@ const defaults = {
13
14
  * @type {import('./').MiddlewareFactory}
14
15
  */
15
16
  module.exports = (config, { strapi }) => {
16
- const { maxAge, path: faviconPath } = defaultsDeep(defaults, config);
17
+ const { maxAge, path: faviconDefaultPath } = defaultsDeep(defaults, config);
18
+ const { root: appRoot } = strapi.dirs.app;
19
+ let faviconPath = faviconDefaultPath;
17
20
 
18
- return favicon(resolve(strapi.dirs.app.root, faviconPath), { maxAge });
21
+ /** TODO (v5): Updating the favicon to use a png caused
22
+ * https://github.com/strapi/strapi/issues/14693
23
+ *
24
+ * This check ensures backwards compatibility until
25
+ * the next major version
26
+ */
27
+ if (!existsSync(resolve(appRoot, faviconPath))) {
28
+ faviconPath = 'favicon.ico';
29
+ }
30
+
31
+ return favicon(resolve(appRoot, faviconPath), { maxAge });
19
32
  };