@defra/forms-engine-plugin 1.0.0 → 1.0.2

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 (47) hide show
  1. package/.server/server/plugins/engine/README.md +56 -0
  2. package/.server/server/plugins/engine/configureEnginePlugin.d.ts +2 -1
  3. package/.server/server/plugins/engine/configureEnginePlugin.js +1 -1
  4. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
  5. package/.server/server/plugins/engine/plugin.d.ts +2 -27
  6. package/.server/server/plugins/engine/plugin.js +17 -594
  7. package/.server/server/plugins/engine/plugin.js.map +1 -1
  8. package/.server/server/plugins/engine/registrationOptions.d.ts +1 -0
  9. package/.server/server/plugins/engine/registrationOptions.js +2 -0
  10. package/.server/server/plugins/engine/registrationOptions.js.map +1 -0
  11. package/.server/server/plugins/engine/routes/file-upload.d.ts +4 -0
  12. package/.server/server/plugins/engine/routes/file-upload.js +41 -0
  13. package/.server/server/plugins/engine/routes/file-upload.js.map +1 -0
  14. package/.server/server/plugins/engine/routes/index.d.ts +7 -0
  15. package/.server/server/plugins/engine/routes/index.js +141 -0
  16. package/.server/server/plugins/engine/routes/index.js.map +1 -0
  17. package/.server/server/plugins/engine/routes/questions.d.ts +3 -0
  18. package/.server/server/plugins/engine/routes/questions.js +168 -0
  19. package/.server/server/plugins/engine/routes/questions.js.map +1 -0
  20. package/.server/server/plugins/engine/routes/repeaters/item-delete.d.ts +3 -0
  21. package/.server/server/plugins/engine/routes/repeaters/item-delete.js +106 -0
  22. package/.server/server/plugins/engine/routes/repeaters/item-delete.js.map +1 -0
  23. package/.server/server/plugins/engine/routes/repeaters/summary.d.ts +3 -0
  24. package/.server/server/plugins/engine/routes/repeaters/summary.js +98 -0
  25. package/.server/server/plugins/engine/routes/repeaters/summary.js.map +1 -0
  26. package/.server/server/plugins/engine/types.d.ts +19 -1
  27. package/.server/server/plugins/engine/types.js.map +1 -1
  28. package/.server/server/plugins/engine/vision.d.ts +12 -0
  29. package/.server/server/plugins/engine/vision.js +55 -0
  30. package/.server/server/plugins/engine/vision.js.map +1 -0
  31. package/.server/server/services/cacheService.d.ts +12 -3
  32. package/.server/server/services/cacheService.js +35 -8
  33. package/.server/server/services/cacheService.js.map +1 -1
  34. package/package.json +3 -3
  35. package/src/server/plugins/engine/README.md +56 -0
  36. package/src/server/plugins/engine/configureEnginePlugin.ts +3 -5
  37. package/src/server/plugins/engine/plugin.ts +35 -765
  38. package/src/server/plugins/engine/registrationOptions.ts +0 -0
  39. package/src/server/plugins/engine/routes/file-upload.ts +54 -0
  40. package/src/server/plugins/engine/routes/index.ts +187 -0
  41. package/src/server/plugins/engine/routes/questions.ts +208 -0
  42. package/src/server/plugins/engine/routes/repeaters/item-delete.ts +157 -0
  43. package/src/server/plugins/engine/routes/repeaters/summary.ts +137 -0
  44. package/src/server/plugins/engine/types.ts +26 -1
  45. package/src/server/plugins/engine/vision.ts +95 -0
  46. package/src/server/services/cacheService.test.ts +98 -2
  47. package/src/server/services/cacheService.ts +57 -8
