@strapi/strapi 4.5.1 → 4.6.0-alpha.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.
package/bin/strapi.js CHANGED
@@ -7,11 +7,18 @@
7
7
  const _ = require('lodash');
8
8
  const resolveCwd = require('resolve-cwd');
9
9
  const { yellow } = require('chalk');
10
- const { Command } = require('commander');
10
+ const { Command, Option } = require('commander');
11
+ const inquirer = require('inquirer');
11
12
 
12
13
  const program = new Command();
13
14
 
14
15
  const packageJSON = require('../package.json');
16
+ const {
17
+ parseInputList,
18
+ parseInputBool,
19
+ promptEncryptionKey,
20
+ confirmKeyValue,
21
+ } = require('../lib/commands/utils/commander');
15
22
 
16
23
  const checkCwdIsStrapiApp = (name) => {
17
24
  const logErrorAndExit = () => {
@@ -60,6 +67,13 @@ const getLocalScript =
60
67
  });
61
68
  };
62
69
 
70
+ // option to exclude types of data for the export, import, and transfer commands
71
+ // TODO: validate these inputs. Hopefully here, but worst case it may require adding a hook on each command
72
+ const excludeOption = new Option(
73
+ '--exclude <data,to,exclude>',
74
+ 'Comma-separated list of data to exclude (files [localMediaFiles, providerMediaFiles], content [entities, links], schema, configuration)' // ['webhooks', 'content', 'localmedia', 'providermedia', 'relations']
75
+ ).argParser(parseInputList);
76
+
63
77
  // Initial program setup
64
78
  program.storeOptionsAsProperties(false).allowUnknownOption(true);
65
79
 
@@ -255,4 +269,97 @@ program
255
269
  .option('-s, --silent', `Run the generation silently, without any output`, false)
256
270
  .action(getLocalScript('ts/generate-types'));
257
271
 
272
+ // `$ strapi export`
273
+ program
274
+ .command('export')
275
+ .description('Export data from Strapi to file')
276
+ .addOption(
277
+ new Option(
278
+ '--encrypt <boolean>',
279
+ `Encrypt output file using the 'aes-128-ecb' algorithm. Prompts for key unless key option is used.`
280
+ )
281
+ .default(true)
282
+ .argParser(parseInputBool)
283
+ )
284
+ .addOption(
285
+ new Option('--compress <boolean>', 'Compress output file using gzip compression')
286
+ .default(true)
287
+ .argParser(parseInputBool)
288
+ )
289
+ .addOption(
290
+ new Option('--key <string>', 'Provide encryption key in command instead of using a prompt')
291
+ )
292
+ .addOption(
293
+ new Option('--max-size <max MB per file>', 'split final file when exceeding size in MB')
294
+ )
295
+ .addOption(
296
+ new Option(
297
+ '--max-size-jsonl <max MB per internal backup file>',
298
+ 'split internal jsonl files when exceeding max size in MB'
299
+ )
300
+ )
301
+ .addOption(new Option('-f, --file <file>', 'name to use for exported file (without extensions)'))
302
+ .addOption(excludeOption)
303
+ .allowExcessArguments(false)
304
+ .hook('preAction', promptEncryptionKey)
305
+ .action(getLocalScript('transfer/export'));
306
+
307
+ // `$ strapi import`
308
+ program
309
+ .command('import')
310
+ .description('Import data from file to Strapi')
311
+ .addOption(
312
+ new Option('--conflictStrategy <conflictStrategy>', 'Which strategy to use for ID conflicts')
313
+ .choices(['restore', 'abort', 'keep', 'replace'])
314
+ .default('restore')
315
+ )
316
+ .addOption(excludeOption)
317
+ .addOption(
318
+ new Option(
319
+ '--schemaComparison <schemaComparison>',
320
+ 'exact requires every field to match, strict requires Strapi version and content type schema fields do not break, subset requires source schema to exist in destination, bypass skips checks',
321
+ parseInputList
322
+ )
323
+ .choices(['exact', 'strict', 'subset', 'bypass'])
324
+ .default('exact')
325
+ )
326
+ .requiredOption(
327
+ '-f, --file <file>',
328
+ 'path and filename to the Strapi export file you want to import'
329
+ )
330
+ .addOption(
331
+ new Option('--key <string>', 'Provide encryption key in command instead of using a prompt')
332
+ )
333
+ .allowExcessArguments(false)
334
+ .hook('preAction', async (thisCommand) => {
335
+ const opts = thisCommand.opts();
336
+
337
+ // check extension to guess if we should prompt for key
338
+ if (String(opts.file).endsWith('.enc')) {
339
+ if (!opts.key) {
340
+ const answers = await inquirer.prompt([
341
+ {
342
+ type: 'password',
343
+ message: 'Please enter your decryption key',
344
+ name: 'key',
345
+ },
346
+ ]);
347
+ if (!answers.key?.length) {
348
+ console.log('No key entered, aborting import.');
349
+ process.exit(0);
350
+ }
351
+ opts.key = answers.key;
352
+ }
353
+ }
354
+ })
355
+ .hook(
356
+ 'preAction',
357
+ confirmKeyValue(
358
+ 'conflictStrategy',
359
+ 'restore',
360
+ "Using strategy 'restore' will delete all data in your database. Are you sure you want to proceed?"
361
+ )
362
+ )
363
+ .action(getLocalScript('transfer/import'));
364
+
258
365
  program.parseAsync(process.argv);
