ti2 1.0.14 → 1.0.17

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.
@@ -1,6 +1,19 @@
1
1
  const jwt = require('jwt-promise');
2
2
  const { omit } = require('ramda');
3
+ const assert = require('assert');
4
+ const { Umzug, SequelizeStorage } = require('umzug');
5
+ const path = require('path');
6
+ const Sequelize = require('sequelize');
7
+ const fs = require('fs').promises;
8
+ const bb = require('bluebird');
9
+ const R = require('ramda');
10
+
3
11
  const sqldb = require('../models');
12
+ const {
13
+ queue,
14
+ addJob,
15
+ jobStatus,
16
+ } = require('../worker/queue');
4
17
 
5
18
  const { env: { jwtSecret } } = process;
6
19
 
@@ -42,6 +55,61 @@ const createAppToken = async (req, res, next) => {
42
55
  });
43
56
  if (userAppKeyDup) await userAppKeyDup.destroy();
44
57
  const newAppKey = await sqldb.UserAppKey.create(payload);
58
+ // create any cronjobs related to the app
59
+ await bb.each(req.app.plugins, async plugin => {
60
+ if (Array.isArray(plugin.jobs)) {
61
+ await bb.each(plugin.jobs.filter(job => Boolean(job.cron)), async job => {
62
+ const where = {
63
+ pluginName: plugin.name,
64
+ pluginJobId: job.method,
65
+ userId,
66
+ hint,
67
+ cron: job.cron,
68
+ };
69
+ const existing = await sqldb.CronJobs.findOne({
70
+ where: R.omit(['cron'], where),
71
+ });
72
+ const jobPayload = {
73
+ ...where,
74
+ ...job.payload,
75
+ };
76
+ const jobParams = {
77
+ ...(job.cron ? {
78
+ repeat: {
79
+ cron: job.cron,
80
+ },
81
+ } : {}),
82
+ ...(job.params || {}),
83
+ removeOnComplete: false,
84
+ };
85
+ let bullJobId;
86
+ if (existing) {
87
+ const bullJob = await queue.getJob(job.bullJobId);
88
+ if (!bullJob) {
89
+ bullJobId = await addJob(jobPayload, jobParams);
90
+ existing.bullJobId = bullJobId;
91
+ await existing.save();
92
+ } else {
93
+ // make sure the cron is the same
94
+ const bullCron = R.path(
95
+ ['opts', 'repeat', 'cron'],
96
+ await queue.getJob(bullJobId),
97
+ );
98
+ if (bullCron !== job.cron) {
99
+ await queue.removeJobs(bullJobId);
100
+ bullJobId = await addJob(jobPayload, jobParams);
101
+ existing.bullJobId = bullJobId;
102
+ await existing.save();
103
+ }
104
+ }
105
+ } else {
106
+ bullJobId = await addJob(jobPayload, jobParams);
107
+ await sqldb.CronJobs.create({ ...where, bullJobId });
108
+ }
109
+ });
110
+ }
111
+ });
112
+
45
113
  return res.json({ value: newAppKey.get('id').toString() });
46
114
  } catch (err) {
47
115
  return next(err);
@@ -83,9 +151,114 @@ const listAppTokens = async (req, res, next) => {
83
151
  }
84
152
  };
85
153
 
