@strapi/strapi 4.6.0-beta.2 → 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.
@@ -15,6 +15,7 @@ const {
15
15
  buildTransferTable,
16
16
  createStrapiInstance,
17
17
  DEFAULT_IGNORED_CONTENT_TYPES,
18
+ formatDiagnostic,
18
19
  } = require('./utils');
19
20
 
20
21
  const logger = console;
@@ -109,6 +110,8 @@ module.exports = async (opts) => {
109
110
  },
110
111
  });
111
112
 
113
+ engine.diagnostics.onDiagnostic(formatDiagnostic('transfer'));
114
+
112
115
  try {
113
116
  logger.log(`Starting transfer...`);
114
117
 
@@ -120,8 +123,7 @@ module.exports = async (opts) => {
120
123
  logger.log(`${chalk.bold('Transfer process has been completed successfully!')}`);
121
124
  process.exit(0);
122
125
  } catch (e) {
123
- logger.error('Transfer process failed unexpectedly');
124
- logger.error(e);
126
+ logger.error('Transfer process failed.');
125
127
  process.exit(1);
126
128
  }
127
129
  };
@@ -4,6 +4,11 @@ const chalk = require('chalk');
4
4
  const Table = require('cli-table3');
5
5
  const { Option } = require('commander');
6
6
  const { TransferGroupPresets } = require('@strapi/data-transfer/lib/engine');
7
+
8
+ const {
9
+ configs: { createOutputFileConfiguration },
10
+ createLogger,
11
+ } = require('@strapi/logger');
7
12
  const { readableBytes, exitWith } = require('../utils/helpers');
8
13
  const strapi = require('../../index');
9
14
  const { getParseListWithChoices } = require('../utils/commander');
@@ -77,29 +82,34 @@ const DEFAULT_IGNORED_CONTENT_TYPES = [
77
82
  'admin::role',
78
83
  'admin::api-token',
79
84
  'admin::api-token-permission',
85
+ 'admin::audit-log',
80
86
  ];
81
87
 
82
88
  const createStrapiInstance = async (logLevel = 'error') => {
83
- const appContext = await strapi.compile();
84
- const app = strapi(appContext);
85
-
86
- app.log.level = logLevel;
87
-
88
- return app.load();
89
+ try {
90
+ const appContext = await strapi.compile();
91
+ const app = strapi(appContext);
92
+
93
+ app.log.level = logLevel;
94
+ return await app.load();
95
+ } catch (err) {
96
+ if (err.code === 'ECONNREFUSED') {
97
+ throw new Error('Process failed. Check the database connection with your Strapi project.');
98
+ }
99
+ throw err;
100
+ }
89
101
  };
90
102
 
91
103
  const transferDataTypes = Object.keys(TransferGroupPresets);
92
104
 
93
105
  const excludeOption = new Option(
94
106
  '--exclude <comma-separated data types>',
95
- `Exclude this data. Options used here override --only. Available types: ${transferDataTypes.join(
96
- ','
97
- )}`
107
+ `Exclude data using comma-separated types. Available types: ${transferDataTypes.join(',')}`
98
108
  ).argParser(getParseListWithChoices(transferDataTypes, 'Invalid options for "exclude"'));
99
109
 
100
110
  const onlyOption = new Option(
101
111
  '--only <command-separated data types>',
102
- `Include only this data (plus schemas). Available types: ${transferDataTypes.join(',')}`
112
+ `Include only these types of data (plus schemas). Available types: ${transferDataTypes.join(',')}`
103
113
  ).argParser(getParseListWithChoices(transferDataTypes, 'Invalid options for "only"'));
104
114
 
105
115
  const validateExcludeOnly = (command) => {
@@ -121,6 +131,44 @@ const validateExcludeOnly = (command) => {
121
131
  }
122
132
  };
123
133
 
