@strapi/strapi 4.0.0-next.11 → 4.0.0-next.15

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 (51) hide show
  1. package/bin/strapi.js +1 -4
  2. package/lib/Strapi.js +82 -28
  3. package/lib/commands/console.js +1 -1
  4. package/lib/commands/develop.js +4 -3
  5. package/lib/core/domain/content-type/index.js +3 -7
  6. package/lib/core/domain/module/index.js +2 -2
  7. package/lib/core/loaders/apis.js +4 -6
  8. package/lib/core/loaders/components.js +3 -5
  9. package/lib/core/loaders/index.js +1 -0
  10. package/lib/core/loaders/middlewares.js +1 -1
  11. package/lib/core/loaders/plugins/get-enabled-plugins.js +2 -2
  12. package/lib/core/loaders/plugins/index.js +7 -7
  13. package/lib/core/loaders/policies.js +1 -1
  14. package/lib/core/loaders/src-index.js +38 -0
  15. package/lib/core/registries/hooks.js +37 -0
  16. package/lib/core/registries/services.js +7 -7
  17. package/lib/core-api/controller/collection-type.js +5 -5
  18. package/lib/core-api/controller/single-type.js +3 -3
  19. package/lib/core-api/controller/transform.js +28 -3
  20. package/lib/core-api/service/collection-type.js +18 -19
  21. package/lib/core-api/service/single-type.js +10 -14
  22. package/lib/index.d.ts +9 -31
  23. package/lib/middlewares/cors/index.js +1 -1
  24. package/lib/middlewares/{boom → error}/defaults.json +1 -1
  25. package/lib/middlewares/{boom → error}/index.js +1 -1
  26. package/lib/middlewares/favicon/index.js +1 -2
  27. package/lib/middlewares/index.js +1 -1
  28. package/lib/middlewares/public/index.js +2 -2
  29. package/lib/middlewares/responses/index.js +2 -1
  30. package/lib/middlewares/router/index.js +5 -3
  31. package/lib/migrations/draft-publish.js +57 -0
  32. package/lib/services/auth/index.js +2 -2
  33. package/lib/services/core-store.js +64 -49
  34. package/lib/services/cron.js +54 -0
  35. package/lib/services/entity-service/components.js +37 -12
  36. package/lib/services/entity-service/index.d.ts +91 -0
  37. package/lib/services/entity-service/index.js +52 -50
  38. package/lib/services/entity-service/params.js +74 -57
  39. package/lib/services/fs.js +1 -1
  40. package/lib/services/metrics/index.js +1 -1
  41. package/lib/services/server/policy.js +15 -4
  42. package/lib/services/webhook-runner.js +1 -1
  43. package/lib/utils/ee.js +3 -3
  44. package/lib/utils/get-dirs.js +15 -0
  45. package/lib/utils/index.js +2 -0
  46. package/lib/utils/update-notifier/index.js +2 -1
  47. package/package.json +88 -98
  48. package/lib/middlewares/cron/defaults.json +0 -5
  49. package/lib/middlewares/cron/index.js +0 -43
  50. package/lib/middlewares/language/defaults.json +0 -9
  51. package/lib/middlewares/language/index.js +0 -40
@@ -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
 