@@ -0,0 +1,166 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ createLocalFileDestinationProvider,
5
+ createLocalStrapiSourceProvider,
6
+ createTransferEngine,
7
+ // TODO: we need to solve this issue with typescript modules
8
+ // eslint-disable-next-line import/no-unresolved, node/no-missing-require
9
+ } = require('@strapi/data-transfer');
10
+ const _ = require('lodash/fp');
11
+ const Table = require('cli-table3');
12
+ const fs = require('fs-extra');
13
+
14
+ const chalk = require('chalk');
15
+ const strapi = require('../../index');
16
+ const { readableBytes } = require('../utils');
17
+
18
+ const pad = (n) => {
19
+ return (n < 10 ? '0' : '') + String(n);
20
+ };
21
+
22
+ const yyyymmddHHMMSS = () => {
23
+ const date = new Date();
24
+
25
+ return (
26
+ date.getFullYear() +
27
+ pad(date.getMonth() + 1) +
28
+ pad(date.getDate()) +
29
+ pad(date.getHours()) +
30
+ pad(date.getMinutes()) +
31
+ pad(date.getSeconds())
32
+ );
33
+ };
34
+
35
+ const getDefaultExportName = () => {
36
+ return `export_${yyyymmddHHMMSS()}`;
37
+ };
38
+
39
+ const logger = console;
40
+
41
+ const BYTES_IN_MB = 1024 * 1024;
42
+
43
+ module.exports = async (opts) => {
44
+ // validate inputs from Commander
45
+ if (!_.isObject(opts)) {
46
+ logger.error('Could not parse arguments');
47
+ process.exit(1);
48
+ }
49
+ const filename = opts.file;
50
+
51
+ /**
52
+ * From local Strapi instance
53
+ */
54
+ const sourceOptions = {
55
+ async getStrapi() {
56
+ return strapi(await strapi.compile()).load();
57
+ },
58
+ };
59
+ const source = createLocalStrapiSourceProvider(sourceOptions);
60
+
61
+ const file = _.isString(filename) && filename.length > 0 ? filename : getDefaultExportName();
62
+
63
+ /**
64
+ * To a Strapi backup file
65
+ */
66
+ // treat any unknown arguments as filenames
67
+ const destinationOptions = {
68
+ file: {
69
+ path: file,
70
+ maxSize: _.isFinite(opts.maxSize) ? Math.floor(opts.maxSize) * BYTES_IN_MB : undefined,
71
+ maxSizeJsonl: _.isFinite(opts.maxSizeJsonl)
72
+ ? Math.floor(opts.maxSizeJsonl) * BYTES_IN_MB
73
+ : undefined,
74
+ },
75
+ encryption: {
76
+ enabled: opts.encrypt,
77
+ key: opts.key,
78
+ },
79
+ compression: {
80
+ enabled: opts.compress,
81
+ },
82
+ };
83
+ const destination = createLocalFileDestinationProvider(destinationOptions);
84
+
85
+ /**
86
+ * Configure and run the transfer engine
87
+ */
88
+ const engineOptions = {
89
+ strategy: 'restore', // for an export to file, strategy will always be 'restore'
90
+ versionMatching: 'ignore', // for an export to file, versionMatching will always be skipped
91
+ exclude: opts.exclude,
92
+ };
93
+ const engine = createTransferEngine(source, destination, engineOptions);
94
+
95
+ try {
96
+ let resultData = [];
97
+ logger.log(`Starting export...`);
98
+
99
+ engine.progress.stream.on('start', ({ stage }) => {
100
+ logger.log(`Starting transfer of ${stage}...`);
101
+ });
102
+
103
+ // engine.progress.stream..on('progress', ({ stage, data }) => {
104
+ // logger.log('progress');
105
+ // });
106
+
107
+ engine.progress.stream.on('complete', ({ stage, data }) => {
108
+ logger.log(`...${stage} complete`);
109
+ resultData = data;
110
+ });
111
+
112
+ const results = await engine.transfer();
113
+
114
+ // Build pretty table
115
+ const table = new Table({
116
+ head: ['Type', 'Count', 'Size'],
117
+ });
118
+
119
+ let totalBytes = 0;
120
+ let totalItems = 0;
121
+ Object.keys(resultData).forEach((key) => {
122
+ const item = resultData[key];
123
+
124
+ table.push([
125
+ { hAlign: 'left', content: chalk.bold(key) },
126
+ { hAlign: 'right', content: item.count },
127
+ { hAlign: 'right', content: `${readableBytes(item.bytes, 1, 11)} ` },
128
+ ]);
129
+ totalBytes += item.bytes;
130
+ totalItems += item.count;
131
+
132
+ if (item.aggregates) {
133
+ Object.keys(item.aggregates).forEach((subkey) => {
134
+ const subitem = item.aggregates[subkey];
135
+
136
+ table.push([
137
+ { hAlign: 'left', content: `-- ${chalk.bold(subkey)}` },
138
+ { hAlign: 'right', content: subitem.count },
139
+ { hAlign: 'right', content: `(${chalk.grey(readableBytes(subitem.bytes, 1, 11))})` },
140
+ ]);
141
+ });
142
+ }
143
+ });
144
+ table.push([
145
+ { hAlign: 'left', content: chalk.bold.green('Total') },
146
+ { hAlign: 'right', content: chalk.bold.green(totalItems) },
147
+ { hAlign: 'right', content: `${chalk.bold.green(readableBytes(totalBytes, 1, 11))} ` },
148
+ ]);
149
+ logger.log(table.toString());
150
+
151
+ // TODO: once archiving is implemented, we need to check file extensions
152
+ if (!fs.pathExistsSync(results.destination.file.path)) {
153
+ logger.log(file);
154
+ throw new Error('Export file not created');
155
+ }
156
+
157
+ logger.log(`
158
+ ${chalk.bold('Export process has been completed successfully!')}
159
+ Export archive is in ${chalk.green(results.destination.file.path)}
160
+ `);
161
+ process.exit(0);
162
+ } catch (e) {
163
+ logger.error('Export process failed unexpectedly:', e.toString());
164
+ process.exit(1);
165
+ }
166
+ };
@@ -0,0 +1,65 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ createLocalFileSourceProvider,
5
+ createLocalStrapiDestinationProvider,
6
+ createTransferEngine,
7
+ // TODO: we need to solve this issue with typescript modules
8
+ // eslint-disable-next-line import/no-unresolved, node/no-missing-require
9
+ } = require('@strapi/data-transfer');
10
+ const { isObject } = require('lodash/fp');
11
+ const strapi = require('../../index');
12
+
13
+ const logger = console;
14
+
15
+ module.exports = async (opts) => {
16
+ // validate inputs from Commander
17
+ if (!isObject(opts)) {
18
+ logger.error('Could not parse arguments');
19
+ process.exit(1);
20
+ }
21
+ const filename = opts.file;
22
+
23
+ /**
24
+ * From strapi backup file
25
+ */
26
+
27
+ // treat any unknown arguments as filenames
28
+ const sourceOptions = {
29
+ backupFilePath: filename,
30
+ };
31
+ const source = createLocalFileSourceProvider(sourceOptions);
32
+
33
+ /**
34
+ * To local Strapi instance
35
+ */
36
+ const destinationOptions = {
37
+ async getStrapi() {
38
+ return strapi(await strapi.compile()).load();
39
+ },
40
+ };
41
+ const destination = createLocalStrapiDestinationProvider(destinationOptions);
42
+
43
+ /**
44
+ * Configure and run the transfer engine
45
+ */
46
+ const engineOptions = {
47
+ strategy: opts.conflictStrategy,
48
+ versionMatching: opts.schemaComparison,
49
+ exclude: opts.exclude,
50
+ };
51
+ const engine = createTransferEngine(source, destination, engineOptions);
52
+
53
+ try {
54
+ logger.log('Importing data...');
55
+ const result = await engine.transfer();
56
+ logger.log('Import process has been completed successfully!');
57
+
58
+ // TODO: this won't dump the entire results, we will print a pretty summary
59
+ logger.log('Results:', result);
60
+ process.exit(0);
61
+ } catch (e) {
62
+ logger.log(`Import process failed unexpectedly: ${e.message}`);
63
+ process.exit(1);
64
+ }
65
+ };
@@ -0,0 +1,92 @@
1
+ 'use strict';
2
+
3
+ const { parseType } = require('@strapi/utils/lib');
4
+ const inquirer = require('inquirer');
5
+
6
+ /**
7
+ * argsParser: Parse a string argument from the command line as a boolean
8
+ */
9
+ const parseInputBool = (arg) => {
10
+ try {
11
+ return parseType({ type: 'boolean', value: arg });
12
+ } catch (e) {
13
+ console.error(e.message);
14
+ process.exit(1);
15
+ }
16
+ };
17
+
18
+ /**
19
+ * argsParser: Parse a comma-delimited string as an array
20
+ */
21
+ const parseInputList = (value) => {
22
+ return value.split(',');
23
+ };
24
+
25
+ /**
26
+ * hook: if encrpyt=true and key not provided, prompt for it
27
+ */
28
+ const promptEncryptionKey = async (thisCommand) => {
29
+ const opts = thisCommand.opts();
30
+
31
+ if (!opts.encrypt && opts.key) {
32
+ console.error('Key may not be present unless encryption is used');
33
+ process.exit(1);
34
+ }
35
+
36
+ // if encrypt is set but we have no key, prompt for it
37
+ if (opts.encrypt && !(opts.key && opts.key.length > 0)) {
38
+ try {
39
+ const answers = await inquirer.prompt([
40
+ {
41
+ type: 'password',
42
+ message: 'Please enter an encryption key',
43
+ name: 'key',
44
+ validate(key) {
45
+ if (key.length > 0) return true;
46
+
47
+ return 'Key must be present when using the encrypt option';
48
+ },
49
+ },
50
+ ]);
51
+ opts.key = answers.key;
52
+ } catch (e) {
53
+ console.error('Failed to get encryption key');
54
+ process.exit(1);
55
+ }
56
+ if (!opts.key) {
57
+ console.error('Failed to get encryption key');
58
+ process.exit(1);
59
+ }
60
+ }
61
+ };
62
+
63
+ /**
64
+ * hook: confirm that key has a value with a provided message
65
+ */
66
+ const confirmKeyValue = (key, value, message) => {
67
+ return async (thisCommand) => {
68
+ const opts = thisCommand.opts();
69
+
70
+ if (!opts[key] || opts[key] !== value) {
71
+ console.error(`Could not confirm key ${key}, halting operation.`);
72
+ process.exit(1);
73
+ }
74
+ const answers = await inquirer.prompt([
75
+ {
76
+ type: 'confirm',
77
+ message,
78
+ name: `confirm_${key}`,
79
+ },
80
+ ]);
81
+ if (!answers[`confirm_${key}`]) {
82
+ process.exit(0);
83
+ }
84
+ };
85
+ };
86
+
87
+ module.exports = {
88
+ parseInputList,
89
+ parseInputBool,
90
+ promptEncryptionKey,
91
+ confirmKeyValue,
92
+ };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const bytesPerKb = 1024;
4
+ const sizes = ['B ', 'KB', 'MB', 'GB', 'TB', 'PB'];
5
+
6
+ const readableBytes = (bytes, decimals = 1, padStart = 0) => {
7
+ if (!bytes) {
8
+ return '0';
9
+ }
10
+ const i = Math.floor(Math.log(bytes) / Math.log(bytesPerKb));
11
+ const result = `${parseFloat((bytes / bytesPerKb ** i).toFixed(decimals))} ${sizes[i].padStart(
12
+ 2
13
+ )}`;
14
+
15
+ return result.padStart(padStart);
16
+ };
17
+
18
+ module.exports = {
19
+ readableBytes,
20
+ };
@@ -5,8 +5,8 @@
5
5
 
