@strapi/strapi 4.0.0-beta.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.
Files changed (143) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +144 -0
  3. package/bin/strapi.js +186 -0
  4. package/lib/Strapi.js +470 -0
  5. package/lib/commands/admin-reset.js +51 -0
  6. package/lib/commands/build.js +56 -0
  7. package/lib/commands/configurationDump.js +50 -0
  8. package/lib/commands/configurationRestore.js +169 -0
  9. package/lib/commands/console.js +26 -0
  10. package/lib/commands/develop.js +157 -0
  11. package/lib/commands/generate-template.js +97 -0
  12. package/lib/commands/install.js +48 -0
  13. package/lib/commands/new.js +11 -0
  14. package/lib/commands/start.js +8 -0
  15. package/lib/commands/uninstall.js +68 -0
  16. package/lib/commands/watchAdmin.js +45 -0
  17. package/lib/container.js +45 -0
  18. package/lib/core/app-configuration/config-loader.js +20 -0
  19. package/lib/core/app-configuration/index.js +75 -0
  20. package/lib/core/app-configuration/load-config-file.js +43 -0
  21. package/lib/core/app-configuration/load-functions.js +28 -0
  22. package/lib/core/bootstrap.js +60 -0
  23. package/lib/core/domain/component/index.js +24 -0
  24. package/lib/core/domain/component/validator.js +29 -0
  25. package/lib/core/domain/content-type/index.js +140 -0
  26. package/lib/core/domain/content-type/validator.js +64 -0
  27. package/lib/core/domain/module/index.js +106 -0
  28. package/lib/core/domain/module/validation.js +36 -0
  29. package/lib/core/loaders/admin.js +16 -0
  30. package/lib/core/loaders/apis.js +157 -0
  31. package/lib/core/loaders/components.js +41 -0
  32. package/lib/core/loaders/index.js +11 -0
  33. package/lib/core/loaders/middlewares.js +86 -0
  34. package/lib/core/loaders/plugins/get-enabled-plugins.js +100 -0
  35. package/lib/core/loaders/plugins/index.js +109 -0
  36. package/lib/core/loaders/policies.js +28 -0
  37. package/lib/core/loaders/src-index.js +38 -0
  38. package/lib/core/registries/apis.js +43 -0
  39. package/lib/core/registries/config.js +21 -0
  40. package/lib/core/registries/content-types.js +53 -0
  41. package/lib/core/registries/controllers.js +43 -0
  42. package/lib/core/registries/hooks.js +37 -0
  43. package/lib/core/registries/middlewares.js +30 -0
  44. package/lib/core/registries/modules.js +44 -0
  45. package/lib/core/registries/plugins.js +28 -0
  46. package/lib/core/registries/policies.js +38 -0
  47. package/lib/core/registries/services.js +58 -0
  48. package/lib/core/utils.js +35 -0
  49. package/lib/core-api/controller/collection-type.js +84 -0
  50. package/lib/core-api/controller/index.js +26 -0
  51. package/lib/core-api/controller/single-type.js +44 -0
  52. package/lib/core-api/controller/transform.js +97 -0
  53. package/lib/core-api/index.js +39 -0
  54. package/lib/core-api/service/collection-type.js +84 -0
  55. package/lib/core-api/service/index.js +55 -0
  56. package/lib/core-api/service/pagination.js +125 -0
  57. package/lib/core-api/service/single-type.js +58 -0
  58. package/lib/index.d.ts +26 -0
  59. package/lib/index.js +3 -0
  60. package/lib/load/filepath-to-prop-path.js +22 -0
  61. package/lib/load/glob.js +15 -0
  62. package/lib/load/index.js +9 -0
  63. package/lib/load/load-files.js +56 -0
  64. package/lib/load/package-path.js +9 -0
  65. package/lib/middlewares/cors/index.js +66 -0
  66. package/lib/middlewares/error/defaults.json +5 -0
  67. package/lib/middlewares/error/index.js +147 -0
  68. package/lib/middlewares/favicon/defaults.json +7 -0
  69. package/lib/middlewares/favicon/index.js +31 -0
  70. package/lib/middlewares/gzip/defaults.json +6 -0
  71. package/lib/middlewares/gzip/index.js +19 -0
  72. package/lib/middlewares/helmet/defaults.json +18 -0
  73. package/lib/middlewares/helmet/index.js +9 -0
  74. package/lib/middlewares/index.js +120 -0
  75. package/lib/middlewares/ip/defaults.json +7 -0
  76. package/lib/middlewares/ip/index.js +25 -0
  77. package/lib/middlewares/logger/defaults.json +5 -0
  78. package/lib/middlewares/logger/index.js +37 -0
  79. package/lib/middlewares/parser/defaults.json +11 -0
  80. package/lib/middlewares/parser/index.js +75 -0
  81. package/lib/middlewares/poweredBy/defaults.json +5 -0
  82. package/lib/middlewares/poweredBy/index.js +16 -0
  83. package/lib/middlewares/public/assets/images/group_people_1.png +0 -0
  84. package/lib/middlewares/public/assets/images/group_people_2.png +0 -0
  85. package/lib/middlewares/public/assets/images/group_people_3.png +0 -0
  86. package/lib/middlewares/public/assets/images/logo_login.png +0 -0
  87. package/lib/middlewares/public/defaults.json +8 -0
  88. package/lib/middlewares/public/index.html +66 -0
  89. package/lib/middlewares/public/index.js +130 -0
  90. package/lib/middlewares/public/serve-static.js +23 -0
  91. package/lib/middlewares/responseTime/defaults.json +5 -0
  92. package/lib/middlewares/responseTime/index.js +25 -0
  93. package/lib/middlewares/responses/defaults.json +5 -0
  94. package/lib/middlewares/responses/index.js +19 -0
  95. package/lib/middlewares/router/defaults.json +7 -0
  96. package/lib/middlewares/router/index.js +97 -0
  97. package/lib/middlewares/session/defaults.json +18 -0
  98. package/lib/middlewares/session/index.js +140 -0
  99. package/lib/migrations/draft-publish.js +57 -0
  100. package/lib/services/auth/index.js +92 -0
  101. package/lib/services/core-store.js +145 -0
  102. package/lib/services/cron.js +54 -0
  103. package/lib/services/entity-service/components.js +365 -0
  104. package/lib/services/entity-service/index.d.ts +91 -0
  105. package/lib/services/entity-service/index.js +244 -0
  106. package/lib/services/entity-service/params.js +145 -0
  107. package/lib/services/entity-validator/index.js +187 -0
  108. package/lib/services/entity-validator/validators.js +123 -0
  109. package/lib/services/event-hub.js +15 -0
  110. package/lib/services/fs.js +58 -0
  111. package/lib/services/metrics/index.js +104 -0
  112. package/lib/services/metrics/is-truthy.js +9 -0
  113. package/lib/services/metrics/middleware.js +33 -0
  114. package/lib/services/metrics/rate-limiter.js +27 -0
  115. package/lib/services/metrics/sender.js +76 -0
  116. package/lib/services/metrics/stringify-deep.js +22 -0
  117. package/lib/services/server/admin-api.js +14 -0
  118. package/lib/services/server/api.js +32 -0
  119. package/lib/services/server/compose-endpoint.js +112 -0
  120. package/lib/services/server/content-api.js +16 -0
  121. package/lib/services/server/http-server.js +64 -0
  122. package/lib/services/server/index.js +108 -0
  123. package/lib/services/server/middleware.js +28 -0
  124. package/lib/services/server/policy.js +34 -0
  125. package/lib/services/server/routing.js +107 -0
  126. package/lib/services/utils/upload-files.js +79 -0
  127. package/lib/services/webhook-runner.js +155 -0
  128. package/lib/services/webhook-store.js +91 -0
  129. package/lib/services/worker-queue.js +58 -0
  130. package/lib/utils/addSlash.js +10 -0
  131. package/lib/utils/ee.js +123 -0
  132. package/lib/utils/get-dirs.js +15 -0
  133. package/lib/utils/get-prefixed-dependencies.js +7 -0
  134. package/lib/utils/index.js +11 -0
  135. package/lib/utils/is-initialized.js +23 -0
  136. package/lib/utils/open-browser.js +12 -0
  137. package/lib/utils/resources/key.pub +9 -0
  138. package/lib/utils/run-checks.js +22 -0
  139. package/lib/utils/startup-logger.js +90 -0
  140. package/lib/utils/success.js +31 -0
  141. package/lib/utils/update-notifier/index.js +97 -0
  142. package/lib/utils/url-from-segments.js +12 -0
  143. package/package.json +133 -0
