@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.
- package/LICENSE +22 -0
- package/README.md +163 -0
- package/bin/strapi.js +239 -0
- package/index.d.ts +13 -0
- package/lib/Strapi.js +498 -0
- package/lib/commands/admin-reset.js +51 -0
- package/lib/commands/build.js +47 -0
- package/lib/commands/configurationDump.js +50 -0
- package/lib/commands/configurationRestore.js +160 -0
- package/lib/commands/console.js +26 -0
- package/lib/commands/develop.js +155 -0
- package/lib/commands/generate-template.js +97 -0
- package/lib/commands/generate.js +66 -0
- package/lib/commands/install.js +48 -0
- package/lib/commands/new.js +11 -0
- package/lib/commands/start.js +8 -0
- package/lib/commands/uninstall.js +68 -0
- package/lib/commands/watchAdmin.js +35 -0
- package/lib/core/app-configuration/config-loader.js +56 -0
- package/lib/core/app-configuration/config-provider.js +28 -0
- package/lib/core/app-configuration/index.js +99 -0
- package/lib/core/bootstrap.js +166 -0
- package/lib/core/fs.js +52 -0
- package/lib/core/index.js +21 -0
- package/lib/core/load-admin.js +36 -0
- package/lib/core/load-apis.js +22 -0
- package/lib/core/load-components.js +43 -0
- package/lib/core/load-extensions.js +71 -0
- package/lib/core/load-functions.js +21 -0
- package/lib/core/load-hooks.js +117 -0
- package/lib/core/load-middlewares.js +130 -0
- package/lib/core/load-modules.js +61 -0
- package/lib/core/load-plugins.js +68 -0
- package/lib/core/load-policies.js +36 -0
- package/lib/core/walk.js +27 -0
- package/lib/core-api/controller.js +158 -0
- package/lib/core-api/index.js +33 -0
- package/lib/core-api/service/collection-type.js +122 -0
- package/lib/core-api/service/index.js +81 -0
- package/lib/core-api/service/single-type.js +68 -0
- package/lib/hooks/index.js +97 -0
- package/lib/index.js +3 -0
- package/lib/load/check-reserved-filename.js +18 -0
- package/lib/load/filepath-to-prop-path.js +22 -0
- package/lib/load/glob.js +15 -0
- package/lib/load/index.js +9 -0
- package/lib/load/load-config-files.js +22 -0
- package/lib/load/load-files.js +56 -0
- package/lib/load/package-path.js +9 -0
- package/lib/load/require-file-parse.js +15 -0
- package/lib/middlewares/boom/defaults.json +5 -0
- package/lib/middlewares/boom/index.js +147 -0
- package/lib/middlewares/cors/index.js +66 -0
- package/lib/middlewares/cron/defaults.json +5 -0
- package/lib/middlewares/cron/index.js +43 -0
- package/lib/middlewares/csp/defaults.json +5 -0
- package/lib/middlewares/csp/index.js +26 -0
- package/lib/middlewares/favicon/defaults.json +7 -0
- package/lib/middlewares/favicon/index.js +35 -0
- package/lib/middlewares/gzip/defaults.json +6 -0
- package/lib/middlewares/gzip/index.js +19 -0
- package/lib/middlewares/hsts/defaults.json +7 -0
- package/lib/middlewares/hsts/index.js +30 -0
- package/lib/middlewares/index.js +120 -0
- package/lib/middlewares/ip/defaults.json +7 -0
- package/lib/middlewares/ip/index.js +25 -0
- package/lib/middlewares/language/defaults.json +9 -0
- package/lib/middlewares/language/index.js +40 -0
- package/lib/middlewares/logger/defaults.json +8 -0
- package/lib/middlewares/logger/index.js +63 -0
- package/lib/middlewares/p3p/defaults.json +6 -0
- package/lib/middlewares/p3p/index.js +29 -0
- package/lib/middlewares/parser/defaults.json +10 -0
- package/lib/middlewares/parser/index.js +71 -0
- package/lib/middlewares/poweredBy/defaults.json +5 -0
- package/lib/middlewares/poweredBy/index.js +16 -0
- package/lib/middlewares/public/assets/images/group_people_1.png +0 -0
- package/lib/middlewares/public/assets/images/group_people_2.png +0 -0
- package/lib/middlewares/public/assets/images/group_people_3.png +0 -0
- package/lib/middlewares/public/assets/images/logo_login.png +0 -0
- package/lib/middlewares/public/defaults.json +8 -0
- package/lib/middlewares/public/index.html +66 -0
- package/lib/middlewares/public/index.js +98 -0
- package/lib/middlewares/public/serve-static.js +23 -0
- package/lib/middlewares/responseTime/defaults.json +5 -0
- package/lib/middlewares/responseTime/index.js +25 -0
- package/lib/middlewares/responses/defaults.json +5 -0
- package/lib/middlewares/responses/index.js +18 -0
- package/lib/middlewares/router/defaults.json +7 -0
- package/lib/middlewares/router/index.js +64 -0
- package/lib/middlewares/router/utils/composeEndpoint.js +25 -0
- package/lib/middlewares/router/utils/routerChecker.js +92 -0
- package/lib/middlewares/session/defaults.json +18 -0
- package/lib/middlewares/session/index.js +140 -0
- package/lib/middlewares/xframe/defaults.json +6 -0
- package/lib/middlewares/xframe/index.js +33 -0
- package/lib/middlewares/xss/defaults.json +6 -0
- package/lib/middlewares/xss/index.js +30 -0
- package/lib/services/core-store.js +144 -0
- package/lib/services/entity-service.js +260 -0
- package/lib/services/entity-validator/index.js +199 -0
- package/lib/services/entity-validator/validators.js +125 -0
- package/lib/services/event-hub.js +15 -0
- package/lib/services/metrics/index.js +103 -0
- package/lib/services/metrics/is-truthy.js +9 -0
- package/lib/services/metrics/middleware.js +33 -0
- package/lib/services/metrics/rate-limiter.js +27 -0
- package/lib/services/metrics/sender.js +76 -0
- package/lib/services/metrics/stringify-deep.js +22 -0
- package/lib/services/utils/upload-files.js +70 -0
- package/lib/services/webhook-runner.js +159 -0
- package/lib/services/webhook-store.js +97 -0
- package/lib/services/worker-queue.js +58 -0
- package/lib/utils/addSlash.js +10 -0
- package/lib/utils/ee.js +123 -0
- package/lib/utils/get-prefixed-dependencies.js +7 -0
- package/lib/utils/index.js +25 -0
- package/lib/utils/openBrowser.js +145 -0
- package/lib/utils/resources/key.pub +9 -0
- package/lib/utils/resources/openChrome.applescript +83 -0
- package/lib/utils/run-checks.js +37 -0
- package/lib/utils/success.js +31 -0
- package/lib/utils/update-notifier/index.js +96 -0
- package/lib/utils/url-from-segments.js +13 -0
- package/package.json +143 -0
package/lib/Strapi.js
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const http = require('http');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fse = require('fs-extra');
|
|
6
|
+
const Koa = require('koa');
|
|
7
|
+
const Router = require('koa-router');
|
|
8
|
+
const _ = require('lodash');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const CLITable = require('cli-table3');
|
|
11
|
+
const {
|
|
12
|
+
logger,
|
|
13
|
+
models,
|
|
14
|
+
getAbsoluteAdminUrl,
|
|
15
|
+
getAbsoluteServerUrl,
|
|
16
|
+
} = require('@akemona-org/strapi-utils');
|
|
17
|
+
const { createDatabaseManager } = require('@akemona-org/strapi-database');
|
|
18
|
+
const loadConfiguration = require('./core/app-configuration');
|
|
19
|
+
|
|
20
|
+
const utils = require('./utils');
|
|
21
|
+
const loadModules = require('./core/load-modules');
|
|
22
|
+
const bootstrap = require('./core/bootstrap');
|
|
23
|
+
const initializeMiddlewares = require('./middlewares');
|
|
24
|
+
const initializeHooks = require('./hooks');
|
|
25
|
+
const createStrapiFs = require('./core/fs');
|
|
26
|
+
const createEventHub = require('./services/event-hub');
|
|
27
|
+
const createWebhookRunner = require('./services/webhook-runner');
|
|
28
|
+
const { webhookModel, createWebhookStore } = require('./services/webhook-store');
|
|
29
|
+
const { createCoreStore, coreStoreModel } = require('./services/core-store');
|
|
30
|
+
const createEntityService = require('./services/entity-service');
|
|
31
|
+
const entityValidator = require('./services/entity-validator');
|
|
32
|
+
// const createTelemetry = require('./services/metrics');
|
|
33
|
+
const createUpdateNotifier = require('./utils/update-notifier');
|
|
34
|
+
const ee = require('./utils/ee');
|
|
35
|
+
|
|
36
|
+
const LIFECYCLES = {
|
|
37
|
+
REGISTER: 'register',
|
|
38
|
+
BOOTSTRAP: 'bootstrap',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Construct an Strapi instance.
|
|
43
|
+
*
|
|
44
|
+
* @constructor
|
|
45
|
+
*/
|
|
46
|
+
class Strapi {
|
|
47
|
+
constructor(opts = {}) {
|
|
48
|
+
this.reload = this.reload();
|
|
49
|
+
|
|
50
|
+
// Expose `koa`.
|
|
51
|
+
this.app = new Koa();
|
|
52
|
+
this.router = new Router();
|
|
53
|
+
|
|
54
|
+
this.initServer();
|
|
55
|
+
|
|
56
|
+
// Logger.
|
|
57
|
+
this.log = logger;
|
|
58
|
+
|
|
59
|
+
// Utils.
|
|
60
|
+
this.utils = {
|
|
61
|
+
models,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
this.dir = opts.dir || process.cwd();
|
|
65
|
+
|
|
66
|
+
this.admin = {};
|
|
67
|
+
this.plugins = {};
|
|
68
|
+
this.config = loadConfiguration(this.dir, opts);
|
|
69
|
+
this.app.proxy = this.config.get('server.proxy');
|
|
70
|
+
|
|
71
|
+
this.isLoaded = false;
|
|
72
|
+
|
|
73
|
+
// internal services.
|
|
74
|
+
this.fs = createStrapiFs(this);
|
|
75
|
+
this.eventHub = createEventHub();
|
|
76
|
+
|
|
77
|
+
this.requireProjectBootstrap();
|
|
78
|
+
|
|
79
|
+
createUpdateNotifier(this).notify();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get EE() {
|
|
83
|
+
return ee({ dir: this.dir, logger });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
handleRequest(req, res) {
|
|
87
|
+
if (!this.requestHandler) {
|
|
88
|
+
this.requestHandler = this.app.callback();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return this.requestHandler(req, res);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
requireProjectBootstrap() {
|
|
95
|
+
const bootstrapPath = path.resolve(this.dir, 'config/functions/bootstrap.js');
|
|
96
|
+
|
|
97
|
+
if (fse.existsSync(bootstrapPath)) {
|
|
98
|
+
require(bootstrapPath);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
logStats() {
|
|
103
|
+
const columns = Math.min(process.stderr.columns, 80) - 2;
|
|
104
|
+
console.log();
|
|
105
|
+
console.log(chalk.black.bgWhite(_.padEnd(' Project information', columns)));
|
|
106
|
+
console.log();
|
|
107
|
+
|
|
108
|
+
const infoTable = new CLITable({
|
|
109
|
+
colWidths: [20, 50],
|
|
110
|
+
chars: { mid: '', 'left-mid': '', 'mid-mid': '', 'right-mid': '' },
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const isEE = strapi.EE === true && ee.isEE === true;
|
|
114
|
+
|
|
115
|
+
infoTable.push(
|
|
116
|
+
[chalk.blue('Time'), `${new Date()}`],
|
|
117
|
+
[chalk.blue('Launched in'), Date.now() - this.config.launchedAt + ' ms'],
|
|
118
|
+
[chalk.blue('Environment'), this.config.environment],
|
|
119
|
+
[chalk.blue('Process PID'), process.pid],
|
|
120
|
+
[chalk.blue('Version'), `${this.config.info.strapi} (node ${process.version})`],
|
|
121
|
+
[chalk.blue('Edition'), isEE ? 'Enterprise' : 'Community']
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
console.log(infoTable.toString());
|
|
125
|
+
console.log();
|
|
126
|
+
console.log(chalk.black.bgWhite(_.padEnd(' Actions available', columns)));
|
|
127
|
+
console.log();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
logFirstStartupMessage() {
|
|
131
|
+
this.logStats();
|
|
132
|
+
|
|
133
|
+
console.log(chalk.bold('One more thing...'));
|
|
134
|
+
console.log(
|
|
135
|
+
chalk.grey('Create your first administrator 💻 by going to the administration panel at:')
|
|
136
|
+
);
|
|
137
|
+
console.log();
|
|
138
|
+
|
|
139
|
+
const addressTable = new CLITable();
|
|
140
|
+
|
|
141
|
+
const adminUrl = getAbsoluteAdminUrl(strapi.config);
|
|
142
|
+
addressTable.push([chalk.bold(adminUrl)]);
|
|
143
|
+
|
|
144
|
+
console.log(`${addressTable.toString()}`);
|
|
145
|
+
console.log();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
logStartupMessage() {
|
|
149
|
+
this.logStats();
|
|
150
|
+
|
|
151
|
+
console.log(chalk.bold('Welcome back!'));
|
|
152
|
+
|
|
153
|
+
if (this.config.serveAdminPanel === true) {
|
|
154
|
+
console.log(chalk.grey('To manage your project 🚀, go to the administration panel at:'));
|
|
155
|
+
const adminUrl = getAbsoluteAdminUrl(strapi.config);
|
|
156
|
+
console.log(chalk.bold(adminUrl));
|
|
157
|
+
console.log();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log(chalk.grey('To access the server ⚡️, go to:'));
|
|
161
|
+
const serverUrl = getAbsoluteServerUrl(strapi.config);
|
|
162
|
+
console.log(chalk.bold(serverUrl));
|
|
163
|
+
console.log();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
initServer() {
|
|
167
|
+
this.server = http.createServer(this.handleRequest.bind(this));
|
|
168
|
+
// handle port in use cleanly
|
|
169
|
+
this.server.on('error', (err) => {
|
|
170
|
+
if (err.code === 'EADDRINUSE') {
|
|
171
|
+
return this.stopWithError(`The port ${err.port} is already used by another application.`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.log.error(err);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Close current connections to fully destroy the server
|
|
178
|
+
const connections = {};
|
|
179
|
+
|
|
180
|
+
this.server.on('connection', (conn) => {
|
|
181
|
+
const key = conn.remoteAddress + ':' + conn.remotePort;
|
|
182
|
+
connections[key] = conn;
|
|
183
|
+
|
|
184
|
+
conn.on('close', function () {
|
|
185
|
+
delete connections[key];
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
this.server.destroy = (cb) => {
|
|
190
|
+
this.server.close(cb);
|
|
191
|
+
|
|
192
|
+
for (let key in connections) {
|
|
193
|
+
connections[key].destroy();
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async start(cb) {
|
|
199
|
+
try {
|
|
200
|
+
if (!this.isLoaded) {
|
|
201
|
+
await this.load();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
this.app.use(this.router.routes()).use(this.router.allowedMethods());
|
|
205
|
+
|
|
206
|
+
// Launch server.
|
|
207
|
+
this.listen(cb);
|
|
208
|
+
} catch (err) {
|
|
209
|
+
this.stopWithError(err);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async destroy() {
|
|
214
|
+
if (_.has(this, 'server.destroy')) {
|
|
215
|
+
await new Promise((res) => this.server.destroy(res));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
await Promise.all(
|
|
219
|
+
Object.values(this.plugins).map((plugin) => {
|
|
220
|
+
if (_.has(plugin, 'destroy') && typeof plugin.destroy === 'function') {
|
|
221
|
+
return plugin.destroy();
|
|
222
|
+
}
|
|
223
|
+
})
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
if (_.has(this, 'admin')) {
|
|
227
|
+
await this.admin.destroy();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
this.eventHub.removeAllListeners();
|
|
231
|
+
|
|
232
|
+
if (_.has(this, 'db')) {
|
|
233
|
+
await this.db.destroy();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// this.telemetry.destroy();
|
|
237
|
+
|
|
238
|
+
delete global.strapi;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Add behaviors to the server
|
|
243
|
+
*/
|
|
244
|
+
async listen(cb) {
|
|
245
|
+
const onListen = async (err) => {
|
|
246
|
+
if (err) return this.stopWithError(err);
|
|
247
|
+
|
|
248
|
+
// Is the project initialised?
|
|
249
|
+
const isInitialised = await utils.isInitialised(this);
|
|
250
|
+
|
|
251
|
+
// Should the startup message be displayed?
|
|
252
|
+
const hideStartupMessage = process.env.STRAPI_HIDE_STARTUP_MESSAGE
|
|
253
|
+
? process.env.STRAPI_HIDE_STARTUP_MESSAGE === 'true'
|
|
254
|
+
: false;
|
|
255
|
+
|
|
256
|
+
if (hideStartupMessage === false) {
|
|
257
|
+
if (!isInitialised) {
|
|
258
|
+
this.logFirstStartupMessage();
|
|
259
|
+
} else {
|
|
260
|
+
this.logStartupMessage();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Get database clients
|
|
265
|
+
// const databaseClients = _.map(this.config.get('connections'), _.property('settings.client'));
|
|
266
|
+
|
|
267
|
+
// Emit started event.
|
|
268
|
+
// await this.telemetry.send('didStartServer', {
|
|
269
|
+
// database: databaseClients,
|
|
270
|
+
// plugins: this.config.installedPlugins,
|
|
271
|
+
// providers: this.config.installedProviders,
|
|
272
|
+
// });
|
|
273
|
+
|
|
274
|
+
if (cb && typeof cb === 'function') {
|
|
275
|
+
cb();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (
|
|
279
|
+
(this.config.environment === 'development' &&
|
|
280
|
+
this.config.get('server.admin.autoOpen', true) !== false) ||
|
|
281
|
+
!isInitialised
|
|
282
|
+
) {
|
|
283
|
+
await utils.openBrowser.call(this);
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const listenSocket = this.config.get('server.socket');
|
|
288
|
+
const listenErrHandler = (err) => onListen(err).catch((err) => this.stopWithError(err));
|
|
289
|
+
|
|
290
|
+
if (listenSocket) {
|
|
291
|
+
this.server.listen(listenSocket, listenErrHandler);
|
|
292
|
+
} else {
|
|
293
|
+
this.server.listen(
|
|
294
|
+
this.config.get('server.port'),
|
|
295
|
+
this.config.get('server.host'),
|
|
296
|
+
listenErrHandler
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
stopWithError(err, customMessage) {
|
|
302
|
+
this.log.debug(`⛔️ Server wasn't able to start properly.`);
|
|
303
|
+
if (customMessage) {
|
|
304
|
+
this.log.error(customMessage);
|
|
305
|
+
}
|
|
306
|
+
this.log.error(err);
|
|
307
|
+
return this.stop();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
stop(exitCode = 1) {
|
|
311
|
+
// Destroy server and available connections.
|
|
312
|
+
if (_.has(this, 'server.destroy')) {
|
|
313
|
+
this.server.destroy();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (this.config.autoReload) {
|
|
317
|
+
process.send('stop');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Kill process
|
|
321
|
+
process.exit(exitCode);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async load() {
|
|
325
|
+
this.app.use(async (ctx, next) => {
|
|
326
|
+
if (ctx.request.url === '/_health' && ['HEAD', 'GET'].includes(ctx.request.method)) {
|
|
327
|
+
ctx.set('strapi', 'You are so French!');
|
|
328
|
+
ctx.status = 204;
|
|
329
|
+
} else {
|
|
330
|
+
await next();
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const modules = await loadModules(this);
|
|
335
|
+
|
|
336
|
+
this.api = modules.api;
|
|
337
|
+
this.admin = modules.admin;
|
|
338
|
+
this.components = modules.components;
|
|
339
|
+
this.plugins = modules.plugins;
|
|
340
|
+
this.middleware = modules.middlewares;
|
|
341
|
+
this.hook = modules.hook;
|
|
342
|
+
|
|
343
|
+
await bootstrap(this);
|
|
344
|
+
|
|
345
|
+
// init webhook runner
|
|
346
|
+
this.webhookRunner = createWebhookRunner({
|
|
347
|
+
eventHub: this.eventHub,
|
|
348
|
+
logger: this.log,
|
|
349
|
+
configuration: this.config.get('server.webhooks', {}),
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// Init core store
|
|
353
|
+
this.models['core_store'] = coreStoreModel(this.config);
|
|
354
|
+
this.models['strapi_webhooks'] = webhookModel(this.config);
|
|
355
|
+
|
|
356
|
+
this.db = createDatabaseManager(this);
|
|
357
|
+
|
|
358
|
+
await this.runLifecyclesFunctions(LIFECYCLES.REGISTER);
|
|
359
|
+
await this.db.initialize();
|
|
360
|
+
|
|
361
|
+
this.store = createCoreStore({
|
|
362
|
+
environment: this.config.environment,
|
|
363
|
+
db: this.db,
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
this.webhookStore = createWebhookStore({ db: this.db });
|
|
367
|
+
|
|
368
|
+
await this.startWebhooks();
|
|
369
|
+
|
|
370
|
+
this.entityValidator = entityValidator;
|
|
371
|
+
|
|
372
|
+
this.entityService = createEntityService({
|
|
373
|
+
db: this.db,
|
|
374
|
+
eventHub: this.eventHub,
|
|
375
|
+
entityValidator: this.entityValidator,
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// this.telemetry = createTelemetry(this);
|
|
379
|
+
|
|
380
|
+
// Initialize hooks and middlewares.
|
|
381
|
+
await initializeMiddlewares.call(this);
|
|
382
|
+
await initializeHooks.call(this);
|
|
383
|
+
|
|
384
|
+
await this.runLifecyclesFunctions(LIFECYCLES.BOOTSTRAP);
|
|
385
|
+
await this.freeze();
|
|
386
|
+
|
|
387
|
+
this.isLoaded = true;
|
|
388
|
+
return this;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async startWebhooks() {
|
|
392
|
+
const webhooks = await this.webhookStore.findWebhooks();
|
|
393
|
+
webhooks.forEach((webhook) => this.webhookRunner.add(webhook));
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
reload() {
|
|
397
|
+
const state = {
|
|
398
|
+
shouldReload: 0,
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
const reload = function () {
|
|
402
|
+
if (state.shouldReload > 0) {
|
|
403
|
+
// Reset the reloading state
|
|
404
|
+
state.shouldReload -= 1;
|
|
405
|
+
reload.isReloading = false;
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (this.config.autoReload) {
|
|
410
|
+
this.server.close();
|
|
411
|
+
process.send('reload');
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
Object.defineProperty(reload, 'isWatching', {
|
|
416
|
+
configurable: true,
|
|
417
|
+
enumerable: true,
|
|
418
|
+
set: (value) => {
|
|
419
|
+
// Special state when the reloader is disabled temporarly (see GraphQL plugin example).
|
|
420
|
+
if (state.isWatching === false && value === true) {
|
|
421
|
+
state.shouldReload += 1;
|
|
422
|
+
}
|
|
423
|
+
state.isWatching = value;
|
|
424
|
+
},
|
|
425
|
+
get: () => {
|
|
426
|
+
return state.isWatching;
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
reload.isReloading = false;
|
|
431
|
+
reload.isWatching = true;
|
|
432
|
+
|
|
433
|
+
return reload;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async runLifecyclesFunctions(lifecycleName) {
|
|
437
|
+
const execLifecycle = async (fn) => {
|
|
438
|
+
if (!fn) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return fn();
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
const configPath = `functions.${lifecycleName}`;
|
|
446
|
+
|
|
447
|
+
// plugins
|
|
448
|
+
await Promise.all(
|
|
449
|
+
Object.keys(this.plugins).map((plugin) => {
|
|
450
|
+
const pluginFunc = _.get(this.plugins[plugin], `config.${configPath}`);
|
|
451
|
+
|
|
452
|
+
return execLifecycle(pluginFunc).catch((err) => {
|
|
453
|
+
strapi.log.error(`${lifecycleName} function in plugin "${plugin}" failed`);
|
|
454
|
+
strapi.log.error(err);
|
|
455
|
+
strapi.stop();
|
|
456
|
+
});
|
|
457
|
+
})
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
// user
|
|
461
|
+
await execLifecycle(_.get(this.config, configPath));
|
|
462
|
+
|
|
463
|
+
// admin
|
|
464
|
+
const adminFunc = _.get(this.admin.config, configPath);
|
|
465
|
+
return execLifecycle(adminFunc).catch((err) => {
|
|
466
|
+
strapi.log.error(`${lifecycleName} function in admin failed`);
|
|
467
|
+
strapi.log.error(err);
|
|
468
|
+
strapi.stop();
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
async freeze() {
|
|
473
|
+
Object.freeze(this.config);
|
|
474
|
+
Object.freeze(this.dir);
|
|
475
|
+
Object.freeze(this.admin);
|
|
476
|
+
Object.freeze(this.plugins);
|
|
477
|
+
Object.freeze(this.api);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
getModel(modelKey, plugin) {
|
|
481
|
+
return this.db.getModel(modelKey, plugin);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Binds queries with a specific model
|
|
486
|
+
* @param {string} entity - entity name
|
|
487
|
+
* @param {string} plugin - plugin name or null
|
|
488
|
+
*/
|
|
489
|
+
query(entity, plugin) {
|
|
490
|
+
return this.db.query(entity, plugin);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
module.exports = (options) => {
|
|
495
|
+
const strapi = new Strapi(options);
|
|
496
|
+
global.strapi = strapi;
|
|
497
|
+
return strapi;
|
|
498
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const inquirer = require('inquirer');
|
|
5
|
+
const strapi = require('../index');
|
|
6
|
+
|
|
7
|
+
const promptQuestions = [
|
|
8
|
+
{ type: 'input', name: 'email', message: 'User email?' },
|
|
9
|
+
{ type: 'password', name: 'password', message: 'New password?' },
|
|
10
|
+
{
|
|
11
|
+
type: 'confirm',
|
|
12
|
+
name: 'confirm',
|
|
13
|
+
message: "Do you really want to reset this user's password?",
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Reset user's password
|
|
19
|
+
* @param {Object} cmdOptions - command options
|
|
20
|
+
* @param {string} cmdOptions.email - user's email
|
|
21
|
+
* @param {string} cmdOptions.password - user's new password
|
|
22
|
+
*/
|
|
23
|
+
module.exports = async function(cmdOptions = {}) {
|
|
24
|
+
const { email, password } = cmdOptions;
|
|
25
|
+
|
|
26
|
+
if (_.isEmpty(email) && _.isEmpty(password) && process.stdin.isTTY) {
|
|
27
|
+
const inquiry = await inquirer.prompt(promptQuestions);
|
|
28
|
+
|
|
29
|
+
if (!inquiry.confirm) {
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return changePassword(inquiry);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (_.isEmpty(email) || _.isEmpty(password)) {
|
|
37
|
+
console.error('Missing required options `email` or `password`');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return changePassword({ email, password });
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
async function changePassword({ email, password }) {
|
|
45
|
+
const app = await strapi().load();
|
|
46
|
+
|
|
47
|
+
await app.admin.services.user.resetPasswordByEmail(email, password);
|
|
48
|
+
|
|
49
|
+
console.log(`Successfully reset user's password`);
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { green } = require('chalk');
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line node/no-extraneous-require
|
|
5
|
+
const strapiAdmin = require('@akemona-org/strapi-admin');
|
|
6
|
+
const { getConfigUrls } = require('@akemona-org/strapi-utils');
|
|
7
|
+
const loadConfiguration = require('../core/app-configuration');
|
|
8
|
+
const ee = require('../utils/ee');
|
|
9
|
+
|
|
10
|
+
const addSlash = require('../utils/addSlash');
|
|
11
|
+
/**
|
|
12
|
+
* `$ strapi build`
|
|
13
|
+
*/
|
|
14
|
+
module.exports = async ({ clean, optimization }) => {
|
|
15
|
+
const dir = process.cwd();
|
|
16
|
+
const config = loadConfiguration(dir);
|
|
17
|
+
|
|
18
|
+
const { serverUrl, adminPath } = getConfigUrls(config.get('server'), true);
|
|
19
|
+
|
|
20
|
+
console.log(`Building your admin UI with ${green(config.environment)} configuration ...`);
|
|
21
|
+
|
|
22
|
+
if (clean) {
|
|
23
|
+
await strapiAdmin.clean({ dir });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
ee({ dir });
|
|
27
|
+
|
|
28
|
+
return strapiAdmin
|
|
29
|
+
.build({
|
|
30
|
+
dir,
|
|
31
|
+
// front end build env is always production for now
|
|
32
|
+
env: 'production',
|
|
33
|
+
optimize: optimization,
|
|
34
|
+
options: {
|
|
35
|
+
backend: serverUrl,
|
|
36
|
+
publicPath: addSlash(adminPath),
|
|
37
|
+
features: ee.isEE ? ee.features.getEnabled() : [],
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
.then(() => {
|
|
41
|
+
process.exit();
|
|
42
|
+
})
|
|
43
|
+
.catch((err) => {
|
|
44
|
+
console.error(err);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
});
|
|
47
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const strapi = require('../index');
|
|
5
|
+
|
|
6
|
+
const CHUNK_SIZE = 100;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Will dump configurations to a file or stdout
|
|
10
|
+
* @param {string} file filepath to use as output
|
|
11
|
+
*/
|
|
12
|
+
module.exports = async function({ file: filePath, pretty }) {
|
|
13
|
+
const output = filePath ? fs.createWriteStream(filePath) : process.stdout;
|
|
14
|
+
|
|
15
|
+
const app = await strapi().load();
|
|
16
|
+
|
|
17
|
+
const count = await app.query('core_store').count();
|
|
18
|
+
|
|
19
|
+
const exportData = [];
|
|
20
|
+
|
|
21
|
+
const pageCount = Math.ceil(count / CHUNK_SIZE);
|
|
22
|
+
|
|
23
|
+
for (let page = 0; page < pageCount; page++) {
|
|
24
|
+
const results = await app
|
|
25
|
+
.query('core_store')
|
|
26
|
+
.find({ _limit: CHUNK_SIZE, _start: page * CHUNK_SIZE, _sort: 'key' });
|
|
27
|
+
|
|
28
|
+
results
|
|
29
|
+
.filter(result => result.key.startsWith('plugin_'))
|
|
30
|
+
.forEach(result => {
|
|
31
|
+
exportData.push({
|
|
32
|
+
key: result.key,
|
|
33
|
+
value: result.value,
|
|
34
|
+
type: result.type,
|
|
35
|
+
environment: result.environment,
|
|
36
|
+
tag: result.tag,
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
output.write(JSON.stringify(exportData, null, pretty ? 2 : null));
|
|
42
|
+
output.write('\n');
|
|
43
|
+
output.end();
|
|
44
|
+
|
|
45
|
+
// log success only when writting to file
|
|
46
|
+
if (filePath) {
|
|
47
|
+
console.log(`Successfully exported ${exportData.length} configuration entries`);
|
|
48
|
+
}
|
|
49
|
+
process.exit(0);
|
|
50
|
+
};
|