@strapi/strapi 4.2.0-beta.2 → 4.2.0-beta.3
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/lib/Strapi.js +16 -0
- package/lib/commands/admin-create.js +9 -2
- package/lib/commands/admin-reset.js +9 -2
- package/lib/commands/build.js +2 -2
- package/lib/commands/configurationDump.js +8 -2
- package/lib/commands/configurationRestore.js +9 -2
- package/lib/commands/console.js +9 -3
- package/lib/commands/develop.js +2 -1
- package/lib/commands/routes/list.js +9 -2
- package/lib/commands/start.js +9 -5
- package/lib/commands/watchAdmin.js +2 -2
- package/lib/core/loaders/apis.js +13 -9
- package/lib/core/loaders/index.js +1 -0
- package/lib/core/loaders/sanitizers.js +5 -0
- package/lib/core/registries/policies.d.ts +1 -1
- package/lib/core/registries/sanitizers.js +26 -0
- package/lib/core-api/controller/index.d.ts +14 -9
- package/lib/core-api/service/index.d.ts +10 -9
- package/lib/factories.d.ts +21 -17
- package/lib/index.d.ts +7 -6
- package/lib/middlewares/body.js +38 -10
- package/lib/services/entity-validator/validators.js +3 -1
- package/lib/types/strapi.d.ts +291 -0
- package/lib/types/utils.d.ts +1 -0
- package/lib/utils/update-notifier/index.js +2 -2
- package/package.json +14 -13
package/lib/Strapi.js
CHANGED
|
@@ -38,10 +38,15 @@ const apisRegistry = require('./core/registries/apis');
|
|
|
38
38
|
const bootstrap = require('./core/bootstrap');
|
|
39
39
|
const loaders = require('./core/loaders');
|
|
40
40
|
const { destroyOnSignal } = require('./utils/signals');
|
|
41
|
+
const sanitizersRegistry = require('./core/registries/sanitizers');
|
|
41
42
|
|
|
42
43
|
// TODO: move somewhere else
|
|
43
44
|
const draftAndPublishSync = require('./migrations/draft-publish');
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* A map of all the available Strapi lifecycles
|
|
48
|
+
* @type {import('@strapi/strapi').Core.Lifecycles}
|
|
49
|
+
*/
|
|
45
50
|
const LIFECYCLES = {
|
|
46
51
|
REGISTER: 'register',
|
|
47
52
|
BOOTSTRAP: 'bootstrap',
|
|
@@ -68,6 +73,7 @@ const resolveWorkingDirectories = opts => {
|
|
|
68
73
|
return { app: appDir, dist: distDir };
|
|
69
74
|
};
|
|
70
75
|
|
|
76
|
+
/** @implements {import('@strapi/strapi').Strapi} */
|
|
71
77
|
class Strapi {
|
|
72
78
|
constructor(opts = {}) {
|
|
73
79
|
destroyOnSignal(this);
|
|
@@ -92,6 +98,7 @@ class Strapi {
|
|
|
92
98
|
this.container.register('plugins', pluginsRegistry(this));
|
|
93
99
|
this.container.register('apis', apisRegistry(this));
|
|
94
100
|
this.container.register('auth', createAuth(this));
|
|
101
|
+
this.container.register('sanitizers', sanitizersRegistry(this));
|
|
95
102
|
|
|
96
103
|
// Create a mapping of every useful directory (for the app, dist and static directories)
|
|
97
104
|
this.dirs = utils.getDirs(rootDirs, { strapi: this });
|
|
@@ -190,6 +197,10 @@ class Strapi {
|
|
|
190
197
|
return this.container.get('auth');
|
|
191
198
|
}
|
|
192
199
|
|
|
200
|
+
get sanitizers() {
|
|
201
|
+
return this.container.get('sanitizers');
|
|
202
|
+
}
|
|
203
|
+
|
|
193
204
|
async start() {
|
|
194
205
|
try {
|
|
195
206
|
if (!this.isLoaded) {
|
|
@@ -337,6 +348,10 @@ class Strapi {
|
|
|
337
348
|
this.app = await loaders.loadSrcIndex(this);
|
|
338
349
|
}
|
|
339
350
|
|
|
351
|
+
async loadSanitizers() {
|
|
352
|
+
await loaders.loadSanitizers(this);
|
|
353
|
+
}
|
|
354
|
+
|
|
340
355
|
registerInternalHooks() {
|
|
341
356
|
this.container.get('hooks').set('strapi::content-types.beforeSync', createAsyncParallelHook());
|
|
342
357
|
this.container.get('hooks').set('strapi::content-types.afterSync', createAsyncParallelHook());
|
|
@@ -348,6 +363,7 @@ class Strapi {
|
|
|
348
363
|
async register() {
|
|
349
364
|
await Promise.all([
|
|
350
365
|
this.loadApp(),
|
|
366
|
+
this.loadSanitizers(),
|
|
351
367
|
this.loadPlugins(),
|
|
352
368
|
this.loadAdmin(),
|
|
353
369
|
this.loadAPIs(),
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const path = require('path');
|
|
4
3
|
const { yup } = require('@strapi/utils');
|
|
5
4
|
const _ = require('lodash');
|
|
6
5
|
const inquirer = require('inquirer');
|
|
@@ -95,7 +94,15 @@ async function createAdmin({ email, password, firstname, lastname }) {
|
|
|
95
94
|
const appDir = process.cwd();
|
|
96
95
|
|
|
97
96
|
const isTSProject = await tsUtils.isUsingTypeScript(appDir);
|
|
98
|
-
const
|
|
97
|
+
const outDir = await tsUtils.resolveOutDir(appDir);
|
|
98
|
+
|
|
99
|
+
if (isTSProject)
|
|
100
|
+
await tsUtils.compile(appDir, {
|
|
101
|
+
watch: false,
|
|
102
|
+
configOptions: { options: { incremental: true } },
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const distDir = isTSProject ? outDir : appDir;
|
|
99
106
|
|
|
100
107
|
const app = await strapi({ appDir, distDir }).load();
|
|
101
108
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const path = require('path');
|
|
4
3
|
const _ = require('lodash');
|
|
5
4
|
const inquirer = require('inquirer');
|
|
6
5
|
const tsUtils = require('@strapi/typescript-utils');
|
|
@@ -47,7 +46,15 @@ async function changePassword({ email, password }) {
|
|
|
47
46
|
const appDir = process.cwd();
|
|
48
47
|
|
|
49
48
|
const isTSProject = await tsUtils.isUsingTypeScript(appDir);
|
|
50
|
-
const
|
|
49
|
+
const outDir = await tsUtils.resolveOutDir(appDir);
|
|
50
|
+
|
|
51
|
+
if (isTSProject)
|
|
52
|
+
await tsUtils.compile(appDir, {
|
|
53
|
+
watch: false,
|
|
54
|
+
configOptions: { options: { incremental: true } },
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const distDir = isTSProject ? outDir : appDir;
|
|
51
58
|
|
|
52
59
|
const app = await strapi({ appDir, distDir }).load();
|
|
53
60
|
|
package/lib/commands/build.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
const path = require('path');
|
|
3
2
|
|
|
4
3
|
const tsUtils = require('@strapi/typescript-utils');
|
|
5
4
|
const { buildAdmin, buildTypeScript } = require('./builders');
|
|
@@ -12,13 +11,14 @@ module.exports = async ({ optimization, forceBuild = true }) => {
|
|
|
12
11
|
const srcDir = process.cwd();
|
|
13
12
|
|
|
14
13
|
const useTypeScriptServer = await tsUtils.isUsingTypeScript(srcDir);
|
|
14
|
+
const outDir = await tsUtils.resolveOutDir(srcDir);
|
|
15
15
|
|
|
16
16
|
// Typescript
|
|
17
17
|
if (useTypeScriptServer) {
|
|
18
18
|
await buildTypeScript({ srcDir, watch: false });
|
|
19
19
|
|
|
20
20
|
// Update the dir path for the next steps
|
|
21
|
-
buildDestDir =
|
|
21
|
+
buildDestDir = outDir;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
await buildAdmin({
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
4
|
const tsUtils = require('@strapi/typescript-utils');
|
|
6
5
|
const strapi = require('../index');
|
|
7
6
|
|
|
@@ -17,7 +16,14 @@ module.exports = async function({ file: filePath, pretty }) {
|
|
|
17
16
|
const appDir = process.cwd();
|
|
18
17
|
|
|
19
18
|
const isTSProject = await tsUtils.isUsingTypeScript(appDir);
|
|
20
|
-
const
|
|
19
|
+
const outDir = await tsUtils.resolveOutDir(appDir);
|
|
20
|
+
if (isTSProject)
|
|
21
|
+
await tsUtils.compile(appDir, {
|
|
22
|
+
watch: false,
|
|
23
|
+
configOptions: { options: { incremental: true } },
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const distDir = isTSProject ? outDir : appDir;
|
|
21
27
|
|
|
22
28
|
const app = await strapi({ appDir, distDir }).load();
|
|
23
29
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
4
|
const _ = require('lodash');
|
|
6
5
|
const tsUtils = require('@strapi/typescript-utils');
|
|
7
6
|
|
|
@@ -18,7 +17,15 @@ module.exports = async function({ file: filePath, strategy = 'replace' }) {
|
|
|
18
17
|
const appDir = process.cwd();
|
|
19
18
|
|
|
20
19
|
const isTSProject = await tsUtils.isUsingTypeScript(appDir);
|
|
21
|
-
const
|
|
20
|
+
const outDir = await tsUtils.resolveOutDir(appDir);
|
|
21
|
+
|
|
22
|
+
if (isTSProject)
|
|
23
|
+
await tsUtils.compile(appDir, {
|
|
24
|
+
watch: false,
|
|
25
|
+
configOptions: { options: { incremental: true } },
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const distDir = isTSProject ? outDir : appDir;
|
|
22
29
|
|
|
23
30
|
const app = await strapi({ appDir, distDir }).load();
|
|
24
31
|
|
package/lib/commands/console.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const REPL = require('repl');
|
|
4
|
-
const path = require('path');
|
|
5
4
|
const tsUtils = require('@strapi/typescript-utils');
|
|
6
5
|
|
|
7
6
|
const strapi = require('../index');
|
|
@@ -12,9 +11,16 @@ const strapi = require('../index');
|
|
|
12
11
|
module.exports = async () => {
|
|
13
12
|
// Now load up the Strapi framework for real.
|
|
14
13
|
const appDir = process.cwd();
|
|
15
|
-
|
|
16
14
|
const isTSProject = await tsUtils.isUsingTypeScript(appDir);
|
|
17
|
-
const
|
|
15
|
+
const outDir = await tsUtils.resolveOutDir(appDir);
|
|
16
|
+
|
|
17
|
+
if (isTSProject)
|
|
18
|
+
await tsUtils.compile(appDir, {
|
|
19
|
+
watch: false,
|
|
20
|
+
configOptions: { options: { incremental: true } },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const distDir = isTSProject ? outDir : appDir;
|
|
18
24
|
|
|
19
25
|
const app = await strapi({ appDir, distDir }).load();
|
|
20
26
|
|
package/lib/commands/develop.js
CHANGED
|
@@ -22,7 +22,8 @@ module.exports = async function({ build, watchAdmin, polling, browser }) {
|
|
|
22
22
|
const appDir = process.cwd();
|
|
23
23
|
|
|
24
24
|
const isTSProject = await tsUtils.isUsingTypeScript(appDir);
|
|
25
|
-
const
|
|
25
|
+
const outDir = await tsUtils.resolveOutDir(appDir);
|
|
26
|
+
const distDir = isTSProject ? outDir : appDir;
|
|
26
27
|
|
|
27
28
|
try {
|
|
28
29
|
if (cluster.isMaster || cluster.isPrimary) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const path = require('path');
|
|
4
3
|
const CLITable = require('cli-table3');
|
|
5
4
|
const chalk = require('chalk');
|
|
6
5
|
const { toUpper } = require('lodash/fp');
|
|
@@ -12,7 +11,15 @@ module.exports = async function() {
|
|
|
12
11
|
const appDir = process.cwd();
|
|
13
12
|
|
|
14
13
|
const isTSProject = await tsUtils.isUsingTypeScript(appDir);
|
|
15
|
-
const
|
|
14
|
+
const outDir = await tsUtils.resolveOutDir(appDir);
|
|
15
|
+
|
|
16
|
+
if (isTSProject)
|
|
17
|
+
await tsUtils.compile(appDir, {
|
|
18
|
+
watch: false,
|
|
19
|
+
configOptions: { options: { incremental: true } },
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const distDir = isTSProject ? outDir : appDir;
|
|
16
23
|
|
|
17
24
|
const app = await strapi({ appDir, distDir }).load();
|
|
18
25
|
|
package/lib/commands/start.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
const
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const tsUtils = require('@strapi/typescript-utils');
|
|
3
4
|
const strapi = require('../index');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* `$ strapi start`
|
|
7
8
|
*/
|
|
8
9
|
module.exports = async specifiedDir => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const appDir = process.cwd();
|
|
11
|
+
const isTSProject = await tsUtils.isUsingTypeScript(appDir);
|
|
12
|
+
const outDir = await tsUtils.resolveOutDir(appDir);
|
|
13
|
+
const buildDirExists = fs.existsSync(outDir);
|
|
14
|
+
if (isTSProject && !buildDirExists) throw new Error(`${outDir} directory not found. Please run the build command before starting your application`);
|
|
15
|
+
const distDir = isTSProject && !specifiedDir ? outDir : specifiedDir;
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
strapi({ distDir }).start();
|
|
14
18
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const path = require('path');
|
|
4
3
|
const strapiAdmin = require('@strapi/admin');
|
|
5
4
|
const tsUtils = require('@strapi/typescript-utils');
|
|
6
5
|
const { getConfigUrls, getAbsoluteServerUrl } = require('@strapi/utils');
|
|
@@ -13,7 +12,8 @@ module.exports = async function({ browser }) {
|
|
|
13
12
|
const currentDirectory = process.cwd();
|
|
14
13
|
|
|
15
14
|
const isTSProject = await tsUtils.isUsingTypeScript(currentDirectory);
|
|
16
|
-
const
|
|
15
|
+
const outDir = await tsUtils.resolveOutDir(currentDirectory);
|
|
16
|
+
const buildDestDir = isTSProject ? outDir : currentDirectory;
|
|
17
17
|
|
|
18
18
|
const strapiInstance = strapi({
|
|
19
19
|
distDir: buildDestDir,
|
package/lib/core/loaders/apis.js
CHANGED
|
@@ -7,31 +7,35 @@ const fse = require('fs-extra');
|
|
|
7
7
|
const { isKebabCase } = require('@strapi/utils');
|
|
8
8
|
const { importDefault } = require('../../utils');
|
|
9
9
|
|
|
10
|
-
// to handle names with numbers in it we first check if it is already in kebabCase
|
|
11
|
-
const normalizeName = name => (isKebabCase(name) ? name : _.kebabCase(name));
|
|
12
|
-
|
|
13
10
|
const DEFAULT_CONTENT_TYPE = {
|
|
14
11
|
schema: {},
|
|
15
12
|
actions: {},
|
|
16
13
|
lifecycles: {},
|
|
17
14
|
};
|
|
18
15
|
|
|
16
|
+
// to handle names with numbers in it we first check if it is already in kebabCase
|
|
17
|
+
const normalizeName = name => (isKebabCase(name) ? name : _.kebabCase(name));
|
|
18
|
+
|
|
19
|
+
const isDirectory = fd => fd.isDirectory();
|
|
20
|
+
const isDotFile = fd => fd.name.startsWith('.');
|
|
21
|
+
|
|
19
22
|
module.exports = async strapi => {
|
|
20
23
|
if (!existsSync(strapi.dirs.dist.api)) {
|
|
21
24
|
return;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
const apisFDs = await fse.readdir(strapi.dirs.dist.api, { withFileTypes: true })
|
|
27
|
+
const apisFDs = await (await fse.readdir(strapi.dirs.dist.api, { withFileTypes: true }))
|
|
28
|
+
.filter(isDirectory)
|
|
29
|
+
.filter(_.negate(isDotFile));
|
|
30
|
+
|
|
25
31
|
const apis = {};
|
|
26
32
|
|
|
27
33
|
// only load folders
|
|
28
34
|
for (const apiFD of apisFDs) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const api = await loadAPI(join(strapi.dirs.dist.api, apiFD.name));
|
|
35
|
+
const apiName = normalizeName(apiFD.name);
|
|
36
|
+
const api = await loadAPI(join(strapi.dirs.dist.api, apiFD.name));
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
}
|
|
38
|
+
apis[apiName] = api;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
validateContentTypesUnicity(apis);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
const sanitizersRegistry = () => {
|
|
6
|
+
const sanitizers = {};
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
get(path) {
|
|
10
|
+
return _.get(sanitizers, path, []);
|
|
11
|
+
},
|
|
12
|
+
add(path, sanitizer) {
|
|
13
|
+
this.get(path).push(sanitizer);
|
|
14
|
+
return this;
|
|
15
|
+
},
|
|
16
|
+
set(path, value = []) {
|
|
17
|
+
_.set(sanitizers, path, value);
|
|
18
|
+
return this;
|
|
19
|
+
},
|
|
20
|
+
has(path) {
|
|
21
|
+
return _.has(sanitizers, path);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
module.exports = sanitizersRegistry;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Context } from 'koa';
|
|
2
2
|
|
|
3
|
-
type
|
|
3
|
+
type ControllerResponse <T=unknown> = T | Promise<T>;
|
|
4
4
|
|
|
5
5
|
interface BaseController {
|
|
6
6
|
transformResponse(data: object, meta: object): object;
|
|
@@ -9,17 +9,22 @@ interface BaseController {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface SingleTypeController extends BaseController {
|
|
12
|
-
find(ctx: Context):
|
|
13
|
-
update(ctx: Context):
|
|
14
|
-
delete(ctx: Context):
|
|
12
|
+
find(ctx: Context): ControllerResponse;
|
|
13
|
+
update(ctx: Context): ControllerResponse;
|
|
14
|
+
delete(ctx: Context): ControllerResponse;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface CollectionTypeController extends BaseController {
|
|
18
|
-
find(ctx: Context):
|
|
19
|
-
findOne(ctx: Context):
|
|
20
|
-
create(ctx: Context):
|
|
21
|
-
update(ctx: Context):
|
|
22
|
-
delete(ctx: Context):
|
|
18
|
+
find(ctx: Context): ControllerResponse;
|
|
19
|
+
findOne(ctx: Context): ControllerResponse
|
|
20
|
+
create(ctx: Context): ControllerResponse;
|
|
21
|
+
update(ctx: Context): ControllerResponse;
|
|
22
|
+
delete(ctx: Context): ControllerResponse;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export type Controller = SingleTypeController | CollectionTypeController;
|
|
26
|
+
|
|
27
|
+
export type GenericController = Partial<Controller> & {
|
|
28
|
+
[method: string | number | symbol]: (ctx: Context) => unknown
|
|
29
|
+
}
|
|
30
|
+
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
type Entity = object;
|
|
2
2
|
|
|
3
3
|
interface BaseService {
|
|
4
|
-
getFetchParams(params: object): object;
|
|
4
|
+
getFetchParams?(params: object): object;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export interface SingleTypeService extends BaseService {
|
|
8
|
-
find(params: object): Promise<Entity
|
|
9
|
-
createOrUpdate(params: object): Promise<Entity
|
|
10
|
-
delete(params: object): Promise<Entity
|
|
8
|
+
find?(params: object): Promise<Entity> | Entity;
|
|
9
|
+
createOrUpdate?(params: object): Promise<Entity> | Entity;
|
|
10
|
+
delete?(params: object): Promise<Entity> | Entity;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface CollectionTypeService extends BaseService {
|
|
14
|
-
find(params: object): Promise<Entity[]
|
|
15
|
-
findOne(params: object): Promise<Entity
|
|
16
|
-
create(params: object): Promise<Entity
|
|
17
|
-
update(params: object): Promise<Entity
|
|
18
|
-
delete(params: object): Promise<Entity
|
|
14
|
+
find?(params: object): Promise<Entity[]> | Entity;
|
|
15
|
+
findOne?(entityId: string,params: object): Promise<Entity> | Entity;
|
|
16
|
+
create?(params: object): Promise<Entity> | Entity;
|
|
17
|
+
update?(entityId: string,params: object): Promise<Entity> | Entity;
|
|
18
|
+
delete?(entityId: string,params: object): Promise<Entity> | Entity;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export type Service = SingleTypeService | CollectionTypeService;
|
|
22
|
+
|
package/lib/factories.d.ts
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
import { Service } from './core-api/service';
|
|
2
|
-
import { Controller } from './core-api/controller';
|
|
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
6
|
|
|
6
|
-
type ControllerConfig = Controller;
|
|
7
|
+
type ControllerConfig<T extends Controller = Controller> = T;
|
|
7
8
|
|
|
8
9
|
type ServiceConfig = Service;
|
|
9
10
|
|
|
10
11
|
type HandlerConfig = {
|
|
11
|
-
auth
|
|
12
|
-
policies
|
|
13
|
-
middlewares
|
|
12
|
+
auth?: false | { scope: string[] };
|
|
13
|
+
policies?: Array<string | Policy>;
|
|
14
|
+
middlewares?: Array<string | Middleware>;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
type SingleTypeRouterConfig = {
|
|
17
|
-
find
|
|
18
|
-
update
|
|
19
|
-
delete
|
|
18
|
+
find?: HandlerConfig;
|
|
19
|
+
update?: HandlerConfig;
|
|
20
|
+
delete?: HandlerConfig;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
type CollectionTypeRouterConfig = {
|
|
23
|
-
find
|
|
24
|
-
findOne
|
|
25
|
-
create
|
|
26
|
-
update
|
|
27
|
-
delete
|
|
24
|
+
find?: HandlerConfig;
|
|
25
|
+
findOne?: HandlerConfig;
|
|
26
|
+
create?: HandlerConfig;
|
|
27
|
+
update?: HandlerConfig;
|
|
28
|
+
delete?: HandlerConfig;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
type RouterConfig = {
|
|
31
|
-
prefix
|
|
32
|
+
prefix?: string;
|
|
32
33
|
only: string[];
|
|
33
|
-
except
|
|
34
|
+
except?: string[];
|
|
34
35
|
config: SingleTypeRouterConfig | CollectionTypeRouterConfig;
|
|
35
36
|
};
|
|
36
37
|
|
|
@@ -43,6 +44,9 @@ interface Router {
|
|
|
43
44
|
routes: Route[];
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
type ControllerCallback <T extends GenericController = GenericController> = (params:{strapi:Strapi}) => T;
|
|
48
|
+
type ServiceCallback <T extends Service = Sevice> = (params:{strapi:Strapi}) => T
|
|
49
|
+
|
|
46
50
|
export function createCoreRouter(uid: string, cfg?: RouterConfig = {}): () => Router;
|
|
47
|
-
export function createCoreController(uid: string, cfg?:
|
|
48
|
-
export function createCoreService(uid: string, cfg?:
|
|
51
|
+
export function createCoreController<T extends GenericController = GenericController>(uid: string, cfg?: ControllerCallback<T> | T = {}): () => T & Controller;
|
|
52
|
+
export function createCoreService<T extends Service = Service>(uid: string, cfg?: ServiceCallback<T> | T = {}): () => T ;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Database } from '@strapi/database';
|
|
2
2
|
import { EntityService } from './services/entity-service';
|
|
3
|
-
import { Strapi as StrapiClass } from './Strapi';
|
|
4
3
|
|
|
4
|
+
import * as Core from './types/strapi';
|
|
5
5
|
export * as factories from './factories';
|
|
6
|
-
export interface StrapiInterface extends StrapiClass {
|
|
7
|
-
query: Database['query'];
|
|
8
|
-
entityService: EntityService;
|
|
9
|
-
}
|
|
10
6
|
|
|
11
|
-
export type
|
|
7
|
+
export type { Core };
|
|
8
|
+
|
|
9
|
+
// Alias to resolve the Strapi global type easily
|
|
10
|
+
export type Strapi = Core.Strapi;
|
|
11
|
+
|
|
12
|
+
export interface StrapiInterface extends Core.Strapi {};
|
|
12
13
|
|
|
13
14
|
declare global {
|
|
14
15
|
interface AllTypes {}
|
package/lib/middlewares/body.js
CHANGED
|
@@ -3,12 +3,23 @@
|
|
|
3
3
|
const fse = require('fs-extra');
|
|
4
4
|
const { defaultsDeep, get } = require('lodash/fp');
|
|
5
5
|
const body = require('koa-body');
|
|
6
|
+
const mime = require('mime-types');
|
|
6
7
|
|
|
7
8
|
const defaults = {
|
|
8
9
|
multipart: true,
|
|
9
10
|
patchKoa: true,
|
|
10
11
|
};
|
|
11
12
|
|
|
13
|
+
function ensureFileMimeType(file) {
|
|
14
|
+
if (!file.type) {
|
|
15
|
+
file.type = mime.lookup(file.name) || 'application/octet-stream';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getFiles(ctx) {
|
|
20
|
+
return get('request.files.files', ctx);
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
/**
|
|
13
24
|
* @type {import('./').MiddlewareFactory}
|
|
14
25
|
*/
|
|
@@ -18,21 +29,38 @@ module.exports = config => {
|
|
|
18
29
|
return async (ctx, next) => {
|
|
19
30
|
// TODO: find a better way later
|
|
20
31
|
if (ctx.url === '/graphql') {
|
|
21
|
-
|
|
22
|
-
}
|
|
32
|
+
await next();
|
|
33
|
+
} else {
|
|
34
|
+
try {
|
|
35
|
+
await body({ patchKoa: true, ...bodyConfig })(ctx, () => {});
|
|
23
36
|
|
|
24
|
-
|
|
25
|
-
await body({ patchKoa: true, ...bodyConfig })(ctx, next);
|
|
26
|
-
} catch (e) {
|
|
27
|
-
if ((e || {}).message && e.message.includes('maxFileSize exceeded')) {
|
|
28
|
-
return ctx.payloadTooLarge('FileTooBig');
|
|
29
|
-
}
|
|
37
|
+
const files = getFiles(ctx);
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
/**
|
|
40
|
+
* in case the mime-type wasn't sent, Strapi tries to guess it
|
|
41
|
+
* from the file extension, to avoid a corrupt database state
|
|
42
|
+
*/
|
|
43
|
+
if (files) {
|
|
44
|
+
if (Array.isArray(files)) {
|
|
45
|
+
files.forEach(ensureFileMimeType);
|
|
46
|
+
} else {
|
|
47
|
+
ensureFileMimeType(files);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
await next();
|
|
52
|
+
} catch (e) {
|
|
53
|
+
if ((e || {}).message && e.message.includes('maxFileSize exceeded')) {
|
|
54
|
+
return ctx.payloadTooLarge('FileTooBig');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
throw e;
|
|
58
|
+
}
|
|
32
59
|
}
|
|
33
60
|
|
|
61
|
+
const files = getFiles(ctx);
|
|
62
|
+
|
|
34
63
|
// clean any file that was uploaded
|
|
35
|
-
const files = get('request.files.files', ctx);
|
|
36
64
|
if (files) {
|
|
37
65
|
if (Array.isArray(files)) {
|
|
38
66
|
// not awaiting to not slow the request
|
|
@@ -166,7 +166,9 @@ const stringValidator = composeValidators(
|
|
|
166
166
|
addUniqueValidator
|
|
167
167
|
);
|
|
168
168
|
|
|
169
|
-
const emailValidator = composeValidators(stringValidator, validator =>
|
|
169
|
+
const emailValidator = composeValidators(stringValidator, validator =>
|
|
170
|
+
validator.email().min(1, '${path} cannot be empty')
|
|
171
|
+
);
|
|
170
172
|
|
|
171
173
|
const uidValidator = composeValidators(stringValidator, validator =>
|
|
172
174
|
validator.matches(new RegExp('^[A-Za-z0-9-_.~]*$'))
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import type Koa from 'koa';
|
|
2
|
+
|
|
3
|
+
import type { StringMap } from './utils';
|
|
4
|
+
|
|
5
|
+
type Controller = {
|
|
6
|
+
[methodName: string | number | symbol]: (context: Koa.Context) => unknown;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The Strapi interface implemented by the main Strapi class.
|
|
11
|
+
*/
|
|
12
|
+
export interface Strapi {
|
|
13
|
+
/**
|
|
14
|
+
* Getter for the Strapi enterprise edition configuration
|
|
15
|
+
*/
|
|
16
|
+
readonly EE: any;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Getter for the Strapi configuration container
|
|
20
|
+
*/
|
|
21
|
+
readonly config: any;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Getter for the Strapi auth container
|
|
25
|
+
*/
|
|
26
|
+
readonly auth: any;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Getter for the Strapi sanitizers container
|
|
30
|
+
*/
|
|
31
|
+
readonly sanitizers: any;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Getter for the Strapi services container
|
|
35
|
+
*
|
|
36
|
+
* It returns all the registered services
|
|
37
|
+
*/
|
|
38
|
+
readonly services: StringMap<Service>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Find a service using its unique identifier
|
|
42
|
+
*/
|
|
43
|
+
service<T extends Service = unknown>(uid: string): T | undefined;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Getter for the Strapi controllers container
|
|
47
|
+
*
|
|
48
|
+
* It returns all the registered controllers
|
|
49
|
+
*/
|
|
50
|
+
readonly controllers: StringMap<Controller>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Find a controller using its unique identifier
|
|
54
|
+
*/
|
|
55
|
+
controller(uid: string): Controller | undefined;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Getter for the Strapi content types container
|
|
59
|
+
*
|
|
60
|
+
* It returns all the registered content types
|
|
61
|
+
*/
|
|
62
|
+
readonly contentTypes: any;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Find a content type using its unique identifier
|
|
66
|
+
*/
|
|
67
|
+
contentType(uid: string): any;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Getter for the Strapi policies container
|
|
71
|
+
*
|
|
72
|
+
* It returns all the registered policies
|
|
73
|
+
*/
|
|
74
|
+
readonly policies: any;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Find a policy using its name
|
|
78
|
+
*/
|
|
79
|
+
policy(name: string): any;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Getter for the Strapi middlewares container
|
|
83
|
+
*
|
|
84
|
+
* It returns all the registered middlewares
|
|
85
|
+
*/
|
|
86
|
+
readonly middlewares: any;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Find a middleware using its name
|
|
90
|
+
*/
|
|
91
|
+
middleware(): any;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Getter for the Strapi plugins container
|
|
95
|
+
*
|
|
96
|
+
* It returns all the registered plugins
|
|
97
|
+
*/
|
|
98
|
+
readonly plugins: any;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Find a plugin using its name
|
|
102
|
+
*/
|
|
103
|
+
plugin(name: string): any;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Getter for the Strapi hooks container
|
|
107
|
+
*
|
|
108
|
+
* It returns all the registered hooks
|
|
109
|
+
*/
|
|
110
|
+
readonly hooks: any;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Find a hook using its name
|
|
114
|
+
*/
|
|
115
|
+
hook(): any;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Getter for the Strapi APIs container
|
|
119
|
+
*
|
|
120
|
+
* It returns all the registered APIs
|
|
121
|
+
*/
|
|
122
|
+
readonly api: any;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Strapi Register Lifecycle.
|
|
126
|
+
*
|
|
127
|
+
* - Load
|
|
128
|
+
* - The user application
|
|
129
|
+
* - The plugins
|
|
130
|
+
* - The admin
|
|
131
|
+
* - The APIs
|
|
132
|
+
* - The components
|
|
133
|
+
* - The middlewares
|
|
134
|
+
* - The policies
|
|
135
|
+
* - Trigger Strapi internal bootstrap
|
|
136
|
+
* - Create the webhooks runner
|
|
137
|
+
* - Create the internal hooks registry.
|
|
138
|
+
* - Init the telemetry cron job and middleware
|
|
139
|
+
* - Run all the `register` lifecycle methods loaded by the user application or the enabled plugins
|
|
140
|
+
*/
|
|
141
|
+
register(): Promise<Strapi>;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Bootstraping phase.
|
|
145
|
+
*
|
|
146
|
+
* - Load all the content types
|
|
147
|
+
* - Initialize the database layer
|
|
148
|
+
* - Initialize the entity service
|
|
149
|
+
* - Run the schemas/database synchronization
|
|
150
|
+
* - Start the webhooks and initializing middlewares and routes
|
|
151
|
+
* - Run all the `bootstrap` lifecycle methods loaded by the
|
|
152
|
+
* user application or the enabled plugins
|
|
153
|
+
*/
|
|
154
|
+
bootstrap(): Promise<Strapi>;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Destroy phase
|
|
158
|
+
*
|
|
159
|
+
* - Destroy Strapi server
|
|
160
|
+
* - Run all the `destroy` lifecycle methods loaded by the
|
|
161
|
+
* user application or the enabled plugins
|
|
162
|
+
* - Cleanup the event hub
|
|
163
|
+
* - Gracefully stop the database
|
|
164
|
+
* - Stop the telemetry and cron instance
|
|
165
|
+
* - Cleanup the global scope by removing global.strapi
|
|
166
|
+
*/
|
|
167
|
+
destroy(): Promise<void>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Run all functions registered for a given lifecycle. (Strapi core, user app, plugins)
|
|
171
|
+
*/
|
|
172
|
+
runLifecyclesFunctions<T extends Lifecycles[keyof Lifecycles]>(lifecycleName: T): Promise<void>;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Load the application if needed and start the server
|
|
176
|
+
*/
|
|
177
|
+
start(): Promise<void>;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Stop the server and provide a custom error and message
|
|
181
|
+
*/
|
|
182
|
+
stopWithError<TError = unknown>(error: TError, customMessage?: string): void;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Gracefully stop the server
|
|
186
|
+
* Call the destroy method.
|
|
187
|
+
*/
|
|
188
|
+
stop(code?: number): void;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Load the server and the user application.
|
|
192
|
+
* It basically triggers the register and bootstrap phases
|
|
193
|
+
*/
|
|
194
|
+
load(): Promise<Strapi>;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Restart the server and reload all the configuration.
|
|
198
|
+
* It re-runs all the lifecycles phases.
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ``` ts
|
|
202
|
+
* setImmediate(() => strapi.reload());
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
reload(): () => void;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Initialize and start all the webhooks registered in the webhook store
|
|
209
|
+
*/
|
|
210
|
+
startWebhooks(): Promise<void>;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Method called when the server is fully initialized and listen to incomming requests.
|
|
214
|
+
* It handles tasks such as logging the startup message
|
|
215
|
+
* or automatically opening the administration panel.
|
|
216
|
+
*/
|
|
217
|
+
postListen(): Promise<void>;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Start listening for incomming requests
|
|
221
|
+
*/
|
|
222
|
+
listen(): Promise<void | Error>;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Opent he administration panel in a browser if the option is enabled.
|
|
226
|
+
* You can disable it using the admin.autoOpen configuration variable.
|
|
227
|
+
*
|
|
228
|
+
* Note: It only works in development envs.
|
|
229
|
+
*/
|
|
230
|
+
openAdmin(options: { isInitialized: boolean }): Promise<void>;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Load the admin panel server logic into the server code and initialize its configuration.
|
|
234
|
+
*/
|
|
235
|
+
loadAdmin(): Promise<void>;
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Resolve every enabled plugin and load them into the application.
|
|
239
|
+
*/
|
|
240
|
+
loadPlugins(): Promise<void>;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Load every global policies in the policies container by
|
|
244
|
+
* reading from the `strapi.dirs.dist.policies` directory.
|
|
245
|
+
*/
|
|
246
|
+
loadPolicies(): Promise<void>;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Load every APIs and their components (config, routes, controllers, services,
|
|
250
|
+
* policies, middlewares, content-types) in the API container.
|
|
251
|
+
*/
|
|
252
|
+
loadAPIs(): Promise<void>;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Resolve every components in the user application and store them in `strapi.components`
|
|
256
|
+
*/
|
|
257
|
+
loadComponents(): Promise<void>;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Load every global and core middlewares in the middlewares container by
|
|
261
|
+
* reading from the `strapi.dirs.dist.middlewares` and internal middlewares directory.
|
|
262
|
+
*/
|
|
263
|
+
loadMiddlewares(): Promise<void>;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Load the user application in the server by reading the `src/index.js` file.
|
|
267
|
+
*/
|
|
268
|
+
loadApp(): Promise<void>;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Add internal hooks to the hooks container.
|
|
272
|
+
* Those hooks are meant for internal usage and might break in future releases.
|
|
273
|
+
*/
|
|
274
|
+
registerInternalHooks(): void;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Find a model (content-type, component) based on its unique identifier.
|
|
278
|
+
*/
|
|
279
|
+
getModel(uid: string): any;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Binds database queries for a specific model based on its unique identifier.
|
|
283
|
+
*/
|
|
284
|
+
query(uid: string): any;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export interface Lifecycles {
|
|
288
|
+
REGISTER: 'register';
|
|
289
|
+
BOOTSTRAP: 'bootstrap';
|
|
290
|
+
DESTROY: 'destroy';
|
|
291
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type StringMap<T> = { [key: string]: T };
|
|
@@ -20,7 +20,7 @@ const boxenOptions = {
|
|
|
20
20
|
borderStyle: 'round',
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const getUpdateMessage = (newVersion, currentVersion) => {
|
|
24
24
|
const currentVersionLog = chalk.dim(currentVersion);
|
|
25
25
|
const newVersionLog = chalk.green(newVersion);
|
|
26
26
|
const releaseLink = chalk.bold('https://github.com/strapi/strapi/releases');
|
|
@@ -78,7 +78,7 @@ const createUpdateNotifier = strapi => {
|
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const message = boxen(
|
|
81
|
+
const message = boxen(getUpdateMessage(latestVersion, pkg.version), boxenOptions);
|
|
82
82
|
config.set('lastNotification', now);
|
|
83
83
|
console.log(message);
|
|
84
84
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/strapi",
|
|
3
|
-
"version": "4.2.0-beta.
|
|
3
|
+
"version": "4.2.0-beta.3",
|
|
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,17 +80,17 @@
|
|
|
80
80
|
"dependencies": {
|
|
81
81
|
"@koa/cors": "3.1.0",
|
|
82
82
|
"@koa/router": "10.1.1",
|
|
83
|
-
"@strapi/admin": "4.2.0-beta.
|
|
84
|
-
"@strapi/database": "4.2.0-beta.
|
|
85
|
-
"@strapi/generate-new": "4.2.0-beta.
|
|
86
|
-
"@strapi/generators": "4.2.0-beta.
|
|
87
|
-
"@strapi/logger": "4.2.0-beta.
|
|
88
|
-
"@strapi/plugin-content-manager": "4.2.0-beta.
|
|
89
|
-
"@strapi/plugin-content-type-builder": "4.2.0-beta.
|
|
90
|
-
"@strapi/plugin-email": "4.2.0-beta.
|
|
91
|
-
"@strapi/plugin-upload": "4.2.0-beta.
|
|
92
|
-
"@strapi/typescript-utils": "4.2.0-beta.
|
|
93
|
-
"@strapi/utils": "4.2.0-beta.
|
|
83
|
+
"@strapi/admin": "4.2.0-beta.3",
|
|
84
|
+
"@strapi/database": "4.2.0-beta.3",
|
|
85
|
+
"@strapi/generate-new": "4.2.0-beta.3",
|
|
86
|
+
"@strapi/generators": "4.2.0-beta.3",
|
|
87
|
+
"@strapi/logger": "4.2.0-beta.3",
|
|
88
|
+
"@strapi/plugin-content-manager": "4.2.0-beta.3",
|
|
89
|
+
"@strapi/plugin-content-type-builder": "4.2.0-beta.3",
|
|
90
|
+
"@strapi/plugin-email": "4.2.0-beta.3",
|
|
91
|
+
"@strapi/plugin-upload": "4.2.0-beta.3",
|
|
92
|
+
"@strapi/typescript-utils": "4.2.0-beta.3",
|
|
93
|
+
"@strapi/utils": "4.2.0-beta.3",
|
|
94
94
|
"bcryptjs": "2.4.3",
|
|
95
95
|
"boxen": "5.1.2",
|
|
96
96
|
"chalk": "4.1.2",
|
|
@@ -118,6 +118,7 @@
|
|
|
118
118
|
"koa-session": "6.2.0",
|
|
119
119
|
"koa-static": "5.0.0",
|
|
120
120
|
"lodash": "4.17.21",
|
|
121
|
+
"mime-types": "2.1.35",
|
|
121
122
|
"node-fetch": "2.6.7",
|
|
122
123
|
"node-machine-id": "1.1.12",
|
|
123
124
|
"node-schedule": "2.0.0",
|
|
@@ -138,5 +139,5 @@
|
|
|
138
139
|
"node": ">=12.22.0 <=16.x.x",
|
|
139
140
|
"npm": ">=6.0.0"
|
|
140
141
|
},
|
|
141
|
-
"gitHead": "
|
|
142
|
+
"gitHead": "c4addbad6ecbc8ef7633bbba3806f3b0a2ae5f49"
|
|
142
143
|
}
|