@strapi/strapi 4.0.0-next.9 → 4.0.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 (140) hide show
  1. package/README.md +12 -12
  2. package/bin/strapi.js +32 -5
  3. package/lib/Strapi.js +140 -72
  4. package/lib/commands/build.js +16 -6
  5. package/lib/commands/console.js +1 -1
  6. package/lib/commands/content-types/list.js +22 -0
  7. package/lib/commands/develop.js +14 -15
  8. package/lib/commands/generate-template.js +4 -5
  9. package/lib/commands/hooks/list.js +22 -0
  10. package/lib/commands/middlewares/list.js +22 -0
  11. package/lib/commands/new.js +3 -1
  12. package/lib/commands/policies/list.js +22 -0
  13. package/lib/commands/routes/list.js +28 -0
  14. package/lib/commands/services/list.js +22 -0
  15. package/lib/commands/watchAdmin.js +18 -9
  16. package/lib/core/app-configuration/index.js +3 -19
  17. package/lib/core/bootstrap.js +3 -34
  18. package/lib/core/domain/content-type/index.js +3 -7
  19. package/lib/core/domain/module/index.js +8 -6
  20. package/lib/core/domain/module/validation.js +1 -4
  21. package/lib/core/loaders/admin.js +2 -2
  22. package/lib/core/loaders/apis.js +7 -7
  23. package/lib/core/loaders/components.js +3 -5
  24. package/lib/core/loaders/index.js +1 -0
  25. package/lib/core/loaders/middlewares.js +23 -123
  26. package/lib/core/loaders/plugins/get-enabled-plugins.js +48 -14
  27. package/lib/core/loaders/plugins/index.js +30 -14
  28. package/lib/core/loaders/policies.js +1 -1
  29. package/lib/core/loaders/src-index.js +39 -0
  30. package/lib/core/registries/apis.js +2 -16
  31. package/lib/core/registries/content-types.js +50 -6
  32. package/lib/core/registries/controllers.d.ts +7 -0
  33. package/lib/core/registries/controllers.js +74 -3
  34. package/lib/core/registries/hooks.d.ts +20 -0
  35. package/lib/core/registries/hooks.js +87 -0
  36. package/lib/core/registries/middlewares.d.ts +5 -0
  37. package/lib/core/registries/middlewares.js +61 -2
  38. package/lib/core/registries/modules.js +3 -3
  39. package/lib/core/registries/plugins.js +2 -2
  40. package/lib/core/registries/policies.d.ts +9 -0
  41. package/lib/core/registries/policies.js +57 -6
  42. package/lib/core/registries/services.d.ts +7 -0
  43. package/lib/core/registries/services.js +71 -15
  44. package/lib/core-api/controller/collection-type.js +38 -11
  45. package/lib/core-api/controller/index.d.ts +25 -0
  46. package/lib/core-api/controller/index.js +30 -11
  47. package/lib/core-api/controller/single-type.js +26 -7
  48. package/lib/core-api/controller/transform.js +28 -3
  49. package/lib/core-api/routes/index.js +71 -0
  50. package/lib/core-api/service/collection-type.js +22 -27
  51. package/lib/core-api/service/index.d.ts +21 -0
  52. package/lib/core-api/service/index.js +9 -19
  53. package/lib/core-api/service/pagination.js +7 -2
  54. package/lib/core-api/service/single-type.js +17 -20
  55. package/lib/factories.d.ts +48 -0
  56. package/lib/factories.js +84 -0
  57. package/lib/index.d.ts +10 -31
  58. package/lib/index.js +5 -1
  59. package/lib/middlewares/body.js +33 -0
  60. package/lib/middlewares/compression.js +8 -0
  61. package/lib/middlewares/cors.js +58 -0
  62. package/lib/middlewares/errors.js +40 -0
  63. package/lib/middlewares/favicon.js +19 -0
  64. package/lib/middlewares/index.d.ts +5 -0
  65. package/lib/middlewares/index.js +30 -116
  66. package/lib/middlewares/ip.js +8 -0
  67. package/lib/middlewares/logger.js +27 -0
  68. package/lib/middlewares/powered-by.js +20 -0
  69. package/lib/middlewares/public/index.js +98 -73
  70. package/lib/middlewares/query.js +46 -0
  71. package/lib/middlewares/response-time.js +15 -0
  72. package/lib/middlewares/responses.js +19 -0
  73. package/lib/middlewares/security.js +51 -0
  74. package/lib/middlewares/session/index.js +6 -6
  75. package/lib/migrations/draft-publish.js +57 -0
  76. package/lib/services/auth/index.js +87 -0
  77. package/lib/services/core-store.js +64 -49
  78. package/lib/services/cron.js +54 -0
  79. package/lib/services/entity-service/attributes/index.js +31 -0
  80. package/lib/services/entity-service/attributes/transforms.js +20 -0
  81. package/lib/services/entity-service/components.js +39 -15
  82. package/lib/services/entity-service/index.d.ts +91 -0
  83. package/lib/services/entity-service/index.js +118 -60
  84. package/lib/services/entity-service/params.js +48 -81
  85. package/lib/services/entity-validator/index.js +76 -43
  86. package/lib/services/entity-validator/validators.js +129 -43
  87. package/lib/services/errors.js +77 -0
  88. package/lib/services/fs.js +1 -1
  89. package/lib/services/metrics/index.js +38 -36
  90. package/lib/services/server/admin-api.js +14 -0
  91. package/lib/services/server/api.js +36 -0
  92. package/lib/services/server/compose-endpoint.js +141 -0
  93. package/lib/services/server/content-api.js +16 -0
  94. package/lib/{server.js → services/server/http-server.js} +0 -0
  95. package/lib/services/server/index.js +127 -0
  96. package/lib/services/server/koa.js +64 -0
  97. package/lib/services/server/middleware.js +122 -0
  98. package/lib/services/server/policy.js +32 -0
  99. package/lib/services/server/register-middlewares.js +110 -0
  100. package/lib/services/server/register-routes.js +106 -0
  101. package/lib/services/server/routing.js +120 -0
  102. package/lib/services/webhook-runner.js +1 -1
  103. package/lib/utils/ee.js +3 -3
  104. package/lib/utils/get-dirs.js +17 -0
  105. package/lib/utils/index.js +2 -0
  106. package/lib/utils/signals.js +24 -0
  107. package/lib/utils/update-notifier/index.js +2 -1
  108. package/package.json +93 -93
  109. package/lib/core/app-configuration/load-functions.js +0 -28
  110. package/lib/core-api/index.js +0 -39
  111. package/lib/middlewares/boom/defaults.json +0 -5
  112. package/lib/middlewares/boom/index.js +0 -147
  113. package/lib/middlewares/cors/index.js +0 -66
  114. package/lib/middlewares/cron/defaults.json +0 -5
  115. package/lib/middlewares/cron/index.js +0 -43
  116. package/lib/middlewares/favicon/defaults.json +0 -7
  117. package/lib/middlewares/favicon/index.js +0 -32
  118. package/lib/middlewares/gzip/defaults.json +0 -6
  119. package/lib/middlewares/gzip/index.js +0 -19
  120. package/lib/middlewares/helmet/defaults.json +0 -18
  121. package/lib/middlewares/helmet/index.js +0 -9
  122. package/lib/middlewares/ip/defaults.json +0 -7
  123. package/lib/middlewares/ip/index.js +0 -25
  124. package/lib/middlewares/language/defaults.json +0 -9
  125. package/lib/middlewares/language/index.js +0 -40
  126. package/lib/middlewares/logger/defaults.json +0 -5
  127. package/lib/middlewares/logger/index.js +0 -37
  128. package/lib/middlewares/parser/defaults.json +0 -11
  129. package/lib/middlewares/parser/index.js +0 -72
  130. package/lib/middlewares/poweredBy/defaults.json +0 -5
  131. package/lib/middlewares/poweredBy/index.js +0 -16
  132. package/lib/middlewares/public/defaults.json +0 -8
  133. package/lib/middlewares/responseTime/defaults.json +0 -5
  134. package/lib/middlewares/responseTime/index.js +0 -25
  135. package/lib/middlewares/responses/defaults.json +0 -5
  136. package/lib/middlewares/responses/index.js +0 -18
  137. package/lib/middlewares/router/defaults.json +0 -7
  138. package/lib/middlewares/router/index.js +0 -72
  139. package/lib/middlewares/router/utils/compose-endpoint.js +0 -169
  140. package/lib/utils/get-prefixed-dependencies.js +0 -7