134
+ const errorColors = {
135
+ fatal: chalk.red,
136
+ error: chalk.red,
137
+ silly: chalk.yellow,
138
+ };
139
+
140
+ const formatDiagnostic =
141
+ (operation) =>
142
+ ({ details, kind }) => {
143
+ const logger = createLogger(
144
+ createOutputFileConfiguration(`${operation}_error_log_${Date.now()}.log`)
145
+ );
146
+ try {
147
+ if (kind === 'error') {
148
+ const { message, severity = 'fatal' } = details;
149
+
150
+ const colorizeError = errorColors[severity];
151
+ const errorMessage = colorizeError(`[${severity.toUpperCase()}] ${message}`);
152
+
153
+ logger.error(errorMessage);
154
+ }
155
+ if (kind === 'info') {
156
+ const { message, params } = details;
157
+
158
+ const msg = `${message}\n${params ? JSON.stringify(params, null, 2) : ''}`;
159
+
160
+ logger.info(msg);
161
+ }
162
+ if (kind === 'warning') {
163
+ const { origin, message } = details;
164
+
165
+ logger.warn(`(${origin ?? 'transfer'}) ${message}`);
166
+ }
167
+ } catch (err) {
168
+ logger.error(err);
169
+ }
170
+ };
171
+
124
172
  module.exports = {
125
173
  buildTransferTable,
126
174
  getDefaultExportName,
@@ -129,4 +177,5 @@ module.exports = {
129
177
  excludeOption,
130
178
  onlyOption,
131
179
  validateExcludeOnly,
180
+ formatDiagnostic,
132
181
  };
@@ -122,7 +122,7 @@ const confirmMessage = (message) => {
122
122
  };
123
123
 
124
124
  const forceOption = new Option(
125
- '-f, --force',
125
+ '--force',
126
126
  `Automatically answer "yes" to all prompts, including potentially destructive requests, and run non-interactively.`
127
127
  );
128
128
 
@@ -85,7 +85,15 @@ const loadPlugins = async (strapi) => {
85
85
  for (const pluginName of Object.keys(enabledPlugins)) {
86
86
  const enabledPlugin = enabledPlugins[pluginName];
87
87
 
88
- const serverEntrypointPath = join(enabledPlugin.pathToPlugin, 'strapi-server.js');
88
+ let serverEntrypointPath;
89
+
90
+ try {
91
+ serverEntrypointPath = join(enabledPlugin.pathToPlugin, 'strapi-server.js');
92
+ } catch (e) {
93
+ throw new Error(
94
+ `Error loading the plugin ${pluginName} because ${pluginName} is not installed. Please either install the plugin or remove it's configuration.`
95
+ );
96
+ }
89
97
 
90
98
  // only load plugins with a server entrypoint
91
99
  if (!(await fse.pathExists(serverEntrypointPath))) {
@@ -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,8 +45,11 @@ const createComponents = async (uid, data) => {
43
45
  throw new Error('Expected an array to create repeatable component');
44
46
  }
45
47
 
46
- const components = await Promise.all(
47
- componentValue.map((value) => createComponent(componentUID, value))
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 }
48
53
  );
49
54
 
50
55
  componentBody[attributeName] = components.map(({ id }) => {
@@ -77,17 +82,22 @@ const createComponents = async (uid, data) => {
77
82
  throw new Error('Expected an array to create repeatable component');
78
83
  }
79
84
 
80
- componentBody[attributeName] = await Promise.all(
81
- dynamiczoneValues.map(async (value) => {
82
- const { id } = await createComponent(value.__component, value);
83
- return {
84
- id,
85
- __component: value.__component,
86
- __pivot: {
87
- field: attributeName,
88
- },
89
- };
90
- })
85
+ const createDynamicZoneComponents = async (value) => {
86
+ const { id } = await createComponent(value.__component, value);
87
+ return {
88
+ id,
89
+ __component: value.__component,
90
+ __pivot: {
91
+ field: attributeName,
92
+ },
93
+ };
94
+ };
95
+
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 }
91
101
  );
92
102
 
93
103
  continue;
@@ -137,8 +147,11 @@ const updateComponents = async (uid, entityToUpdate, data) => {
137
147
  throw new Error('Expected an array to create repeatable component');
138
148
  }
139
149
 
140
- const components = await Promise.all(
141
- componentValue.map((value) => updateOrCreateComponent(componentUID, value))
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 }
142
155
  );
143
156
 
144
157
  componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {
@@ -173,8 +186,10 @@ const updateComponents = async (uid, entityToUpdate, data) => {
173
186
  throw new Error('Expected an array to create repeatable component');
174
187
  }
175
188
 
176
- componentBody[attributeName] = await Promise.all(
177
- dynamiczoneValues.map(async (value) => {
189
+ // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
190
+ componentBody[attributeName] = await mapAsync(
191
+ dynamiczoneValues,
192
+ async (value) => {
178
193
  const { id } = await updateOrCreateComponent(value.__component, value);
179
194
 
180
195
  return {
@@ -184,7 +199,8 @@ const updateComponents = async (uid, entityToUpdate, data) => {
184
199
  field: attributeName,
185
200
  },
186
201
  };
187
- })
202
+ },
203
+ { concurrency: isDialectMySQL() ? 1 : Infinity }
188
204
  );
189
205
 
190
206
  continue;
@@ -287,13 +303,17 @@ const deleteComponents = async (uid, entityToDelete, { loadComponents = true } =
287
303
 
288
304
  if (attribute.type === 'component') {
289
305
  const { component: componentUID } = attribute;
290
- await Promise.all(
291
- _.castArray(value).map((subValue) => deleteComponent(componentUID, subValue))
292
- );
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
+ });
293
310
  } else {
294
311
  // delete dynamic zone components
295
- await Promise.all(
296
- _.castArray(value).map((subValue) => deleteComponent(subValue.__component, subValue))
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 }
297
317
  );
298
318
  }
299
319
 
@@ -70,6 +70,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
70
70
 
71
71
  eventHub.emit(event, {
72
72
  model: model.modelName,
73
+ uid: model.uid,
73
74
  entry: sanitizedEntity,
74
75
  });
75
76
  },
@@ -5,12 +5,8 @@
5
5
  * You can learn more at https://docs.strapi.io/developer-docs/latest/getting-started/usage-information.html
6
6
  */
7
7
 
8
- const crypto = require('crypto');
9
- const fs = require('fs');
10
- const path = require('path');
11
8
  const { scheduleJob } = require('node-schedule');
12
9
 
13
- const ee = require('../../utils/ee');
14
10
  const wrapWithRateLimit = require('./rate-limiter');
15
11
  const createSender = require('./sender');
16
12
  const createMiddleware = require('./middleware');
@@ -46,41 +42,14 @@ const createTelemetryInstance = (strapi) => {
46
42
  strapi.server.use(createMiddleware({ sendEvent }));
47
43
  }
48
44
  },
49
- bootstrap() {
50
- if (strapi.EE === true && ee.isEE === true) {
51
- const pingDisabled =
52
- isTruthy(process.env.STRAPI_LICENSE_PING_DISABLED) && ee.licenseInfo.type === 'gold';
53
45
 
54
- const sendLicenseCheck = () => {
55
- return sendEvent(
56
- 'didCheckLicense',
57
- {
58
- groupProperties: {
59
- licenseInfo: {
60
- ...ee.licenseInfo,
61
- projectHash: hashProject(strapi),
62
- dependencyHash: hashDep(strapi),
63
- },
64
- },
65
- },
66
- {
67
- headers: { 'x-strapi-project': 'enterprise' },
68
- }
69
- );
70
- };
46
+ bootstrap() {},
71
47
 
72
- if (!pingDisabled) {
73
- const licenseCron = scheduleJob('0 0 0 * * 7', () => sendLicenseCheck());
74
- crons.push(licenseCron);
75
-
76
- sendLicenseCheck();
77
- }
78
- }
79
- },
80
48
  destroy() {
81
- // clear open handles
49
+ // Clear open handles
82
50
  crons.forEach((cron) => cron.cancel());
83
51
  },
52
+
84
53
  async send(event, payload) {
85
54
  if (isDisabled) return true;
86
55
  return sendEvent(event, payload);
@@ -88,24 +57,4 @@ const createTelemetryInstance = (strapi) => {
88
57
  };
89
58
  };
90
59
 
91
- const hash = (str) => crypto.createHash('sha256').update(str).digest('hex');
92
-
93
- const hashProject = (strapi) =>
94
- hash(`${strapi.config.get('info.name')}${strapi.config.get('info.description')}`);
95
-
96
- const hashDep = (strapi) => {
97
- const depStr = JSON.stringify(strapi.config.info.dependencies);
98
- const readmePath = path.join(strapi.dirs.app.root, 'README.md');
99
-
100
- try {
101
- if (fs.existsSync(readmePath)) {
102
- return hash(`${depStr}${fs.readFileSync(readmePath)}`);
103
- }
104
- } catch (err) {
105
- return hash(`${depStr}`);
106
- }
107
-
108
- return hash(`${depStr}`);
109
- };
110
-
111
60
  module.exports = createTelemetryInstance;
@@ -3,12 +3,12 @@
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');
9
10
  const { isUsingTypeScriptSync } = require('@strapi/typescript-utils');
10
11
  const { env } = require('@strapi/utils');
11
- const ee = require('../../utils/ee');
12
12
  const machineID = require('../../utils/machine-id');
13
13
  const { generateAdminUserHash } = require('./admin-user-hash');
14
14
 
@@ -37,11 +37,18 @@ const addPackageJsonStrapiMetadata = (metadata, strapi) => {
37
37
  module.exports = (strapi) => {
38
38
  const { uuid } = strapi.config;
39
39
  const deviceId = machineID();
40
- const isEE = strapi.EE === true && ee.isEE === true;
41
40
 
42
41
  const serverRootPath = strapi.dirs.app.root;
43
42
  const adminRootPath = path.join(strapi.dirs.app.root, 'src', 'admin');
44
43
 
44
+ const getNumberOfDynamicZones = () => {
45
+ return pipe(
46
+ map('attributes'),
47
+ flatMap(values),
48
+ sumBy(propEq('type', 'dynamiczone'))
49
+ )(strapi.contentTypes);
50
+ };
51
+
45
52
  const anonymousUserProperties = {
46
53
  environment: strapi.config.environment,
47
54
  os: os.type(),
@@ -55,11 +62,13 @@ module.exports = (strapi) => {
55
62
  docker: process.env.DOCKER || isDocker(),
56
63
  isCI: ciEnv.isCI,
57
64
  version: strapi.config.get('info.strapi'),
58
- projectType: isEE ? 'Enterprise' : 'Community',
59
65
  useTypescriptOnServer: isUsingTypeScriptSync(serverRootPath),
60
66
  useTypescriptOnAdmin: isUsingTypeScriptSync(adminRootPath),
61
67
  projectId: uuid,
62
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(),
63
72
  };
64
73
 
65
74
  addPackageJsonStrapiMetadata(anonymousGroupProperties, strapi);
@@ -77,6 +86,7 @@ module.exports = (strapi) => {
77
86
  userProperties: userId ? { ...anonymousUserProperties, ...payload.userProperties } : {},
78
87
  groupProperties: {
79
88
  ...anonymousGroupProperties,
89
+ projectType: strapi.EE ? 'Enterprise' : 'Community',
80
90
  ...payload.groupProperties,
81
91
  },
82
92
  }),
@@ -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;
@@ -0,0 +1,56 @@
1
+ 'use strict';
2
+
3
+ const { isEmpty, negate } = require('lodash/fp');
4
+
5
+ const INTEGER_REGEX = /^\d+$/;
6
+ const STEP_REGEX = /^\*\/\d+$/;
7
+ const COMPONENTS = [
8
+ { limit: 60, zeroBasedIndices: true, functionName: 'getSeconds' },
9
+ { limit: 60, zeroBasedIndices: true, functionName: 'getMinutes' },
10
+ { limit: 24, zeroBasedIndices: true, functionName: 'getHours' },
11
+ { limit: 31, zeroBasedIndices: false, functionName: 'getDate' },
12
+ { limit: 12, zeroBasedIndices: false, functionName: 'getMonth' },
13
+ { limit: 7, zeroBasedIndices: true, functionName: 'getDay' },
14
+ ];
15
+
16
+ const shift = (component, index, date) => {
17
+ if (component === '*') {
18
+ return '*';
19
+ }
20
+
21
+ const { limit, zeroBasedIndices, functionName } = COMPONENTS[index];
22
+ const offset = +!zeroBasedIndices;
23
+ const currentValue = date[functionName]();
24
+
25
+ if (INTEGER_REGEX.test(component)) {
26
+ return ((Number.parseInt(component, 10) + currentValue) % limit) + offset;
27
+ }
28
+
29
+ if (STEP_REGEX.test(component)) {
30
+ const [, step] = component.split('/');
31
+ const frequency = Math.floor(limit / step);
32
+ const list = Array.from({ length: frequency }, (_, index) => index * step);
33
+ return list.map((value) => ((value + currentValue) % limit) + offset).sort((a, b) => a - b);
34
+ }
35
+
36
+ // Unsupported syntax
37
+ return component;
38
+ };
39
+
40
+ /**
41
+ * Simulate an interval by shifting a cron expression using the specified date.
42
+ * @param {string} rule A cron expression you want to shift.
43
+ * @param {Date} date The date that's gonna be used as the start of the "interval", it defaults to now.
44
+ * @returns The shifted cron expression.
45
+ */
46
+ const shiftCronExpression = (rule, date = new Date()) => {
47
+ const components = rule.trim().split(' ').filter(negate(isEmpty));
48
+ const secondsIncluded = components.length === 6;
49
+ return components
50
+ .map((component, index) => shift(component, secondsIncluded ? index : index + 1, date))
51
+ .join(' ');
52
+ };
53
+
54
+ module.exports = {
55
+ shiftCronExpression,
56
+ };
package/lib/utils/ee.js CHANGED
@@ -1,123 +1,3 @@
1
1
  'use strict';
2
2
 
3
- const path = require('path');
4
- const fs = require('fs');
5
- const crypto = require('crypto');
6
- const _ = require('lodash');
7
-
8
- const publicKey = fs.readFileSync(path.join(__dirname, '../utils/resources/key.pub'));
9
-
10
- const noop = () => {};
11
-
12
- const noLog = {
13
- warn: noop,
14
- info: noop,
15
- };
16
-
17
- const internals = {};
18
- const features = {
19
- bronze: [],
20
- silver: [],
21
- gold: ['sso', 'audit-logs'],
22
- };
23
-
24
- module.exports = ({ dir, logger = noLog }) => {
25
- if (_.has(internals, 'isEE')) return internals.isEE;
26
-
27
- const warnAndReturn = (msg = 'Invalid license. Starting in CE.') => {
28
- logger.warn(msg);
29
- internals.isEE = false;
30
- return false;
31
- };
32
-
33
- if (process.env.STRAPI_DISABLE_EE === 'true') {
34
- internals.isEE = false;
35
- return false;
36
- }
37
-
38
- const licensePath = path.join(dir, 'license.txt');
39
-
40
- let license;
41
- if (_.has(process.env, 'STRAPI_LICENSE')) {
42
- license = process.env.STRAPI_LICENSE;
43
- } else if (fs.existsSync(licensePath)) {
44
- license = fs.readFileSync(licensePath).toString();
45
- }
46
-
47
- if (_.isNil(license)) {
48
- internals.isEE = false;
49
- return false;
50
- }
51
-
52
- try {
53
- const plainLicense = Buffer.from(license, 'base64').toString();
54
- const [signatureb64, contentb64] = plainLicense.split('\n');
55
-
56
- const signature = Buffer.from(signatureb64, 'base64');
57
- const content = Buffer.from(contentb64, 'base64').toString();
58
-
59
- const verifier = crypto.createVerify('RSA-SHA256');
60
- verifier.update(content);
61
- verifier.end();
62
-
63
- const isValid = verifier.verify(publicKey, signature);
64
- if (!isValid) return warnAndReturn();
65
-
66
- internals.licenseInfo = JSON.parse(content);
67
-
68
- const expirationTime = new Date(internals.licenseInfo.expireAt).getTime();
69
- if (expirationTime < new Date().getTime()) {
70
- return warnAndReturn('License expired. Starting in CE');
71
- }
72
- } catch (err) {
73
- return warnAndReturn();
74
- }
75
-
76
- internals.isEE = true;
77
- return true;
78
- };
79
-
80
- Object.defineProperty(module.exports, 'licenseInfo', {
81
- get() {
82
- mustHaveKey('licenseInfo');
83
- return internals.licenseInfo;
84
- },
85
- configurable: false,
86
- enumerable: false,
87
- });
88
-
89
- Object.defineProperty(module.exports, 'isEE', {
90
- get() {
91
- mustHaveKey('isEE');
92
- return internals.isEE;
93
- },
94
- configurable: false,
95
- enumerable: false,
96
- });
97
-
98
- Object.defineProperty(module.exports, 'features', {
99
- get() {
100
- mustHaveKey('licenseInfo');
101
-
102
- const { type: licenseType } = module.exports.licenseInfo;
103
-
104
- return {
105
- isEnabled(feature) {
106
- return features[licenseType].includes(feature);
107
- },
108
- getEnabled() {
109
- return features[licenseType];
110
- },
111
- };
112
- },
113
- configurable: false,
114
- enumerable: false,
115
- });
116
-
117
- const mustHaveKey = (key) => {
118
- if (!_.has(internals, key)) {
119
- const err = new Error('Tampering with license');
120
- // err.stack = null;
121
- throw err;
122
- }
123
- };
3
+ module.exports = require('../../ee');
@@ -4,7 +4,6 @@ const chalk = require('chalk');
4
4
  const CLITable = require('cli-table3');
5
5
  const _ = require('lodash/fp');
6
6
  const { getAbsoluteAdminUrl, getAbsoluteServerUrl } = require('@strapi/utils');
7
- const ee = require('./ee');
8
7
 
9
8
  module.exports = (app) => {
10
9
  return {
@@ -19,15 +18,14 @@ module.exports = (app) => {
19
18
  chars: { mid: '', 'left-mid': '', 'mid-mid': '', 'right-mid': '' },
20
19
  });
21
20
 
22
- const isEE = app.EE === true && ee.isEE === true;
23
-
24
21
  infoTable.push(
25
22
  [chalk.blue('Time'), `${new Date()}`],
26
23
  [chalk.blue('Launched in'), `${Date.now() - app.config.launchedAt} ms`],
27
24
  [chalk.blue('Environment'), app.config.environment],
28
25
  [chalk.blue('Process PID'), process.pid],
29
26
  [chalk.blue('Version'), `${app.config.info.strapi} (node ${process.version})`],
30
- [chalk.blue('Edition'), isEE ? 'Enterprise' : 'Community']
27
+ [chalk.blue('Edition'), app.EE ? 'Enterprise' : 'Community'],
28
+ [chalk.blue('Database'), app.db.dialect.client]
31
29
  );
32
30
 
33
31
  console.log(infoTable.toString());