@@ -0,0 +1,169 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const _ = require('lodash');
5
+ const strapi = require('../index');
6
+
7
+ /**
8
+ * Will restore configurations. It reads from a file or stdin
9
+ * @param {string} file filepath to use as input
10
+ * @param {string} strategy import strategy. one of (replace, merge, keep, default: replace)
11
+ */
12
+ module.exports = async function({ file: filePath, strategy = 'replace' }) {
13
+ const input = filePath ? fs.readFileSync(filePath) : await readStdin(process.stdin);
14
+
15
+ const app = await strapi().load();
16
+
17
+ let dataToImport;
18
+ try {
19
+ dataToImport = JSON.parse(input);
20
+ } catch (error) {
21
+ throw new Error(`Invalid input data: ${error.message}. Expected a valid JSON array.`);
22
+ }
23
+
24
+ if (!Array.isArray(dataToImport)) {
25
+ throw new Error(`Invalid input data. Expected a valid JSON array.`);
26
+ }
27
+
28
+ const importer = createImporter(app.db, strategy);
29
+
30
+ for (const config of dataToImport) {
31
+ await importer.import(config);
32
+ }
33
+
34
+ console.log(
35
+ `Successfully imported configuration with ${strategy} strategy. Statistics: ${importer.printStatistics()}.`
36
+ );
37
+
38
+ process.exit(0);
39
+ };
40
+
41
+ const readStdin = () => {
42
+ const { stdin } = process;
43
+ let result = '';
44
+
45
+ if (stdin.isTTY) return Promise.resolve(result);
46
+
47
+ return new Promise((resolve, reject) => {
48
+ stdin.setEncoding('utf8');
49
+ stdin.on('readable', () => {
50
+ let chunk;
51
+ while ((chunk = stdin.read())) {
52
+ result += chunk;
53
+ }
54
+ });
55
+
56
+ stdin.on('end', () => {
57
+ resolve(result);
58
+ });
59
+
60
+ stdin.on('error', reject);
61
+ });
62
+ };
63
+
64
+ const createImporter = (db, strategy) => {
65
+ switch (strategy) {
66
+ case 'replace':
67
+ return createReplaceImporter(db);
68
+ case 'merge':
69
+ return createMergeImporter(db);
70
+ case 'keep':
71
+ return createKeepImporter(db);
72
+ default:
73
+ throw new Error(`No importer available for strategy "${strategy}"`);
74
+ }
75
+ };
76
+
77
+ /**
78
+ * Replace importer. Will replace the keys that already exist and create the new ones
79
+ * @param {Object} db - DatabaseManager instance
80
+ */
81
+ const createReplaceImporter = db => {
82
+ const stats = {
83
+ created: 0,
84
+ replaced: 0,
85
+ };
86
+
87
+ return {
88
+ printStatistics() {
89
+ return `${stats.created} created, ${stats.replaced} replaced`;
90
+ },
91
+
92
+ async import(conf) {
93
+ const matching = await db.query('strapi::core-store').count({ where: { key: conf.key } });
94
+ if (matching > 0) {
95
+ stats.replaced += 1;
96
+ await db.query('strapi::core-store').update({
97
+ where: { key: conf.key },
98
+ data: conf,
99
+ });
100
+ } else {
101
+ stats.created += 1;
102
+ await db.query('strapi::core-store').create({ data: conf });
103
+ }
104
+ },
105
+ };
106
+ };
107
+
108
+ /**
109
+ * Merge importer. Will merge the keys that already exist with their new value and create the new ones
110
+ * @param {Object} db - DatabaseManager instance
111
+ */
112
+ const createMergeImporter = db => {
113
+ const stats = {
114
+ created: 0,
115
+ merged: 0,
116
+ };
117
+
118
+ return {
119
+ printStatistics() {
120
+ return `${stats.created} created, ${stats.merged} merged`;
121
+ },
122
+
123
+ async import(conf) {
124
+ const existingConf = await db
125
+ .query('strapi::core-store')
126
+ .findOne({ where: { key: conf.key } });
127
+
128
+ if (existingConf) {
129
+ stats.merged += 1;
130
+ await db.query('strapi::core-store').update({
131
+ where: { key: conf.key },
132
+ data: _.merge(existingConf, conf),
133
+ });
134
+ } else {
135
+ stats.created += 1;
136
+ await db.query('strapi::core-store').create({ data: conf });
137
+ }
138
+ },
139
+ };
140
+ };
141
+
142
+ /**
143
+ * Merge importer. Will keep the keys that already exist without changing them and create the new ones
144
+ * @param {Object} db - DatabaseManager instance
145
+ */
146
+ const createKeepImporter = db => {
147
+ const stats = {
148
+ created: 0,
149
+ untouched: 0,
150
+ };
151
+
152
+ return {
153
+ printStatistics() {
154
+ return `${stats.created} created, ${stats.untouched} untouched`;
155
+ },
156
+
157
+ async import(conf) {
158
+ const matching = await db.query('strapi::core-store').count({ where: { key: conf.key } });
159
+ if (matching > 0) {
160
+ stats.untouched += 1;
161
+ // if configuration already exists do not overwrite it
162
+ return;
163
+ }
164
+
165
+ stats.created += 1;
166
+ await db.query('strapi::core-store').create({ data: conf });
167
+ },
168
+ };
169
+ };
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ const REPL = require('repl');
4
+ const strapi = require('../index');
5
+
6
+ /**
7
+ * `$ strapi console`
8
+ */
9
+ module.exports = () => {
10
+ // Now load up the Strapi framework for real.
11
+ const app = strapi();
12
+
13
+ app.start().then(() => {
14
+ const repl = REPL.start(app.config.info.name + ' > ' || 'strapi > '); // eslint-disable-line prefer-template
15
+
16
+ repl.on('exit', function(err) {
17
+ if (err) {
18
+ app.log.error(err);
19
+ process.exit(1);
20
+ }
21
+
22
+ app.server.destroy();
23
+ process.exit(0);
24
+ });
25
+ });
26
+ };
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const cluster = require('cluster');
5
+ const fs = require('fs-extra');
6
+ const chokidar = require('chokidar');
7
+ const execa = require('execa');
8
+ const { getOr } = require('lodash/fp');
9
+
10
+ const { createLogger } = require('@strapi/logger');
11
+ const loadConfiguration = require('../core/app-configuration');
12
+ const strapi = require('../index');
13
+
14
+ /**
15
+ * `$ strapi develop`
16
+ *
17
+ */
18
+ module.exports = async function({ build, watchAdmin, polling, browser }) {
19
+ const dir = process.cwd();
20
+ const config = loadConfiguration(dir);
21
+ const logger = createLogger(config.logger, {});
22
+
23
+ const adminWatchIgnoreFiles = getOr([], 'server.admin.watchIgnoreFiles')(config);
24
+ const serveAdminPanel = getOr(true, 'server.admin.serveAdminPanel')(config);
25
+
26
+ const buildExists = fs.existsSync(path.join(dir, 'build'));
27
+ // Don't run the build process if the admin is in watch mode
28
+ if (build && !watchAdmin && serveAdminPanel && !buildExists) {
29
+ try {
30
+ execa.sync('npm run -s build -- --no-optimization', {
31
+ stdio: 'inherit',
32
+ shell: true,
33
+ });
34
+ } catch (err) {
35
+ process.exit(1);
36
+ }
37
+ }
38
+
39
+ try {
40
+ if (cluster.isMaster) {
41
+ if (watchAdmin) {
42
+ try {
43
+ execa('npm', ['run', '-s', 'strapi', 'watch-admin', '--', '--browser', browser], {
44
+ stdio: 'inherit',
45
+ });
46
+ } catch (err) {
47
+ process.exit(1);
48
+ }
49
+ }
50
+
51
+ cluster.on('message', (worker, message) => {
52
+ switch (message) {
53
+ case 'reload':
54
+ logger.info('The server is restarting\n');
55
+ worker.send('isKilled');
56
+ break;
57
+ case 'kill':
58
+ worker.kill();
59
+ cluster.fork();
60
+ break;
61
+ case 'stop':
62
+ worker.kill();
63
+ process.exit(1);
64
+ default:
65
+ return;
66
+ }
67
+ });
68
+
69
+ cluster.fork();
70
+ }
71
+
72
+ if (cluster.isWorker) {
73
+ const strapiInstance = strapi({
74
+ dir,
75
+ autoReload: true,
76
+ serveAdminPanel: watchAdmin ? false : true,
77
+ });
78
+
79
+ watchFileChanges({
80
+ dir,
81
+ strapiInstance,
82
+ watchIgnoreFiles: adminWatchIgnoreFiles,
83
+ polling,
84
+ });
85
+
86
+ process.on('message', async message => {
87
+ switch (message) {
88
+ case 'isKilled':
89
+ await strapiInstance.server.destroy();
90
+ process.send('kill');
91
+ break;
92
+ default:
93
+ // Do nothing.
94
+ }
95
+ });
96
+
97
+ return strapiInstance.start();
98
+ }
99
+ } catch (e) {
100
+ logger.error(e);
101
+ process.exit(1);
102
+ }
103
+ };
104
+
105
+ /**
106
+ * Init file watching to auto restart strapi app
107
+ * @param {Object} options - Options object
108
+ * @param {string} options.dir - This is the path where the app is located, the watcher will watch the files under this folder
109
+ * @param {Strapi} options.strapi - Strapi instance
110
+ * @param {array} options.watchIgnoreFiles - Array of custom file paths that should not be watched
111
+ */
112
+ function watchFileChanges({ dir, strapiInstance, watchIgnoreFiles, polling }) {
113
+ const restart = () => {
114
+ if (strapiInstance.reload.isWatching && !strapiInstance.reload.isReloading) {
115
+ strapiInstance.reload.isReloading = true;
116
+ strapiInstance.reload();
117
+ }
118
+ };
119
+
120
+ const watcher = chokidar.watch(dir, {
121
+ ignoreInitial: true,
122
+ usePolling: polling,
123
+ ignored: [
124
+ /(^|[/\\])\../, // dot files
125
+ /tmp/,
126
+ '**/admin',
127
+ '**/admin/**',
128
+ 'src/extensions/**/admin',
129
+ 'src/extensions/**/admin/**',
130
+ '**/documentation',
131
+ '**/documentation/**',
132
+ '**/node_modules',
133
+ '**/node_modules/**',
134
+ '**/plugins.json',
135
+ '**/index.html',
136
+ '**/public',
137
+ '**/public/**',
138
+ '**/*.db*',
139
+ '**/exports/**',
140
+ ...watchIgnoreFiles,
141
+ ],
142
+ });
143
+
144
+ watcher
145
+ .on('add', path => {
146
+ strapiInstance.log.info(`File created: ${path}`);
147
+ restart();
148
+ })
149
+ .on('change', path => {
150
+ strapiInstance.log.info(`File changed: ${path}`);
151
+ restart();
152
+ })
153
+ .on('unlink', path => {
154
+ strapiInstance.log.info(`File deleted: ${path}`);
155
+ restart();
156
+ });
157
+ }
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ const { resolve, join, basename } = require('path');
4
+ const fse = require('fs-extra');
5
+ const chalk = require('chalk');
6
+ const inquirer = require('inquirer');
7
+
8
+ // All directories that a template could need
9
+ const TEMPLATE_CONTENT = ['api', 'components', 'config/functions/bootstrap.js', 'data'];
10
+
11
+ /**
12
+ *
13
+ * @param {string} templatePath Absolute path to template directory
14
+ * @param {string} rootBase Name of the root directory
15
+ */
16
+ async function copyContent(templatePath, rootBase) {
17
+ for (const item of TEMPLATE_CONTENT) {
18
+ try {
19
+ const pathToCopy = join(process.cwd(), item);
20
+
21
+ if (!(await fse.pathExists(pathToCopy))) {
22
+ continue;
23
+ }
24
+
25
+ await fse.copy(pathToCopy, join(templatePath, item));
26
+ const currentProjectBase = basename(process.cwd());
27
+ console.log(
28
+ `${chalk.green(
29
+ 'success'
30
+ )}: copy ${currentProjectBase}/${item} => ${rootBase}/template/${item}`
31
+ );
32
+ } catch (error) {
33
+ console.error(`${chalk.red('error')}: ${error.message}`);
34
+ }
35
+ }
36
+ }
37
+
38
+ /**
39
+ *
40
+ * @param {string} rootPath Absolute path to the root directory
41
+ */
42
+ async function writeTemplateJson(rootPath) {
43
+ try {
44
+ await fse.writeJSON(join(rootPath, 'template.json'), {});
45
+ console.log(`${chalk.green('success')}: create JSON config file`);
46
+ } catch (error) {
47
+ console.error(`${chalk.red('error')}: ${error.message}`);
48
+ }
49
+ }
50
+
51
+ /**
52
+ *
53
+ * @param {string} rootPath Absolute path to the root directory
54
+ * @returns boolean
55
+ */
56
+ async function templateConfigExists(rootPath) {
57
+ const jsonConfig = await fse.pathExists(join(rootPath, 'template.json'));
58
+ const functionConfig = await fse.pathExists(join(rootPath, 'template.js'));
59
+
60
+ return jsonConfig || functionConfig;
61
+ }
62
+
63
+ module.exports = async function generateTemplate(directory) {
64
+ const rootPath = resolve(directory);
65
+
66
+ // Get path to template directory: <rootPath>/template
67
+ const templatePath = join(rootPath, 'template');
68
+
69
+ // Check if the template directory exists
70
+ const exists = await fse.pathExists(templatePath);
71
+ const rootBase = basename(rootPath);
72
+
73
+ if (exists) {
74
+ // Confirm the user wants to replace the existing template
75
+ const inquiry = await inquirer.prompt({
76
+ type: 'confirm',
77
+ name: 'confirm',
78
+ message: `${chalk.yellow(rootBase)} already exists. Do you want to replace it?`,
79
+ });
80
+
81
+ if (!inquiry.confirm) {
82
+ process.exit(0);
83
+ }
84
+ }
85
+
86
+ // Create or replace root directory with <roothPath>/template
87
+ await fse.ensureDir(templatePath);
88
+ // Copy content to /template
89
+ await copyContent(templatePath, rootBase);
90
+ // Create config file if it doesn't exist
91
+ const configExists = await templateConfigExists(rootPath);
92
+ if (!configExists) {
93
+ await writeTemplateJson(rootPath);
94
+ }
95
+
96
+ console.log(`${chalk.green('success')}: generated template at ${chalk.yellow(rootPath)}`);
97
+ };
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ const { join } = require('path');
4
+ const { existsSync } = require('fs-extra');
5
+ const ora = require('ora');
6
+ const execa = require('execa');
7
+ const findPackagePath = require('../load/package-path');
8
+
9
+ module.exports = async plugins => {
10
+ const loader = ora();
11
+ const dir = process.cwd();
12
+
13
+ const version = require(join(dir, 'package.json')).dependencies['@strapi/strapi'];
14
+
15
+ const pluginArgs = plugins.map(name => `@strapi/plugin-${name}@${version}`);
16
+
17
+ try {
18
+ loader.start(`Installing dependencies`);
19
+
20
+ const useYarn = existsSync(join(dir, 'yarn.lock'));
21
+ if (useYarn) {
22
+ await execa('yarn', ['add', ...pluginArgs]);
23
+ } else {
24
+ await execa('npm', ['install', '--save', ...pluginArgs]);
25
+ }
26
+
27
+ loader.succeed();
28
+
29
+ // check if rebuild is necessary
30
+ let shouldRebuild = false;
31
+ for (let name of plugins) {
32
+ let pkgPath = findPackagePath(`@strapi/plugin-${name}`);
33
+ if (existsSync(join(pkgPath, 'admin', 'src', 'index.js'))) {
34
+ shouldRebuild = true;
35
+ }
36
+ }
37
+
38
+ if (shouldRebuild) {
39
+ loader.start(`Rebuilding admin UI`);
40
+ await execa('npm', ['run', 'build']);
41
+ loader.succeed();
42
+ }
43
+ } catch (err) {
44
+ loader.clear();
45
+ console.error(err.message);
46
+ process.exit(1);
47
+ }
48
+ };
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * `$ strapi new`
5
+ *
6
+ * Generate a new Strapi application.
7
+ */
8
+
9
+ module.exports = function(...args) {
10
+ return require('@strapi/generate-new')(...args);
11
+ };
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ const strapi = require('../index');
4
+
5
+ /**
6
+ * `$ strapi start`
7
+ */
8
+ module.exports = () => strapi().start();
@@ -0,0 +1,68 @@
1
+ 'use strict';
2
+
3
+ const { join } = require('path');
4
+ const { existsSync, removeSync } = require('fs-extra');
5
+ const ora = require('ora');
6
+ const execa = require('execa');
7
+ const inquirer = require('inquirer');
8
+ const findPackagePath = require('../load/package-path');
9
+
10
+ module.exports = async (plugins, { deleteFiles }) => {
11
+ const answers = await inquirer.prompt([
12
+ {
13
+ type: 'confirm',
14
+ name: 'deleteFiles',
15
+ message: `Do you want to delete the plugin generated files in the extensions folder ?`,
16
+ default: true,
17
+ when: !deleteFiles,
18
+ },
19
+ ]);
20
+
21
+ const loader = ora();
22
+ const dir = process.cwd();
23
+
24
+ const pluginArgs = plugins.map(name => `@strapi/plugin-${name}`);
25
+
26
+ try {
27
+ // verify should rebuild before removing the pacakge
28
+ let shouldRebuild = false;
29
+ for (let name of plugins) {
30
+ let pkgPath = findPackagePath(`@strapi/plugin-${name}`);
31
+ if (existsSync(join(pkgPath, 'admin', 'src', 'index.js'))) {
32
+ shouldRebuild = true;
33
+ }
34
+ }
35
+
36
+ loader.start(`Uninstalling dependencies`);
37
+
38
+ const useYarn = existsSync(join(dir, 'yarn.lock'));
39
+ if (useYarn) {
40
+ await execa('yarn', ['remove', ...pluginArgs]);
41
+ } else {
42
+ await execa('npm', ['remove', ...pluginArgs]);
43
+ }
44
+
45
+ loader.succeed();
46
+
47
+ if (deleteFiles === true || answers.deleteFiles === true) {
48
+ loader.start('Deleting old files');
49
+ for (let name of plugins) {
50
+ const pluginDir = join(dir, 'extensions', name);
51
+ if (existsSync(pluginDir)) {
52
+ removeSync(pluginDir);
53
+ }
54
+ }
55
+ loader.succeed();
56
+ }
57
+
58
+ if (shouldRebuild) {
59
+ loader.start(`Rebuilding admin UI`);
60
+ await execa('npm', ['run', 'build']);
61
+ loader.succeed();
62
+ }
63
+ } catch (err) {
64
+ loader.clear();
65
+ console.error(err.message);
66
+ process.exit(1);
67
+ }
68
+ };
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ const strapiAdmin = require('@strapi/admin');
4
+ const { getConfigUrls, getAbsoluteServerUrl } = require('@strapi/utils');
5
+
6
+ const ee = require('../utils/ee');
7
+ const addSlash = require('../utils/addSlash');
8
+ const strapi = require('../index');
9
+ const getEnabledPlugins = require('../core/loaders/plugins/get-enabled-plugins');
10
+
11
+ module.exports = async function({ browser }) {
12
+ const dir = process.cwd();
13
+
14
+ const strapiInstance = strapi({
15
+ dir,
16
+ autoReload: true,
17
+ serveAdminPanel: false,
18
+ });
19
+
20
+ const plugins = await getEnabledPlugins(strapiInstance);
21
+
22
+ const { adminPath } = getConfigUrls(strapiInstance.config.get('server'), true);
23
+
24
+ const adminPort = strapiInstance.config.get('server.admin.port', 8000);
25
+ const adminHost = strapiInstance.config.get('server.admin.host', 'localhost');
26
+ const adminWatchIgnoreFiles = strapiInstance.config.get('server.admin.watchIgnoreFiles', []);
27
+
28
+ const backendURL = getAbsoluteServerUrl(strapiInstance.config, true);
29
+
30
+ ee({ dir });
31
+
32
+ strapiAdmin.watchAdmin({
33
+ dir,
34
+ plugins,
35
+ port: adminPort,
36
+ host: adminHost,
37
+ browser,
38
+ options: {
39
+ backend: backendURL,
40
+ adminPath: addSlash(adminPath),
41
+ watchIgnoreFiles: adminWatchIgnoreFiles,
42
+ features: ee.isEE ? ee.features.getEnabled() : [],
43
+ },
44
+ });
45
+ };
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ const createContainer = strapi => {
4
+ const registered = new Map();
5
+ const resolved = new Map();
6
+
7
+ return {
8
+ register(name, resolver) {
9
+ if (registered.has(name)) {
10
+ throw new Error(`Cannot register already registered service ${name}`);
11
+ }
12
+
13
+ registered.set(name, resolver);
14
+ return this;
15
+ },
16
+
17
+ get(name, args) {
18
+ // TODO: handle singleton vs reinstanciation everytime
19
+ if (resolved.has(name)) {
20
+ return resolved.get(name);
21
+ }
22
+
23
+ if (registered.has(name)) {
24
+ const resolver = registered.get(name);
25
+
26
+ if (typeof resolver === 'function') {
27
+ resolved.set(name, resolver({ strapi }, args));
28
+ } else {
29
+ resolved.set(name, resolver);
30
+ }
31
+
32
+ return resolved.get(name);
33
+ }
34
+
35
+ throw new Error(`Could not resolve service ${name}`);
36
+ },
37
+
38
+ // TODO: implement
39
+ extend() {},
40
+ };
41
+ };
42
+
43
+ module.exports = {
44
+ createContainer,
45
+ };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const loadFile = require('./load-config-file');
6
+
7
+ module.exports = dir => {
8
+ if (!fs.existsSync(dir)) return {};
9
+
10
+ return fs
11
+ .readdirSync(dir, { withFileTypes: true })
12
+ .filter(file => file.isFile())
13
+ .reduce((acc, file) => {
14
+ const key = path.basename(file.name, path.extname(file.name));
15
+
16
+ acc[key] = loadFile(path.resolve(dir, file.name));
17
+
18
+ return acc;
19
+ }, {});
20
+ };