@@ -28,19 +28,18 @@ const createCollectionTypeService = ({ model, strapi, utils }) => {
28
28
  const { sanitizeInput, getFetchParams } = utils;
29
29
 
30
30
  return {
31
- async find(opts = {}) {
32
- const params = getFetchParams(opts.params);
31
+ async find(params = {}) {
32
+ const fetchParams = getFetchParams(params);
33
33
 
34
- const paginationInfo = getPaginationInfo(params);
34
+ const paginationInfo = getPaginationInfo(fetchParams);
35
35
 
36
- const results = await strapi.entityService.find(uid, {
37
- params: { ...params, ...convertPagedToStartLimit(paginationInfo) },
36
+ const results = await strapi.entityService.findMany(uid, {
37
+ ...fetchParams,
38
+ ...convertPagedToStartLimit(paginationInfo),
38
39
  });
39
40
 
40
- if (shouldCount(params)) {
41
- const count = await strapi.entityService.count(uid, {
42
- params: { ...params, ...paginationInfo },
43
- });
41
+ if (shouldCount(fetchParams)) {
42
+ const count = await strapi.entityService.count(uid, { ...fetchParams, ...paginationInfo });
44
43
 
45
44
  return {
46
45
  results,
@@ -54,30 +53,30 @@ const createCollectionTypeService = ({ model, strapi, utils }) => {
54
53
  };
55
54
  },
56
55
 
57
- findOne(entityId, opts = {}) {
58
- const params = getFetchParams(opts.params);
59
-
60
- return strapi.entityService.findOne(uid, entityId, { params });
56
+ findOne(entityId, params = {}) {
57
+ return strapi.entityService.findOne(uid, entityId, getFetchParams(params));
61
58
  },
62
59
 
63
- create({ params, data, files } = {}) {
60
+ create(params = {}) {
61
+ const { data } = params;
64
62
  const sanitizedData = sanitizeInput(data);
65
63
 
66
64
  if (hasDraftAndPublish(model)) {
67
65
  setPublishedAt(sanitizedData);
68
66
  }
69
67
 
70
- return strapi.entityService.create(uid, { params, data: sanitizedData, files });
68
+ return strapi.entityService.create(uid, { ...params, data: sanitizedData });
71
69
  },
72
70
 
73
- update(entityId, { params, data, files } = {}) {
71
+ update(entityId, params = {}) {
72
+ const { data } = params;
74
73
  const sanitizedData = sanitizeInput(data);
75
74
 
76
- return strapi.entityService.update(uid, entityId, { params, data: sanitizedData, files });
75
+ return strapi.entityService.update(uid, entityId, { ...params, data: sanitizedData });
77
76
  },
78
77
 
79
- delete(entityId, { params } = {}) {
80
- return strapi.entityService.delete(uid, entityId, { params });
78
+ delete(entityId, params = {}) {
79
+ return strapi.entityService.delete(uid, entityId, params);
81
80
  },
82
81
  };
83
82
  };
@@ -13,9 +13,8 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
13
13
  *
14
14
  * @return {Promise}
15
15
  */
16
- find({ params } = {}) {
17
- const normalizedParams = getFetchParams(params);
18
- return strapi.entityService.find(uid, { params: normalizedParams });
16
+ find(params = {}) {
17
+ return strapi.entityService.findMany(uid, getFetchParams(params));
19
18
  },
20
19
 
21
20
  /**
@@ -23,9 +22,10 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
23
22
  *
24
23
  * @return {Promise}
25
24
  */
26
- async createOrUpdate({ params, data, files } = {}) {
27
- const entity = await this.find({ params });
25
+ async createOrUpdate(params = {}) {
26
+ const entity = await this.find(params);
28
27
 
28
+ const { data } = params;
29
29
  const sanitizedData = sanitizeInput(data);
30
30
 
31
31
  if (!entity) {
@@ -34,14 +34,10 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
34
34
  throw strapi.errors.badRequest('singleType.alreadyExists');
35
35
  }
36
36
 
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
- });
37
+ return strapi.entityService.create(uid, { ...params, data: sanitizedData });
44
38
  }
39
+
40
+ return strapi.entityService.update(uid, entity.id, { ...params, data: sanitizedData });
45
41
  },
46
42
 
47
43
  /**
@@ -49,8 +45,8 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
49
45
  *
50
46
  * @return {Promise}
51
47
  */
52
- async delete({ params } = {}) {
53
- const entity = await this.find({ params });
48
+ async delete(params = {}) {
49
+ const entity = await this.find(params);
54
50
 
55
51
  if (!entity) return;
56
52
 
package/lib/index.d.ts CHANGED
@@ -1,40 +1,14 @@
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
+ interface StrapiInterface extends StrapiClass {
34
6
  query: Database['query'];
35
7
  entityService: EntityService;
36
8
  }
37
9
 
10
+ export type Strapi = StrapiInterface;
11
+
38
12
  declare global {
39
13
  interface AllTypes {}
40
14
  }
@@ -44,5 +18,9 @@ declare global {
44
18
  strapi: StrapiInterface;
45
19
  }
46
20
 
21
+ export type Strapi = StrapiInterface;
22
+
47
23
  const strapi: StrapiInterface;
48
24
  }
25
+
26
+ export default function(opts): Strapi;
@@ -32,7 +32,7 @@ module.exports = strapi => {
32
32
 
33
33
  strapi.server.use(
34
34
  cors({
35
- origin: async function(ctx) {
35
+ async origin(ctx) {
36
36
  let originList;
37
37
 
38
38
  if (typeof origin === 'function') {
@@ -1,5 +1,5 @@
1
1
  {
2
- "boom": {
2
+ "error": {
3
3
  "enabled": true
4
4
  }
5
5
  }
@@ -6,7 +6,7 @@
6
6
 
7
7
  // Public node modules.
8
8
  const _ = require('lodash');
9
- const Boom = require('boom');
9
+ const Boom = require('@hapi/boom');
10
10
  const delegate = require('delegates');
11
11
 
12
12
  const boomMethods = [
@@ -19,11 +19,10 @@ module.exports = strapi => {
19
19
  */
20
20
 
21
21
  initialize() {
22
- const { dir } = strapi;
23
22
  const { maxAge, path: faviconPath } = strapi.config.middleware.settings.favicon;
24
23
 
25
24
  strapi.server.use(
26
- favicon(resolve(dir, faviconPath), {
25
+ favicon(resolve(strapi.dirs.root, faviconPath), {
27
26
  maxAge,
28
27
  })
29
28
  );
@@ -7,7 +7,7 @@ const requiredMiddlewares = [
7
7
  'responses',
8
8
  'router',
9
9
  'logger',
10
- 'boom',
10
+ 'error',
11
11
  'cors',
12
12
  'cron',
13
13
  'xframe',
@@ -25,7 +25,7 @@ module.exports = strapi => {
25
25
 
26
26
  async initialize() {
27
27
  const { defaultIndex, maxAge, path: publicPath } = strapi.config.middleware.settings.public;
28
- const staticDir = path.resolve(strapi.dir, publicPath || strapi.config.paths.static);
28
+ const staticDir = path.resolve(strapi.dirs.root, publicPath || strapi.config.paths.static);
29
29
 
30
30
  if (defaultIndex === true) {
31
31
  const index = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
@@ -98,7 +98,7 @@ module.exports = strapi => {
98
98
 
99
99
  if (!strapi.config.serveAdminPanel) return;
100
100
 
101
- const buildDir = path.resolve(strapi.dir, 'build');
101
+ const buildDir = path.resolve(strapi.dirs.root, 'build');
102
102
  const serveAdmin = async (ctx, next) => {
103
103
  await next();
104
104
 
@@ -8,7 +8,8 @@ module.exports = strapi => {
8
8
  strapi.server.use(async (ctx, next) => {
9
9
  await next();
10
10
 
11
- const responseFn = strapi.config.get(['functions', 'responses', ctx.status]);
11
+ const status = ctx.status;
12
+ const responseFn = strapi.config.get(`middleware.settings.responses.handlers.${status}`);
12
13
  if (_.isFunction(responseFn)) {
13
14
  await responseFn(ctx);
14
15
  }
@@ -9,9 +9,11 @@ const createRouteScopeGenerator = namespace => route => {
9
9
  if (typeof route.handler === 'string') {
10
10
  const [controller, action] = route.handler.split('.');
11
11
 
12
- _.defaultsDeep(route.config, {
13
- auth: {
14
- scope: `${prefix}${controller}.${toLower(action)}`,
12
+ _.defaultsDeep(route, {
13
+ config: {
14
+ auth: {
15
+ scope: `${prefix}${controller}.${toLower(action)}`,
16
+ },
15
17
  },
16
18
  });
17
19
  }
@@ -0,0 +1,57 @@
1
+ 'use strict';
2
+
3
+ const { hasDraftAndPublish } = require('@strapi/utils').contentTypes;
4
+
5
+ const enableDraftAndPublish = async ({ oldContentTypes, contentTypes }) => {
6
+ if (!oldContentTypes) {
7
+ return;
8
+ }
9
+ // run the after content types migrations
10
+
11
+ for (const uid in contentTypes) {
12
+ if (!oldContentTypes[uid]) {
13
+ continue;
14
+ }
15
+
16
+ const oldContentType = oldContentTypes[uid];
17
+ const contentType = contentTypes[uid];
18
+
19
+ // if d&p was enabled set publishedAt to eq createdAt
20
+ if (!hasDraftAndPublish(oldContentType) && hasDraftAndPublish(contentType)) {
21
+ const qb = strapi.db.queryBuilder(uid);
22
+ await qb
23
+ .update({ publishedAt: qb.ref('createdAt') })
24
+ .where({ publishedAt: null })
25
+ .execute();
26
+ }
27
+ }
28
+ };
29
+
30
+ const disableDraftAndPublish = async ({ oldContentTypes, contentTypes }) => {
31
+ if (!oldContentTypes) {
32
+ return;
33
+ }
34
+
35
+ for (const uid in contentTypes) {
36
+ if (!oldContentTypes[uid]) {
37
+ continue;
38
+ }
39
+
40
+ const oldContentType = oldContentTypes[uid];
41
+ const contentType = contentTypes[uid];
42
+
43
+ // if d&p was disabled remove unpublish content before sync
44
+ if (hasDraftAndPublish(oldContentType) && !hasDraftAndPublish(contentType)) {
45
+ await strapi.db
46
+ .queryBuilder(uid)
47
+ .delete()
48
+ .where({ publishedAt: null })
49
+ .execute();
50
+ }
51
+ }
52
+ };
53
+
54
+ module.exports = {
55
+ enable: enableDraftAndPublish,
56
+ disable: disableDraftAndPublish,
57
+ };
@@ -69,7 +69,7 @@ const createAuthentication = () => {
69
69
  }
70
70
  }
71
71
 
72
- return ctx.unauthorized('Missing credentials');
72
+ return ctx.unauthorized('Missing or invalid credentials');
73
73
  },
74
74
  async verify(auth, config = {}) {
75
75
  if (config === false) {
@@ -81,7 +81,7 @@ const createAuthentication = () => {
81
81
  }
82
82
 
83
83
  if (typeof auth.strategy.verify === 'function') {
84
- return await auth.strategy.verify(auth, config);
84
+ return auth.strategy.verify(auth, config);
85
85
  }
86
86
 
87
87
  return;
@@ -22,21 +22,37 @@ const coreStoreModel = {
22
22
  },
23
23
  };
24
24
 
25
- const createCoreStore = ({ environment: defaultEnv, db }) => {
26
- return (source = {}) => {
27
- async function get(params = {}) {
28
- const { key, environment = defaultEnv, type = 'core', name = '', tag = '' } = Object.assign(
29
- {},
30
- source,
31
- params
32
- );
25
+ const createCoreStore = ({ db }) => {
26
+ const mergeParams = (defaultParams, params) => {
27
+ return {
28
+ ...defaultParams,
29
+ ...params,
30
+ };
31
+ };
32
+
33
+ const store = function(defaultParams = {}) {
34
+ return {
35
+ get: params => store.get(mergeParams(defaultParams, params)),
36
+ set: params => store.set(mergeParams(defaultParams, params)),
37
+ delete: params => store.delete(mergeParams(defaultParams, params)),
38
+ };
39
+ };
40
+
41
+ Object.assign(store, {
42
+ /**
43
+ * Get value from the core store
44
+ * @param {Object} params
45
+ * @returns {*}
46
+ */
47
+ async get(params = {}) {
48
+ const { key, type = 'core', environment, name, tag } = params;
33
49
 
34
50
  const prefix = `${type}${name ? `_${name}` : ''}`;
35
51
 
36
52
  const where = {
37
53
  key: `${prefix}_${key}`,
38
- environment,
39
- tag,
54
+ environment: environment || null,
55
+ tag: tag || null,
40
56
  };
41
57
 
42
58
  const data = await db.query('strapi::core-store').findOne({ where });
@@ -57,71 +73,70 @@ const createCoreStore = ({ environment: defaultEnv, db }) => {
57
73
  return new Date(data.value);
58
74
  }
59
75
  } else if (data.type === 'number') {
60
- return parseFloat(data.value);
76
+ return Number(data.value);
61
77
  } else {
62
78
  return null;
63
79
  }
64
- }
80
+ },
65
81
 
66
- async function set(params = {}) {
67
- const { key, value, environment = defaultEnv, type, name, tag = '' } = Object.assign(
68
- {},
69
- source,
70
- params
71
- );
82
+ /**
83
+ * Set value in the core store
84
+ * @param {Object} params
85
+ * @returns {*}
86
+ */
87
+ async set(params = {}) {
88
+ const { key, value, type, environment, name, tag } = params;
72
89
 
73
90
  const prefix = `${type}${name ? `_${name}` : ''}`;
74
91
 
75
92
  const where = {
76
93
  key: `${prefix}_${key}`,
77
- environment,
78
- tag,
94
+ environment: environment || null,
95
+ tag: tag || null,
79
96
  };
80
97
 
81
98
  const data = await db.query('strapi::core-store').findOne({ where });
82
99
 
83
100
  if (data) {
84
- Object.assign(data, {
85
- value: JSON.stringify(value) || value.toString(),
86
- type: (typeof value).toString(),
101
+ return db.query('strapi::core-store').update({
102
+ where: { id: data.id },
103
+ data: {
104
+ value: JSON.stringify(value) || value.toString(),
105
+ type: typeof value,
106
+ },
87
107
  });
108
+ }
88
109
 
89
- await db.query('strapi::core-store').update({ where: { id: data.id }, data });
90
- } else {
91
- const data = Object.assign({}, where, {
110
+ return db.query('strapi::core-store').create({
111
+ data: {
112
+ ...where,
92
113
  value: JSON.stringify(value) || value.toString(),
93
- type: (typeof value).toString(),
94
- tag,
95
- });
96
-
97
- await db.query('strapi::core-store').create({ data });
98
- }
99
- }
114
+ type: typeof value,
115
+ },
116
+ });
117
+ },
100
118
 
101
- async function deleteFn(params = {}) {
102
- const { key, environment = defaultEnv, type, name, tag = '' } = Object.assign(
103
- {},
104
- source,
105
- params
106
- );
119
+ /**
120
+ * Deletes a value from the core store
121
+ * @param {Object} params
122
+ * @returns {*}
123
+ */
124
+ async delete(params = {}) {
125
+ const { key, environment, type, name, tag } = params;
107
126
 
108
127
  const prefix = `${type}${name ? `_${name}` : ''}`;
109
128
 
110
129
  const where = {
111
130
  key: `${prefix}_${key}`,
112
- environment,
113
- tag,
131
+ environment: environment || null,
132
+ tag: tag || null,
114
133
  };
115
134
 
116
- await db.query('strapi::core-store').delete({ where });
117
- }
135
+ return db.query('strapi::core-store').delete({ where });
136
+ },
137
+ });
118
138
 
119
- return {
120
- get,
121
- set,
122
- delete: deleteFn,
123
- };
124
- };
139
+ return store;
125
140
  };
126
141
 
127
142
  module.exports = {
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ const { Job } = require('node-schedule');
4
+ const { isFunction } = require('lodash/fp');
5
+
6
+ const createCronService = () => {
7
+ let jobsSpecs = [];
8
+
9
+ return {
10
+ add(tasks = {}) {
11
+ for (const taskExpression in tasks) {
12
+ const taskValue = tasks[taskExpression];
13
+
14
+ let fn;
15
+ let options;
16
+ if (isFunction(taskValue)) {
17
+ fn = taskValue.bind(tasks);
18
+ options = taskExpression;
19
+ } else if (isFunction(taskValue.task)) {
20
+ fn = taskValue.task.bind(taskValue);
21
+ options = taskValue.options;
22
+ } else {
23
+ throw new Error(
24
+ `Could not schedule a cron job for "${taskExpression}": no function found.`
25
+ );
26
+ }
27
+
28
+ const fnWithStrapi = (...args) => fn({ strapi }, ...args);
29
+
30
+ const job = new Job(null, fnWithStrapi);
31
+ jobsSpecs.push({ job, options });
32
+ }
33
+ return this;
34
+ },
35
+ start() {
36
+ if (!strapi.config.get('server.cron.enabled')) {
37
+ return;
38
+ }
39
+ jobsSpecs.forEach(({ job, options }) => job.schedule(options));
40
+ return this;
41
+ },
42
+ stop() {
43
+ jobsSpecs.forEach(({ job }) => job.cancel());
44
+ return this;
45
+ },
46
+ destroy() {
47
+ this.stop();
48
+ jobsSpecs = [];
49
+ return this;
50
+ },
51
+ };
52
+ };
53
+
54
+ module.exports = createCronService;