@strapi/strapi 4.3.7 → 4.3.9

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.
package/README.md CHANGED
@@ -86,7 +86,7 @@ Complete installation requirements can be found in the documentation under <a hr
86
86
 
87
87
  **Node:**
88
88
 
89
- - NodeJS >= 14 <= 16
89
+ - NodeJS >= 14 <= 18
90
90
  - NPM >= 6.x
91
91
 
92
92
  **Database:**
package/lib/Strapi.js CHANGED
@@ -21,6 +21,7 @@ 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');
25
26
  const createUpdateNotifier = require('./utils/update-notifier');
26
27
  const createStartupLogger = require('./utils/startup-logger');
@@ -108,6 +109,7 @@ class Strapi {
108
109
  this.log = createLogger(this.config.get('logger', {}));
109
110
  this.cron = createCronService();
110
111
  this.telemetry = createTelemetry(this);
112
+ this.requestContext = requestContext;
111
113
 
112
114
  createUpdateNotifier(this).notify();
113
115
  }
@@ -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
 
@@ -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' });
@@ -40,7 +40,7 @@ module.exports = async (strapi) => {
40
40
 
41
41
  validateContentTypesUnicity(apis);
42
42
 
43
- for (const apiName in apis) {
43
+ for (const apiName of Object.keys(apis)) {
44
44
  strapi.container.get('apis').add(apiName, apis[apiName]);
45
45
  }
46
46
  };
@@ -131,11 +131,12 @@ const loadDir = async (dir) => {
131
131
 
132
132
  const root = {};
133
133
  for (const fd of fds) {
134
- if (!fd.isFile()) {
134
+ if (!fd.isFile() || extname(fd.name) === '.map') {
135
135
  continue;
136
136
  }
137
137
 
138
138
  const key = basename(fd.name, extname(fd.name));
139
+
139
140
  root[normalizeName(key)] = await loadFile(join(dir, fd.name));
140
141
  }
141
142
 
@@ -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
  };
@@ -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
 
@@ -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
 
@@ -9,7 +9,7 @@ const createCronService = () => {
9
9
 
10
10
  return {
11
11
  add(tasks = {}) {
12
- for (const taskExpression in tasks) {
12
+ for (const taskExpression of Object.keys(tasks)) {
13
13
  const taskValue = tasks[taskExpression];
14
14
 
15
15
  let fn;
@@ -18,11 +18,11 @@ const omitComponentData = (contentType, data) => {
18
18
 
19
19
  // NOTE: we could generalize the logic to allow CRUD of relation directly in the DB layer
20
20
  const createComponents = async (uid, data) => {
21
- const { attributes } = strapi.getModel(uid);
21
+ const { attributes = {} } = strapi.getModel(uid);
22
22
 
23
23
  const componentBody = {};
24
24
 
25
- for (const attributeName in attributes) {
25
+ for (const attributeName of Object.keys(attributes)) {
26
26
  const attribute = attributes[attributeName];
27
27
 
28
28
  if (!has(attributeName, data) || !contentTypesUtils.isComponentAttribute(attribute)) {
@@ -118,11 +118,11 @@ const getComponents = async (uid, entity) => {
118
118
  create or update
119
119
  */
120
120
  const updateComponents = async (uid, entityToUpdate, data) => {
121
- const { attributes } = strapi.getModel(uid);
121
+ const { attributes = {} } = strapi.getModel(uid);
122
122
 
123
123
  const componentBody = {};
124
124
 
125
- for (const attributeName in attributes) {
125
+ for (const attributeName of Object.keys(attributes)) {
126
126
  const attribute = attributes[attributeName];
127
127
 
128
128
  if (!has(attributeName, data)) {
@@ -275,9 +275,9 @@ const deleteOldDZComponents = async (uid, entityToUpdate, attributeName, dynamic
275
275
  };
276
276
 
277
277
  const deleteComponents = async (uid, entityToDelete) => {
278
- const { attributes } = strapi.getModel(uid);
278
+ const { attributes = {} } = strapi.getModel(uid);
279
279
 
280
- for (const attributeName in attributes) {
280
+ for (const attributeName of Object.keys(attributes)) {
281
281
  const attribute = attributes[attributeName];
282
282
 
283
283
  if (attribute.type === 'component') {
@@ -14,51 +14,56 @@ const { isMediaAttribute, isScalarAttribute, getWritableAttributes } = strapiUti
14
14
  const { ValidationError } = strapiUtils.errors;
15
15
 
16
16
  const addMinMax = (validator, { attr, updatedAttribute }) => {
17
+ let nextValidator = validator;
18
+
17
19
  if (
18
20
  Number.isInteger(attr.min) &&
19
21
  (attr.required || (Array.isArray(updatedAttribute.value) && updatedAttribute.value.length > 0))
20
22
  ) {
21
- validator = validator.min(attr.min);
23
+ nextValidator = nextValidator.min(attr.min);
22
24
  }
23
25
  if (Number.isInteger(attr.max)) {
24
- validator = validator.max(attr.max);
26
+ nextValidator = nextValidator.max(attr.max);
25
27
  }
26
- return validator;
28
+ return nextValidator;
27
29
  };
28
30
 
29
- const addRequiredValidation =
30
- (createOrUpdate) =>
31
- (validator, { attr: { required } }) => {
31
+ const addRequiredValidation = (createOrUpdate) => {
32
+ return (validator, { attr: { required } }) => {
33
+ let nextValidator = validator;
32
34
  if (required) {
33
35
  if (createOrUpdate === 'creation') {
34
- validator = validator.notNil();
36
+ nextValidator = nextValidator.notNil();
35
37
  } else if (createOrUpdate === 'update') {
36
- validator = validator.notNull();
38
+ nextValidator = nextValidator.notNull();
37
39
  }
38
40
  } else {
39
- validator = validator.nullable();
41
+ nextValidator = nextValidator.nullable();
40
42
  }
41
- return validator;
43
+ return nextValidator;
42
44
  };
45
+ };
46
+
47
+ const addDefault = (createOrUpdate) => {
48
+ return (validator, { attr }) => {
49
+ let nextValidator = validator;
43
50
 
44
- const addDefault =
45
- (createOrUpdate) =>
46
- (validator, { attr }) => {
47
51
  if (createOrUpdate === 'creation') {
48
52
  if (
49
53
  ((attr.type === 'component' && attr.repeatable) || attr.type === 'dynamiczone') &&
50
54
  !attr.required
51
55
  ) {
52
- validator = validator.default([]);
56
+ nextValidator = nextValidator.default([]);
53
57
  } else {
54
- validator = validator.default(attr.default);
58
+ nextValidator = nextValidator.default(attr.default);
55
59
  }
56
60
  } else {
57
- validator = validator.default(undefined);
61
+ nextValidator = nextValidator.default(undefined);
58
62
  }
59
63
 
60
- return validator;
64
+ return nextValidator;
61
65
  };
66
+ };
62
67
 
63
68
  const preventCast = (validator) => validator.transform((val, originalVal) => originalVal);
64
69
 
@@ -22,7 +22,7 @@ const createMiddleware = ({ sendEvent }) => {
22
22
  sendEvent('didReceiveRequest', { url: ctx.request.url });
23
23
 
24
24
  // Increase counter.
25
- _state.counter++;
25
+ _state.counter += 1;
26
26
  }
27
27
  }
28
28
 
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ const { AsyncLocalStorage } = require('async_hooks');
4
+
5
+ const storage = new AsyncLocalStorage();
6
+
7
+ const requestCtx = {
8
+ async run(store, cb) {
9
+ return storage.run(store, cb);
10
+ },
11
+
12
+ get() {
13
+ return storage.getStore();
14
+ },
15
+ };
16
+
17
+ module.exports = requestCtx;
@@ -9,6 +9,7 @@ const { createContentAPI } = require('./content-api');
9
9
  const registerAllRoutes = require('./register-routes');
10
10
  const registerApplicationMiddlewares = require('./register-middlewares');
11
11
  const createKoaApp = require('./koa');
12
+ const requestCtx = require('../request-context');
12
13
 
13
14
  const healthCheck = async (ctx) => {
14
15
  ctx.set('strapi', 'You are so French!');
@@ -33,6 +34,8 @@ const createServer = (strapi) => {
33
34
  keys: strapi.config.get('server.app.keys'),
34
35
  });
35
36
 
37
+ app.use((ctx, next) => requestCtx.run(ctx, () => next()));
38
+
36
39
  const router = new Router();
37
40
 
38
41
  const routeManager = createRouteManager(strapi);
@@ -50,7 +50,7 @@ const registerAdminRoutes = (strapi) => {
50
50
  * @param {import('../../').Strapi} strapi
51
51
  */
52
52
  const registerPluginRoutes = (strapi) => {
53
- for (const pluginName in strapi.plugins) {
53
+ for (const pluginName of Object.keys(strapi.plugins)) {
54
54
  const plugin = strapi.plugins[pluginName];
55
55
 
56
56
  const generateRouteScope = createRouteScopeGenerator(`plugin::${pluginName}`);
@@ -86,7 +86,7 @@ const registerPluginRoutes = (strapi) => {
86
86
  * @param {import('../../').Strapi} strapi
87
87
  */
88
88
  const registerAPIRoutes = (strapi) => {
89
- for (const apiName in strapi.api) {
89
+ for (const apiName of Object.keys(strapi.api)) {
90
90
  const api = strapi.api[apiName];
91
91
 
92
92
  const generateRouteScope = createRouteScopeGenerator(`api::${apiName}`);
@@ -27,7 +27,7 @@ module.exports = async (uid, entity, files) => {
27
27
  let tmpModel = modelDef;
28
28
  let modelUID = uid;
29
29
 
30
- for (let i = 0; i < path.length; i++) {
30
+ for (let i = 0; i < path.length; i += 1) {
31
31
  if (!tmpModel) return {};
32
32
  const part = path[i];
33
33
  const attr = tmpModel.attributes[part];
@@ -26,7 +26,7 @@ module.exports = class WorkerQueue {
26
26
  enqueue(payload) {
27
27
  debug('Enqueue event in worker queue');
28
28
  if (this.running < this.concurrency) {
29
- this.running++;
29
+ this.running += 1;
30
30
  this.execute(payload);
31
31
  } else {
32
32
  this.queue.unshift(payload);
@@ -40,7 +40,7 @@ module.exports = class WorkerQueue {
40
40
  if (payload) {
41
41
  this.execute(payload);
42
42
  } else {
43
- this.running--;
43
+ this.running -= 1;
44
44
  }
45
45
  }
46
46
 
@@ -1,10 +1,11 @@
1
1
  'use strict';
2
2
 
3
3
  module.exports = (path) => {
4
- if (typeof path !== 'string') throw new Error('admin.url must be a string');
5
- if (path === '' || path === '/') return '/';
4
+ let tmpPath = path;
5
+ if (typeof tmpPath !== 'string') throw new Error('admin.url must be a string');
6
+ if (tmpPath === '' || tmpPath === '/') return '/';
6
7
 
7
- if (path[0] != '/') path = `/${path}`;
8
- if (path[path.length - 1] != '/') path += '/';
9
- return path;
8
+ if (tmpPath[0] !== '/') tmpPath = `/${tmpPath}`;
9
+ if (tmpPath[tmpPath.length - 1] !== '/') tmpPath += '/';
10
+ return tmpPath;
10
11
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/strapi",
3
- "version": "4.3.7",
3
+ "version": "4.3.9",
4
4
  "description": "An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MySQL, MariaDB, PostgreSQL, SQLite",
5
5
  "keywords": [
6
6
  "strapi",
@@ -80,17 +80,17 @@
80
80
  "dependencies": {
81
81
  "@koa/cors": "3.4.1",
82
82
  "@koa/router": "10.1.1",
83
- "@strapi/admin": "4.3.7",
84
- "@strapi/database": "4.3.7",
85
- "@strapi/generate-new": "4.3.7",
86
- "@strapi/generators": "4.3.7",
87
- "@strapi/logger": "4.3.7",
88
- "@strapi/plugin-content-manager": "4.3.7",
89
- "@strapi/plugin-content-type-builder": "4.3.7",
90
- "@strapi/plugin-email": "4.3.7",
91
- "@strapi/plugin-upload": "4.3.7",
92
- "@strapi/typescript-utils": "4.3.7",
93
- "@strapi/utils": "4.3.7",
83
+ "@strapi/admin": "4.3.9",
84
+ "@strapi/database": "4.3.9",
85
+ "@strapi/generate-new": "4.3.9",
86
+ "@strapi/generators": "4.3.9",
87
+ "@strapi/logger": "4.3.9",
88
+ "@strapi/plugin-content-manager": "4.3.9",
89
+ "@strapi/plugin-content-type-builder": "4.3.9",
90
+ "@strapi/plugin-email": "4.3.9",
91
+ "@strapi/plugin-upload": "4.3.9",
92
+ "@strapi/typescript-utils": "4.3.9",
93
+ "@strapi/utils": "4.3.9",
94
94
  "bcryptjs": "2.4.3",
95
95
  "boxen": "5.1.2",
96
96
  "chalk": "4.1.2",
@@ -136,8 +136,8 @@
136
136
  "typescript": "4.6.2"
137
137
  },
138
138
  "engines": {
139
- "node": ">=14.19.1 <=16.x.x",
139
+ "node": ">=14.19.1 <=18.x.x",
140
140
  "npm": ">=6.0.0"
141
141
  },
142
- "gitHead": "73f523b98322cea8992c72977b94a73a624d2e79"
142
+ "gitHead": "8ebf58d9edb62872acf88d19d1f878b4a1632ff7"
143
143
  }