@defra/forms-engine-plugin 2.1.10 → 3.0.1

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 (136) hide show
  1. package/.server/server/index.js +2 -1
  2. package/.server/server/index.js.map +1 -1
  3. package/.server/server/plugins/engine/README.md +2 -2
  4. package/.server/server/plugins/engine/configureEnginePlugin.d.ts +2 -1
  5. package/.server/server/plugins/engine/configureEnginePlugin.js +4 -4
  6. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
  7. package/.server/server/plugins/engine/helpers.d.ts +7 -11
  8. package/.server/server/plugins/engine/helpers.js +2 -2
  9. package/.server/server/plugins/engine/helpers.js.map +1 -1
  10. package/.server/server/plugins/engine/models/FormModel.d.ts +2 -0
  11. package/.server/server/plugins/engine/models/FormModel.js +5 -2
  12. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  13. package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +1 -1
  14. package/.server/server/plugins/engine/models/SummaryViewModel.js +1 -1
  15. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  16. package/.server/server/plugins/engine/options.js +3 -6
  17. package/.server/server/plugins/engine/options.js.map +1 -1
  18. package/.server/server/plugins/engine/options.test.js +2 -8
  19. package/.server/server/plugins/engine/options.test.js.map +1 -1
  20. package/.server/server/plugins/engine/outputFormatters/adapter/v1.d.ts +4 -0
  21. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +25 -0
  22. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  23. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +7 -6
  24. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  25. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +5 -6
  26. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  27. package/.server/server/plugins/engine/pageControllers/PageController.d.ts +6 -6
  28. package/.server/server/plugins/engine/pageControllers/PageController.js +4 -4
  29. package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
  30. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +13 -13
  31. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +12 -20
  32. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  33. package/.server/server/plugins/engine/pageControllers/RepeatPageController.d.ts +7 -8
  34. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  35. package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +2 -2
  36. package/.server/server/plugins/engine/pageControllers/StartPageController.js +1 -1
  37. package/.server/server/plugins/engine/pageControllers/StartPageController.js.map +1 -1
  38. package/.server/server/plugins/engine/pageControllers/StatusPageController.d.ts +3 -4
  39. package/.server/server/plugins/engine/pageControllers/StatusPageController.js +1 -1
  40. package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -1
  41. package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +5 -4
  42. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +12 -1
  43. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  44. package/.server/server/plugins/engine/pageControllers/TerminalPageController.d.ts +4 -4
  45. package/.server/server/plugins/engine/pageControllers/TerminalPageController.js +1 -1
  46. package/.server/server/plugins/engine/pageControllers/TerminalPageController.js.map +1 -1
  47. package/.server/server/plugins/engine/pageControllers/__stubs__/server.d.ts +1 -1
  48. package/.server/server/plugins/engine/pageControllers/__stubs__/server.js +2 -6
  49. package/.server/server/plugins/engine/pageControllers/__stubs__/server.js.map +1 -1
  50. package/.server/server/plugins/engine/plugin.js +7 -12
  51. package/.server/server/plugins/engine/plugin.js.map +1 -1
  52. package/.server/server/plugins/engine/routes/index.d.ts +5 -5
  53. package/.server/server/plugins/engine/routes/index.js +3 -1
  54. package/.server/server/plugins/engine/routes/index.js.map +1 -1
  55. package/.server/server/plugins/engine/routes/questions.d.ts +4 -4
  56. package/.server/server/plugins/engine/routes/questions.js.map +1 -1
  57. package/.server/server/plugins/engine/routes/repeaters/item-delete.js.map +1 -1
  58. package/.server/server/plugins/engine/routes/repeaters/summary.js.map +1 -1
  59. package/.server/server/plugins/engine/types/index.d.ts +2 -2
  60. package/.server/server/plugins/engine/types/index.js.map +1 -1
  61. package/.server/server/plugins/engine/types/schema.js +3 -2
  62. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  63. package/.server/server/plugins/engine/types.d.ts +13 -12
  64. package/.server/server/plugins/engine/types.js.map +1 -1
  65. package/.server/server/plugins/engine/views/partials/form.html +3 -3
  66. package/.server/server/plugins/engine/views/summary.html +21 -5
  67. package/.server/server/plugins/nunjucks/context.d.ts +5 -6
  68. package/.server/server/plugins/nunjucks/context.js +3 -3
  69. package/.server/server/plugins/nunjucks/context.js.map +1 -1
  70. package/.server/server/routes/types.d.ts +3 -2
  71. package/.server/server/routes/types.js +1 -1
  72. package/.server/server/routes/types.js.map +1 -1
  73. package/.server/server/schemas/index.js +1 -1
  74. package/.server/server/schemas/index.js.map +1 -1
  75. package/.server/server/services/cacheService.d.ts +11 -19
  76. package/.server/server/services/cacheService.js +9 -30
  77. package/.server/server/services/cacheService.js.map +1 -1
  78. package/.server/server/types.d.ts +4 -1
  79. package/.server/server/types.js.map +1 -1
  80. package/.server/typings/hapi/index.d.js.map +1 -1
  81. package/package.json +4 -2
  82. package/src/server/index.test.ts +0 -39
  83. package/src/server/index.ts +4 -1
  84. package/src/server/plugins/engine/README.md +2 -2
  85. package/src/server/plugins/engine/components/helpers/helpers.test.ts +1 -1
  86. package/src/server/plugins/engine/configureEnginePlugin.ts +15 -11
  87. package/src/server/plugins/engine/helpers.test.ts +3 -2
  88. package/src/server/plugins/engine/helpers.ts +6 -6
  89. package/src/server/plugins/engine/models/FormModel.test.ts +66 -2
  90. package/src/server/plugins/engine/models/FormModel.ts +6 -4
  91. package/src/server/plugins/engine/models/SummaryViewModel.test.ts +7 -7
  92. package/src/server/plugins/engine/models/SummaryViewModel.ts +1 -1
  93. package/src/server/plugins/engine/options.js +6 -6
  94. package/src/server/plugins/engine/options.test.js +2 -6
  95. package/src/server/plugins/engine/outputFormatters/adapter/v1.test.ts +446 -13
  96. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +37 -0
  97. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +8 -6
  98. package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +8 -10
  99. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +9 -8
  100. package/src/server/plugins/engine/pageControllers/PageController.test.ts +11 -8
  101. package/src/server/plugins/engine/pageControllers/PageController.ts +9 -15
  102. package/src/server/plugins/engine/pageControllers/QuestionPageController.test.ts +35 -102
  103. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +24 -36
  104. package/src/server/plugins/engine/pageControllers/RepeatPageController.test.ts +4 -6
  105. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +8 -11
  106. package/src/server/plugins/engine/pageControllers/StartPageController.test.ts +4 -4
  107. package/src/server/plugins/engine/pageControllers/StartPageController.ts +1 -1
  108. package/src/server/plugins/engine/pageControllers/StatusPageController.test.ts +4 -4
  109. package/src/server/plugins/engine/pageControllers/StatusPageController.ts +6 -4
  110. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +15 -5
  111. package/src/server/plugins/engine/pageControllers/TerminalController.test.ts +4 -4
  112. package/src/server/plugins/engine/pageControllers/TerminalPageController.ts +7 -4
  113. package/src/server/plugins/engine/pageControllers/__stubs__/server.ts +5 -6
  114. package/src/server/plugins/engine/plugin.ts +7 -13
  115. package/src/server/plugins/engine/routes/index.ts +9 -12
  116. package/src/server/plugins/engine/routes/questions.test.ts +29 -53
  117. package/src/server/plugins/engine/routes/questions.ts +6 -8
  118. package/src/server/plugins/engine/routes/repeaters/item-delete.ts +5 -14
  119. package/src/server/plugins/engine/routes/repeaters/summary.ts +5 -14
  120. package/src/server/plugins/engine/types/index.ts +4 -1
  121. package/src/server/plugins/engine/types/schema.test.ts +40 -0
  122. package/src/server/plugins/engine/types/schema.ts +3 -1
  123. package/src/server/plugins/engine/types.ts +22 -13
  124. package/src/server/plugins/engine/views/partials/form.html +3 -3
  125. package/src/server/plugins/engine/views/summary.html +21 -5
  126. package/src/server/plugins/nunjucks/context.js +3 -3
  127. package/src/server/routes/types.ts +7 -2
  128. package/src/server/schemas/index.ts +1 -1
  129. package/src/server/services/cacheService.test.ts +1 -117
  130. package/src/server/services/cacheService.ts +22 -73
  131. package/src/server/types.ts +4 -1
  132. package/src/typings/hapi/index.d.ts +6 -7
  133. package/.server/server/plugins/engine/routes/exit.d.ts +0 -46
  134. package/.server/server/plugins/engine/routes/exit.js +0 -36
  135. package/.server/server/plugins/engine/routes/exit.js.map +0 -1
  136. package/src/server/plugins/engine/routes/exit.ts +0 -47