6
6
  'use strict';
7
7
 
8
- const { uniqBy, castArray, isNil } = require('lodash');
9
- const { has, assoc, prop, isObject, isEmpty, merge } = require('lodash/fp');
8
+ const { uniqBy, castArray, isNil, isArray, mergeWith } = require('lodash');
9
+ const { has, assoc, prop, isObject, isEmpty } = require('lodash/fp');
10
10
  const strapiUtils = require('@strapi/utils');
11
11
  const validators = require('./validators');
12
12
 
@@ -247,9 +247,14 @@ const createValidateEntity =
247
247
  * @returns {Object}
248
248
  */
249
249
  const buildRelationsStore = ({ uid, data }) => {
250
+ if (!uid) {
251
+ throw new ValidationError(`Cannot build relations store: "uid" is undefined`);
252
+ }
253
+
250
254
  if (isEmpty(data)) {
251
255
  return {};
252
256
  }
257
+
253
258
  const currentModel = strapi.getModel(uid);
254
259
 
255
260
  return Object.keys(currentModel.attributes).reduce((result, attributeName) => {
@@ -290,12 +295,17 @@ const buildRelationsStore = ({ uid, data }) => {
290
295
  case 'component': {
291
296
  return castArray(value).reduce(
292
297
  (relationsStore, componentValue) =>
293
- merge(
298
+ mergeWith(
294
299
  relationsStore,
295
300
  buildRelationsStore({
296
301
  uid: attribute.component,
297
302
  data: componentValue,
298
- })
303
+ }),
304
+ (objValue, srcValue) => {
305
+ if (isArray(objValue)) {
306
+ return objValue.concat(srcValue);
307
+ }
308
+ }
299
309
  ),
300
310
  result
301
311
  );
@@ -303,12 +313,17 @@ const buildRelationsStore = ({ uid, data }) => {
303
313
  case 'dynamiczone': {
304
314
  return value.reduce(
305
315
  (relationsStore, dzValue) =>
306
- merge(
316
+ mergeWith(
307
317
  relationsStore,
308
318
  buildRelationsStore({
309
319
  uid: dzValue.__component,
310
320
  data: dzValue,
311
- })
321
+ }),
322
+ (objValue, srcValue) => {
323
+ if (isArray(objValue)) {
324
+ return objValue.concat(srcValue);
325
+ }
326
+ }
312
327
  ),
313
328
  result
314
329
  );
@@ -3,7 +3,7 @@ import { Attribute, ConfigurableOption, PrivateOption } from './base';
3
3
  import { GetAttributesByType, GetAttributesValues } from './utils';
4
4
 
5
5
  export type BasicRelationsType = 'oneToOne' | 'oneToMany' | 'manyToOne' | 'manyToMany';
6
- export type PolymorphicRelationsType = 'morphToOne' | 'morphToMany' | 'morphOne' | 'morphMany';
6
+ export type PolymorphicRelationsType = 'morphToOne' | 'morphToMany' | 'morphOne' | 'morphMany';
7
7
  export type RelationsType = BasicRelationsType | PolymorphicRelationsType;
8
8
 
9
9
  export interface BasicRelationAttributeProperties<
@@ -17,16 +17,14 @@ export interface BasicRelationAttributeProperties<
17
17
  mappedBy?: RelationsKeysFromTo<T, S>;
18
18
  }
19
19
 
20
- export interface PolymorphicRelationAttributeProperties<
21
- R extends RelationsType,
22
- > {
20
+ export interface PolymorphicRelationAttributeProperties<R extends RelationsType> {
23
21
  relation: R;
24
22
  }
25
23
 
26
24
  export type RelationAttribute<
27
25
  S extends SchemaUID,
28
26
  R extends RelationsType,
29
- T extends R extends PolymorphicRelationsType ? never: SchemaUID = never
27
+ T extends R extends PolymorphicRelationsType ? never : SchemaUID = never
30
28
  > = Attribute<'relation'> &
31
29
  // Properties
32
30
  (R extends BasicRelationsType
@@ -34,22 +32,21 @@ export type RelationAttribute<
34
32
  : PolymorphicRelationAttributeProperties<R>) &
35
33
  // Options
36
34
  ConfigurableOption &
37
- PrivateOption
35
+ PrivateOption;
38
36
 
39
37
  export type RelationsKeysFromTo<
40
38
  TTarget extends SchemaUID,
41
39
  TSource extends SchemaUID
42
40
  > = keyof PickRelationsFromTo<TTarget, TSource>;
43
41
 
44
- export type PickRelationsFromTo<TTarget extends SchemaUID, TSource extends SchemaUID> = GetAttributesByType<
45
- TTarget,
46
- 'relation',
47
- { target: TSource }
48
- >;
42
+ export type PickRelationsFromTo<
43
+ TTarget extends SchemaUID,
44
+ TSource extends SchemaUID
45
+ > = GetAttributesByType<TTarget, 'relation', { target: TSource }>;
49
46
 
50
47
  export type RelationPluralityModifier<
51
48
  TRelation extends RelationsType,
52
- TValue extends Object
49
+ TValue extends Record<string, unknown>
53
50
  > = TRelation extends `${string}Many` ? TValue[] : TValue;
54
51
 
55
52
  export type RelationValue<
@@ -1,5 +1,5 @@
1
1
  import { Attribute, ComponentAttribute } from '../attributes';
2
- import { KeysBy, StringRecord } from '../../utils';
2
+ import { KeysBy, SchemaUID, StringRecord } from '../../utils';
3
3
 
4
4
  /**
5
5
  * Literal union type representing the possible natures of a content type
@@ -98,6 +98,11 @@ export interface PluginOptions {}
98
98
  export interface ContentTypeSchema extends Schema {
99
99
  modelType: 'contentType';
100
100
 
101
+ /**
102
+ * Unique identifier of the schema
103
+ */
104
+ uid: SchemaUID;
105
+
101
106
  /**
102
107
  * Determine the type of the content type (single-type or collection-type)
103
108
  */
@@ -2,8 +2,8 @@ import type Koa from 'koa';
2
2
  import { Database } from '@strapi/database';
3
3
 
4
4
  import type { StringMap } from './utils';
5
- import type { GenericController } from '../../../core-api/controller'
6
- import type { GenericService } from '../../../core-api/service'
5
+ import type { GenericController } from '../../../core-api/controller';
6
+ import type { GenericService } from '../../../core-api/service';
7
7
 
8
8
  // TODO move custom fields types to a separate file
9
9
  interface CustomFieldServerOptions {
@@ -92,9 +92,16 @@ export interface Strapi {
92
92
  */
93
93
  contentType(uid: string): any;
94
94
 
95
+ /**
96
+ * Getter for the Strapi component container
97
+ *
98
+ * It returns all the registered components
99
+ */
100
+ readonly components: any;
101
+
95
102
  /**
96
103
  * The custom fields registry
97
- *
104
+ *
98
105
  * It returns the custom fields interface
99
106
  */
100
107
  readonly customFields: CustomFields;
@@ -361,7 +368,6 @@ export interface Strapi {
361
368
  */
362
369
  log: any;
363
370
 
364
-
365
371
  /**
366
372
  * Used to manage cron within Strapi
367
373
  */
@@ -1,8 +1,8 @@
1
- import { Service,GenericService } from '../core-api/service';
1
+ import { Service, GenericService } from '../core-api/service';
2
2
  import { Controller, GenericController } from '../core-api/controller';
3
3
  import { Middleware } from '../middlewares';
4
4
  import { Policy } from '../core/registries/policies';
5
- import { Strapi } from '@strapi/strapi';
5
+ import { Strapi } from './core/strapi';
6
6
 
7
7
  type ControllerConfig<T extends Controller = Controller> = T;
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/strapi",
3
- "version": "4.5.1",
3
+ "version": "4.6.0-alpha.0",
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,18 +80,19 @@
80
80
  "dependencies": {
81
81
  "@koa/cors": "3.4.3",
82
82
  "@koa/router": "10.1.1",
83
- "@strapi/admin": "4.5.1",
84
- "@strapi/database": "4.5.1",
85
- "@strapi/generate-new": "4.5.1",
86
- "@strapi/generators": "4.5.1",
87
- "@strapi/logger": "4.5.1",
88
- "@strapi/permissions": "4.5.1",
89
- "@strapi/plugin-content-manager": "4.5.1",
90
- "@strapi/plugin-content-type-builder": "4.5.1",
91
- "@strapi/plugin-email": "4.5.1",
92
- "@strapi/plugin-upload": "4.5.1",
93
- "@strapi/typescript-utils": "4.5.1",
94
- "@strapi/utils": "4.5.1",
83
+ "@strapi/admin": "4.6.0-alpha.0",
84
+ "@strapi/data-transfer": "4.6.0-alpha.0",
85
+ "@strapi/database": "4.6.0-alpha.0",
86
+ "@strapi/generate-new": "4.6.0-alpha.0",
87
+ "@strapi/generators": "4.6.0-alpha.0",
88
+ "@strapi/logger": "4.6.0-alpha.0",
89
+ "@strapi/permissions": "4.6.0-alpha.0",
90
+ "@strapi/plugin-content-manager": "4.6.0-alpha.0",
91
+ "@strapi/plugin-content-type-builder": "4.6.0-alpha.0",
92
+ "@strapi/plugin-email": "4.6.0-alpha.0",
93
+ "@strapi/plugin-upload": "4.6.0-alpha.0",
94
+ "@strapi/typescript-utils": "4.6.0-alpha.0",
95
+ "@strapi/utils": "4.6.0-alpha.0",
95
96
  "bcryptjs": "2.4.3",
96
97
  "boxen": "5.1.2",
97
98
  "chalk": "4.1.2",
@@ -128,7 +129,7 @@
128
129
  "package-json": "7.0.0",
129
130
  "qs": "6.10.1",
130
131
  "resolve-cwd": "3.0.0",
131
- "semver": "7.3.7",
132
+ "semver": "7.3.8",
132
133
  "statuses": "2.0.1",
133
134
  "uuid": "^8.3.2"
134
135
  },
@@ -140,5 +141,5 @@
140
141
  "node": ">=14.19.1 <=18.x.x",
141
142
  "npm": ">=6.0.0"
142
143
  },
143
- "gitHead": "8c20ea2b5c5a115b78454086ea270dcd59b06004"
144
+ "gitHead": "b7a87dcffc6f44e18eedef92e354096ffe32ce0c"
144
145
  }