154
+ const migrateApp = async ({ integrationId, action }) => {
155
+ const { sequelize } = sqldb;
156
+ assert(integrationId);
157
+ assert(action);
158
+ const migrationsPath = path.join(
159
+ __dirname,
160
+ '../',
161
+ '../',
162
+ `ti2-${integrationId}`,
163
+ 'migrations',
164
+ );
165
+ try {
166
+ await fs.access(migrationsPath);
167
+ } catch (err) {
168
+ throw Error(`Could not find any migrations for ${integrationId} on ${migrationsPath}`);
169
+ }
170
+ const umzug = new Umzug({
171
+ migrations: {
172
+ glob: `${migrationsPath}/*.js`,
173
+ resolve: ({ name, path: migPath, context }) => {
174
+ const migration = require(migPath);
175
+ return {
176
+ name,
177
+ up: async () => migration.up(context, Sequelize),
178
+ down: async () => migration.down(context, Sequelize),
179
+ };
180
+ },
181
+ },
182
+ context: sequelize.getQueryInterface(),
183
+ storage: new SequelizeStorage({
184
+ sequelize,
185
+ tableName: `SequelizeMeta-${integrationId}`,
186
+ }),
187
+ logger: console,
188
+ });
189
+ if (action === 'migrate') {
190
+ return umzug.up();
191
+ }
192
+ if (action === 'revert') {
193
+ return umzug.down({ to: 0 });
194
+ }
195
+ throw Error('No recognized action');
196
+ };
197
+
198
+ const getAppScheduledJobs = async ({
199
+ integrationId,
200
+ userId,
201
+ hint,
202
+ }) => {
203
+ const where = R.reject(R.isNil)({
204
+ pluginName: integrationId,
205
+ userId,
206
+ hint,
207
+ });
208
+ const jobs = await sqldb.CronJobs.findAll({
209
+ where,
210
+ raw: true,
211
+ });
212
+ return { jobs };
213
+ };
214
+
215
+ const runAppJob = async (req, res, next) => {
216
+ const {
217
+ body: {
218
+ payload,
219
+ jobParams,
220
+ },
221
+ params: {
222
+ app: pluginName,
223
+ hint,
224
+ userId,
225
+ },
226
+ } = req;
227
+ try {
228
+ const bullJobId = await addJob({
229
+ ...payload,
230
+ pluginName,
231
+ hint,
232
+ userId,
233
+ }, jobParams);
234
+ assert(bullJobId);
235
+ return res.json(await jobStatus({ jobId: bullJobId }));
236
+ } catch (err) {
237
+ return next(err);
238
+ }
239
+ };
240
+
241
+ const getJobStatus = async (req, res, next) => {
242
+ const {
243
+ params: {
244
+ jobId,
245
+ },
246
+ } = req;
247
+ try {
248
+ const returnValue = await jobStatus({ jobId });
249
+ return res.json(returnValue);
250
+ } catch (err) {
251
+ return next(err);
252
+ }
253
+ };
254
+
86
255
  module.exports = {
87
- jwtEncode,
88
256
  createAppToken,
89
257
  deleteAppToken,
258
+ getAppScheduledJobs,
259
+ getJobStatus,
260
+ jwtEncode,
90
261
  listAppTokens,
262
+ migrateApp,
263
+ runAppJob,
91
264
  };
@@ -110,6 +110,33 @@ const bookingsAvailabilitySearch = plugins => async (req, res, next) => {
110
110
  }
111
111
  };
112
112
 
113
+ const bookingsAvailabilityCalendar = plugins => async (req, res, next) => {
114
+ const {
115
+ params: { appKey, userId, hint },
116
+ body: payload,
117
+ } = req;
118
+ try {
119
+ const app = plugins.find(({ name }) => name === appKey);
120
+ // const app = load(appKey);
121
+ const userAppKeys = (await UserAppKey.findOne({
122
+ where: {
123
+ userId,
124
+ integrationId: appKey,
125
+ ...(hint ? { hint } : {}),
126
+ },
127
+ }));
128
+ assert(userAppKeys, 'could not find the app key');
129
+ const token = userAppKeys.appKey;
130
+ const results = await app.availabilityCalendar({
131
+ token,
132
+ payload,
133
+ });
134
+ return res.json(results);
135
+ } catch (err) {
136
+ return next(err);
137
+ }
138
+ };
139
+
113
140
  const searchQuote = plugins => async (req, res, next) => {
114
141
  const {
115
142
  params: { appKey, userId, hint },
@@ -171,6 +198,7 @@ module.exports = plugins => ({
171
198
  bookingsCancel: bookingsCancel(plugins),
172
199
  bookingsProductSearch: bookingsProductSearch(plugins),
173
200
  bookingsAvailabilitySearch: bookingsAvailabilitySearch(plugins),
201
+ bookingsAvailabilityCalendar: bookingsAvailabilityCalendar(plugins),
174
202
  searchQuote: searchQuote(plugins),
175
203
  createBooking: createBooking(plugins),
176
204
  });
@@ -20,7 +20,8 @@ const ping = (_req, res, next) => {
20
20
  });
21
21
  } catch (err) {
22
22
  return next(err);
23
- } };
23
+ }
24
+ };
24
25
 