@@ -1,92 +1,32 @@
1
- import { existsSync } from 'fs';
2
- import { dirname, join } from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { getErrorMessage, hasFormComponents, slugSchema } from '@defra/forms-model';
5
- import Boom from '@hapi/boom';
6
- import vision from '@hapi/vision';
7
- import { isEqual } from 'date-fns';
8
- import Joi from 'joi';
9
- import nunjucks from 'nunjucks';
10
- import resolvePkg from 'resolve';
11
- import { PREVIEW_PATH_PREFIX } from "../../constants.js";
12
- import { checkEmailAddressForLiveFormSubmission, checkFormStatus, findPage, getCacheService, getPage, getStartPath, normalisePath, proceed, redirectPath } from "./helpers.js";
13
- import { VIEW_PATH, context, prepareNunjucksEnvironment } from "./index.js";
14
- import { FormModel, SummaryViewModel } from "./models/index.js";
15
- import { format } from "./outputFormatters/machine/v1.js";
16
- import { FileUploadPageController } from "./pageControllers/FileUploadPageController.js";
17
- import { RepeatPageController } from "./pageControllers/RepeatPageController.js";
18
- import { getFormSubmissionData } from "./pageControllers/SummaryPageController.js";
19
- import { generateUniqueReference } from "./referenceNumbers.js";
20
- import * as defaultServices from "./services/index.js";
21
- import { getUploadStatus } from "./services/uploadService.js";
22
- import { actionSchema, confirmSchema, crumbSchema, itemIdSchema, pathSchema, stateSchema } from "../../schemas/index.js";
23
- import * as httpService from "../../services/httpService.js";
1
+ import { getRoutes as getFileUploadStatusRoutes } from "./routes/file-upload.js";
2
+ import { makeLoadFormPreHandler } from "./routes/index.js";
3
+ import { getRoutes as getQuestionRoutes } from "./routes/questions.js";
4
+ import { getRoutes as getRepeaterItemDeleteRoutes } from "./routes/repeaters/item-delete.js";
5
+ import { getRoutes as getRepeaterSummaryRoutes } from "./routes/repeaters/summary.js";
6
+ import { registerVision } from "./vision.js";
24
7
  import { CacheService } from "../../services/index.js";
