@akemona-org/strapi 3.7.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 (125) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +163 -0
  3. package/bin/strapi.js +239 -0
  4. package/index.d.ts +13 -0
  5. package/lib/Strapi.js +498 -0
  6. package/lib/commands/admin-reset.js +51 -0
  7. package/lib/commands/build.js +47 -0
  8. package/lib/commands/configurationDump.js +50 -0
  9. package/lib/commands/configurationRestore.js +160 -0
  10. package/lib/commands/console.js +26 -0
  11. package/lib/commands/develop.js +155 -0
  12. package/lib/commands/generate-template.js +97 -0
  13. package/lib/commands/generate.js +66 -0
  14. package/lib/commands/install.js +48 -0
  15. package/lib/commands/new.js +11 -0
  16. package/lib/commands/start.js +8 -0
  17. package/lib/commands/uninstall.js +68 -0
  18. package/lib/commands/watchAdmin.js +35 -0
  19. package/lib/core/app-configuration/config-loader.js +56 -0
  20. package/lib/core/app-configuration/config-provider.js +28 -0
  21. package/lib/core/app-configuration/index.js +99 -0
  22. package/lib/core/bootstrap.js +166 -0
  23. package/lib/core/fs.js +52 -0
  24. package/lib/core/index.js +21 -0
  25. package/lib/core/load-admin.js +36 -0
  26. package/lib/core/load-apis.js +22 -0
  27. package/lib/core/load-components.js +43 -0
  28. package/lib/core/load-extensions.js +71 -0
  29. package/lib/core/load-functions.js +21 -0
  30. package/lib/core/load-hooks.js +117 -0
  31. package/lib/core/load-middlewares.js +130 -0
  32. package/lib/core/load-modules.js +61 -0
  33. package/lib/core/load-plugins.js +68 -0
  34. package/lib/core/load-policies.js +36 -0
  35. package/lib/core/walk.js +27 -0
  36. package/lib/core-api/controller.js +158 -0
  37. package/lib/core-api/index.js +33 -0
  38. package/lib/core-api/service/collection-type.js +122 -0
  39. package/lib/core-api/service/index.js +81 -0
  40. package/lib/core-api/service/single-type.js +68 -0
  41. package/lib/hooks/index.js +97 -0
  42. package/lib/index.js +3 -0
  43. package/lib/load/check-reserved-filename.js +18 -0
  44. package/lib/load/filepath-to-prop-path.js +22 -0
  45. package/lib/load/glob.js +15 -0
  46. package/lib/load/index.js +9 -0
  47. package/lib/load/load-config-files.js +22 -0
  48. package/lib/load/load-files.js +56 -0
  49. package/lib/load/package-path.js +9 -0
  50. package/lib/load/require-file-parse.js +15 -0
  51. package/lib/middlewares/boom/defaults.json +5 -0
  52. package/lib/middlewares/boom/index.js +147 -0
  53. package/lib/middlewares/cors/index.js +66 -0
  54. package/lib/middlewares/cron/defaults.json +5 -0
  55. package/lib/middlewares/cron/index.js +43 -0
  56. package/lib/middlewares/csp/defaults.json +5 -0
  57. package/lib/middlewares/csp/index.js +26 -0
  58. package/lib/middlewares/favicon/defaults.json +7 -0
  59. package/lib/middlewares/favicon/index.js +35 -0
  60. package/lib/middlewares/gzip/defaults.json +6 -0
  61. package/lib/middlewares/gzip/index.js +19 -0
  62. package/lib/middlewares/hsts/defaults.json +7 -0
  63. package/lib/middlewares/hsts/index.js +30 -0
  64. package/lib/middlewares/index.js +120 -0
  65. package/lib/middlewares/ip/defaults.json +7 -0
  66. package/lib/middlewares/ip/index.js +25 -0
  67. package/lib/middlewares/language/defaults.json +9 -0
  68. package/lib/middlewares/language/index.js +40 -0
  69. package/lib/middlewares/logger/defaults.json +8 -0
  70. package/lib/middlewares/logger/index.js +63 -0
  71. package/lib/middlewares/p3p/defaults.json +6 -0
  72. package/lib/middlewares/p3p/index.js +29 -0
  73. package/lib/middlewares/parser/defaults.json +10 -0
  74. package/lib/middlewares/parser/index.js +71 -0
  75. package/lib/middlewares/poweredBy/defaults.json +5 -0
  76. package/lib/middlewares/poweredBy/index.js +16 -0
  77. package/lib/middlewares/public/assets/images/group_people_1.png +0 -0
  78. package/lib/middlewares/public/assets/images/group_people_2.png +0 -0
  79. package/lib/middlewares/public/assets/images/group_people_3.png +0 -0
  80. package/lib/middlewares/public/assets/images/logo_login.png +0 -0
  81. package/lib/middlewares/public/defaults.json +8 -0
  82. package/lib/middlewares/public/index.html +66 -0
  83. package/lib/middlewares/public/index.js +98 -0
  84. package/lib/middlewares/public/serve-static.js +23 -0
  85. package/lib/middlewares/responseTime/defaults.json +5 -0
  86. package/lib/middlewares/responseTime/index.js +25 -0
  87. package/lib/middlewares/responses/defaults.json +5 -0
  88. package/lib/middlewares/responses/index.js +18 -0
  89. package/lib/middlewares/router/defaults.json +7 -0
  90. package/lib/middlewares/router/index.js +64 -0
  91. package/lib/middlewares/router/utils/composeEndpoint.js +25 -0
  92. package/lib/middlewares/router/utils/routerChecker.js +92 -0
  93. package/lib/middlewares/session/defaults.json +18 -0
  94. package/lib/middlewares/session/index.js +140 -0
  95. package/lib/middlewares/xframe/defaults.json +6 -0
  96. package/lib/middlewares/xframe/index.js +33 -0
  97. package/lib/middlewares/xss/defaults.json +6 -0
  98. package/lib/middlewares/xss/index.js +30 -0
  99. package/lib/services/core-store.js +144 -0
  100. package/lib/services/entity-service.js +260 -0
  101. package/lib/services/entity-validator/index.js +199 -0
  102. package/lib/services/entity-validator/validators.js +125 -0
  103. package/lib/services/event-hub.js +15 -0
  104. package/lib/services/metrics/index.js +103 -0
  105. package/lib/services/metrics/is-truthy.js +9 -0
  106. package/lib/services/metrics/middleware.js +33 -0
  107. package/lib/services/metrics/rate-limiter.js +27 -0
  108. package/lib/services/metrics/sender.js +76 -0
  109. package/lib/services/metrics/stringify-deep.js +22 -0
  110. package/lib/services/utils/upload-files.js +70 -0
  111. package/lib/services/webhook-runner.js +159 -0
  112. package/lib/services/webhook-store.js +97 -0
  113. package/lib/services/worker-queue.js +58 -0
  114. package/lib/utils/addSlash.js +10 -0
  115. package/lib/utils/ee.js +123 -0
  116. package/lib/utils/get-prefixed-dependencies.js +7 -0
  117. package/lib/utils/index.js +25 -0
  118. package/lib/utils/openBrowser.js +145 -0
  119. package/lib/utils/resources/key.pub +9 -0
  120. package/lib/utils/resources/openChrome.applescript +83 -0
  121. package/lib/utils/run-checks.js +37 -0
  122. package/lib/utils/success.js +31 -0
  123. package/lib/utils/update-notifier/index.js +96 -0
  124. package/lib/utils/url-from-segments.js +13 -0
  125. package/package.json +143 -0