@@ -2,7 +2,6 @@ import { randomUUID } from 'crypto'
2
2
 
3
3
  import { type PageRepeat, type Repeat } from '@defra/forms-model'
4
4
  import Boom from '@hapi/boom'
5
- import { type ResponseToolkit } from '@hapi/hapi'
6
5
  import Joi from 'joi'
7
6
 
8
7
  import { isRepeatState } from '~/src/server/plugins/engine/components/FormComponent.js'
@@ -25,7 +24,8 @@ import {
25
24
  import {
26
25
  FormAction,
27
26
  type FormRequest,
28
- type FormRequestPayload
27
+ type FormRequestPayload,
28
+ type FormResponseToolkit
29
29
  } from '~/src/server/routes/types.js'
30
30
 
31
31
  export class RepeatPageController extends QuestionPageController {
@@ -128,10 +128,7 @@ export class RepeatPageController extends QuestionPageController {
128
128
  }
129
129
  }
130
130
 
131
- proceed(
132
- request: FormContextRequest,
133
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
134
- ) {
131
+ proceed(request: FormContextRequest, h: FormResponseToolkit) {
135
132
  const nextPath = this.getSummaryPath(request)
136
133
  return super.proceed(request, h, nextPath)
137
134
  }
@@ -151,7 +148,7 @@ export class RepeatPageController extends QuestionPageController {
151
148
  return async (
152
149
  request: FormRequest,
153
150
  context: FormContext,
154
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
151
+ h: FormResponseToolkit
155
152
  ) => {
156
153
  const { path } = this
157
154
  const { query } = request
@@ -179,7 +176,7 @@ export class RepeatPageController extends QuestionPageController {
179
176
  return (
180
177
  request: FormRequest,
181
178
  context: FormContext,
182
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
179
+ h: FormResponseToolkit
183
180
  ) => {
184
181
  const { path } = this
185
182
  const { query } = request
@@ -205,7 +202,7 @@ export class RepeatPageController extends QuestionPageController {
205
202
  return (
206
203
  request: FormRequestPayload,
207
204
  context: FormContext,
208
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
205
+ h: FormResponseToolkit
209
206
  ) => {
210
207
  const { path, repeat } = this
211
208
  const { query } = request
@@ -269,7 +266,7 @@ export class RepeatPageController extends QuestionPageController {
269
266
  return (
270
267
  request: FormRequest,
271
268
  context: FormContext,
272
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
269
+ h: FormResponseToolkit
273
270
  ) => {
274
271
  const { viewModel } = this
275
272
  const { state } = context
@@ -304,7 +301,7 @@ export class RepeatPageController extends QuestionPageController {
304
301
  return async (
305
302
  request: FormRequestPayload,
306
303
  context: FormContext,
307
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
304
+ h: FormResponseToolkit
308
305
  ) => {
309
306
  const { repeat } = this
310
307
  const { state } = context
@@ -1,6 +1,6 @@
1
1
  import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
2
2
  import { StartPageController } from '~/src/server/plugins/engine/pageControllers/StartPageController.js'
3
- import { serverWithSaveAndReturn } from '~/src/server/plugins/engine/pageControllers/__stubs__/server.js'
3
+ import { serverWithSaveAndExit } from '~/src/server/plugins/engine/pageControllers/__stubs__/server.js'
4
4
  import definition from '~/test/form/definitions/basic.js'
5
5
 
6
6
  describe('StartPageController', () => {
@@ -22,9 +22,9 @@ describe('StartPageController', () => {
22
22
  controller = new StartPageController(model, mockPage as any)
23
23
  })
24
24
 
25
- describe('shouldShowSaveAndReturn', () => {
26
- it('should return false (StartPageController does not allow save and return)', () => {
27
- expect(controller.shouldShowSaveAndReturn(serverWithSaveAndReturn)).toBe(
25
+ describe('shouldShowSaveAndExit', () => {
26
+ it('should return false (StartPageController does not allow save and exit)', () => {
27
+ expect(controller.shouldShowSaveAndExit(serverWithSaveAndExit)).toBe(
28
28
  false
29
29
  )
30
30
  })
@@ -9,7 +9,7 @@ export class StartPageController extends QuestionPageController {
9
9
  * but start pages should really live on gov.uk (whitehall publisher) so a user can be properly signposted.
10
10
  */
11
11
 
12
- allowSaveAndReturn = false
12
+ allowSaveAndExit = false
13
13
 
14
14
  getViewModel(request: FormRequest, context: FormContext) {
15
15
  return {
@@ -1,6 +1,6 @@
1
1
  import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
2
2
  import { StatusPageController } from '~/src/server/plugins/engine/pageControllers/StatusPageController.js'
3
- import { serverWithSaveAndReturn } from '~/src/server/plugins/engine/pageControllers/__stubs__/server.js'
3
+ import { serverWithSaveAndExit } from '~/src/server/plugins/engine/pageControllers/__stubs__/server.js'
4
4
  import definition from '~/test/form/definitions/basic.js'
5
5
 
6
6
  describe('StatusPageController', () => {
@@ -22,9 +22,9 @@ describe('StatusPageController', () => {
22
22
  controller = new StatusPageController(model, mockPage as any)
23
23
  })
24
24
 
25
- describe('shouldShowSaveAndReturn', () => {
26
- it('should return false (StatusPageController does not allow save and return)', () => {
27
- expect(controller.shouldShowSaveAndReturn(serverWithSaveAndReturn)).toBe(
25
+ describe('shouldShowSaveAndExit', () => {
26
+ it('should return false (StatusPageController does not allow save and exit)', () => {
27
+ expect(controller.shouldShowSaveAndExit(serverWithSaveAndExit)).toBe(
28
28
  false
29
29
  )
30
30
  })
@@ -1,15 +1,17 @@
1
1
  import { type PageStatus } from '@defra/forms-model'
2
- import { type ResponseToolkit } from '@hapi/hapi'
3
2
 
4
3
  import { getCacheService } from '~/src/server/plugins/engine/helpers.js'
5
4
  import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
6
5
  import { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'
7
6
  import { type FormContext } from '~/src/server/plugins/engine/types.js'
8
- import { type FormRequest } from '~/src/server/routes/types.js'
7
+ import {
8
+ type FormRequest,
9
+ type FormResponseToolkit
10
+ } from '~/src/server/routes/types.js'
9
11
 
10
12
  export class StatusPageController extends QuestionPageController {
11
13
  declare pageDef: PageStatus
12
- allowSaveAndReturn = false
14
+ allowSaveAndExit = false
13
15
 
14
16
  constructor(model: FormModel, pageDef: PageStatus) {
15
17
  super(model, pageDef)
@@ -24,7 +26,7 @@ export class StatusPageController extends QuestionPageController {
24
26
  return async (
25
27
  request: FormRequest,
26
28
  context: FormContext,
27
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
29
+ h: FormResponseToolkit
28
30
  ) => {
29
31
  const { viewModel, viewName } = this
30
32
 
@@ -5,7 +5,7 @@ import {
5
5
  type SubmitPayload
6
6
  } from '@defra/forms-model'
7
7
  import Boom from '@hapi/boom'
8
- import { type ResponseToolkit, type RouteOptions } from '@hapi/hapi'
8
+ import { type RouteOptions } from '@hapi/hapi'
9
9
 
10
10
  import { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'
11
11
  import { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'
@@ -30,13 +30,16 @@ import {
30
30
  type FormSubmissionState
31
31
  } from '~/src/server/plugins/engine/types.js'
32
32
  import {
33
+ FormAction,
33
34
  type FormRequest,
34
35
  type FormRequestPayload,
35
- type FormRequestPayloadRefs
36
+ type FormRequestPayloadRefs,
37
+ type FormResponseToolkit
36
38
  } from '~/src/server/routes/types.js'
37
39
 
38
40
  export class SummaryPageController extends QuestionPageController {
39
41
  declare pageDef: Page
42
+ allowSaveAndExit = true
40
43
 
41
44
  /**
42
45
  * The controller which is used when Page["controller"] is defined as "./pages/summary.js"
@@ -69,7 +72,7 @@ export class SummaryPageController extends QuestionPageController {
69
72
  viewModel.feedbackLink = this.feedbackLink
70
73
  viewModel.phaseTag = this.phaseTag
71
74
  viewModel.components = components
72
- viewModel.allowSaveAndReturn = this.shouldShowSaveAndReturn(request.server)
75
+ viewModel.allowSaveAndExit = this.shouldShowSaveAndExit(request.server)
73
76
 
74
77
  return viewModel
75
78
  }
@@ -81,7 +84,7 @@ export class SummaryPageController extends QuestionPageController {
81
84
  return async (
82
85
  request: FormRequest,
83
86
  context: FormContext,
84
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
87
+ h: FormResponseToolkit
85
88
  ) => {
86
89
  const { viewName } = this
87
90
 
@@ -102,10 +105,17 @@ export class SummaryPageController extends QuestionPageController {
102
105
  return async (
103
106
  request: FormRequestPayload,
104
107
  context: FormContext,
105
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
108
+ h: FormResponseToolkit
106
109
  ) => {
107
110
  const { model } = this
108
111
  const { params } = request
112
+
113
+ // Check if this is a save-and-exit action
114
+ const { action } = request.payload
115
+ if (action === FormAction.SaveAndExit) {
116
+ return this.handleSaveAndExit(request, context, h)
117
+ }
118
+
109
119
  const cacheService = getCacheService(request.server)
110
120
 
111
121
  const { formsService } = this.model.services
@@ -1,6 +1,6 @@
1
1
  import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
2
2
  import { TerminalPageController } from '~/src/server/plugins/engine/pageControllers/TerminalPageController.js'
3
- import { serverWithSaveAndReturn } from '~/src/server/plugins/engine/pageControllers/__stubs__/server.js'
3
+ import { serverWithSaveAndExit } from '~/src/server/plugins/engine/pageControllers/__stubs__/server.js'
4
4
  import definition from '~/test/form/definitions/basic.js'
5
5
 
6
6
  describe('TerminalController', () => {
@@ -27,9 +27,9 @@ describe('TerminalController', () => {
27
27
  })
28
28
  })
29
29
 
30
- describe('shouldShowSaveAndReturn', () => {
31
- it('should return false (TerminalPageController does not allow save and return)', () => {
32
- expect(controller1.shouldShowSaveAndReturn(serverWithSaveAndReturn)).toBe(
30
+ describe('shouldShowSaveAndExit', () => {
31
+ it('should return false (TerminalPageController does not allow save and exit)', () => {
32
+ expect(controller1.shouldShowSaveAndExit(serverWithSaveAndExit)).toBe(
33
33
  false
34
34
  )
35
35
  })
@@ -1,19 +1,22 @@
1
1
  import { type PageTerminal } from '@defra/forms-model'
2
2
  import Boom from '@hapi/boom'
3
- import { type ResponseObject, type ResponseToolkit } from '@hapi/hapi'
3
+ import { type ResponseObject } from '@hapi/hapi'
4
4
 
5
5
  import { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'
6
6
  import { type FormContext } from '~/src/server/plugins/engine/types.js'
7
- import { type FormRequestPayload } from '~/src/server/routes/types.js'
7
+ import {
8
+ type FormRequestPayload,
9
+ type FormResponseToolkit
10
+ } from '~/src/server/routes/types.js'
8
11
 
9
12
  export class TerminalPageController extends QuestionPageController {
10
13
  declare pageDef: PageTerminal
11
- allowSaveAndReturn = false
14
+ allowSaveAndExit = false
12
15
 
13
16
  makePostRouteHandler(): (
14
17
  request: FormRequestPayload,
15
18
  context: FormContext,
16
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
19
+ h: FormResponseToolkit
17
20
  ) => Promise<ResponseObject> {
18
21
  throw Boom.methodNotAllowed('POST method not allowed for terminal pages')
19
22
  }
@@ -12,16 +12,15 @@ export const server: Server = {
12
12
  }
13
13
  } as Server // only mocking out properties we care about;
14
14
 
15
- export const serverWithSaveAndReturn: Server = {
15
+ export const serverWithSaveAndExit: Server = {
16
16
  plugins: {
17
17
  ...server.plugins,
18
18
  'forms-engine-plugin': {
19
19
  ...server.plugins['forms-engine-plugin'],
20
- saveAndReturn: {
21
- keyGenerator: jest.fn().mockReturnValue('foobar'),
22
- sessionHydrator: jest.fn().mockReturnValue({}),
23
- sessionPersister: jest.fn().mockImplementation(() => Promise.resolve())
24
- } as Pick<PluginOptions, 'saveAndReturn'>
20
+ saveAndExit: jest.fn().mockReturnValue({}) as Pick<
21
+ PluginOptions,
22
+ 'saveAndExit'
23
+ >
25
24
  }
26
25
  }
27
26
  } as Server // only mocking out properties we care about
@@ -8,7 +8,6 @@ import {
8
8
 
9
9
  import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
10
10
  import { validatePluginOptions } from '~/src/server/plugins/engine/options.js'
11
- import { getRoutes as getSaveAndReturnExitRoutes } from '~/src/server/plugins/engine/routes/exit.js'
12
11
  import { getRoutes as getFileUploadStatusRoutes } from '~/src/server/plugins/engine/routes/file-upload.js'
13
12
  import { makeLoadFormPreHandler } from '~/src/server/plugins/engine/routes/index.js'
14
13
  import { getRoutes as getQuestionRoutes } from '~/src/server/plugins/engine/routes/questions.js'
@@ -31,28 +30,24 @@ export const plugin = {
31
30
 
32
31
  const {
33
32
  model,
34
- cacheName,
35
- saveAndReturn,
33
+ cache,
34
+ saveAndExit,
36
35
  nunjucks: nunjucksOptions,
37
36
  viewContext,
38
37
  preparePageEventRequestOptions
39
38
  } = options
40
39
 
41
- const cacheService = new CacheService({
42
- server,
43
- cacheName,
44
- options: {
45
- keyGenerator: saveAndReturn?.keyGenerator,
46
- sessionHydrator: saveAndReturn?.sessionHydrator
47
- }
48
- })
40
+ const cacheService =
41
+ typeof cache === 'string'
42
+ ? new CacheService({ server, cacheName: cache })
43
+ : cache
49
44
 
50
45
  await registerVision(server, options)
51
46
 
52
47
  server.expose('baseLayoutPath', nunjucksOptions.baseLayoutPath)
53
48
  server.expose('viewContext', viewContext)
54
49
  server.expose('cacheService', cacheService)
55
- server.expose('saveAndReturn', saveAndReturn)
50
+ server.expose('saveAndExit', saveAndExit)
56
51
 
57
52
  server.app.model = model
58
53
 
@@ -92,7 +87,6 @@ export const plugin = {
92
87
  ),
93
88
  ...getRepeaterSummaryRoutes(getRouteOptions, postRouteOptions),
94
89
  ...getRepeaterItemDeleteRoutes(getRouteOptions, postRouteOptions),
95
- ...getSaveAndReturnExitRoutes(getRouteOptions),
96
90
  ...getFileUploadStatusRoutes()
97
91
  ]
98
92
 
@@ -21,17 +21,18 @@ import { type PageControllerClass } from '~/src/server/plugins/engine/pageContro
21
21
  import { generateUniqueReference } from '~/src/server/plugins/engine/referenceNumbers.js'
22
22
  import * as defaultServices from '~/src/server/plugins/engine/services/index.js'
23
23
  import {
24
+ type AnyFormRequest,
24
25
  type FormContext,
25
26
  type PluginOptions
26
27
  } from '~/src/server/plugins/engine/types.js'
27
28
  import {
28
29
  type FormRequest,
29
- type FormRequestPayload
30
+ type FormResponseToolkit
30
31
  } from '~/src/server/routes/types.js'
31
32
 
32
33
  export async function redirectOrMakeHandler(
33
- request: FormRequest | FormRequestPayload,
34
- h: Pick<ResponseToolkit, 'redirect' | 'view'>,
34
+ request: AnyFormRequest,
35
+ h: FormResponseToolkit,
35
36
  makeHandler: (
36
37
  page: PageControllerClass,
37
38
  context: FormContext
@@ -92,10 +93,7 @@ export function makeLoadFormPreHandler(server: Server, options: PluginOptions) {
92
93
 
93
94
  const { formsService } = services
94
95
 
95
- async function handler(
96
- request: FormRequest | FormRequestPayload,
97
- h: ResponseToolkit
98
- ) {
96
+ async function handler(request: AnyFormRequest, h: ResponseToolkit) {
99
97
  if (server.app.model) {
100
98
  request.app.model = server.app.model
101
99
 
@@ -153,10 +151,12 @@ export function makeLoadFormPreHandler(server: Server, options: PluginOptions) {
153
151
  : `${prefix}/${slug}`
154
152
  ).substring(1)
155
153
 
154
+ const versionNumber = metadata.versions?.[0]?.versionNumber
155
+
156
156
  // Construct the form model
157
157
  const model = new FormModel(
158
158
  definition,
159
- { basePath },
159
+ { basePath, versionNumber },
160
160
  services,
161
161
  controllers
162
162
  )
@@ -181,10 +181,7 @@ export function makeLoadFormPreHandler(server: Server, options: PluginOptions) {
181
181
  return handler
182
182
  }
183
183
 
184
- export function dispatchHandler(
185
- request: FormRequest,
186
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
187
- ) {
184
+ export function dispatchHandler(request: FormRequest, h: FormResponseToolkit) {
188
185
  const { model } = request.app
189
186
 
190
187
  const servicePath = model ? `/${model.basePath}` : ''
@@ -1,5 +1,5 @@
1
1
  import Boom from '@hapi/boom'
2
- import { type ResponseObject, type ResponseToolkit } from '@hapi/hapi'
2
+ import { type ResponseObject } from '@hapi/hapi'
3
3
  // eslint-disable-next-line n/no-unpublished-import
4
4
  import nock from 'nock'
5
5
 
@@ -10,10 +10,14 @@ import {
10
10
  makeGetHandler,
11
11
  makePostHandler
12
12
  } from '~/src/server/plugins/engine/routes/questions.js'
13
- import { type FormContext } from '~/src/server/plugins/engine/types.js'
13
+ import {
14
+ type AnyFormRequest,
15
+ type FormContext
16
+ } from '~/src/server/plugins/engine/types.js'
14
17
  import {
15
18
  type FormRequest,
16
- type FormRequestPayload
19
+ type FormRequestPayload,
20
+ type FormResponseToolkit
17
21
  } from '~/src/server/routes/types.js'
18
22
  jest.mock('~/src/server/plugins/engine/models/SummaryViewModel', () => ({
19
23
  SummaryViewModel: class {
@@ -35,7 +39,7 @@ jest.mock('~/src/server/plugins/engine/outputFormatters/machine/v1', () => ({
35
39
  jest.mock('~/src/server/plugins/engine/routes/index')
36
40
 
37
41
  describe('makeGetHandler', () => {
38
- const hMock: Pick<ResponseToolkit, 'redirect' | 'view'> = {
42
+ const hMock: FormResponseToolkit = {
39
43
  redirect: jest.fn(),
40
44
  view: jest.fn()
41
45
  }
@@ -64,7 +68,7 @@ describe('makeGetHandler', () => {
64
68
  (
65
69
  _request: FormRequest,
66
70
  context: FormContext,
67
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>
71
+ _h: FormResponseToolkit
68
72
  ) => {
69
73
  data = context.data
70
74
  return Promise.resolve({} as unknown as ResponseObject)
@@ -80,12 +84,8 @@ describe('makeGetHandler', () => {
80
84
 
81
85
  jest
82
86
  .mocked(redirectOrMakeHandler)
83
- .mockImplementation(
84
- (
85
- _req: FormRequest | FormRequestPayload,
86
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>,
87
- fn
88
- ) => Promise.resolve(fn(pageMock, contextMock))
87
+ .mockImplementation((_req: AnyFormRequest, _h: FormResponseToolkit, fn) =>
88
+ Promise.resolve(fn(pageMock, contextMock))
89
89
  )
90
90
 
91
91
  await makeGetHandler()(requestMock, hMock)
@@ -108,7 +108,7 @@ describe('makeGetHandler', () => {
108
108
  (
109
109
  _request: FormRequest,
110
110
  context: FormContext,
111
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>
111
+ _h: FormResponseToolkit
112
112
  ) => {
113
113
  data = context.data
114
114
  return Promise.resolve({} as unknown as ResponseObject)
@@ -126,12 +126,8 @@ describe('makeGetHandler', () => {
126
126
 
127
127
  jest
128
128
  .mocked(redirectOrMakeHandler)
129
- .mockImplementation(
130
- (
131
- _req: FormRequest | FormRequestPayload,
132
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>,
133
- fn
134
- ) => Promise.resolve(fn(pageMock, contextMock))
129
+ .mockImplementation((_req: AnyFormRequest, _h: FormResponseToolkit, fn) =>
130
+ Promise.resolve(fn(pageMock, contextMock))
135
131
  )
136
132
 
137
133
  await makeGetHandler()(requestMock, hMock)
@@ -152,7 +148,7 @@ describe('makeGetHandler', () => {
152
148
  (
153
149
  _request: FormRequest,
154
150
  _context: FormContext,
155
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>
151
+ _h: FormResponseToolkit
156
152
  ) => {
157
153
  return Promise.resolve({} as unknown as ResponseObject)
158
154
  }
@@ -168,11 +164,7 @@ describe('makeGetHandler', () => {
168
164
  jest
169
165
  .mocked(redirectOrMakeHandler)
170
166
  .mockImplementation(
171
- async (
172
- _req: FormRequest | FormRequestPayload,
173
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>,
174
- fn
175
- ) => {
167
+ async (_req: AnyFormRequest, _h: FormResponseToolkit, fn) => {
176
168
  try {
177
169
  await fn(pageMock, contextMock)
178
170
  } catch (err) {
@@ -190,7 +182,7 @@ describe('makeGetHandler', () => {
190
182
  })
191
183
 
192
184
  describe('makePostHandler', () => {
193
- const hMock: Pick<ResponseToolkit, 'redirect' | 'view'> = {
185
+ const hMock: FormResponseToolkit = {
194
186
  redirect: jest.fn(),
195
187
  view: jest.fn()
196
188
  }
@@ -221,7 +213,7 @@ describe('makePostHandler', () => {
221
213
  (
222
214
  _request: FormRequest,
223
215
  _context: FormContext,
224
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>
216
+ _h: FormResponseToolkit
225
217
  ) => {
226
218
  // do return a valid ResponseObject wrapped in Promise.resolve
227
219
  return mockPostResponse
@@ -238,12 +230,8 @@ describe('makePostHandler', () => {
238
230
 
239
231
  jest
240
232
  .mocked(redirectOrMakeHandler)
241
- .mockImplementation(
242
- (
243
- _req: FormRequest | FormRequestPayload,
244
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>,
245
- fn
246
- ) => Promise.resolve(fn(pageMock, contextMock))
233
+ .mockImplementation((_req: AnyFormRequest, _h: FormResponseToolkit, fn) =>
234
+ Promise.resolve(fn(pageMock, contextMock))
247
235
  )
248
236
 
249
237
  const response = await makePostHandler()(requestMock, hMock)
@@ -263,7 +251,7 @@ describe('makePostHandler', () => {
263
251
  (
264
252
  _request: FormRequest,
265
253
  _context: FormContext,
266
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>
254
+ _h: FormResponseToolkit
267
255
  ) => {
268
256
  return Promise.resolve({} as unknown as ResponseObject)
269
257
  }
@@ -281,12 +269,8 @@ describe('makePostHandler', () => {
281
269
 
282
270
  jest
283
271
  .mocked(redirectOrMakeHandler)
284
- .mockImplementation(
285
- (
286
- _req: FormRequest | FormRequestPayload,
287
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>,
288
- fn
289
- ) => Promise.resolve(fn(pageMock, contextMock))
272
+ .mockImplementation((_req: AnyFormRequest, _h: FormResponseToolkit, fn) =>
273
+ Promise.resolve(fn(pageMock, contextMock))
290
274
  )
291
275
 
292
276
  await makePostHandler()(requestMock, hMock)
@@ -309,7 +293,7 @@ describe('makePostHandler', () => {
309
293
  (
310
294
  _request: FormRequest,
311
295
  _context: FormContext,
312
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>
296
+ _h: FormResponseToolkit
313
297
  ) => {
314
298
  // do return a valid ResponseObject wrapped in Promise.resolve
315
299
  return mockPostResponse
@@ -326,12 +310,8 @@ describe('makePostHandler', () => {
326
310
 
327
311
  jest
328
312
  .mocked(redirectOrMakeHandler)
329
- .mockImplementation(
330
- (
331
- _req: FormRequest | FormRequestPayload,
332
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>,
333
- fn
334
- ) => Promise.resolve(fn(pageMock, contextMock))
313
+ .mockImplementation((_req: AnyFormRequest, _h: FormResponseToolkit, fn) =>
314
+ Promise.resolve(fn(pageMock, contextMock))
335
315
  )
336
316
 
337
317
  await makePostHandler()(requestMock, hMock)
@@ -352,7 +332,7 @@ describe('makePostHandler', () => {
352
332
  (
353
333
  _request: FormRequest,
354
334
  _context: FormContext,
355
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>
335
+ _h: FormResponseToolkit
356
336
  ) => {
357
337
  return Promise.resolve({} as unknown as ResponseObject)
358
338
  }
@@ -369,11 +349,7 @@ describe('makePostHandler', () => {
369
349
  jest
370
350
  .mocked(redirectOrMakeHandler)
371
351
  .mockImplementation(
372
- async (
373
- _req: FormRequest | FormRequestPayload,
374
- _h: Pick<ResponseToolkit, 'redirect' | 'view'>,
375
- fn
376
- ) => {
352
+ async (_req: AnyFormRequest, _h: FormResponseToolkit, fn) => {
377
353
  try {
378
354
  await fn(pageMock, contextMock)
379
355
  } catch (err) {
@@ -395,7 +371,7 @@ function createMockPageController(
395
371
  routeHandler: (
396
372
  request: FormRequest,
397
373
  context: FormContext,
398
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
374
+ h: FormResponseToolkit
399
375
  ) => ResponseObject | Promise<ResponseObject>
400
376
  ): PageControllerClass {
401
377
  return {
@@ -2,7 +2,6 @@ import { hasFormComponents, slugSchema, type Event } from '@defra/forms-model'
2
2
  import Boom from '@hapi/boom'
3
3
  import {
4
4
  type ResponseObject,
5
- type ResponseToolkit,
6
5
  type RouteOptions,
7
6
  type ServerRoute
8
7
  } from '@hapi/hapi'
@@ -25,6 +24,7 @@ import {
25
24
  redirectOrMakeHandler
26
25
  } from '~/src/server/plugins/engine/routes/index.js'
27
26
  import {
27
+ type AnyFormRequest,
28
28
  type FormContext,
29
29
  type PreparePageEventRequestOptions
30
30
  } from '~/src/server/plugins/engine/types.js'
@@ -32,7 +32,8 @@ import {
32
32
  type FormRequest,
33
33
  type FormRequestPayload,
34
34
  type FormRequestPayloadRefs,
35
- type FormRequestRefs
35
+ type FormRequestRefs,
36
+ type FormResponseToolkit
36
37
  } from '~/src/server/routes/types.js'
37
38
  import {
38
39
  actionSchema,
@@ -44,7 +45,7 @@ import {
44
45
  import * as httpService from '~/src/server/services/httpService.js'
45
46
 
46
47
  async function handleHttpEvent(
47
- request: FormRequest | FormRequestPayload,
48
+ request: AnyFormRequest,
48
49
  page: PageControllerClass,
49
50
  context: FormContext,
50
51
  event: Event,
@@ -75,10 +76,7 @@ async function handleHttpEvent(
75
76
  export function makeGetHandler(
76
77
  preparePageEventRequestOptions?: PreparePageEventRequestOptions
77
78
  ) {
78
- return function getHandler(
79
- request: FormRequest,
80
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
81
- ) {
79
+ return function getHandler(request: FormRequest, h: FormResponseToolkit) {
82
80
  const { params } = request
83
81
 
84
82
  if (normalisePath(params.path) === '') {
@@ -116,7 +114,7 @@ export function makePostHandler(
116
114
  ) {
117
115
  return function postHandler(
118
116
  request: FormRequestPayload,
119
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
117
+ h: FormResponseToolkit
120
118
  ) {
121
119
  const { query } = request
122
120