@strapi/strapi 4.6.0 → 4.6.1

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/bin/strapi.js CHANGED
@@ -409,6 +409,13 @@ program
409
409
  } else {
410
410
  thisCommand.opts().decompress = false;
411
411
  }
412
+
413
+ if (extname(file) !== '.tar') {
414
+ exitWith(
415
+ 1,
416
+ `The file '${opts.file}' does not appear to be a valid Strapi data file. It must have an extension ending in .tar[.gz][.enc]`
417
+ );
418
+ }
412
419
  })
413
420
  .hook(
414
421
  'preAction',
@@ -3,10 +3,12 @@
3
3
  const _ = require('lodash');
4
4
  const { has, prop, omit, toString, pipe, assign } = require('lodash/fp');
5
5
 
6
- const { contentTypes: contentTypesUtils } = require('@strapi/utils');
6
+ const { contentTypes: contentTypesUtils, mapAsync } = require('@strapi/utils');
7
7
  const { ApplicationError } = require('@strapi/utils').errors;
8
8
  const { getComponentAttributes } = require('@strapi/utils').contentTypes;
9
9
 
10
+ const isDialectMySQL = () => strapi.db.dialect.client === 'mysql';
11
+
10
12
  const omitComponentData = (contentType, data) => {
11
13
  const { attributes } = contentType;
12
14
  const componentAttributes = Object.keys(attributes).filter((attributeName) =>
@@ -43,10 +45,12 @@ const createComponents = async (uid, data) => {
43
45
  throw new Error('Expected an array to create repeatable component');
44
46
  }
45
47
 
46
- const components = [];
47
- for (const value of componentValue) {
48
- components.push(await createComponent(componentUID, value));
49
- }
48
+ // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
49
+ const components = await mapAsync(
50
+ componentValue,
51
+ (value) => createComponent(componentUID, value),
52
+ { concurrency: isDialectMySQL() ? 1 : Infinity }
53
+ );
50
54
 
51
55
  componentBody[attributeName] = components.map(({ id }) => {
52
56
  return {
@@ -78,19 +82,23 @@ const createComponents = async (uid, data) => {
78
82
  throw new Error('Expected an array to create repeatable component');
79
83
  }
80
84
 
81
- const dynamicZoneData = [];
82
- for (const value of dynamiczoneValues) {
85
+ const createDynamicZoneComponents = async (value) => {
83
86
  const { id } = await createComponent(value.__component, value);
84
- dynamicZoneData.push({
87
+ return {
85
88
  id,
86
89
  __component: value.__component,
87
90
  __pivot: {
88
91
  field: attributeName,
89
92
  },
90
- });
91
- }
93
+ };
94
+ };
92
95
 
93
- componentBody[attributeName] = dynamicZoneData;
96
+ // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
97
+ componentBody[attributeName] = await mapAsync(
98
+ dynamiczoneValues,
99
+ createDynamicZoneComponents,
100
+ { concurrency: isDialectMySQL() ? 1 : Infinity }
101
+ );
94
102
 
95
103
  continue;
96
104
  }
@@ -139,10 +147,12 @@ const updateComponents = async (uid, entityToUpdate, data) => {
139
147
  throw new Error('Expected an array to create repeatable component');
140
148
  }
141
149
 
142
- const components = [];
143
- for (const value of componentValue) {
144
- components.push(await updateOrCreateComponent(componentUID, value));
145
- }
150
+ // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
151
+ const components = await mapAsync(
152
+ componentValue,
153
+ (value) => updateOrCreateComponent(componentUID, value),
154
+ { concurrency: isDialectMySQL() ? 1 : Infinity }
155
+ );
146
156
 
147
157
  componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {
148
158
  return {
@@ -176,19 +186,22 @@ const updateComponents = async (uid, entityToUpdate, data) => {
176
186
  throw new Error('Expected an array to create repeatable component');
177
187
  }
178
188
 
179
- const dynamicZoneData = [];
180
- for (const value of dynamiczoneValues) {
181
- const { id } = await updateOrCreateComponent(value.__component, value);
182
- dynamicZoneData.push({
183
- id,
184
- __component: value.__component,
185
- __pivot: {
186
- field: attributeName,
187
- },
188
- });
189
- }
189
+ // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
190
+ componentBody[attributeName] = await mapAsync(
191
+ dynamiczoneValues,
192
+ async (value) => {
193
+ const { id } = await updateOrCreateComponent(value.__component, value);
190
194
 
191
- componentBody[attributeName] = dynamicZoneData;
195
+ return {
196
+ id,
197
+ __component: value.__component,
198
+ __pivot: {
199
+ field: attributeName,
200
+ },
201
+ };
202
+ },
203
+ { concurrency: isDialectMySQL() ? 1 : Infinity }
204
+ );
192
205
 
193
206
  continue;
194
207
  }
@@ -290,14 +303,18 @@ const deleteComponents = async (uid, entityToDelete, { loadComponents = true } =
290
303
 
291
304
  if (attribute.type === 'component') {
292
305
  const { component: componentUID } = attribute;
293
- for (const subValue of _.castArray(value)) {
294
- await deleteComponent(componentUID, subValue);
295
- }
306
+ // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
307
+ await mapAsync(_.castArray(value), (subValue) => deleteComponent(componentUID, subValue), {
308
+ concurrency: isDialectMySQL() ? 1 : Infinity,
309
+ });
296
310
  } else {
297
311
  // delete dynamic zone components
298
- for (const subValue of _.castArray(value)) {
299
- await deleteComponent(subValue.__component, subValue);
300
- }
312
+ // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
313
+ await mapAsync(
314
+ _.castArray(value),
315
+ (subValue) => deleteComponent(subValue.__component, subValue),
316
+ { concurrency: isDialectMySQL() ? 1 : Infinity }
317
+ );
301
318
  }
302
319
 
303
320
  continue;
@@ -3,6 +3,7 @@
3
3
  const os = require('os');
4
4
  const path = require('path');
5
5
  const _ = require('lodash');
6
+ const { map, values, sumBy, pipe, flatMap, propEq } = require('lodash/fp');
6
7
  const isDocker = require('is-docker');
7
8
  const fetch = require('node-fetch');
8
9
  const ciEnv = require('ci-info');
@@ -40,6 +41,14 @@ module.exports = (strapi) => {
40
41
  const serverRootPath = strapi.dirs.app.root;
41
42
  const adminRootPath = path.join(strapi.dirs.app.root, 'src', 'admin');
42
43
 
44
+ const getNumberOfDynamicZones = () => {
45
+ return pipe(
46
+ map('attributes'),
47
+ flatMap(values),
48
+ sumBy(propEq('type', 'dynamiczone'))
49
+ )(strapi.contentTypes);
50
+ };
51
+
43
52
  const anonymousUserProperties = {
44
53
  environment: strapi.config.environment,
45
54
  os: os.type(),
@@ -57,6 +66,9 @@ module.exports = (strapi) => {
57
66
  useTypescriptOnAdmin: isUsingTypeScriptSync(adminRootPath),
58
67
  projectId: uuid,
59
68
  isHostedOnStrapiCloud: env('STRAPI_HOSTING', null) === 'strapi.cloud',
69
+ numberOfAllContentTypes: _.size(strapi.contentTypes), // TODO: V5: This event should be renamed numberOfContentTypes in V5 as the name is already taken to describe the number of content types using i18n.
70
+ numberOfComponents: _.size(strapi.components),
71
+ numberOfDynamicZones: getNumberOfDynamicZones(),
60
72
  };
61
73
 
62
74
  addPackageJsonStrapiMetadata(anonymousGroupProperties, strapi);
@@ -30,7 +30,10 @@ export type ConfigurableAttribute = { configurable: true };
30
30
  export type NonConfigurableAttribute = { configurable: false };
31
31
 
32
32
  // custom field
33
- export type CustomField<T extends string, P extends object = undefined> = { customField: T, options?: P };
33
+ export type CustomField<T extends string, P extends object = undefined> = {
34
+ customField: T;
35
+ options?: P;
36
+ };
34
37
 
35
38
  // min/max
36
39
  export type SetMinMax<T extends MinMaxOption<U>, U = number> = T;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/strapi",
3
- "version": "4.6.0",
3
+ "version": "4.6.1",
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",
@@ -81,19 +81,19 @@
81
81
  "dependencies": {
82
82
  "@koa/cors": "3.4.3",
83
83
  "@koa/router": "10.1.1",
84
- "@strapi/admin": "4.6.0",
85
- "@strapi/data-transfer": "4.6.0",
86
- "@strapi/database": "4.6.0",
87
- "@strapi/generate-new": "4.6.0",
88
- "@strapi/generators": "4.6.0",
89
- "@strapi/logger": "4.6.0",
90
- "@strapi/permissions": "4.6.0",
91
- "@strapi/plugin-content-manager": "4.6.0",
92
- "@strapi/plugin-content-type-builder": "4.6.0",
93
- "@strapi/plugin-email": "4.6.0",
94
- "@strapi/plugin-upload": "4.6.0",
95
- "@strapi/typescript-utils": "4.6.0",
96
- "@strapi/utils": "4.6.0",
84
+ "@strapi/admin": "4.6.1",
85
+ "@strapi/data-transfer": "4.6.1",
86
+ "@strapi/database": "4.6.1",
87
+ "@strapi/generate-new": "4.6.1",
88
+ "@strapi/generators": "4.6.1",
89
+ "@strapi/logger": "4.6.1",
90
+ "@strapi/permissions": "4.6.1",
91
+ "@strapi/plugin-content-manager": "4.6.1",
92
+ "@strapi/plugin-content-type-builder": "4.6.1",
93
+ "@strapi/plugin-email": "4.6.1",
94
+ "@strapi/plugin-upload": "4.6.1",
95
+ "@strapi/typescript-utils": "4.6.1",
96
+ "@strapi/utils": "4.6.1",
97
97
  "bcryptjs": "2.4.3",
98
98
  "boxen": "5.1.2",
99
99
  "chalk": "4.1.2",
@@ -109,7 +109,7 @@
109
109
  "fs-extra": "10.0.0",
110
110
  "glob": "7.2.0",
111
111
  "http-errors": "1.8.1",
112
- "inquirer": "8.2.4",
112
+ "inquirer": "8.2.5",
113
113
  "is-docker": "2.2.1",
114
114
  "koa": "2.13.4",
115
115
  "koa-body": "4.2.0",
@@ -142,5 +142,5 @@
142
142
  "node": ">=14.19.1 <=18.x.x",
143
143
  "npm": ">=6.0.0"
144
144
  },
145
- "gitHead": "a9e55435c489f3379d88565bf3f729deb29bfb45"
145
+ "gitHead": "17a7845e3d453ea2e7911bda6ec25ed196dd5f16"
146
146
  }