@@ -0,0 +1,160 @@
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('core_store').count({ key: conf.key });
94
+ if (matching > 0) {
95
+ stats.replaced += 1;
96
+ await db.query('core_store').update({ key: conf.key }, conf);
97
+ } else {
98
+ stats.created += 1;
99
+ await db.query('core_store').create(conf);
100
+ }
101
+ },
102
+ };
103
+ };
104
+
105
+ /**
106
+ * Merge importer. Will merge the keys that already exist with their new value and create the new ones
107
+ * @param {Object} db - DatabaseManager instance
108
+ */
109
+ const createMergeImporter = db => {
110
+ const stats = {
111
+ created: 0,
112
+ merged: 0,
113
+ };
114
+
115
+ return {
116
+ printStatistics() {
117
+ return `${stats.created} created, ${stats.merged} merged`;
118
+ },
119
+
120
+ async import(conf) {
121
+ const existingConf = await db.query('core_store').find({ key: conf.key });
122
+ if (existingConf) {
123
+ stats.merged += 1;
124
+ await db.query('core_store').update({ key: conf.key }, _.merge(existingConf, conf));
125
+ } else {
126
+ stats.created += 1;
127
+ await db.query('core_store').create(conf);
128
+ }
129
+ },
130
+ };
131
+ };
132
+
133
+ /**
134
+ * Merge importer. Will keep the keys that already exist without changing them and create the new ones
135
+ * @param {Object} db - DatabaseManager instance
136
+ */
137
+ const createKeepImporter = db => {
138
+ const stats = {
139
+ created: 0,
140
+ untouched: 0,
141
+ };
142
+
143
+ return {
144
+ printStatistics() {
145
+ return `${stats.created} created, ${stats.untouched} untouched`;
146
+ },
147
+
148
+ async import(conf) {
149
+ const matching = await db.query('core_store').count({ key: conf.key });
150
+ if (matching > 0) {
151
+ stats.untouched += 1;
152
+ // if configuration already exists do not overwrite it
153
+ return;
154
+ }
155
+
156
+ stats.created += 1;
157
+ await db.query('core_store').create(conf);
158
+ },
159
+ };
160
+ };
@@ -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(() => {
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,155 @@
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
+
9
+ const { logger } = require('@akemona-org/strapi-utils');
10
+ const loadConfiguration = require('../core/app-configuration');
11
+ const strapi = require('../index');
12
+
13
+ /**
14
+ * `$ strapi develop`
15
+ *
16
+ */
17
+ module.exports = async function ({ build, watchAdmin, polling, browser }) {
18
+ const dir = process.cwd();
19
+ const config = loadConfiguration(dir);
20
+
21
+ const adminWatchIgnoreFiles = config.get('server.admin.watchIgnoreFiles', []);
22
+ const serveAdminPanel = config.get('server.admin.serveAdminPanel', true);
23
+
24
+ const buildExists = fs.existsSync(path.join(dir, 'build'));
25
+ // Don't run the build process if the admin is in watch mode
26
+ if (build && !watchAdmin && serveAdminPanel && !buildExists) {
27
+ try {
28
+ execa.shellSync('npm run -s build -- --no-optimization', {
29
+ stdio: 'inherit',
30
+ });
31
+ } catch (err) {
32
+ process.exit(1);
33
+ }
34
+ }
35
+
36
+ try {
37
+ if (cluster.isMaster) {
38
+ if (watchAdmin) {
39
+ try {
40
+ execa('npm', ['run', '-s', 'strapi', 'watch-admin', '--', '--browser', browser], {
41
+ stdio: 'inherit',
42
+ });
43
+ } catch (err) {
44
+ process.exit(1);
45
+ }
46
+ }
47
+
48
+ cluster.on('message', (worker, message) => {
49
+ switch (message) {
50
+ case 'reload':
51
+ logger.info('The server is restarting\n');
52
+ worker.send('isKilled');
53
+ break;
54
+ case 'kill':
55
+ worker.kill();
56
+ cluster.fork();
57
+ break;
58
+ case 'stop':
59
+ worker.kill();
60
+ process.exit(1);
61
+ default:
62
+ return;
63
+ }
64
+ });
65
+
66
+ cluster.fork();
67
+ }
68
+
69
+ if (cluster.isWorker) {
70
+ const strapiInstance = strapi({
71
+ dir,
72
+ autoReload: true,
73
+ serveAdminPanel: watchAdmin ? false : true,
74
+ });
75
+
76
+ watchFileChanges({
77
+ dir,
78
+ strapiInstance,
79
+ watchIgnoreFiles: adminWatchIgnoreFiles,
80
+ polling,
81
+ });
82
+
83
+ process.on('message', (message) => {
84
+ switch (message) {
85
+ case 'isKilled':
86
+ strapiInstance.server.destroy(() => {
87
+ process.send('kill');
88
+ });
89
+ break;
90
+ default:
91
+ // Do nothing.
92
+ }
93
+ });
94
+
95
+ return strapiInstance.start();
96
+ }
97
+ } catch (e) {
98
+ logger.error(e);
99
+ process.exit(1);
100
+ }
101
+ };
102
+
103
+ /**
104
+ * Init file watching to auto restart strapi app
105
+ * @param {Object} options - Options object
106
+ * @param {string} options.dir - This is the path where the app is located, the watcher will watch the files under this folder
107
+ * @param {Strapi} options.strapi - Strapi instance
108
+ * @param {array} options.watchIgnoreFiles - Array of custom file paths that should not be watched
109
+ */
110
+ function watchFileChanges({ dir, strapiInstance, watchIgnoreFiles, polling }) {
111
+ const restart = () => {
112
+ if (strapiInstance.reload.isWatching && !strapiInstance.reload.isReloading) {
113
+ strapiInstance.reload.isReloading = true;
114
+ strapiInstance.reload();
115
+ }
116
+ };
117
+
118
+ const watcher = chokidar.watch(dir, {
119
+ ignoreInitial: true,
120
+ usePolling: polling,
121
+ ignored: [
122
+ /(^|[/\\])\../, // dot files
123
+ /tmp/,
124
+ 'admin',
125
+ 'admin/**',
126
+ 'extensions/**/admin',
127
+ 'extensions/**/admin/**',
128
+ '**/documentation',
129
+ '**/documentation/**',
130
+ '**/node_modules',
131
+ '**/node_modules/**',
132
+ '**/plugins.json',
133
+ '**/index.html',
134
+ '**/public',
135
+ '**/public/**',
136
+ '**/*.db*',
137
+ '**/exports/**',
138
+ ...watchIgnoreFiles,
139
+ ],
140
+ });
141
+
142
+ watcher
143
+ .on('add', (path) => {
144
+ strapiInstance.log.info(`File created: ${path}`);
145
+ restart();
146
+ })
147
+ .on('change', (path) => {
148
+ strapiInstance.log.info(`File changed: ${path}`);
149
+ restart();
150
+ })
151
+ .on('unlink', (path) => {
152
+ strapiInstance.log.info(`File deleted: ${path}`);
153
+ restart();
154
+ });
155
+ }
@@ -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,66 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Node.js core.
8
+ const path = require('path');
9
+
10
+ // Master of ceremonies for generators.
11
+ const generate = require('@akemona-org/strapi-generate');
12
+
13
+ // Logger.
14
+ const { logger } = require('@akemona-org/strapi-utils');
15
+
16
+ // Local Strapi dependencies.
17
+ const packageJSON = require('../../package.json');
18
+
19
+ /**
20
+ * `$ strapi generate`
21
+ *
22
+ * Scaffolding for the application in our working directory.
23
+ */
24
+
25
+ module.exports = function (id, cliArguments) {
26
+ // Build initial scope.
27
+ const scope = {
28
+ rootPath: process.cwd(),
29
+ strapiRoot: path.resolve(__dirname, '..'),
30
+ id: id,
31
+ args: cliArguments,
32
+ strapiPackageJSON: packageJSON,
33
+ };
34
+
35
+ scope.generatorType = process.argv[2].split(':')[1];
36
+
37
+ // Show usage if no generator type is defined.
38
+ if (!scope.generatorType) {
39
+ return logger.error('Write `$ strapi generate:something` instead.');
40
+ }
41
+
42
+ return generate(scope, {
43
+ // Log and exit the REPL in case there is an error
44
+ // while we were trying to generate the requested generator.
45
+ error(msg) {
46
+ logger.error(msg);
47
+ process.exit(1);
48
+ },
49
+
50
+ // Log and exit the REPL in case of success
51
+ // but first make sure we have all the info we need.
52
+ success() {
53
+ if (!scope.outputPath && scope.filename && scope.destDir) {
54
+ scope.outputPath = scope.destDir + scope.filename;
55
+ }
56
+
57
+ if (scope.generatorType !== 'new') {
58
+ logger.info(
59
+ `Generated a new ${scope.generatorType} \`${scope.name}\` at \`${scope.filePath}\`.`
60
+ );
61
+ }
62
+
63
+ process.exit(0);
64
+ },
65
+ });
66
+ };
@@ -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;
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('@akemona-org/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,35 @@
1
+ 'use strict';
2
+
3
+ // eslint-disable-next-line node/no-extraneous-require
4
+ const strapiAdmin = require('@akemona-org/strapi-admin');
5
+ const { getConfigUrls, getAbsoluteServerUrl } = require('@akemona-org/strapi-utils');
6
+ const loadConfiguration = require('../core/app-configuration');
7
+ const ee = require('../utils/ee');
8
+ const addSlash = require('../utils/addSlash');
9
+
10
+ module.exports = async function ({ browser }) {
11
+ const dir = process.cwd();
12
+
13
+ const config = loadConfiguration(dir);
14
+
15
+ const { adminPath } = getConfigUrls(config.get('server'), true);
16
+
17
+ const adminPort = config.get('server.admin.port', 8000);
18
+ const adminHost = config.get('server.admin.host', 'localhost');
19
+ const adminWatchIgnoreFiles = config.get('server.admin.watchIgnoreFiles', []);
20
+
21
+ ee({ dir });
22
+
23
+ strapiAdmin.watchAdmin({
24
+ dir,
25
+ port: adminPort,
26
+ host: adminHost,
27
+ browser,
28
+ options: {
29
+ backend: getAbsoluteServerUrl(config, true),
30
+ publicPath: addSlash(adminPath),
31
+ watchIgnoreFiles: adminWatchIgnoreFiles,
32
+ features: ee.isEE ? ee.features.getEnabled() : [],
33
+ },
34
+ });
35
+ };