25
26
  module.exports = {
26
27
  ping,
@@ -1,11 +1,7 @@
1
1
  // controllers/user.js
2
- const { omit, flatten } = require('ramda');
3
- const assert = require('assert');
4
- const Promise = require('bluebird');
5
- const moment = require('moment');
2
+ const { omit } = require('ramda');
6
3
 
7
- const { UserAppKey, Sequelize: { Op } } = require('../models');
8
- // const { load } = require('../../plugins/index.js');
4
+ const { UserAppKey } = require('../models');
9
5
 
10
6
  const userAppList = async (req, res, next) => {
11
7
  const { params: { userId } } = req;
package/index.js CHANGED
@@ -5,6 +5,9 @@ const swaggerUi = require('swagger-ui-express');
5
5
  const yaml = require('js-yaml');
6
6
  const fs = require('fs');
7
7
  const { pickBy } = require('ramda');
8
+ const bb = require('bluebird');
9
+ const { Op } = require('sequelize');
10
+ const R = require('ramda');
8
11
 
9
12
  const schema = yaml.load(fs.readFileSync(`${__dirname}/api.yml`));
10
13
 
@@ -14,18 +17,20 @@ const adminController = require('./controllers/admin');
14
17
  const appController = require('./controllers/app');
15
18
  const userController = require('./controllers/user');
16
19
  const bookingsController = require('./controllers/bookings');
20
+ const { Integration } = require('./models');
17
21
 
18
- module.exports = ({
22
+ module.exports = async ({
19
23
  apiDocs = true,
20
24
  elasticLogIndex = 'apilog_ti2',
21
25
  elasticLogsClient,
22
26
  plugins: pluginsParam = {},
23
27
  port: portParam,
24
28
  startServer = true,
29
+ worker = false,
25
30
  }) => {
26
31
  const port = portParam || process.env.PORT || 10010;
27
- const app = express();
28
- const plugins = Object.entries(pluginsParam).map(([pluginName, Plugin]) => {
32
+ // create the plugin instances
33
+ const plugins = await bb.map(Object.entries(pluginsParam), async ([pluginName, Plugin]) => {
29
34
  // pass all env variables
30
35
  const pluginEnv = pickBy(
31
36
  (_val, key) => key.substring(0, `ti2_${pluginName}`.length)
@@ -37,9 +42,34 @@ module.exports = ({
37
42
  const nuName = attr.replace(/_/g, '-').replace(`ti2-${pluginName}-`, '');
38
43
  params[nuName] = value;
39
44
  });
40
- return new Plugin({ name: pluginName, ...params });
45
+ const pluginInstance = await new Plugin({ name: pluginName, ...params });
46
+ return pluginInstance;
47
+ });
48
+ if (worker) {
49
+ return require('./worker/index')({ plugins });
50
+ }
51
+ // make sure all plugins have a DB entry
52
+ const pluginNames = plugins.map(R.prop('name'));
53
+ const matchedIntegrations = await Integration.findAll({
54
+ attributes: ['name'],
55
+ where: {
56
+ name: {
57
+ [Op.in]: pluginNames,
58
+ },
59
+ },
60
+ raw: true,
41
61
  });
42
- // console.log({ plugins });
62
+ const missingIntegrations = R.difference(pluginNames, matchedIntegrations.map(R.prop('name')));
63
+ if (missingIntegrations.length > 0) {
64
+ // need to crete the missing integrations
65
+ await Integration.bulkCreate(missingIntegrations.map(name => ({
66
+ name,
67
+ packageName: `ti2-${name}`,
68
+ adminEmail: `ti2+${name}@localhost.local`,
69
+ })));
70
+ }
71
+ // create the API Web server
72
+ const app = express();
43
73
  const api = {
44
74
  ...pingController,
45
75
  ...adminController,
@@ -141,9 +171,12 @@ module.exports = ({
141
171
  connect(app);
142
172
  app.use(middleware.mock());
143
173
  // global error Handling
144
- app.use((err, req, res, next) => {
174
+ app.use((err, req, res) => {
145
175
  // console.log(req.headers.['X-Request-Id'], err);
146
176
  res.status(err.status || 500);
177
+ if ((process.env.JEST_WORKER_ID)) {
178
+ console.debug(err);
179
+ }
147
180
  return res.json({
148
181
  message: err.message || 'Internal Error',
149
182
  });
@@ -156,8 +189,11 @@ module.exports = ({
156
189
  // first create a generic "terminator"
157
190
  const terminator = sig => {
158
191
  if (typeof sig === 'string') {
159
- console.log('%s: Received %s - terminating ti2 ...',
160
- Date(Date.now()), sig);
192
+ console.log(
193
+ '%s: Received %s - terminating ti2 ...',
194
+ Date(Date.now()),
195
+ sig,
196
+ );
161
197
  process.exit(1);
162
198
  }
163
199
  console.log('%s: Node server stopped.', Date(Date.now()));
package/jest.setup.js ADDED
@@ -0,0 +1,11 @@
1
+ /* global afterAll */
2
+
3
+ const closeAll = require('./closeAll');
4
+
5
+ afterAll(async () => {
6
+ await closeAll();
7
+ });
8
+
9
+ global.sleep = (ms = 300) => new Promise(r => {
10
+ setTimeout(r, ms);
11
+ });
@@ -1,4 +1,3 @@
1
-
2
1
  module.exports = {
3
2
  up: (queryInterface, Sequelize) => queryInterface.addColumn(
4
3
  'Integrations',
@@ -3,8 +3,8 @@ module.exports = {
3
3
  type: Sequelize.TEXT,
4
4
  allowNull: false,
5
5
  }),
6
- down: (queryInterface, Sequelize) => queryInterface.changeColumn('UserAppKeys', 'appKey', {
6
+ down: (queryInterface, Sequelize) => queryInterface.changeColumn('UserAppKeys', 'appKey', {
7
7
  type: Sequelize.STRING,
8
8
  allowNull: false,
9
- })
9
+ }),
10
10
  };
@@ -0,0 +1,41 @@
1
+ module.exports = {
2
+ up: (queryInterface, Sequelize) => queryInterface
3
+ .createTable('CronJobs', {
4
+ pluginName: {
5
+ allowNull: false,
6
+ primaryKey: true,
7
+ type: Sequelize.STRING,
8
+ },
9
+ userId: {
10
+ allowNull: false,
11
+ primaryKey: true,
12
+ type: Sequelize.STRING,
13
+ },
14
+ hint: {
15
+ allowNull: false,
16
+ primaryKey: true,
17
+ type: Sequelize.STRING,
18
+ },
19
+ pluginJobId: {
20
+ allowNull: false,
21
+ type: Sequelize.STRING,
22
+ },
23
+ bullJobId: {
24
+ allowNull: false,
25
+ type: Sequelize.STRING,
26
+ },
27
+ cron: {
28
+ allowNull: false,
29
+ type: Sequelize.STRING,
30
+ },
31
+ createdAt: {
32
+ allowNull: false,
33
+ type: Sequelize.DATE,
34
+ },
35
+ updatedAt: {
36
+ allowNull: false,
37
+ type: Sequelize.DATE,
38
+ },
39
+ }),
40
+ down: queryInterface => queryInterface.dropTable('CronJobs'),
41
+ };
@@ -0,0 +1,31 @@
1
+ const Sequelize = require('sequelize');
2
+ const db = require('./db');
3
+
4
+ const CronJobs = db.define('CronJobs', {
5
+ pluginName: {
6
+ type: Sequelize.STRING,
7
+ primaryKey: true,
8
+ },
9
+ userId: {
10
+ type: Sequelize.STRING,
11
+ primaryKey: true,
12
+ },
13
+ hint: {
14
+ type: Sequelize.STRING,
15
+ primaryKey: true,
16
+ },
17
+ pluginJobId: {
18
+ type: Sequelize.STRING,
19
+ primaryKey: true,
20
+ },
21
+ bullJobId: {
22
+ type: Sequelize.STRING,
23
+ allowNull: false,
24
+ },
25
+ cron: {
26
+ type: Sequelize.STRING,
27
+ allowNull: false,
28
+ },
29
+ }, {});
30
+
31
+ module.exports = CronJobs;
package/models/db.js CHANGED
@@ -7,7 +7,6 @@ const {
7
7
  } = process;
8
8
 
9
9
  const options = {
10
- operatorsAliases: false,
11
10
  logging: false,
12
11
  };
13
12
 
package/models/index.js CHANGED
@@ -10,6 +10,7 @@ fs
10
10
  .readdirSync(__dirname)
11
11
  .filter(file => (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'))
12
12
  .forEach(file => {
13
+ // eslint-disable-next-line import/no-dynamic-require, global-require
13
14
  const model = require(path.join(__dirname, file));
14
15
  models[model.name] = model;
15
16
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ti2",
3
- "version": "1.0.14",
3
+ "version": "1.0.17",
4
4
  "description": "Tourist Industry Exchange (TI2)",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -8,19 +8,28 @@
8
8
  "sequelize": "sequelize-cli",
9
9
  "doc": "jsdoc -c jsdoc.conf.json -u tutorials"
10
10
  },
11
+ "jest": {
12
+ "setupFilesAfterEnv": [
13
+ "./jest.setup.js"
14
+ ]
15
+ },
11
16
  "repository": {
12
17
  "type": "git",
13
18
  "url": "git+https://github.com/ti2travel/ti2.git"
14
19
  },
20
+ "bin": "./cli.js",
15
21
  "author": "",
16
- "license": "GPL-3",
22
+ "license": "GPL-3.0",
17
23
  "bugs": {
18
24
  "url": "https://github.com/ti2travel/ti2/issues"
19
25
  },
20
26
  "homepage": "https://github.com/ti2travel/ti2#readme",
21
27
  "dependencies": {
22
28
  "bluebird": "^3.7.2",
29
+ "bull": "^4.8.2",
30
+ "commander": "^9.2.0",
23
31
  "express": "^4.17.2",
32
+ "ioredis": "^5.0.4",
24
33
  "js-yaml": "^4.1.0",
25
34
  "jsonwebtoken": "^8.5.1",
26
35
  "jwt-promise": "^1.0.0",
@@ -32,16 +41,18 @@
32
41
  "swagger-express-middleware": "3.0.0-alpha.5",
33
42
  "swagger-routes-express": "3.3.1",
34
43
  "swagger-ui-express": "4.3.0",
44
+ "throng": "^5.0.0",
45
+ "umzug": "^3.1.1",
35
46
  "uninstall": "^0.0.0"
36
47
  },
37
48
  "devDependencies": {
49
+ "@salvador/minami": "^1.2.3",
38
50
  "chance": "^1.1.8",
39
51
  "eslint": "^8.7.0",
40
52
  "eslint-config-airbnb-base": "^15.0.0",
41
53
  "eslint-plugin-import": "^2.25.4",
42
54
  "jest": "^27.4.7",
43
55
  "jsdoc": "^3.6.10",
44
- "minami": "git+https://github.com/MyNameReallySux/minami.git#sort-data",
45
56
  "supertest": "^6.2.2"
46
57
  }
47
58
  }
package/test/plugin.js CHANGED
@@ -1,4 +1,15 @@
1
1
  /* global jest, expect */
2
+ /* eslint class-methods-use-this: "off", max-len: "off" */
3
+
4
+ const jestPlugin = (() => {
5
+ if (typeof jest === 'undefined') {
6
+ return {
7
+ fn: fn => fn,
8
+ };
9
+ }
10
+ return jest;
11
+ })();
12
+
2
13
  const chance = require('chance').Chance();
3
14
 
4
15
  class Plugin {
@@ -15,16 +26,16 @@ class Plugin {
15
26
  this[attr] = value;
16
27
  });
17
28
  // mock implementations
18
- this.validateToken = jest.fn(() => true);
19
- this.getProfile = jest.fn(() => {});
20
- this.updateProfile = jest.fn(() => {});
21
- this.getProduct = jest.fn(() => ({ products: [] }));
22
- this.getProducts = jest.fn(() => true);
23
- this.createLocation = jest.fn(() => ({ locationId: chance.guid() }));
24
- this.updateLocation = jest.fn(() => true);
25
- this.searchBooking = jest.fn(() => ({ bookings: [] }));
26
- this.searchProducts = jest.fn(() => ({ bookings: [], products: [] }));
27
- this.searchAvailability = jest.fn(({
29
+ this.validateToken = jestPlugin.fn(() => true);
30
+ this.getProfile = jestPlugin.fn(() => {});
31
+ this.updateProfile = jestPlugin.fn(() => {});
32
+ this.getProduct = jestPlugin.fn(() => ({ products: [] }));
33
+ this.getProducts = jestPlugin.fn(() => true);
34
+ this.createLocation = jestPlugin.fn(() => ({ locationId: chance.guid() }));
35
+ this.updateLocation = jestPlugin.fn(() => true);
36
+ this.searchBooking = jestPlugin.fn(() => ({ bookings: [] }));
37
+ this.searchProducts = jestPlugin.fn(() => ({ bookings: [], products: [] }));
38
+ this.searchAvailability = jestPlugin.fn(({
28
39
  token,
29
40
  payload: {
30
41
  travelDateStart,
@@ -40,9 +51,23 @@ class Plugin {
40
51
  expect(Array.isArray(occupancies)).toBeTruthy();
41
52
  return { availability: [{ id: chance.guid() }] };
42
53
  });
54
+ this.searchQuote = jestPlugin.fn(() => ({ quote: [{ id: chance.guid() }] }));
55
+ this.createBooking = jestPlugin.fn(() => {});
56
+
57
+ /**
58
+ * Background and schedule Jos
59
+ */
60
+ this.jobs = [{
61
+ method: 'dailyReport',
62
+ payload: {
63
+ action: 'report',
64
+ },
65
+ cron: '0 9 * * *',
66
+ }];
43
67
 
44
- this.searchQuote = jest.fn(() => ({ quote: [{ id: chance.guid() }] }));
45
- this.createBooking = jest.fn(() => {});
68
+ this.dailyReport = jestPlugin.fn(() => ({
69
+ someVal: true,
70
+ }));
46
71
  }
47
72
 
48
73
  /**
@@ -258,7 +283,7 @@ class Plugin {
258
283
  return true;
259
284
  }
260
285
 
261
- searchHotelBooking = jest.fn(() => ({ bookings: [] }));
286
+ searchHotelBooking = jestPlugin.fn(() => ({ bookings: [] }));
262
287
 
263
288
  /**
264
289
  * Booking Object
@@ -364,6 +389,23 @@ class Plugin {
364
389
  // return (args);
365
390
  }
366
391
 
392
+ /**
393
+ * Retrieve an availability calendar over a date range
394
+ * @async
395
+ * @param {Object} args - Availability search arguments.
396
+ * @param {Object} args.token - A token definition, it's content varies between integrations.
397
+ * @param {Object} args.payload - Search spect object.
398
+ * @param {string} args.payload.dateFormat - Date format sent, using [momentjs formatting](https://momentjs.com/docs/#/parsing/string-format/).
399
+ * @param {string} args.payload.travelDateStart - Date of travel start.
400
+ * @param {string} args.payload.travelDateEnd - Date of travel end.
401
+ * @param {Occupancy[]} args.payload.occupancies - Occupancy detail.
402
+ * @returns {object} retVal - the return object
403
+ * @returns {Availability[]} retVal.availability - Array of availability objects
404
+ */
405
+ availabilityCalndar() {
406
+ // return (args);
407
+ }
408
+
367
409
  /**
368
410
  * A quote return spec
369
411
  * @typedef {Object} Quote
package/test/utils.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const chance = require('chance').Chance();
4
4
  const request = require('supertest');
5
5
  const assert = require('assert');
6
+
6
7
  const appReq = require('../index');
7
8
  const Plugin = require('./plugin');
8
9
  const slugify = require('./slugify');
@@ -10,12 +11,10 @@ const sqldb = require('../models/db');
10
11
 
11
12
  const { env: { adminKey } } = process;
12
13
 
13
- const timeout = ms => (new Promise(resolve => setTimeout(resolve, ms)));
14
-
15
14
  afterAll(async () => {
16
15
  await sqldb.connectionManager.close();
17
16
  });
18
- module.exports = (appParams = {}) => {
17
+ module.exports = async (appParams = {}) => {
19
18
  const plugins = (() => {
20
19
  if (Array.isArray(appParams.plugins)) {
21
20
  const retVal = {};
@@ -28,7 +27,7 @@ module.exports = (appParams = {}) => {
28
27
  mockName: Plugin,
29
28
  };
30
29
  })();
31
- const app = appReq({
30
+ const app = await appReq({
32
31
  startServer: false,
33
32
  ...appParams,
34
33
  plugins,
@@ -104,7 +103,6 @@ module.exports = (appParams = {}) => {
104
103
  doApiPost,
105
104
  doApiPut,
106
105
  slugify,
107
- timeout,
108
106
  plugins: app.plugins,
109
107
  };
110
108
  };
package/test/worker.js ADDED
@@ -0,0 +1,5 @@
1
+ // tests only file, should not be execute by itself
2
+
3
+ const worker = require('../worker/index')({ plugins: [] });
4
+
5
+ worker.then(() => {});