@@ -24,13 +24,28 @@ const transformResponse = (resource, meta = {}, { contentType } = {}) => {
24
24
  };
25
25
  };
26
26
 
27
- const transformEntry = (entry, contentType) => {
27
+ const transformComponent = (data, component) => {
28
+ if (Array.isArray(data)) {
29
+ return data.map(datum => transformComponent(datum, component));
30
+ }
31
+
32
+ const res = transformEntry(data, component);
33
+
34
+ if (isNil(res)) {
35
+ return res;
36
+ }
37
+
38
+ const { id, attributes } = res;
39
+ return { id, ...attributes };
40
+ };
41
+
42
+ const transformEntry = (entry, type) => {
28
43
  if (isNil(entry)) {
29
44
  return entry;
30
45
  }
31
46
 
32
47
  if (Array.isArray(entry)) {
33
- return entry.map(singleEntry => transformEntry(singleEntry, contentType));
48
+ return entry.map(singleEntry => transformEntry(singleEntry, type));
34
49
  }
35
50
 
36
51
  if (!isPlainObject(entry)) {
@@ -43,12 +58,22 @@ const transformEntry = (entry, contentType) => {
43
58
 
44
59
  for (const key in properties) {
45
60
  const property = properties[key];
46
- const attribute = contentType && contentType.attributes[key];
61
+ const attribute = type && type.attributes[key];
47
62
 
48
63
  if (attribute && attribute.type === 'relation') {
49
64
  const data = transformEntry(property, strapi.contentType(attribute.target));
50
65
 
51
66
  attributeValues[key] = { data };
67
+ } else if (attribute && attribute.type === 'component') {
68
+ attributeValues[key] = transformComponent(property, strapi.components[attribute.component]);
69
+ } else if (attribute && attribute.type === 'dynamiczone') {
70
+ if (isNil(property)) {
71
+ attributeValues[key] = property;
72
+ }
73
+
74
+ attributeValues[key] = property.map(subProperty => {
75
+ return transformComponent(subProperty, strapi.components[subProperty.__component]);
76
+ });
52
77
  } else if (attribute && attribute.type === 'media') {
53
78
  const data = transformEntry(property, strapi.contentType('plugin::upload.file'));
54
79
 
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+
3
+ const { isSingleType } = require('@strapi/utils').contentTypes;
4
+
5
+ const createRoutes = ({ contentType }) => {
6
+ if (isSingleType(contentType)) {
7
+ return getSingleTypeRoutes(contentType);
8
+ }
9
+
10
+ return getCollectionTypeRoutes(contentType);
11
+ };
12
+
13
+ const getSingleTypeRoutes = ({ uid, info }) => {
14
+ return {
15
+ find: {
16
+ method: 'GET',
17
+ path: `/${info.singularName}`,
18
+ handler: `${uid}.find`,
19
+ config: {},
20
+ },
21
+ update: {
22
+ method: 'PUT',
23
+ path: `/${info.singularName}`,
24
+ handler: `${uid}.update`,
25
+ config: {},
26
+ },
27
+ delete: {
28
+ method: 'DELETE',
29
+ path: `/${info.singularName}`,
30
+ handler: `${uid}.delete`,
31
+ config: {},
32
+ },
33
+ };
34
+ };
35
+
36
+ const getCollectionTypeRoutes = ({ uid, info }) => {
37
+ return {
38
+ find: {
39
+ method: 'GET',
40
+ path: `/${info.pluralName}`,
41
+ handler: `${uid}.find`,
42
+ config: {},
43
+ },
44
+ findOne: {
45
+ method: 'GET',
46
+ path: `/${info.pluralName}/:id`,
47
+ handler: `${uid}.findOne`,
48
+ config: {},
49
+ },
50
+ create: {
51
+ method: 'POST',
52
+ path: `/${info.pluralName}`,
53
+ handler: `${uid}.create`,
54
+ config: {},
55
+ },
56
+ update: {
57
+ method: 'PUT',
58
+ path: `/${info.pluralName}/:id`,
59
+ handler: `${uid}.update`,
60
+ config: {},
61
+ },
62
+ delete: {
63
+ method: 'DELETE',
64
+ path: `/${info.pluralName}/:id`,
65
+ handler: `${uid}.delete`,
66
+ config: {},
67
+ },
68
+ };
69
+ };
70
+
71
+ module.exports = { createRoutes };
@@ -22,25 +22,22 @@ const setPublishedAt = data => {
22
22
  *
23
23
  * Returns a collection type service to handle default core-api actions
24
24
  */
25
- const createCollectionTypeService = ({ model, strapi, utils }) => {
26
- const { uid } = model;
27
-
28
- const { sanitizeInput, getFetchParams } = utils;
25
+ const createCollectionTypeService = ({ contentType }) => {
26
+ const { uid } = contentType;
29
27
 
30
28
  return {
31
- async find(opts = {}) {
32
- const params = getFetchParams(opts.params);
29
+ async find(params = {}) {
30
+ const fetchParams = this.getFetchParams(params);
33
31
 
34
- const paginationInfo = getPaginationInfo(params);
32
+ const paginationInfo = getPaginationInfo(fetchParams);
35
33
 
36
- const results = await strapi.entityService.find(uid, {
37
- params: { ...params, ...convertPagedToStartLimit(paginationInfo) },
34
+ const results = await strapi.entityService.findMany(uid, {
35
+ ...fetchParams,
36
+ ...convertPagedToStartLimit(paginationInfo),
38
37
  });
39
38
 
40
- if (shouldCount(params)) {
41
- const count = await strapi.entityService.count(uid, {
42
- params: { ...params, ...paginationInfo },
43
- });
39
+ if (shouldCount(fetchParams)) {
40
+ const count = await strapi.entityService.count(uid, { ...fetchParams, ...paginationInfo });
44
41
 
45
42
  return {
46
43
  results,
@@ -54,30 +51,28 @@ const createCollectionTypeService = ({ model, strapi, utils }) => {
54
51
  };
55
52
  },
56
53
 
57
- findOne(entityId, opts = {}) {
58
- const params = getFetchParams(opts.params);
59
-
60
- return strapi.entityService.findOne(uid, entityId, { params });
54
+ findOne(entityId, params = {}) {
55
+ return strapi.entityService.findOne(uid, entityId, this.getFetchParams(params));
61
56
  },
62
57
 
63
- create({ params, data, files } = {}) {
64
- const sanitizedData = sanitizeInput(data);
58
+ create(params = {}) {
59
+ const { data } = params;
65
60
 
66
- if (hasDraftAndPublish(model)) {
67
- setPublishedAt(sanitizedData);
61
+ if (hasDraftAndPublish(contentType)) {
62
+ setPublishedAt(data);
68
63
  }
69
64
 
70
- return strapi.entityService.create(uid, { params, data: sanitizedData, files });
65
+ return strapi.entityService.create(uid, { ...params, data });
71
66
  },
72
67
 
73
- update(entityId, { params, data, files } = {}) {
74
- const sanitizedData = sanitizeInput(data);
68
+ update(entityId, params = {}) {
69
+ const { data } = params;
75
70
 
76
- return strapi.entityService.update(uid, entityId, { params, data: sanitizedData, files });
71
+ return strapi.entityService.update(uid, entityId, { ...params, data });
77
72
  },
78
73
 
79
- delete(entityId, { params } = {}) {
80
- return strapi.entityService.delete(uid, entityId, { params });
74
+ delete(entityId, params = {}) {
75
+ return strapi.entityService.delete(uid, entityId, params);
81
76
  },
82
77
  };
83
78
  };
@@ -0,0 +1,21 @@
1
+ type Entity = object;
2
+
3
+ interface BaseService {
4
+ getFetchParams(params: object): object;
5
+ }
6
+
7
+ export interface SingleTypeService extends BaseService {
8
+ find(params: object): Promise<Entity>;
9
+ createOrUpdate(params: object): Promise<Entity>;
10
+ delete(params: object): Promise<Entity>;
11
+ }
12
+
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>;
19
+ }
20
+
21
+ export type Service = SingleTypeService | CollectionTypeService;
@@ -1,10 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const _ = require('lodash');
4
-
5
3
  const {
6
4
  isSingleType,
7
- getNonWritableAttributes,
8
5
  constants: { DP_PUB_STATE_LIVE },
9
6
  } = require('@strapi/utils').contentTypes;
10
7
 
@@ -16,14 +13,18 @@ const createCollectionTypeService = require('./collection-type');
16
13
  * @param {{ model: object, strapi: object }} context
17
14
  * @returns {object}
18
15
  */
19
- const createService = ({ model, strapi }) => {
20
- const utils = createUtils({ model });
16
+ const createService = ({ contentType }) => {
17
+ const proto = { getFetchParams };
18
+
19
+ let service;
21
20
 
22
- if (isSingleType(model)) {
23
- return createSingleTypeService({ model, strapi, utils });
21
+ if (isSingleType(contentType)) {
22
+ service = createSingleTypeService({ contentType });
23
+ } else {
24
+ service = createCollectionTypeService({ contentType });
24
25
  }
25
26
 
26
- return createCollectionTypeService({ model, strapi, utils });
27
+ return Object.assign(Object.create(proto), service);
27
28
  };
28
29
 
29
30
  /**
@@ -38,17 +39,6 @@ const getFetchParams = (params = {}) => {
38
39
  };
39
40
  };
40
41
 
41
- /**
42
- * Mixins
43
- */
44
- const createUtils = ({ model }) => {
45
- return {
46
- // make sure to keep the call to getNonWritableAttributes dynamic
47
- sanitizeInput: data => _.omit(data, getNonWritableAttributes(model)),
48
- getFetchParams,
49
- };
50
- };
51
-
52
42
  module.exports = {
53
43
  createService,
54
44
  getFetchParams,
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { has, toNumber, isUndefined } = require('lodash/fp');
4
+ const { ValidationError } = require('@strapi/utils').errors;
4
5
 
5
6
  /**
6
7
  * Default limit values from config
@@ -41,7 +42,9 @@ const shouldCount = params => {
41
42
  return false;
42
43
  }
43
44
 
44
- throw new Error('Invalid withCount parameter. Expected "t","1","true","false","0","f"');
45
+ throw new ValidationError(
46
+ 'Invalid withCount parameter. Expected "t","1","true","false","0","f"'
47
+ );
45
48
  }
46
49
 
47
50
  return Boolean(strapi.config.get('api.rest.withCount', true));
@@ -66,7 +69,9 @@ const getPaginationInfo = params => {
66
69
  }
67
70
 
68
71
  if (isOffset && isPaged) {
69
- throw new Error('Invalid pagination parameters. Expected either start/limit or page/pageSize');
72
+ throw new ValidationError(
73
+ 'Invalid pagination parameters. Expected either start/limit or page/pageSize'
74
+ );
70
75
  }
71
76
 
72
77
  if (isPagedPagination(pagination)) {
@@ -1,21 +1,24 @@
1
1
  'use strict';
2
2
 
3
+ const { ValidationError } = require('@strapi/utils').errors;
4
+
3
5
  /**
4
6
  * Returns a single type service to handle default core-api actions
5
7
  */
6
- const createSingleTypeService = ({ model, strapi, utils }) => {
7
- const { uid } = model;
8
- const { sanitizeInput, getFetchParams } = utils;
8
+ const createSingleTypeService = ({ contentType }) => {
9
+ const { uid } = contentType;
9
10
 
11
+ /**
12
+ * @type {import('./').SingleTypeService}
13
+ */
10
14
  return {
11
15
  /**
12
16
  * Returns singleType content
13
17
  *
14
18
  * @return {Promise}
15
19
  */
16
- find({ params } = {}) {
17
- const normalizedParams = getFetchParams(params);
18
- return strapi.entityService.find(uid, { params: normalizedParams });
20
+ find(params = {}) {
21
+ return strapi.entityService.findMany(uid, this.getFetchParams(params));
19
22
  },
20
23
 
21
24
  /**
@@ -23,25 +26,19 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
23
26
  *
24
27
  * @return {Promise}
25
28
  */
26
- async createOrUpdate({ params, data, files } = {}) {
27
- const entity = await this.find({ params });
28
-
29
- const sanitizedData = sanitizeInput(data);
29
+ async createOrUpdate({ data, ...params } = {}) {
30
+ const entity = await this.find(params);
30
31
 
31
32
  if (!entity) {
32
33
  const count = await strapi.query(uid).count();
33
34
  if (count >= 1) {
34
- throw strapi.errors.badRequest('singleType.alreadyExists');
35
+ throw new ValidationError('singleType.alreadyExists');
35
36
  }
36
37
 
37
- return strapi.entityService.create(uid, { params, data: sanitizedData, files });
38
- } else {
39
- return strapi.entityService.update(uid, entity.id, {
40
- params,
41
- data: sanitizedData,
42
- files,
43
- });
38
+ return strapi.entityService.create(uid, { ...params, data });
44
39
  }
40
+
41
+ return strapi.entityService.update(uid, entity.id, { ...params, data });
45
42
  },
46
43
 
47
44
  /**
@@ -49,8 +46,8 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
49
46
  *
50
47
  * @return {Promise}
51
48
  */
52
- async delete({ params } = {}) {
53
- const entity = await this.find({ params });
49
+ async delete(params = {}) {
50
+ const entity = await this.find(params);
54
51
 
55
52
  if (!entity) return;
56
53
 
@@ -0,0 +1,48 @@
1
+ import { Service } from './core-api/service';
2
+ import { Controller } from './core-api/controller';
3
+ import { Middleware } from './middlewares';
4
+ import { Policy } from './core/registries/policies';
5
+
6
+ type ControllerConfig = Controller;
7
+
8
+ type ServiceConfig = Service;
9
+
10
+ type HandlerConfig = {
11
+ auth: false | { scope: string[] };
12
+ policies: Array<string | Policy>;
13
+ middlewares: Array<string | Middleware>;
14
+ };
15
+
16
+ type SingleTypeRouterConfig = {
17
+ find: HandlerConfig;
18
+ update: HandlerConfig;
19
+ delete: HandlerConfig;
20
+ };
21
+
22
+ type CollectionTypeRouterConfig = {
23
+ find: HandlerConfig;
24
+ findOne: HandlerConfig;
25
+ create: HandlerConfig;
26
+ update: HandlerConfig;
27
+ delete: HandlerConfig;
28
+ };
29
+
30
+ type RouterConfig = {
31
+ prefix: string;
32
+ only: string[];
33
+ except: string[];
34
+ config: SingleTypeRouterConfig | CollectionTypeRouterConfig;
35
+ };
36
+
37
+ interface Route {
38
+ method: string;
39
+ path: string;
40
+ }
41
+ interface Router {
42
+ prefix: string;
43
+ routes: Route[];
44
+ }
45
+
46
+ export function createCoreRouter(uid: string, cfg: RouterConfig): () => Router;
47
+ export function createCoreController(uid: string, cfg: ControllerConfig): () => Controller;
48
+ export function createCoreService(uid: string, cfg: ServiceConfig): () => Service;
@@ -0,0 +1,84 @@
1
+ 'use strict';
2
+
3
+ const { pipe, omit, pick } = require('lodash/fp');
4
+
5
+ const { createController } = require('./core-api/controller');
6
+ const { createService } = require('./core-api/service');
7
+ const { createRoutes } = require('./core-api/routes');
8
+
9
+ const createCoreController = (uid, cfg = {}) => {
10
+ return ({ strapi }) => {
11
+ const baseController = createController({
12
+ contentType: strapi.contentType(uid),
13
+ });
14
+
15
+ let userCtrl = typeof cfg === 'function' ? cfg({ strapi }) : cfg;
16
+
17
+ for (const methodName of Object.keys(baseController)) {
18
+ if (userCtrl[methodName] === undefined) {
19
+ userCtrl[methodName] = baseController[methodName];
20
+ }
21
+ }
22
+
23
+ Object.setPrototypeOf(userCtrl, baseController);
24
+ return userCtrl;
25
+ };
26
+ };
27
+
28
+ const createCoreService = (uid, cfg = {}) => {
29
+ return ({ strapi }) => {
30
+ const baseService = createService({
31
+ contentType: strapi.contentType(uid),
32
+ });
33
+
34
+ let userService = typeof cfg === 'function' ? cfg({ strapi }) : cfg;
35
+
36
+ for (const methodName of Object.keys(baseService)) {
37
+ if (userService[methodName] === undefined) {
38
+ userService[methodName] = baseService[methodName];
39
+ }
40
+ }
41
+
42
+ Object.setPrototypeOf(userService, baseService);
43
+ return userService;
44
+ };
45
+ };
46
+
47
+ const createCoreRouter = (uid, cfg = {}) => {
48
+ const { prefix, config = {}, only, except } = cfg;
49
+ let routes;
50
+
51
+ return {
52
+ get prefix() {
53
+ return prefix;
54
+ },
55
+ get routes() {
56
+ if (!routes) {
57
+ const contentType = strapi.contentType(uid);
58
+
59
+ const defaultRoutes = createRoutes({ contentType });
60
+
61
+ Object.keys(defaultRoutes).forEach(routeName => {
62
+ const defaultRoute = defaultRoutes[routeName];
63
+
64
+ Object.assign(defaultRoute.config, config[routeName] || {});
65
+ });
66
+
67
+ const selectedRoutes = pipe(
68
+ routes => (except ? omit(except, routes) : routes),
69
+ routes => (only ? pick(only, routes) : routes)
70
+ )(defaultRoutes);
71
+
72
+ routes = Object.values(selectedRoutes);
73
+ }
74
+
75
+ return routes;
76
+ },
77
+ };
78
+ };
79
+
80
+ module.exports = {
81
+ createCoreController,
82
+ createCoreService,
83
+ createCoreRouter,
84
+ };
package/lib/index.d.ts CHANGED
@@ -1,40 +1,15 @@
1
1
  import { Database } from '@strapi/database';
2
- import { Strapi } from './Strapi';
2
+ import { EntityService } from './services/entity-service';
3
+ import { Strapi as StrapiClass } from './Strapi';
3
4
 
4
- type ID = number | string;
5
-
6
- interface Options<T> {
7
- params: Params<T>;
8
- }
9
-
10
- interface Params<T> {
11
- fields: (keyof T)[];
12
- }
13
-
14
- interface EntityService {
15
- uploadFiles<T extends keyof AllTypes>(uid: T);
16
- wrapOptions<T extends keyof AllTypes>(uid: T);
17
-
18
- find<T extends keyof AllTypes>(uid: T): Promise<AllTypes[T][]>;
19
- findPage<T extends keyof AllTypes>(uid: T): Promise<any>;
20
- findWithRelationCounts<T extends keyof AllTypes>(uid: T): Promise<any>;
21
- findOne<T extends keyof AllTypes>(
22
- uid: T,
23
- id: ID,
24
- opts: Options<AllTypes[T]>
25
- ): Promise<AllTypes[T]>;
26
-
27
- count<T extends keyof AllTypes>(uid: T): Promise<any>;
28
- create<T extends keyof AllTypes>(uid: T): Promise<any>;
29
- update<T extends keyof AllTypes>(uid: T): Promise<any>;
30
- delete<T extends keyof AllTypes>(uid: T): Promise<any>;
31
- }
32
-
33
- interface StrapiInterface extends Strapi {
5
+ export * as factories from './factories';
6
+ interface StrapiInterface extends StrapiClass {
34
7
  query: Database['query'];
35
8
  entityService: EntityService;
36
9
  }
37
10
 
11
+ export type Strapi = StrapiInterface;
12
+
38
13
  declare global {
39
14
  interface AllTypes {}
40
15
  }
@@ -44,5 +19,9 @@ declare global {
44
19
  strapi: StrapiInterface;
45
20
  }
46
21
 
22
+ export type Strapi = StrapiInterface;
23
+
47
24
  const strapi: StrapiInterface;
48
25
  }
26
+
27
+ export default function(opts): Strapi;
package/lib/index.js CHANGED
@@ -1,3 +1,7 @@
1
1
  'use strict';
2
2
 
3
- module.exports = require('./Strapi');
3
+ const Strapi = require('./Strapi');
4
+
5
+ Strapi.factories = require('./factories');
6
+
7
+ module.exports = Strapi;
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ const { defaultsDeep } = require('lodash/fp');
4
+ const body = require('koa-body');
5
+
6
+ const defaults = {
7
+ multipart: true,
8
+ patchKoa: true,
9
+ };
10
+
11
+ /**
12
+ * @type {import('./').MiddlewareFactory}
13
+ */
14
+ module.exports = config => {
15
+ const bodyConfig = defaultsDeep(defaults, config);
16
+
17
+ return async (ctx, next) => {
18
+ // TODO: find a better way later
19
+ if (ctx.url === '/graphql') {
20
+ return next();
21
+ }
22
+
23
+ try {
24
+ await body({ patchKoa: true, ...bodyConfig })(ctx, next);
25
+ } catch (e) {
26
+ if ((e || {}).message && e.message.includes('maxFileSize exceeded')) {
27
+ return ctx.payloadTooLarge('FileTooBig');
28
+ }
29
+
30
+ throw e;
31
+ }
32
+ };
33
+ };
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ const compress = require('koa-compress');
4
+
5
+ /**
6
+ * @type {import('./').MiddlewareFactory}
7
+ */
8
+ module.exports = config => compress(config);
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ const { defaultsDeep } = require('lodash/fp');
4
+ const cors = require('@koa/cors');
5
+
6
+ const defaults = {
7
+ origin: '*',
8
+ maxAge: 31536000,
9
+ credentials: true,
10
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
11
+ headers: ['Content-Type', 'Authorization', 'Origin', 'Accept'],
12
+ keepHeadersOnError: false,
13
+ };
14
+
15
+ /**
16
+ * @type {import('./').MiddlewareFactory}
17
+ */
18
+ module.exports = config => {
19
+ const {
20
+ origin,
21
+ expose,
22
+ maxAge,
23
+ credentials,
24
+ methods,
25
+ headers,
26
+ keepHeadersOnError,
27
+ } = defaultsDeep(defaults, config);
28
+
29
+ return cors({
30
+ async origin(ctx) {
31
+ let originList;
32
+
33
+ if (typeof origin === 'function') {
34
+ originList = await origin(ctx);
35
+ } else {
36
+ originList = origin;
37
+ }
38
+
39
+ const whitelist = Array.isArray(originList) ? originList : originList.split(/\s*,\s*/);
40
+
41
+ const requestOrigin = ctx.accept.headers.origin;
42
+ if (whitelist.includes('*')) {
43
+ return '*';
44
+ }
45
+
46
+ if (!whitelist.includes(requestOrigin)) {
47
+ return ctx.throw(`${requestOrigin} is not a valid origin`);
48
+ }
49
+ return requestOrigin;
50
+ },
51
+ exposeHeaders: expose,
52
+ maxAge,
53
+ credentials,
54
+ allowMethods: methods,
55
+ allowHeaders: headers,
56
+ keepHeadersOnError,
57
+ });
58
+ };