@defra/forms-engine-plugin 4.0.42 → 4.0.44

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 (169) hide show
  1. package/.public/javascripts/shared.min.js +1 -1
  2. package/.public/javascripts/shared.min.js.map +1 -1
  3. package/.public/stylesheets/application.min.css +1 -1
  4. package/.public/stylesheets/application.min.css.map +1 -1
  5. package/.server/client/javascripts/location-map.js +8 -4
  6. package/.server/client/javascripts/location-map.js.map +1 -1
  7. package/.server/client/stylesheets/_payment-field.scss +8 -0
  8. package/.server/client/stylesheets/application.scss +2 -0
  9. package/.server/index.js +3 -1
  10. package/.server/index.js.map +1 -1
  11. package/.server/server/constants.d.ts +1 -0
  12. package/.server/server/constants.js +1 -0
  13. package/.server/server/constants.js.map +1 -1
  14. package/.server/server/forms/payment-test.yaml +42 -0
  15. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +14 -0
  16. package/.server/server/plugins/engine/components/FormComponent.d.ts +1 -0
  17. package/.server/server/plugins/engine/components/FormComponent.js +1 -0
  18. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  19. package/.server/server/plugins/engine/components/PaymentField.d.ts +135 -0
  20. package/.server/server/plugins/engine/components/PaymentField.js +228 -0
  21. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -0
  22. package/.server/server/plugins/engine/components/PaymentField.types.d.ts +21 -0
  23. package/.server/server/plugins/engine/components/PaymentField.types.js +2 -0
  24. package/.server/server/plugins/engine/components/PaymentField.types.js.map +1 -0
  25. package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -1
  26. package/.server/server/plugins/engine/components/UkAddressField.js +3 -1
  27. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  28. package/.server/server/plugins/engine/components/helpers/components.d.ts +1 -1
  29. package/.server/server/plugins/engine/components/helpers/components.js +3 -0
  30. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  31. package/.server/server/plugins/engine/components/index.d.ts +1 -0
  32. package/.server/server/plugins/engine/components/index.js +1 -0
  33. package/.server/server/plugins/engine/components/index.js.map +1 -1
  34. package/.server/server/plugins/engine/configureEnginePlugin.d.ts +1 -1
  35. package/.server/server/plugins/engine/configureEnginePlugin.js +4 -2
  36. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
  37. package/.server/server/plugins/engine/helpers.d.ts +1 -0
  38. package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +3 -0
  39. package/.server/server/plugins/engine/models/SummaryViewModel.js +7 -0
  40. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  41. package/.server/server/plugins/engine/options.js +2 -1
  42. package/.server/server/plugins/engine/options.js.map +1 -1
  43. package/.server/server/plugins/engine/outputFormatters/human/v1.js +34 -1
  44. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  45. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +22 -0
  46. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +43 -1
  47. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  48. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +29 -8
  49. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  50. package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +2 -0
  51. package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +17 -0
  52. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +173 -51
  53. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  54. package/.server/server/plugins/engine/pageControllers/errors.d.ts +31 -0
  55. package/.server/server/plugins/engine/pageControllers/errors.js +59 -2
  56. package/.server/server/plugins/engine/pageControllers/errors.js.map +1 -1
  57. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +27 -0
  58. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +77 -0
  59. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -0
  60. package/.server/server/plugins/engine/plugin.js +10 -5
  61. package/.server/server/plugins/engine/plugin.js.map +1 -1
  62. package/.server/server/plugins/engine/routes/index.js +8 -4
  63. package/.server/server/plugins/engine/routes/index.js.map +1 -1
  64. package/.server/server/plugins/engine/routes/payment-helper.d.ts +14 -0
  65. package/.server/server/plugins/engine/routes/payment-helper.js +41 -0
  66. package/.server/server/plugins/engine/routes/payment-helper.js.map +1 -0
  67. package/.server/server/plugins/engine/routes/payment-helper.test.js +81 -0
  68. package/.server/server/plugins/engine/routes/payment-helper.test.js.map +1 -0
  69. package/.server/server/plugins/engine/routes/payment.d.ts +8 -0
  70. package/.server/server/plugins/engine/routes/payment.js +140 -0
  71. package/.server/server/plugins/engine/routes/payment.js.map +1 -0
  72. package/.server/server/plugins/engine/routes/payment.test.js +187 -0
  73. package/.server/server/plugins/engine/routes/payment.test.js.map +1 -0
  74. package/.server/server/plugins/engine/services/localFormsService.js +6 -0
  75. package/.server/server/plugins/engine/services/localFormsService.js.map +1 -1
  76. package/.server/server/plugins/engine/types/schema.js +7 -0
  77. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  78. package/.server/server/plugins/engine/types.d.ts +20 -1
  79. package/.server/server/plugins/engine/types.js +4 -0
  80. package/.server/server/plugins/engine/types.js.map +1 -1
  81. package/.server/server/plugins/engine/validationHelpers.d.ts +1 -1
  82. package/.server/server/plugins/engine/validationHelpers.js.map +1 -1
  83. package/.server/server/plugins/engine/views/components/paymentfield.html +42 -0
  84. package/.server/server/plugins/engine/views/index.html +9 -1
  85. package/.server/server/plugins/engine/views/partials/form.html +20 -5
  86. package/.server/server/plugins/engine/views/summary.html +17 -1
  87. package/.server/server/plugins/map/routes/get-os-token.d.ts +6 -0
  88. package/.server/server/plugins/map/routes/get-os-token.js +41 -0
  89. package/.server/server/plugins/map/routes/get-os-token.js.map +1 -0
  90. package/.server/server/plugins/map/routes/get-os-token.test.js +49 -0
  91. package/.server/server/plugins/map/routes/get-os-token.test.js.map +1 -0
  92. package/.server/server/plugins/map/routes/index.d.ts +1 -11
  93. package/.server/server/plugins/map/routes/index.js +60 -16
  94. package/.server/server/plugins/map/routes/index.js.map +1 -1
  95. package/.server/server/plugins/map/types.d.ts +1 -0
  96. package/.server/server/plugins/map/types.js +1 -0
  97. package/.server/server/plugins/map/types.js.map +1 -1
  98. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  99. package/.server/server/plugins/payment/helper.d.ts +30 -0
  100. package/.server/server/plugins/payment/helper.js +49 -0
  101. package/.server/server/plugins/payment/helper.js.map +1 -0
  102. package/.server/server/plugins/payment/helper.test.js +37 -0
  103. package/.server/server/plugins/payment/helper.test.js.map +1 -0
  104. package/.server/server/plugins/payment/service.d.ts +40 -0
  105. package/.server/server/plugins/payment/service.js +129 -0
  106. package/.server/server/plugins/payment/service.js.map +1 -0
  107. package/.server/server/plugins/payment/service.test.js +162 -0
  108. package/.server/server/plugins/payment/service.test.js.map +1 -0
  109. package/.server/server/plugins/payment/types.d.ts +172 -0
  110. package/.server/server/plugins/payment/types.js +78 -0
  111. package/.server/server/plugins/payment/types.js.map +1 -0
  112. package/.server/server/types.d.ts +3 -0
  113. package/.server/server/types.js.map +1 -1
  114. package/.server/typings/hapi/index.d.js.map +1 -1
  115. package/README.md +12 -9
  116. package/package.json +2 -2
  117. package/src/client/javascripts/location-map.js +12 -4
  118. package/src/client/stylesheets/_payment-field.scss +8 -0
  119. package/src/client/stylesheets/application.scss +2 -0
  120. package/src/index.ts +5 -1
  121. package/src/server/constants.js +1 -0
  122. package/src/server/forms/payment-test.yaml +42 -0
  123. package/src/server/forms/register-as-a-unicorn-breeder.yaml +14 -0
  124. package/src/server/plugins/engine/components/FormComponent.ts +1 -0
  125. package/src/server/plugins/engine/components/PaymentField.test.ts +611 -0
  126. package/src/server/plugins/engine/components/PaymentField.ts +367 -0
  127. package/src/server/plugins/engine/components/PaymentField.types.ts +21 -0
  128. package/src/server/plugins/engine/components/UkAddressField.ts +2 -1
  129. package/src/server/plugins/engine/components/helpers/components.ts +5 -0
  130. package/src/server/plugins/engine/components/index.ts +1 -0
  131. package/src/server/plugins/engine/configureEnginePlugin.ts +4 -2
  132. package/src/server/plugins/engine/models/SummaryViewModel.ts +8 -0
  133. package/src/server/plugins/engine/options.js +2 -1
  134. package/src/server/plugins/engine/outputFormatters/human/v1.payment.test.ts +147 -0
  135. package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +105 -103
  136. package/src/server/plugins/engine/outputFormatters/human/v1.ts +61 -2
  137. package/src/server/plugins/engine/outputFormatters/machine/v2.payment.test.ts +115 -0
  138. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +60 -1
  139. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +32 -6
  140. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +247 -72
  141. package/src/server/plugins/engine/pageControllers/errors.test.ts +13 -1
  142. package/src/server/plugins/engine/pageControllers/errors.ts +79 -4
  143. package/src/server/plugins/engine/pageControllers/helpers/submission.test.ts +299 -0
  144. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +110 -0
  145. package/src/server/plugins/engine/plugin.ts +17 -10
  146. package/src/server/plugins/engine/routes/index.ts +17 -16
  147. package/src/server/plugins/engine/routes/payment-helper.js +39 -0
  148. package/src/server/plugins/engine/routes/payment-helper.test.js +90 -0
  149. package/src/server/plugins/engine/routes/payment.js +151 -0
  150. package/src/server/plugins/engine/routes/payment.test.js +180 -0
  151. package/src/server/plugins/engine/services/localFormsService.js +7 -0
  152. package/src/server/plugins/engine/types/schema.ts +9 -0
  153. package/src/server/plugins/engine/types.ts +25 -1
  154. package/src/server/plugins/engine/validationHelpers.ts +1 -1
  155. package/src/server/plugins/engine/views/components/paymentfield.html +42 -0
  156. package/src/server/plugins/engine/views/index.html +9 -1
  157. package/src/server/plugins/engine/views/partials/form.html +20 -5
  158. package/src/server/plugins/engine/views/summary.html +17 -1
  159. package/src/server/plugins/map/routes/get-os-token.js +41 -0
  160. package/src/server/plugins/map/routes/get-os-token.test.js +55 -0
  161. package/src/server/plugins/map/routes/index.js +70 -24
  162. package/src/server/plugins/map/types.js +1 -0
  163. package/src/server/plugins/payment/helper.js +56 -0
  164. package/src/server/plugins/payment/helper.test.js +52 -0
  165. package/src/server/plugins/payment/service.js +171 -0
  166. package/src/server/plugins/payment/service.test.js +205 -0
  167. package/src/server/plugins/payment/types.js +77 -0
  168. package/src/server/types.ts +3 -0
  169. package/src/typings/hapi/index.d.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":["FileStatus","UploadStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Event,\n type FormVersionMetadata,\n type Item,\n type List,\n type Page,\n type UkAddressFieldComponent\n} from '@defra/forms-model'\nimport {\n type PluginProperties,\n type Request,\n type ResponseObject\n} from '@hapi/hapi'\nimport { type JoiExpression, type ValidationErrorItem } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { type FileUploadField } from '~/src/server/plugins/engine/components/index.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel,\n type DatePartsState,\n type EastingNorthingState,\n type LatLongState,\n type MonthYearState\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItemField } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { type QuestionPageController } from '~/src/server/plugins/engine/pageControllers/index.js'\nimport {\n type FileStatus,\n type FormAdapterSubmissionSchemaVersion,\n type UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport {\n type FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\nimport { type RequestOptions } from '~/src/server/services/httpService.js'\nimport { type Services } from '~/src/server/types.js'\n\nexport type AnyFormRequest = FormRequest | FormRequestPayload\nexport type AnyRequest = Request | AnyFormRequest\n\n/**\n * Form submission state stores the following in Redis:\n * Props containing user's submitted values as `{ [inputId]: value }` or as `{ [sectionName]: { [inputName]: value } }`\n * a) . e.g:\n * ```ts\n * {\n * _C9PRHmsgt: 'Ben',\n * WfLk9McjzX: 'Music',\n * IK7jkUFCBL: 'Royal Academy of Music'\n * }\n * ```\n *\n * b)\n * ```ts\n * {\n * checkBeforeYouStart: { ukPassport: true },\n * applicantDetails: {\n * numberOfApplicants: 1,\n * phoneNumber: '77777777',\n * emailAddress: 'aaa@aaa.com'\n * },\n * applicantOneDetails: {\n * firstName: 'a',\n * middleName: 'a',\n * lastName: 'a',\n * address: { addressLine1: 'a', addressLine2: 'a', town: 'a', postcode: 'a' }\n * }\n * }\n * ```\n */\n\n/**\n * Form submission state\n */\nexport type FormSubmissionState = {\n upload?: Record<string, TempFileState>\n} & FormState\n\nexport interface FormSubmissionError\n extends Pick<ValidationErrorItem, 'context' | 'path'> {\n href: string // e.g: '#dateField__day'\n name: string // e.g: 'dateField__day'\n text: string // e.g: 'Date field must be a real date'\n}\n\nexport interface FormConfirmationState {\n confirmed?: true\n formId?: string\n referenceNumber?: string\n}\n\nexport interface FormPayloadParams {\n action?: FormAction\n confirm?: true\n crumb?: string\n itemId?: string\n}\n\n/**\n * Form POST for question pages\n * (after Joi has converted value types)\n */\nexport type FormPayload = FormPayloadParams & Partial<Record<string, FormValue>>\n\nexport type FormValue =\n | Item['value']\n | Item['value'][]\n | UploadState\n | RepeatListState\n | undefined\n\nexport type FormState = Partial<Record<string, FormStateValue>>\nexport type FormStateValue = Exclude<FormValue, undefined> | null\n\nexport interface FormValidationResult<\n ValueType extends FormPayload | FormSubmissionState\n> {\n value: ValueType\n errors: FormSubmissionError[] | undefined\n}\n\nexport interface FormContext {\n /**\n * Evaluation form state only (filtered by visited paths),\n * with values formatted for condition evaluation using\n * {@link FormComponent.getContextValueFromState}\n */\n evaluationState: FormState\n\n /**\n * Relevant form state only (filtered by visited paths)\n */\n relevantState: FormState\n\n /**\n * Relevant pages only (filtered by visited paths)\n */\n relevantPages: PageControllerClass[]\n\n /**\n * Form submission payload (single page)\n */\n payload: FormPayload\n\n /**\n * Form submission state (entire form)\n */\n state: FormSubmissionState\n\n /**\n * Validation errors (entire form)\n */\n errors?: FormSubmissionError[]\n\n /**\n * Visited paths evaluated from form state\n */\n paths: string[]\n\n /**\n * Preview URL direct access is allowed\n */\n isForceAccess: boolean\n\n /**\n * Miscellaneous extra data from event responses\n */\n data: object\n\n pageDefMap: Map<string, Page>\n listDefMap: Map<string, List>\n componentDefMap: Map<string, ComponentDef>\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n referenceNumber: string\n submittedVersionNumber?: number\n}\n\nexport type FormContextRequest = (\n | {\n method: 'get'\n payload?: undefined\n }\n | {\n method: 'post'\n payload: FormPayload\n }\n | {\n method: FormRequest['method']\n payload?: object | undefined\n }\n) &\n Pick<\n FormRequest,\n 'app' | 'method' | 'params' | 'path' | 'query' | 'url' | 'server'\n >\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport {\n FileStatus,\n UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\n\nexport type UploadState = FileState[]\n\nexport type FileUpload = {\n fileId: string\n filename: string\n contentLength: number\n} & (\n | {\n fileStatus: FileStatus.complete | FileStatus.rejected | FileStatus.pending\n errorMessage?: string\n }\n | {\n fileStatus: FileStatus.complete\n errorMessage?: undefined\n }\n)\n\nexport interface FileUploadMetadata {\n retrievalKey: string\n}\n\nexport type UploadStatusResponse =\n | {\n uploadStatus: UploadStatus.initiated\n metadata: FileUploadMetadata\n form: { file?: undefined }\n }\n | {\n uploadStatus: UploadStatus.pending | UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles?: number\n }\n | {\n uploadStatus: UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles: 0\n }\n\nexport type UploadStatusFileResponse = Exclude<\n UploadStatusResponse,\n { uploadStatus: UploadStatus.initiated }\n>\n\nexport interface FileState {\n uploadId: string\n status: UploadStatusFileResponse\n}\n\nexport interface TempFileState {\n upload?: UploadInitiateResponse\n files: UploadState\n}\n\nexport interface RepeatItemState extends FormPayload {\n itemId: string\n}\n\nexport type RepeatListState = RepeatItemState[]\n\nexport interface CheckAnswers {\n title?: ComponentText\n summaryList: SummaryList\n}\n\nexport interface SummaryList {\n classes?: string\n rows: SummaryListRow[]\n}\n\nexport interface SummaryListRow {\n key: ComponentText\n value: ComponentText\n actions?: { items: SummaryListAction[] }\n}\n\nexport type SummaryListAction = ComponentText & {\n href: string\n visuallyHiddenText: string\n}\n\nexport interface PageViewModelBase extends Partial<ViewContext> {\n page: PageController\n name?: string\n pageTitle: string\n sectionTitle?: string\n showTitle: boolean\n isStartPage: boolean\n backLink?: BackLink\n feedbackLink?: string\n serviceUrl: string\n phaseTag?: string\n}\n\nexport interface ItemDeletePageViewModel extends PageViewModelBase {\n context: FormContext\n itemTitle: string\n confirmation?: ComponentText\n buttonConfirm: ComponentText\n buttonCancel: ComponentText\n}\n\nexport interface FormPageViewModel extends PageViewModelBase {\n components: ComponentViewModel[]\n context: FormContext\n errors?: FormSubmissionError[]\n hasMissingNotificationEmail?: boolean\n allowSaveAndExit: boolean\n}\n\nexport interface RepeaterSummaryPageViewModel extends PageViewModelBase {\n context: FormContext\n errors?: FormSubmissionError[]\n checkAnswers: CheckAnswers[]\n repeatTitle: string\n allowSaveAndExit: boolean\n}\n\nexport interface FeaturedFormPageViewModel extends FormPageViewModel {\n formAction?: string\n formComponent: ComponentViewModel\n componentsBefore: ComponentViewModel[]\n uploadId: string | undefined\n proxyUrl: string | null\n}\n\nexport type PageViewModel =\n | PageViewModelBase\n | ItemDeletePageViewModel\n | FormPageViewModel\n | RepeaterSummaryPageViewModel\n | FeaturedFormPageViewModel\n\nexport type GlobalFunction = (value: unknown) => unknown\nexport type FilterFunction = (value: unknown) => unknown\nexport interface ErrorMessageTemplate {\n type: string\n template: JoiExpression\n}\n\nexport interface ErrorMessageTemplateList {\n baseErrors: ErrorMessageTemplate[]\n advancedSettingsErrors: ErrorMessageTemplate[]\n}\n\nexport type PreparePageEventRequestOptions = (\n options: RequestOptions,\n event: Event,\n page: PageControllerClass,\n context: FormContext\n) => void\n\nexport type OnRequestCallback = (\n request: AnyFormRequest,\n h: FormResponseToolkit,\n context: FormContext\n) =>\n | ResponseObject\n | FormResponseToolkit['continue']\n | Promise<ResponseObject | FormResponseToolkit['continue']>\n\nexport type SaveAndExitHandler = (\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n) => ResponseObject\n\nexport interface ExternalArgs {\n component: ComponentDef\n controller: QuestionPageController\n sourceUrl: string\n actionArgs: Record<string, string>\n}\n\nexport interface PostcodeLookupExternalArgs extends ExternalArgs {\n component: UkAddressFieldComponent\n actionArgs: { step: string }\n}\n\nexport interface ExternalStateAppendage {\n component: string\n data: FormStateValue | FormState\n}\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n cache?: CacheService | string\n globals?: Record<string, GlobalFunction>\n filters?: Record<string, FilterFunction>\n saveAndExit?: SaveAndExitHandler\n pluginPath?: string\n nunjucks: {\n baseLayoutPath: string\n paths: string[]\n }\n viewContext: PluginProperties['forms-engine-plugin']['viewContext']\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n baseUrl: string // base URL of the application, protocol and hostname e.g. \"https://myapp.com\"\n ordnanceSurveyApiKey?: string\n}\n\nexport interface FormAdapterSubmissionMessageMeta {\n schemaVersion: FormAdapterSubmissionSchemaVersion\n timestamp: Date\n referenceNumber: string\n formName: string\n formId: string\n formSlug: string\n status: FormStatus\n isPreview: boolean\n notificationEmail: string\n versionMetadata?: FormVersionMetadata\n custom?: Record<string, unknown>\n}\n\nexport type FormAdapterSubmissionMessageMetaSerialised = Omit<\n FormAdapterSubmissionMessageMeta,\n 'schemaVersion' | 'timestamp' | 'status'\n> & {\n schemaVersion: number\n status: string\n timestamp: string\n}\nexport interface FormAdapterFile {\n fileName: string\n fileId: string\n userDownloadLink: string\n}\n\nexport interface FormAdapterSubmissionMessageResult {\n files: {\n main: string\n repeaters: Record<string, string>\n }\n}\n\n/**\n * A detail item specifically for files\n */\nexport type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {\n field: FileUploadField\n}\nexport type RichFormValue =\n | FormValue\n | FormPayload\n | DatePartsState\n | MonthYearState\n | UkAddressState\n | EastingNorthingState\n | LatLongState\n\nexport interface FormAdapterSubmissionMessageData {\n main: Record<string, RichFormValue | null>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<string, FormAdapterFile[]>\n}\n\nexport interface FormAdapterSubmissionMessagePayload {\n meta: FormAdapterSubmissionMessageMeta\n data: FormAdapterSubmissionMessageData\n result: FormAdapterSubmissionMessageResult\n}\n\nexport interface FormAdapterSubmissionMessage\n extends FormAdapterSubmissionMessagePayload {\n messageId: string\n recordCreatedAt: Date\n}\n\nexport interface FormAdapterSubmissionService {\n handleFormSubmission: (\n submissionMessage: FormAdapterSubmissionMessage\n ) => unknown\n}\n"],"mappings":"AAsDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAyBA;AACA;AACA;AACA;;AAsGA,SACEA,UAAU,EACVC,YAAY;;AAmPd;AACA;AACA","ignoreList":[]}
1
+ {"version":3,"file":"types.js","names":["FileStatus","UploadStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Event,\n type FormVersionMetadata,\n type Item,\n type List,\n type Page,\n type UkAddressFieldComponent\n} from '@defra/forms-model'\nimport {\n type PluginProperties,\n type Request,\n type ResponseObject\n} from '@hapi/hapi'\nimport { type JoiExpression, type ValidationErrorItem } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type FileUploadField,\n type PaymentField\n} from '~/src/server/plugins/engine/components/index.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel,\n type DatePartsState,\n type EastingNorthingState,\n type LatLongState,\n type MonthYearState\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItemField } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { type QuestionPageController } from '~/src/server/plugins/engine/pageControllers/index.js'\nimport {\n type FileStatus,\n type FormAdapterSubmissionSchemaVersion,\n type UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport {\n type FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\nimport { type RequestOptions } from '~/src/server/services/httpService.js'\nimport { type Services } from '~/src/server/types.js'\n\nexport type AnyFormRequest = FormRequest | FormRequestPayload\nexport type AnyRequest = Request | AnyFormRequest\n\n/**\n * Form submission state stores the following in Redis:\n * Props containing user's submitted values as `{ [inputId]: value }` or as `{ [sectionName]: { [inputName]: value } }`\n * a) . e.g:\n * ```ts\n * {\n * _C9PRHmsgt: 'Ben',\n * WfLk9McjzX: 'Music',\n * IK7jkUFCBL: 'Royal Academy of Music'\n * }\n * ```\n *\n * b)\n * ```ts\n * {\n * checkBeforeYouStart: { ukPassport: true },\n * applicantDetails: {\n * numberOfApplicants: 1,\n * phoneNumber: '77777777',\n * emailAddress: 'aaa@aaa.com'\n * },\n * applicantOneDetails: {\n * firstName: 'a',\n * middleName: 'a',\n * lastName: 'a',\n * address: { addressLine1: 'a', addressLine2: 'a', town: 'a', postcode: 'a' }\n * }\n * }\n * ```\n */\n\n/**\n * Form submission state\n */\nexport type FormSubmissionState = {\n upload?: Record<string, TempFileState>\n} & FormState\n\nexport interface FormSubmissionError\n extends Pick<ValidationErrorItem, 'context' | 'path'> {\n href: string // e.g: '#dateField__day'\n name: string // e.g: 'dateField__day'\n text: string // e.g: 'Date field must be a real date'\n}\n\nexport interface FormConfirmationState {\n confirmed?: true\n formId?: string\n referenceNumber?: string\n}\n\nexport interface FormPayloadParams {\n action?: FormAction\n confirm?: true\n crumb?: string\n itemId?: string\n}\n\n/**\n * Form POST for question pages\n * (after Joi has converted value types)\n */\nexport type FormPayload = FormPayloadParams & Partial<Record<string, FormValue>>\n\nexport type FormValue =\n | Item['value']\n | Item['value'][]\n | UploadState\n | RepeatListState\n | undefined\n\nexport type FormState = Partial<Record<string, FormStateValue>>\nexport type FormStateValue = Exclude<FormValue, undefined> | null\n\nexport interface FormValidationResult<\n ValueType extends FormPayload | FormSubmissionState\n> {\n value: ValueType\n errors: FormSubmissionError[] | undefined\n}\n\nexport interface FormContext {\n /**\n * Evaluation form state only (filtered by visited paths),\n * with values formatted for condition evaluation using\n * {@link FormComponent.getContextValueFromState}\n */\n evaluationState: FormState\n\n /**\n * Relevant form state only (filtered by visited paths)\n */\n relevantState: FormState\n\n /**\n * Relevant pages only (filtered by visited paths)\n */\n relevantPages: PageControllerClass[]\n\n /**\n * Form submission payload (single page)\n */\n payload: FormPayload\n\n /**\n * Form submission state (entire form)\n */\n state: FormSubmissionState\n\n /**\n * Validation errors (entire form)\n */\n errors?: FormSubmissionError[]\n\n /**\n * Visited paths evaluated from form state\n */\n paths: string[]\n\n /**\n * Preview URL direct access is allowed\n */\n isForceAccess: boolean\n\n /**\n * Miscellaneous extra data from event responses\n */\n data: object\n\n pageDefMap: Map<string, Page>\n listDefMap: Map<string, List>\n componentDefMap: Map<string, ComponentDef>\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n referenceNumber: string\n submittedVersionNumber?: number\n}\n\nexport type FormContextRequest = (\n | {\n method: 'get'\n payload?: undefined\n }\n | {\n method: 'post'\n payload: FormPayload\n }\n | {\n method: FormRequest['method']\n payload?: object | undefined\n }\n) &\n Pick<\n FormRequest,\n 'app' | 'method' | 'params' | 'path' | 'query' | 'url' | 'server'\n >\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport {\n FileStatus,\n UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\n\nexport type UploadState = FileState[]\n\nexport type FileUpload = {\n fileId: string\n filename: string\n contentLength: number\n} & (\n | {\n fileStatus: FileStatus.complete | FileStatus.rejected | FileStatus.pending\n errorMessage?: string\n }\n | {\n fileStatus: FileStatus.complete\n errorMessage?: undefined\n }\n)\n\nexport interface FileUploadMetadata {\n retrievalKey: string\n}\n\nexport type UploadStatusResponse =\n | {\n uploadStatus: UploadStatus.initiated\n metadata: FileUploadMetadata\n form: { file?: undefined }\n }\n | {\n uploadStatus: UploadStatus.pending | UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles?: number\n }\n | {\n uploadStatus: UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles: 0\n }\n\nexport type UploadStatusFileResponse = Exclude<\n UploadStatusResponse,\n { uploadStatus: UploadStatus.initiated }\n>\n\nexport interface FileState {\n uploadId: string\n status: UploadStatusFileResponse\n}\n\nexport interface TempFileState {\n upload?: UploadInitiateResponse\n files: UploadState\n}\n\nexport interface RepeatItemState extends FormPayload {\n itemId: string\n}\n\nexport type RepeatListState = RepeatItemState[]\n\nexport interface CheckAnswers {\n title?: ComponentText\n summaryList: SummaryList\n}\n\nexport interface SummaryList {\n classes?: string\n rows: SummaryListRow[]\n}\n\nexport interface SummaryListRow {\n key: ComponentText\n value: ComponentText\n actions?: { items: SummaryListAction[] }\n}\n\nexport type SummaryListAction = ComponentText & {\n href: string\n visuallyHiddenText: string\n}\n\nexport interface PageViewModelBase extends Partial<ViewContext> {\n page: PageController\n name?: string\n pageTitle: string\n sectionTitle?: string\n showTitle: boolean\n isStartPage: boolean\n backLink?: BackLink\n feedbackLink?: string\n serviceUrl: string\n phaseTag?: string\n}\n\nexport interface ItemDeletePageViewModel extends PageViewModelBase {\n context: FormContext\n itemTitle: string\n confirmation?: ComponentText\n buttonConfirm: ComponentText\n buttonCancel: ComponentText\n}\n\nexport interface FormPageViewModel extends PageViewModelBase {\n components: ComponentViewModel[]\n context: FormContext\n errors?: FormSubmissionError[]\n hasMissingNotificationEmail?: boolean\n allowSaveAndExit: boolean\n showSubmitButton?: boolean\n showPaymentExpiredNotification?: boolean\n}\n\nexport interface RepeaterSummaryPageViewModel extends PageViewModelBase {\n context: FormContext\n errors?: FormSubmissionError[]\n checkAnswers: CheckAnswers[]\n repeatTitle: string\n allowSaveAndExit: boolean\n}\n\nexport interface FeaturedFormPageViewModel extends FormPageViewModel {\n formAction?: string\n formComponent: ComponentViewModel\n componentsBefore: ComponentViewModel[]\n uploadId: string | undefined\n proxyUrl: string | null\n}\n\nexport type PageViewModel =\n | PageViewModelBase\n | ItemDeletePageViewModel\n | FormPageViewModel\n | RepeaterSummaryPageViewModel\n | FeaturedFormPageViewModel\n\nexport type GlobalFunction = (value: unknown) => unknown\nexport type FilterFunction = (value: unknown) => unknown\nexport interface ErrorMessageTemplate {\n type: string\n template: JoiExpression\n}\n\nexport interface ErrorMessageTemplateList {\n baseErrors: ErrorMessageTemplate[]\n advancedSettingsErrors: ErrorMessageTemplate[]\n}\n\nexport type PreparePageEventRequestOptions = (\n options: RequestOptions,\n event: Event,\n page: PageControllerClass,\n context: FormContext\n) => void\n\nexport type OnRequestCallback = (\n request: AnyFormRequest,\n h: FormResponseToolkit,\n context: FormContext\n) =>\n | ResponseObject\n | FormResponseToolkit['continue']\n | Promise<ResponseObject | FormResponseToolkit['continue']>\n\nexport type SaveAndExitHandler = (\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n) => ResponseObject\n\nexport interface ExternalArgs {\n component: ComponentDef\n controller: QuestionPageController\n sourceUrl: string\n actionArgs: Record<string, string>\n isLive: boolean\n isPreview: boolean\n}\n\nexport interface PostcodeLookupExternalArgs extends ExternalArgs {\n component: UkAddressFieldComponent\n actionArgs: { step: string }\n}\n\nexport interface ExternalStateAppendage {\n component: string\n data: FormStateValue | FormState\n}\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n cache?: CacheService | string\n globals?: Record<string, GlobalFunction>\n filters?: Record<string, FilterFunction>\n saveAndExit?: SaveAndExitHandler\n pluginPath?: string\n nunjucks: {\n baseLayoutPath: string\n paths: string[]\n }\n viewContext: PluginProperties['forms-engine-plugin']['viewContext']\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n baseUrl: string // base URL of the application, protocol and hostname e.g. \"https://myapp.com\"\n ordnanceSurveyApiKey?: string\n ordnanceSurveyApiSecret?: string\n}\n\nexport interface FormAdapterSubmissionMessageMeta {\n schemaVersion: FormAdapterSubmissionSchemaVersion\n timestamp: Date\n referenceNumber: string\n formName: string\n formId: string\n formSlug: string\n status: FormStatus\n isPreview: boolean\n notificationEmail: string\n versionMetadata?: FormVersionMetadata\n custom?: Record<string, unknown>\n}\n\nexport type FormAdapterSubmissionMessageMetaSerialised = Omit<\n FormAdapterSubmissionMessageMeta,\n 'schemaVersion' | 'timestamp' | 'status'\n> & {\n schemaVersion: number\n status: string\n timestamp: string\n}\nexport interface FormAdapterFile {\n fileName: string\n fileId: string\n userDownloadLink: string\n}\n\nexport interface FormAdapterPayment {\n paymentId: string\n reference: string\n amount: number\n description: string\n createdAt: string\n}\n\nexport interface FormAdapterSubmissionMessageResult {\n files: {\n main: string\n repeaters: Record<string, string>\n }\n}\n\n/**\n * A detail item specifically for files\n */\nexport type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {\n field: FileUploadField\n}\n\n/**\n * A detail item specifically for payments\n */\nexport type PaymentFieldDetailItem = Omit<DetailItemField, 'field'> & {\n field: PaymentField\n}\nexport type RichFormValue =\n | FormValue\n | FormPayload\n | DatePartsState\n | MonthYearState\n | UkAddressState\n | EastingNorthingState\n | LatLongState\n\nexport interface FormAdapterSubmissionMessageData {\n main: Record<string, RichFormValue | null>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<string, FormAdapterFile[]>\n payment?: FormAdapterPayment\n}\n\nexport interface FormAdapterSubmissionMessagePayload {\n meta: FormAdapterSubmissionMessageMeta\n data: FormAdapterSubmissionMessageData\n result: FormAdapterSubmissionMessageResult\n}\n\nexport interface FormAdapterSubmissionMessage\n extends FormAdapterSubmissionMessagePayload {\n messageId: string\n recordCreatedAt: Date\n}\n\nexport interface FormAdapterSubmissionService {\n handleFormSubmission: (\n submissionMessage: FormAdapterSubmissionMessage\n ) => unknown\n}\n"],"mappings":"AAyDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAyBA;AACA;AACA;AACA;;AAsGA,SACEA,UAAU,EACVC,YAAY;;AAgQd;AACA;AACA;;AAKA;AACA;AACA","ignoreList":[]}
@@ -3,7 +3,7 @@ import { type FormRequestPayload, type FormResponseToolkit } from '~/src/server/
3
3
  import { type ExternalArgs } from '~/src/server/plugins/engine/types.js';
4
4
  export declare function isExternalComponent(component: unknown): component is ExternalComponent;
5
5
  export interface ExternalComponent {
6
- dispatcher(request: FormRequestPayload, h: FormResponseToolkit, args: ExternalArgs): ResponseObject;
6
+ dispatcher(request: FormRequestPayload, h: FormResponseToolkit, args: ExternalArgs): Promise<ResponseObject>;
7
7
  }
8
8
  /**
9
9
  * Returns internal and external components from a componentMap, regardless of error state.
@@ -1 +1 @@
1
- {"version":3,"file":"validationHelpers.js","names":["Components","isExternalComponent","component","dispatcher","getComponentsByType","internalComponents","Map","externalComponents","componentMap","Object","entries","name","set"],"sources":["../../../../src/server/plugins/engine/validationHelpers.ts"],"sourcesContent":["import { type ResponseObject } from '@hapi/hapi'\n\nimport * as Components from '~/src/server/plugins/engine/components/index.js'\nimport {\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/plugins/engine/types/index.js'\nimport { type ExternalArgs } from '~/src/server/plugins/engine/types.js'\n\n// Type guard for ExternalComponent\nexport function isExternalComponent(\n component: unknown\n): component is ExternalComponent {\n return typeof (component as ExternalComponent).dispatcher === 'function'\n}\n\n// External components are guaranteed to have a dispatcher method\nexport interface ExternalComponent {\n dispatcher(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n args: ExternalArgs\n ): ResponseObject\n}\n\n/**\n * Returns internal and external components from a componentMap, regardless of error state.\n * @returns An object containing internalComponents and externalComponents arrays\n */\nexport function getComponentsByType(): {\n internalComponents: Map<string, unknown>\n externalComponents: Map<string, ExternalComponent>\n} {\n const internalComponents = new Map<string, unknown>()\n const externalComponents = new Map<string, ExternalComponent>()\n\n const componentMap = new Map<string, unknown>(Object.entries(Components))\n\n for (const [name, component] of componentMap.entries()) {\n if (isExternalComponent(component)) {\n externalComponents.set(name, component)\n } else {\n internalComponents.set(name, component)\n }\n }\n\n return { internalComponents, externalComponents }\n}\n"],"mappings":"AAEA,OAAO,KAAKA,UAAU;AAOtB;AACA,OAAO,SAASC,mBAAmBA,CACjCC,SAAkB,EACc;EAChC,OAAO,OAAQA,SAAS,CAAuBC,UAAU,KAAK,UAAU;AAC1E;;AAEA;;AASA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CAAA,EAGjC;EACA,MAAMC,kBAAkB,GAAG,IAAIC,GAAG,CAAkB,CAAC;EACrD,MAAMC,kBAAkB,GAAG,IAAID,GAAG,CAA4B,CAAC;EAE/D,MAAME,YAAY,GAAG,IAAIF,GAAG,CAAkBG,MAAM,CAACC,OAAO,CAACV,UAAU,CAAC,CAAC;EAEzE,KAAK,MAAM,CAACW,IAAI,EAAET,SAAS,CAAC,IAAIM,YAAY,CAACE,OAAO,CAAC,CAAC,EAAE;IACtD,IAAIT,mBAAmB,CAACC,SAAS,CAAC,EAAE;MAClCK,kBAAkB,CAACK,GAAG,CAACD,IAAI,EAAET,SAAS,CAAC;IACzC,CAAC,MAAM;MACLG,kBAAkB,CAACO,GAAG,CAACD,IAAI,EAAET,SAAS,CAAC;IACzC;EACF;EAEA,OAAO;IAAEG,kBAAkB;IAAEE;EAAmB,CAAC;AACnD","ignoreList":[]}
1
+ {"version":3,"file":"validationHelpers.js","names":["Components","isExternalComponent","component","dispatcher","getComponentsByType","internalComponents","Map","externalComponents","componentMap","Object","entries","name","set"],"sources":["../../../../src/server/plugins/engine/validationHelpers.ts"],"sourcesContent":["import { type ResponseObject } from '@hapi/hapi'\n\nimport * as Components from '~/src/server/plugins/engine/components/index.js'\nimport {\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/plugins/engine/types/index.js'\nimport { type ExternalArgs } from '~/src/server/plugins/engine/types.js'\n\n// Type guard for ExternalComponent\nexport function isExternalComponent(\n component: unknown\n): component is ExternalComponent {\n return typeof (component as ExternalComponent).dispatcher === 'function'\n}\n\n// External components are guaranteed to have a dispatcher method\nexport interface ExternalComponent {\n dispatcher(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n args: ExternalArgs\n ): Promise<ResponseObject>\n}\n\n/**\n * Returns internal and external components from a componentMap, regardless of error state.\n * @returns An object containing internalComponents and externalComponents arrays\n */\nexport function getComponentsByType(): {\n internalComponents: Map<string, unknown>\n externalComponents: Map<string, ExternalComponent>\n} {\n const internalComponents = new Map<string, unknown>()\n const externalComponents = new Map<string, ExternalComponent>()\n\n const componentMap = new Map<string, unknown>(Object.entries(Components))\n\n for (const [name, component] of componentMap.entries()) {\n if (isExternalComponent(component)) {\n externalComponents.set(name, component)\n } else {\n internalComponents.set(name, component)\n }\n }\n\n return { internalComponents, externalComponents }\n}\n"],"mappings":"AAEA,OAAO,KAAKA,UAAU;AAOtB;AACA,OAAO,SAASC,mBAAmBA,CACjCC,SAAkB,EACc;EAChC,OAAO,OAAQA,SAAS,CAAuBC,UAAU,KAAK,UAAU;AAC1E;;AAEA;;AASA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CAAA,EAGjC;EACA,MAAMC,kBAAkB,GAAG,IAAIC,GAAG,CAAkB,CAAC;EACrD,MAAMC,kBAAkB,GAAG,IAAID,GAAG,CAA4B,CAAC;EAE/D,MAAME,YAAY,GAAG,IAAIF,GAAG,CAAkBG,MAAM,CAACC,OAAO,CAACV,UAAU,CAAC,CAAC;EAEzE,KAAK,MAAM,CAACW,IAAI,EAAET,SAAS,CAAC,IAAIM,YAAY,CAACE,OAAO,CAAC,CAAC,EAAE;IACtD,IAAIT,mBAAmB,CAACC,SAAS,CAAC,EAAE;MAClCK,kBAAkB,CAACK,GAAG,CAACD,IAAI,EAAET,SAAS,CAAC;IACzC,CAAC,MAAM;MACLG,kBAAkB,CAACO,GAAG,CAACD,IAAI,EAAET,SAAS,CAAC;IACzC;EACF;EAEA,OAAO;IAAEG,kBAAkB;IAAEE;EAAmB,CAAC;AACnD","ignoreList":[]}
@@ -0,0 +1,42 @@
1
+ {% from "govuk/components/warning-text/macro.njk" import govukWarningText %}
2
+ {% from "govuk/components/button/macro.njk" import govukButton %}
3
+
4
+ {% macro PaymentField(component) %}
5
+ {% set model = component.model %}
6
+ {% set amount = model.amount %}
7
+ {% set description = model.description %}
8
+ {% set paymentState = model.paymentState %}
9
+ {% set isPreAuthorised = paymentState and paymentState.preAuth and paymentState.preAuth.status == 'success' %}
10
+
11
+ <div class="app-payment-field">
12
+ {% if isPreAuthorised %}
13
+ {# Payment already pre-authorised - show confirmation message #}
14
+ <h2 class="govuk-heading-m">You have already authorised a payment for this form</h2>
15
+
16
+ <p class="govuk-body">Continue to submit the form. You will not be charged twice.</p>
17
+ {% else %}
18
+ {# No pre-authorisation - show payment form #}
19
+ <h2 class="govuk-heading-m">{{ model.label.text if model.label and model.label.text else "Payment details required" }}</h2>
20
+
21
+ <p class="govuk-body">{{ description }}</p>
22
+
23
+ {{ govukWarningText({
24
+ text: "You may see a pending transaction in your bank account but you will only be charged when you submit the form.",
25
+ iconFallbackText: "Warning"
26
+ }) }}
27
+
28
+ <p class="govuk-body">You can submit the form after you have added your payment details.</p>
29
+
30
+ <p class="govuk-body govuk-!-margin-bottom-1">Total amount:</p>
31
+ <p class="govuk-heading-l govuk-!-margin-bottom-4 govuk-!-padding-top-0">£{{ amount }}</p>
32
+
33
+ {{ govukButton({
34
+ text: "Add payment details",
35
+ attributes: {
36
+ name: "action",
37
+ value: "external-" + model.name
38
+ }
39
+ }) }}
40
+ {% endif %}
41
+ </div>
42
+ {% endmacro %}
@@ -1,6 +1,7 @@
1
1
  {% extends baseLayoutPath %}
2
2
 
3
3
  {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
4
+ {% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %}
4
5
  {% from "partials/components.html" import componentList with context %}
5
6
 
6
7
  {% block content %}
@@ -10,7 +11,14 @@
10
11
  {% include "partials/preview-banner.html" %}
11
12
  {% endif %}
12
13
 
13
- {% if errors | length %}
14
+ {% if showPaymentExpiredNotification %}
15
+ {{ govukNotificationBanner({
16
+ titleText: "Important",
17
+ html: '<h3 class="govuk-notification-banner__heading">Your payment has been cancelled</h3><p class="govuk-body">Your payment details were deleted because the form was inactive for 5 days.</p><p class="govuk-body">Add your payment details again.</p>'
18
+ }) }}
19
+ {% endif %}
20
+
21
+ {% if errors | length and not showPaymentExpiredNotification %}
14
22
  {{ govukErrorSummary({
15
23
  titleText: "There is a problem",
16
24
  errorList: checkErrorTemplates(errors)
@@ -1,6 +1,19 @@
1
1
  {% from "govuk/components/button/macro.njk" import govukButton %}
2
2
  {% from "govuk/components/summary-list/macro.njk" import govukSummaryList -%}
3
3
 
4
+ {% set noPaymentFields = true %}
5
+ {% set hasIncompletePayment = false %}
6
+
7
+ {% for comp in components %}
8
+ {% if comp.type == 'PaymentField' %}
9
+ {% set noPaymentFields = false %}
10
+ {# Check if payment is incomplete (no preAuth status) #}
11
+ {% if not comp.model.paymentState or not comp.model.paymentState.preAuth or comp.model.paymentState.preAuth.status != 'success' %}
12
+ {% set hasIncompletePayment = true %}
13
+ {% endif %}
14
+ {% endif %}
15
+ {% endfor %}
16
+
4
17
  <form method="post" novalidate>
5
18
  <input type="hidden" name="crumb" value="{{ crumb }}">
6
19
 
@@ -15,11 +28,13 @@
15
28
  {% endif %}
16
29
 
17
30
  <div class="govuk-button-group">
18
- {{ govukButton({
19
- text: buttonText,
20
- isStartButton: isStartPage,
21
- preventDoubleClick: true
22
- }) }}
31
+ {% if showSubmitButton !== false and not hasIncompletePayment %}
32
+ {{ govukButton({
33
+ text: buttonText,
34
+ isStartButton: isStartPage,
35
+ preventDoubleClick: true
36
+ }) }}
37
+ {% endif %}
23
38
 
24
39
  {% if allowSaveAndExit %}
25
40
  {{ govukButton({
@@ -3,6 +3,7 @@
3
3
  {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
4
4
  {% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}
5
5
  {% from "govuk/components/button/macro.njk" import govukButton %}
6
+ {% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %}
6
7
  {% from "partials/components.html" import componentList with context %}
7
8
  {% from "govuk/components/input/macro.njk" import govukInput %}
8
9
 
@@ -13,6 +14,14 @@
13
14
  {% include "partials/preview-banner.html" %}
14
15
  {% endif %}
15
16
 
17
+ {% if paymentState and paymentState.preAuth and paymentState.preAuth.status == 'success' %}
18
+ {{ govukNotificationBanner({
19
+ type: "success",
20
+ titleText: "Success",
21
+ html: "<h3 class=\"govuk-notification-banner__heading\">We have your payment details</h3><p class=\"govuk-body\">Your payment is on hold. We will charge you when you submit the form.</p>"
22
+ }) }}
23
+ {% endif %}
24
+
16
25
  {% if errors %}
17
26
  {{ govukErrorSummary({
18
27
  titleText: "There is a problem",
@@ -41,6 +50,13 @@
41
50
  {% endif %}
42
51
  {% endfor %}
43
52
 
53
+ {% if paymentDetails %}
54
+ <h2 class="govuk-heading-m">
55
+ {{ paymentDetails.title.text }}
56
+ </h2>
57
+ {{ govukSummaryList(paymentDetails.summaryList) }}
58
+ {% endif %}
59
+
44
60
  <form method="post" novalidate>
45
61
  <input type="hidden" name="crumb" value="{{ crumb }}">
46
62
 
@@ -59,7 +75,7 @@
59
75
  {% set isDeclaration = declaration or components | length %}
60
76
 
61
77
  {{ govukButton({
62
- text: "Accept and send" if isDeclaration else "Send",
78
+ text: "Accept and submit" if isDeclaration else "Submit",
63
79
  name: "action",
64
80
  value: "send",
65
81
  preventDoubleClick: true
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Get Ordnance Survey OAuth token
3
+ * @param {MapConfiguration} options - Ordnance survey map options
4
+ */
5
+ export function getAccessToken(options: MapConfiguration): Promise<string>;
6
+ import type { MapConfiguration } from '~/src/server/plugins/map/types.js';
@@ -0,0 +1,41 @@
1
+ import { post } from "../../../services/httpService.js";
2
+
3
+ /**
4
+ * @type {string}
5
+ */
6
+ let cachedToken;
7
+ let tokenExpiry = 0;
8
+
9
+ /**
10
+ * Get Ordnance Survey OAuth token
11
+ * @param {MapConfiguration} options - Ordnance survey map options
12
+ */
13
+ export async function getAccessToken(options) {
14
+ const {
15
+ ordnanceSurveyApiKey: key,
16
+ ordnanceSurveyApiSecret: secret
17
+ } = options;
18
+ const now = Date.now();
19
+ if (cachedToken && now < tokenExpiry) {
20
+ return cachedToken;
21
+ }
22
+ const creds = `${key}:${secret}`;
23
+ const result = await post('https://api.os.uk/oauth2/token/v1', {
24
+ headers: {
25
+ Authorization: `Basic ${btoa(creds)}`,
26
+ 'Content-Type': 'application/x-www-form-urlencoded'
27
+ },
28
+ payload: 'grant_type=client_credentials',
29
+ json: true
30
+ });
31
+ const data = result.payload;
32
+ cachedToken = data.access_token;
33
+ tokenExpiry = now + (data.expires_in - 60) * 1000; // refresh early
34
+
35
+ return cachedToken;
36
+ }
37
+
38
+ /**
39
+ * @import { MapConfiguration } from '~/src/server/plugins/map/types.js'
40
+ */
41
+ //# sourceMappingURL=get-os-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-os-token.js","names":["post","cachedToken","tokenExpiry","getAccessToken","options","ordnanceSurveyApiKey","key","ordnanceSurveyApiSecret","secret","now","Date","creds","result","headers","Authorization","btoa","payload","json","data","access_token","expires_in"],"sources":["../../../../../src/server/plugins/map/routes/get-os-token.js"],"sourcesContent":["import { post } from '~/src/server/services/httpService.js'\n\n/**\n * @type {string}\n */\nlet cachedToken\nlet tokenExpiry = 0\n\n/**\n * Get Ordnance Survey OAuth token\n * @param {MapConfiguration} options - Ordnance survey map options\n */\nexport async function getAccessToken(options) {\n const { ordnanceSurveyApiKey: key, ordnanceSurveyApiSecret: secret } = options\n const now = Date.now()\n\n if (cachedToken && now < tokenExpiry) {\n return cachedToken\n }\n\n const creds = `${key}:${secret}`\n const result = await post('https://api.os.uk/oauth2/token/v1', {\n headers: {\n Authorization: `Basic ${btoa(creds)}`,\n 'Content-Type': 'application/x-www-form-urlencoded'\n },\n payload: 'grant_type=client_credentials',\n json: true\n })\n\n const data = result.payload\n\n cachedToken = data.access_token\n tokenExpiry = now + (data.expires_in - 60) * 1000 // refresh early\n\n return cachedToken\n}\n\n/**\n * @import { MapConfiguration } from '~/src/server/plugins/map/types.js'\n */\n"],"mappings":"AAAA,SAASA,IAAI;;AAEb;AACA;AACA;AACA,IAAIC,WAAW;AACf,IAAIC,WAAW,GAAG,CAAC;;AAEnB;AACA;AACA;AACA;AACA,OAAO,eAAeC,cAAcA,CAACC,OAAO,EAAE;EAC5C,MAAM;IAAEC,oBAAoB,EAAEC,GAAG;IAAEC,uBAAuB,EAAEC;EAAO,CAAC,GAAGJ,OAAO;EAC9E,MAAMK,GAAG,GAAGC,IAAI,CAACD,GAAG,CAAC,CAAC;EAEtB,IAAIR,WAAW,IAAIQ,GAAG,GAAGP,WAAW,EAAE;IACpC,OAAOD,WAAW;EACpB;EAEA,MAAMU,KAAK,GAAG,GAAGL,GAAG,IAAIE,MAAM,EAAE;EAChC,MAAMI,MAAM,GAAG,MAAMZ,IAAI,CAAC,mCAAmC,EAAE;IAC7Da,OAAO,EAAE;MACPC,aAAa,EAAE,SAASC,IAAI,CAACJ,KAAK,CAAC,EAAE;MACrC,cAAc,EAAE;IAClB,CAAC;IACDK,OAAO,EAAE,+BAA+B;IACxCC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMC,IAAI,GAAGN,MAAM,CAACI,OAAO;EAE3Bf,WAAW,GAAGiB,IAAI,CAACC,YAAY;EAC/BjB,WAAW,GAAGO,GAAG,GAAG,CAACS,IAAI,CAACE,UAAU,GAAG,EAAE,IAAI,IAAI,EAAC;;EAElD,OAAOnB,WAAW;AACpB;;AAEA;AACA;AACA","ignoreList":[]}
@@ -0,0 +1,49 @@
1
+ import { getAccessToken } from "./get-os-token.js";
2
+ import { post } from "../../../services/httpService.js";
3
+ jest.mock("../../../services/httpService.ts");
4
+ describe('OS OAuth token', () => {
5
+ describe('getAccessToken', () => {
6
+ it('should get access token', async () => {
7
+ jest.mocked(post).mockResolvedValueOnce({
8
+ res: (/** @type {IncomingMessage} */{
9
+ statusCode: 200,
10
+ headers: {}
11
+ }),
12
+ payload: {
13
+ access_token: 'access_token',
14
+ expires_in: '299',
15
+ issued_at: '1770036762387',
16
+ token_type: 'Bearer'
17
+ },
18
+ error: undefined
19
+ });
20
+ const token = await getAccessToken({
21
+ ordnanceSurveyApiKey: 'apikey',
22
+ ordnanceSurveyApiSecret: 'apisecret'
23
+ });
24
+ expect(token).toBe('access_token');
25
+ expect(post).toHaveBeenCalledWith('https://api.os.uk/oauth2/token/v1', {
26
+ headers: {
27
+ Authorization: `Basic ${btoa('apikey:apisecret')}`,
28
+ 'Content-Type': 'application/x-www-form-urlencoded'
29
+ },
30
+ payload: 'grant_type=client_credentials',
31
+ json: true
32
+ });
33
+ expect(post).toHaveBeenCalledTimes(1);
34
+ });
35
+ it('should return an cached token', async () => {
36
+ const token = await getAccessToken({
37
+ ordnanceSurveyApiKey: 'apikey',
38
+ ordnanceSurveyApiSecret: 'apisecret'
39
+ });
40
+ expect(token).toBe('access_token');
41
+ expect(post).toHaveBeenCalledTimes(0);
42
+ });
43
+ });
44
+ });
45
+
46
+ /**
47
+ * @import { IncomingMessage } from 'node:http'
48
+ */
49
+ //# sourceMappingURL=get-os-token.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-os-token.test.js","names":["getAccessToken","post","jest","mock","describe","it","mocked","mockResolvedValueOnce","res","statusCode","headers","payload","access_token","expires_in","issued_at","token_type","error","undefined","token","ordnanceSurveyApiKey","ordnanceSurveyApiSecret","expect","toBe","toHaveBeenCalledWith","Authorization","btoa","json","toHaveBeenCalledTimes"],"sources":["../../../../../src/server/plugins/map/routes/get-os-token.test.js"],"sourcesContent":["import { getAccessToken } from '~/src/server/plugins/map/routes/get-os-token.js'\nimport { post } from '~/src/server/services/httpService.js'\n\njest.mock('~/src/server/services/httpService.ts')\n\ndescribe('OS OAuth token', () => {\n describe('getAccessToken', () => {\n it('should get access token', async () => {\n jest.mocked(post).mockResolvedValueOnce({\n res: /** @type {IncomingMessage} */ ({\n statusCode: 200,\n headers: {}\n }),\n payload: {\n access_token: 'access_token',\n expires_in: '299',\n issued_at: '1770036762387',\n token_type: 'Bearer'\n },\n error: undefined\n })\n\n const token = await getAccessToken({\n ordnanceSurveyApiKey: 'apikey',\n ordnanceSurveyApiSecret: 'apisecret'\n })\n\n expect(token).toBe('access_token')\n\n expect(post).toHaveBeenCalledWith('https://api.os.uk/oauth2/token/v1', {\n headers: {\n Authorization: `Basic ${btoa('apikey:apisecret')}`,\n 'Content-Type': 'application/x-www-form-urlencoded'\n },\n payload: 'grant_type=client_credentials',\n json: true\n })\n expect(post).toHaveBeenCalledTimes(1)\n })\n\n it('should return an cached token', async () => {\n const token = await getAccessToken({\n ordnanceSurveyApiKey: 'apikey',\n ordnanceSurveyApiSecret: 'apisecret'\n })\n\n expect(token).toBe('access_token')\n expect(post).toHaveBeenCalledTimes(0)\n })\n })\n})\n\n/**\n * @import { IncomingMessage } from 'node:http'\n */\n"],"mappings":"AAAA,SAASA,cAAc;AACvB,SAASC,IAAI;AAEbC,IAAI,CAACC,IAAI,mCAAuC,CAAC;AAEjDC,QAAQ,CAAC,gBAAgB,EAAE,MAAM;EAC/BA,QAAQ,CAAC,gBAAgB,EAAE,MAAM;IAC/BC,EAAE,CAAC,yBAAyB,EAAE,YAAY;MACxCH,IAAI,CAACI,MAAM,CAACL,IAAI,CAAC,CAACM,qBAAqB,CAAC;QACtCC,GAAG,GAAE,8BAAgC;UACnCC,UAAU,EAAE,GAAG;UACfC,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACFC,OAAO,EAAE;UACPC,YAAY,EAAE,cAAc;UAC5BC,UAAU,EAAE,KAAK;UACjBC,SAAS,EAAE,eAAe;UAC1BC,UAAU,EAAE;QACd,CAAC;QACDC,KAAK,EAAEC;MACT,CAAC,CAAC;MAEF,MAAMC,KAAK,GAAG,MAAMlB,cAAc,CAAC;QACjCmB,oBAAoB,EAAE,QAAQ;QAC9BC,uBAAuB,EAAE;MAC3B,CAAC,CAAC;MAEFC,MAAM,CAACH,KAAK,CAAC,CAACI,IAAI,CAAC,cAAc,CAAC;MAElCD,MAAM,CAACpB,IAAI,CAAC,CAACsB,oBAAoB,CAAC,mCAAmC,EAAE;QACrEb,OAAO,EAAE;UACPc,aAAa,EAAE,SAASC,IAAI,CAAC,kBAAkB,CAAC,EAAE;UAClD,cAAc,EAAE;QAClB,CAAC;QACDd,OAAO,EAAE,+BAA+B;QACxCe,IAAI,EAAE;MACR,CAAC,CAAC;MACFL,MAAM,CAACpB,IAAI,CAAC,CAAC0B,qBAAqB,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC;IAEFtB,EAAE,CAAC,+BAA+B,EAAE,YAAY;MAC9C,MAAMa,KAAK,GAAG,MAAMlB,cAAc,CAAC;QACjCmB,oBAAoB,EAAE,QAAQ;QAC9BC,uBAAuB,EAAE;MAC3B,CAAC,CAAC;MAEFC,MAAM,CAACH,KAAK,CAAC,CAACI,IAAI,CAAC,cAAc,CAAC;MAClCD,MAAM,CAACpB,IAAI,CAAC,CAAC0B,qBAAqB,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ,CAAC,CAAC;;AAEF;AACA;AACA","ignoreList":[]}
@@ -2,17 +2,7 @@
2
2
  * Gets the map support routes
3
3
  * @param {MapConfiguration} options - ordnance survey names api key
4
4
  */
5
- export function getRoutes(options: MapConfiguration): (ServerRoute<MapProxyGetRequestRefs> | ServerRoute<MapGeocodeGetRequestRefs> | ServerRoute<MapReverseGeocodeGetRequestRefs> | {
6
- method: string;
7
- path: string;
8
- options: {
9
- handler: {
10
- directory: {
11
- path: string;
12
- };
13
- };
14
- };
15
- })[];
5
+ export function getRoutes(options: MapConfiguration): (ServerRoute<MapProxyGetRequestRefs> | ServerRoute<MapGeocodeGetRequestRefs> | ServerRoute<MapReverseGeocodeGetRequestRefs>)[];
16
6
  import type { MapConfiguration } from '~/src/server/plugins/map/types.js';
17
7
  import type { MapProxyGetRequestRefs } from '~/src/server/plugins/map/types.js';
18
8
  import type { ServerRoute } from '@hapi/hapi';
@@ -1,20 +1,22 @@
1
1
  import { resolve } from 'node:path';
2
+ import { StatusCodes } from 'http-status-codes';
2
3
  import Joi from 'joi';
4
+ import { getAccessToken } from "./get-os-token.js";
3
5
  import { find, nearest } from "../service.js";
4
- import { request as httpRequest } from "../../../services/httpService.js";
6
+ import { get, request as httpRequest } from "../../../services/httpService.js";
5
7
 
6
8
  /**
7
9
  * Gets the map support routes
8
10
  * @param {MapConfiguration} options - ordnance survey names api key
9
11
  */
10
12
  export function getRoutes(options) {
11
- return [mapProxyRoute(options), geocodeProxyRoute(options), reverseGeocodeProxyRoute(options), ...tileRoutes()];
13
+ return [mapStyleResourceRoutes(), mapProxyRoute(options), tileProxyRoute(options), geocodeProxyRoute(options), reverseGeocodeProxyRoute(options)];
12
14
  }
13
15
 
14
16
  /**
15
17
  * Proxies ordnance survey requests from the front end to api.os.com
16
- * Used for VTS map tiles, sprites and fonts by forwarding on the request
17
- * and adding the apikey and optionally an SRS (spatial reference system)
18
+ * Used for the VTS map source by forwarding on the request
19
+ * and adding the auth token and SRS (spatial reference system)
18
20
  * @param {MapConfiguration} options - the map options
19
21
  * @returns {ServerRoute<MapProxyGetRequestRefs>}
20
22
  */
@@ -27,13 +29,13 @@ function mapProxyRoute(options) {
27
29
  query
28
30
  } = request;
29
31
  const targetUrl = new URL(decodeURIComponent(query.url));
30
-
31
- // Add API key server-side and set SRS
32
- targetUrl.searchParams.set('key', options.ordnanceSurveyApiKey);
33
- if (!targetUrl.searchParams.has('srs')) {
34
- targetUrl.searchParams.set('srs', '3857');
35
- }
36
- const proxyResponse = await httpRequest('get', targetUrl.toString());
32
+ const token = await getAccessToken(options);
33
+ targetUrl.searchParams.set('srs', '3857');
34
+ const proxyResponse = await httpRequest('get', targetUrl.toString(), {
35
+ headers: {
36
+ Authorization: `Bearer ${token}`
37
+ }
38
+ });
37
39
  const buffer = proxyResponse.payload;
38
40
  const contentType = proxyResponse.res.headers['content-type'];
39
41
  const response = h.response(buffer);
@@ -53,7 +55,44 @@ function mapProxyRoute(options) {
53
55
  }
54
56
 
55
57
  /**
56
- * Proxies ordnance survey geocode requests from the front end to api.os.com
58
+ * Proxies ordnance survey requests from the front end to api.os.uk
59
+ * Used for VTS map tiles forwarding on the request and adding the auth token
60
+ * @param {MapConfiguration} options - the map options
61
+ * @returns {ServerRoute<MapProxyGetRequestRefs>}
62
+ */
63
+ function tileProxyRoute(options) {
64
+ return {
65
+ method: 'GET',
66
+ path: '/api/tile/{z}/{y}/{x}.pbf',
67
+ handler: async (request, h) => {
68
+ const {
69
+ z,
70
+ y,
71
+ x
72
+ } = request.params;
73
+ const token = await getAccessToken(options);
74
+ const url = `https://api.os.uk/maps/vector/v1/vts/tile/${z}/${y}/${x}.pbf?srs=3857`;
75
+ const {
76
+ payload,
77
+ res
78
+ } = await get(url, {
79
+ headers: {
80
+ Authorization: `Bearer ${token}`,
81
+ Accept: 'application/x-protobuf'
82
+ },
83
+ json: false,
84
+ gunzip: true
85
+ });
86
+ if (res.statusCode && res.statusCode !== StatusCodes.OK.valueOf()) {
87
+ return h.response('Tile fetch failed').code(res.statusCode);
88
+ }
89
+ return h.response(payload).type('application/x-protobuf').header('Cache-Control', 'public, max-age=86400');
90
+ }
91
+ };
92
+ }
93
+
94
+ /**
95
+ * Proxies ordnance survey geocode requests from the front end to api.os.uk
57
96
  * Used for the gazzeteer address lookup to find name from query strings like postcode and place names
58
97
  * @param {MapConfiguration} options - the map options
59
98
  * @returns {ServerRoute<MapGeocodeGetRequestRefs>}
@@ -80,7 +119,7 @@ function geocodeProxyRoute(options) {
80
119
  }
81
120
 
82
121
  /**
83
- * Proxies ordnance survey reverse geocode requests from the front end to api.os.com
122
+ * Proxies ordnance survey reverse geocode requests from the front end to api.os.uk
84
123
  * Used to find name from easting and northing points.
85
124
  * N.B this endpoint is currently not used by the front end but will be soon in "maps V2"
86
125
  * @param {MapConfiguration} options - the map options
@@ -107,8 +146,13 @@ function reverseGeocodeProxyRoute(options) {
107
146
  }
108
147
  };
109
148
  }
110
- function tileRoutes() {
111
- return [{
149
+
150
+ /**
151
+ * Resource routes to return sprites and glyphs
152
+ * @returns {ServerRoute<MapProxyGetRequestRefs>}
153
+ */
154
+ function mapStyleResourceRoutes() {
155
+ return {
112
156
  method: 'GET',
113
157
  path: '/api/maps/vts/{path*}',
114
158
  options: {
@@ -118,7 +162,7 @@ function tileRoutes() {
118
162
  }
119
163
  }
120
164
  }
121
- }];
165
+ };
122
166
  }
123
167
 
124
168
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["resolve","Joi","find","nearest","request","httpRequest","getRoutes","options","mapProxyRoute","geocodeProxyRoute","reverseGeocodeProxyRoute","tileRoutes","method","path","handler","h","query","targetUrl","URL","decodeURIComponent","url","searchParams","set","ordnanceSurveyApiKey","has","proxyResponse","toString","buffer","payload","contentType","res","headers","response","type","validate","object","keys","string","required","optional","_h","data","easting","northing","number","directory","import","meta","dirname"],"sources":["../../../../../src/server/plugins/map/routes/index.js"],"sourcesContent":["import { resolve } from 'node:path'\n\nimport Joi from 'joi'\n\nimport { find, nearest } from '~/src/server/plugins/map/service.js'\nimport { request as httpRequest } from '~/src/server/services/httpService.js'\n\n/**\n * Gets the map support routes\n * @param {MapConfiguration} options - ordnance survey names api key\n */\nexport function getRoutes(options) {\n return [\n mapProxyRoute(options),\n geocodeProxyRoute(options),\n reverseGeocodeProxyRoute(options),\n ...tileRoutes()\n ]\n}\n\n/**\n * Proxies ordnance survey requests from the front end to api.os.com\n * Used for VTS map tiles, sprites and fonts by forwarding on the request\n * and adding the apikey and optionally an SRS (spatial reference system)\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapProxyGetRequestRefs>}\n */\nfunction mapProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/map-proxy',\n handler: async (request, h) => {\n const { query } = request\n const targetUrl = new URL(decodeURIComponent(query.url))\n\n // Add API key server-side and set SRS\n targetUrl.searchParams.set('key', options.ordnanceSurveyApiKey)\n if (!targetUrl.searchParams.has('srs')) {\n targetUrl.searchParams.set('srs', '3857')\n }\n\n const proxyResponse = await httpRequest('get', targetUrl.toString())\n const buffer = proxyResponse.payload\n const contentType = proxyResponse.res.headers['content-type']\n const response = h.response(buffer)\n\n if (contentType) {\n response.type(contentType)\n }\n\n return response\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n url: Joi.string().required()\n })\n .optional()\n }\n }\n }\n}\n\n/**\n * Proxies ordnance survey geocode requests from the front end to api.os.com\n * Used for the gazzeteer address lookup to find name from query strings like postcode and place names\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapGeocodeGetRequestRefs>}\n */\nfunction geocodeProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/geocode-proxy',\n async handler(request, _h) {\n const { query } = request\n const data = await find(query.query, options.ordnanceSurveyApiKey)\n\n return data\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n query: Joi.string().required()\n })\n .required()\n }\n }\n }\n}\n\n/**\n * Proxies ordnance survey reverse geocode requests from the front end to api.os.com\n * Used to find name from easting and northing points.\n * N.B this endpoint is currently not used by the front end but will be soon in \"maps V2\"\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapReverseGeocodeGetRequestRefs>}\n */\nfunction reverseGeocodeProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/reverse-geocode-proxy',\n async handler(request, _h) {\n const { query } = request\n const data = await nearest(\n query.easting,\n query.northing,\n options.ordnanceSurveyApiKey\n )\n\n return data\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n easting: Joi.number().required(),\n northing: Joi.number().required()\n })\n .required()\n }\n }\n }\n}\n\nfunction tileRoutes() {\n return [\n {\n method: 'GET',\n path: '/api/maps/vts/{path*}',\n options: {\n handler: {\n directory: {\n path: resolve(import.meta.dirname, './vts')\n }\n }\n }\n }\n ]\n}\n\n/**\n * @import { ServerRoute } from '@hapi/hapi'\n * @import { MapConfiguration, MapProxyGetRequestRefs, MapGeocodeGetRequestRefs, MapReverseGeocodeGetRequestRefs } from '~/src/server/plugins/map/types.js'\n */\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["resolve","StatusCodes","Joi","getAccessToken","find","nearest","get","request","httpRequest","getRoutes","options","mapStyleResourceRoutes","mapProxyRoute","tileProxyRoute","geocodeProxyRoute","reverseGeocodeProxyRoute","method","path","handler","h","query","targetUrl","URL","decodeURIComponent","url","token","searchParams","set","proxyResponse","toString","headers","Authorization","buffer","payload","contentType","res","response","type","validate","object","keys","string","required","optional","z","y","x","params","Accept","json","gunzip","statusCode","OK","valueOf","code","header","_h","data","ordnanceSurveyApiKey","easting","northing","number","directory","import","meta","dirname"],"sources":["../../../../../src/server/plugins/map/routes/index.js"],"sourcesContent":["import { resolve } from 'node:path'\n\nimport { StatusCodes } from 'http-status-codes'\nimport Joi from 'joi'\n\nimport { getAccessToken } from '~/src/server/plugins/map/routes/get-os-token.js'\nimport { find, nearest } from '~/src/server/plugins/map/service.js'\nimport {\n get,\n request as httpRequest\n} from '~/src/server/services/httpService.js'\n\n/**\n * Gets the map support routes\n * @param {MapConfiguration} options - ordnance survey names api key\n */\nexport function getRoutes(options) {\n return [\n mapStyleResourceRoutes(),\n mapProxyRoute(options),\n tileProxyRoute(options),\n geocodeProxyRoute(options),\n reverseGeocodeProxyRoute(options)\n ]\n}\n\n/**\n * Proxies ordnance survey requests from the front end to api.os.com\n * Used for the VTS map source by forwarding on the request\n * and adding the auth token and SRS (spatial reference system)\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapProxyGetRequestRefs>}\n */\nfunction mapProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/map-proxy',\n handler: async (request, h) => {\n const { query } = request\n const targetUrl = new URL(decodeURIComponent(query.url))\n const token = await getAccessToken(options)\n\n targetUrl.searchParams.set('srs', '3857')\n\n const proxyResponse = await httpRequest('get', targetUrl.toString(), {\n headers: {\n Authorization: `Bearer ${token}`\n }\n })\n const buffer = proxyResponse.payload\n const contentType = proxyResponse.res.headers['content-type']\n const response = h.response(buffer)\n\n if (contentType) {\n response.type(contentType)\n }\n\n return response\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n url: Joi.string().required()\n })\n .optional()\n }\n }\n }\n}\n\n/**\n * Proxies ordnance survey requests from the front end to api.os.uk\n * Used for VTS map tiles forwarding on the request and adding the auth token\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapProxyGetRequestRefs>}\n */\nfunction tileProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/tile/{z}/{y}/{x}.pbf',\n handler: async (request, h) => {\n const { z, y, x } = request.params\n const token = await getAccessToken(options)\n\n const url = `https://api.os.uk/maps/vector/v1/vts/tile/${z}/${y}/${x}.pbf?srs=3857`\n\n const { payload, res } = await get(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: 'application/x-protobuf'\n },\n json: false,\n gunzip: true\n })\n\n if (res.statusCode && res.statusCode !== StatusCodes.OK.valueOf()) {\n return h.response('Tile fetch failed').code(res.statusCode)\n }\n\n return h\n .response(payload)\n .type('application/x-protobuf')\n .header('Cache-Control', 'public, max-age=86400')\n }\n }\n}\n\n/**\n * Proxies ordnance survey geocode requests from the front end to api.os.uk\n * Used for the gazzeteer address lookup to find name from query strings like postcode and place names\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapGeocodeGetRequestRefs>}\n */\nfunction geocodeProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/geocode-proxy',\n async handler(request, _h) {\n const { query } = request\n const data = await find(query.query, options.ordnanceSurveyApiKey)\n\n return data\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n query: Joi.string().required()\n })\n .required()\n }\n }\n }\n}\n\n/**\n * Proxies ordnance survey reverse geocode requests from the front end to api.os.uk\n * Used to find name from easting and northing points.\n * N.B this endpoint is currently not used by the front end but will be soon in \"maps V2\"\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapReverseGeocodeGetRequestRefs>}\n */\nfunction reverseGeocodeProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/reverse-geocode-proxy',\n async handler(request, _h) {\n const { query } = request\n const data = await nearest(\n query.easting,\n query.northing,\n options.ordnanceSurveyApiKey\n )\n\n return data\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n easting: Joi.number().required(),\n northing: Joi.number().required()\n })\n .required()\n }\n }\n }\n}\n\n/**\n * Resource routes to return sprites and glyphs\n * @returns {ServerRoute<MapProxyGetRequestRefs>}\n */\nfunction mapStyleResourceRoutes() {\n return {\n method: 'GET',\n path: '/api/maps/vts/{path*}',\n options: {\n handler: {\n directory: {\n path: resolve(import.meta.dirname, './vts')\n }\n }\n }\n }\n}\n\n/**\n * @import { ServerRoute } from '@hapi/hapi'\n * @import { MapConfiguration, MapProxyGetRequestRefs, MapGeocodeGetRequestRefs, MapReverseGeocodeGetRequestRefs } from '~/src/server/plugins/map/types.js'\n */\n"],"mappings":"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","ignoreList":[]}
@@ -1,5 +1,6 @@
1
1
  export type MapConfiguration = {
2
2
  ordnanceSurveyApiKey: string;
3
+ ordnanceSurveyApiSecret: string;
3
4
  };
4
5
  /**
5
6
  * Map proxy query params
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @typedef {{
3
3
  * ordnanceSurveyApiKey: string
4
+ * ordnanceSurveyApiSecret: string
4
5
  * }} MapConfiguration
5
6
  */
6
7
 
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../../../src/server/plugins/map/types.js"],"sourcesContent":["/**\n * @typedef {{\n * ordnanceSurveyApiKey: string\n * }} MapConfiguration\n */\n\n//\n// Route types\n//\n\n/**\n * Map proxy query params\n * @typedef {object} MapProxyQuery\n * @property {string} url - the proxied url\n */\n\n/**\n * Map geocode query params\n * @typedef {object} MapGeocodeQuery\n * @property {string} query - name query\n */\n\n/**\n * Map reverse geocode query params\n * @typedef {object} MapReverseGeocodeQuery\n * @property {number} easting - the Easting point\n * @property {number} northing - the Northing point\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapProxyGetRequestRefs\n * @property {MapProxyQuery} Query - Request query\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapGeocodeGetRequestRefs\n * @property {MapGeocodeQuery} Query - Request query\n */\n\n/**\n * Map reverst geocode get request\n * @typedef {object} MapReverseGeocodeGetRequestRefs\n * @property {MapReverseGeocodeQuery} Query - Request query\n */\n\n/**\n * @typedef {MapProxyGetRequestRefs} MapProxyRequestRefs\n * @typedef {MapGeocodeGetRequestRefs} MapGeocodeRequestRefs\n * @typedef {MapReverseGeocodeGetRequestRefs} MapReverseGeocodeRequestRefs\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapProxyGetRequest\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapGeocodeGetRequest\n * @typedef {Request<MapReverseGeocodeGetRequestRefs>} MapReverseGeocodeGetRequest\n * @typedef {MapProxyGetRequest | MapGeocodeGetRequest | MapReverseGeocodeGetRequest} MapRequest\n */\n\n//\n// Service types\n//\n\n/**\n * @typedef {object} OsNamesFindResponse\n * @property {OsNamesFindHeader} header - Metadata about the search request and results.\n * @property {OsNamesFindResult[]} results - An array of matched place records from the search.\n */\n\n/**\n * @typedef {object} OsNamesFindHeader\n * @property {string} uri - The query URI (usually same as search text).\n * @property {string} query - The original text query string passed to the API.\n * @property {string} format - The response format returned (e.g., \"JSON\").\n * @property {number} maxresults - The maximum number of results requested.\n * @property {number} offset - The offset used in the search results.\n * @property {number} totalresults - The total number of results that matched the query.\n * @property {string} filter - The original filter string passed to the API.\n */\n\n/**\n * @typedef {object} OsNamesFindGazetteerEntry\n * @property {string} ID - Unique identifier for the place/feature.\n * @property {string} NAMES_URI - A URI (identifier) for this named feature.\n * @property {string} NAME1 - Primary name of the feature.\n * @property {string} TYPE - General type classification of the feature.\n * @property {string} LOCAL_TYPE - Local or more specific type classification.\n * @property {number} GEOMETRY_X - Easting coordinate (British National Grid).\n * @property {number} GEOMETRY_Y - Northing coordinate (British National Grid).\n * @property {number} MOST_DETAIL_VIEW_RES - Most detailed resolution available.\n * @property {number} LEAST_DETAIL_VIEW_RES - Least detailed resolution available.\n * @property {number} [MBR_XMIN] - Minimum bounding box X (easting).\n * @property {number} [MBR_YMIN] - Minimum bounding box Y (northing).\n * @property {number} [MBR_XMAX] - Maximum bounding box X (easting).\n * @property {number} [MBR_YMAX] - Maximum bounding box Y (northing).\n * @property {string} [DISTRICT_BOROUGH] - (Optional) District borough.\n * @property {string} [DISTRICT_BOROUGH_URI] - (Optional) URI for the district borough.\n * @property {string} [DISTRICT_BOROUGH_TYPE] - (Optional) Type of the district borough.\n * @property {string} [POSTCODE_DISTRICT] - (Optional) Postcode district.\n * @property {string} [POSTCODE_DISTRICT_URI] - (Optional) URI for the postcode district.\n * @property {string} [POPULATED_PLACE] - (Optional) Name of associated populated place.\n * @property {string} [POPULATED_PLACE_URI] - (Optional) URI of populated place.\n * @property {string} [POPULATED_PLACE_TYPE] - (Optional) Type of populated place.\n * @property {string} [COUNTY_UNITARY] - (Optional) County or unitary authority name.\n * @property {string} [COUNTY_UNITARY_URI] - (Optional) URI for county/unitary authority.\n * @property {string} [COUNTY_UNITARY_TYPE] - (Optional) Classification of county/unitary authority.\n * @property {string} [REGION] - (Optional) Region name.\n * @property {string} [REGION_URI] - (Optional) URI for region.\n * @property {string} [COUNTRY] - (Optional) Country name.\n * @property {string} [COUNTRY_URI] - (Optional) URI for country.\n */\n\n/**\n * OS names GAZETTEER_ENTRY response\n * @typedef {object} OsNamesFindResult\n * @property {OsNamesFindGazetteerEntry} GAZETTEER_ENTRY - Gazetteer entry\n */\n\n/**\n * @import { Request } from '@hapi/hapi'\n */\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA","ignoreList":[]}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../../src/server/plugins/map/types.js"],"sourcesContent":["/**\n * @typedef {{\n * ordnanceSurveyApiKey: string\n * ordnanceSurveyApiSecret: string\n * }} MapConfiguration\n */\n\n//\n// Route types\n//\n\n/**\n * Map proxy query params\n * @typedef {object} MapProxyQuery\n * @property {string} url - the proxied url\n */\n\n/**\n * Map geocode query params\n * @typedef {object} MapGeocodeQuery\n * @property {string} query - name query\n */\n\n/**\n * Map reverse geocode query params\n * @typedef {object} MapReverseGeocodeQuery\n * @property {number} easting - the Easting point\n * @property {number} northing - the Northing point\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapProxyGetRequestRefs\n * @property {MapProxyQuery} Query - Request query\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapGeocodeGetRequestRefs\n * @property {MapGeocodeQuery} Query - Request query\n */\n\n/**\n * Map reverst geocode get request\n * @typedef {object} MapReverseGeocodeGetRequestRefs\n * @property {MapReverseGeocodeQuery} Query - Request query\n */\n\n/**\n * @typedef {MapProxyGetRequestRefs} MapProxyRequestRefs\n * @typedef {MapGeocodeGetRequestRefs} MapGeocodeRequestRefs\n * @typedef {MapReverseGeocodeGetRequestRefs} MapReverseGeocodeRequestRefs\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapProxyGetRequest\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapGeocodeGetRequest\n * @typedef {Request<MapReverseGeocodeGetRequestRefs>} MapReverseGeocodeGetRequest\n * @typedef {MapProxyGetRequest | MapGeocodeGetRequest | MapReverseGeocodeGetRequest} MapRequest\n */\n\n//\n// Service types\n//\n\n/**\n * @typedef {object} OsNamesFindResponse\n * @property {OsNamesFindHeader} header - Metadata about the search request and results.\n * @property {OsNamesFindResult[]} results - An array of matched place records from the search.\n */\n\n/**\n * @typedef {object} OsNamesFindHeader\n * @property {string} uri - The query URI (usually same as search text).\n * @property {string} query - The original text query string passed to the API.\n * @property {string} format - The response format returned (e.g., \"JSON\").\n * @property {number} maxresults - The maximum number of results requested.\n * @property {number} offset - The offset used in the search results.\n * @property {number} totalresults - The total number of results that matched the query.\n * @property {string} filter - The original filter string passed to the API.\n */\n\n/**\n * @typedef {object} OsNamesFindGazetteerEntry\n * @property {string} ID - Unique identifier for the place/feature.\n * @property {string} NAMES_URI - A URI (identifier) for this named feature.\n * @property {string} NAME1 - Primary name of the feature.\n * @property {string} TYPE - General type classification of the feature.\n * @property {string} LOCAL_TYPE - Local or more specific type classification.\n * @property {number} GEOMETRY_X - Easting coordinate (British National Grid).\n * @property {number} GEOMETRY_Y - Northing coordinate (British National Grid).\n * @property {number} MOST_DETAIL_VIEW_RES - Most detailed resolution available.\n * @property {number} LEAST_DETAIL_VIEW_RES - Least detailed resolution available.\n * @property {number} [MBR_XMIN] - Minimum bounding box X (easting).\n * @property {number} [MBR_YMIN] - Minimum bounding box Y (northing).\n * @property {number} [MBR_XMAX] - Maximum bounding box X (easting).\n * @property {number} [MBR_YMAX] - Maximum bounding box Y (northing).\n * @property {string} [DISTRICT_BOROUGH] - (Optional) District borough.\n * @property {string} [DISTRICT_BOROUGH_URI] - (Optional) URI for the district borough.\n * @property {string} [DISTRICT_BOROUGH_TYPE] - (Optional) Type of the district borough.\n * @property {string} [POSTCODE_DISTRICT] - (Optional) Postcode district.\n * @property {string} [POSTCODE_DISTRICT_URI] - (Optional) URI for the postcode district.\n * @property {string} [POPULATED_PLACE] - (Optional) Name of associated populated place.\n * @property {string} [POPULATED_PLACE_URI] - (Optional) URI of populated place.\n * @property {string} [POPULATED_PLACE_TYPE] - (Optional) Type of populated place.\n * @property {string} [COUNTY_UNITARY] - (Optional) County or unitary authority name.\n * @property {string} [COUNTY_UNITARY_URI] - (Optional) URI for county/unitary authority.\n * @property {string} [COUNTY_UNITARY_TYPE] - (Optional) Classification of county/unitary authority.\n * @property {string} [REGION] - (Optional) Region name.\n * @property {string} [REGION_URI] - (Optional) URI for region.\n * @property {string} [COUNTRY] - (Optional) Country name.\n * @property {string} [COUNTRY_URI] - (Optional) URI for country.\n */\n\n/**\n * OS names GAZETTEER_ENTRY response\n * @typedef {object} OsNamesFindResult\n * @property {OsNamesFindGazetteerEntry} GAZETTEER_ENTRY - Gazetteer entry\n */\n\n/**\n * @import { Request } from '@hapi/hapi'\n */\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA","ignoreList":[]}