25
- export function findPackageRoot() {
26
- const currentFileName = fileURLToPath(import.meta.url);
27
- const currentDirectoryName = dirname(currentFileName);
28
- let dir = currentDirectoryName;
29
- while (dir !== '/') {
30
- if (existsSync(join(dir, 'package.json'))) {
31
- return dir;
32
- }
33
- dir = dirname(dir);
34
- }
35
- throw new Error('package.json not found in parent directories');
36
- }
37
8
  export const plugin = {
38
9
  name: '@defra/forms-engine-plugin',
39
10
  dependencies: ['@hapi/crumb', '@hapi/yar', 'hapi-pino'],
40
11
  multiple: true,
41
12
  async register(server, options) {
42
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- hapi types are wrong
43
- const prefix = server.realm.modifiers.route.prefix ?? '';
44
13
  const {
45
14
  model,
46
- services = defaultServices,
47
- controllers,
48
15
  cacheName,
49
- filters,
16
+ keyGenerator,
17
+ sessionHydrator,
50
18
  nunjucks: nunjucksOptions,
51
19
  viewContext
52
20
  } = options;
53
- const {
54
- formsService
55
- } = services;
56
- const cacheService = new CacheService(server, cacheName);
57
- const packageRoot = findPackageRoot();
58
- const govukFrontendPath = dirname(resolvePkg.sync('govuk-frontend/package.json'));
59
- const viewPathResolved = join(packageRoot, VIEW_PATH);
60
- const paths = [...nunjucksOptions.paths, viewPathResolved, join(govukFrontendPath, 'dist')];
61
- await server.register({
62
- plugin: vision,
21
+ const cacheService = new CacheService({
22
+ server,
23
+ cacheName,
63
24
  options: {
64
- engines: {
65
- html: {
66
- compile: (path, compileOptions) => {
67
- const template = nunjucks.compile(path, compileOptions.environment);
68
- return context => {
69
- return template.render(context);
70
- };
71
- },
72
- prepare: (options, next) => {
73
- // Nunjucks also needs an additional path configuration
74
- // to use the templates and macros from `govuk-frontend`
75
- const environment = nunjucks.configure(paths);
76
-
77
- // Applies custom filters and globals for nunjucks
78
- // that are required by the `forms-engine-plugin`
79
- prepareNunjucksEnvironment(environment, filters);
80
- options.compileOptions.environment = environment;
81
- next();
82
- }
83
- }
84
- },
85
- path: paths,
86
- // Provides global context used with all templates
87
- context
25
+ keyGenerator,
26
+ sessionHydrator
88
27
  }
89
28
  });
29
+ await registerVision(server, options);
90
30
  server.expose('baseLayoutPath', nunjucksOptions.baseLayoutPath);
91
31
  server.expose('viewContext', viewContext);
92
32
  server.expose('cacheService', cacheService);
@@ -96,258 +36,12 @@ export const plugin = {
96
36
  // (for testing purposes) through `server.app.models`
97
37
  const itemCache = new Map();
98
38
  server.app.models = itemCache;
99
- const loadFormPreHandler = async (request, h) => {
100
- if (server.app.model) {
101
- request.app.model = server.app.model;
102
- return h.continue;
103
- }
104
- const {
105
- params
106
- } = request;
107
- const {
108
- slug
109
- } = params;
110
- const {
111
- isPreview,
112
- state: formState
113
- } = checkFormStatus(params);
114
-
115
- // Get the form metadata using the `slug` param
116
- const metadata = await formsService.getFormMetadata(slug);
117
- const {
118
- id,
119
- [formState]: state
120
- } = metadata;
121
-
122
- // Check the metadata supports the requested state
123
- if (!state) {
124
- throw Boom.notFound(`No '${formState}' state for form metadata ${id}`);
125
- }
126
-
127
- // Cache the models based on id, state and whether
128
- // it's a preview or not. There could be up to 3 models
129
- // cached for a single form:
130
- // "{id}_live_false" (live/live)
131
- // "{id}_live_true" (live/preview)
132
- // "{id}_draft_true" (draft/preview)
133
- const key = `${id}_${formState}_${isPreview}`;
134
- let item = itemCache.get(key);
135
- if (!item || !isEqual(item.updatedAt, state.updatedAt)) {
136
- server.logger.info(`Getting form definition ${id} (${slug}) ${formState}`);
137
-
138
- // Get the form definition using the `id` from the metadata
139
- const definition = await formsService.getFormDefinition(id, formState);
140
- if (!definition) {
141
- throw Boom.notFound(`No definition found for form metadata ${id} (${slug}) ${formState}`);
142
- }
143
- const emailAddress = metadata.notificationEmail ?? definition.outputEmail;
144
- checkEmailAddressForLiveFormSubmission(emailAddress, isPreview);
145
-
146
- // Build the form model
147
- server.logger.info(`Building model for form definition ${id} (${slug}) ${formState}`);
148
-
149
- // Set up the basePath for the model
150
- const basePath = (isPreview ? `${prefix}${PREVIEW_PATH_PREFIX}/${formState}/${slug}` : `${prefix}/${slug}`).substring(1);
151
-
152
- // Construct the form model
153
- const model = new FormModel(definition, {
154
- basePath
155
- }, services, controllers);
156
-
157
- // Create new item and add it to the item cache
158
- item = {
159
- model,
160
- updatedAt: state.updatedAt
161
- };
162
- itemCache.set(key, item);
163
- }
164
-
165
- // Assign the model to the request data
166
- // for use in the downstream handler
167
- request.app.model = item.model;
168
- return h.continue;
169
- };
170
- const dispatchHandler = (request, h) => {
171
- const {
172
- model
173
- } = request.app;
174
- const servicePath = model ? `/${model.basePath}` : '';
175
- return proceed(request, h, `${servicePath}${getStartPath(model)}`);
176
- };
177
- const redirectOrMakeHandler = async (request, h, makeHandler) => {
178
- const {
179
- app,
180
- params
181
- } = request;
182
- const {
183
- model
184
- } = app;
185
- if (!model) {
186
- throw Boom.notFound(`No model found for /${params.path}`);
187
- }
188
- const cacheService = getCacheService(request.server);
189
- const page = getPage(model, request);
190
- let state = await page.getState(request);
191
- if (!state.$$__referenceNumber) {
192
- const prefix = model.def.metadata?.referenceNumberPrefix ?? '';
193
- if (typeof prefix !== 'string') {
194
- throw Boom.badImplementation('Reference number prefix must be a string or undefined');
195
- }
196
- const referenceNumber = generateUniqueReference(prefix);
197
- state = await page.mergeState(request, state, {
198
- $$__referenceNumber: referenceNumber
199
- });
200
- }
201
- const flash = cacheService.getFlash(request);
202
- const context = model.getFormContext(request, state, flash?.errors);
203
- const relevantPath = page.getRelevantPath(request, context);
204
- const summaryPath = page.getSummaryPath();
205
-
206
- // Return handler for relevant pages or preview URL direct access
207
- if (relevantPath.startsWith(page.path) || context.isForceAccess) {
208
- return makeHandler(page, context);
209
- }
210
-
211
- // Redirect back to last relevant page
212
- const redirectTo = findPage(model, relevantPath);
213
-
214
- // Set the return URL unless an exit page
215
- if (redirectTo?.next.length) {
216
- request.query.returnUrl = page.getHref(summaryPath);
217
- }
218
- return proceed(request, h, page.getHref(relevantPath));
219
- };
220
- const getHandler = (request, h) => {
221
- const {
222
- params
223
- } = request;
224
- if (normalisePath(params.path) === '') {
225
- return dispatchHandler(request, h);
226
- }
227
- return redirectOrMakeHandler(request, h, async (page, context) => {
228
- // Check for a page onLoad HTTP event and if one exists,
229
- // call it and assign the response to the context data
230
- const {
231
- events
232
- } = page;
233
- const {
234
- model
235
- } = request.app;
236
- if (!model) {
237
- throw Boom.notFound(`No model found for /${params.path}`);
238
- }
239
- if (events?.onLoad && events.onLoad.type === 'http') {
240
- const {
241
- options
242
- } = events.onLoad;
243
- const {
244
- url
245
- } = options;
246
-
247
- // TODO: Update structured data POST payload with when helper
248
- // is updated to removing the dependency on `SummaryViewModel` etc.
249
- const viewModel = new SummaryViewModel(request, page, context);
250
- const items = getFormSubmissionData(viewModel.context, viewModel.details);
251
-
252
- // @ts-expect-error - function signature will be refactored in the next iteration of the formatter
253
- const payload = format(items, model, undefined, undefined);
254
- const {
255
- payload: response
256
- } = await httpService.postJson(url, {
257
- payload
258
- });
259
- Object.assign(context.data, response);
260
- }
261
- return page.makeGetRouteHandler()(request, context, h);
262
- });
263
- };
264
- const postHandler = (request, h) => {
265
- const {
266
- query
267
- } = request;
268
- return redirectOrMakeHandler(request, h, (page, context) => {
269
- const {
270
- pageDef
271
- } = page;
272
- const {
273
- isForceAccess
274
- } = context;
275
-
276
- // Redirect to GET for preview URL direct access
277
- if (isForceAccess && !hasFormComponents(pageDef)) {
278
- return proceed(request, h, redirectPath(page.href, query));
279
- }
280
- return page.makePostRouteHandler()(request, context, h);
281
- });
282
- };
283
- const dispatchRouteOptions = {
284
- pre: [{
285
- method: loadFormPreHandler
286
- }]
287
- };
288
- server.route({
289
- method: 'get',
290
- path: '/{slug}',
291
- handler: dispatchHandler,
292
- options: {
293
- ...dispatchRouteOptions,
294
- validate: {
295
- params: Joi.object().keys({
296
- slug: slugSchema
297
- })
298
- }
299
- }
300
- });
301
- server.route({
302
- method: 'get',
303
- path: '/preview/{state}/{slug}',
304
- handler: dispatchHandler,
305
- options: {
306
- ...dispatchRouteOptions,
307
- validate: {
308
- params: Joi.object().keys({
309
- state: stateSchema,
310
- slug: slugSchema
311
- })
312
- }
313
- }
314
- });
39
+ const loadFormPreHandler = makeLoadFormPreHandler(server, options);
315
40
  const getRouteOptions = {
316
41
  pre: [{
317
42
  method: loadFormPreHandler
318
43
  }]
319
44
  };
320
- server.route({
321
- method: 'get',
322
- path: '/{slug}/{path}/{itemId?}',
323
- handler: getHandler,
324
- options: {
325
- ...getRouteOptions,
326
- validate: {
327
- params: Joi.object().keys({
328
- slug: slugSchema,
329
- path: pathSchema,
330
- itemId: itemIdSchema.optional()
331
- })
332
- }
333
- }
334
- });
335
- server.route({
336
- method: 'get',
337
- path: '/preview/{state}/{slug}/{path}/{itemId?}',
338
- handler: getHandler,
339
- options: {
340
- ...getRouteOptions,
341
- validate: {
342
- params: Joi.object().keys({
343
- state: stateSchema,
344
- slug: slugSchema,
345
- path: pathSchema,
346
- itemId: itemIdSchema.optional()
347
- })
348
- }
349
- }
350
- });
351
45
  const postRouteOptions = {
352
46
  payload: {
353
47
  parse: true
@@ -356,279 +50,8 @@ export const plugin = {
356
50
  method: loadFormPreHandler
357
51
  }]
358
52
  };
359
- server.route({
360
- method: 'post',
361
- path: '/{slug}/{path}/{itemId?}',
362
- handler: postHandler,
363
- options: {
364
- ...postRouteOptions,
365
- validate: {
366
- params: Joi.object().keys({
367
- slug: slugSchema,
368
- path: pathSchema,
369
- itemId: itemIdSchema.optional()
370
- }),
371
- payload: Joi.object().keys({
372
- crumb: crumbSchema,
373
- action: actionSchema
374
- }).unknown(true).required()
375
- }
376
- }
377
- });
378
- server.route({
379
- method: 'post',
380
- path: '/preview/{state}/{slug}/{path}/{itemId?}',
381
- handler: postHandler,
382
- options: {
383
- ...postRouteOptions,
384
- validate: {
385
- params: Joi.object().keys({
386
- state: stateSchema,
387
- slug: slugSchema,
388
- path: pathSchema,
389
- itemId: itemIdSchema.optional()
390
- }),
391
- payload: Joi.object().keys({
392
- crumb: crumbSchema,
393
- action: actionSchema
394
- }).unknown(true).required()
395
- }
396
- }
397
- });
398
-
399
- /**
400
- * "AddAnother" repeat routes
401
- */
402
-
403
- // List summary GET route
404
- const getListSummaryHandler = (request, h) => {
405
- const {
406
- params
407
- } = request;
408
- return redirectOrMakeHandler(request, h, (page, context) => {
409
- if (!(page instanceof RepeatPageController)) {
410
- throw Boom.notFound(`No repeater page found for /${params.path}`);
411
- }
412
- return page.makeGetListSummaryRouteHandler()(request, context, h);
413
- });
414
- };
415
- server.route({
416
- method: 'get',
417
- path: '/{slug}/{path}/summary',
418
- handler: getListSummaryHandler,
419
- options: {
420
- ...getRouteOptions,
421
- validate: {
422
- params: Joi.object().keys({
423
- slug: slugSchema,
424
- path: pathSchema
425
- })
426
- }
427
- }
428
- });
429
- server.route({
430
- method: 'get',
431
- path: '/preview/{state}/{slug}/{path}/summary',
432
- handler: getListSummaryHandler,
433
- options: {
434
- ...getRouteOptions,
435
- validate: {
436
- params: Joi.object().keys({
437
- state: stateSchema,
438
- slug: slugSchema,
439
- path: pathSchema
440
- })
441
- }
442
- }
443
- });
444
-
445
- // List summary POST route
446
- const postListSummaryHandler = (request, h) => {
447
- const {
448
- params
449
- } = request;
450
- return redirectOrMakeHandler(request, h, (page, context) => {
451
- const {
452
- isForceAccess
453
- } = context;
454
- if (isForceAccess || !(page instanceof RepeatPageController)) {
455
- throw Boom.notFound(`No repeater page found for /${params.path}`);
456
- }
457
- return page.makePostListSummaryRouteHandler()(request, context, h);
458
- });
459
- };
460
- server.route({
461
- method: 'post',
462
- path: '/{slug}/{path}/summary',
463
- handler: postListSummaryHandler,
464
- options: {
465
- ...postRouteOptions,
466
- validate: {
467
- params: Joi.object().keys({
468
- slug: slugSchema,
469
- path: pathSchema
470
- }),
471
- payload: Joi.object().keys({
472
- crumb: crumbSchema,
473
- action: actionSchema
474
- }).required()
475
- }
476
- }
477
- });
478
- server.route({
479
- method: 'post',
480
- path: '/preview/{state}/{slug}/{path}/summary',
481
- handler: postListSummaryHandler,
482
- options: {
483
- ...postRouteOptions,
484
- validate: {
485
- params: Joi.object().keys({
486
- state: stateSchema,
487
- slug: slugSchema,
488
- path: pathSchema
489
- }),
490
- payload: Joi.object().keys({
491
- crumb: crumbSchema,
492
- action: actionSchema
493
- }).required()
494
- }
495
- }
496
- });
497
-
498
- // Item delete GET route
499
- const getItemDeleteHandler = (request, h) => {
500
- const {
501
- params
502
- } = request;
503
- return redirectOrMakeHandler(request, h, (page, context) => {
504
- if (!(page instanceof RepeatPageController || page instanceof FileUploadPageController)) {
505
- throw Boom.notFound(`No page found for /${params.path}`);
506
- }
507
- return page.makeGetItemDeleteRouteHandler()(request, context, h);
508
- });
509
- };
510
- server.route({
511
- method: 'get',
512
- path: '/{slug}/{path}/{itemId}/confirm-delete',
513
- handler: getItemDeleteHandler,
514
- options: {
515
- ...getRouteOptions,
516
- validate: {
517
- params: Joi.object().keys({
518
- slug: slugSchema,
519
- path: pathSchema,
520
- itemId: itemIdSchema
521
- })
522
- }
523
- }
524
- });
525
- server.route({
526
- method: 'get',
527
- path: '/preview/{state}/{slug}/{path}/{itemId}/confirm-delete',
528
- handler: getItemDeleteHandler,
529
- options: {
530
- ...getRouteOptions,
531
- validate: {
532
- params: Joi.object().keys({
533
- state: stateSchema,
534
- slug: slugSchema,
535
- path: pathSchema,
536
- itemId: itemIdSchema
537
- })
538
- }
539
- }
540
- });
541
-
542
- // Item delete POST route
543
- const postItemDeleteHandler = (request, h) => {
544
- const {
545
- params
546
- } = request;
547
- return redirectOrMakeHandler(request, h, (page, context) => {
548
- const {
549
- isForceAccess
550
- } = context;
551
- if (isForceAccess || !(page instanceof RepeatPageController || page instanceof FileUploadPageController)) {
552
- throw Boom.notFound(`No page found for /${params.path}`);
553
- }
554
- return page.makePostItemDeleteRouteHandler()(request, context, h);
555
- });
556
- };
557
- server.route({
558
- method: 'post',
559
- path: '/{slug}/{path}/{itemId}/confirm-delete',
560
- handler: postItemDeleteHandler,
561
- options: {
562
- ...postRouteOptions,
563
- validate: {
564
- params: Joi.object().keys({
565
- slug: slugSchema,
566
- path: pathSchema,
567
- itemId: itemIdSchema
568
- }),
569
- payload: Joi.object().keys({
570
- crumb: crumbSchema,
571
- action: actionSchema,
572
- confirm: confirmSchema
573
- }).required()
574
- }
575
- }
576
- });
577
- server.route({
578
- method: 'post',
579
- path: '/preview/{state}/{slug}/{path}/{itemId}/confirm-delete',
580
- handler: postItemDeleteHandler,
581
- options: {
582
- ...postRouteOptions,
583
- validate: {
584
- params: Joi.object().keys({
585
- state: stateSchema,
586
- slug: slugSchema,
587
- path: pathSchema,
588
- itemId: itemIdSchema
589
- }),
590
- payload: Joi.object().keys({
591
- crumb: crumbSchema,
592
- action: actionSchema,
593
- confirm: confirmSchema
594
- }).required()
595
- }
596
- }
597
- });
598
- server.route({
599
- method: 'get',
600
- path: '/upload-status/{uploadId}',
601
- handler: async (request, h) => {
602
- const {
603
- uploadId
604
- } = request.params;
605
- try {
606
- const status = await getUploadStatus(uploadId);
607
- if (!status) {
608
- return h.response({
609
- error: 'Status check failed'
610
- }).code(400);
611
- }
612
- return h.response(status);
613
- } catch (error) {
614
- const errMsg = getErrorMessage(error);
615
- request.logger.error(errMsg, `[uploadStatusFailed] Upload status check failed for uploadId: ${uploadId} - ${errMsg}`);
616
- return h.response({
617
- error: 'Status check error'
618
- }).code(500);
619
- }
620
- },
621
- options: {
622
- plugins: {
623
- crumb: false
624
- },
625
- validate: {
626
- params: Joi.object().keys({
627
- uploadId: Joi.string().guid().required()
628
- })
629
- }
630
- }
631
- });
53
+ const routes = [...getQuestionRoutes(getRouteOptions, postRouteOptions), ...getRepeaterSummaryRoutes(getRouteOptions, postRouteOptions), ...getRepeaterItemDeleteRoutes(getRouteOptions, postRouteOptions), ...getFileUploadStatusRoutes()];
54
+ server.route(routes); // TODO
632
55
  }
633
56
  };
634
57
  //# sourceMappingURL=plugin.js.map