diff --git a/.tool-versions b/.tool-versions index 5f6bb2f9c..8f9af443b 100644 --- a/.tool-versions +++ b/.tool-versions @@ -6,6 +6,7 @@ terraform-docs 0.19.0 vale 3.6.0 tfsec 1.28.10 nodejs 20.18.2 +jq 1.6 # ============================================================================== # The section below is reserved for Docker image versions. diff --git a/frontend/src/__tests__/app/copy-template/page.test.tsx b/frontend/src/__tests__/app/copy-template/page.test.tsx index 68c5503c9..e940b3364 100644 --- a/frontend/src/__tests__/app/copy-template/page.test.tsx +++ b/frontend/src/__tests__/app/copy-template/page.test.tsx @@ -3,18 +3,10 @@ */ import CopyTemplatePage from '@app/copy-template/[templateId]/page'; import { CopyTemplate } from '@forms/CopyTemplate/CopyTemplate'; -import { - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { getTemplate } from '@utils/form-actions'; -import { - Language, - LetterType, - TemplateDTO, - VirusScanStatus, -} from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { LetterTemplate } from 'nhs-notify-web-template-management-utils'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -28,34 +20,34 @@ describe('CopyTemplatePage', () => { const template = { id: 'template-id', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', subject: 'template-subject-line', message: 'template-message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - } satisfies TemplateDTO; + } satisfies TemplateDto; - const letterTemplate: TemplateDTO = { + const letterTemplate: LetterTemplate = { id: 'template-id', - templateType: TemplateType.LETTER, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'LETTER', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - letterType: LetterType.Q4, - language: Language.FR, + letterType: 'q4', + language: 'fr', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: '61C1267A-0F37-4E1D-831E-494DE2BECC8C', - virusScanStatus: VirusScanStatus.PASSED, + virusScanStatus: 'PASSED', }, testDataCsv: { fileName: 'file.csv', currentVersion: 'A8A76934-70F4-4735-8314-51CE097130DB', - virusScanStatus: VirusScanStatus.PASSED, + virusScanStatus: 'PASSED', }, }, }; diff --git a/frontend/src/__tests__/app/create-email-template/__snapshots__/page.test.tsx.snap b/frontend/src/__tests__/app/create-email-template/__snapshots__/page.test.tsx.snap index 1bab77da0..17dcf630c 100644 --- a/frontend/src/__tests__/app/create-email-template/__snapshots__/page.test.tsx.snap +++ b/frontend/src/__tests__/app/create-email-template/__snapshots__/page.test.tsx.snap @@ -7,7 +7,6 @@ exports[`CreateEmailTemplatePage should render CreateEmailTemplatePage 1`] = ` "message": "", "name": "", "subject": "", - "templateStatus": "NOT_YET_SUBMITTED", "templateType": "EMAIL", } } diff --git a/frontend/src/__tests__/app/create-nhs-app-template/__snapshots__/page.test.tsx.snap b/frontend/src/__tests__/app/create-nhs-app-template/__snapshots__/page.test.tsx.snap index ab219c33e..6654f0594 100644 --- a/frontend/src/__tests__/app/create-nhs-app-template/__snapshots__/page.test.tsx.snap +++ b/frontend/src/__tests__/app/create-nhs-app-template/__snapshots__/page.test.tsx.snap @@ -6,7 +6,6 @@ exports[`CreateNHSAppTemplatePage should render CreateNHSAppTemplatePage 1`] = ` { "message": "", "name": "", - "templateStatus": "NOT_YET_SUBMITTED", "templateType": "NHS_APP", } } diff --git a/frontend/src/__tests__/app/create-text-message-template/__snapshots__/page.test.tsx.snap b/frontend/src/__tests__/app/create-text-message-template/__snapshots__/page.test.tsx.snap index 059755a27..8493572b8 100644 --- a/frontend/src/__tests__/app/create-text-message-template/__snapshots__/page.test.tsx.snap +++ b/frontend/src/__tests__/app/create-text-message-template/__snapshots__/page.test.tsx.snap @@ -6,7 +6,6 @@ exports[`CreateSMSTemplatePage should render CreateSMSTemplatePage 1`] = ` { "message": "", "name": "", - "templateStatus": "NOT_YET_SUBMITTED", "templateType": "SMS", } } diff --git a/frontend/src/__tests__/app/delete-template/page.test.tsx b/frontend/src/__tests__/app/delete-template/page.test.tsx index 3437b44bf..cc0935b79 100644 --- a/frontend/src/__tests__/app/delete-template/page.test.tsx +++ b/frontend/src/__tests__/app/delete-template/page.test.tsx @@ -3,14 +3,9 @@ */ import DeleteTemplatePage from '@app/delete-template/[templateId]/page'; import { DeleteTemplate } from '@forms/DeleteTemplate/DeleteTemplate'; -import { - EmailTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { getTemplate } from '@utils/form-actions'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -25,20 +20,20 @@ describe('PreviewEmailTemplatePage', () => { it('should load page', async () => { const templateDTO = { id: 'template-id', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', subject: 'template-subject-line', message: 'template-message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - } satisfies TemplateDTO; + } satisfies TemplateDto; - const emailTemplate: EmailTemplate = { + const emailTemplate: TemplateDto = { ...templateDTO, subject: 'template-subject-line', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', }; getTemplateMock.mockResolvedValueOnce(templateDTO); @@ -65,8 +60,8 @@ describe('PreviewEmailTemplatePage', () => { test('should redirect to invalid-template when template is already submitted', async () => { getTemplateMock.mockResolvedValueOnce({ id: 'template-id', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.NHS_APP, + templateStatus: 'SUBMITTED', + templateType: 'NHS_APP', name: 'template-name', message: 'template-message', createdAt: 'today', @@ -85,8 +80,8 @@ describe('PreviewEmailTemplatePage', () => { test('should redirect to manage-templates when template is already deleted', async () => { getTemplateMock.mockResolvedValueOnce({ id: 'template-id', - templateStatus: TemplateStatus.DELETED, - templateType: TemplateType.NHS_APP, + templateStatus: 'DELETED', + templateType: 'NHS_APP', name: 'template-name', message: 'template-message', createdAt: 'today', diff --git a/frontend/src/__tests__/app/edit-email-template/page.test.tsx b/frontend/src/__tests__/app/edit-email-template/page.test.tsx index dd7380311..4ffdcd85a 100644 --- a/frontend/src/__tests__/app/edit-email-template/page.test.tsx +++ b/frontend/src/__tests__/app/edit-email-template/page.test.tsx @@ -3,14 +3,9 @@ */ import EditEmailTemplatePage from '@app/edit-email-template/[templateId]/page'; import { getTemplate } from '@utils/form-actions'; -import { - EmailTemplate, - TemplateStatus, - TemplateType, -} from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { EmailTemplateForm } from '@forms/EmailTemplateForm/EmailTemplateForm'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { EmailTemplate } from 'nhs-notify-web-template-management-utils'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -19,16 +14,16 @@ jest.mock('@forms/EmailTemplateForm/EmailTemplateForm'); const getTemplateMock = jest.mocked(getTemplate); const redirectMock = jest.mocked(redirect); -const templateDTO = { +const template: EmailTemplate = { id: 'template-id', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', subject: 'subject', message: 'message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', -} satisfies TemplateDTO; +}; describe('EditEmailTemplatePage', () => { beforeEach(jest.resetAllMocks); @@ -49,8 +44,8 @@ describe('EditEmailTemplatePage', () => { it('should redirect to invalid-template when template type is not EMAIL', async () => { getTemplateMock.mockResolvedValueOnce({ - ...templateDTO, - templateType: TemplateType.NHS_APP, + ...template, + templateType: 'NHS_APP', }); await EditEmailTemplatePage({ @@ -65,13 +60,13 @@ describe('EditEmailTemplatePage', () => { }); it('should render CreateEmailTemplatePage component when template is found', async () => { - getTemplateMock.mockResolvedValueOnce(templateDTO); + getTemplateMock.mockResolvedValueOnce(template); - const emailTemplate: EmailTemplate = { - ...templateDTO, + const emailTemplate = { + ...template, subject: 'subject', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL' as const, + templateStatus: 'NOT_YET_SUBMITTED', }; const page = await EditEmailTemplatePage({ diff --git a/frontend/src/__tests__/app/edit-nhs-app-template/page.test.tsx b/frontend/src/__tests__/app/edit-nhs-app-template/page.test.tsx index 996ccb326..8c2979a82 100644 --- a/frontend/src/__tests__/app/edit-nhs-app-template/page.test.tsx +++ b/frontend/src/__tests__/app/edit-nhs-app-template/page.test.tsx @@ -2,15 +2,12 @@ * @jest-environment node */ import { redirect } from 'next/navigation'; -import { - TemplateType, - TemplateStatus, - NHSAppTemplate, -} from 'nhs-notify-web-template-management-utils'; +import { NHSAppTemplate } from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { NhsAppTemplateForm } from '@forms/NhsAppTemplateForm/NhsAppTemplateForm'; import EditNhsAppTemplatePage from '@app/edit-nhs-app-template/[templateId]/page'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { EMAIL_TEMPLATE, LETTER_TEMPLATE, SMS_TEMPLATE } from '../../helpers'; jest.mock('@forms/NhsAppTemplateForm/NhsAppTemplateForm'); jest.mock('@utils/form-actions'); @@ -23,23 +20,23 @@ describe('EditNhsAppTemplatePage', () => { beforeEach(jest.resetAllMocks); test('page loads', async () => { - const templateDTO = { + const template = { id: 'template-id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - } satisfies TemplateDTO; + } satisfies TemplateDto; const nhsAppTemplate: NHSAppTemplate = { - ...templateDTO, - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + ...template, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', }; - getTemplateMock.mockResolvedValueOnce(templateDTO); + getTemplateMock.mockResolvedValueOnce(template); const page = await EditNhsAppTemplatePage({ params: Promise.resolve({ @@ -62,23 +59,10 @@ describe('EditNhsAppTemplatePage', () => { expect(redirectMock).toHaveBeenCalledWith('/invalid-template', 'replace'); }); - const invalidTemplateTypes: TemplateType[] = [ - TemplateType.EMAIL, - TemplateType.SMS, - ]; - - test.each(invalidTemplateTypes)( - 'should render invalid template, when template type is %p', - async (templateType) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - templateType, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - name: 'name', - message: 'message', - createdAt: 'today', - updatedAt: 'today', - }); + test.each([EMAIL_TEMPLATE, SMS_TEMPLATE, LETTER_TEMPLATE])( + 'should render invalid template, when template type is $templateType', + async (template) => { + getTemplateMock.mockResolvedValueOnce(template); await EditNhsAppTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/app/edit-text-message-template/page.test.tsx b/frontend/src/__tests__/app/edit-text-message-template/page.test.tsx index cb6866128..99363114b 100644 --- a/frontend/src/__tests__/app/edit-text-message-template/page.test.tsx +++ b/frontend/src/__tests__/app/edit-text-message-template/page.test.tsx @@ -3,14 +3,10 @@ */ import EditSmsTemplatePage from '@app/edit-text-message-template/[templateId]/page'; import { getTemplate } from '@utils/form-actions'; -import { - SMSTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { SmsTemplateForm } from '@forms/SmsTemplateForm/SmsTemplateForm'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { SMSTemplate } from 'nhs-notify-web-template-management-utils'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -21,13 +17,13 @@ const redirectMock = jest.mocked(redirect); const templateDTO = { id: 'template-id', - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', -} satisfies TemplateDTO; +} satisfies TemplateDto; describe('EditSmsTemplatePage', () => { beforeEach(jest.resetAllMocks); @@ -49,7 +45,7 @@ describe('EditSmsTemplatePage', () => { it('should redirect to invalid-template when template type is not SMS', async () => { getTemplateMock.mockResolvedValueOnce({ ...templateDTO, - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }); await EditSmsTemplatePage({ @@ -68,8 +64,8 @@ describe('EditSmsTemplatePage', () => { const smsTemplate: SMSTemplate = { ...templateDTO, - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', }; const page = await EditSmsTemplatePage({ diff --git a/frontend/src/__tests__/app/email-template-submitted/page.test.tsx b/frontend/src/__tests__/app/email-template-submitted/page.test.tsx index edb19b4c1..dbed2f2d5 100644 --- a/frontend/src/__tests__/app/email-template-submitted/page.test.tsx +++ b/frontend/src/__tests__/app/email-template-submitted/page.test.tsx @@ -2,13 +2,10 @@ * @jest-environment node */ import EmailTemplateSubmittedPage from '@app/email-template-submitted/[templateId]/page'; -import { - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; import { TemplateSubmitted } from '@molecules/TemplateSubmitted/TemplateSubmitted'; import { getTemplate } from '@utils/form-actions'; import { redirect } from 'next/navigation'; +import { TemplateDto } from 'nhs-notify-backend-client'; jest.mock('@molecules/TemplateSubmitted/TemplateSubmitted'); jest.mock('@utils/form-actions'); @@ -23,14 +20,14 @@ describe('EmailTemplateSubmittedPage', () => { test('should load page', async () => { const template = { id: 'template-id', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'SUBMITTED', name: 'template-name', message: 'example', subject: 'subject', createdAt: 'today', updatedAt: 'today', - }; + } satisfies TemplateDto; getTemplateMock.mockResolvedValueOnce(template); diff --git a/frontend/src/__tests__/app/manage-templates/page.test.tsx b/frontend/src/__tests__/app/manage-templates/page.test.tsx index 05fc4ac65..836973bf1 100644 --- a/frontend/src/__tests__/app/manage-templates/page.test.tsx +++ b/frontend/src/__tests__/app/manage-templates/page.test.tsx @@ -3,22 +3,17 @@ import { render, screen } from '@testing-library/react'; import ManageTemplatesPage from '@app/manage-templates/page'; import content from '@content/content'; import { getTemplates } from '@utils/form-actions'; -import { - TemplateStatus, - TemplateType, -} from 'nhs-notify-web-template-management-utils'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; const manageTemplatesContent = content.pages.manageTemplates; -const mockTemplates: TemplateDTO[] = [ +const mockTemplates: TemplateDto[] = [ { id: '1', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'Template 1', message: 'Message', - subject: 'Subject Line', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', }, diff --git a/frontend/src/__tests__/app/nhs-app-template-submitted/page.test.tsx b/frontend/src/__tests__/app/nhs-app-template-submitted/page.test.tsx index 85438f9dc..b04dd6637 100644 --- a/frontend/src/__tests__/app/nhs-app-template-submitted/page.test.tsx +++ b/frontend/src/__tests__/app/nhs-app-template-submitted/page.test.tsx @@ -2,13 +2,10 @@ * @jest-environment node */ import NhsAppTemplateSubmittedPage from '@app/nhs-app-template-submitted/[templateId]/page'; -import { - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; import { TemplateSubmitted } from '@molecules/TemplateSubmitted/TemplateSubmitted'; import { getTemplate } from '@utils/form-actions'; import { redirect } from 'next/navigation'; +import { TemplateDto } from 'nhs-notify-backend-client'; jest.mock('@molecules/TemplateSubmitted/TemplateSubmitted'); jest.mock('@utils/form-actions'); @@ -23,11 +20,11 @@ describe('NhsAppTemplateSubmittedPage', () => { test('should load page', async () => { const template = { id: 'template-id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'SUBMITTED', name: 'template-name', message: 'example', - }; + } satisfies Partial; getTemplateMock.mockResolvedValueOnce({ ...template, diff --git a/frontend/src/__tests__/app/preview-email-template/page.test.tsx b/frontend/src/__tests__/app/preview-email-template/page.test.tsx index 4520d1a40..140a016c8 100644 --- a/frontend/src/__tests__/app/preview-email-template/page.test.tsx +++ b/frontend/src/__tests__/app/preview-email-template/page.test.tsx @@ -3,14 +3,16 @@ */ import PreviewEmailTemplatePage from '@app/preview-email-template/[templateId]/page'; import { PreviewEmailTemplate } from '@forms/PreviewEmailTemplate'; -import { - EmailTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { EmailTemplate } from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { getTemplate } from '@utils/form-actions'; -import { Language, LetterType, TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { + EMAIL_TEMPLATE, + LETTER_TEMPLATE, + NHS_APP_TEMPLATE, + SMS_TEMPLATE, +} from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -25,20 +27,20 @@ describe('PreviewEmailTemplatePage', () => { it('should load page', async () => { const templateDTO = { id: 'template-id', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', subject: 'template-subject-line', message: 'template-message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - } satisfies TemplateDTO; + } satisfies TemplateDto; const emailTemplate: EmailTemplate = { ...templateDTO, subject: 'template-subject-line', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', }; getTemplateMock.mockResolvedValueOnce(templateDTO); @@ -63,58 +65,29 @@ describe('PreviewEmailTemplatePage', () => { }); test.each([ + SMS_TEMPLATE, + NHS_APP_TEMPLATE, + LETTER_TEMPLATE, { - templateType: TemplateType.SMS, - name: 'template-name', - subject: 'template-subject-line', - message: 'template-message', - }, - { - templateType: TemplateType.NHS_APP, - name: 'template-name', - subject: 'template-subject-line', - message: 'template-message', - }, - { - templateType: TemplateType.LETTER, - name: 'template-name', - letterType: LetterType.X0, - language: Language.EN, - }, - { - templateType: TemplateType.EMAIL, + ...EMAIL_TEMPLATE, name: undefined as unknown as string, - subject: 'template-subject-line', - message: 'template-message', }, { - templateType: TemplateType.EMAIL, - name: 'template-name', + ...EMAIL_TEMPLATE, subject: undefined as unknown as string, - message: 'template-message', }, { - templateType: TemplateType.EMAIL, - name: 'template-name', - subject: 'template-subject-line', + ...EMAIL_TEMPLATE, message: undefined as unknown as string, }, { - templateType: TemplateType.EMAIL, - name: 'template-name', - subject: 'template-subject-line', + ...EMAIL_TEMPLATE, message: null as unknown as string, }, ])( 'should redirect to invalid-template when template is $templateType and name is $emailTemplateName and subjectLine is $$emailTemplateSubjectLine and message is $emailTemplateMessage', async (value) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - ...value, - createdAt: '2025-01-13T10:19:25.579Z', - updatedAt: '2025-01-13T10:19:25.579Z', - }); + getTemplateMock.mockResolvedValueOnce(value); await PreviewEmailTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/app/preview-letter-template/page.test.tsx b/frontend/src/__tests__/app/preview-letter-template/page.test.tsx index f4d854939..eaead30c6 100644 --- a/frontend/src/__tests__/app/preview-letter-template/page.test.tsx +++ b/frontend/src/__tests__/app/preview-letter-template/page.test.tsx @@ -3,19 +3,11 @@ */ import PreviewLetterTemplatePage from '@app/preview-letter-template/[templateId]/page'; import { PreviewLetterTemplate } from '@forms/PreviewLetterTemplate/PreviewLetterTemplate'; -import { - type LetterTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { type LetterTemplate } from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { getTemplate } from '@utils/form-actions'; -import { - Language, - LetterType, - TemplateDTO, - VirusScanStatus, -} from 'nhs-notify-backend-client'; +import { Language, LetterType, TemplateDto } from 'nhs-notify-backend-client'; +import { EMAIL_TEMPLATE, NHS_APP_TEMPLATE, SMS_TEMPLATE } from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -26,31 +18,31 @@ const getTemplateMock = jest.mocked(getTemplate); const templateDTO = { id: 'template-id', - templateType: TemplateType.LETTER, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'LETTER', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - letterType: LetterType.X0, - language: Language.EN, + letterType: 'x0', + language: 'en', files: { pdfTemplate: { fileName: 'template.pdf', currentVersion: 'saoj867b789', - virusScanStatus: VirusScanStatus.PASSED, + virusScanStatus: 'PASSED', }, testDataCsv: { fileName: 'test-data.csv', currentVersion: '897asiahv87', - virusScanStatus: VirusScanStatus.FAILED, + virusScanStatus: 'FAILED', }, }, -} satisfies TemplateDTO; +} satisfies TemplateDto; const letterTemplate: LetterTemplate = { ...templateDTO, - templateType: TemplateType.LETTER, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'LETTER', + templateStatus: 'NOT_YET_SUBMITTED', }; describe('PreviewLetterTemplatePage', () => { @@ -85,21 +77,15 @@ describe('PreviewLetterTemplatePage', () => { test.each([ { description: 'an email', - templateType: TemplateType.EMAIL, - name: 'template-name', - message: 'template-message', + ...EMAIL_TEMPLATE, }, { description: 'an SMS', - templateType: TemplateType.SMS, - name: 'template-name', - message: 'template-message', + ...SMS_TEMPLATE, }, { description: 'an app message', - templateType: TemplateType.NHS_APP, - name: 'template-name', - message: 'template-message', + ...NHS_APP_TEMPLATE, }, { description: 'a letter lacking language', @@ -119,7 +105,7 @@ describe('PreviewLetterTemplatePage', () => { pdfTemplate: { fileName: undefined as unknown as string, currentVersion: 'uuid', - virusScanStatus: VirusScanStatus.FAILED, + virusScanStatus: 'FAILED' as const, }, }, }, diff --git a/frontend/src/__tests__/app/preview-nhs-app-template/page.test.tsx b/frontend/src/__tests__/app/preview-nhs-app-template/page.test.tsx index ffdc6c043..748bb9194 100644 --- a/frontend/src/__tests__/app/preview-nhs-app-template/page.test.tsx +++ b/frontend/src/__tests__/app/preview-nhs-app-template/page.test.tsx @@ -3,14 +3,16 @@ */ import PreviewNhsAppTemplatePage from '@app/preview-nhs-app-template/[templateId]/page'; import { PreviewNHSAppTemplate } from '@forms/PreviewNHSAppTemplate/PreviewNHSAppTemplate'; -import { - NHSAppTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { NHSAppTemplate } from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { getTemplate } from '@utils/form-actions'; -import { Language, LetterType, TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { + EMAIL_TEMPLATE, + LETTER_TEMPLATE, + NHS_APP_TEMPLATE, + SMS_TEMPLATE, +} from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -25,18 +27,18 @@ describe('PreviewNhsAppTemplatePage', () => { it('should load page', async () => { const templateDTO = { id: 'template-id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', message: 'template-message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - } satisfies TemplateDTO; + } satisfies TemplateDto; const nhsAppTemplate: NHSAppTemplate = { ...templateDTO, - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', }; getTemplateMock.mockResolvedValueOnce(templateDTO); @@ -63,47 +65,26 @@ describe('PreviewNhsAppTemplatePage', () => { }); test.each([ + EMAIL_TEMPLATE, + SMS_TEMPLATE, + LETTER_TEMPLATE, { - templateType: TemplateType.EMAIL, - name: 'template-name', - message: 'template-message', - }, - { - templateType: TemplateType.SMS, - name: 'template-name', - message: 'template-message', - }, - { - templateType: TemplateType.LETTER, - name: 'template-name', - letterType: LetterType.X0, - language: Language.EN, - }, - { - templateType: TemplateType.NHS_APP, - name: 'template-name', + ...NHS_APP_TEMPLATE, message: undefined as unknown as string, }, { - templateType: TemplateType.NHS_APP, + ...NHS_APP_TEMPLATE, name: undefined as unknown as string, - message: 'template-message', }, { - templateType: TemplateType.NHS_APP, + ...NHS_APP_TEMPLATE, name: null as unknown as string, message: null as unknown as string, }, ])( 'should redirect to invalid-template when template is $templateType and name is $nhsAppTemplateName and message is $nhsAppTemplateMessage', async (value) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - ...value, - createdAt: '2025-01-13T10:19:25.579Z', - updatedAt: '2025-01-13T10:19:25.579Z', - }); + getTemplateMock.mockResolvedValueOnce(value); await PreviewNhsAppTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/app/preview-text-message-template/page.test.tsx b/frontend/src/__tests__/app/preview-text-message-template/page.test.tsx index 9102992ba..2d61780ee 100644 --- a/frontend/src/__tests__/app/preview-text-message-template/page.test.tsx +++ b/frontend/src/__tests__/app/preview-text-message-template/page.test.tsx @@ -3,14 +3,16 @@ */ import PreviewSMSTemplatePage from '@app/preview-text-message-template/[templateId]/page'; import { PreviewSMSTemplate } from '@forms/PreviewSMSTemplate'; -import { - SMSTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { SMSTemplate } from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { getTemplate } from '@utils/form-actions'; -import { Language, LetterType, TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { + EMAIL_TEMPLATE, + LETTER_TEMPLATE, + NHS_APP_TEMPLATE, + SMS_TEMPLATE, +} from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -25,18 +27,18 @@ describe('PreviewSMSTemplatePage', () => { it('should load page', async () => { const templateDTO = { id: 'template-id', - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', message: 'template-message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - } satisfies TemplateDTO; + } satisfies TemplateDto; const smsTemplate: SMSTemplate = { ...templateDTO, - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', }; getTemplateMock.mockResolvedValueOnce(templateDTO); @@ -61,47 +63,26 @@ describe('PreviewSMSTemplatePage', () => { }); test.each([ + EMAIL_TEMPLATE, + NHS_APP_TEMPLATE, + LETTER_TEMPLATE, { - templateType: TemplateType.EMAIL, - name: 'template-name', - message: 'template-message', - }, - { - templateType: TemplateType.NHS_APP, - name: 'template-name', - message: 'template-message', - }, - { - templateType: TemplateType.LETTER, - name: 'template-name', - letterType: LetterType.X0, - language: Language.EN, - }, - { - templateType: TemplateType.SMS, - name: 'template-name', + ...SMS_TEMPLATE, message: undefined as unknown as string, }, { - templateType: TemplateType.SMS, + ...SMS_TEMPLATE, name: undefined as unknown as string, - message: 'template-message', }, { - templateType: TemplateType.SMS, + ...SMS_TEMPLATE, name: null as unknown as string, message: null as unknown as string, }, ])( - 'should redirect to invalid-template when template is $templateType and name is $smsTemplateName and message is $smsTemplateMessage', + 'should redirect to invalid-template when template is $templateType and name is $name and message is $message', async (value) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - ...value, - createdAt: 'today', - updatedAt: 'today', - }); + getTemplateMock.mockResolvedValueOnce(value); await PreviewSMSTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/app/submit-email-template/page.test.tsx b/frontend/src/__tests__/app/submit-email-template/page.test.tsx index 67b8b11e3..3e859f7d6 100644 --- a/frontend/src/__tests__/app/submit-email-template/page.test.tsx +++ b/frontend/src/__tests__/app/submit-email-template/page.test.tsx @@ -5,10 +5,8 @@ import SubmitEmailTemplatePage from '@app/submit-email-template/[templateId]/pag import { SubmitTemplate } from '@forms/SubmitTemplate/SubmitTemplate'; import { redirect } from 'next/navigation'; import { getTemplate } from '@utils/form-actions'; -import { - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { EMAIL_TEMPLATE, NHS_APP_TEMPLATE, SMS_TEMPLATE } from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -23,12 +21,12 @@ describe('SubmitEmailTemplatePage', () => { test('should load page', async () => { const state = { id: 'template-id', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', subject: 'template-subject-line', message: 'template-message', - }; + } satisfies Partial; getTemplateMock.mockResolvedValue({ ...state, @@ -65,52 +63,28 @@ describe('SubmitEmailTemplatePage', () => { }); test.each([ + SMS_TEMPLATE, + NHS_APP_TEMPLATE, { - templateType: TemplateType.SMS, - name: 'template-name', - subject: 'template-subject-line', - message: 'template-message', - }, - { - templateType: TemplateType.NHS_APP, - name: 'template-name', - subject: 'template-subject-line', - message: 'template-message', - }, - { - templateType: TemplateType.EMAIL, + ...EMAIL_TEMPLATE, name: undefined as unknown as string, - subject: 'template-subject-line', - message: 'template-message', }, { - templateType: TemplateType.EMAIL, - name: 'template-name', + ...EMAIL_TEMPLATE, subject: undefined as unknown as string, - message: 'template-message', }, { - templateType: TemplateType.EMAIL, - name: 'template-name', - subject: 'template-subject-line', + ...EMAIL_TEMPLATE, message: undefined as unknown as string, }, { - templateType: TemplateType.EMAIL, - name: 'template-name', - subject: 'template-subject-line', + ...EMAIL_TEMPLATE, message: null as unknown as string, }, ])( 'should redirect to invalid-template when template is $templateType and name is $smsTemplateName and message is $smsTemplateMessage', async (value) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - ...value, - createdAt: 'today', - updatedAt: 'today', - }); + getTemplateMock.mockResolvedValueOnce(value); await SubmitEmailTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/app/submit-nhs-app-template/page.test.tsx b/frontend/src/__tests__/app/submit-nhs-app-template/page.test.tsx index 8a9190ad0..e1c351c35 100644 --- a/frontend/src/__tests__/app/submit-nhs-app-template/page.test.tsx +++ b/frontend/src/__tests__/app/submit-nhs-app-template/page.test.tsx @@ -5,10 +5,13 @@ import SubmitNhsAppTemplatePage from '@app/submit-nhs-app-template/[templateId]/ import { SubmitTemplate } from '@forms/SubmitTemplate/SubmitTemplate'; import { redirect } from 'next/navigation'; import { getTemplate } from '@utils/form-actions'; +import { TemplateDto } from 'nhs-notify-backend-client'; import { - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; + EMAIL_TEMPLATE, + LETTER_TEMPLATE, + NHS_APP_TEMPLATE, + SMS_TEMPLATE, +} from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -23,11 +26,11 @@ describe('SubmitNhsAppTemplatePage', () => { test('should load page', async () => { const state = { id: 'template-id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', message: 'template-message', - }; + } satisfies Partial; getTemplateMock.mockResolvedValue({ ...state, @@ -63,41 +66,26 @@ describe('SubmitNhsAppTemplatePage', () => { }); test.each([ + EMAIL_TEMPLATE, + SMS_TEMPLATE, + LETTER_TEMPLATE, { - templateType: TemplateType.EMAIL, - name: 'template-name', - message: 'template-message', - }, - { - templateType: TemplateType.SMS, - name: 'template-name', - message: 'template-message', - }, - { - templateType: TemplateType.NHS_APP, - name: 'template-name', + ...NHS_APP_TEMPLATE, message: undefined as unknown as string, }, { - templateType: TemplateType.NHS_APP, + ...NHS_APP_TEMPLATE, name: undefined as unknown as string, - message: 'template-message', }, { - templateType: TemplateType.NHS_APP, + ...NHS_APP_TEMPLATE, name: null as unknown as string, message: null as unknown as string, }, ])( 'should redirect to invalid-template when template is $templateType and name is $nhsAppTemplateName and message is $nhsAppTemplateMessage', async (value) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - ...value, - createdAt: 'today', - updatedAt: 'today', - }); + getTemplateMock.mockResolvedValueOnce(value); await SubmitNhsAppTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/app/submit-text-message-template/page.test.tsx b/frontend/src/__tests__/app/submit-text-message-template/page.test.tsx index ea05dc09f..e8497024c 100644 --- a/frontend/src/__tests__/app/submit-text-message-template/page.test.tsx +++ b/frontend/src/__tests__/app/submit-text-message-template/page.test.tsx @@ -5,10 +5,13 @@ import SubmitSmsTemplatePage from '@app/submit-text-message-template/[templateId import { SubmitTemplate } from '@forms/SubmitTemplate/SubmitTemplate'; import { redirect } from 'next/navigation'; import { getTemplate } from '@utils/form-actions'; +import { TemplateDto } from 'nhs-notify-backend-client'; import { - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; + EMAIL_TEMPLATE, + LETTER_TEMPLATE, + NHS_APP_TEMPLATE, + SMS_TEMPLATE, +} from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -23,11 +26,11 @@ describe('SubmitSmsTemplatePage', () => { test('should load page', async () => { const state = { id: 'template-id', - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', message: 'template-message', - }; + } satisfies Partial; getTemplateMock.mockResolvedValue({ ...state, @@ -64,41 +67,26 @@ describe('SubmitSmsTemplatePage', () => { }); test.each([ + EMAIL_TEMPLATE, + NHS_APP_TEMPLATE, + LETTER_TEMPLATE, { - templateType: TemplateType.EMAIL, - name: 'template-name', - message: 'template-message', - }, - { - templateType: TemplateType.NHS_APP, - name: 'template-name', - message: 'template-message', - }, - { - templateType: TemplateType.SMS, - name: 'template-name', + ...SMS_TEMPLATE, message: undefined as unknown as string, }, { - templateType: TemplateType.SMS, + ...SMS_TEMPLATE, name: undefined as unknown as string, - message: 'template-message', }, { - templateType: TemplateType.SMS, + ...SMS_TEMPLATE, name: null as unknown as string, message: null as unknown as string, }, ])( 'should redirect to invalid-template when template is $templateType and name is $smsTemplateName and message is $smsTemplateMessage', async (value) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - ...value, - createdAt: 'today', - updatedAt: 'today', - }); + getTemplateMock.mockResolvedValueOnce(value); await SubmitSmsTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/app/text-message-template-submitted/page.test.tsx b/frontend/src/__tests__/app/text-message-template-submitted/page.test.tsx index f1b9c1287..87abc8b56 100644 --- a/frontend/src/__tests__/app/text-message-template-submitted/page.test.tsx +++ b/frontend/src/__tests__/app/text-message-template-submitted/page.test.tsx @@ -2,13 +2,10 @@ * @jest-environment node */ import SmsTemplateSubmittedPage from '@app/text-message-template-submitted/[templateId]/page'; -import { - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; import { TemplateSubmitted } from '@molecules/TemplateSubmitted/TemplateSubmitted'; import { getTemplate } from '@utils/form-actions'; import { redirect } from 'next/navigation'; +import { TemplateDto } from 'nhs-notify-backend-client'; jest.mock('@molecules/TemplateSubmitted/TemplateSubmitted'); jest.mock('@utils/form-actions'); @@ -23,11 +20,11 @@ describe('TextMessageTemplateSubmittedPage', () => { test('should load page', async () => { const template = { id: 'template-id', - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'SMS', + templateStatus: 'SUBMITTED', name: 'template-name', message: 'example', - }; + } satisfies Partial; getTemplateMock.mockResolvedValueOnce({ ...template, diff --git a/frontend/src/__tests__/app/view-submitted-email-template/page.test.tsx b/frontend/src/__tests__/app/view-submitted-email-template/page.test.tsx index ea892172f..f6b10929d 100644 --- a/frontend/src/__tests__/app/view-submitted-email-template/page.test.tsx +++ b/frontend/src/__tests__/app/view-submitted-email-template/page.test.tsx @@ -3,14 +3,11 @@ */ import ViewSubmittedEmailTemplatePage from '@app/view-submitted-email-template/[templateId]/page'; import { ViewEmailTemplate } from '@molecules/ViewEmailTemplate/ViewEmailTemplate'; -import { - EmailTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { EmailTemplate } from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect } from 'next/navigation'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { EMAIL_TEMPLATE, NHS_APP_TEMPLATE, SMS_TEMPLATE } from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -24,20 +21,20 @@ describe('ViewSubmittedEmailTemplatePage', () => { it('should load page', async () => { const templateDTO = { id: 'template-id', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'SUBMITTED', name: 'template-name', subject: 'template-subject-line', message: 'template-message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - } satisfies TemplateDTO; + } satisfies TemplateDto; const submittedEmailTemplate: EmailTemplate = { ...templateDTO, subject: 'template-subject-line', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'SUBMITTED', }; getTemplateMock.mockResolvedValueOnce(templateDTO); @@ -65,63 +62,41 @@ describe('ViewSubmittedEmailTemplatePage', () => { test.each([ { - templateType: TemplateType.SMS, - name: 'template-name', - subject: 'template-subject-line', - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + ...SMS_TEMPLATE, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.NHS_APP, - name: 'template-name', - subject: 'template-subject-line', - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + ...NHS_APP_TEMPLATE, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.EMAIL, + ...EMAIL_TEMPLATE, name: undefined as unknown as string, - subject: 'template-subject-line', - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.EMAIL, - name: 'template-name', + ...EMAIL_TEMPLATE, subject: undefined as unknown as string, - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.EMAIL, - name: 'template-name', - subject: 'template-subject-line', + ...EMAIL_TEMPLATE, message: undefined as unknown as string, - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.EMAIL, - name: 'template-name', - subject: 'template-subject-line', + ...EMAIL_TEMPLATE, message: null as unknown as string, - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.EMAIL, - name: 'template-name', - subject: 'template-subject-line', - message: 'template-message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + ...EMAIL_TEMPLATE, + templateStatus: 'NOT_YET_SUBMITTED' as const, }, ])( 'should redirect to invalid-template when template is $templateType, name is $name, subjectLine is $subject, message is $message, and status is $templateStatus', async (value) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - ...value, - createdAt: '2025-01-13T10:19:25.579Z', - updatedAt: '2025-01-13T10:19:25.579Z', - }); + getTemplateMock.mockResolvedValueOnce(value); await ViewSubmittedEmailTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/app/view-submitted-nhs-app-template/page.test.tsx b/frontend/src/__tests__/app/view-submitted-nhs-app-template/page.test.tsx index 9a0eb2e8f..42cb877e3 100644 --- a/frontend/src/__tests__/app/view-submitted-nhs-app-template/page.test.tsx +++ b/frontend/src/__tests__/app/view-submitted-nhs-app-template/page.test.tsx @@ -3,14 +3,11 @@ */ import ViewSubmittedNHSAppTemplatePage from '@app/view-submitted-nhs-app-template/[templateId]/page'; import { ViewNHSAppTemplate } from '@molecules/ViewNHSAppTemplate/ViewNHSAppTemplate'; -import { - NHSAppTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { NHSAppTemplate } from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect } from 'next/navigation'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { EMAIL_TEMPLATE, NHS_APP_TEMPLATE, SMS_TEMPLATE } from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -24,18 +21,18 @@ describe('ViewSubmittedNHSAppTemplatePage', () => { it('should load page', async () => { const templateDTO = { id: 'template-id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'SUBMITTED', name: 'template-name', message: 'template-message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - } satisfies TemplateDTO; + } satisfies TemplateDto; const submittedNHSAppTemplate: NHSAppTemplate = { ...templateDTO, - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'SUBMITTED', }; getTemplateMock.mockResolvedValueOnce(templateDTO); @@ -63,56 +60,45 @@ describe('ViewSubmittedNHSAppTemplatePage', () => { test.each([ { - templateType: TemplateType.EMAIL, - name: 'template-name', - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + ...EMAIL_TEMPLATE, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.SMS, - name: 'template-name', - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + ...SMS_TEMPLATE, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.NHS_APP, - name: 'template-name', + ...NHS_APP_TEMPLATE, message: undefined as unknown as string, - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.NHS_APP, + ...NHS_APP_TEMPLATE, name: undefined as unknown as string, - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.NHS_APP, + ...NHS_APP_TEMPLATE, name: null as unknown as string, message: null as unknown as string, - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.NHS_APP, + ...NHS_APP_TEMPLATE, name: null as unknown as string, message: null as unknown as string, - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.NHS_APP, + ...NHS_APP_TEMPLATE, name: 'template-name', message: 'template-message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED' as const, }, ])( 'should redirect to invalid-template when template is $templateType, name is $name, message is $message, and status is $templateStatus', async (value) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - ...value, - createdAt: '2025-01-13T10:19:25.579Z', - updatedAt: '2025-01-13T10:19:25.579Z', - }); + getTemplateMock.mockResolvedValueOnce(value); await ViewSubmittedNHSAppTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/app/view-submitted-text-message-template/page.test.tsx b/frontend/src/__tests__/app/view-submitted-text-message-template/page.test.tsx index 23f843834..e78628e85 100644 --- a/frontend/src/__tests__/app/view-submitted-text-message-template/page.test.tsx +++ b/frontend/src/__tests__/app/view-submitted-text-message-template/page.test.tsx @@ -3,14 +3,11 @@ */ import ViewSubmittedSMSTemplatePage from '@app/view-submitted-text-message-template/[templateId]/page'; import { ViewSMSTemplate } from '@molecules/ViewSMSTemplate/ViewSMSTemplate'; -import { - SMSTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { SMSTemplate } from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect } from 'next/navigation'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; +import { EMAIL_TEMPLATE, NHS_APP_TEMPLATE, SMS_TEMPLATE } from '../../helpers'; jest.mock('@utils/form-actions'); jest.mock('next/navigation'); @@ -24,18 +21,18 @@ describe('ViewSubmittedSMSTemplatePage', () => { it('should load page', async () => { const templateDTO = { id: 'template-id', - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'SMS', + templateStatus: 'SUBMITTED', name: 'template-name', message: 'template-message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - } satisfies TemplateDTO; + } satisfies TemplateDto; const submittedSMSTemplate: SMSTemplate = { ...templateDTO, - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'SMS', + templateStatus: 'SUBMITTED', }; getTemplateMock.mockResolvedValueOnce(templateDTO); @@ -63,50 +60,37 @@ describe('ViewSubmittedSMSTemplatePage', () => { test.each([ { - templateType: TemplateType.EMAIL, - name: 'template-name', - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + ...EMAIL_TEMPLATE, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.NHS_APP, - name: 'template-name', - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + ...NHS_APP_TEMPLATE, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.SMS, - name: 'template-name', + ...SMS_TEMPLATE, message: undefined as unknown as string, - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.SMS, + ...SMS_TEMPLATE, name: undefined as unknown as string, - message: 'template-message', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.SMS, + ...SMS_TEMPLATE, name: null as unknown as string, message: null as unknown as string, - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED' as const, }, { - templateType: TemplateType.SMS, - name: 'template-name', - message: 'template-message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + ...SMS_TEMPLATE, + templateStatus: 'NOT_YET_SUBMITTED' as const, }, ])( 'should redirect to invalid-template when template is $templateType, name is $name, message is $message, and status is $templateStatus', async (value) => { - getTemplateMock.mockResolvedValueOnce({ - id: 'template-id', - ...value, - createdAt: '2025-01-13T10:19:25.579Z', - updatedAt: '2025-01-13T10:19:25.579Z', - }); + getTemplateMock.mockResolvedValueOnce(value); await ViewSubmittedSMSTemplatePage({ params: Promise.resolve({ diff --git a/frontend/src/__tests__/components/forms/ChooseTemplate/ChooseTemplate.test.tsx b/frontend/src/__tests__/components/forms/ChooseTemplate/ChooseTemplate.test.tsx index 8d13fbb78..f9d7f0084 100644 --- a/frontend/src/__tests__/components/forms/ChooseTemplate/ChooseTemplate.test.tsx +++ b/frontend/src/__tests__/components/forms/ChooseTemplate/ChooseTemplate.test.tsx @@ -3,10 +3,8 @@ import { useActionState } from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import { ChooseTemplate } from '@forms/ChooseTemplate/ChooseTemplate'; -import { - TemplateFormState, - TemplateType, -} from 'nhs-notify-web-template-management-utils'; +import { TemplateFormState } from 'nhs-notify-web-template-management-utils'; +import { TEMPLATE_TYPE_LIST } from 'nhs-notify-backend-client'; jest.mock('@utils/amplify-utils'); @@ -32,7 +30,7 @@ jest.mock('react', () => { describe('Choose template page', () => { it('selects one radio button at a time', () => { const container = render( - + ); expect(container.asFragment()).toMatchSnapshot(); @@ -81,7 +79,7 @@ describe('Choose template page', () => { jest.mocked(useActionState).mockImplementation(mockUseActionState); const container = render( - + ); expect(container.asFragment()).toMatchSnapshot(); }); diff --git a/frontend/src/__tests__/components/forms/ChooseTemplate/server-action.test.ts b/frontend/src/__tests__/components/forms/ChooseTemplate/server-action.test.ts index 08913c8e3..d8bd7081b 100644 --- a/frontend/src/__tests__/components/forms/ChooseTemplate/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/ChooseTemplate/server-action.test.ts @@ -1,6 +1,5 @@ import { chooseTemplateAction } from '@forms/ChooseTemplate/server-action'; import { getMockFormData } from '@testhelpers'; -import { TemplateType } from 'nhs-notify-web-template-management-utils'; import { redirect, RedirectType } from 'next/navigation'; jest.mock('next/navigation'); @@ -32,7 +31,7 @@ test('submit form - no validation error', async () => { await chooseTemplateAction( {}, getMockFormData({ - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }) ); diff --git a/frontend/src/__tests__/components/forms/CopyTemplate/CopyTemplate.test.tsx b/frontend/src/__tests__/components/forms/CopyTemplate/CopyTemplate.test.tsx index a05ed77f5..4e8aa3bbf 100644 --- a/frontend/src/__tests__/components/forms/CopyTemplate/CopyTemplate.test.tsx +++ b/frontend/src/__tests__/components/forms/CopyTemplate/CopyTemplate.test.tsx @@ -3,11 +3,9 @@ import { useActionState } from 'react'; import { mockDeep } from 'jest-mock-extended'; import { render, screen, fireEvent } from '@testing-library/react'; -import { CopyTemplate } from '@forms/CopyTemplate/CopyTemplate'; -import { - Template, - TemplateFormState, -} from 'nhs-notify-web-template-management-utils'; +import { CopyTemplate, ValidCopyType } from '@forms/CopyTemplate/CopyTemplate'; +import { TemplateFormState } from 'nhs-notify-web-template-management-utils'; +import { ValidatedTemplateDto } from 'nhs-notify-backend-client'; jest.mock('@utils/amplify-utils'); @@ -32,7 +30,13 @@ jest.mock('react', () => { describe('Choose template page', () => { it('selects one radio button at a time', () => { - const container = render(()} />); + const container = render( + ()} + /> + ); expect(container.asFragment()).toMatchSnapshot(); const radioButtons = [ @@ -78,7 +82,13 @@ describe('Choose template page', () => { jest.mocked(useActionState).mockImplementation(mockUseActionState); - const container = render(()} />); + const container = render( + ()} + /> + ); expect(container.asFragment()).toMatchSnapshot(); }); }); diff --git a/frontend/src/__tests__/components/forms/CopyTemplate/server-action.test.ts b/frontend/src/__tests__/components/forms/CopyTemplate/server-action.test.ts index 38941e58e..2d13f33fe 100644 --- a/frontend/src/__tests__/components/forms/CopyTemplate/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/CopyTemplate/server-action.test.ts @@ -3,8 +3,6 @@ import { getMockFormData } from '@testhelpers'; import { EmailTemplate, NHSAppTemplate, - TemplateStatus, - TemplateType, } from 'nhs-notify-web-template-management-utils'; import { redirect, RedirectType } from 'next/navigation'; import { createTemplate } from '@utils/form-actions'; @@ -22,10 +20,12 @@ beforeAll(() => { test('submit form - validation error', async () => { const template: NHSAppTemplate = { id: 'template-id', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.NHS_APP, + templateStatus: 'NOT_YET_SUBMITTED', + templateType: 'NHS_APP', name: 'template-name', message: 'template-message', + createdAt: 'today', + updatedAt: 'today', }; const response = await copyTemplateAction( @@ -52,22 +52,24 @@ test('submit form - create email template from non-email template', async () => const mockRedirect = jest.mocked(redirect); const mockCreateTemplate = jest.mocked(createTemplate); - const testTemplate: Omit = { - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.NHS_APP, + const testTemplate: Omit = { + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', message: 'template-message', + createdAt: 'today', + updatedAt: 'today', }; await copyTemplateAction( { template: { ...testTemplate, + templateType: 'NHS_APP' as const, id: 'template-id', }, }, getMockFormData({ - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', }) ); @@ -77,10 +79,10 @@ test('submit form - create email template from non-email template', async () => ); expect(mockCreateTemplate).toHaveBeenCalledWith({ - ...testTemplate, + message: testTemplate.message, subject: 'Enter a subject line', name: 'COPY (2022-01-01 09:00:00): template-name', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', }); }); @@ -88,23 +90,25 @@ test('submit form - create email template from email template', async () => { const mockRedirect = jest.mocked(redirect); const mockCreateTemplate = jest.mocked(createTemplate); - const testTemplate: Omit = { - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.EMAIL, + const testTemplate: Omit = { + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', message: 'template-message', subject: 'template-subject', + createdAt: 'today', + updatedAt: 'today', }; await copyTemplateAction( { template: { ...testTemplate, + templateType: 'EMAIL', id: 'template-id', }, }, getMockFormData({ - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', }) ); @@ -114,9 +118,10 @@ test('submit form - create email template from email template', async () => { ); expect(mockCreateTemplate).toHaveBeenCalledWith({ - ...testTemplate, + message: testTemplate.message, + subject: testTemplate.subject, name: 'COPY (2022-01-01 09:00:00): template-name', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', }); }); @@ -124,22 +129,24 @@ test('submit form - create non-email template', async () => { const mockRedirect = jest.mocked(redirect); const mockCreateTemplate = jest.mocked(createTemplate); - const testTemplate: Omit = { - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.NHS_APP, + const testTemplate: Omit = { + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', message: 'template-message', + createdAt: 'today', + updatedAt: 'today', }; await copyTemplateAction( { template: { ...testTemplate, + templateType: 'NHS_APP', id: 'template-id', }, }, getMockFormData({ - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }) ); @@ -149,8 +156,8 @@ test('submit form - create non-email template', async () => { ); expect(mockCreateTemplate).toHaveBeenCalledWith({ - ...testTemplate, + message: testTemplate.message, name: 'COPY (2022-01-01 09:00:00): template-name', - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }); }); diff --git a/frontend/src/__tests__/components/forms/DeleteTemplate/server-action.test.ts b/frontend/src/__tests__/components/forms/DeleteTemplate/server-action.test.ts index b87c6da16..d5caaf22a 100644 --- a/frontend/src/__tests__/components/forms/DeleteTemplate/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/DeleteTemplate/server-action.test.ts @@ -3,11 +3,7 @@ import { deleteTemplateYesAction, deleteTemplateNoAction, } from '@forms/DeleteTemplate/server-action'; -import { - NHSAppTemplate, - TemplateStatus, - TemplateType, -} from 'nhs-notify-web-template-management-utils'; +import { NHSAppTemplate } from 'nhs-notify-web-template-management-utils'; import { saveTemplate } from '@utils/form-actions'; jest.mock('next/navigation'); @@ -37,15 +33,17 @@ test('calls form action and redirects', async () => { id: 'template-id', name: 'template-name', message: 'template-message', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', + createdAt: 'today', + updatedAt: 'today', }; await deleteTemplateYesAction(mockTemplate); expect(mockSaveTemplate).toHaveBeenCalledWith({ ...mockTemplate, - templateStatus: TemplateStatus.DELETED, + templateStatus: 'DELETED', }); expect(mockRedirect).toHaveBeenCalledWith( diff --git a/frontend/src/__tests__/components/forms/EmailTemplateForm/server-action.test.ts b/frontend/src/__tests__/components/forms/EmailTemplateForm/server-action.test.ts index 14c6f2095..9f4b08aaf 100644 --- a/frontend/src/__tests__/components/forms/EmailTemplateForm/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/EmailTemplateForm/server-action.test.ts @@ -1,10 +1,6 @@ import { getMockFormData } from '@testhelpers'; import { saveTemplate, createTemplate } from '@utils/form-actions'; -import { - EmailTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { EmailTemplate } from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { processFormActions } from '@forms/EmailTemplateForm/server-action'; import { MAX_EMAIL_CHARACTER_LENGTH } from '@utils/constants'; @@ -19,8 +15,8 @@ const redirectMock = jest.mocked(redirect); const initialState: EmailTemplate = { id: 'template-id', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', subject: 'subject', message: 'message', diff --git a/frontend/src/__tests__/components/forms/NhsAppTemplateForm/server-action.test.ts b/frontend/src/__tests__/components/forms/NhsAppTemplateForm/server-action.test.ts index b6f609398..058cc8998 100644 --- a/frontend/src/__tests__/components/forms/NhsAppTemplateForm/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/NhsAppTemplateForm/server-action.test.ts @@ -2,8 +2,7 @@ import { getMockFormData } from '@testhelpers'; import { saveTemplate, createTemplate } from '@utils/form-actions'; import { NHSAppTemplate, - TemplateType, - TemplateStatus, + CreateNHSAppTemplate, } from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { processFormActions } from '@forms/NhsAppTemplateForm/server-action'; @@ -16,12 +15,16 @@ const saveTemplateMock = jest.mocked(saveTemplate); const createTemplateMock = jest.mocked(createTemplate); const redirectMock = jest.mocked(redirect); -const initialState: NHSAppTemplate = { - id: 'template-id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, +const initialState: CreateNHSAppTemplate = { + templateType: 'NHS_APP', name: 'name', message: 'message', +}; + +const savedState: NHSAppTemplate = { + ...initialState, + id: 'template-id', + templateStatus: 'NOT_YET_SUBMITTED', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', }; @@ -70,15 +73,13 @@ describe('CreateNHSAppTemplate server actions', () => { test('should save the template and redirect', async () => { saveTemplateMock.mockResolvedValue({ - ...initialState, + ...savedState, name: 'template-name', message: 'template-message', - createdAt: '2025-01-13T10:19:25.579Z', - updatedAt: '2025-01-13T10:19:25.579Z', }); await processFormActions( - initialState, + savedState, getMockFormData({ nhsAppTemplateName: 'template-name', nhsAppTemplateMessage: 'template-message', @@ -86,7 +87,7 @@ describe('CreateNHSAppTemplate server actions', () => { ); expect(saveTemplateMock).toHaveBeenCalledWith({ - ...initialState, + ...savedState, name: 'template-name', message: 'template-message', }); @@ -98,19 +99,10 @@ describe('CreateNHSAppTemplate server actions', () => { }); test('should create the template and redirect', async () => { - const { id: _, ...initialDraftState } = initialState; // eslint-disable-line sonarjs/no-unused-vars - - createTemplateMock.mockResolvedValue({ - ...initialDraftState, - id: 'new-template-id', - name: 'template-name', - message: 'template-message', - createdAt: '2025-01-13T10:19:25.579Z', - updatedAt: '2025-01-13T10:19:25.579Z', - }); + createTemplateMock.mockResolvedValue(savedState); await processFormActions( - initialDraftState, + initialState, getMockFormData({ nhsAppTemplateName: 'template-name', nhsAppTemplateMessage: 'template-message', @@ -118,13 +110,13 @@ describe('CreateNHSAppTemplate server actions', () => { ); expect(createTemplateMock).toHaveBeenCalledWith({ - ...initialDraftState, + ...initialState, name: 'template-name', message: 'template-message', }); expect(redirectMock).toHaveBeenCalledWith( - '/preview-nhs-app-template/new-template-id?from=edit', + '/preview-nhs-app-template/template-id?from=edit', 'push' ); }); diff --git a/frontend/src/__tests__/components/forms/PreviewEmailTemplate/server-action.test.ts b/frontend/src/__tests__/components/forms/PreviewEmailTemplate/server-action.test.ts index 5df481861..f39f45aa2 100644 --- a/frontend/src/__tests__/components/forms/PreviewEmailTemplate/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/PreviewEmailTemplate/server-action.test.ts @@ -3,11 +3,7 @@ import { $FormSchema, } from '@forms/PreviewEmailTemplate'; import { redirect } from 'next/navigation'; -import { - EmailTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { EmailTemplate } from 'nhs-notify-web-template-management-utils'; import { getMockFormData } from '@testhelpers'; jest.mock('next/navigation'); @@ -16,11 +12,13 @@ const redirectMock = jest.mocked(redirect); const initialState: EmailTemplate = { id: 'template-id', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', subject: 'template-subject', message: 'template-message', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }; describe('previewEmailTemplateAction server action', () => { diff --git a/frontend/src/__tests__/components/forms/PreviewLetterTemplate/PreviewLetterTemplate.test.tsx b/frontend/src/__tests__/components/forms/PreviewLetterTemplate/PreviewLetterTemplate.test.tsx index da6f04fbd..4d53d54b3 100644 --- a/frontend/src/__tests__/components/forms/PreviewLetterTemplate/PreviewLetterTemplate.test.tsx +++ b/frontend/src/__tests__/components/forms/PreviewLetterTemplate/PreviewLetterTemplate.test.tsx @@ -8,11 +8,6 @@ import { } from 'nhs-notify-web-template-management-utils'; import { mockDeep } from 'jest-mock-extended'; import { useSearchParams } from 'next/navigation'; -import { - Language, - LetterType, - VirusScanStatus, -} from 'nhs-notify-backend-client'; jest.mock('@forms/PreviewLetterTemplate/server-actions'); @@ -45,13 +40,13 @@ describe('Preview letter form renders', () => { validationError: undefined, name: 'test-template-letter', id: 'template-id', - language: Language.EN, - letterType: LetterType.Q1, + language: 'en', + letterType: 'q1', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: '4C728B7D-A028-4BA2-B180-A63CDD2AE1E9', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, })} @@ -73,18 +68,18 @@ describe('Preview letter form renders', () => { validationError: undefined, name: 'test-template-letter', id: 'template-id', - language: Language.EN, - letterType: LetterType.Q1, + language: 'en', + letterType: 'q1', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: '4C728B7D-A028-4BA2-B180-A63CDD2AE1E9', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, testDataCsv: { fileName: 'test-data.csv', currentVersion: '622AB7FA-29BA-418A-B1B6-1E63FB299269', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, })} @@ -106,18 +101,18 @@ describe('Preview letter form renders', () => { }, name: 'test-template-letter', id: 'template-id', - language: Language.DE, - letterType: LetterType.X3, + language: 'de', + letterType: 'x3', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: '4C728B7D-A028-4BA2-B180-A63CDD2AE1E9', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, testDataCsv: { fileName: 'test-data.csv', currentVersion: '622AB7FA-29BA-418A-B1B6-1E63FB299269', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, })} @@ -134,18 +129,18 @@ describe('Preview letter form renders', () => { validationError: undefined, name: 'test-template-email', id: 'template-id', - language: Language.HI, - letterType: LetterType.X0, + language: 'hi', + letterType: 'x0', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: '4C728B7D-A028-4BA2-B180-A63CDD2AE1E9', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, testDataCsv: { fileName: 'test-data.csv', currentVersion: '622AB7FA-29BA-418A-B1B6-1E63FB299269', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, })} diff --git a/frontend/src/__tests__/components/forms/PreviewLetterTemplate/server-action.test.ts b/frontend/src/__tests__/components/forms/PreviewLetterTemplate/server-action.test.ts index 0ffe09408..16c709ffa 100644 --- a/frontend/src/__tests__/components/forms/PreviewLetterTemplate/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/PreviewLetterTemplate/server-action.test.ts @@ -3,17 +3,8 @@ import { previewLetterTemplateAction, } from '@forms/PreviewLetterTemplate'; import { redirect } from 'next/navigation'; -import { - TemplateType, - TemplateStatus, - LetterTemplate, -} from 'nhs-notify-web-template-management-utils'; +import { LetterTemplate } from 'nhs-notify-web-template-management-utils'; import { getMockFormData } from '@testhelpers'; -import { - Language, - LetterType, - VirusScanStatus, -} from 'nhs-notify-backend-client'; jest.mock('next/navigation'); @@ -21,23 +12,25 @@ const redirectMock = jest.mocked(redirect); const initialState: LetterTemplate = { id: 'template-id', - templateType: TemplateType.LETTER, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'LETTER', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', - language: Language.SQ, - letterType: LetterType.X0, + language: 'sq', + letterType: 'x0', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: '4C728B7D-A028-4BA2-B180-A63CDD2AE1E9', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, testDataCsv: { fileName: 'test-data.csv', currentVersion: '622AB7FA-29BA-418A-B1B6-1E63FB299269', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }; describe('previewLetterTemplateAction server action', () => { diff --git a/frontend/src/__tests__/components/forms/PreviewSMSTemplate/server-action.test.ts b/frontend/src/__tests__/components/forms/PreviewSMSTemplate/server-action.test.ts index 1ca19598a..471c52e66 100644 --- a/frontend/src/__tests__/components/forms/PreviewSMSTemplate/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/PreviewSMSTemplate/server-action.test.ts @@ -3,11 +3,7 @@ import { $FormSchema, } from '@forms/PreviewSMSTemplate'; import { redirect } from 'next/navigation'; -import { - SMSTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { SMSTemplate } from 'nhs-notify-web-template-management-utils'; import { getMockFormData } from '@testhelpers'; jest.mock('next/navigation'); @@ -16,10 +12,12 @@ const redirectMock = jest.mocked(redirect); const initialState: SMSTemplate = { id: 'template-id', - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', name: 'template-name', message: 'template-message', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }; describe('previewSmsTemplateAction server action', () => { diff --git a/frontend/src/__tests__/components/forms/ReviewNHSAppTemplate/server-action.test.ts b/frontend/src/__tests__/components/forms/ReviewNHSAppTemplate/server-action.test.ts index 46b236052..c7513e52d 100644 --- a/frontend/src/__tests__/components/forms/ReviewNHSAppTemplate/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/ReviewNHSAppTemplate/server-action.test.ts @@ -4,8 +4,6 @@ import { getMockFormData } from '@testhelpers'; import { NHSAppTemplate, TemplateFormState, - TemplateType, - TemplateStatus, } from 'nhs-notify-web-template-management-utils'; jest.mock('next/navigation'); @@ -15,11 +13,13 @@ const redirectMock = jest.mocked(redirect); describe('previewNhsAppTemplateAction', () => { const currentState: TemplateFormState = { id: 'template-id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'Example name', message: 'Example message', validationError: undefined, + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }; beforeEach(() => jest.clearAllMocks()); @@ -30,11 +30,7 @@ describe('previewNhsAppTemplateAction', () => { const newState = previewNhsAppTemplateAction(currentState, formData); expect(newState).toEqual({ - id: 'template-id', - templateType: 'NHS_APP', - templateStatus: 'NOT_YET_SUBMITTED', - name: 'Example name', - message: 'Example message', + ...currentState, validationError: { fieldErrors: { previewNHSAppTemplateAction: ['Select an option'], diff --git a/frontend/src/__tests__/components/forms/SmsTemplateForm/SmsTemplateForm.test.tsx b/frontend/src/__tests__/components/forms/SmsTemplateForm/SmsTemplateForm.test.tsx index 108bd37e4..d6ebf95b9 100644 --- a/frontend/src/__tests__/components/forms/SmsTemplateForm/SmsTemplateForm.test.tsx +++ b/frontend/src/__tests__/components/forms/SmsTemplateForm/SmsTemplateForm.test.tsx @@ -4,7 +4,7 @@ import { mockDeep } from 'jest-mock-extended'; import { TemplateFormState, SMSTemplate, - Draft, + CreateSMSTemplate, } from 'nhs-notify-web-template-management-utils'; import { SmsTemplateForm } from '@forms/SmsTemplateForm/SmsTemplateForm'; @@ -29,7 +29,7 @@ describe('CreateSmsTemplate component', () => { test('renders page with back link if initial state has no id - edit mode', async () => { const container = render( >>({ + initialState={mockDeep>({ validationError: undefined, name: 'template-name', message: 'template-message', diff --git a/frontend/src/__tests__/components/forms/SmsTemplateForm/server-action.test.ts b/frontend/src/__tests__/components/forms/SmsTemplateForm/server-action.test.ts index 7d95954fa..fc8c4b5b3 100644 --- a/frontend/src/__tests__/components/forms/SmsTemplateForm/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/SmsTemplateForm/server-action.test.ts @@ -1,13 +1,9 @@ import { getMockFormData } from '@testhelpers'; import { saveTemplate, createTemplate } from '@utils/form-actions'; -import { - SMSTemplate, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { SMSTemplate } from 'nhs-notify-web-template-management-utils'; import { redirect } from 'next/navigation'; import { processFormActions } from '@forms/SmsTemplateForm/server-action'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; jest.mock('@utils/amplify-utils'); jest.mock('@utils/form-actions'); @@ -19,8 +15,8 @@ const redirectMock = jest.mocked(redirect); const initialState: SMSTemplate = { id: 'template-id', - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', createdAt: '2025-01-13T10:19:25.579Z', @@ -74,7 +70,7 @@ describe('CreateSmsTemplate server actions', () => { ...initialState, name: 'template-name', message: 'template-message', - } as TemplateDTO); + } as TemplateDto); await processFormActions( initialState, @@ -104,7 +100,7 @@ describe('CreateSmsTemplate server actions', () => { id: 'new-template-id', name: 'template-name', message: 'template-message', - } as TemplateDTO); + } as TemplateDto); await processFormActions( initialDraftState, diff --git a/frontend/src/__tests__/components/forms/SubmitTemplate/server-action.test.ts b/frontend/src/__tests__/components/forms/SubmitTemplate/server-action.test.ts index d950b4e0b..5dc6ce688 100644 --- a/frontend/src/__tests__/components/forms/SubmitTemplate/server-action.test.ts +++ b/frontend/src/__tests__/components/forms/SubmitTemplate/server-action.test.ts @@ -5,11 +5,7 @@ import { submitTemplate } from '@forms/SubmitTemplate/server-action'; import { getMockFormData } from '@testhelpers'; import { redirect } from 'next/navigation'; import { getTemplate, saveTemplate } from '@utils/form-actions'; -import { - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; -import { TemplateDTO } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; jest.mock('next/navigation'); jest.mock('@utils/form-actions'); @@ -20,14 +16,14 @@ const getTemplateMock = jest.mocked(getTemplate); const saveTemplateMock = jest.mocked(saveTemplate); const mockNhsAppTemplate = { - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'body', id: '1', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', -}; +} satisfies TemplateDto; describe('submitTemplate', () => { beforeEach(jest.resetAllMocks); @@ -55,7 +51,7 @@ describe('submitTemplate', () => { it('should handle error when validating template', async () => { getTemplateMock.mockResolvedValueOnce({ id: 'template-id', - } as unknown as TemplateDTO); + } as unknown as TemplateDto); const formData = getMockFormData({ templateId: '1' }); diff --git a/frontend/src/__tests__/components/molecules/ChannelGuidance.test.tsx b/frontend/src/__tests__/components/molecules/ChannelGuidance.test.tsx index cf596968e..237075d67 100644 --- a/frontend/src/__tests__/components/molecules/ChannelGuidance.test.tsx +++ b/frontend/src/__tests__/components/molecules/ChannelGuidance.test.tsx @@ -1,18 +1,12 @@ import { render } from '@testing-library/react'; import { ChannelGuidance } from '@molecules/ChannelGuidance/ChannelGuidance'; -import { TemplateType } from 'nhs-notify-web-template-management-utils'; +import { TEMPLATE_TYPE_LIST } from 'nhs-notify-backend-client'; describe('ChannelGuidance component', () => { - const templateTypes = Object.values(TemplateType); - - it.each(templateTypes)( + it.each(TEMPLATE_TYPE_LIST)( 'should correctly render the component for templateType %s', - (templateType: string) => { - const templateTypeToUse = templateType as TemplateType; - - const container = render( - - ); + (templateType) => { + const container = render(); expect(container.asFragment()).toMatchSnapshot(); } diff --git a/frontend/src/__tests__/components/molecules/ManageTemplates.test.tsx b/frontend/src/__tests__/components/molecules/ManageTemplates.test.tsx index 1bde1b567..c11406f7c 100644 --- a/frontend/src/__tests__/components/molecules/ManageTemplates.test.tsx +++ b/frontend/src/__tests__/components/molecules/ManageTemplates.test.tsx @@ -1,45 +1,46 @@ import { render, screen } from '@testing-library/react'; import { ManageTemplates } from '@molecules/ManageTemplates/ManageTemplates'; -import { - TemplateStatus, - TemplateType, -} from 'nhs-notify-web-template-management-utils'; import content from '@content/content'; -import { LetterType, Language } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; const manageTemplatesContent = content.pages.manageTemplates; -const manageTemplatesProps = { +const manageTemplatesProps: { + templateList: TemplateDto[]; +} = { templateList: [ { id: '1', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'Template 1', message: 'Message', - subject: 'Subject Line', createdAt: '2021-01-01T00:00:00.000Z', updatedAt: '2021-01-01T00:00:00.000Z', }, { id: '2', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'SUBMITTED', name: 'Template 2', message: 'Message', - subject: 'Subject Line', createdAt: '2021-02-01T00:00:00.000Z', updatedAt: '2021-02-01T00:00:00.000Z', }, { id: '3', - templateType: TemplateType.LETTER, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'LETTER', + templateStatus: 'SUBMITTED', name: 'Template 3', createdAt: '2021-02-01T00:00:00.000Z', - letterType: LetterType.X0, - language: Language.FR, + letterType: 'x0', + language: 'fr', updatedAt: '2021-02-01T00:00:00.000Z', + files: { + pdfTemplate: { + fileName: 'template.pdf', + }, + }, }, ], }; @@ -51,8 +52,7 @@ describe('ManageTemplates component', () => { expect(container.asFragment()).toMatchSnapshot(); }); it('matches snapshot with submitted status', () => { - manageTemplatesProps.templateList[0].templateStatus = - TemplateStatus.SUBMITTED; + manageTemplatesProps.templateList[0].templateStatus = 'SUBMITTED'; const container = render(); expect(container.asFragment()).toMatchSnapshot(); diff --git a/frontend/src/__tests__/components/molecules/MessageFormatting.test.tsx b/frontend/src/__tests__/components/molecules/MessageFormatting.test.tsx index 4e77db1c2..f4abb8480 100644 --- a/frontend/src/__tests__/components/molecules/MessageFormatting.test.tsx +++ b/frontend/src/__tests__/components/molecules/MessageFormatting.test.tsx @@ -1,9 +1,8 @@ import { render, screen } from '@testing-library/react'; import { MessageFormatting } from '@molecules/MessageFormatting/MessageFormatting'; -import { TemplateType } from 'nhs-notify-web-template-management-utils'; const componentProps = { - template: TemplateType.SMS, + template: 'SMS' as const, }; describe('MessageFormatting component', () => { @@ -19,7 +18,7 @@ describe('MessageFormatting component', () => { it('renders component correctly with APP related formatting', () => { const appFormattingProps = { ...componentProps, - template: TemplateType.NHS_APP, + template: 'NHS_APP' as const, }; render(); @@ -37,7 +36,7 @@ describe('MessageFormatting component', () => { it('renders component correctly with EMAIL related formatting', () => { const emailFormattingProps = { ...componentProps, - template: TemplateType.EMAIL, + template: 'EMAIL' as const, }; render(); diff --git a/frontend/src/__tests__/components/molecules/PreviewTemplateDetails.test.tsx b/frontend/src/__tests__/components/molecules/PreviewTemplateDetails.test.tsx index c467ccea2..fa1ca0edf 100644 --- a/frontend/src/__tests__/components/molecules/PreviewTemplateDetails.test.tsx +++ b/frontend/src/__tests__/components/molecules/PreviewTemplateDetails.test.tsx @@ -1,14 +1,5 @@ import { render, screen } from '@testing-library/react'; import { PreviewTemplateDetails } from '@molecules/PreviewTemplateDetails'; -import { - TemplateStatus, - TemplateType, -} from 'nhs-notify-web-template-management-utils'; -import { - Language, - LetterType, - VirusScanStatus, -} from 'nhs-notify-backend-client'; describe('PreviewTemplateDetails component', () => { it('matches not yet submitted snapshot', () => { @@ -18,8 +9,10 @@ describe('PreviewTemplateDetails component', () => { id: 'template-id', name: 'Example template', message: 'app message message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.NHS_APP, + templateStatus: 'NOT_YET_SUBMITTED', + templateType: 'NHS_APP', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }} templateTypeText='Channel template' contentPreview={[ @@ -41,9 +34,11 @@ describe('PreviewTemplateDetails component', () => { template={{ id: 'template-id', name: 'Example template', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.SMS, + templateStatus: 'SUBMITTED', + templateType: 'SMS', message: 'text message message', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }} templateTypeText='Channel template' contentPreview={[ @@ -65,22 +60,24 @@ describe('PreviewTemplateDetails component', () => { template={{ id: 'template-id', name: 'Example template', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.LETTER, - letterType: LetterType.X0, - language: Language.FR, + templateStatus: 'SUBMITTED', + templateType: 'LETTER', + letterType: 'x0', + language: 'fr', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: '4C728B7D-A028-4BA2-B180-A63CDD2AE1E9', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, testDataCsv: { fileName: 'file.csv', currentVersion: '622AB7FA-29BA-418A-B1B6-1E63FB299269', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }} additionalMetaFields={[ { @@ -102,17 +99,19 @@ describe('PreviewTemplateDetails component', () => { template={{ id: 'template-id', name: 'Example template', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.LETTER, - letterType: LetterType.X0, - language: Language.FR, + templateStatus: 'SUBMITTED', + templateType: 'LETTER', + letterType: 'x0', + language: 'fr', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: '4C728B7D-A028-4BA2-B180-A63CDD2AE1E9', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }} /> ); @@ -127,8 +126,10 @@ describe('PreviewTemplateDetails component', () => { id: 'template-id', name: 'Example template', message: 'app message message', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }} templateTypeText='Channel template' contentPreview={[ diff --git a/frontend/src/__tests__/components/molecules/TemplateNameGuidance.test.tsx b/frontend/src/__tests__/components/molecules/TemplateNameGuidance.test.tsx index a0f4f7c93..ad5504c21 100644 --- a/frontend/src/__tests__/components/molecules/TemplateNameGuidance.test.tsx +++ b/frontend/src/__tests__/components/molecules/TemplateNameGuidance.test.tsx @@ -1,30 +1,25 @@ import { render } from '@testing-library/react'; import { TemplateNameGuidance } from '@molecules/TemplateNameGuidance'; -import { TemplateType } from 'nhs-notify-web-template-management-utils'; import content from '@content/content'; +import { TEMPLATE_TYPE_LIST } from 'nhs-notify-backend-client'; describe('TemplateNameGuidance component', () => { - const templateTypes = Object.keys(TemplateType); - it('renders component correctly as TemplateNameGuidance', () => { - const container = render( - - ); + const container = render(); expect(container.asFragment()).toMatchSnapshot(); }); - it.each(templateTypes)( + it.each(TEMPLATE_TYPE_LIST)( 'should correctly display the template naming example when templateType is %s', - (templateType: string) => { - const templateTypeToUse = templateType as TemplateType; + (templateType) => { const expectedText = content.components.nameYourTemplate.templateNameDetailsExample[ - templateTypeToUse + templateType ]; const container = render( - + ); expect( diff --git a/frontend/src/__tests__/components/molecules/ViewEmailTemplate.test.tsx b/frontend/src/__tests__/components/molecules/ViewEmailTemplate.test.tsx index 66c04d74b..72774590c 100644 --- a/frontend/src/__tests__/components/molecules/ViewEmailTemplate.test.tsx +++ b/frontend/src/__tests__/components/molecules/ViewEmailTemplate.test.tsx @@ -1,9 +1,6 @@ import { render } from '@testing-library/react'; import { ViewEmailTemplate } from '@molecules/ViewEmailTemplate/ViewEmailTemplate'; -import { - EmailTemplate, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { EmailTemplate } from 'nhs-notify-web-template-management-utils'; describe('ViewEmailTemplate component', () => { it('matches submitted snapshot', () => { @@ -13,7 +10,7 @@ describe('ViewEmailTemplate component', () => { { id: 'template-id', name: 'Example template', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED', subject: 'Example subject', message: 'Example message', } as EmailTemplate diff --git a/frontend/src/__tests__/components/molecules/ViewNHSAppTemplate.test.tsx b/frontend/src/__tests__/components/molecules/ViewNHSAppTemplate.test.tsx index 730b38568..14d25e032 100644 --- a/frontend/src/__tests__/components/molecules/ViewNHSAppTemplate.test.tsx +++ b/frontend/src/__tests__/components/molecules/ViewNHSAppTemplate.test.tsx @@ -1,9 +1,6 @@ import { render } from '@testing-library/react'; import { ViewNHSAppTemplate } from '@molecules/ViewNHSAppTemplate/ViewNHSAppTemplate'; -import { - NHSAppTemplate, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { NHSAppTemplate } from 'nhs-notify-web-template-management-utils'; describe('ViewNHSAppTemplate component', () => { it('matches submitted snapshot', () => { @@ -13,7 +10,7 @@ describe('ViewNHSAppTemplate component', () => { { id: 'template-id', name: 'Example template', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED', message: 'Example message', } as NHSAppTemplate } diff --git a/frontend/src/__tests__/components/molecules/ViewSMSTemplate.test.tsx b/frontend/src/__tests__/components/molecules/ViewSMSTemplate.test.tsx index 3a854c282..1ffec6fc5 100644 --- a/frontend/src/__tests__/components/molecules/ViewSMSTemplate.test.tsx +++ b/frontend/src/__tests__/components/molecules/ViewSMSTemplate.test.tsx @@ -1,9 +1,6 @@ import { render } from '@testing-library/react'; import { ViewSMSTemplate } from '@molecules/ViewSMSTemplate/ViewSMSTemplate'; -import { - SMSTemplate, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { SMSTemplate } from 'nhs-notify-web-template-management-utils'; describe('ViewNHSAppTemplate component', () => { it('matches submitted snapshot', () => { @@ -13,7 +10,7 @@ describe('ViewNHSAppTemplate component', () => { { id: 'template-id', name: 'Example template', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED', message: 'Example message', } as SMSTemplate } diff --git a/frontend/src/__tests__/helpers.ts b/frontend/src/__tests__/helpers.ts index 5994144d9..58741e371 100644 --- a/frontend/src/__tests__/helpers.ts +++ b/frontend/src/__tests__/helpers.ts @@ -1,4 +1,5 @@ import { mockDeep } from 'jest-mock-extended'; +import { TemplateDto } from 'nhs-notify-backend-client'; function* iteratorFromList(list: T[]): IterableIterator { for (const item of list) { @@ -15,3 +16,50 @@ export const getMockFormData = (formData: Record) => }), get: (key: string) => formData[key], }); + +export const NHS_APP_TEMPLATE: TemplateDto = { + id: 'template-id', + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', + name: 'name', + message: 'message', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', +} as const; + +export const EMAIL_TEMPLATE: TemplateDto = { + id: 'template-id', + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', + name: 'name', + message: 'message', + subject: 'subject', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', +} as const; + +export const SMS_TEMPLATE: TemplateDto = { + id: 'template-id', + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', + name: 'name', + message: 'message', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', +} as const; + +export const LETTER_TEMPLATE: TemplateDto = { + id: 'template-id', + templateType: 'LETTER', + templateStatus: 'NOT_YET_SUBMITTED', + letterType: 'x0', + language: 'en', + files: { + pdfTemplate: { + fileName: 'template.pdf', + }, + }, + name: 'name', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', +} as const; diff --git a/frontend/src/__tests__/utils/form-actions.test.ts b/frontend/src/__tests__/utils/form-actions.test.ts index 5ea5dca0d..5ed2bae33 100644 --- a/frontend/src/__tests__/utils/form-actions.test.ts +++ b/frontend/src/__tests__/utils/form-actions.test.ts @@ -2,10 +2,8 @@ * @jest-environment node */ import { + CreateNHSAppTemplate, NHSAppTemplate, - Draft, - TemplateType, - TemplateStatus, } from 'nhs-notify-web-template-management-utils'; import { createTemplate, @@ -15,7 +13,7 @@ import { } from '@utils/form-actions'; import { getAccessTokenServer } from '@utils/amplify-utils'; import { mockDeep } from 'jest-mock-extended'; -import { ITemplateClient } from 'nhs-notify-backend-client'; +import { ITemplateClient, TemplateDto } from 'nhs-notify-backend-client'; const mockedTemplateClient = mockDeep(); const authIdTokenServerMock = jest.mocked(getAccessTokenServer); @@ -34,22 +32,20 @@ describe('form-actions', () => { test('createTemplate', async () => { const responseData = { id: 'id', - version: 1, - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - }; + } satisfies TemplateDto; mockedTemplateClient.createTemplate.mockResolvedValueOnce({ data: responseData, }); - const createTemplateInput: Draft = { - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + const createTemplateInput: CreateNHSAppTemplate = { + templateType: 'NHS_APP', name: 'name', message: 'message', }; @@ -71,9 +67,8 @@ describe('form-actions', () => { }, }); - const createTemplateInput: Draft = { - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + const createTemplateInput: CreateNHSAppTemplate = { + templateType: 'NHS_APP', name: 'name', message: 'message', }; @@ -91,9 +86,8 @@ describe('form-actions', () => { authIdTokenServerMock.mockReset(); authIdTokenServerMock.mockResolvedValueOnce(undefined); - const createTemplateInput: Draft = { - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + const createTemplateInput: CreateNHSAppTemplate = { + templateType: 'NHS_APP', name: 'name', message: 'message', }; @@ -106,13 +100,13 @@ describe('form-actions', () => { test('saveTemplate', async () => { const responseData = { id: 'id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - }; + } satisfies TemplateDto; mockedTemplateClient.updateTemplate.mockResolvedValueOnce({ data: responseData, @@ -120,10 +114,12 @@ describe('form-actions', () => { const updateTemplateInput: NHSAppTemplate = { id: 'pickle', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }; const response = await saveTemplate(updateTemplateInput); @@ -146,10 +142,12 @@ describe('form-actions', () => { const updateTemplateInput: NHSAppTemplate = { id: 'pickle', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }; await expect(saveTemplate(updateTemplateInput)).rejects.toThrow( @@ -168,10 +166,12 @@ describe('form-actions', () => { const updateTemplateInput: NHSAppTemplate = { id: 'pickle', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', }; await expect(saveTemplate(updateTemplateInput)).rejects.toThrow( @@ -182,13 +182,13 @@ describe('form-actions', () => { test('getTemplate', async () => { const responseData = { id: 'id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - }; + } satisfies TemplateDto; mockedTemplateClient.getTemplate.mockResolvedValueOnce({ data: responseData, @@ -229,13 +229,13 @@ describe('form-actions', () => { test('getTemplates', async () => { const responseData = { id: 'id', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', name: 'name', message: 'message', createdAt: '2025-01-13T10:19:25.579Z', updatedAt: '2025-01-13T10:19:25.579Z', - }; + } satisfies TemplateDto; mockedTemplateClient.listTemplates.mockResolvedValueOnce({ data: [responseData], @@ -271,41 +271,26 @@ describe('form-actions', () => { test('getTemplates - order by createdAt and then id', async () => { const baseTemplate = { - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', name: 'Template', message: 'Message', updatedAt: '2021-01-01T00:00:00.000Z', - }; + } satisfies Partial; const templates = [ { ...baseTemplate, id: '06', createdAt: '2022-01-01T00:00:00.000Z' }, { ...baseTemplate, id: '08', createdAt: '2020-01-01T00:00:00.000Z' }, { ...baseTemplate, id: '05', createdAt: '2021-01-01T00:00:00.000Z' }, { ...baseTemplate, id: '02', createdAt: '2021-01-01T00:00:00.000Z' }, - { ...baseTemplate, id: '09', createdAt: '' }, - { ...baseTemplate, id: '10', createdAt: '' }, { ...baseTemplate, id: '01', createdAt: '2021-01-01T00:00:00.000Z' }, - { ...baseTemplate, id: '07', createdAt: '' }, { ...baseTemplate, id: '03', createdAt: '2021-01-01T00:00:00.000Z' }, { ...baseTemplate, id: '04', createdAt: '2021-01-01T00:00:00.000Z' }, ]; // 06 is the newest, 08 is the oldest. - // Templates without a createdAt, 07, 09 and 10, go at the end. // 01 - 05 all have the same createdAt. - const expectedOrder = [ - '06', - '01', - '02', - '03', - '04', - '05', - '08', - '07', - '09', - '10', - ]; + const expectedOrder = ['06', '01', '02', '03', '04', '05', '08']; mockedTemplateClient.listTemplates.mockResolvedValueOnce({ data: templates, diff --git a/frontend/src/app/choose-a-template-type/page.tsx b/frontend/src/app/choose-a-template-type/page.tsx index 782a7f088..d1fb8e69b 100644 --- a/frontend/src/app/choose-a-template-type/page.tsx +++ b/frontend/src/app/choose-a-template-type/page.tsx @@ -1,13 +1,11 @@ 'use server'; import { ChooseTemplate } from '@forms/ChooseTemplate/ChooseTemplate'; -import { TemplateType } from 'nhs-notify-backend-client'; +import { TEMPLATE_TYPE_LIST } from 'nhs-notify-backend-client'; const ChooseATemplateTypePage = async () => { - const templateTypes = Object.values(TemplateType).filter( - (t) => - process.env.NEXT_PUBLIC_ENABLE_LETTERS === 'true' || - t !== TemplateType.LETTER + const templateTypes = TEMPLATE_TYPE_LIST.filter( + (t) => process.env.NEXT_PUBLIC_ENABLE_LETTERS === 'true' || t !== 'LETTER' ); return ; diff --git a/frontend/src/app/copy-template/[templateId]/page.tsx b/frontend/src/app/copy-template/[templateId]/page.tsx index 4e4b81459..8f60a2de6 100644 --- a/frontend/src/app/copy-template/[templateId]/page.tsx +++ b/frontend/src/app/copy-template/[templateId]/page.tsx @@ -2,16 +2,16 @@ import { redirect, RedirectType } from 'next/navigation'; import { CopyTemplate } from '@forms/CopyTemplate/CopyTemplate'; -import { PageProps, $Template } from 'nhs-notify-web-template-management-utils'; +import { PageProps } from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; -import { zodValidate } from '@utils/validate-template'; +import { isTemplateDtoValid } from 'nhs-notify-backend-client'; const CopyTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; const template = await getTemplate(templateId); - const validatedTemplate = zodValidate($Template, template); + const validatedTemplate = isTemplateDtoValid(template); if (!validatedTemplate) { return redirect('/invalid-template', RedirectType.replace); diff --git a/frontend/src/app/create-email-template/page.tsx b/frontend/src/app/create-email-template/page.tsx index 05b10ec24..7a9a0f56e 100644 --- a/frontend/src/app/create-email-template/page.tsx +++ b/frontend/src/app/create-email-template/page.tsx @@ -1,15 +1,9 @@ import { EmailTemplateForm } from '@forms/EmailTemplateForm/EmailTemplateForm'; -import { - EmailTemplate, - Draft, - TemplateStatus, - TemplateType, -} from 'nhs-notify-web-template-management-utils'; +import { CreateEmailTemplate } from 'nhs-notify-web-template-management-utils'; const CreateEmailTemplatePage = async () => { - const initialState: Draft = { - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + const initialState: CreateEmailTemplate = { + templateType: 'EMAIL', name: '', subject: '', message: '', diff --git a/frontend/src/app/create-nhs-app-template/page.tsx b/frontend/src/app/create-nhs-app-template/page.tsx index b86cfd98d..14059251d 100644 --- a/frontend/src/app/create-nhs-app-template/page.tsx +++ b/frontend/src/app/create-nhs-app-template/page.tsx @@ -1,15 +1,9 @@ import { NhsAppTemplateForm } from '@forms/NhsAppTemplateForm/NhsAppTemplateForm'; -import { - NHSAppTemplate, - Draft, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { CreateNHSAppTemplate } from 'nhs-notify-web-template-management-utils'; const CreateNHSAppTemplatePage = async () => { - const initialState: Draft = { - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + const initialState: CreateNHSAppTemplate = { + templateType: 'NHS_APP', name: '', message: '', }; diff --git a/frontend/src/app/create-text-message-template/page.tsx b/frontend/src/app/create-text-message-template/page.tsx index f24296c33..683cfdd46 100644 --- a/frontend/src/app/create-text-message-template/page.tsx +++ b/frontend/src/app/create-text-message-template/page.tsx @@ -1,15 +1,9 @@ import { SmsTemplateForm } from '@forms/SmsTemplateForm/SmsTemplateForm'; -import { - SMSTemplate, - Draft, - TemplateType, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; +import { CreateSMSTemplate } from 'nhs-notify-web-template-management-utils'; const CreateSMSTemplatePage = async () => { - const initialState: Draft = { - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + const initialState: CreateSMSTemplate = { + templateType: 'SMS', name: '', message: '', }; diff --git a/frontend/src/app/delete-template/[templateId]/page.tsx b/frontend/src/app/delete-template/[templateId]/page.tsx index 4cc208d28..247bc288d 100644 --- a/frontend/src/app/delete-template/[templateId]/page.tsx +++ b/frontend/src/app/delete-template/[templateId]/page.tsx @@ -2,19 +2,18 @@ import { PageProps, - TemplateStatus, + validateNonSubmittedTemplate, } from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; import { DeleteTemplate } from '@forms/DeleteTemplate/DeleteTemplate'; -import { validateNonSubmittedTemplate } from '@utils/validate-template'; const DeleteTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; const template = await getTemplate(templateId); - if (template?.templateStatus === TemplateStatus.DELETED) { + if (template?.templateStatus === 'DELETED') { return redirect('/manage-templates', RedirectType.push); } diff --git a/frontend/src/app/edit-email-template/[templateId]/page.tsx b/frontend/src/app/edit-email-template/[templateId]/page.tsx index b3934bc72..754b73b8f 100644 --- a/frontend/src/app/edit-email-template/[templateId]/page.tsx +++ b/frontend/src/app/edit-email-template/[templateId]/page.tsx @@ -1,8 +1,10 @@ import { EmailTemplateForm } from '@forms/EmailTemplateForm/EmailTemplateForm'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateEmailTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; -import { validateEmailTemplate } from '@utils/validate-template'; const CreateEmailTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/edit-nhs-app-template/[templateId]/page.tsx b/frontend/src/app/edit-nhs-app-template/[templateId]/page.tsx index 91fc2c18a..40d8c61fb 100644 --- a/frontend/src/app/edit-nhs-app-template/[templateId]/page.tsx +++ b/frontend/src/app/edit-nhs-app-template/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; import { NhsAppTemplateForm } from '@forms/NhsAppTemplateForm/NhsAppTemplateForm'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateNHSAppTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; -import { validateNHSAppTemplate } from '@utils/validate-template'; const CreateNhsAppTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/edit-text-message-template/[templateId]/page.tsx b/frontend/src/app/edit-text-message-template/[templateId]/page.tsx index 215c31fcb..ed5be7886 100644 --- a/frontend/src/app/edit-text-message-template/[templateId]/page.tsx +++ b/frontend/src/app/edit-text-message-template/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; import { SmsTemplateForm } from '@forms/SmsTemplateForm/SmsTemplateForm'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateSMSTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; -import { validateSMSTemplate } from '@utils/validate-template'; const CreateSmsTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/email-template-submitted/[templateId]/page.tsx b/frontend/src/app/email-template-submitted/[templateId]/page.tsx index b8cf49ccc..df3a66fc7 100644 --- a/frontend/src/app/email-template-submitted/[templateId]/page.tsx +++ b/frontend/src/app/email-template-submitted/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; import { TemplateSubmitted } from '@molecules/TemplateSubmitted/TemplateSubmitted'; -import { TemplateSubmittedPageProps } from 'nhs-notify-web-template-management-utils'; +import { + TemplateSubmittedPageProps, + validateSubmittedEmailTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; -import { validateSubmittedEmailTemplate } from '@utils/validate-template'; const EmailTemplateSubmittedPage = async ( props: TemplateSubmittedPageProps diff --git a/frontend/src/app/nhs-app-template-submitted/[templateId]/page.tsx b/frontend/src/app/nhs-app-template-submitted/[templateId]/page.tsx index f6b845c51..80bb86f59 100644 --- a/frontend/src/app/nhs-app-template-submitted/[templateId]/page.tsx +++ b/frontend/src/app/nhs-app-template-submitted/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; import { TemplateSubmitted } from '@molecules/TemplateSubmitted/TemplateSubmitted'; -import { TemplateSubmittedPageProps } from 'nhs-notify-web-template-management-utils'; +import { + TemplateSubmittedPageProps, + validateSubmittedNHSAppTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; -import { validateSubmittedNHSAppTemplate } from '@utils/validate-template'; const NhsAppTemplateSubmittedPage = async ( props: TemplateSubmittedPageProps diff --git a/frontend/src/app/preview-email-template/[templateId]/page.tsx b/frontend/src/app/preview-email-template/[templateId]/page.tsx index 5b029e624..da91b193b 100644 --- a/frontend/src/app/preview-email-template/[templateId]/page.tsx +++ b/frontend/src/app/preview-email-template/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateEmailTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; import { PreviewEmailTemplate } from '@forms/PreviewEmailTemplate'; -import { validateEmailTemplate } from '@utils/validate-template'; const PreviewEmailTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/preview-letter-template/[templateId]/page.tsx b/frontend/src/app/preview-letter-template/[templateId]/page.tsx index 44938c8bc..fb8bd97de 100644 --- a/frontend/src/app/preview-letter-template/[templateId]/page.tsx +++ b/frontend/src/app/preview-letter-template/[templateId]/page.tsx @@ -1,9 +1,11 @@ 'use server'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateLetterTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; -import { validateLetterTemplate } from '@utils/validate-template'; import { PreviewLetterTemplate } from '@forms/PreviewLetterTemplate/PreviewLetterTemplate'; const PreviewLetterTemplatePage = async (props: PageProps) => { diff --git a/frontend/src/app/preview-nhs-app-template/[templateId]/page.tsx b/frontend/src/app/preview-nhs-app-template/[templateId]/page.tsx index eab789cc0..7529c1703 100644 --- a/frontend/src/app/preview-nhs-app-template/[templateId]/page.tsx +++ b/frontend/src/app/preview-nhs-app-template/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; import { PreviewNHSAppTemplate } from '@forms/PreviewNHSAppTemplate/PreviewNHSAppTemplate'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateNHSAppTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; -import { validateNHSAppTemplate } from '@utils/validate-template'; const PreviewNhsAppTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/preview-text-message-template/[templateId]/page.tsx b/frontend/src/app/preview-text-message-template/[templateId]/page.tsx index bfadf7d38..6d21f8bd4 100644 --- a/frontend/src/app/preview-text-message-template/[templateId]/page.tsx +++ b/frontend/src/app/preview-text-message-template/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateSMSTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; import { PreviewSMSTemplate } from '@forms/PreviewSMSTemplate'; -import { validateSMSTemplate } from '@utils/validate-template'; const PreviewSMSTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/submit-email-template/[templateId]/page.tsx b/frontend/src/app/submit-email-template/[templateId]/page.tsx index efc8e0d77..9ce3b04b9 100644 --- a/frontend/src/app/submit-email-template/[templateId]/page.tsx +++ b/frontend/src/app/submit-email-template/[templateId]/page.tsx @@ -2,9 +2,11 @@ import { redirect, RedirectType } from 'next/navigation'; import { SubmitTemplate } from '@forms/SubmitTemplate/SubmitTemplate'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateEmailTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; -import { validateEmailTemplate } from '@utils/validate-template'; const SubmitEmailTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/submit-nhs-app-template/[templateId]/page.tsx b/frontend/src/app/submit-nhs-app-template/[templateId]/page.tsx index 55afb74b6..c959a989e 100644 --- a/frontend/src/app/submit-nhs-app-template/[templateId]/page.tsx +++ b/frontend/src/app/submit-nhs-app-template/[templateId]/page.tsx @@ -2,9 +2,11 @@ import { redirect, RedirectType } from 'next/navigation'; import { SubmitTemplate } from '@forms/SubmitTemplate/SubmitTemplate'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateNHSAppTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; -import { validateNHSAppTemplate } from '@utils/validate-template'; const SubmitNhsAppTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/submit-text-message-template/[templateId]/page.tsx b/frontend/src/app/submit-text-message-template/[templateId]/page.tsx index eb3d0125b..548845b94 100644 --- a/frontend/src/app/submit-text-message-template/[templateId]/page.tsx +++ b/frontend/src/app/submit-text-message-template/[templateId]/page.tsx @@ -2,9 +2,11 @@ import { redirect, RedirectType } from 'next/navigation'; import { SubmitTemplate } from '@forms/SubmitTemplate/SubmitTemplate'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateSMSTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; -import { validateSMSTemplate } from '@utils/validate-template'; const SubmitSmsTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/text-message-template-submitted/[templateId]/page.tsx b/frontend/src/app/text-message-template-submitted/[templateId]/page.tsx index 1a81f4960..9dbde9e4a 100644 --- a/frontend/src/app/text-message-template-submitted/[templateId]/page.tsx +++ b/frontend/src/app/text-message-template-submitted/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; import { TemplateSubmitted } from '@molecules/TemplateSubmitted/TemplateSubmitted'; -import { TemplateSubmittedPageProps } from 'nhs-notify-web-template-management-utils'; +import { + TemplateSubmittedPageProps, + validateSubmittedSMSTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; -import { validateSubmittedSMSTemplate } from '@utils/validate-template'; const SmsTemplateSubmittedPage = async (props: TemplateSubmittedPageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/view-submitted-email-template/[templateId]/page.tsx b/frontend/src/app/view-submitted-email-template/[templateId]/page.tsx index d59c6c778..8ad5dc67f 100644 --- a/frontend/src/app/view-submitted-email-template/[templateId]/page.tsx +++ b/frontend/src/app/view-submitted-email-template/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateSubmittedEmailTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; import { ViewEmailTemplate } from '@molecules/ViewEmailTemplate/ViewEmailTemplate'; -import { validateSubmittedEmailTemplate } from '@utils/validate-template'; const ViewSubmittedEmailTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/app/view-submitted-nhs-app-template/[templateId]/page.tsx b/frontend/src/app/view-submitted-nhs-app-template/[templateId]/page.tsx index e3edee785..1f03c0df3 100644 --- a/frontend/src/app/view-submitted-nhs-app-template/[templateId]/page.tsx +++ b/frontend/src/app/view-submitted-nhs-app-template/[templateId]/page.tsx @@ -1,9 +1,11 @@ 'use server'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateSubmittedNHSAppTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; -import { validateSubmittedNHSAppTemplate } from '@utils/validate-template'; import { ViewNHSAppTemplate } from '@molecules/ViewNHSAppTemplate/ViewNHSAppTemplate'; const ViewSubmittedNHSAppTemplatePage = async (props: PageProps) => { diff --git a/frontend/src/app/view-submitted-text-message-template/[templateId]/page.tsx b/frontend/src/app/view-submitted-text-message-template/[templateId]/page.tsx index 12543303a..b997ae570 100644 --- a/frontend/src/app/view-submitted-text-message-template/[templateId]/page.tsx +++ b/frontend/src/app/view-submitted-text-message-template/[templateId]/page.tsx @@ -1,10 +1,12 @@ 'use server'; -import { PageProps } from 'nhs-notify-web-template-management-utils'; +import { + PageProps, + validateSubmittedSMSTemplate, +} from 'nhs-notify-web-template-management-utils'; import { getTemplate } from '@utils/form-actions'; import { redirect, RedirectType } from 'next/navigation'; import { ViewSMSTemplate } from '@molecules/ViewSMSTemplate/ViewSMSTemplate'; -import { validateSubmittedSMSTemplate } from '@utils/validate-template'; const ViewSubmittedSMSTemplatePage = async (props: PageProps) => { const { templateId } = await props.params; diff --git a/frontend/src/components/forms/ChooseTemplate/ChooseTemplate.tsx b/frontend/src/components/forms/ChooseTemplate/ChooseTemplate.tsx index 161d964ab..39978a848 100644 --- a/frontend/src/components/forms/ChooseTemplate/ChooseTemplate.tsx +++ b/frontend/src/components/forms/ChooseTemplate/ChooseTemplate.tsx @@ -6,12 +6,10 @@ import { NHSNotifyRadioButtonForm } from '@molecules/NHSNotifyRadioButtonForm/NH import { ZodErrorSummary } from '@molecules/ZodErrorSummary/ZodErrorSummary'; import { getBasePath } from '@utils/get-base-path'; import content from '@content/content'; -import { - TemplateType, - templateTypeDisplayMappings, -} from 'nhs-notify-web-template-management-utils'; +import { templateTypeDisplayMappings } from 'nhs-notify-web-template-management-utils'; import { NHSNotifyMain } from '@atoms/NHSNotifyMain/NHSNotifyMain'; import { chooseTemplateAction } from './server-action'; +import { TemplateType } from 'nhs-notify-backend-client'; export const ChooseTemplate = ({ templateTypes, diff --git a/frontend/src/components/forms/ChooseTemplate/server-action.ts b/frontend/src/components/forms/ChooseTemplate/server-action.ts index 3deeac1a9..ed7150970 100644 --- a/frontend/src/components/forms/ChooseTemplate/server-action.ts +++ b/frontend/src/components/forms/ChooseTemplate/server-action.ts @@ -1,13 +1,13 @@ import { redirect, RedirectType } from 'next/navigation'; +import { TEMPLATE_TYPE_LIST } from 'nhs-notify-backend-client'; import { FormState, - TemplateType, templateTypeToUrlTextMappings, } from 'nhs-notify-web-template-management-utils'; import { z } from 'zod'; const $ChooseTemplate = z.object({ - templateType: z.nativeEnum(TemplateType, { + templateType: z.enum(TEMPLATE_TYPE_LIST, { message: 'Select a template type', }), }); diff --git a/frontend/src/components/forms/CopyTemplate/CopyTemplate.tsx b/frontend/src/components/forms/CopyTemplate/CopyTemplate.tsx index 82c99d321..a57a68fba 100644 --- a/frontend/src/components/forms/CopyTemplate/CopyTemplate.tsx +++ b/frontend/src/components/forms/CopyTemplate/CopyTemplate.tsx @@ -5,27 +5,24 @@ import { BackLink } from 'nhsuk-react-components'; import { NHSNotifyRadioButtonForm } from '@molecules/NHSNotifyRadioButtonForm/NHSNotifyRadioButtonForm'; import { ZodErrorSummary } from '@molecules/ZodErrorSummary/ZodErrorSummary'; import content from '@content/content'; -import { - Template, - TemplateType, - templateTypeDisplayMappings, -} from 'nhs-notify-web-template-management-utils'; +import { templateTypeDisplayMappings } from 'nhs-notify-web-template-management-utils'; import { getBasePath } from '@utils/get-base-path'; import { NHSNotifyMain } from '@atoms/NHSNotifyMain/NHSNotifyMain'; import { copyTemplateAction } from './server-action'; +import { TemplateType, ValidatedTemplateDto } from 'nhs-notify-backend-client'; + +export type ValidCopyType = Exclude; type CopyTemplate = { - template: Template; + template: ValidatedTemplateDto & { templateType: ValidCopyType }; }; export const CopyTemplate = ({ template }: CopyTemplate) => { + const copyTypes = ['NHS_APP', 'EMAIL', 'SMS'] as const; + const [state, action] = useActionState(copyTemplateAction, { template }); - const options = [ - TemplateType.NHS_APP, - TemplateType.EMAIL, - TemplateType.SMS, - ].map((templateType) => ({ + const options = copyTypes.map((templateType) => ({ id: templateType, text: templateTypeDisplayMappings(templateType), })); diff --git a/frontend/src/components/forms/CopyTemplate/server-action.ts b/frontend/src/components/forms/CopyTemplate/server-action.ts index 771a97d6e..788045ba9 100644 --- a/frontend/src/components/forms/CopyTemplate/server-action.ts +++ b/frontend/src/components/forms/CopyTemplate/server-action.ts @@ -1,23 +1,26 @@ 'use server'; import { redirect, RedirectType } from 'next/navigation'; -import { - Template, - FormState, - TemplateType, -} from 'nhs-notify-web-template-management-utils'; +import { FormState } from 'nhs-notify-web-template-management-utils'; import { z } from 'zod'; import { createTemplate } from '@utils/form-actions'; import { format } from 'date-fns/format'; +import { + TEMPLATE_TYPE_LIST, + TemplateType, + ValidatedTemplateDto, +} from 'nhs-notify-backend-client'; const $CopyTemplate = z.object({ - templateType: z.nativeEnum(TemplateType, { + templateType: z.enum(TEMPLATE_TYPE_LIST, { message: 'Select a template type', }), }); type CopyTemplateActionState = FormState & { - template: Template; + template: ValidatedTemplateDto & { + templateType: Exclude; + }; }; type CopyTemplateAction = ( formState: CopyTemplateActionState, @@ -40,23 +43,37 @@ export const copyTemplateAction: CopyTemplateAction = async ( } const newTemplateType = parsedForm.data.templateType; - const { - name, - id: _1, - createdAt: _2, - ...baseTemplateAttributes - } = formState.template; - - await createTemplate({ - ...baseTemplateAttributes, - name: `COPY (${format(new Date(), 'yyyy-MM-dd HH:mm:ss')}): ${name}`, - templateType: newTemplateType, - ...(parsedForm.data.templateType === TemplateType.EMAIL && { - subject: - ('subject' in formState.template && formState.template.subject) || - 'Enter a subject line', - }), - }); + const { name, message } = formState.template; + const subject = + formState.template.templateType === 'EMAIL' + ? formState.template.subject + : 'Enter a subject line'; + + const copyName = `COPY (${format(new Date(), 'yyyy-MM-dd HH:mm:ss')}): ${name}`; + + switch (newTemplateType) { + case 'NHS_APP': + case 'SMS': { + await createTemplate({ + name: copyName, + message, + templateType: newTemplateType, + }); + + break; + } + case 'EMAIL': { + await createTemplate({ + name: copyName, + message, + templateType: newTemplateType, + subject, + }); + + break; + } + // no default + } return redirect(`/manage-templates`, RedirectType.push); }; diff --git a/frontend/src/components/forms/DeleteTemplate/DeleteTemplate.tsx b/frontend/src/components/forms/DeleteTemplate/DeleteTemplate.tsx index 5c8eb66ec..ff06ecbe9 100644 --- a/frontend/src/components/forms/DeleteTemplate/DeleteTemplate.tsx +++ b/frontend/src/components/forms/DeleteTemplate/DeleteTemplate.tsx @@ -1,7 +1,6 @@ 'use client'; import { FC, useActionState } from 'react'; -import { Template } from 'nhs-notify-web-template-management-utils'; import content from '@content/content'; import { NHSNotifyMain } from '@atoms/NHSNotifyMain/NHSNotifyMain'; import { NHSNotifyFormWrapper } from '@molecules/NHSNotifyFormWrapper/NHSNotifyFormWrapper'; @@ -11,9 +10,10 @@ import { deleteTemplateNoAction, } from './server-action'; import concatClassNames from '@utils/concat-class-names'; +import { TemplateDto } from 'nhs-notify-backend-client'; type DeleteTemplateProps = { - template: Template; + template: TemplateDto; }; export const DeleteTemplate: FC = ({ template }) => { diff --git a/frontend/src/components/forms/DeleteTemplate/server-action.ts b/frontend/src/components/forms/DeleteTemplate/server-action.ts index 52d6a798f..2e1448e46 100644 --- a/frontend/src/components/forms/DeleteTemplate/server-action.ts +++ b/frontend/src/components/forms/DeleteTemplate/server-action.ts @@ -1,20 +1,17 @@ import { redirect, RedirectType } from 'next/navigation'; -import { - Template, - TemplateStatus, -} from 'nhs-notify-web-template-management-utils'; import { saveTemplate } from '@utils/form-actions'; +import { TemplateDto } from 'nhs-notify-backend-client'; export const deleteTemplateNoAction = async () => { redirect('/manage-templates', RedirectType.push); }; export const deleteTemplateYesAction = async ( - template: Template + template: TemplateDto ): Promise => { await saveTemplate({ ...template, - templateStatus: TemplateStatus.DELETED, + templateStatus: 'DELETED', }); redirect('/manage-templates', RedirectType.push); diff --git a/frontend/src/components/forms/EmailTemplateForm/EmailTemplateForm.tsx b/frontend/src/components/forms/EmailTemplateForm/EmailTemplateForm.tsx index 53df66593..3ef860d72 100644 --- a/frontend/src/components/forms/EmailTemplateForm/EmailTemplateForm.tsx +++ b/frontend/src/components/forms/EmailTemplateForm/EmailTemplateForm.tsx @@ -16,10 +16,9 @@ import { TemplateNameGuidance } from '@molecules/TemplateNameGuidance'; import { Personalisation } from '@molecules/Personalisation/Personalisation'; import { MessageFormatting } from '@molecules/MessageFormatting/MessageFormatting'; import { - Draft, + CreateEmailTemplate, EmailTemplate, PageComponentProps, - TemplateType, } from 'nhs-notify-web-template-management-utils'; import content from '@content/content'; import { useTextInput } from '@hooks/use-text-input.hook'; @@ -28,7 +27,7 @@ import { NHSNotifyMain } from '@atoms/NHSNotifyMain/NHSNotifyMain'; import { NHSNotifyButton } from '@atoms/NHSNotifyButton/NHSNotifyButton'; export const EmailTemplateForm: FC< - PageComponentProps> + PageComponentProps > = ({ initialState }) => { const { pageHeadingSuffix, @@ -87,7 +86,7 @@ export const EmailTemplateForm: FC< {templateNameLabelText} {templateNameHintText} - + diff --git a/frontend/src/components/forms/EmailTemplateForm/server-action.ts b/frontend/src/components/forms/EmailTemplateForm/server-action.ts index ad470b4e4..eee27b4be 100644 --- a/frontend/src/components/forms/EmailTemplateForm/server-action.ts +++ b/frontend/src/components/forms/EmailTemplateForm/server-action.ts @@ -1,7 +1,7 @@ import { - TemplateFormState, + CreateEmailTemplate, EmailTemplate, - Draft, + TemplateFormState, } from 'nhs-notify-web-template-management-utils'; import { z } from 'zod'; import { createTemplate, saveTemplate } from '@utils/form-actions'; @@ -24,9 +24,9 @@ const $EmailTemplateFormSchema = z.object({ }); export async function processFormActions( - formState: TemplateFormState>, + formState: TemplateFormState, formData: FormData -): Promise>> { +): Promise> { const parsedForm = $EmailTemplateFormSchema.safeParse( Object.fromEntries(formData.entries()) ); diff --git a/frontend/src/components/forms/NhsAppTemplateForm/NhsAppTemplateForm.tsx b/frontend/src/components/forms/NhsAppTemplateForm/NhsAppTemplateForm.tsx index 6a186a797..e522a3fa1 100644 --- a/frontend/src/components/forms/NhsAppTemplateForm/NhsAppTemplateForm.tsx +++ b/frontend/src/components/forms/NhsAppTemplateForm/NhsAppTemplateForm.tsx @@ -16,10 +16,9 @@ import { TemplateNameGuidance } from '@molecules/TemplateNameGuidance'; import { Personalisation } from '@molecules/Personalisation/Personalisation'; import { MessageFormatting } from '@molecules/MessageFormatting/MessageFormatting'; import { - Draft, + CreateNHSAppTemplate, NHSAppTemplate, PageComponentProps, - TemplateType, } from 'nhs-notify-web-template-management-utils'; import content from '@content/content'; import { useTextInput } from '@hooks/use-text-input.hook'; @@ -29,7 +28,7 @@ import { NHSNotifyMain } from '@atoms/NHSNotifyMain/NHSNotifyMain'; import { NHSNotifyButton } from '@atoms/NHSNotifyButton/NHSNotifyButton'; export const NhsAppTemplateForm: FC< - PageComponentProps> + PageComponentProps > = ({ initialState }) => { const { pageHeadingSuffix, @@ -82,7 +81,7 @@ export const NhsAppTemplateForm: FC< {templateNameLabelText} {templateNameHintText} - + diff --git a/frontend/src/components/forms/NhsAppTemplateForm/server-action.ts b/frontend/src/components/forms/NhsAppTemplateForm/server-action.ts index 378434e87..0bfa715d2 100644 --- a/frontend/src/components/forms/NhsAppTemplateForm/server-action.ts +++ b/frontend/src/components/forms/NhsAppTemplateForm/server-action.ts @@ -1,7 +1,7 @@ import { TemplateFormState, NHSAppTemplate, - Draft, + CreateNHSAppTemplate, } from 'nhs-notify-web-template-management-utils'; import { z } from 'zod'; import { saveTemplate, createTemplate } from '@utils/form-actions'; @@ -18,9 +18,9 @@ const $CreateNhsAppTemplateSchema = z.object({ }); export async function processFormActions( - formState: TemplateFormState>, + formState: TemplateFormState, formData: FormData -): Promise>> { +): Promise> { const parsedForm = $CreateNhsAppTemplateSchema.safeParse( Object.fromEntries(formData.entries()) ); diff --git a/frontend/src/components/forms/SmsTemplateForm/SmsTemplateForm.tsx b/frontend/src/components/forms/SmsTemplateForm/SmsTemplateForm.tsx index 7f57ae7b6..6fec8b860 100644 --- a/frontend/src/components/forms/SmsTemplateForm/SmsTemplateForm.tsx +++ b/frontend/src/components/forms/SmsTemplateForm/SmsTemplateForm.tsx @@ -14,10 +14,9 @@ import { } from 'nhsuk-react-components'; import { getBasePath } from '@utils/get-base-path'; import { - Draft, + CreateSMSTemplate, PageComponentProps, SMSTemplate, - TemplateType, } from 'nhs-notify-web-template-management-utils'; import { FC, useActionState } from 'react'; import { ZodErrorSummary } from '@molecules/ZodErrorSummary/ZodErrorSummary'; @@ -31,7 +30,7 @@ import { processFormActions } from './server-action'; import { calculateHowManySmsMessages } from './view-actions'; export const SmsTemplateForm: FC< - PageComponentProps> + PageComponentProps > = ({ initialState }) => { const [state, action] = useActionState(processFormActions, initialState); @@ -135,8 +134,8 @@ export const SmsTemplateForm: FC< diff --git a/frontend/src/components/forms/SmsTemplateForm/server-action.ts b/frontend/src/components/forms/SmsTemplateForm/server-action.ts index f94514eed..59cfb84da 100644 --- a/frontend/src/components/forms/SmsTemplateForm/server-action.ts +++ b/frontend/src/components/forms/SmsTemplateForm/server-action.ts @@ -1,7 +1,7 @@ import { TemplateFormState, SMSTemplate, - Draft, + CreateSMSTemplate, } from 'nhs-notify-web-template-management-utils'; import { z } from 'zod'; import { saveTemplate, createTemplate } from '@utils/form-actions'; @@ -19,9 +19,9 @@ const $CreateSmsTemplateSchema = z.object({ }); export async function processFormActions( - formState: TemplateFormState>, + formState: TemplateFormState, formData: FormData -): Promise>> { +): Promise> { const parsedForm = $CreateSmsTemplateSchema.safeParse( Object.fromEntries(formData.entries()) ); diff --git a/frontend/src/components/forms/SubmitTemplate/server-action.ts b/frontend/src/components/forms/SubmitTemplate/server-action.ts index 72efb5ede..31f430075 100644 --- a/frontend/src/components/forms/SubmitTemplate/server-action.ts +++ b/frontend/src/components/forms/SubmitTemplate/server-action.ts @@ -3,8 +3,7 @@ import { redirect, RedirectType } from 'next/navigation'; import { getTemplate, saveTemplate } from '@utils/form-actions'; import { z } from 'zod'; -import { validateTemplate } from '@utils/validate-template'; -import { TemplateStatus } from 'nhs-notify-web-template-management-utils'; +import { validateTemplate } from 'nhs-notify-web-template-management-utils'; import { logger } from 'nhs-notify-web-template-management-utils/logger'; const $TemplateIdSchema = z.string(); @@ -29,7 +28,7 @@ export async function submitTemplate(route: string, formData: FormData) { try { await saveTemplate({ ...validatedTemplate, - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED', }); } catch (error) { logger.error('Failed to submit template', { diff --git a/frontend/src/components/molecules/ChannelGuidance/ChannelGuidance.tsx b/frontend/src/components/molecules/ChannelGuidance/ChannelGuidance.tsx index da8f80c0a..dc04cfb26 100644 --- a/frontend/src/components/molecules/ChannelGuidance/ChannelGuidance.tsx +++ b/frontend/src/components/molecules/ChannelGuidance/ChannelGuidance.tsx @@ -1,4 +1,4 @@ -import { TemplateType } from 'nhs-notify-web-template-management-utils'; +import { TemplateType } from 'nhs-notify-backend-client'; import styles from './ChannelGuidance.module.scss'; import content from '@content/content'; diff --git a/frontend/src/components/molecules/ManageTemplates/ManageTemplates.tsx b/frontend/src/components/molecules/ManageTemplates/ManageTemplates.tsx index c2d45adf2..532c18dea 100644 --- a/frontend/src/components/molecules/ManageTemplates/ManageTemplates.tsx +++ b/frontend/src/components/molecules/ManageTemplates/ManageTemplates.tsx @@ -9,25 +9,24 @@ import Link from 'next/link'; import { letterTypeDisplayMappings, previewTemplatePages, - TemplateStatus, templateStatusToDisplayMappings, templateTypeDisplayMappings, viewSubmittedTemplatePages, } from 'nhs-notify-web-template-management-utils'; -import { TemplateDTO, TemplateType } from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; const manageTemplatesContent = content.pages.manageTemplates; -const generateViewTemplateLink = (template: TemplateDTO): string => { - if (template.templateStatus === TemplateStatus.SUBMITTED) { +const generateViewTemplateLink = (template: TemplateDto): string => { + if (template.templateStatus === 'SUBMITTED') { return `/${viewSubmittedTemplatePages(template.templateType)}/${template.id}`; } return `/${previewTemplatePages(template.templateType)}/${template.id}`; }; -const typeDisplayMappings = (template: TemplateDTO): string => - template.templateType === TemplateType.LETTER && +const typeDisplayMappings = (template: TemplateDto): string => + template.templateType === 'LETTER' && 'letterType' in template && template.letterType && 'language' in template && @@ -38,7 +37,7 @@ const typeDisplayMappings = (template: TemplateDTO): string => export function ManageTemplates({ templateList, }: { - templateList: TemplateDTO[]; + templateList: TemplateDto[]; }) { return (
@@ -80,7 +79,7 @@ export function ManageTemplates({ - {template.templateType === TemplateType.LETTER ? null : ( + {template.templateType === 'LETTER' ? null : (

)} - {template.templateStatus === - TemplateStatus.NOT_YET_SUBMITTED ? ( + {template.templateStatus === 'NOT_YET_SUBMITTED' ? (

{manageTemplatesContent.tableHeadings.action.delete} diff --git a/frontend/src/components/molecules/MessageFormatting/MessageFormatting.tsx b/frontend/src/components/molecules/MessageFormatting/MessageFormatting.tsx index 1f27402c3..bfdd9047b 100644 --- a/frontend/src/components/molecules/MessageFormatting/MessageFormatting.tsx +++ b/frontend/src/components/molecules/MessageFormatting/MessageFormatting.tsx @@ -1,4 +1,3 @@ -import { TemplateType } from 'nhs-notify-web-template-management-utils'; import content from '@content/content'; import { BoldText, @@ -11,17 +10,18 @@ import { NumberedList, } from './formats'; import { JSX } from 'react'; +import { TemplateType } from 'nhs-notify-backend-client'; const messageFormattingContent = content.components.messageFormatting; const messageFormattingMap: Record = { - [TemplateType.NHS_APP]: [ + NHS_APP: [ LineBreaksAndParagraphs(), Headings(), BoldText(), LinksAndUrlsMarkdown(), ], - [TemplateType.EMAIL]: [ + EMAIL: [ LineBreaksAndParagraphs(), Headings(), BulletList(), @@ -29,8 +29,8 @@ const messageFormattingMap: Record = { HorizontalRule(), LinksAndUrlsMarkdown(), ], - [TemplateType.SMS]: [LinksAndUrlsNoMarkdown()], - [TemplateType.LETTER]: [], + SMS: [LinksAndUrlsNoMarkdown()], + LETTER: [], }; export function MessageFormatting({ template }: { template: TemplateType }) { diff --git a/frontend/src/components/molecules/PreviewTemplateDetails/PreviewTemplateDetails.tsx b/frontend/src/components/molecules/PreviewTemplateDetails/PreviewTemplateDetails.tsx index 68c3d3089..ff29772e1 100644 --- a/frontend/src/components/molecules/PreviewTemplateDetails/PreviewTemplateDetails.tsx +++ b/frontend/src/components/molecules/PreviewTemplateDetails/PreviewTemplateDetails.tsx @@ -6,7 +6,6 @@ import { type LetterTemplate, type SMSTemplate, NHSAppTemplate, - TemplateStatus, templateStatusToDisplayMappings, templateTypeDisplayMappings, } from 'nhs-notify-web-template-management-utils'; @@ -56,9 +55,7 @@ export function PreviewTemplateDetails({ {templateStatusToDisplayMappings(template.templateStatus)} diff --git a/frontend/src/components/molecules/PreviewTemplateDetails/preview-template-details.types.ts b/frontend/src/components/molecules/PreviewTemplateDetails/preview-template-details.types.ts index ee603c082..69bee8736 100644 --- a/frontend/src/components/molecules/PreviewTemplateDetails/preview-template-details.types.ts +++ b/frontend/src/components/molecules/PreviewTemplateDetails/preview-template-details.types.ts @@ -1,4 +1,4 @@ -import { Template } from 'nhs-notify-web-template-management-utils'; +import { TemplateDto } from 'nhs-notify-backend-client'; type PreviewTemplateHeadingsType = | 'Id' @@ -8,7 +8,7 @@ type PreviewTemplateHeadingsType = | 'Message'; export type PreviewTemplateDetailsProps = { - template: Template; + template: TemplateDto; templateTypeText: string; additionalMetaFields?: { title: string; diff --git a/frontend/src/components/molecules/TemplateNameGuidance/template-name-guidance.types.ts b/frontend/src/components/molecules/TemplateNameGuidance/template-name-guidance.types.ts index 2f920e1ba..d7e383ba3 100644 --- a/frontend/src/components/molecules/TemplateNameGuidance/template-name-guidance.types.ts +++ b/frontend/src/components/molecules/TemplateNameGuidance/template-name-guidance.types.ts @@ -1,5 +1,5 @@ -import { TemplateType } from 'nhs-notify-web-template-management-utils'; +import { TemplateType } from 'nhs-notify-backend-client'; export type TemplateNameGuidanceType = { - template: keyof typeof TemplateType; + template: TemplateType; }; diff --git a/frontend/src/components/organisms/PreviewTemplate/preview-template.types.ts b/frontend/src/components/organisms/PreviewTemplate/preview-template.types.ts index 47636bc20..0db36904a 100644 --- a/frontend/src/components/organisms/PreviewTemplate/preview-template.types.ts +++ b/frontend/src/components/organisms/PreviewTemplate/preview-template.types.ts @@ -1,10 +1,10 @@ import { PreviewTemplateDetails } from '@molecules/PreviewTemplateDetails/PreviewTemplateDetails'; import { NHSNotifyRadioButtonFormProps } from '@molecules/NHSNotifyRadioButtonForm/NHSNotifyRadioButtonForm'; -import { Template } from 'nhs-notify-web-template-management-utils'; +import { TemplateDto } from 'nhs-notify-backend-client'; export type PreviewTemplateProps = { sectionHeading: string | undefined; - template: Template; + template: TemplateDto; form: { errorHeading: string; } & NHSNotifyRadioButtonFormProps; diff --git a/frontend/src/content/content.ts b/frontend/src/content/content.ts index db63cc66e..e9232f39c 100644 --- a/frontend/src/content/content.ts +++ b/frontend/src/content/content.ts @@ -1,5 +1,4 @@ import { getBasePath } from '@utils/get-base-path'; -import { TemplateType } from 'nhs-notify-web-template-management-utils'; const header = { serviceName: 'Notify', @@ -359,15 +358,15 @@ const nameYourTemplate = { }, ], templateNameDetailsExample: { - [TemplateType.NHS_APP]: `For example, 'NHS App - covid19 2023 - over 65s - version 3'`, - [TemplateType.EMAIL]: `For example, 'Email - covid19 2023 - over 65s - version 3'`, - [TemplateType.SMS]: `For example, 'SMS - covid19 2023 - over 65s - version 3'`, - [TemplateType.LETTER]: `For example, 'LETTER - covid19 2023 - over 65s - version 3'`, + NHS_APP: `For example, 'NHS App - covid19 2023 - over 65s - version 3'`, + EMAIL: `For example, 'Email - covid19 2023 - over 65s - version 3'`, + SMS: `For example, 'SMS - covid19 2023 - over 65s - version 3'`, + LETTER: `For example, 'LETTER - covid19 2023 - over 65s - version 3'`, }, }; const channelGuidance = { - [TemplateType.NHS_APP]: { + NHS_APP: { heading: 'More about NHS App messages', guidanceLinks: [ { @@ -384,7 +383,7 @@ const channelGuidance = { }, ], }, - [TemplateType.EMAIL]: { + EMAIL: { heading: 'More about emails', guidanceLinks: [ { @@ -401,7 +400,7 @@ const channelGuidance = { }, ], }, - [TemplateType.SMS]: { + SMS: { heading: 'More about text messages', guidanceLinks: [ { @@ -418,7 +417,7 @@ const channelGuidance = { }, ], }, - [TemplateType.LETTER]: { + LETTER: { heading: 'More about letters', guidanceLinks: [], }, diff --git a/frontend/src/utils/form-actions.ts b/frontend/src/utils/form-actions.ts index 725df4379..b51c2ab6e 100644 --- a/frontend/src/utils/form-actions.ts +++ b/frontend/src/utils/form-actions.ts @@ -2,16 +2,17 @@ import { getAccessTokenServer } from '@utils/amplify-utils'; import { - Template, - isTemplateValid, -} from 'nhs-notify-web-template-management-utils'; -import { CreateTemplate, TemplateDTO } from 'nhs-notify-backend-client'; + CreateTemplate, + isTemplateDtoValid, + TemplateDto, + ValidatedTemplateDto, +} from 'nhs-notify-backend-client'; import { logger } from 'nhs-notify-web-template-management-utils/logger'; import { TemplateClient } from 'nhs-notify-backend-client/src/template-api-client'; export async function createTemplate( template: CreateTemplate -): Promise { +): Promise { const token = await getAccessTokenServer(); if (!token) { @@ -28,7 +29,9 @@ export async function createTemplate( return data; } -export async function saveTemplate(template: Template): Promise { +export async function saveTemplate( + template: TemplateDto +): Promise { const token = await getAccessTokenServer(); if (!token) { @@ -50,7 +53,7 @@ export async function saveTemplate(template: Template): Promise { export async function getTemplate( templateId: string -): Promise { +): Promise { const token = await getAccessTokenServer(); if (!token) { @@ -66,7 +69,7 @@ export async function getTemplate( return data; } -export async function getTemplates(): Promise { +export async function getTemplates(): Promise { const token = await getAccessTokenServer(); if (!token) { @@ -81,8 +84,10 @@ export async function getTemplates(): Promise { } const sortedData = data - .map((template) => isTemplateValid(template)) - .filter((template): template is TemplateDTO => template !== undefined) + .map((template) => isTemplateDtoValid(template)) + .filter( + (template): template is ValidatedTemplateDto => template !== undefined + ) .sort((a, b) => { const aCreatedAt = a.createdAt; const bCreatedAt = b.createdAt; diff --git a/frontend/src/utils/validate-template.ts b/frontend/src/utils/validate-template.ts deleted file mode 100644 index 43c712558..000000000 --- a/frontend/src/utils/validate-template.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { z } from 'zod'; -import { - $NHSAppTemplate, - $SMSTemplate, - $EmailTemplate, - $LetterTemplate, - $Template, - $NonSubmittedTemplate, - $SubmittedEmailTemplate, - $SubmittedNHSAppTemplate, - $SubmittedSMSTemplate, -} from 'nhs-notify-web-template-management-utils'; -import { TemplateDTO } from 'nhs-notify-backend-client'; -import { logger } from 'nhs-notify-web-template-management-utils/logger'; - -export const zodValidate = ( - schema: T, - obj: unknown -): z.infer | undefined => { - try { - return schema.parse(obj); - } catch (error) { - logger.error(error); - return undefined; - } -}; - -export const validateNHSAppTemplate = (template?: TemplateDTO) => - zodValidate($NHSAppTemplate, template); - -export const validateSMSTemplate = (template?: TemplateDTO) => - zodValidate($SMSTemplate, template); - -export const validateEmailTemplate = (template?: TemplateDTO) => - zodValidate($EmailTemplate, template); - -export const validateLetterTemplate = (template?: TemplateDTO) => - zodValidate($LetterTemplate, template); - -export const validateSubmittedEmailTemplate = (template?: TemplateDTO) => - zodValidate($SubmittedEmailTemplate, template); - -export const validateSubmittedSMSTemplate = (template?: TemplateDTO) => - zodValidate($SubmittedSMSTemplate, template); - -export const validateSubmittedNHSAppTemplate = (template?: TemplateDTO) => - zodValidate($SubmittedNHSAppTemplate, template); - -export const validateTemplate = (template?: TemplateDTO) => - zodValidate($Template, template); - -export const validateNonSubmittedTemplate = (template?: TemplateDTO) => - zodValidate($NonSubmittedTemplate, template); diff --git a/infrastructure/terraform/modules/backend-api/spec.tmpl.json b/infrastructure/terraform/modules/backend-api/spec.tmpl.json index 5d0ca227b..ff994e91d 100644 --- a/infrastructure/terraform/modules/backend-api/spec.tmpl.json +++ b/infrastructure/terraform/modules/backend-api/spec.tmpl.json @@ -282,54 +282,6 @@ } }, "schemas": { - "TemplateDTO": { - "type": "object", - "required": [ - "id", - "templateType", - "templateStatus", - "name", - "createdAt", - "updatedAt" - ], - "properties": { - "id": { - "type": "string" - }, - "templateType": { - "$ref": "#/components/schemas/TemplateType" - }, - "templateStatus": { - "$ref": "#/components/schemas/TemplateStatus" - }, - "letterType": { - "$ref": "#/components/schemas/LetterType" - }, - "language": { - "$ref": "#/components/schemas/Language" - }, - "files": { - "$ref": "#/components/schemas/Files" - }, - "name": { - "type": "string" - }, - "message": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "subject": { - "type": "string" - } - } - }, "TemplateType": { "type": "string", "enum": [ @@ -399,11 +351,10 @@ "PASSED" ] }, - "File": { + "FileDetails": { "type": "object", "required": [ - "fileName", - "virusScanStatus" + "fileName" ], "properties": { "fileName": { @@ -417,36 +368,44 @@ } } }, - "Files": { + "LetterFiles": { "type": "object", + "required": [ + "pdfTemplate" + ], "properties": { "pdfTemplate": { - "$ref": "#/components/schemas/File" + "$ref": "#/components/schemas/FileDetails" }, "testDataCsv": { - "$ref": "#/components/schemas/File" + "$ref": "#/components/schemas/FileDetails" }, "proofs": { "type": "array", "items": { - "$ref": "#/components/schemas/File" + "$ref": "#/components/schemas/FileDetails" } } } }, - "CreateTemplate": { + "NhsAppProperties": { "type": "object", "required": [ - "templateType", - "name" + "message" ], "properties": { - "templateType": { - "$ref": "#/components/schemas/TemplateType" - }, - "name": { + "message": { "type": "string" - }, + } + } + }, + "EmailProperties": { + "type": "object", + "required": [ + "message", + "subject" + ], + "properties": { "message": { "type": "string" }, @@ -455,33 +414,159 @@ } } }, - "UpdateTemplate": { + "SmsProperties": { "type": "object", "required": [ - "templateStatus", - "name", - "templateType" + "message" ], "properties": { - "templateStatus": { - "$ref": "#/components/schemas/TemplateStatus" - }, - "name": { - "type": "string" - }, "message": { "type": "string" + } + } + }, + "LetterProperties": { + "type": "object", + "required": [ + "letterType", + "language", + "files" + ], + "properties": { + "letterType": { + "$ref": "#/components/schemas/LetterType" }, - "subject": { - "type": "string" + "language": { + "$ref": "#/components/schemas/Language" }, + "files": { + "$ref": "#/components/schemas/LetterFiles" + } + } + }, + "BaseTemplate": { + "type": "object", + "required": [ + "templateType", + "name" + ], + "properties": { "templateType": { - "$ref": "#/components/schemas/TemplateType", - "readOnly": true, - "description": "This value will never be updated. It is used to determine the type of template being validated." + "$ref": "#/components/schemas/TemplateType" + }, + "name": { + "type": "string" } } }, + "CreateTemplate": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/BaseTemplate" + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/NhsAppProperties" + }, + { + "$ref": "#/components/schemas/EmailProperties" + }, + { + "$ref": "#/components/schemas/SmsProperties" + }, + { + "$ref": "#/components/schemas/LetterProperties" + } + ] + } + ] + }, + "UpdateTemplate": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/BaseTemplate" + }, + { + "type": "object", + "required": [ + "templateStatus" + ], + "properties": { + "templateStatus": { + "$ref": "#/components/schemas/TemplateStatus" + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/NhsAppProperties" + }, + { + "$ref": "#/components/schemas/EmailProperties" + }, + { + "$ref": "#/components/schemas/SmsProperties" + }, + { + "$ref": "#/components/schemas/LetterProperties" + } + ] + } + ] + }, + "TemplateDto": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/BaseTemplate" + }, + { + "type": "object", + "required": [ + "id", + "templateStatus", + "createdAt", + "updatedAt" + ], + "properties": { + "id": { + "type": "string" + }, + "templateStatus": { + "$ref": "#/components/schemas/TemplateStatus" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/NhsAppProperties" + }, + { + "$ref": "#/components/schemas/EmailProperties" + }, + { + "$ref": "#/components/schemas/SmsProperties" + }, + { + "$ref": "#/components/schemas/LetterProperties" + } + ] + } + ] + }, "Success": { "type": "object", "required": [ @@ -490,7 +575,7 @@ ], "properties": { "template": { - "$ref": "#/components/schemas/TemplateDTO" + "$ref": "#/components/schemas/TemplateDto" }, "statusCode": { "type": "integer" @@ -507,7 +592,7 @@ "templates": { "type": "array", "items": { - "$ref": "#/components/schemas/TemplateDTO" + "$ref": "#/components/schemas/TemplateDto" } }, "statusCode": { diff --git a/lambdas/backend-api/src/__tests__/templates/api/create.test.ts b/lambdas/backend-api/src/__tests__/templates/api/create.test.ts index 38fde3489..7eafb171b 100644 --- a/lambdas/backend-api/src/__tests__/templates/api/create.test.ts +++ b/lambdas/backend-api/src/__tests__/templates/api/create.test.ts @@ -1,11 +1,6 @@ import type { APIGatewayProxyEvent, Context } from 'aws-lambda'; import { mock } from 'jest-mock-extended'; -import { - TemplateDTO, - TemplateStatus, - TemplateType, - CreateTemplate, -} from 'nhs-notify-backend-client'; +import { TemplateDto, CreateTemplate } from 'nhs-notify-backend-client'; import { handler } from '@backend-api/templates/api/create'; import { TemplateClient } from '@backend-api/templates/app/template-client'; @@ -102,12 +97,12 @@ describe('Template API - Create', () => { const create: CreateTemplate = { name: 'updated-name', message: 'message', - templateType: TemplateType.SMS, + templateType: 'SMS', }; - const response: TemplateDTO = { + const response: TemplateDto = { ...create, id: 'id', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; diff --git a/lambdas/backend-api/src/__tests__/templates/api/get.test.ts b/lambdas/backend-api/src/__tests__/templates/api/get.test.ts index e6f340495..64dcce08c 100644 --- a/lambdas/backend-api/src/__tests__/templates/api/get.test.ts +++ b/lambdas/backend-api/src/__tests__/templates/api/get.test.ts @@ -1,10 +1,6 @@ import type { APIGatewayProxyEvent, Context } from 'aws-lambda'; import { mock } from 'jest-mock-extended'; -import { - TemplateDTO, - TemplateStatus, - TemplateType, -} from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; import { handler } from '@backend-api/templates/api/get'; import { TemplateClient } from '@backend-api/templates/app/template-client'; @@ -112,14 +108,15 @@ describe('Template API - Get', () => { }); test('should return template', async () => { - const template: TemplateDTO = { + const template: TemplateDto = { id: 'id', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', name: 'name', message: 'message', + subject: 'subject', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', }; getTemplateMock.mockResolvedValueOnce({ diff --git a/lambdas/backend-api/src/__tests__/templates/api/list.test.ts b/lambdas/backend-api/src/__tests__/templates/api/list.test.ts index 9d2cbf73b..1ddd439e1 100644 --- a/lambdas/backend-api/src/__tests__/templates/api/list.test.ts +++ b/lambdas/backend-api/src/__tests__/templates/api/list.test.ts @@ -1,10 +1,6 @@ import type { APIGatewayProxyEvent, Context } from 'aws-lambda'; import { mock } from 'jest-mock-extended'; -import { - TemplateDTO, - TemplateStatus, - TemplateType, -} from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; import { handler } from '@backend-api/templates/api/list'; import { TemplateClient } from '@backend-api/templates/app/template-client'; @@ -93,14 +89,15 @@ describe('Template API - List', () => { }); test('should return template', async () => { - const template: TemplateDTO = { + const template: TemplateDto = { id: 'id', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', name: 'name', message: 'message', + subject: 'subject', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', }; listTemplatesMock.mockResolvedValueOnce({ diff --git a/lambdas/backend-api/src/__tests__/templates/api/responses.test.ts b/lambdas/backend-api/src/__tests__/templates/api/responses.test.ts index f37c8e9fd..e4f7edda6 100644 --- a/lambdas/backend-api/src/__tests__/templates/api/responses.test.ts +++ b/lambdas/backend-api/src/__tests__/templates/api/responses.test.ts @@ -1,18 +1,15 @@ import { apiSuccess, apiFailure } from '@backend-api/templates/api/responses'; -import { - TemplateDTO, - TemplateStatus, - TemplateType, -} from 'nhs-notify-backend-client'; +import { TemplateDto } from 'nhs-notify-backend-client'; describe('responses', () => { it('should return success response', () => { - const dto: TemplateDTO = { + const dto: TemplateDto = { id: '1', name: 'name', message: 'message', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.EMAIL, + subject: 'subject', + templateStatus: 'SUBMITTED', + templateType: 'EMAIL', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; diff --git a/lambdas/backend-api/src/__tests__/templates/api/update.test.ts b/lambdas/backend-api/src/__tests__/templates/api/update.test.ts index 83f9765aa..59efea0ed 100644 --- a/lambdas/backend-api/src/__tests__/templates/api/update.test.ts +++ b/lambdas/backend-api/src/__tests__/templates/api/update.test.ts @@ -1,11 +1,6 @@ import type { APIGatewayProxyEvent, Context } from 'aws-lambda'; import { mock } from 'jest-mock-extended'; -import { - TemplateDTO, - TemplateStatus, - TemplateType, - UpdateTemplate, -} from 'nhs-notify-backend-client'; +import { TemplateDto, UpdateTemplate } from 'nhs-notify-backend-client'; import { handler } from '@backend-api/templates/api/update'; import { TemplateClient } from '@backend-api/templates/app/template-client'; @@ -128,13 +123,13 @@ describe('Template API - Update', () => { const update: UpdateTemplate = { name: 'updated-name', message: 'message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.SMS, + templateStatus: 'NOT_YET_SUBMITTED', + templateType: 'SMS', }; - const response: TemplateDTO = { + const response: TemplateDto = { ...update, id: '1-2-3', - templateType: TemplateType.SMS, + templateType: 'SMS', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; diff --git a/lambdas/backend-api/src/__tests__/templates/app/template-client.test.ts b/lambdas/backend-api/src/__tests__/templates/app/template-client.test.ts index dde6855d2..2eb0d10af 100644 --- a/lambdas/backend-api/src/__tests__/templates/app/template-client.test.ts +++ b/lambdas/backend-api/src/__tests__/templates/app/template-client.test.ts @@ -1,14 +1,9 @@ import { CreateTemplate, - TemplateDTO, - TemplateStatus, - TemplateType, + TemplateDto, UpdateTemplate, $CreateTemplateSchema, $UpdateTemplateSchema, - Language, - LetterType, - VirusScanStatus, } from 'nhs-notify-backend-client'; import { DatabaseTemplate, @@ -42,9 +37,10 @@ describe('templateClient', () => { }); const data: CreateTemplate = { - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', name: 'name', message: 'message', + subject: 'subject', }; const result = await client.createTemplate(data); @@ -61,9 +57,10 @@ describe('templateClient', () => { test('should return a failure result, when saving to the database unexpectedly fails', async () => { const data: CreateTemplate = { - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', name: 'name', message: 'message', + subject: 'subject', }; validateMock.mockResolvedValueOnce({ @@ -89,23 +86,66 @@ describe('templateClient', () => { }); }); + test('should return a failure result, when created database template is invalid', async () => { + const data: CreateTemplate = { + templateType: 'EMAIL', + name: 'name', + message: 'message', + subject: 'subject', + }; + + const expectedTemplateDto: TemplateDto = { + ...data, + id: 'id', + createdAt: undefined as unknown as string, + updatedAt: new Date().toISOString(), + templateStatus: 'NOT_YET_SUBMITTED', + }; + + const template: DatabaseTemplate = { + ...expectedTemplateDto, + owner: 'owner', + version: 1, + }; + + validateMock.mockResolvedValueOnce({ + data, + }); + + createMock.mockResolvedValueOnce({ + data: template, + }); + + const result = await client.createTemplate(data); + + expect(createMock).toHaveBeenCalledWith(data, 'owner'); + + expect(result).toEqual({ + error: { + code: 500, + message: 'Error retrieving template', + }, + }); + }); + test('should return created template', async () => { const data: CreateTemplate = { - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', name: 'name', message: 'message', + subject: 'subject', }; - const expectedTemplateDTO: TemplateDTO = { + const expectedTemplateDto: TemplateDto = { ...data, id: 'id', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', }; const template: DatabaseTemplate = { - ...expectedTemplateDTO, + ...expectedTemplateDto, owner: 'owner', version: 1, }; @@ -123,7 +163,7 @@ describe('templateClient', () => { expect(createMock).toHaveBeenCalledWith(data, 'owner'); expect(result).toEqual({ - data: expectedTemplateDTO, + data: expectedTemplateDto, }); }); }); @@ -140,8 +180,8 @@ describe('templateClient', () => { const data: UpdateTemplate = { name: 'name', message: 'message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.SMS, + templateStatus: 'NOT_YET_SUBMITTED', + templateType: 'SMS', }; const result = await client.updateTemplate('id', data); @@ -160,8 +200,8 @@ describe('templateClient', () => { const data: UpdateTemplate = { name: 'name', message: 'message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.SMS, + templateStatus: 'NOT_YET_SUBMITTED', + templateType: 'SMS', }; validateMock.mockResolvedValueOnce({ @@ -187,18 +227,60 @@ describe('templateClient', () => { }); }); + test('should return a failure result, when updated database template is invalid', async () => { + const data: UpdateTemplate = { + name: 'name', + message: 'message', + templateStatus: 'NOT_YET_SUBMITTED', + templateType: 'SMS', + }; + + const expectedTemplateDto: TemplateDto = { + ...data, + id: 'id', + createdAt: undefined as unknown as string, + updatedAt: new Date().toISOString(), + templateStatus: 'NOT_YET_SUBMITTED', + }; + + const template: DatabaseTemplate = { + ...expectedTemplateDto, + owner: 'owner', + version: 1, + }; + + validateMock.mockResolvedValueOnce({ + data, + }); + + updateMock.mockResolvedValueOnce({ + data: template, + }); + + const result = await client.updateTemplate('id', data); + + expect(updateMock).toHaveBeenCalledWith('id', data, 'owner'); + + expect(result).toEqual({ + error: { + code: 500, + message: 'Error retrieving template', + }, + }); + }); + test('should return updated template', async () => { const data: UpdateTemplate = { name: 'name', message: 'message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.SMS, + templateStatus: 'NOT_YET_SUBMITTED', + templateType: 'SMS', }; - const template: TemplateDTO = { + const template: TemplateDto = { ...data, id: 'id', - templateType: TemplateType.SMS, + templateType: 'SMS', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; @@ -242,19 +324,53 @@ describe('templateClient', () => { }); }); + test('should return a failure result, when database template is invalid', async () => { + const templateDTO: TemplateDto = { + id: 'id', + templateType: 'EMAIL', + name: 'name', + message: 'message', + subject: 'subject', + createdAt: undefined as unknown as string, + updatedAt: new Date().toISOString(), + templateStatus: 'NOT_YET_SUBMITTED', + }; + + const template: DatabaseTemplate = { + ...templateDTO, + owner: 'owner', + version: 1, + }; + + getMock.mockResolvedValueOnce({ + data: template, + }); + + const result = await client.getTemplate('id'); + + expect(getMock).toHaveBeenCalledWith('id', 'owner'); + + expect(result).toEqual({ + error: { + code: 500, + message: 'Error retrieving template', + }, + }); + }); + test('should return a failure result, when fetching a letter, if letter flag is not enabled', async () => { const noLettersClient = new TemplateClient('owner', false); getMock.mockResolvedValueOnce({ data: { id: 'id', - templateType: TemplateType.LETTER, + templateType: 'LETTER', name: 'name', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - letterType: LetterType.Q4, - language: Language.FR, + templateStatus: 'NOT_YET_SUBMITTED', + letterType: 'q4', + language: 'fr', owner: 'owner', version: 1, }, @@ -273,14 +389,15 @@ describe('templateClient', () => { }); test('should return template', async () => { - const template: TemplateDTO = { + const template: TemplateDto = { id: 'id', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', name: 'name', message: 'message', + subject: 'subject', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', }; getMock.mockResolvedValueOnce({ @@ -321,25 +438,25 @@ describe('templateClient', () => { test('filters out letters if the feature flag is not enabled', async () => { const noLettersClient = new TemplateClient('owner', false); - const template: TemplateDTO = { + const template: TemplateDto = { id: 'id', - templateType: TemplateType.LETTER, + templateType: 'LETTER', name: 'name', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - letterType: LetterType.Q4, - language: Language.FR, + templateStatus: 'NOT_YET_SUBMITTED', + letterType: 'q4', + language: 'fr', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: 'uuid', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, testDataCsv: { fileName: 'file.csv', currentVersion: 'uuid', - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, }; @@ -357,15 +474,54 @@ describe('templateClient', () => { }); }); + test('should filter out invalid templates', async () => { + const template: TemplateDto = { + id: 'id', + templateType: 'EMAIL', + name: 'name', + message: 'message', + subject: 'subject', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + templateStatus: 'NOT_YET_SUBMITTED', + }; + const template2: TemplateDto = { + id: undefined as unknown as string, + templateType: 'EMAIL', + name: undefined as unknown as string, + message: 'message', + subject: 'subject', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + templateStatus: 'NOT_YET_SUBMITTED', + }; + + listMock.mockResolvedValueOnce({ + data: [ + { ...template, owner: 'owner', version: 1 }, + { ...template2, owner: 'owner', version: 1 }, + ], + }); + + const result = await client.listTemplates(); + + expect(listMock).toHaveBeenCalledWith('owner'); + + expect(result).toEqual({ + data: [template], + }); + }); + test('should return templates', async () => { - const template: TemplateDTO = { + const template: TemplateDto = { id: 'id', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', name: 'name', message: 'message', + subject: 'subject', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', }; listMock.mockResolvedValueOnce({ diff --git a/lambdas/backend-api/src/__tests__/templates/infra/template-repository.test.ts b/lambdas/backend-api/src/__tests__/templates/infra/template-repository.test.ts index e7f67ed62..2c966ccc9 100644 --- a/lambdas/backend-api/src/__tests__/templates/infra/template-repository.test.ts +++ b/lambdas/backend-api/src/__tests__/templates/infra/template-repository.test.ts @@ -8,9 +8,11 @@ import { } from '@aws-sdk/lib-dynamodb'; import { mockClient } from 'aws-sdk-client-mock'; import { - TemplateStatus, - TemplateType, - UpdateTemplate, + EmailProperties, + LetterProperties, + NhsAppProperties, + SmsProperties, + ValidatedUpdateTemplate, } from 'nhs-notify-backend-client'; import { ConditionalCheckFailedException } from '@aws-sdk/client-dynamodb'; import { DatabaseTemplate, templateRepository } from '../../../templates/infra'; @@ -20,17 +22,72 @@ jest.mock('node:crypto'); const uuidMock = jest.mocked(uuidv4); const ddbMock = mockClient(DynamoDBDocumentClient); -const template: DatabaseTemplate = { - id: 'abc-def-ghi-jkl-123', - owner: 'real-owner', - name: 'name', +const emailProperties: EmailProperties = { message: 'message', subject: 'pickles', - templateType: TemplateType.EMAIL, +}; + +const smsProperties: SmsProperties = { + message: 'message', +}; + +const nhsAppProperties: NhsAppProperties = { + message: 'message', +}; + +const letterProperties: LetterProperties = { + letterType: 'x0', + language: 'en', + files: { + pdfTemplate: { + fileName: 'template.pdf', + }, + testDataCsv: { + fileName: 'test.csv', + }, + }, +}; + +const createTemplateProperties = { + name: 'name', +}; + +const updateTemplateProperties = { + ...createTemplateProperties, + templateStatus: 'NOT_YET_SUBMITTED' as const, +}; + +const databaseTemplateProperties = { + ...updateTemplateProperties, + id: 'abc-def-ghi-jkl-123', + owner: 'real-owner', version: 1, createdAt: '2024-12-27T00:00:00.000Z', updatedAt: '2024-12-27T00:00:00.000Z', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, +}; + +const emailTemplate: DatabaseTemplate = { + templateType: 'EMAIL', + ...emailProperties, + ...databaseTemplateProperties, +}; + +const smsTemplate: DatabaseTemplate = { + templateType: 'SMS', + ...smsProperties, + ...databaseTemplateProperties, +}; + +const nhsAppTemplate: DatabaseTemplate = { + templateType: 'NHS_APP', + ...nhsAppProperties, + ...databaseTemplateProperties, +}; + +const letterTemplate: DatabaseTemplate = { + templateType: 'LETTER', + ...letterProperties, + ...databaseTemplateProperties, }; describe('templateRepository', () => { @@ -86,7 +143,7 @@ describe('templateRepository', () => { Item: { id: 'abc-def-ghi-jkl-123', owner: 'real-owner', - templateStatus: TemplateStatus.DELETED, + templateStatus: 'DELETED', }, }); @@ -127,7 +184,7 @@ describe('templateRepository', () => { Key: { id: 'abc-def-ghi-jkl-123', owner: 'real-owner' }, }) .resolves({ - Item: template, + Item: emailTemplate, }); const response = await templateRepository.get( @@ -136,7 +193,7 @@ describe('templateRepository', () => { ); expect(response).toEqual({ - data: template, + data: emailTemplate, }); }); }); @@ -181,13 +238,13 @@ describe('templateRepository', () => { }, }) .resolves({ - Items: [template], + Items: [emailTemplate, smsTemplate, nhsAppTemplate, letterTemplate], }); const response = await templateRepository.list('real-owner'); expect(response).toEqual({ - data: [template], + data: [emailTemplate, smsTemplate, nhsAppTemplate, letterTemplate], }); }); }); @@ -200,7 +257,7 @@ describe('templateRepository', () => { const response = await templateRepository.create( { - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', name: 'name', message: 'message', subject: 'pickles', @@ -217,30 +274,42 @@ describe('templateRepository', () => { }); }); - test('should create template', async () => { - uuidMock.mockReturnValue('abc-def-ghi-jkl-123'); + test.each([ + { templateType: 'EMAIL' as const, ...emailProperties }, + { templateType: 'SMS' as const, ...smsProperties }, + { templateType: 'NHS_APP' as const, ...nhsAppProperties }, + { templateType: 'LETTER' as const, ...letterProperties }, + ])( + 'should create template of type $templateType', + async (channelProperties) => { + uuidMock.mockReturnValue('abc-def-ghi-jkl-123'); - ddbMock - .on(PutCommand, { - TableName: 'templates', - Item: template, - }) - .resolves({}); + ddbMock + .on(PutCommand, { + TableName: 'templates', + Item: { + ...channelProperties, + ...databaseTemplateProperties, + }, + }) + .resolves({}); - const response = await templateRepository.create( - { - templateType: TemplateType.EMAIL, - name: 'name', - message: 'message', - subject: 'pickles', - }, - 'real-owner' - ); + const response = await templateRepository.create( + { + ...channelProperties, + ...createTemplateProperties, + }, + 'real-owner' + ); - expect(response).toEqual({ - data: template, - }); - }); + expect(response).toEqual({ + data: { + ...channelProperties, + ...databaseTemplateProperties, + }, + }); + } + ); }); describe('update', () => { @@ -254,8 +323,8 @@ describe('templateRepository', () => { testName: 'Fails when user tries to change templateType from SMS to EMAIL', Item: { - templateType: { S: TemplateType.SMS }, - templateStatus: { S: TemplateStatus.NOT_YET_SUBMITTED }, + templateType: { S: 'SMS' }, + templateStatus: { S: 'NOT_YET_SUBMITTED' }, }, code: 400, message: 'Can not change template templateType', @@ -267,8 +336,8 @@ describe('templateRepository', () => { testName: 'Fails when user tries to update template when templateStatus is SUBMITTED', Item: { - templateType: { S: TemplateType.EMAIL }, - templateStatus: { S: TemplateStatus.SUBMITTED }, + templateType: { S: 'EMAIL' }, + templateStatus: { S: 'SUBMITTED' }, }, code: 400, message: 'Template with status SUBMITTED cannot be updated', @@ -277,8 +346,8 @@ describe('templateRepository', () => { testName: 'Fails when user tries to update template when templateStatus is DELETED', Item: { - templateType: { S: TemplateType.EMAIL }, - templateStatus: { S: TemplateStatus.DELETED }, + templateType: { S: 'EMAIL' }, + templateStatus: { S: 'DELETED' }, }, code: 404, message: 'Template not found', @@ -300,8 +369,8 @@ describe('templateRepository', () => { name: 'name', message: 'message', subject: 'subject', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.EMAIL, + templateStatus: 'SUBMITTED', + templateType: 'EMAIL', }, 'real-owner' ); @@ -328,8 +397,8 @@ describe('templateRepository', () => { name: 'name', message: 'message', subject: 'subject', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, - templateType: TemplateType.EMAIL, + templateStatus: 'NOT_YET_SUBMITTED', + templateType: 'EMAIL', }, 'real-owner' ); @@ -343,47 +412,56 @@ describe('templateRepository', () => { }); }); - test('should update template with subject', async () => { - const updatedTemplate: UpdateTemplate = { - name: 'updated-name', - message: 'updated-message', - subject: 'updated-subject', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.EMAIL, - }; + test.each([ + { templateType: 'EMAIL' as const, ...emailProperties }, + { templateType: 'SMS' as const, ...smsProperties }, + { templateType: 'NHS_APP' as const, ...nhsAppProperties }, + { templateType: 'LETTER' as const, ...letterProperties }, + ])( + 'should update template of type $templateType with name', + async (channelProperties) => { + const updatedTemplate: ValidatedUpdateTemplate = { + ...channelProperties, + ...updateTemplateProperties, + name: 'updated-name', + templateStatus: 'SUBMITTED', + }; - ddbMock - .on(UpdateCommand, { - TableName: 'templates', - Key: { id: 'abc-def-ghi-jkl-123', owner: 'real-owner' }, - }) - .resolves({ - Attributes: { - ...template, + ddbMock + .on(UpdateCommand, { + TableName: 'templates', + Key: { id: 'abc-def-ghi-jkl-123', owner: 'real-owner' }, + }) + .resolves({ + Attributes: { + ...channelProperties, + ...databaseTemplateProperties, + ...updatedTemplate, + }, + }); + + const response = await templateRepository.update( + 'abc-def-ghi-jkl-123', + updatedTemplate, + 'real-owner' + ); + + expect(response).toEqual({ + data: { + ...channelProperties, + ...databaseTemplateProperties, ...updatedTemplate, }, }); - - const response = await templateRepository.update( - 'abc-def-ghi-jkl-123', - updatedTemplate, - 'real-owner' - ); - - expect(response).toEqual({ - data: { - ...template, - ...updatedTemplate, - }, - }); - }); + } + ); test('should update template to deleted state', async () => { - const updatedTemplate: UpdateTemplate = { + const updatedTemplate: ValidatedUpdateTemplate = { name: 'updated-name', message: 'updated-message', - templateStatus: TemplateStatus.DELETED, - templateType: TemplateType.NHS_APP, + templateStatus: 'DELETED', + templateType: 'NHS_APP', }; ddbMock @@ -393,7 +471,7 @@ describe('templateRepository', () => { }) .resolves({ Attributes: { - ...template, + ...emailTemplate, ...updatedTemplate, }, }); @@ -406,7 +484,7 @@ describe('templateRepository', () => { expect(response).toEqual({ data: { - ...template, + ...emailTemplate, ...updatedTemplate, }, }); diff --git a/lambdas/backend-api/src/templates/api/responses.ts b/lambdas/backend-api/src/templates/api/responses.ts index 3c6a42a5f..4b98ae599 100644 --- a/lambdas/backend-api/src/templates/api/responses.ts +++ b/lambdas/backend-api/src/templates/api/responses.ts @@ -2,12 +2,12 @@ import { Failure, Success, SuccessList, - TemplateDTO, + TemplateDto, } from 'nhs-notify-backend-client'; export const apiSuccess = ( statusCode: number, - result: TemplateDTO | TemplateDTO[] + result: TemplateDto | TemplateDto[] ) => { if (Array.isArray(result)) { return { diff --git a/lambdas/backend-api/src/templates/app/template-client.ts b/lambdas/backend-api/src/templates/app/template-client.ts index a2e5d7930..7a5fbe39c 100644 --- a/lambdas/backend-api/src/templates/app/template-client.ts +++ b/lambdas/backend-api/src/templates/app/template-client.ts @@ -3,12 +3,12 @@ import { CreateTemplate, ITemplateClient, Result, - TemplateDTO, + TemplateDto, UpdateTemplate, $CreateTemplateSchema, $UpdateTemplateSchema, - TemplateType, ErrorCase, + isTemplateDtoValid, } from 'nhs-notify-backend-client'; import { DatabaseTemplate, @@ -21,7 +21,7 @@ export class TemplateClient implements ITemplateClient { private readonly enableLetters: boolean ) {} - async createTemplate(template: CreateTemplate): Promise> { + async createTemplate(template: CreateTemplate): Promise> { const log = logger.child({ template, }); @@ -50,13 +50,18 @@ export class TemplateClient implements ITemplateClient { return createResult; } - return success(this.mapDatabaseObjectToDTO(createResult.data)); + const templateDTO = this.mapDatabaseObjectToDTO(createResult.data); + if (!templateDTO) { + return failure(ErrorCase.DATABASE_FAILURE, 'Error retrieving template'); + } + + return success(templateDTO); } async updateTemplate( templateId: string, template: UpdateTemplate - ): Promise> { + ): Promise> { const log = logger.child({ templateId, template, @@ -82,10 +87,15 @@ export class TemplateClient implements ITemplateClient { return updateResult; } - return success(this.mapDatabaseObjectToDTO(updateResult.data)); + const templateDTO = this.mapDatabaseObjectToDTO(updateResult.data); + if (!templateDTO) { + return failure(ErrorCase.DATABASE_FAILURE, 'Error retrieving template'); + } + + return success(templateDTO); } - async getTemplate(templateId: string): Promise> { + async getTemplate(templateId: string): Promise> { const log = logger.child({ templateId, }); @@ -98,25 +108,27 @@ export class TemplateClient implements ITemplateClient { return getResult; } - if ( - getResult.data.templateType === TemplateType.LETTER && - !this.enableLetters - ) { + if (getResult.data.templateType === 'LETTER' && !this.enableLetters) { return failure(ErrorCase.TEMPLATE_NOT_FOUND, 'Template not found'); } - return success(this.mapDatabaseObjectToDTO(getResult.data)); + const templateDTO = this.mapDatabaseObjectToDTO(getResult.data); + if (!templateDTO) { + return failure(ErrorCase.DATABASE_FAILURE, 'Error retrieving template'); + } + + return success(templateDTO); } private mapDatabaseObjectToDTO( databaseTemplate: DatabaseTemplate - ): TemplateDTO { + ): TemplateDto | undefined { const { owner: _1, version: _2, ...templateDTO } = databaseTemplate; - return templateDTO; + return isTemplateDtoValid(templateDTO); } - async listTemplates(): Promise> { + async listTemplates(): Promise> { const listResult = await templateRepository.list(this._owner); if (listResult.error) { @@ -127,9 +139,8 @@ export class TemplateClient implements ITemplateClient { const templateDTOs = listResult.data .map((template) => this.mapDatabaseObjectToDTO(template)) - .filter( - (t) => this.enableLetters || t.templateType !== TemplateType.LETTER - ); + .flatMap((t) => t ?? []) + .filter((t) => this.enableLetters || t.templateType !== 'LETTER'); return success(templateDTOs); } diff --git a/lambdas/backend-api/src/templates/infra/template-repository.ts b/lambdas/backend-api/src/templates/infra/template-repository.ts index aedaf8678..dc3215c3c 100644 --- a/lambdas/backend-api/src/templates/infra/template-repository.ts +++ b/lambdas/backend-api/src/templates/infra/template-repository.ts @@ -1,9 +1,13 @@ import { randomUUID as uuidv4 } from 'node:crypto'; import { CreateTemplate, + EmailProperties, ErrorCase, - TemplateStatus, + LetterProperties, + NhsAppProperties, + SmsProperties, UpdateTemplate, + ValidatedUpdateTemplate, } from 'nhs-notify-backend-client'; import { ConditionalCheckFailedException, @@ -49,7 +53,7 @@ const get = async ( const item = response.Item as DatabaseTemplate; - if (item.templateStatus === TemplateStatus.DELETED) { + if (item.templateStatus === 'DELETED') { return failure(ErrorCase.TEMPLATE_NOT_FOUND, 'Template not found'); } @@ -69,7 +73,7 @@ const create = async ( id: uuidv4(), owner, version: 1, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', createdAt: date, updatedAt: date, }; @@ -92,15 +96,143 @@ const create = async ( } }; +const nhsAppAttributes: Record = { + message: null, +}; + +const emailAttributes: Record = { + message: null, + subject: null, +}; + +const smsAttributes: Record = { + message: null, +}; + +const letterAttributes: Record = { + letterType: null, + language: null, + files: null, +}; + +const attributeExpressionsFromMap = ( + channelSpecificAttributes: Record +) => Object.keys(channelSpecificAttributes).map((att) => `#${att} = :${att}`); + +const getChannelAttributeExpressions = (template: UpdateTemplate) => { + const expressions = []; + if (template.templateType === 'NHS_APP') { + expressions.push( + attributeExpressionsFromMap(nhsAppAttributes) + ); + } + if (template.templateType === 'EMAIL') { + expressions.push( + attributeExpressionsFromMap(emailAttributes) + ); + } + if (template.templateType === 'SMS') { + expressions.push(attributeExpressionsFromMap(smsAttributes)); + } + if (template.templateType === 'LETTER') { + expressions.push( + attributeExpressionsFromMap(letterAttributes) + ); + } + return expressions; +}; + +const attributeNamesFromMap = ( + channelSpecificAttributes: Record +) => { + let attributeNames = {}; + + for (const att in channelSpecificAttributes) { + attributeNames = { + ...attributeNames, + [`#${att}`]: att, + }; + } + + return attributeNames; +}; + +const getChannelAttributeNames = (template: UpdateTemplate) => { + let names = {}; + + if (template.templateType === 'NHS_APP') { + names = attributeNamesFromMap(nhsAppAttributes); + } + if (template.templateType === 'EMAIL') { + names = attributeNamesFromMap(emailAttributes); + } + if (template.templateType === 'SMS') { + names = attributeNamesFromMap(smsAttributes); + } + if (template.templateType === 'LETTER') { + names = attributeNamesFromMap(letterAttributes); + } + + return names; +}; + +const attributeValuesFromMapAndTemplate = ( + channelSpecificAttributes: Record, + template: T +) => { + let attributeValues = {}; + + for (const att in channelSpecificAttributes) { + attributeValues = { + ...attributeValues, + [`:${att}`]: template[att], + }; + } + + return attributeValues; +}; + +const getChannelAttributeValues = (template: ValidatedUpdateTemplate) => { + let values = {}; + + if (template.templateType === 'NHS_APP') { + values = attributeValuesFromMapAndTemplate( + nhsAppAttributes, + template + ); + } + if (template.templateType === 'EMAIL') { + values = attributeValuesFromMapAndTemplate( + emailAttributes, + template + ); + } + if (template.templateType === 'SMS') { + values = attributeValuesFromMapAndTemplate( + smsAttributes, + template + ); + } + if (template.templateType === 'LETTER') { + values = attributeValuesFromMapAndTemplate( + letterAttributes, + template + ); + } + + return values; +}; + const update = async ( templateId: string, - template: UpdateTemplate, + template: ValidatedUpdateTemplate, owner: string ): Promise> => { const updateExpression = [ '#name = :name', '#updatedAt = :updateAt', '#templateStatus = :templateStatus', + ...getChannelAttributeExpressions(template), ]; let expressionAttributeNames: Record = { @@ -108,41 +240,19 @@ const update = async ( '#templateStatus': 'templateStatus', '#updatedAt': 'updatedAt', '#templateType': 'templateType', + ...getChannelAttributeNames(template), }; let expressionAttributeValues: Record = { ':name': template.name, ':templateStatus': template.templateStatus, ':updateAt': new Date().toISOString(), - ':not_yet_submitted': TemplateStatus.NOT_YET_SUBMITTED, + ':not_yet_submitted': 'NOT_YET_SUBMITTED', ':templateType': template.templateType, + ...getChannelAttributeValues(template), }; - if (template.message) { - updateExpression.push('#message = :message'); - expressionAttributeNames = { - ...expressionAttributeNames, - '#message': 'message', - }; - expressionAttributeValues = { - ...expressionAttributeValues, - ':message': template.message, - }; - } - - if (template.subject) { - updateExpression.push('#subject = :subject'); - expressionAttributeNames = { - ...expressionAttributeNames, - '#subject': 'subject', - }; - expressionAttributeValues = { - ...expressionAttributeValues, - ':subject': template.subject, - }; - } - - if (template.templateStatus === TemplateStatus.DELETED) { + if (template.templateStatus === 'DELETED') { updateExpression.push('#ttl = :ttl'); expressionAttributeNames = { ...expressionAttributeNames, @@ -175,10 +285,7 @@ const update = async ( return success(response.Attributes as DatabaseTemplate); } catch (error) { if (error instanceof ConditionalCheckFailedException) { - if ( - !error.Item || - error.Item.templateStatus.S === TemplateStatus.DELETED - ) { + if (!error.Item || error.Item.templateStatus.S === 'DELETED') { return failure( ErrorCase.TEMPLATE_NOT_FOUND, `Template not found`, @@ -186,7 +293,7 @@ const update = async ( ); } - if (error.Item.templateStatus.S !== TemplateStatus.NOT_YET_SUBMITTED) { + if (error.Item.templateStatus.S !== 'NOT_YET_SUBMITTED') { return failure( ErrorCase.TEMPLATE_ALREADY_SUBMITTED, `Template with status ${error.Item.templateStatus.S} cannot be updated`, @@ -227,7 +334,7 @@ const list = async ( }, ExpressionAttributeValues: { ':owner': owner, - ':deletedStatus': TemplateStatus.DELETED, + ':deletedStatus': 'DELETED', }, FilterExpression: '#status <> :deletedStatus', }; diff --git a/lambdas/backend-api/src/templates/infra/template.ts b/lambdas/backend-api/src/templates/infra/template.ts index f7e4ff88e..b67bc926f 100644 --- a/lambdas/backend-api/src/templates/infra/template.ts +++ b/lambdas/backend-api/src/templates/infra/template.ts @@ -1,5 +1,5 @@ import { - Files, + LetterFiles, Language, LetterType, TemplateStatus, @@ -19,5 +19,5 @@ export type DatabaseTemplate = { updatedAt: string; letterType?: LetterType; language?: Language; - files?: Files; + files?: LetterFiles; }; diff --git a/lambdas/backend-client/openapi-ts.config.ts b/lambdas/backend-client/openapi-ts.config.ts new file mode 100644 index 000000000..1495a34f5 --- /dev/null +++ b/lambdas/backend-client/openapi-ts.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from '@hey-api/openapi-ts'; + +export default defineConfig({ + input: '../../infrastructure/terraform/modules/backend-api/spec.tmpl.json', + output: { + path: './src/types/generated', + case: 'preserve', + format: 'prettier', + lint: 'eslint', + }, + plugins: ['@hey-api/typescript'], +}); diff --git a/lambdas/backend-client/package.json b/lambdas/backend-client/package.json index 7b6a89134..ebfce325a 100644 --- a/lambdas/backend-client/package.json +++ b/lambdas/backend-client/package.json @@ -9,13 +9,14 @@ "lint:fix": "eslint . --fix", "test:unit": "jest", "typecheck": "tsc --noEmit", - "generate-dependencies": "npx openapi-typescript-codegen --exportCore false --exportServices false --input ../../infrastructure/terraform/modules/backend-api/spec.tmpl.json --output ./src/types/generated" + "generate-dependencies": "npx @hey-api/openapi-ts" }, "files": [ "src/index.ts" ], "types": "src/index.ts", "dependencies": { + "@hey-api/openapi-ts": "^0.64.10", "axios": "^1.7.9", "axios-retry": "^4.5.0", "zod": "^3.24.1" diff --git a/lambdas/backend-client/src/__tests__/schemas/template-schema.test.ts b/lambdas/backend-client/src/__tests__/schemas/template-schema.test.ts index fc1cb3c23..c6b2a70fe 100644 --- a/lambdas/backend-client/src/__tests__/schemas/template-schema.test.ts +++ b/lambdas/backend-client/src/__tests__/schemas/template-schema.test.ts @@ -1,69 +1,38 @@ -import { TemplateStatus, TemplateType } from 'nhs-notify-backend-client'; import { - $CreateTemplateSchema, - $UpdateTemplateSchema, - $CreateEmailTemplateSchema, - $CreateSMSTemplateSchema, - $CreateNhsAppTemplateSchema, -} from '../../schemas'; + CreateTemplate, + isCreateTemplateValid, + isTemplateDtoValid, + isUpdateTemplateValid, + TemplateDto, + UpdateTemplate, +} from 'nhs-notify-backend-client'; +import { $CreateTemplateSchema, $UpdateTemplateSchema } from '../../schemas'; describe('Template schemas', () => { test.each([ { - schema: $CreateEmailTemplateSchema, - data: { - name: 'Test Template', - message: 'This is a test template', - subject: 'Test Subject', - templateType: TemplateType.EMAIL, - }, - }, - { - schema: $CreateSMSTemplateSchema, - data: { - name: 'Test Template', - message: 'This is a test template', - templateType: TemplateType.SMS, - }, - }, - { - schema: $CreateNhsAppTemplateSchema, - data: { - name: 'Test Template', - message: 'This is a test template', - templateType: TemplateType.NHS_APP, - }, - }, - ])('%p.templateType - should pass validation', async ({ schema, data }) => { - const result = schema.safeParse(data); - - expect(result.data).toEqual(data); - }); - - test.each([ - { - schema: $CreateEmailTemplateSchema, + schema: $CreateTemplateSchema, data: { name: 'Test Template', message: 'a'.repeat(100_001), subject: 'Test Subject', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', }, }, { - schema: $CreateSMSTemplateSchema, + schema: $CreateTemplateSchema, data: { name: 'Test Template', message: 'a'.repeat(919), - templateType: TemplateType.SMS, + templateType: 'SMS', }, }, { - schema: $CreateNhsAppTemplateSchema, + schema: $CreateTemplateSchema, data: { name: 'Test Template', message: 'a'.repeat(5001), - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }, }, ])( @@ -85,28 +54,28 @@ describe('Template schemas', () => { test.each([ { - schema: $CreateEmailTemplateSchema, + schema: $CreateTemplateSchema, data: { name: ' ', message: ' ', subject: ' ', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', }, }, { - schema: $CreateSMSTemplateSchema, + schema: $CreateTemplateSchema, data: { name: ' ', message: ' ', - templateType: TemplateType.SMS, + templateType: 'SMS', }, }, { - schema: $CreateNhsAppTemplateSchema, + schema: $CreateTemplateSchema, data: { name: ' ', message: ' ', - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }, }, ])( @@ -122,7 +91,7 @@ describe('Template schemas', () => { }, }; - if (data.templateType === TemplateType.EMAIL) { + if (data.templateType === 'EMAIL') { Object.assign(errors.fieldErrors, { subject: [errorMessage], }); @@ -134,28 +103,28 @@ describe('Template schemas', () => { test.each([ { - schema: $CreateEmailTemplateSchema, + schema: $CreateTemplateSchema, data: { name: '', message: '', subject: '', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', }, }, { - schema: $CreateSMSTemplateSchema, + schema: $CreateTemplateSchema, data: { name: '', message: '', - templateType: TemplateType.SMS, + templateType: 'SMS', }, }, { - schema: $CreateNhsAppTemplateSchema, + schema: $CreateTemplateSchema, data: { name: '', message: '', - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }, }, ])( @@ -171,7 +140,7 @@ describe('Template schemas', () => { }, }; - if (data.templateType === TemplateType.EMAIL) { + if (data.templateType === 'EMAIL') { Object.assign(errors.fieldErrors, { subject: [errorMessage], }); @@ -182,10 +151,10 @@ describe('Template schemas', () => { ); test('$EmailTemplateFields - should fail validation, when no subject', async () => { - const result = $CreateEmailTemplateSchema.safeParse({ + const result = $CreateTemplateSchema.safeParse({ name: 'Test Template', message: 'a'.repeat(100_000), - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', }); expect(result.error?.flatten()).toEqual( @@ -204,10 +173,10 @@ describe('Template schemas', () => { ])( '$NhsAppTemplateFields - should fail validation, when invalid characters are present %p', async (message) => { - const result = $CreateNhsAppTemplateSchema.safeParse({ + const result = $CreateTemplateSchema.safeParse({ name: 'Test Template', message, - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }); expect(result.error?.flatten()).toEqual( @@ -225,68 +194,76 @@ describe('Template schemas', () => { describe('$CreateTemplateSchema', () => { const commonFields = { name: 'Test Template', - message: 'This is a test template', }; test.each([ { ...commonFields, subject: 'Test Subject', - templateType: TemplateType.EMAIL, + message: 'This is a test template', + templateType: 'EMAIL', + }, + { + ...commonFields, + message: 'This is a test template', + templateType: 'SMS', }, { ...commonFields, - templateType: TemplateType.SMS, + message: 'This is a test template', + templateType: 'NHS_APP', }, { ...commonFields, - templateType: TemplateType.NHS_APP, + templateType: 'LETTER', + letterType: 'x0', + language: 'en', + files: { + pdfTemplate: { + fileName: 'template.pdf', + }, + }, }, ])('should pass validation %p', async (template) => { const result = $CreateTemplateSchema.safeParse(template); expect(result.data).toEqual(template); }); - - test('Letter creation should fail', () => { - const result = $CreateTemplateSchema.safeParse({ - name: 'Test Template', - message: 'mesage', - templateType: TemplateType.LETTER, - }); - - expect(result.error?.flatten()).toEqual( - expect.objectContaining({ - fieldErrors: { - templateType: [ - "Invalid discriminator value. Expected 'SMS' | 'NHS_APP' | 'EMAIL'", - ], - }, - }) - ); - }); }); describe('$UpdateTemplateSchema', () => { const commonFields = { name: 'Test Template', - message: 'This is a test template', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED', }; test.each([ { ...commonFields, subject: 'Test Subject', - templateType: TemplateType.EMAIL, + message: 'This is a test template', + templateType: 'EMAIL', + }, + { + ...commonFields, + message: 'This is a test template', + templateType: 'SMS', }, { ...commonFields, - templateType: TemplateType.SMS, + message: 'This is a test template', + templateType: 'NHS_APP', }, { ...commonFields, - templateType: TemplateType.NHS_APP, + templateType: 'LETTER', + letterType: 'x0', + language: 'en', + files: { + pdfTemplate: { + fileName: 'template.pdf', + }, + }, }, ])('should pass validation %p', async (template) => { const result = $UpdateTemplateSchema.safeParse(template); @@ -295,21 +272,77 @@ describe('Template schemas', () => { }); }); - test('Letter update should fail', () => { - const result = $UpdateTemplateSchema.safeParse({ + describe('isCreateTemplateValid', () => { + const template: CreateTemplate = { name: 'Test Template', - message: 'mesage', - templateType: TemplateType.LETTER, + message: 'This is a test template', + templateType: 'NHS_APP', + }; + + test('Should return template on pass', async () => { + const result = isCreateTemplateValid(template); + + expect(result).toEqual(template); }); - expect(result.error?.flatten()).toEqual( - expect.objectContaining({ - fieldErrors: { - templateType: [ - "Invalid discriminator value. Expected 'SMS' | 'NHS_APP' | 'EMAIL'", - ], - }, - }) - ); + test('Should return undefined on fail', async () => { + const result = isCreateTemplateValid({ + ...template, + name: undefined, + }); + + expect(result).toEqual(undefined); + }); + }); + + describe('isUpdateTemplateValid', () => { + const template: UpdateTemplate = { + name: 'Test Template', + message: 'This is a test template', + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', + }; + + test('Should return template on pass', async () => { + const result = isUpdateTemplateValid(template); + + expect(result).toEqual(template); + }); + + test('Should return undefined on fail', async () => { + const result = isUpdateTemplateValid({ + ...template, + name: undefined, + }); + + expect(result).toEqual(undefined); + }); + }); + + describe('isTemplateDtoValid', () => { + const template: TemplateDto = { + name: 'Test Template', + message: 'This is a test template', + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', + id: 'id', + createdAt: '2025-01-13T10:19:25.579Z', + updatedAt: '2025-01-13T10:19:25.579Z', + }; + + test('Should return template on pass', async () => { + const result = isTemplateDtoValid(template); + + expect(result).toEqual(template); + }); + + test('Should return undefined on fail', async () => { + const result = isTemplateDtoValid({ + ...template, + name: undefined, + }); + + expect(result).toEqual(undefined); + }); }); }); diff --git a/lambdas/backend-client/src/__tests__/schemas/union-lists.test.ts b/lambdas/backend-client/src/__tests__/schemas/union-lists.test.ts new file mode 100644 index 000000000..f594b1e49 --- /dev/null +++ b/lambdas/backend-client/src/__tests__/schemas/union-lists.test.ts @@ -0,0 +1,42 @@ +import { + arrayOfAll, + LANGUAGE_LIST, + LETTER_TYPE_LIST, + TEMPLATE_STATUS_LIST, + TEMPLATE_TYPE_LIST, + VIRUS_SCAN_STATUS_LIST, +} from '../../schemas/union-lists'; + +describe('arrayOfAll', () => { + type Union = 'a' | 'b' | 'c'; + + test('compiles when all cases of the union are in the array, order is ignored', () => { + expect(arrayOfAll()(['c', 'b', 'a'])).toEqual(['c', 'b', 'a']); + }); + + test('does not compile if a case is missing', () => { + const a: Union[] = ['a', 'b', 'c']; + + // @ts-expect-error `Type 'Union[]' is not assignable to type '"Invalid"'.` + expect(arrayOfAll()(a)).toEqual(a); + }); + + test('does not compile if extra cases are present in the array', () => { + const a: Array = ['a', 'b', 'c', 'd']; + + // @ts-expect-error `Type '"d"' is not assignable to type 'Union'.` + expect(arrayOfAll()(a)).toEqual(a); + }); +}); + +describe('Union lists', () => { + test.each([ + { name: 'TemplateType', list: TEMPLATE_TYPE_LIST }, + { name: 'TemplateStatus', list: TEMPLATE_STATUS_LIST }, + { name: 'Language', list: LANGUAGE_LIST }, + { name: 'LetterType', list: LETTER_TYPE_LIST }, + { name: 'VirusScanStatus', list: VIRUS_SCAN_STATUS_LIST }, + ])('$name list contains no duplicates', ({ list }) => { + expect(list.length).toEqual(new Set(list).size); + }); +}); diff --git a/lambdas/backend-client/src/__tests__/template-api-client.test.ts b/lambdas/backend-client/src/__tests__/template-api-client.test.ts index 6e8745463..38bd4c5c6 100644 --- a/lambdas/backend-client/src/__tests__/template-api-client.test.ts +++ b/lambdas/backend-client/src/__tests__/template-api-client.test.ts @@ -1,7 +1,6 @@ import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { TemplateApiClient, TemplateClient } from '../template-api-client'; -import { TemplateStatus, TemplateType } from '../types/generated'; const axiosMock = new MockAdapter(axios); @@ -32,7 +31,7 @@ describe('TemplateAPIClient', () => { const result = await client.createTemplate({ name: 'test', message: '', - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }); expect(result.error).toEqual({ @@ -55,7 +54,7 @@ describe('TemplateAPIClient', () => { id: 'id', name: 'name', message: 'message', - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }, }); @@ -64,14 +63,14 @@ describe('TemplateAPIClient', () => { const result = await client.createTemplate({ name: 'name', message: 'message', - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }); expect(result.data).toEqual({ id: 'id', name: 'name', message: 'message', - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', }); expect(result.error).toBeUndefined(); @@ -91,8 +90,8 @@ describe('TemplateAPIClient', () => { const result = await client.updateTemplate('real-id', { name: 'test', message: '', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.NHS_APP, + templateStatus: 'SUBMITTED', + templateType: 'NHS_APP', }); expect(result.error).toEqual({ @@ -113,8 +112,8 @@ describe('TemplateAPIClient', () => { id: 'id', name: 'name', message: 'message', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.NHS_APP, + templateStatus: 'SUBMITTED', + templateType: 'NHS_APP', }; axiosMock.onPost('/v1/template/real-id').reply(200, { @@ -127,8 +126,8 @@ describe('TemplateAPIClient', () => { const result = await client.updateTemplate('real-id', { name: 'name', message: 'message', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.NHS_APP, + templateStatus: 'SUBMITTED', + templateType: 'NHS_APP', }); expect(result.data).toEqual(data); @@ -167,8 +166,8 @@ describe('TemplateAPIClient', () => { id: 'id', name: 'name', message: 'message', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.NHS_APP, + templateStatus: 'SUBMITTED', + templateType: 'NHS_APP', }; axiosMock.onGet('/v1/template/real-id').reply(200, { @@ -210,8 +209,8 @@ describe('TemplateAPIClient', () => { id: 'id', name: 'name', message: 'message', - templateStatus: TemplateStatus.SUBMITTED, - templateType: TemplateType.NHS_APP, + templateStatus: 'SUBMITTED', + templateType: 'NHS_APP', }; axiosMock.onGet('/v1/templates').reply(200, { diff --git a/lambdas/backend-client/src/index.ts b/lambdas/backend-client/src/index.ts index 0936c268c..14ffe2855 100644 --- a/lambdas/backend-client/src/index.ts +++ b/lambdas/backend-client/src/index.ts @@ -3,3 +3,4 @@ export * from './types/generated'; export * from './types/result'; export * from './types/template-client'; export * from './schemas/template-schema'; +export * from './schemas/union-lists'; diff --git a/lambdas/backend-client/src/schemas/template-schema.ts b/lambdas/backend-client/src/schemas/template-schema.ts index 47abebce7..6fdda3d0e 100644 --- a/lambdas/backend-client/src/schemas/template-schema.ts +++ b/lambdas/backend-client/src/schemas/template-schema.ts @@ -1,37 +1,89 @@ import { z } from 'zod'; import { + BaseTemplate, CreateTemplate, - TemplateDTO, - TemplateStatus, - TemplateType, + EmailProperties, + FileDetails, + LetterFiles, + LetterProperties, + NhsAppProperties, + SmsProperties, + TemplateDto, UpdateTemplate, -} from 'nhs-notify-backend-client'; -import { schemaFor } from './schema-for'; +} from '../types/generated'; import { - MAX_SMS_CHARACTER_LENGTH, MAX_EMAIL_CHARACTER_LENGTH, MAX_NHS_APP_CHARACTER_LENGTH, + MAX_SMS_CHARACTER_LENGTH, NHS_APP_DISALLOWED_CHARACTERS, } from './constants'; +import { schemaFor } from './schema-for'; +import { + LANGUAGE_LIST, + LETTER_TYPE_LIST, + TEMPLATE_STATUS_LIST, + TEMPLATE_TYPE_LIST, + VIRUS_SCAN_STATUS_LIST, +} from './union-lists'; -const $BaseCreateTemplateSchema = schemaFor()( +export type EmailPropertiesWithType = EmailProperties & { + templateType: 'EMAIL'; +}; +export type NhsAppPropertiesWithType = NhsAppProperties & { + templateType: 'NHS_APP'; +}; +export type SmsPropertiesWithType = SmsProperties & { templateType: 'SMS' }; +export type LetterPropertiesWithType = LetterProperties & { + templateType: 'LETTER'; +}; + +export type ValidatedCreateTemplate = CreateTemplate & + ( + | EmailPropertiesWithType + | NhsAppPropertiesWithType + | SmsPropertiesWithType + | LetterPropertiesWithType + ); +export type ValidatedUpdateTemplate = UpdateTemplate & + ( + | EmailPropertiesWithType + | NhsAppPropertiesWithType + | SmsPropertiesWithType + | LetterPropertiesWithType + ); +export type ValidatedTemplateDto = TemplateDto & + ( + | EmailPropertiesWithType + | NhsAppPropertiesWithType + | SmsPropertiesWithType + | LetterPropertiesWithType + ); + +const $FileDetails = schemaFor()( z.object({ - templateType: z.nativeEnum(TemplateType), - name: z.string().trim().min(1), - message: z.string().trim().min(1).optional(), + fileName: z.string().trim().min(1), + currentVersion: z.string().optional(), + virusScanStatus: z.enum(VIRUS_SCAN_STATUS_LIST).optional(), }) ); -export const $CreateSMSTemplateSchema = schemaFor()( - $BaseCreateTemplateSchema.extend({ - templateType: z.literal(TemplateType.SMS), - message: z.string().trim().min(1).max(MAX_SMS_CHARACTER_LENGTH), +const $LetterFiles = schemaFor()( + z.object({ + pdfTemplate: $FileDetails, + testDataCsv: $FileDetails.optional(), + proofs: z.array($FileDetails).optional(), }) ); -export const $CreateNhsAppTemplateSchema = schemaFor()( - $BaseCreateTemplateSchema.extend({ - templateType: z.literal(TemplateType.NHS_APP), +const $EmailProperties = schemaFor()( + z.object({ + subject: z.string().trim().min(1), + message: z.string().trim().min(1).max(MAX_EMAIL_CHARACTER_LENGTH), + }) +); + +const $NhsAppProperties = schemaFor()( + z.object({ message: z .string() .trim() @@ -44,37 +96,100 @@ export const $CreateNhsAppTemplateSchema = schemaFor()( }) ); -export const $CreateEmailTemplateSchema = schemaFor()( - $BaseCreateTemplateSchema.extend({ - subject: z.string().trim().min(1), - templateType: z.literal(TemplateType.EMAIL), - message: z.string().trim().min(1).max(MAX_EMAIL_CHARACTER_LENGTH), +const $SmsProperties = schemaFor()( + z.object({ + message: z.string().trim().min(1).max(MAX_SMS_CHARACTER_LENGTH), }) ); -export const $CreateTemplateSchema = z.discriminatedUnion('templateType', [ - $CreateSMSTemplateSchema, - $CreateNhsAppTemplateSchema, - $CreateEmailTemplateSchema, -]); +const $LetterProperties = schemaFor()( + z.object({ + letterType: z.enum(LETTER_TYPE_LIST), + language: z.enum(LANGUAGE_LIST), + files: $LetterFiles, + }) +); -const $UpdateTemplateFields = { - templateStatus: z.nativeEnum(TemplateStatus), -}; +export const $BaseTemplateSchema = schemaFor()( + z.object({ + name: z.string().trim().min(1), + templateType: z.enum(TEMPLATE_TYPE_LIST), + }) +); -export const $UpdateTemplateSchema = schemaFor()( +export const $SmsPropertiesWithType = $SmsProperties.merge( + z.object({ templateType: z.literal('SMS') }) +); +export const $NhsAppPropertiesWithType = $NhsAppProperties.merge( + z.object({ templateType: z.literal('NHS_APP') }) +); +export const $EmailPropertiesWithType = $EmailProperties.merge( + z.object({ templateType: z.literal('EMAIL') }) +); +export const $LetterPropertiesWithType = $LetterProperties.merge( + z.object({ templateType: z.literal('LETTER') }) +); + +export const $CreateTemplateSchema = schemaFor< + CreateTemplate, + ValidatedCreateTemplate +>()( z.discriminatedUnion('templateType', [ - $CreateSMSTemplateSchema.extend($UpdateTemplateFields), - $CreateNhsAppTemplateSchema.extend($UpdateTemplateFields), - $CreateEmailTemplateSchema.extend($UpdateTemplateFields), + $BaseTemplateSchema.merge($NhsAppPropertiesWithType), + $BaseTemplateSchema.merge($EmailPropertiesWithType), + $BaseTemplateSchema.merge($SmsPropertiesWithType), + $BaseTemplateSchema.merge($LetterPropertiesWithType), ]) ); -export const $TemplateDTOSchema = schemaFor()( - $BaseCreateTemplateSchema.extend({ - id: z.string(), - templateStatus: z.nativeEnum(TemplateStatus), +const $UpdateTemplateFields = z + .object({ + templateStatus: z.enum(TEMPLATE_STATUS_LIST), + }) + .merge($BaseTemplateSchema); + +export const $UpdateTemplateSchema = schemaFor< + UpdateTemplate, + ValidatedUpdateTemplate +>()( + z.discriminatedUnion('templateType', [ + $UpdateTemplateFields.merge($NhsAppPropertiesWithType), + $UpdateTemplateFields.merge($EmailPropertiesWithType), + $UpdateTemplateFields.merge($SmsPropertiesWithType), + $UpdateTemplateFields.merge($LetterPropertiesWithType), + ]) +); + +const $TemplateDtoFields = z + .object({ + id: z.string().trim().min(1), createdAt: z.string(), updatedAt: z.string(), }) + .merge($UpdateTemplateFields); + +export const $TemplateDtoSchema = schemaFor< + TemplateDto, + ValidatedTemplateDto +>()( + z.discriminatedUnion('templateType', [ + $TemplateDtoFields.merge($NhsAppPropertiesWithType), + $TemplateDtoFields.merge($EmailPropertiesWithType), + $TemplateDtoFields.merge($SmsPropertiesWithType), + $TemplateDtoFields.merge($LetterPropertiesWithType), + ]) ); + +export const isCreateTemplateValid = ( + input: unknown +): ValidatedCreateTemplate | undefined => + $CreateTemplateSchema.safeParse(input).data; + +export const isUpdateTemplateValid = ( + input: unknown +): ValidatedUpdateTemplate | undefined => + $UpdateTemplateSchema.safeParse(input).data; + +export const isTemplateDtoValid = ( + input: unknown +): ValidatedTemplateDto | undefined => $TemplateDtoSchema.safeParse(input).data; diff --git a/lambdas/backend-client/src/schemas/union-lists.ts b/lambdas/backend-client/src/schemas/union-lists.ts new file mode 100644 index 000000000..0e67f3770 --- /dev/null +++ b/lambdas/backend-client/src/schemas/union-lists.ts @@ -0,0 +1,88 @@ +/** + * Lists of generated string literal unions, for iteration and zod validation via z.enum. + * Ideally the generator would create the unions off an as const array and + * this wouldn't be needed, but that's not currently available. + * Note that there is a unit test against these to guard against duplicates + */ +import { + Language, + LetterType, + TemplateStatus, + TemplateType, + VirusScanStatus, +} from '../types/generated'; + +/** + * Returns an identity function which will fail to compile if 'array' + * doesn't contain all the cases of 'Union' + * + * @example + * const arrayOfFooBarBaz = arrayOfAll<'foo' | 'bar' | 'baz'>(); + * + * const a = arrayOfFooBarBaz(['foo', 'bar']); // does not compile + * const b = arrayOfFooBarBaz(['foo', 'bar', 'baz']); // compiles + */ +export function arrayOfAll() { + return ( + array: T & ([Union] extends [T[number]] ? unknown : 'Invalid') + ) => array; +} + +export const TEMPLATE_TYPE_LIST = arrayOfAll()([ + 'NHS_APP', + 'EMAIL', + 'SMS', + 'LETTER', +]); + +export const TEMPLATE_STATUS_LIST = arrayOfAll()([ + 'NOT_YET_SUBMITTED', + 'SUBMITTED', + 'DELETED', +]); + +export const LANGUAGE_LIST = arrayOfAll()([ + 'ar', + 'bg', + 'bn', + 'de', + 'el', + 'en', + 'es', + 'fa', + 'fr', + 'gu', + 'hi', + 'hu', + 'it', + 'ku', + 'lt', + 'lv', + 'ne', + 'pa', + 'pl', + 'pt', + 'ro', + 'ru', + 'sk', + 'so', + 'sq', + 'ta', + 'tr', + 'ur', + 'zh', +]); + +export const LETTER_TYPE_LIST = arrayOfAll()([ + 'x3', + 'q1', + 'q4', + 'x0', + 'x1', +]); + +export const VIRUS_SCAN_STATUS_LIST = arrayOfAll()([ + 'PENDING', + 'FAILED', + 'PASSED', +]); diff --git a/lambdas/backend-client/src/template-api-client.ts b/lambdas/backend-client/src/template-api-client.ts index 6a13e6234..3496eef36 100644 --- a/lambdas/backend-client/src/template-api-client.ts +++ b/lambdas/backend-client/src/template-api-client.ts @@ -3,7 +3,7 @@ import { CreateTemplate, Success, SuccessList, - TemplateDTO, + TemplateDto, UpdateTemplate, } from './types/generated'; import { Result } from './types/result'; @@ -20,7 +20,7 @@ export class TemplateApiClient implements ITemplateClient { this._client = createAxiosClient(token); } - async createTemplate(template: CreateTemplate): Promise> { + async createTemplate(template: CreateTemplate): Promise> { const response = await catchAxiosError( this._client.post('/v1/template', template) ); @@ -39,7 +39,7 @@ export class TemplateApiClient implements ITemplateClient { async updateTemplate( templateId: string, template: UpdateTemplate - ): Promise> { + ): Promise> { const response = await catchAxiosError( this._client.post(`/v1/template/${templateId}`, template) ); @@ -55,7 +55,7 @@ export class TemplateApiClient implements ITemplateClient { }; } - async getTemplate(templateId: string): Promise> { + async getTemplate(templateId: string): Promise> { const response = await catchAxiosError( this._client.get(`/v1/template/${templateId}`) ); @@ -71,7 +71,7 @@ export class TemplateApiClient implements ITemplateClient { }; } - async listTemplates(): Promise> { + async listTemplates(): Promise> { const response = await catchAxiosError( this._client.get('/v1/templates') ); diff --git a/lambdas/backend-client/src/types/generated/index.ts b/lambdas/backend-client/src/types/generated/index.ts index e7b3ba4bd..343d3c8f7 100644 --- a/lambdas/backend-client/src/types/generated/index.ts +++ b/lambdas/backend-client/src/types/generated/index.ts @@ -1,18 +1,2 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ - -export type { CreateTemplate } from './models/CreateTemplate'; -export type { Failure } from './models/Failure'; -export type { File } from './models/File'; -export type { Files } from './models/Files'; -export { Language } from './models/Language'; -export { LetterType } from './models/LetterType'; -export type { Success } from './models/Success'; -export type { SuccessList } from './models/SuccessList'; -export type { TemplateDTO } from './models/TemplateDTO'; -export { TemplateStatus } from './models/TemplateStatus'; -export { TemplateType } from './models/TemplateType'; -export type { UpdateTemplate } from './models/UpdateTemplate'; -export { VirusScanStatus } from './models/VirusScanStatus'; +// This file is auto-generated by @hey-api/openapi-ts +export * from './types.gen'; diff --git a/lambdas/backend-client/src/types/generated/models/CreateTemplate.ts b/lambdas/backend-client/src/types/generated/models/CreateTemplate.ts deleted file mode 100644 index 6fe1ba694..000000000 --- a/lambdas/backend-client/src/types/generated/models/CreateTemplate.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { TemplateType } from './TemplateType'; -export type CreateTemplate = { - templateType: TemplateType; - name: string; - message?: string; - subject?: string; -}; - diff --git a/lambdas/backend-client/src/types/generated/models/Failure.ts b/lambdas/backend-client/src/types/generated/models/Failure.ts deleted file mode 100644 index 58a433eab..000000000 --- a/lambdas/backend-client/src/types/generated/models/Failure.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type Failure = { - technicalMessage: string; - statusCode: number; - details?: any; -}; - diff --git a/lambdas/backend-client/src/types/generated/models/File.ts b/lambdas/backend-client/src/types/generated/models/File.ts deleted file mode 100644 index f7c7ca0e2..000000000 --- a/lambdas/backend-client/src/types/generated/models/File.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { VirusScanStatus } from './VirusScanStatus'; -export type File = { - fileName: string; - currentVersion?: string; - virusScanStatus: VirusScanStatus; -}; - diff --git a/lambdas/backend-client/src/types/generated/models/Files.ts b/lambdas/backend-client/src/types/generated/models/Files.ts deleted file mode 100644 index 9b269b871..000000000 --- a/lambdas/backend-client/src/types/generated/models/Files.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { File } from './File'; -export type Files = { - pdfTemplate?: File; - testDataCsv?: File; - proofs?: Array; -}; - diff --git a/lambdas/backend-client/src/types/generated/models/Language.ts b/lambdas/backend-client/src/types/generated/models/Language.ts deleted file mode 100644 index 7a9713e0b..000000000 --- a/lambdas/backend-client/src/types/generated/models/Language.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export enum Language { - AR = 'ar', - BG = 'bg', - BN = 'bn', - DE = 'de', - EL = 'el', - EN = 'en', - ES = 'es', - FA = 'fa', - FR = 'fr', - GU = 'gu', - HI = 'hi', - HU = 'hu', - IT = 'it', - KU = 'ku', - LT = 'lt', - LV = 'lv', - NE = 'ne', - PA = 'pa', - PL = 'pl', - PT = 'pt', - RO = 'ro', - RU = 'ru', - SK = 'sk', - SO = 'so', - SQ = 'sq', - TA = 'ta', - TR = 'tr', - UR = 'ur', - ZH = 'zh', -} diff --git a/lambdas/backend-client/src/types/generated/models/LetterType.ts b/lambdas/backend-client/src/types/generated/models/LetterType.ts deleted file mode 100644 index b3c959c9c..000000000 --- a/lambdas/backend-client/src/types/generated/models/LetterType.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export enum LetterType { - Q1 = 'q1', - Q4 = 'q4', - X0 = 'x0', - X1 = 'x1', - X3 = 'x3', -} diff --git a/lambdas/backend-client/src/types/generated/models/Success.ts b/lambdas/backend-client/src/types/generated/models/Success.ts deleted file mode 100644 index 5b2a8088c..000000000 --- a/lambdas/backend-client/src/types/generated/models/Success.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { TemplateDTO } from './TemplateDTO'; -export type Success = { - template: TemplateDTO; - statusCode: number; -}; - diff --git a/lambdas/backend-client/src/types/generated/models/SuccessList.ts b/lambdas/backend-client/src/types/generated/models/SuccessList.ts deleted file mode 100644 index 5403fd892..000000000 --- a/lambdas/backend-client/src/types/generated/models/SuccessList.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { TemplateDTO } from './TemplateDTO'; -export type SuccessList = { - templates: Array; - statusCode: number; -}; - diff --git a/lambdas/backend-client/src/types/generated/models/TemplateDTO.ts b/lambdas/backend-client/src/types/generated/models/TemplateDTO.ts deleted file mode 100644 index ecf6eca73..000000000 --- a/lambdas/backend-client/src/types/generated/models/TemplateDTO.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { Files } from './Files'; -import type { Language } from './Language'; -import type { LetterType } from './LetterType'; -import type { TemplateStatus } from './TemplateStatus'; -import type { TemplateType } from './TemplateType'; -export type TemplateDTO = { - id: string; - templateType: TemplateType; - templateStatus: TemplateStatus; - letterType?: LetterType; - language?: Language; - files?: Files; - name: string; - message?: string; - createdAt: string; - updatedAt: string; - subject?: string; -}; - diff --git a/lambdas/backend-client/src/types/generated/models/TemplateStatus.ts b/lambdas/backend-client/src/types/generated/models/TemplateStatus.ts deleted file mode 100644 index d6fde9834..000000000 --- a/lambdas/backend-client/src/types/generated/models/TemplateStatus.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export enum TemplateStatus { - NOT_YET_SUBMITTED = 'NOT_YET_SUBMITTED', - SUBMITTED = 'SUBMITTED', - DELETED = 'DELETED', -} diff --git a/lambdas/backend-client/src/types/generated/models/TemplateType.ts b/lambdas/backend-client/src/types/generated/models/TemplateType.ts deleted file mode 100644 index 55b40fd5b..000000000 --- a/lambdas/backend-client/src/types/generated/models/TemplateType.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export enum TemplateType { - NHS_APP = 'NHS_APP', - EMAIL = 'EMAIL', - SMS = 'SMS', - LETTER = 'LETTER', -} diff --git a/lambdas/backend-client/src/types/generated/models/UpdateTemplate.ts b/lambdas/backend-client/src/types/generated/models/UpdateTemplate.ts deleted file mode 100644 index 0624a2bdd..000000000 --- a/lambdas/backend-client/src/types/generated/models/UpdateTemplate.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { TemplateStatus } from './TemplateStatus'; -import type { TemplateType } from './TemplateType'; -export type UpdateTemplate = { - templateStatus: TemplateStatus; - name: string; - message?: string; - subject?: string; - /** - * This value will never be updated. It is used to determine the type of template being validated. - */ - readonly templateType: TemplateType; -}; - diff --git a/lambdas/backend-client/src/types/generated/models/VirusScanStatus.ts b/lambdas/backend-client/src/types/generated/models/VirusScanStatus.ts deleted file mode 100644 index b433dd725..000000000 --- a/lambdas/backend-client/src/types/generated/models/VirusScanStatus.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export enum VirusScanStatus { - PENDING = 'PENDING', - FAILED = 'FAILED', - PASSED = 'PASSED', -} diff --git a/lambdas/backend-client/src/types/generated/types.gen.ts b/lambdas/backend-client/src/types/generated/types.gen.ts new file mode 100644 index 000000000..7629ab306 --- /dev/null +++ b/lambdas/backend-client/src/types/generated/types.gen.ts @@ -0,0 +1,234 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type TemplateType = 'NHS_APP' | 'EMAIL' | 'SMS' | 'LETTER'; + +export type TemplateStatus = 'NOT_YET_SUBMITTED' | 'SUBMITTED' | 'DELETED'; + +export type Language = + | 'ar' + | 'bg' + | 'bn' + | 'de' + | 'el' + | 'en' + | 'es' + | 'fa' + | 'fr' + | 'gu' + | 'hi' + | 'hu' + | 'it' + | 'ku' + | 'lt' + | 'lv' + | 'ne' + | 'pa' + | 'pl' + | 'pt' + | 'ro' + | 'ru' + | 'sk' + | 'so' + | 'sq' + | 'ta' + | 'tr' + | 'ur' + | 'zh'; + +export type LetterType = 'q1' | 'q4' | 'x0' | 'x1' | 'x3'; + +export type VirusScanStatus = 'PENDING' | 'FAILED' | 'PASSED'; + +export type FileDetails = { + fileName: string; + currentVersion?: string; + virusScanStatus?: VirusScanStatus; +}; + +export type LetterFiles = { + pdfTemplate: FileDetails; + testDataCsv?: FileDetails; + proofs?: Array; +}; + +export type NhsAppProperties = { + message: string; +}; + +export type EmailProperties = { + message: string; + subject: string; +}; + +export type SmsProperties = { + message: string; +}; + +export type LetterProperties = { + letterType: LetterType; + language: Language; + files: LetterFiles; +}; + +export type BaseTemplate = { + templateType: TemplateType; + name: string; +}; + +export type CreateTemplate = BaseTemplate & + (NhsAppProperties | EmailProperties | SmsProperties | LetterProperties); + +export type UpdateTemplate = BaseTemplate & { + templateStatus: TemplateStatus; +} & (NhsAppProperties | EmailProperties | SmsProperties | LetterProperties); + +export type TemplateDto = BaseTemplate & { + id: string; + templateStatus: TemplateStatus; + createdAt: string; + updatedAt: string; +} & (NhsAppProperties | EmailProperties | SmsProperties | LetterProperties); + +export type Success = { + template: TemplateDto; + statusCode: number; +}; + +export type SuccessList = { + templates: Array; + statusCode: number; +}; + +export type Failure = { + technicalMessage: string; + statusCode: number; + details?: unknown; +}; + +export type GetV1TemplateByTemplateIdData = { + body?: never; + path: { + /** + * ID of template to return + */ + templateId: string; + }; + query?: never; + url: '/v1/template/{templateId}'; +}; + +export type GetV1TemplateByTemplateIdErrors = { + /** + * Error + */ + default: Failure; +}; + +export type GetV1TemplateByTemplateIdError = + GetV1TemplateByTemplateIdErrors[keyof GetV1TemplateByTemplateIdErrors]; + +export type GetV1TemplateByTemplateIdResponses = { + /** + * 200 response + */ + 200: Success; +}; + +export type GetV1TemplateByTemplateIdResponse = + GetV1TemplateByTemplateIdResponses[keyof GetV1TemplateByTemplateIdResponses]; + +export type PostV1TemplateByTemplateIdData = { + /** + * Template to update + */ + body: UpdateTemplate; + path: { + /** + * ID of template to update + */ + templateId: string; + }; + query?: never; + url: '/v1/template/{templateId}'; +}; + +export type PostV1TemplateByTemplateIdErrors = { + /** + * Error + */ + default: Failure; +}; + +export type PostV1TemplateByTemplateIdError = + PostV1TemplateByTemplateIdErrors[keyof PostV1TemplateByTemplateIdErrors]; + +export type PostV1TemplateByTemplateIdResponses = { + /** + * 200 response + */ + 200: Success; +}; + +export type PostV1TemplateByTemplateIdResponse = + PostV1TemplateByTemplateIdResponses[keyof PostV1TemplateByTemplateIdResponses]; + +export type PostV1TemplateData = { + /** + * Template to create + */ + body: CreateTemplate; + path?: never; + query?: never; + url: '/v1/template'; +}; + +export type PostV1TemplateErrors = { + /** + * Error + */ + default: Failure; +}; + +export type PostV1TemplateError = + PostV1TemplateErrors[keyof PostV1TemplateErrors]; + +export type PostV1TemplateResponses = { + /** + * 201 response + */ + 201: Success; +}; + +export type PostV1TemplateResponse = + PostV1TemplateResponses[keyof PostV1TemplateResponses]; + +export type GetV1TemplatesData = { + body?: never; + path?: never; + query?: never; + url: '/v1/templates'; +}; + +export type GetV1TemplatesErrors = { + /** + * Error + */ + default: Failure; +}; + +export type GetV1TemplatesError = + GetV1TemplatesErrors[keyof GetV1TemplatesErrors]; + +export type GetV1TemplatesResponses = { + /** + * 200 response + */ + 200: SuccessList; +}; + +export type GetV1TemplatesResponse = + GetV1TemplatesResponses[keyof GetV1TemplatesResponses]; + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; diff --git a/lambdas/backend-client/src/types/template-client.ts b/lambdas/backend-client/src/types/template-client.ts index 006724fe0..ab178ef3f 100644 --- a/lambdas/backend-client/src/types/template-client.ts +++ b/lambdas/backend-client/src/types/template-client.ts @@ -1,15 +1,15 @@ -import { TemplateDTO, CreateTemplate, UpdateTemplate } from './generated'; +import { TemplateDto, CreateTemplate, UpdateTemplate } from './generated'; import { Result } from './result'; export interface ITemplateClient { - createTemplate(template: CreateTemplate): Promise>; + createTemplate(template: CreateTemplate): Promise>; updateTemplate( templateId: string, template: UpdateTemplate - ): Promise>; + ): Promise>; - getTemplate(templateId: string): Promise>; + getTemplate(templateId: string): Promise>; - listTemplates(): Promise>; + listTemplates(): Promise>; } diff --git a/package-lock.json b/package-lock.json index e94fa603b..9d5039666 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "dependencies": { "@aws-amplify/adapter-nextjs": "^1.4.3", "@aws-amplify/ui-react": "^6.9.1", + "@aws-sdk/client-ses": "^3.637.0", "aws-amplify": "^6.12.3", "clsx": "^2.1.1", "date-fns": "^4.1.0", @@ -53,7 +54,7 @@ "jwt-decode": "^4.0.0", "markdown-it": "^13.0.1", "mimetext": "^3.0.24", - "next": "^15.2.1", + "next": "^15.1.7", "next-client-cookies": "^2.0.1", "nhs-notify-backend-client": "*", "nhs-notify-web-template-management-utils": "*", @@ -655,6 +656,7 @@ "name": "nhs-notify-backend-client", "version": "0.0.1", "dependencies": { + "@hey-api/openapi-ts": "^0.64.10", "axios": "^1.7.9", "axios-retry": "^4.5.0", "zod": "^3.24.1" @@ -5041,419 +5043,523 @@ "tslib": "^2.6.2" } }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.713.0.tgz", - "integrity": "sha512-qrgL/BILiRdv3npkJ88XxTeVPE/HPZ2gW9peyhYWP4fXCdPjpWYnAebbWBN6TqofiSlpP7xuoX8Xc1czwr90sg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.758.0.tgz", + "integrity": "sha512-cWBjZqY7SsFdTTSw3726DEPy3d7FfQ8qrw21RCukM/p3Ty42NWauHkqgxOmRygeiSY3ygHmWexc32B+4RXXqTw==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.713.0", - "@aws-sdk/middleware-host-header": "3.713.0", - "@aws-sdk/middleware-logger": "3.713.0", - "@aws-sdk/middleware-recursion-detection": "3.713.0", - "@aws-sdk/middleware-user-agent": "3.713.0", - "@aws-sdk/region-config-resolver": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@aws-sdk/util-endpoints": "3.713.0", - "@aws-sdk/util-user-agent-browser": "3.713.0", - "@aws-sdk/util-user-agent-node": "3.713.0", - "@smithy/config-resolver": "^3.0.13", - "@smithy/core": "^2.5.5", - "@smithy/fetch-http-handler": "^4.1.2", - "@smithy/hash-node": "^3.0.11", - "@smithy/invalid-dependency": "^3.0.11", - "@smithy/middleware-content-length": "^3.0.13", - "@smithy/middleware-endpoint": "^3.2.5", - "@smithy/middleware-retry": "^3.0.30", - "@smithy/middleware-serde": "^3.0.11", - "@smithy/middleware-stack": "^3.0.11", - "@smithy/node-config-provider": "^3.1.12", - "@smithy/node-http-handler": "^3.3.2", - "@smithy/protocol-http": "^4.1.8", - "@smithy/smithy-client": "^3.5.0", - "@smithy/types": "^3.7.2", - "@smithy/url-parser": "^3.0.11", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.30", - "@smithy/util-defaults-mode-node": "^3.0.30", - "@smithy/util-endpoints": "^2.1.7", - "@smithy/util-middleware": "^3.0.11", - "@smithy/util-retry": "^3.0.11", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-node": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.713.0.tgz", - "integrity": "sha512-B7N1Nte4Kqn8oaqLR2qnegLZjAgylYDAYNmXDY2+f1QNLF2D3emmWu8kLvBPIxT3wj23Mt177CPcBvMMGF2+aQ==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/client-sso": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.758.0.tgz", + "integrity": "sha512-BoGO6IIWrLyLxQG6txJw6RT2urmbtlwfggapNCrNPyYjlXpzTSJhBYjndg7TpDATFd0SXL0zm8y/tXsUXNkdYQ==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.713.0", - "@aws-sdk/credential-provider-node": "3.713.0", - "@aws-sdk/middleware-host-header": "3.713.0", - "@aws-sdk/middleware-logger": "3.713.0", - "@aws-sdk/middleware-recursion-detection": "3.713.0", - "@aws-sdk/middleware-user-agent": "3.713.0", - "@aws-sdk/region-config-resolver": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@aws-sdk/util-endpoints": "3.713.0", - "@aws-sdk/util-user-agent-browser": "3.713.0", - "@aws-sdk/util-user-agent-node": "3.713.0", - "@smithy/config-resolver": "^3.0.13", - "@smithy/core": "^2.5.5", - "@smithy/fetch-http-handler": "^4.1.2", - "@smithy/hash-node": "^3.0.11", - "@smithy/invalid-dependency": "^3.0.11", - "@smithy/middleware-content-length": "^3.0.13", - "@smithy/middleware-endpoint": "^3.2.5", - "@smithy/middleware-retry": "^3.0.30", - "@smithy/middleware-serde": "^3.0.11", - "@smithy/middleware-stack": "^3.0.11", - "@smithy/node-config-provider": "^3.1.12", - "@smithy/node-http-handler": "^3.3.2", - "@smithy/protocol-http": "^4.1.8", - "@smithy/smithy-client": "^3.5.0", - "@smithy/types": "^3.7.2", - "@smithy/url-parser": "^3.0.11", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.30", - "@smithy/util-defaults-mode-node": "^3.0.30", - "@smithy/util-endpoints": "^2.1.7", - "@smithy/util-middleware": "^3.0.11", - "@smithy/util-retry": "^3.0.11", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.713.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.713.0.tgz", - "integrity": "sha512-sjXy6z5bS1uspOdA0B4xQVri0XxdM24MkK0XhLoFoWAWoMlrORAMy+zW3YyU/vlsLckNYs7B4+j0P0MK35d+AQ==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/core": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.758.0.tgz", + "integrity": "sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg==", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.713.0", - "@aws-sdk/core": "3.713.0", - "@aws-sdk/credential-provider-node": "3.713.0", - "@aws-sdk/middleware-host-header": "3.713.0", - "@aws-sdk/middleware-logger": "3.713.0", - "@aws-sdk/middleware-recursion-detection": "3.713.0", - "@aws-sdk/middleware-user-agent": "3.713.0", - "@aws-sdk/region-config-resolver": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@aws-sdk/util-endpoints": "3.713.0", - "@aws-sdk/util-user-agent-browser": "3.713.0", - "@aws-sdk/util-user-agent-node": "3.713.0", - "@smithy/config-resolver": "^3.0.13", - "@smithy/core": "^2.5.5", - "@smithy/fetch-http-handler": "^4.1.2", - "@smithy/hash-node": "^3.0.11", - "@smithy/invalid-dependency": "^3.0.11", - "@smithy/middleware-content-length": "^3.0.13", - "@smithy/middleware-endpoint": "^3.2.5", - "@smithy/middleware-retry": "^3.0.30", - "@smithy/middleware-serde": "^3.0.11", - "@smithy/middleware-stack": "^3.0.11", - "@smithy/node-config-provider": "^3.1.12", - "@smithy/node-http-handler": "^3.3.2", - "@smithy/protocol-http": "^4.1.8", - "@smithy/smithy-client": "^3.5.0", - "@smithy/types": "^3.7.2", - "@smithy/url-parser": "^3.0.11", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.30", - "@smithy/util-defaults-mode-node": "^3.0.30", - "@smithy/util-endpoints": "^2.1.7", - "@smithy/util-middleware": "^3.0.11", - "@smithy/util-retry": "^3.0.11", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/types": "3.734.0", + "@smithy/core": "^3.1.5", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/signature-v4": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/core": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.713.0.tgz", - "integrity": "sha512-7Xq7LY6Q3eITvlqR1bP3cJu3RvTt4eb+WilK85eezPemi9589o6MNL0lu4nL0i+OdgPWw4x9z9WArRwXhHTreg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.758.0.tgz", + "integrity": "sha512-N27eFoRrO6MeUNumtNHDW9WOiwfd59LPXPqDrIa3kWL/s+fOKFHb9xIcF++bAwtcZnAxKkgpDCUP+INNZskE+w==", "dependencies": { - "@aws-sdk/types": "3.713.0", - "@smithy/core": "^2.5.5", - "@smithy/node-config-provider": "^3.1.12", - "@smithy/property-provider": "^3.1.11", - "@smithy/protocol-http": "^4.1.8", - "@smithy/signature-v4": "^4.2.4", - "@smithy/smithy-client": "^3.5.0", - "@smithy/types": "^3.7.2", - "@smithy/util-middleware": "^3.0.11", - "fast-xml-parser": "4.4.1", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.713.0.tgz", - "integrity": "sha512-B5+AbvN8qr5jmaiFdErtHlhdZtfMCP7JB1nwdi9LTsZLVP8BhFXnOYlIE7z6jq8GRkDBHybTxovKWzSfI0gg+w==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.758.0.tgz", + "integrity": "sha512-Xt9/U8qUCiw1hihztWkNeIR+arg6P+yda10OuCHX6kFVx3auTlU7+hCqs3UxqniGU4dguHuftf3mRpi5/GJ33Q==", "dependencies": { - "@aws-sdk/core": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@smithy/property-provider": "^3.1.11", - "@smithy/types": "^3.7.2", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/property-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.1.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.713.0.tgz", - "integrity": "sha512-VarD43CV9Bn+yNCZZb17xMiSjX/FRdU3wN2Aw/jP6ZE3/d87J9L7fxRRFmt4FAgLg35MJbooDGT9heycwg/WWw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.758.0.tgz", + "integrity": "sha512-cymSKMcP5d+OsgetoIZ5QCe1wnp2Q/tq+uIxVdh9MbfdBBEnl9Ecq6dH6VlYS89sp4QKuxHxkWXVnbXU3Q19Aw==", "dependencies": { - "@aws-sdk/core": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@smithy/fetch-http-handler": "^4.1.2", - "@smithy/node-http-handler": "^3.3.2", - "@smithy/property-provider": "^3.1.11", - "@smithy/protocol-http": "^4.1.8", - "@smithy/smithy-client": "^3.5.0", - "@smithy/types": "^3.7.2", - "@smithy/util-stream": "^3.3.2", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.758.0", + "@aws-sdk/credential-provider-web-identity": "3.758.0", + "@aws-sdk/nested-clients": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.713.0.tgz", - "integrity": "sha512-6oQuPjYONMCWTWhq5yV61OziX2KeU+nhTsdk+Zh4RiuaTkRRNTLnMAVA/VoG1FG8cnQbZJDFezh58nzlBTWHdw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.758.0.tgz", + "integrity": "sha512-+DaMv63wiq7pJrhIQzZYMn4hSarKiizDoJRvyR7WGhnn0oQ/getX9Z0VNCV3i7lIFoLNTb7WMmQ9k7+z/uD5EQ==", "dependencies": { - "@aws-sdk/core": "3.713.0", - "@aws-sdk/credential-provider-env": "3.713.0", - "@aws-sdk/credential-provider-http": "3.713.0", - "@aws-sdk/credential-provider-process": "3.713.0", - "@aws-sdk/credential-provider-sso": "3.713.0", - "@aws-sdk/credential-provider-web-identity": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@smithy/credential-provider-imds": "^3.2.8", - "@smithy/property-provider": "^3.1.11", - "@smithy/shared-ini-file-loader": "^3.1.12", - "@smithy/types": "^3.7.2", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-ini": "3.758.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.758.0", + "@aws-sdk/credential-provider-web-identity": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.713.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.713.0.tgz", - "integrity": "sha512-uIRHrhqcjcc+fUcid7Dey7mXRYfntPcA2xzebOnIK5hGBNwfQHpRG3RAlEB8K864psqW+j+XxvjoRHx9trL5Zg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.758.0.tgz", + "integrity": "sha512-AzcY74QTPqcbXWVgjpPZ3HOmxQZYPROIBz2YINF0OQk0MhezDWV/O7Xec+K1+MPGQO3qS6EDrUUlnPLjsqieHA==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.713.0", - "@aws-sdk/credential-provider-http": "3.713.0", - "@aws-sdk/credential-provider-ini": "3.713.0", - "@aws-sdk/credential-provider-process": "3.713.0", - "@aws-sdk/credential-provider-sso": "3.713.0", - "@aws-sdk/credential-provider-web-identity": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@smithy/credential-provider-imds": "^3.2.8", - "@smithy/property-provider": "^3.1.11", - "@smithy/shared-ini-file-loader": "^3.1.12", - "@smithy/types": "^3.7.2", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.713.0.tgz", - "integrity": "sha512-adVC8iz8uHmhVmZaYGj4Ab8rLz+hmnR6rOeMQ6wVbCAnWDb2qoahb+vLZ9sW9yMCVRqiDWeVK7lsa0MDRCM1sw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.758.0.tgz", + "integrity": "sha512-x0FYJqcOLUCv8GLLFDYMXRAQKGjoM+L0BG4BiHYZRDf24yQWFCAZsCQAYKo6XZYh2qznbsW6f//qpyJ5b0QVKQ==", "dependencies": { - "@aws-sdk/core": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@smithy/property-provider": "^3.1.11", - "@smithy/shared-ini-file-loader": "^3.1.12", - "@smithy/types": "^3.7.2", + "@aws-sdk/client-sso": "3.758.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/token-providers": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.713.0.tgz", - "integrity": "sha512-67QzqZJ6i04ZJVRB4WTUfU3QWJgr9fmv9JdqiLl63GTfz2KGOMwmojbi4INJ9isq4rDVUycdHsgl1Mhe6eDXJg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.758.0.tgz", + "integrity": "sha512-XGguXhBqiCXMXRxcfCAVPlMbm3VyJTou79r/3mxWddHWF0XbhaQiBIbUz6vobVTD25YQRbWSmSch7VA8kI5Lrw==", "dependencies": { - "@aws-sdk/client-sso": "3.713.0", - "@aws-sdk/core": "3.713.0", - "@aws-sdk/token-providers": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@smithy/property-provider": "^3.1.11", - "@smithy/shared-ini-file-loader": "^3.1.12", - "@smithy/types": "^3.7.2", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/nested-clients": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.713.0.tgz", - "integrity": "sha512-hz2Ru+xKYQupxyYb8KCCmH6qhzn4MSkocFbnBxevlQMYbugi80oaQtpmkj2ovrKCY2ktD4ufhC/8UZJMFGjAqw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.734.0.tgz", + "integrity": "sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==", "dependencies": { - "@aws-sdk/core": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@smithy/property-provider": "^3.1.11", - "@smithy/types": "^3.7.2", + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/middleware-logger": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.734.0.tgz", + "integrity": "sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.713.0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/endpoint-cache": { - "version": "3.723.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.723.0.tgz", - "integrity": "sha512-2+a4WXRc+07uiPR+zJiPGKSOWaNJQNqitkks+6Hhm/haTLJqNVTgY2OWDh2PXvwMNpKB+AlGdhE65Oy6NzUgXg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.734.0.tgz", + "integrity": "sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==", "dependencies": { - "mnemonist": "0.38.3", + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/lib-dynamodb": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.713.0.tgz", - "integrity": "sha512-bO4iEORF2RMTyM+hz5VubkkpMRIO+hlqhHykZdKYjftAdp0ZcUjCNNPdmsI16j+AJh8BZdCe92/1vLT+oWn2IA==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.758.0.tgz", + "integrity": "sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg==", "dependencies": { - "@aws-sdk/core": "3.713.0", - "@aws-sdk/util-dynamodb": "3.713.0", - "@smithy/core": "^2.5.5", - "@smithy/smithy-client": "^3.5.0", - "@smithy/types": "^3.7.2", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@smithy/core": "^3.1.5", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.734.0.tgz", + "integrity": "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/token-providers": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.758.0.tgz", + "integrity": "sha512-ckptN1tNrIfQUaGWm/ayW1ddG+imbKN7HHhjFdS4VfItsP0QQOB0+Ov+tpgb4MoNR4JaUghMIVStjIeHN2ks1w==", + "dependencies": { + "@aws-sdk/nested-clients": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/types": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.734.0.tgz", + "integrity": "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/util-endpoints": { + "version": "3.743.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.743.0.tgz", + "integrity": "sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "@smithy/util-endpoints": "^3.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.734.0.tgz", + "integrity": "sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.758.0.tgz", + "integrity": "sha512-A5EZw85V6WhoKMV2hbuFRvb9NPlxEErb4HPO6/SPXYY4QrjprIzScHxikqcWv1w4J3apB1wto9LPU3IMsYtfrw==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" }, "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.713.0" + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.723.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.723.0.tgz", - "integrity": "sha512-7AO4KEDTWCAQSgAv6KsR+VAo6OBPgyp4i071blwO1dohACGfNLBuvx/Ux914h7x6Aye8ViGjPtbb6wFJy5OCUw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", "dependencies": { - "@aws-sdk/endpoint-cache": "3.723.0", - "@aws-sdk/types": "3.723.0", - "@smithy/node-config-provider": "^4.0.0", - "@smithy/protocol-http": "^5.0.0", - "@smithy/types": "^4.0.0", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@aws-sdk/types": { - "version": "3.723.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.723.0.tgz", - "integrity": "sha512-LmK3kwiMZG1y5g3LGihT9mNkeNOmwEyPk6HGcJqh0wOSV4QpWoKu2epyKE4MLQNUUlz2kOVbVbOrwmI6ZcteuA==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/config-resolver": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.0.1.tgz", + "integrity": "sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==", "dependencies": { - "@smithy/types": "^4.0.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/node-config-provider": { + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/core": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.5.tgz", + "integrity": "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA==", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.1.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/credential-provider-imds": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", - "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.1.tgz", + "integrity": "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==", "dependencies": { + "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", - "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/property-provider": { + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/hash-node": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", - "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.1.tgz", + "integrity": "sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==", "dependencies": { "@smithy/types": "^4.1.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/protocol-http": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", - "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/invalid-dependency": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.1.tgz", + "integrity": "sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-content-length": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.1.tgz", + "integrity": "sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==", "dependencies": { + "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, @@ -5461,11 +5567,1594 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/shared-ini-file-loader": { + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.6.tgz", + "integrity": "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg==", + "dependencies": { + "@smithy/core": "^3.1.5", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-retry": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.0.7.tgz", + "integrity": "sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/service-error-classification": "^4.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/node-http-handler": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.3.tgz", + "integrity": "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA==", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/service-error-classification": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.1.tgz", + "integrity": "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==", + "dependencies": { + "@smithy/types": "^4.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/signature-v4": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.1.tgz", + "integrity": "sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-uri-escape": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/smithy-client": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.6.tgz", + "integrity": "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw==", + "dependencies": { + "@smithy/core": "^3.1.5", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.1.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-body-length-node": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", + "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-config-provider": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz", + "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.7.tgz", + "integrity": "sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-defaults-mode-node": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.7.tgz", + "integrity": "sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ==", + "dependencies": { + "@smithy/config-resolver": "^4.0.1", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-endpoints": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.1.tgz", + "integrity": "sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-retry": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.1.tgz", + "integrity": "sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==", + "dependencies": { + "@smithy/service-error-classification": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-stream": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.1.2.tgz", + "integrity": "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw==", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-waiter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.2.tgz", + "integrity": "sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.713.0.tgz", + "integrity": "sha512-qrgL/BILiRdv3npkJ88XxTeVPE/HPZ2gW9peyhYWP4fXCdPjpWYnAebbWBN6TqofiSlpP7xuoX8Xc1czwr90sg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.713.0", + "@aws-sdk/middleware-host-header": "3.713.0", + "@aws-sdk/middleware-logger": "3.713.0", + "@aws-sdk/middleware-recursion-detection": "3.713.0", + "@aws-sdk/middleware-user-agent": "3.713.0", + "@aws-sdk/region-config-resolver": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@aws-sdk/util-endpoints": "3.713.0", + "@aws-sdk/util-user-agent-browser": "3.713.0", + "@aws-sdk/util-user-agent-node": "3.713.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.713.0.tgz", + "integrity": "sha512-B7N1Nte4Kqn8oaqLR2qnegLZjAgylYDAYNmXDY2+f1QNLF2D3emmWu8kLvBPIxT3wj23Mt177CPcBvMMGF2+aQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.713.0", + "@aws-sdk/credential-provider-node": "3.713.0", + "@aws-sdk/middleware-host-header": "3.713.0", + "@aws-sdk/middleware-logger": "3.713.0", + "@aws-sdk/middleware-recursion-detection": "3.713.0", + "@aws-sdk/middleware-user-agent": "3.713.0", + "@aws-sdk/region-config-resolver": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@aws-sdk/util-endpoints": "3.713.0", + "@aws-sdk/util-user-agent-browser": "3.713.0", + "@aws-sdk/util-user-agent-node": "3.713.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.713.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.713.0.tgz", + "integrity": "sha512-sjXy6z5bS1uspOdA0B4xQVri0XxdM24MkK0XhLoFoWAWoMlrORAMy+zW3YyU/vlsLckNYs7B4+j0P0MK35d+AQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.713.0", + "@aws-sdk/core": "3.713.0", + "@aws-sdk/credential-provider-node": "3.713.0", + "@aws-sdk/middleware-host-header": "3.713.0", + "@aws-sdk/middleware-logger": "3.713.0", + "@aws-sdk/middleware-recursion-detection": "3.713.0", + "@aws-sdk/middleware-user-agent": "3.713.0", + "@aws-sdk/region-config-resolver": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@aws-sdk/util-endpoints": "3.713.0", + "@aws-sdk/util-user-agent-browser": "3.713.0", + "@aws-sdk/util-user-agent-node": "3.713.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.713.0.tgz", + "integrity": "sha512-7Xq7LY6Q3eITvlqR1bP3cJu3RvTt4eb+WilK85eezPemi9589o6MNL0lu4nL0i+OdgPWw4x9z9WArRwXhHTreg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.713.0", + "@smithy/core": "^2.5.5", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/signature-v4": "^4.2.4", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.713.0.tgz", + "integrity": "sha512-B5+AbvN8qr5jmaiFdErtHlhdZtfMCP7JB1nwdi9LTsZLVP8BhFXnOYlIE7z6jq8GRkDBHybTxovKWzSfI0gg+w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.713.0.tgz", + "integrity": "sha512-VarD43CV9Bn+yNCZZb17xMiSjX/FRdU3wN2Aw/jP6ZE3/d87J9L7fxRRFmt4FAgLg35MJbooDGT9heycwg/WWw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.713.0.tgz", + "integrity": "sha512-6oQuPjYONMCWTWhq5yV61OziX2KeU+nhTsdk+Zh4RiuaTkRRNTLnMAVA/VoG1FG8cnQbZJDFezh58nzlBTWHdw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.713.0", + "@aws-sdk/credential-provider-env": "3.713.0", + "@aws-sdk/credential-provider-http": "3.713.0", + "@aws-sdk/credential-provider-process": "3.713.0", + "@aws-sdk/credential-provider-sso": "3.713.0", + "@aws-sdk/credential-provider-web-identity": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.713.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.713.0.tgz", + "integrity": "sha512-uIRHrhqcjcc+fUcid7Dey7mXRYfntPcA2xzebOnIK5hGBNwfQHpRG3RAlEB8K864psqW+j+XxvjoRHx9trL5Zg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.713.0", + "@aws-sdk/credential-provider-http": "3.713.0", + "@aws-sdk/credential-provider-ini": "3.713.0", + "@aws-sdk/credential-provider-process": "3.713.0", + "@aws-sdk/credential-provider-sso": "3.713.0", + "@aws-sdk/credential-provider-web-identity": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.713.0.tgz", + "integrity": "sha512-adVC8iz8uHmhVmZaYGj4Ab8rLz+hmnR6rOeMQ6wVbCAnWDb2qoahb+vLZ9sW9yMCVRqiDWeVK7lsa0MDRCM1sw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.713.0.tgz", + "integrity": "sha512-67QzqZJ6i04ZJVRB4WTUfU3QWJgr9fmv9JdqiLl63GTfz2KGOMwmojbi4INJ9isq4rDVUycdHsgl1Mhe6eDXJg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.713.0", + "@aws-sdk/core": "3.713.0", + "@aws-sdk/token-providers": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.713.0.tgz", + "integrity": "sha512-hz2Ru+xKYQupxyYb8KCCmH6qhzn4MSkocFbnBxevlQMYbugi80oaQtpmkj2ovrKCY2ktD4ufhC/8UZJMFGjAqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.713.0" + } + }, + "node_modules/@aws-sdk/endpoint-cache": { + "version": "3.723.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.723.0.tgz", + "integrity": "sha512-2+a4WXRc+07uiPR+zJiPGKSOWaNJQNqitkks+6Hhm/haTLJqNVTgY2OWDh2PXvwMNpKB+AlGdhE65Oy6NzUgXg==", + "license": "Apache-2.0", + "dependencies": { + "mnemonist": "0.38.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/lib-dynamodb": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.713.0.tgz", + "integrity": "sha512-bO4iEORF2RMTyM+hz5VubkkpMRIO+hlqhHykZdKYjftAdp0ZcUjCNNPdmsI16j+AJh8BZdCe92/1vLT+oWn2IA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.713.0", + "@aws-sdk/util-dynamodb": "3.713.0", + "@smithy/core": "^2.5.5", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.713.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery": { + "version": "3.723.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.723.0.tgz", + "integrity": "sha512-7AO4KEDTWCAQSgAv6KsR+VAo6OBPgyp4i071blwO1dohACGfNLBuvx/Ux914h7x6Aye8ViGjPtbb6wFJy5OCUw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/endpoint-cache": "3.723.0", + "@aws-sdk/types": "3.723.0", + "@smithy/node-config-provider": "^4.0.0", + "@smithy/protocol-http": "^5.0.0", + "@smithy/types": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@aws-sdk/types": { + "version": "3.723.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.723.0.tgz", + "integrity": "sha512-LmK3kwiMZG1y5g3LGihT9mNkeNOmwEyPk6HGcJqh0wOSV4QpWoKu2epyKE4MLQNUUlz2kOVbVbOrwmI6ZcteuA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.713.0.tgz", + "integrity": "sha512-T1cRV9hs9WKwb2porR4QmW76ScCHqbdsrAAH+/2fR8IVRpFRU0BMnwrpSrRr7ujj6gqWQRQ97JLL+GpqpY3/ag==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.713.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.713.0.tgz", + "integrity": "sha512-mpTK7ost3lQt08YhTsf+C4uEAwg3Xu1LKxexlIZGXucCB6AqBKpP7e86XzpFFAtuRgEfTJVbW+Gqna8LM+yXoA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.713.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.713.0.tgz", + "integrity": "sha512-6vgQw92yvKR8MNsSXJE4seZhMSPVuyuBLuX81DWPr1pak/RpuUzn96CSYCTAYoCtf5vJgNseIcPfKQLkRYmBzg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.713.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.713.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.713.0.tgz", + "integrity": "sha512-MYg2N9EUXQ4Kf0+rk7qCHPLbxRPAeWrxJXp8xDxSBiDPf0hcbCtT+cXXB6qWVrnp+OuacoUDrur3h604sp47Aw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.713.0", + "@aws-sdk/types": "3.713.0", + "@aws-sdk/util-endpoints": "3.713.0", + "@smithy/core": "^2.5.5", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.758.0.tgz", + "integrity": "sha512-YZ5s7PSvyF3Mt2h1EQulCG93uybprNGbBkPmVuy/HMMfbFTt4iL3SbKjxqvOZelm86epFfj7pvK7FliI2WOEcg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/core": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.758.0.tgz", + "integrity": "sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/core": "^3.1.5", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/signature-v4": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.734.0.tgz", + "integrity": "sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-logger": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.734.0.tgz", + "integrity": "sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.734.0.tgz", + "integrity": "sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.758.0.tgz", + "integrity": "sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg==", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@smithy/core": "^3.1.5", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.734.0.tgz", + "integrity": "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/types": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.734.0.tgz", + "integrity": "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-endpoints": { + "version": "3.743.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.743.0.tgz", + "integrity": "sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "@smithy/util-endpoints": "^3.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.734.0.tgz", + "integrity": "sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.758.0.tgz", + "integrity": "sha512-A5EZw85V6WhoKMV2hbuFRvb9NPlxEErb4HPO6/SPXYY4QrjprIzScHxikqcWv1w4J3apB1wto9LPU3IMsYtfrw==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/config-resolver": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.0.1.tgz", + "integrity": "sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/core": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.5.tgz", + "integrity": "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA==", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.1.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/credential-provider-imds": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.1.tgz", + "integrity": "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/hash-node": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.1.tgz", + "integrity": "sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/invalid-dependency": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.1.tgz", + "integrity": "sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-content-length": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.1.tgz", + "integrity": "sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.6.tgz", + "integrity": "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg==", + "dependencies": { + "@smithy/core": "^3.1.5", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-retry": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.0.7.tgz", + "integrity": "sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/service-error-classification": "^4.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.3.tgz", + "integrity": "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA==", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/service-error-classification": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.1.tgz", + "integrity": "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==", + "dependencies": { + "@smithy/types": "^4.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/signature-v4": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.1.tgz", + "integrity": "sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-uri-escape": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/smithy-client": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.6.tgz", + "integrity": "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw==", + "dependencies": { + "@smithy/core": "^3.1.5", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.1.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-body-length-node": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", + "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-config-provider": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz", + "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.7.tgz", + "integrity": "sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-defaults-mode-node": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.7.tgz", + "integrity": "sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ==", + "dependencies": { + "@smithy/config-resolver": "^4.0.1", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-endpoints": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.1.tgz", + "integrity": "sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-middleware": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", - "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -5474,78 +7163,58 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-retry": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.1.tgz", + "integrity": "sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==", "dependencies": { + "@smithy/service-error-classification": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.713.0.tgz", - "integrity": "sha512-T1cRV9hs9WKwb2porR4QmW76ScCHqbdsrAAH+/2fR8IVRpFRU0BMnwrpSrRr7ujj6gqWQRQ97JLL+GpqpY3/ag==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.713.0", - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.713.0.tgz", - "integrity": "sha512-mpTK7ost3lQt08YhTsf+C4uEAwg3Xu1LKxexlIZGXucCB6AqBKpP7e86XzpFFAtuRgEfTJVbW+Gqna8LM+yXoA==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-stream": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.1.2.tgz", + "integrity": "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw==", "dependencies": { - "@aws-sdk/types": "3.713.0", - "@smithy/types": "^3.7.2", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.713.0.tgz", - "integrity": "sha512-6vgQw92yvKR8MNsSXJE4seZhMSPVuyuBLuX81DWPr1pak/RpuUzn96CSYCTAYoCtf5vJgNseIcPfKQLkRYmBzg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", "dependencies": { - "@aws-sdk/types": "3.713.0", - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.713.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.713.0.tgz", - "integrity": "sha512-MYg2N9EUXQ4Kf0+rk7qCHPLbxRPAeWrxJXp8xDxSBiDPf0hcbCtT+cXXB6qWVrnp+OuacoUDrur3h604sp47Aw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", "dependencies": { - "@aws-sdk/core": "3.713.0", - "@aws-sdk/types": "3.713.0", - "@aws-sdk/util-endpoints": "3.713.0", - "@smithy/core": "^2.5.5", - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", + "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/region-config-resolver": { @@ -8297,6 +9966,53 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@hey-api/json-schema-ref-parser": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@hey-api/json-schema-ref-parser/-/json-schema-ref-parser-1.0.2.tgz", + "integrity": "sha512-F6LSkttZcT/XiX3ydeDqTY3uRN3BLJMwyMTk4kg/ichZlKUp3+3Odv0WokSmXGSoZGTW/N66FROMYAm5NPdJlA==", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/hey-api" + } + }, + "node_modules/@hey-api/openapi-ts": { + "version": "0.64.10", + "resolved": "https://registry.npmjs.org/@hey-api/openapi-ts/-/openapi-ts-0.64.10.tgz", + "integrity": "sha512-mTTD4DtOt68OmrZ6VXM4+sCma+JxhqDjiqdaUCpLIS8yWNWAmgBCRS5LE3i8AS8HUN1dsCetTGFAIUT2rElDVg==", + "dependencies": { + "@hey-api/json-schema-ref-parser": "1.0.2", + "c12": "2.0.1", + "commander": "13.0.0", + "handlebars": "4.7.8" + }, + "bin": { + "openapi-ts": "bin/index.cjs" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=22.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/hey-api" + }, + "peerDependencies": { + "typescript": "^5.5.3" + } + }, + "node_modules/@hey-api/openapi-ts/node_modules/commander": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.0.0.tgz", + "integrity": "sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==", + "engines": { + "node": ">=18" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -9231,6 +10947,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -13378,6 +15099,59 @@ "node": ">= 0.8" } }, + "node_modules/c12": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/c12/-/c12-2.0.1.tgz", + "integrity": "sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==", + "dependencies": { + "chokidar": "^4.0.1", + "confbox": "^0.1.7", + "defu": "^6.1.4", + "dotenv": "^16.4.5", + "giget": "^1.2.3", + "jiti": "^2.3.0", + "mlly": "^1.7.1", + "ohash": "^1.1.4", + "pathe": "^1.1.2", + "perfect-debounce": "^1.0.0", + "pkg-types": "^1.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/c12/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -13643,6 +15417,14 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0.0" } }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dependencies": { + "consola": "^3.2.3" + } + }, "node_modules/cjs-module-lexer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", @@ -13878,11 +15660,24 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==" + }, "node_modules/confusing-browser-globals": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" }, + "node_modules/consola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", + "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/constructs": { "version": "10.4.2", "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.4.2.tgz", @@ -14292,6 +16087,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==" + }, "node_modules/degenerator": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", @@ -14326,6 +16126,11 @@ "node": ">=6" } }, + "node_modules/destr": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.3.tgz", + "integrity": "sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==" + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -14478,6 +16283,17 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -16451,6 +18267,33 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -16666,6 +18509,28 @@ "node": ">= 14" } }, + "node_modules/giget": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.5.tgz", + "integrity": "sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug==", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.5.4", + "pathe": "^2.0.3", + "tar": "^6.2.1" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/giget/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" + }, "node_modules/git-node-fs": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/git-node-fs/-/git-node-fs-1.0.0.tgz", @@ -18563,6 +20428,14 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/joi": { "version": "17.13.3", "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", @@ -19461,6 +21334,34 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -19470,7 +21371,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -19485,6 +21385,22 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, + "node_modules/mlly": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" + } + }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" + }, "node_modules/mnemonist": { "version": "0.38.3", "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", @@ -19994,6 +21910,11 @@ } } }, + "node_modules/node-fetch-native": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", + "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==" + }, "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -20128,6 +22049,30 @@ "dev": true, "license": "MIT" }, + "node_modules/nypm": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.5.4.tgz", + "integrity": "sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA==", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "tinyexec": "^0.3.2", + "ufo": "^1.5.4" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/nypm/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -20244,6 +22189,11 @@ "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==", "license": "MIT" }, + "node_modules/ohash": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.6.tgz", + "integrity": "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg==" + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -20712,11 +22662,21 @@ "node": ">=16" } }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==" + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -20858,6 +22818,21 @@ "node": ">=8" } }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" + }, "node_modules/playwright": { "version": "1.49.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", @@ -21652,6 +23627,15 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, "node_modules/react": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", @@ -23351,6 +25335,22 @@ "node": ">=6" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tar-fs": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", @@ -23379,6 +25379,27 @@ "node": ">=6" } }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/tcomb": { "version": "3.2.29", "resolved": "https://registry.npmjs.org/tcomb/-/tcomb-3.2.29.tgz", @@ -23460,6 +25481,11 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -24267,7 +26293,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", - "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -24283,6 +26308,11 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "license": "MIT" }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==" + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", @@ -25254,7 +27284,6 @@ "eslint-plugin-playwright": "^2.2.0", "generate-password": "^1.7.1", "glob": "^11.0.1", - "nhs-notify-backend-client": "*", "nhs-notify-web-template-management-util-backend-config": "*" } }, diff --git a/tests/accessibility/pa11y-setup.ts b/tests/accessibility/pa11y-setup.ts index 2e94ae696..3da8c7453 100644 --- a/tests/accessibility/pa11y-setup.ts +++ b/tests/accessibility/pa11y-setup.ts @@ -4,16 +4,7 @@ import { TestUserClient } from './test-user-client'; import { generate } from 'generate-password'; import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; import { PutCommand, DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb'; -import { - LetterTemplate, - TemplateType, -} from 'nhs-notify-web-template-management-utils'; -import { - Language, - LetterType, - TemplateStatus, - VirusScanStatus, -} from 'nhs-notify-backend-client'; +import { LetterTemplate } from 'nhs-notify-web-template-management-utils'; const setup = async () => { const testEmail = `nhs-notify-automated-test-accessibility-test-${randomUUID()}@nhs.net`; @@ -44,25 +35,26 @@ const setup = async () => { TableName: process.env.TEMPLATES_TABLE_NAME, Item: { owner: userId, - templateType: TemplateType.LETTER, + templateType: 'LETTER', id: templateId, - letterType: LetterType.X0, - language: Language.EN, + letterType: 'x0', + language: 'en', createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), name: 'pa11y_letter', files: { pdfTemplate: { fileName: 'template.pdf', currentVersion: randomUUID(), - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, testDataCsv: { fileName: 'test-data.csv', currentVersion: randomUUID(), - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', } satisfies LetterTemplate & { owner: string }, }) ); diff --git a/tests/test-team/helpers/factories/template-api-payload-factory.ts b/tests/test-team/helpers/factories/template-api-payload-factory.ts index 832700bda..8a9782d7f 100644 --- a/tests/test-team/helpers/factories/template-api-payload-factory.ts +++ b/tests/test-team/helpers/factories/template-api-payload-factory.ts @@ -1,21 +1,5 @@ import { faker } from '@faker-js/faker'; -import { - CreateTemplate, - TemplateStatus, - TemplateType, - UpdateTemplate, -} from 'nhs-notify-backend-client'; - -type CreateTemplatePayload = Omit & { - templateType: string; -}; -type UpdateTemplatePayload = Omit< - UpdateTemplate, - 'templateType' | 'templateStatus' -> & { - templateType: string; - templateStatus: string; -}; +import { CreateTemplatePayload, UpdateTemplatePayload } from '../types'; type TemplatePayload = CreateTemplatePayload | UpdateTemplatePayload; @@ -41,7 +25,7 @@ type Output> = T & const createPayloadData = (templateType: unknown) => ({ name: faker.word.noun(), message: faker.word.words(5), - ...(templateType === TemplateType.EMAIL && { + ...(templateType === 'EMAIL' && { subject: faker.word.interjection(), }), }); @@ -66,7 +50,7 @@ export const TemplateAPIPayloadFactory = { template: T ): Output { return { - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', ...createPayloadData(template.templateType), ...template, }; diff --git a/tests/test-team/helpers/factories/template-factory.ts b/tests/test-team/helpers/factories/template-factory.ts index 3a9887cf2..e30c3fc22 100644 --- a/tests/test-team/helpers/factories/template-factory.ts +++ b/tests/test-team/helpers/factories/template-factory.ts @@ -1,23 +1,19 @@ -import { - Language, - LetterType, - VirusScanStatus, -} from 'nhs-notify-backend-client'; -import { Template, TemplateStatus, TemplateType } from '../types'; +import { Template } from '../types'; import { randomUUID } from 'node:crypto'; export const TemplateFactory = { createEmailTemplate: ( id: string, owner: string, - name: string = '' + name: string = 'test' ): Template => { return TemplateFactory.create({ id, owner, name, - templateType: TemplateType.EMAIL, - subject: '', + templateType: 'EMAIL', + message: 'test-message', + subject: 'test-subject', }); }, @@ -25,8 +21,9 @@ export const TemplateFactory = { return TemplateFactory.create({ id, owner, - name: '', - templateType: TemplateType.SMS, + name: 'test', + templateType: 'SMS', + message: 'test-message', }); }, @@ -34,8 +31,9 @@ export const TemplateFactory = { return TemplateFactory.create({ id, owner, - name: '', - templateType: TemplateType.NHS_APP, + name: 'test-name', + templateType: 'NHS_APP', + message: 'test-message', }); }, @@ -44,19 +42,19 @@ export const TemplateFactory = { id, owner, name, - templateType: TemplateType.LETTER, - letterType: LetterType.X0, - language: Language.EN, + templateType: 'LETTER', + letterType: 'x0', + language: 'en', files: { pdfTemplate: { fileName: 'file.pdf', currentVersion: randomUUID(), - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, testDataCsv: { fileName: 'test-data.csv', currentVersion: randomUUID(), - virusScanStatus: VirusScanStatus.PENDING, + virusScanStatus: 'PENDING', }, }, }); @@ -71,11 +69,10 @@ export const TemplateFactory = { } ): Template => { return { - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', version: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - message: '', ...template, }; }, diff --git a/tests/test-team/helpers/types.ts b/tests/test-team/helpers/types.ts index 11e8a74cc..96743f826 100644 --- a/tests/test-team/helpers/types.ts +++ b/tests/test-team/helpers/types.ts @@ -1,59 +1,53 @@ -import { - Language, - LetterType, - VirusScanStatus, -} from 'nhs-notify-backend-client'; - -export enum TemplateType { - NHS_APP = 'NHS_APP', - SMS = 'SMS', - EMAIL = 'EMAIL', - LETTER = 'LETTER', -} - -export const templateTypeDisplayMappings = (type: TemplateType) => - ({ - [TemplateType.NHS_APP]: 'NHS App message', - [TemplateType.SMS]: 'Text message (SMS)', - [TemplateType.EMAIL]: 'Email', - [TemplateType.LETTER]: 'Letter', - })[type]; - -export const templateTypeToUrlTextMappings = (type: TemplateType) => - ({ - [TemplateType.NHS_APP]: 'nhs-app', - [TemplateType.SMS]: 'text-message', - [TemplateType.EMAIL]: 'email', - [TemplateType.LETTER]: 'letter', - })[type]; +export const templateTypeDisplayMappings: Record = { + NHS_APP: 'NHS App message', + SMS: 'Text message (SMS)', + EMAIL: 'Email', + LETTER: 'Letter', +}; -export enum TemplateStatus { - NOT_YET_SUBMITTED = 'NOT_YET_SUBMITTED', - SUBMITTED = 'SUBMITTED', -} +export const templateTypeToUrlTextMappings: Record = { + NHS_APP: 'nhs-app', + SMS: 'text-message', + EMAIL: 'email', + LETTER: 'letter', +}; type File = { fileName: string; currentVersion?: string; - virusScanStatus: VirusScanStatus; + virusScanStatus: string; }; -export type Template = { - createdAt: string; - updatedAt: string; - id: string; - version: number; - name: string; - message: string; +type TypeSpecificProperties = { + message?: string; subject?: string; - templateType: TemplateType; - templateStatus: TemplateStatus; - letterType?: LetterType; - language?: Language; + letterType?: string; + language?: string; files?: { pdfTemplate?: File; testDataCsv: File; proofs?: File[]; }; +}; + +export type CreateTemplatePayload = TypeSpecificProperties & { + name: string; + templateType: string; +}; + +export type UpdateTemplatePayload = TypeSpecificProperties & { + name: string; + templateType: string; + templateStatus: string; +}; + +export type Template = TypeSpecificProperties & { + createdAt: string; + updatedAt: string; + id: string; + version: number; + name: string; + templateType: string; + templateStatus: string; owner: string; }; diff --git a/tests/test-team/package.json b/tests/test-team/package.json index 9f3867307..831574158 100644 --- a/tests/test-team/package.json +++ b/tests/test-team/package.json @@ -25,7 +25,6 @@ "eslint-plugin-playwright": "^2.2.0", "generate-password": "^1.7.1", "glob": "^11.0.1", - "nhs-notify-backend-client": "*", "nhs-notify-web-template-management-util-backend-config": "*" } } diff --git a/tests/test-team/template-mgmt-api-tests/create-template.api.spec.ts b/tests/test-team/template-mgmt-api-tests/create-template.api.spec.ts index 75482fac7..095ede1a8 100644 --- a/tests/test-team/template-mgmt-api-tests/create-template.api.spec.ts +++ b/tests/test-team/template-mgmt-api-tests/create-template.api.spec.ts @@ -48,7 +48,7 @@ test.describe('POST /v1/template', () => { technicalMessage: 'Request failed validation', details: { templateType: - "Invalid discriminator value. Expected 'SMS' | 'NHS_APP' | 'EMAIL'", + "Invalid discriminator value. Expected 'NHS_APP' | 'EMAIL' | 'SMS' | 'LETTER'", }, }); }); @@ -75,7 +75,7 @@ test.describe('POST /v1/template', () => { technicalMessage: 'Request failed validation', details: { templateType: - "Invalid discriminator value. Expected 'SMS' | 'NHS_APP' | 'EMAIL'", + "Invalid discriminator value. Expected 'NHS_APP' | 'EMAIL' | 'SMS' | 'LETTER'", }, }); }); diff --git a/tests/test-team/template-mgmt-api-tests/update-template.api.spec.ts b/tests/test-team/template-mgmt-api-tests/update-template.api.spec.ts index d0f1f7c5b..637018aee 100644 --- a/tests/test-team/template-mgmt-api-tests/update-template.api.spec.ts +++ b/tests/test-team/template-mgmt-api-tests/update-template.api.spec.ts @@ -128,7 +128,7 @@ test.describe('POST /v1/template/:templateId', () => { technicalMessage: 'Request failed validation', details: { templateType: - "Invalid discriminator value. Expected 'SMS' | 'NHS_APP' | 'EMAIL'", + "Invalid discriminator value. Expected 'NHS_APP' | 'EMAIL' | 'SMS' | 'LETTER'", }, }); }); @@ -171,7 +171,7 @@ test.describe('POST /v1/template/:templateId', () => { technicalMessage: 'Request failed validation', details: { templateType: - "Invalid discriminator value. Expected 'SMS' | 'NHS_APP' | 'EMAIL'", + "Invalid discriminator value. Expected 'NHS_APP' | 'EMAIL' | 'SMS' | 'LETTER'", }, }); }); diff --git a/tests/test-team/template-mgmt-component-tests/email/template-mgmt-edit-email-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/email/template-mgmt-edit-email-page.component.spec.ts index d99234099..09a9cc2df 100644 --- a/tests/test-team/template-mgmt-component-tests/email/template-mgmt-edit-email-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/email/template-mgmt-edit-email-page.component.spec.ts @@ -9,7 +9,6 @@ import { assertNotifyBannerLink, assertSkipToMainContent, } from '../template-mgmt-common.steps'; -import { TemplateType } from '../../helpers/types'; import { createAuthHelper, TestUserId, @@ -17,7 +16,7 @@ import { function createTemplates(owner: string) { return { - empty: TemplateFactory.createEmailTemplate('empty-email-template', owner), + valid: TemplateFactory.createEmailTemplate('valid-email-template', owner), submit: TemplateFactory.createEmailTemplate('submit-email-template', owner), submitAndReturn: TemplateFactory.createEmailTemplate( 'submit-and-return-create-email-template', @@ -29,7 +28,7 @@ function createTemplates(owner: string) { ), noEmailTemplateType: TemplateFactory.create({ id: 'no-email-template-type-template', - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', name: 'no-email-template-type-template', owner, }), @@ -65,10 +64,10 @@ test.describe('Edit Email message template Page', () => { }) => { const editEmailTemplatePage = new TemplateMgmtEditEmailPage(page); - await editEmailTemplatePage.loadPage(templates.empty.id); + await editEmailTemplatePage.loadPage(templates.valid.id); await expect(page).toHaveURL( - `${baseURL}/templates/edit-email-template/${templates.empty.id}` + `${baseURL}/templates/edit-email-template/${templates.valid.id}` ); await expect(editEmailTemplatePage.pageHeader).toHaveText( @@ -80,7 +79,7 @@ test.describe('Edit Email message template Page', () => { test('common page tests', async ({ page, baseURL }) => { const props = { page: new TemplateMgmtEditEmailPage(page), - id: templates.empty.id, + id: templates.valid.id, baseURL, }; @@ -128,7 +127,7 @@ test.describe('Edit Email message template Page', () => { }) => { const editEmailTemplatePage = new TemplateMgmtEditEmailPage(page); - await editEmailTemplatePage.loadPage(templates.empty.id); + await editEmailTemplatePage.loadPage(templates.valid.id); await editEmailTemplatePage.messageFormatting.assertDetailsOpen([ editEmailTemplatePage.messageFormatting.lineBreaksAndParagraphs, @@ -158,7 +157,7 @@ test.describe('Edit Email message template Page', () => { baseURL, }) => { const editTemplatePage = new TemplateMgmtEditEmailPage(page); - await editTemplatePage.loadPage('empty-email-template'); + await editTemplatePage.loadPage('valid-email-template'); const newTabPromise = page.waitForEvent('popup'); await page.getByRole('link', { name }).click(); const newTab = await newTabPromise; @@ -171,7 +170,7 @@ test.describe('Edit Email message template Page', () => { }) => { const editEmailTemplatePage = new TemplateMgmtEditEmailPage(page); - await editEmailTemplatePage.loadPage(templates.empty.id); + await editEmailTemplatePage.loadPage(templates.valid.id); await editEmailTemplatePage.namingYourTemplate.click({ position: { x: 0, y: 0 }, @@ -237,7 +236,13 @@ test.describe('Edit Email message template Page', () => { }) => { const editEmailTemplatePage = new TemplateMgmtEditEmailPage(page); - await editEmailTemplatePage.loadPage(templates.empty.id); + await editEmailTemplatePage.loadPage(templates.valid.id); + + await editEmailTemplatePage.nameInput.fill(''); + + await editEmailTemplatePage.subjectLineInput.fill(''); + + await editEmailTemplatePage.messageTextArea.fill(''); await editEmailTemplatePage.clickSaveAndPreviewButton(); @@ -273,7 +278,9 @@ test.describe('Edit Email message template Page', () => { const editEmailTemplatePage = new TemplateMgmtEditEmailPage(page); - await editEmailTemplatePage.loadPage(templates.empty.id); + await editEmailTemplatePage.loadPage(templates.valid.id); + + await editEmailTemplatePage.nameInput.fill(''); await editEmailTemplatePage.subjectLineInput.fill( 'template-subject-line' @@ -301,10 +308,12 @@ test.describe('Edit Email message template Page', () => { const editEmailTemplatePage = new TemplateMgmtEditEmailPage(page); - await editEmailTemplatePage.loadPage(templates.empty.id); + await editEmailTemplatePage.loadPage(templates.valid.id); await editEmailTemplatePage.nameInput.fill('template-name'); + await editEmailTemplatePage.subjectLineInput.fill(''); + await editEmailTemplatePage.messageTextArea.fill('template-message'); await editEmailTemplatePage.clickSaveAndPreviewButton(); @@ -328,7 +337,7 @@ test.describe('Edit Email message template Page', () => { const editEmailTemplatePage = new TemplateMgmtEditEmailPage(page); - await editEmailTemplatePage.loadPage(templates.empty.id); + await editEmailTemplatePage.loadPage(templates.valid.id); await editEmailTemplatePage.nameInput.fill('template-name'); @@ -336,6 +345,8 @@ test.describe('Edit Email message template Page', () => { 'template-subject-line' ); + await editEmailTemplatePage.messageTextArea.fill(''); + await editEmailTemplatePage.clickSaveAndPreviewButton(); const emailMessageErrorLink = editEmailTemplatePage.errorSummary.locator( diff --git a/tests/test-team/template-mgmt-component-tests/email/template-mgmt-preview-email-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/email/template-mgmt-preview-email-page.component.spec.ts index 7d64c6f97..3359a413c 100644 --- a/tests/test-team/template-mgmt-component-tests/email/template-mgmt-preview-email-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/email/template-mgmt-preview-email-page.component.spec.ts @@ -12,7 +12,7 @@ import { assertNotifyBannerLink, assertSkipToMainContent, } from '../template-mgmt-common.steps'; -import { TemplateType, Template, TemplateStatus } from '../../helpers/types'; +import { Template } from '../../helpers/types'; import { createAuthHelper, TestUserId, @@ -26,8 +26,8 @@ async function createTemplates() { version: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', owner: user.userId, } as Template, valid: { diff --git a/tests/test-team/template-mgmt-component-tests/email/template-mgmt-view-submitted-email-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/email/template-mgmt-view-submitted-email-page.component.spec.ts index e930a2b2e..8ded6031b 100644 --- a/tests/test-team/template-mgmt-component-tests/email/template-mgmt-view-submitted-email-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/email/template-mgmt-view-submitted-email-page.component.spec.ts @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test'; import { TemplateStorageHelper } from '../../helpers/db/template-storage-helper'; import { TemplateMgmtViewSubmittedEmailPage } from '../../pages/email/template-mgmt-view-submitted-email-page'; import { TemplateFactory } from '../../helpers/factories/template-factory'; -import { Template, TemplateStatus } from '../../helpers/types'; +import { Template } from '../../helpers/types'; import { assertFooterLinks, assertSignOutLink, @@ -28,7 +28,7 @@ function createTemplates(owner: string) { name: 'test-template-email', subject: 'test-template-subject-line', message: 'test-template-message', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED', }, invalid: { ...TemplateFactory.createEmailTemplate( @@ -38,7 +38,7 @@ function createTemplates(owner: string) { name: 'test-template-email', subject: 'test-template-subject-line', message: 'test-template-message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', }, }; } diff --git a/tests/test-team/template-mgmt-component-tests/letter/template-mgmt-preview-letter-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/letter/template-mgmt-preview-letter-page.component.spec.ts index b05028c46..16a3a49e1 100644 --- a/tests/test-team/template-mgmt-component-tests/letter/template-mgmt-preview-letter-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/letter/template-mgmt-preview-letter-page.component.spec.ts @@ -11,7 +11,7 @@ import { assertNotifyBannerLink, assertSkipToMainContent, } from '../template-mgmt-common.steps'; -import { Template, TemplateType, TemplateStatus } from '../../helpers/types'; +import { Template } from '../../helpers/types'; import { createAuthHelper, TestUserId, @@ -26,8 +26,8 @@ async function createTemplates() { version: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateType: TemplateType.LETTER, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'LETTER', + templateStatus: 'NOT_YET_SUBMITTED', owner: user.userId, } as Template, valid: { diff --git a/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-edit-nhs-app-template-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-edit-nhs-app-template-page.component.spec.ts index 7a56ce3e2..ffe974f66 100644 --- a/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-edit-nhs-app-template-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-edit-nhs-app-template-page.component.spec.ts @@ -17,8 +17,8 @@ import { function createTemplates(owner: string) { return { - emptyTemplateData: TemplateFactory.createNhsAppTemplate( - 'empty-nhs-app-template', + valid: TemplateFactory.createNhsAppTemplate( + 'valid-nhs-app-template', owner ), submit: TemplateFactory.createNhsAppTemplate( @@ -52,10 +52,10 @@ test.describe('Edit NHS App Template Page', () => { }) => { const editTemplatePage = new TemplateMgmtEditNhsAppPage(page); - await editTemplatePage.loadPage(templates.emptyTemplateData.id); + await editTemplatePage.loadPage(templates.valid.id); await expect(page).toHaveURL( - `${baseURL}/templates/edit-nhs-app-template/${templates.emptyTemplateData.id}` + `${baseURL}/templates/edit-nhs-app-template/${templates.valid.id}` ); await expect(editTemplatePage.pageHeader).toHaveText( 'Edit NHS App message template' @@ -65,7 +65,7 @@ test.describe('Edit NHS App Template Page', () => { test('common page tests', async ({ page, baseURL }) => { const props = { page: new TemplateMgmtEditNhsAppPage(page), - id: templates.emptyTemplateData.id, + id: templates.valid.id, baseURL, }; @@ -82,17 +82,18 @@ test.describe('Edit NHS App Template Page', () => { }) => { const editTemplatePage = new TemplateMgmtEditNhsAppPage(page); - await editTemplatePage.loadPage(templates.emptyTemplateData.id); + await editTemplatePage.loadPage(templates.valid.id); await expect(page).toHaveURL( - `${baseURL}/templates/edit-nhs-app-template/${templates.emptyTemplateData.id}` + `${baseURL}/templates/edit-nhs-app-template/${templates.valid.id}` ); await expect(editTemplatePage.pageHeader).toHaveText( 'Edit NHS App message template' ); + await page.locator('[id="nhsAppTemplateName"]').fill(''); + await page.locator('[id="nhsAppTemplateMessage"]').fill(''); await editTemplatePage.clickSaveAndPreviewButton(); await expect(page.locator('.nhsuk-error-summary')).toBeVisible(); - await expect( page.locator('ul[class="nhsuk-list nhsuk-error-summary__list"] > li') ).toHaveText(['Enter a template name', 'Enter a template message']); @@ -126,16 +127,17 @@ test.describe('Edit NHS App Template Page', () => { }) => { const editTemplatePage = new TemplateMgmtEditNhsAppPage(page); - await editTemplatePage.loadPage(templates.emptyTemplateData.id); + await editTemplatePage.loadPage(templates.valid.id); await expect(page).toHaveURL( - `${baseURL}/templates/edit-nhs-app-template/${templates.emptyTemplateData.id}` + `${baseURL}/templates/edit-nhs-app-template/${templates.valid.id}` ); await expect(editTemplatePage.pageHeader).toHaveText( 'Edit NHS App message template' ); const templateName = 'NHS Testing 123'; await page.locator('[id="nhsAppTemplateName"]').fill(templateName); + await page.locator('[id="nhsAppTemplateMessage"]').fill(''); await editTemplatePage.clickSaveAndPreviewButton(); await expect(page.locator('.nhsuk-error-summary')).toBeVisible(); await expect( @@ -149,14 +151,15 @@ test.describe('Edit NHS App Template Page', () => { }) => { const editTemplatePage = new TemplateMgmtEditNhsAppPage(page); - await editTemplatePage.loadPage(templates.emptyTemplateData.id); + await editTemplatePage.loadPage(templates.valid.id); await expect(page).toHaveURL( - `${baseURL}/templates/edit-nhs-app-template/${templates.emptyTemplateData.id}` + `${baseURL}/templates/edit-nhs-app-template/${templates.valid.id}` ); await expect(editTemplatePage.pageHeader).toHaveText( 'Edit NHS App message template' ); + await page.locator('[id="nhsAppTemplateName"]').fill(''); const templateMessage = 'Test Message box'; await page.locator('[id="nhsAppTemplateMessage"]').fill(templateMessage); await editTemplatePage.clickSaveAndPreviewButton(); @@ -173,10 +176,10 @@ test.describe('Edit NHS App Template Page', () => { }) => { const editTemplatePage = new TemplateMgmtEditNhsAppPage(page); - await editTemplatePage.loadPage(templates.emptyTemplateData.id); + await editTemplatePage.loadPage(templates.valid.id); await expect(page).toHaveURL( - `${baseURL}/templates/edit-nhs-app-template/${templates.emptyTemplateData.id}` + `${baseURL}/templates/edit-nhs-app-template/${templates.valid.id}` ); await page.locator('[id="nhsAppTemplateName"]').fill('NHS Testing 123'); await page @@ -191,10 +194,10 @@ test.describe('Edit NHS App Template Page', () => { }) => { const editTemplatePage = new TemplateMgmtEditNhsAppPage(page); - await editTemplatePage.loadPage(templates.emptyTemplateData.id); + await editTemplatePage.loadPage(templates.valid.id); await expect(page).toHaveURL( - `${baseURL}/templates/edit-nhs-app-template/${templates.emptyTemplateData.id}` + `${baseURL}/templates/edit-nhs-app-template/${templates.valid.id}` ); await page.locator('[id="nhsAppTemplateName"]').fill('NHS Testing 123'); @@ -226,9 +229,9 @@ test.describe('Edit NHS App Template Page', () => { baseURL, }) => { const editTemplatePage = new TemplateMgmtEditNhsAppPage(page); - await editTemplatePage.loadPage(templates.emptyTemplateData.id); + await editTemplatePage.loadPage(templates.valid.id); await expect(page).toHaveURL( - `${baseURL}/templates/edit-nhs-app-template/${templates.emptyTemplateData.id}` + `${baseURL}/templates/edit-nhs-app-template/${templates.valid.id}` ); await page.locator(`${section} > summary`).click(); @@ -262,7 +265,7 @@ test.describe('Edit NHS App Template Page', () => { baseURL, }) => { const editTemplatePage = new TemplateMgmtEditNhsAppPage(page); - await editTemplatePage.loadPage('empty-nhs-app-template'); + await editTemplatePage.loadPage('valid-nhs-app-template'); const newTabPromise = page.waitForEvent('popup'); await page.getByRole('link', { name }).click(); const newTab = await newTabPromise; diff --git a/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-preview-nhs-app-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-preview-nhs-app-page.component.spec.ts index ec9cd084f..b58aef50f 100644 --- a/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-preview-nhs-app-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-preview-nhs-app-page.component.spec.ts @@ -12,7 +12,7 @@ import { assertNotifyBannerLink, assertSkipToMainContent, } from '../template-mgmt-common.steps'; -import { Template, TemplateType, TemplateStatus } from '../../helpers/types'; +import { Template } from '../../helpers/types'; import { createAuthHelper, TestUserId, @@ -26,8 +26,8 @@ async function createTemplates() { version: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', owner: user.userId, } as Template, valid: { diff --git a/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-view-submitted-nhs-app-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-view-submitted-nhs-app-page.component.spec.ts index 9065140d4..12fd71990 100644 --- a/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-view-submitted-nhs-app-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/nhs-app/template-mgmt-view-submitted-nhs-app-page.component.spec.ts @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test'; import { TemplateStorageHelper } from '../../helpers/db/template-storage-helper'; import { TemplateMgmtViewSubmittedNhsAppPage } from '../../pages/nhs-app/template-mgmt-view-submitted-nhs-app-page'; import { TemplateFactory } from '../../helpers/factories/template-factory'; -import { Template, TemplateStatus } from '../../helpers/types'; +import { Template } from '../../helpers/types'; import { assertFooterLinks, assertSignOutLink, @@ -27,7 +27,7 @@ function createTemplates(owner: string) { ), name: 'test-template-nhs-app', message: 'test-template-message', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED', }, invalid: { ...TemplateFactory.createNhsAppTemplate( @@ -36,7 +36,7 @@ function createTemplates(owner: string) { ), name: 'test-template-nhs-app', message: 'test-template-message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', }, }; } diff --git a/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-edit-sms-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-edit-sms-page.component.spec.ts index 34c686a62..adb292a03 100644 --- a/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-edit-sms-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-edit-sms-page.component.spec.ts @@ -9,7 +9,7 @@ import { assertNotifyBannerLink, assertSkipToMainContent, } from '../template-mgmt-common.steps'; -import { Template, TemplateType } from '../../helpers/types'; +import { Template } from '../../helpers/types'; import { createAuthHelper, TestUserId, @@ -17,7 +17,7 @@ import { function createTemplates(owner: string) { return { - empty: TemplateFactory.createSmsTemplate('empty-sms-template', owner), + valid: TemplateFactory.createSmsTemplate('valid-sms-template', owner), submit: TemplateFactory.createSmsTemplate('submit-sms-template', owner), submitAndReturn: TemplateFactory.createSmsTemplate( 'submit-and-return-create-sms-template', @@ -29,7 +29,7 @@ function createTemplates(owner: string) { ), noSmsTemplateType: TemplateFactory.create({ id: 'no-sms-template-type-template', - templateType: TemplateType.EMAIL, + templateType: 'EMAIL', owner, name: 'no-sms-template-type-template', }), @@ -61,10 +61,10 @@ test.describe('Edit SMS message template Page', () => { }) => { const editSmsTemplatePage = new TemplateMgmtEditSmsPage(page); - await editSmsTemplatePage.loadPage(templates.empty.id); + await editSmsTemplatePage.loadPage(templates.valid.id); await expect(page).toHaveURL( - `${baseURL}/templates/edit-text-message-template/${templates.empty.id}` + `${baseURL}/templates/edit-text-message-template/${templates.valid.id}` ); await expect(editSmsTemplatePage.pageHeader).toHaveText( @@ -81,7 +81,7 @@ test.describe('Edit SMS message template Page', () => { test('common page tests', async ({ page, baseURL }) => { const props = { page: new TemplateMgmtEditSmsPage(page), - id: templates.empty.id, + id: templates.valid.id, baseURL, }; @@ -103,7 +103,7 @@ test.describe('Edit SMS message template Page', () => { templates.previousData.name ); await expect(editSmsTemplatePage.messageTextArea).toHaveValue( - templates.previousData.message + templates.previousData.message! ); }); @@ -146,7 +146,7 @@ test.describe('Edit SMS message template Page', () => { }) => { const editSmsTemplatePage = new TemplateMgmtEditSmsPage(page); - await editSmsTemplatePage.loadPage(templates.empty.id); + await editSmsTemplatePage.loadPage(templates.valid.id); await editSmsTemplatePage.messageFormatting.assertDetailsOpen([ editSmsTemplatePage.messageFormatting.linksAndUrls, @@ -158,7 +158,7 @@ test.describe('Edit SMS message template Page', () => { }) => { const editSmsTemplatePage = new TemplateMgmtEditSmsPage(page); - await editSmsTemplatePage.loadPage(templates.empty.id); + await editSmsTemplatePage.loadPage(templates.valid.id); await editSmsTemplatePage.namingYourTemplate.click({ position: { x: 0, y: 0 }, @@ -190,7 +190,7 @@ test.describe('Edit SMS message template Page', () => { baseURL, }) => { const editTemplatePage = new TemplateMgmtEditSmsPage(page); - await editTemplatePage.loadPage('empty-sms-template'); + await editTemplatePage.loadPage('valid-sms-template'); const newTabPromise = page.waitForEvent('popup'); await page.getByRole('link', { name }).click(); const newTab = await newTabPromise; @@ -246,7 +246,11 @@ test.describe('Edit SMS message template Page', () => { }) => { const editSmsTemplatePage = new TemplateMgmtEditSmsPage(page); - await editSmsTemplatePage.loadPage(templates.empty.id); + await editSmsTemplatePage.loadPage(templates.valid.id); + + await editSmsTemplatePage.nameInput.fill(''); + + await editSmsTemplatePage.messageTextArea.fill(''); await editSmsTemplatePage.clickSaveAndPreviewButton(); @@ -272,7 +276,9 @@ test.describe('Edit SMS message template Page', () => { const editSmsTemplatePage = new TemplateMgmtEditSmsPage(page); - await editSmsTemplatePage.loadPage(templates.empty.id); + await editSmsTemplatePage.loadPage(templates.valid.id); + + await editSmsTemplatePage.nameInput.fill(''); await editSmsTemplatePage.messageTextArea.fill('template-message'); @@ -296,10 +302,12 @@ test.describe('Edit SMS message template Page', () => { const editSmsTemplatePage = new TemplateMgmtEditSmsPage(page); - await editSmsTemplatePage.loadPage(templates.empty.id); + await editSmsTemplatePage.loadPage(templates.valid.id); await editSmsTemplatePage.nameInput.fill('template-name'); + await editSmsTemplatePage.messageTextArea.fill(''); + await editSmsTemplatePage.clickSaveAndPreviewButton(); const smsMessageErrorLink = editSmsTemplatePage.errorSummary.locator( diff --git a/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-preview-sms-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-preview-sms-page.component.spec.ts index e443c92a0..1be98eedc 100644 --- a/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-preview-sms-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-preview-sms-page.component.spec.ts @@ -12,7 +12,7 @@ import { assertNotifyBannerLink, assertSkipToMainContent, } from '../template-mgmt-common.steps'; -import { TemplateType, Template, TemplateStatus } from '../../helpers/types'; +import { Template } from '../../helpers/types'; import { createAuthHelper, TestUserId, @@ -26,8 +26,8 @@ async function createTemplates() { version: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', owner: user.userId, } as Template, valid: { diff --git a/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-view-submitted-sms-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-view-submitted-sms-page.component.spec.ts index cc10863c8..c52f568c8 100644 --- a/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-view-submitted-sms-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/sms/template-mgmt-view-submitted-sms-page.component.spec.ts @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test'; import { TemplateStorageHelper } from '../../helpers/db/template-storage-helper'; import { TemplateMgmtViewSubmittedSmsPage } from '../../pages/sms/template-mgmt-view-submitted-sms-page'; import { TemplateFactory } from '../../helpers/factories/template-factory'; -import { Template, TemplateStatus } from '../../helpers/types'; +import { Template } from '../../helpers/types'; import { assertFooterLinks, assertSignOutLink, @@ -27,7 +27,7 @@ function createTemplates(owner: string) { ), name: 'test-template-sms', message: 'test-template-message', - templateStatus: TemplateStatus.SUBMITTED, + templateStatus: 'SUBMITTED', }, invalid: { ...TemplateFactory.createSmsTemplate( @@ -36,7 +36,7 @@ function createTemplates(owner: string) { ), name: 'test-template-sms', message: 'test-template-message', - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateStatus: 'NOT_YET_SUBMITTED', }, }; } diff --git a/tests/test-team/template-mgmt-component-tests/template-mgmt-copy-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/template-mgmt-copy-page.component.spec.ts index 0feb1762d..13cdff354 100644 --- a/tests/test-team/template-mgmt-component-tests/template-mgmt-copy-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/template-mgmt-copy-page.component.spec.ts @@ -11,7 +11,6 @@ import { TemplateStorageHelper } from '../helpers/db/template-storage-helper'; import { TemplateFactory } from '../helpers/factories/template-factory'; import { Template, - TemplateType, templateTypeDisplayMappings, templateTypeToUrlTextMappings, } from '../helpers/types'; @@ -126,11 +125,7 @@ test.describe('Copy Template Page', () => { }); for (const sourceTemplateType of ['nhsApp', 'email', 'sms']) { - for (const targetTemplateType of [ - TemplateType.EMAIL, - TemplateType.NHS_APP, - TemplateType.SMS, - ]) { + for (const targetTemplateType of ['EMAIL', 'NHS_APP', 'SMS']) { // eslint-disable-next-line no-loop-func test(`should copy ${sourceTemplateType} to ${targetTemplateType} template`, async ({ page, @@ -141,7 +136,7 @@ test.describe('Copy Template Page', () => { const template = templates[sourceTemplateType]; await copyTemplatePage.loadPage(template.id); await copyTemplatePage.checkRadioButton( - templateTypeDisplayMappings(targetTemplateType) + templateTypeDisplayMappings[targetTemplateType] ); await copyTemplatePage.clickContinueButton(); @@ -151,7 +146,7 @@ test.describe('Copy Template Page', () => { .getByRole('row') .filter({ has: page.getByText( - `Type ${templateTypeDisplayMappings(targetTemplateType)}`, + `Type ${templateTypeDisplayMappings[targetTemplateType]}`, { exact: true } ), }) @@ -183,12 +178,12 @@ test.describe('Copy Template Page', () => { }); await copyTemplatePage.navigateTo( - `/templates/preview-${templateTypeToUrlTextMappings(targetTemplateType)}-template/${newTemplateId}` + `/templates/preview-${templateTypeToUrlTextMappings[targetTemplateType]}-template/${newTemplateId}` ); - await expect(page.getByText(template.message)).toBeVisible(); + await expect(page.getByText(template.message || '')).toBeVisible(); - if (targetTemplateType === TemplateType.EMAIL) { + if (targetTemplateType === 'EMAIL') { const expectedSubject = template.subject ?? 'Enter a subject line'; await expect(page.getByText(expectedSubject)).toBeVisible(); } diff --git a/tests/test-team/template-mgmt-component-tests/template-mgmt-manage-templates-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/template-mgmt-manage-templates-page.component.spec.ts index 0ebc1db48..711797aee 100644 --- a/tests/test-team/template-mgmt-component-tests/template-mgmt-manage-templates-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/template-mgmt-manage-templates-page.component.spec.ts @@ -9,7 +9,7 @@ import { assertSkipToMainContent, } from './template-mgmt-common.steps'; import { TemplateFactory } from '../helpers/factories/template-factory'; -import { Template, TemplateStatus, TemplateType } from '../helpers/types'; +import { Template } from '../helpers/types'; import { TemplateStorageHelper } from '../helpers/db/template-storage-helper'; import { createAuthHelper, @@ -25,8 +25,8 @@ function createTemplates(owner: string) { name: 'email-submitted_manage-templates-page', message: 'test example message', subject: 'test example subject', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'SUBMITTED', createdAt: '2010-10-11T11:11:11.111Z', }), emailNotYetSubmitted: TemplateFactory.create({ @@ -36,8 +36,8 @@ function createTemplates(owner: string) { name: 'email-not-yet-submitted_manage-templates-page', message: 'test example message', subject: 'test example subject', - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', createdAt: '2010-10-11T10:10:10.100Z', }), smsSubmitted: TemplateFactory.create({ @@ -45,8 +45,8 @@ function createTemplates(owner: string) { owner, name: 'sms-submitted_manage-templates-page', message: 'test example message', - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'SMS', + templateStatus: 'SUBMITTED', createdAt: '2010-10-10T11:11:11.111Z', }), smsNotYetSubmitted: TemplateFactory.create({ @@ -54,8 +54,8 @@ function createTemplates(owner: string) { owner, name: 'sms-not-yet-submitted_manage-templates-page', message: 'test example message', - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', createdAt: '2010-10-10T10:10:10.100Z', }), nhsAppSubmitted: TemplateFactory.create({ @@ -63,8 +63,8 @@ function createTemplates(owner: string) { owner, name: 'nhs-app-submitted_manage-templates-page', message: 'test example message', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'SUBMITTED', createdAt: '2010-10-09T11:11:11.111Z', }), nhsAppNotYetSubmitted: TemplateFactory.create({ @@ -72,8 +72,8 @@ function createTemplates(owner: string) { owner, name: 'nhs-app-not-yet-submitted_manage-templates-page', message: 'test example message', - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', createdAt: '2010-10-09T10:10:10.100Z', }), }; diff --git a/tests/test-team/template-mgmt-component-tests/template-mgmt-submit-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/template-mgmt-submit-page.component.spec.ts index 912345aea..25bfc5553 100644 --- a/tests/test-team/template-mgmt-component-tests/template-mgmt-submit-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/template-mgmt-submit-page.component.spec.ts @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test'; import { TemplateStorageHelper } from '../helpers/db/template-storage-helper'; import { TemplateFactory } from '../helpers/factories/template-factory'; -import { Template, TemplateType, TemplateStatus } from '../helpers/types'; +import { Template } from '../helpers/types'; import { assertFooterLinks, assertSignOutLink, @@ -43,8 +43,8 @@ async function createTemplates() { version: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'NOT_YET_SUBMITTED', owner: user.userId, } as Template, submit: { @@ -75,8 +75,8 @@ async function createTemplates() { version: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'SMS', + templateStatus: 'NOT_YET_SUBMITTED', owner: user.userId, } as Template, submit: { @@ -107,8 +107,8 @@ async function createTemplates() { version: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.NOT_YET_SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'NOT_YET_SUBMITTED', owner: user.userId, } as Template, submit: { diff --git a/tests/test-team/template-mgmt-component-tests/template-mgmt-submitted-page.component.spec.ts b/tests/test-team/template-mgmt-component-tests/template-mgmt-submitted-page.component.spec.ts index a27d6ce08..6788e54ea 100644 --- a/tests/test-team/template-mgmt-component-tests/template-mgmt-submitted-page.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/template-mgmt-submitted-page.component.spec.ts @@ -8,7 +8,7 @@ import { assertSkipToMainContent, } from './template-mgmt-common.steps'; import { TemplateFactory } from '../helpers/factories/template-factory'; -import { TemplateType, TemplateStatus, Template } from '../helpers/types'; +import { Template } from '../helpers/types'; import { createAuthHelper, TestUserId, @@ -21,8 +21,8 @@ function createTemplates(owner: string) { return { email: TemplateFactory.create({ owner, - templateType: TemplateType.EMAIL, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'EMAIL', + templateStatus: 'SUBMITTED', id: 'valid-email-template', name: 'test-template-email', subject: 'test-template-subject', @@ -30,16 +30,16 @@ function createTemplates(owner: string) { }), 'text-message': TemplateFactory.create({ owner, - templateType: TemplateType.SMS, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'SMS', + templateStatus: 'SUBMITTED', id: 'valid-sms-template', name: 'test-template-sms', message: 'test example content', }), 'nhs-app': TemplateFactory.create({ owner, - templateType: TemplateType.NHS_APP, - templateStatus: TemplateStatus.SUBMITTED, + templateType: 'NHS_APP', + templateStatus: 'SUBMITTED', id: 'valid-nhs-app-template', name: 'test-template-nhs-app', message: 'test example content', diff --git a/tests/test-team/template-mgmt-component-tests/template-unauthorised-data.component.spec.ts b/tests/test-team/template-mgmt-component-tests/template-unauthorised-data.component.spec.ts index c2be43ed2..d2e39192c 100644 --- a/tests/test-team/template-mgmt-component-tests/template-unauthorised-data.component.spec.ts +++ b/tests/test-team/template-mgmt-component-tests/template-unauthorised-data.component.spec.ts @@ -1,6 +1,5 @@ import { test, expect } from '@playwright/test'; import { TemplateFactory } from '../helpers/factories/template-factory'; -import { TemplateType } from '../helpers/types'; import { TemplateStorageHelper } from '../helpers/db/template-storage-helper'; import { createAuthHelper, @@ -29,7 +28,7 @@ function createTemplates(owner: string) { ), noEmailTemplateType: TemplateFactory.create({ id: 'no-email-template-type-template', - templateType: TemplateType.NHS_APP, + templateType: 'NHS_APP', owner, name: 'no-email-template-type-template-name', }), diff --git a/utils/utils/src/__tests__/enum.test.ts b/utils/utils/src/__tests__/enum.test.ts index 71a6ddf88..f34381e52 100644 --- a/utils/utils/src/__tests__/enum.test.ts +++ b/utils/utils/src/__tests__/enum.test.ts @@ -2,9 +2,7 @@ import { Language, LetterType } from 'nhs-notify-backend-client'; import { letterTypeDisplayMappings, previewTemplatePages, - TemplateStatus, templateStatusToDisplayMappings, - TemplateType, templateTypeDisplayMappings, templateTypeToUrlTextMappings, viewSubmittedTemplatePages, @@ -12,35 +10,31 @@ import { describe('templateTypeDisplayMappings', () => { test('NHS_APP', () => { - expect(templateTypeDisplayMappings(TemplateType.NHS_APP)).toEqual( - 'NHS App message' - ); + expect(templateTypeDisplayMappings('NHS_APP')).toEqual('NHS App message'); }); test('SMS', () => { - expect(templateTypeDisplayMappings(TemplateType.SMS)).toEqual( - 'Text message (SMS)' - ); + expect(templateTypeDisplayMappings('SMS')).toEqual('Text message (SMS)'); }); test('EMAIL', () => { - expect(templateTypeDisplayMappings(TemplateType.EMAIL)).toEqual('Email'); + expect(templateTypeDisplayMappings('EMAIL')).toEqual('Email'); }); test('LETTER', () => { - expect(templateTypeDisplayMappings(TemplateType.LETTER)).toEqual('Letter'); + expect(templateTypeDisplayMappings('LETTER')).toEqual('Letter'); }); }); describe('letterTypeDisplayMappings', () => { const letterCases: [LetterType, Language, string][] = [ - [LetterType.X0, Language.EN, 'Standard letter'], - [LetterType.X0, Language.BN, 'Letter - Bengali'], - [LetterType.X0, Language.EL, 'Letter - Greek'], - [LetterType.Q1, Language.EN, 'Braille letter'], - [LetterType.X3, Language.EN, 'Audio CD letter'], - [LetterType.X1, Language.EN, 'Large print letter'], - [LetterType.Q4, Language.EN, 'British Sign Language letter'], + ['x0', 'en', 'Standard letter'], + ['x0', 'bn', 'Letter - Bengali'], + ['x0', 'el', 'Letter - Greek'], + ['q1', 'en', 'Braille letter'], + ['x3', 'en', 'Audio CD letter'], + ['x1', 'en', 'Large print letter'], + ['q4', 'en', 'British Sign Language letter'], ]; test.each(letterCases)( @@ -53,75 +47,65 @@ describe('letterTypeDisplayMappings', () => { describe('templateStatusToDisplayMappings', () => { test('NOT_YET_SUBMITTED', () => { - expect( - templateStatusToDisplayMappings(TemplateStatus.NOT_YET_SUBMITTED) - ).toEqual('Not yet submitted'); + expect(templateStatusToDisplayMappings('NOT_YET_SUBMITTED')).toEqual( + 'Not yet submitted' + ); }); test('SUBMITTED', () => { - expect(templateStatusToDisplayMappings(TemplateStatus.SUBMITTED)).toEqual( - 'Submitted' - ); + expect(templateStatusToDisplayMappings('SUBMITTED')).toEqual('Submitted'); }); test('DELETED', () => { - expect(templateStatusToDisplayMappings(TemplateStatus.DELETED)).toEqual(''); + expect(templateStatusToDisplayMappings('DELETED')).toEqual(''); }); }); describe('templateTypeToUrlTextMappings', () => { test('NHS_APP', () => { - expect(templateTypeToUrlTextMappings(TemplateType.NHS_APP)).toEqual( - 'nhs-app' - ); + expect(templateTypeToUrlTextMappings('NHS_APP')).toEqual('nhs-app'); }); test('SMS', () => { - expect(templateTypeToUrlTextMappings(TemplateType.SMS)).toEqual( - 'text-message' - ); + expect(templateTypeToUrlTextMappings('SMS')).toEqual('text-message'); }); test('EMAIL', () => { - expect(templateTypeToUrlTextMappings(TemplateType.EMAIL)).toEqual('email'); + expect(templateTypeToUrlTextMappings('EMAIL')).toEqual('email'); }); }); describe('previewTemplatePages', () => { test('NHS_APP', () => { - expect(previewTemplatePages(TemplateType.NHS_APP)).toEqual( - 'preview-nhs-app-template' - ); + expect(previewTemplatePages('NHS_APP')).toEqual('preview-nhs-app-template'); }); test('SMS', () => { - expect(previewTemplatePages(TemplateType.SMS)).toEqual( + expect(previewTemplatePages('SMS')).toEqual( 'preview-text-message-template' ); }); test('EMAIL', () => { - expect(previewTemplatePages(TemplateType.EMAIL)).toEqual( - 'preview-email-template' - ); + expect(previewTemplatePages('EMAIL')).toEqual('preview-email-template'); }); }); describe('viewSubmittedTemplatePages', () => { test('NHS_APP', () => { - expect(viewSubmittedTemplatePages(TemplateType.NHS_APP)).toEqual( + expect(viewSubmittedTemplatePages('NHS_APP')).toEqual( 'view-submitted-nhs-app-template' ); }); test('SMS', () => { - expect(viewSubmittedTemplatePages(TemplateType.SMS)).toEqual( + expect(viewSubmittedTemplatePages('SMS')).toEqual( 'view-submitted-text-message-template' ); }); test('EMAIL', () => { - expect(viewSubmittedTemplatePages(TemplateType.EMAIL)).toEqual( + expect(viewSubmittedTemplatePages('EMAIL')).toEqual( 'view-submitted-email-template' ); }); diff --git a/utils/utils/src/enum.ts b/utils/utils/src/enum.ts index d839bcb39..b6aea0a6e 100644 --- a/utils/utils/src/enum.ts +++ b/utils/utils/src/enum.ts @@ -5,79 +5,76 @@ import { Language, } from 'nhs-notify-backend-client'; -// eslint-disable-next-line unicorn/prefer-export-from -export { TemplateType, TemplateStatus }; - export const languageMapping = (language: Language) => ({ - [Language.AR]: 'Arabic', - [Language.BG]: 'Bulgarian', - [Language.BN]: 'Bengali', - [Language.DE]: 'German', - [Language.EL]: 'Greek', - [Language.EN]: 'English', - [Language.ES]: 'Spanish', - [Language.FA]: 'Persian', - [Language.FR]: 'French', - [Language.GU]: 'Gujurati', - [Language.HI]: 'Hindi', - [Language.HU]: 'Hungarian', - [Language.IT]: 'Italian', - [Language.KU]: 'Kurdish', - [Language.LT]: 'Lithuanian', - [Language.LV]: 'Latvian', - [Language.NE]: 'Nepali', - [Language.PA]: 'Punjabi', - [Language.PL]: 'Polish', - [Language.PT]: 'Portuguese', - [Language.RO]: 'Romanian', - [Language.RU]: 'Russian', - [Language.SK]: 'Slovak', - [Language.SO]: 'Somali', - [Language.SQ]: 'Albanian', - [Language.TA]: 'Tamil', - [Language.TR]: 'Turkish', - [Language.UR]: 'Urdu', - [Language.ZH]: 'Chinese', + ar: 'Arabic', + bg: 'Bulgarian', + bn: 'Bengali', + de: 'German', + el: 'Greek', + en: 'English', + es: 'Spanish', + fa: 'Persian', + fr: 'French', + gu: 'Gujurati', + hi: 'Hindi', + hu: 'Hungarian', + it: 'Italian', + ku: 'Kurdish', + lt: 'Lithuanian', + lv: 'Latvian', + ne: 'Nepali', + pa: 'Punjabi', + pl: 'Polish', + pt: 'Portuguese', + ro: 'Romanian', + ru: 'Russian', + sk: 'Slovak', + so: 'Somali', + sq: 'Albanian', + ta: 'Tamil', + tr: 'Turkish', + ur: 'Urdu', + zh: 'Chinese', })[language]; const letterTypeMapping = (letterType: LetterType) => ({ - [LetterType.X3]: 'Audio CD', - [LetterType.Q1]: 'Braille', - [LetterType.Q4]: 'British Sign Language', - [LetterType.X0]: 'Standard', - [LetterType.X1]: 'Large print', + x3: 'Audio CD', + q1: 'Braille', + q4: 'British Sign Language', + x0: 'Standard', + x1: 'Large print', })[letterType]; export const letterTypeDisplayMappings = ( letterType: LetterType, language: Language ) => - language === Language.EN + language === 'en' ? `${letterTypeMapping(letterType)} letter` : `Letter - ${languageMapping(language)}`; export const templateTypeDisplayMappings = (type: TemplateType) => ({ - [TemplateType.NHS_APP]: 'NHS App message', - [TemplateType.SMS]: 'Text message (SMS)', - [TemplateType.EMAIL]: 'Email', - [TemplateType.LETTER]: 'Letter', + NHS_APP: 'NHS App message', + SMS: 'Text message (SMS)', + EMAIL: 'Email', + LETTER: 'Letter', })[type]; export const templateStatusToDisplayMappings = (status: TemplateStatus) => ({ - [TemplateStatus.NOT_YET_SUBMITTED]: 'Not yet submitted', - [TemplateStatus.SUBMITTED]: 'Submitted', - [TemplateStatus.DELETED]: '', // will not be shown in the UI + NOT_YET_SUBMITTED: 'Not yet submitted', + SUBMITTED: 'Submitted', + DELETED: '', // will not be shown in the UI })[status]; export const templateTypeToUrlTextMappings = (type: TemplateType) => ({ - [TemplateType.NHS_APP]: 'nhs-app', - [TemplateType.SMS]: 'text-message', - [TemplateType.EMAIL]: 'email', - [TemplateType.LETTER]: 'letter', + NHS_APP: 'nhs-app', + SMS: 'text-message', + EMAIL: 'email', + LETTER: 'letter', })[type]; export const previewTemplatePages = (type: TemplateType) => diff --git a/utils/utils/src/types.ts b/utils/utils/src/types.ts index 7887fd940..4483d3534 100644 --- a/utils/utils/src/types.ts +++ b/utils/utils/src/types.ts @@ -1,11 +1,11 @@ -import { z } from 'zod'; import { - $EmailTemplate, - $SMSTemplate, - $NHSAppTemplate, - $Template, - $LetterTemplate, -} from './zod-validators'; + CreateTemplate, + EmailProperties, + LetterProperties, + NhsAppProperties, + SmsProperties, + TemplateDto, +} from 'nhs-notify-backend-client'; export type FormId = | 'choose-a-template-type' @@ -22,23 +22,37 @@ export type FormErrorState = { fieldErrors: Record; }; -export type EmailTemplate = z.infer; +export type FormState = { + validationError?: FormErrorState; +}; -export type SMSTemplate = z.infer; +type NhsAppPropertiesWithType = NhsAppProperties & { + templateType: 'NHS_APP'; +}; -export type NHSAppTemplate = z.infer; +type EmailPropertiesWithType = EmailProperties & { + templateType: 'EMAIL'; +}; -export type LetterTemplate = z.infer; +type SmsPropertiesWithType = SmsProperties & { + templateType: 'SMS'; +}; -export type Template = z.infer; +type LetterPropertiesWithType = LetterProperties & { + templateType: 'LETTER'; +}; -export type Draft = Omit; +export type CreateNHSAppTemplate = CreateTemplate & NhsAppPropertiesWithType; +export type CreateEmailTemplate = CreateTemplate & EmailPropertiesWithType; +export type CreateSMSTemplate = CreateTemplate & SmsPropertiesWithType; +export type CreateLetterTemplate = CreateTemplate & LetterPropertiesWithType; -export type FormState = { - validationError?: FormErrorState; -}; +export type NHSAppTemplate = TemplateDto & NhsAppPropertiesWithType; +export type EmailTemplate = TemplateDto & EmailPropertiesWithType; +export type SMSTemplate = TemplateDto & SmsPropertiesWithType; +export type LetterTemplate = TemplateDto & LetterPropertiesWithType; -export type TemplateFormState = FormState & T; +export type TemplateFormState = FormState & T; export type PageProps = { params: Promise<{ diff --git a/utils/utils/src/zod-validators.ts b/utils/utils/src/zod-validators.ts index d0b609f01..060a04e64 100644 --- a/utils/utils/src/zod-validators.ts +++ b/utils/utils/src/zod-validators.ts @@ -1,103 +1,114 @@ import { z } from 'zod'; import { - $TemplateDTOSchema, - Language, - LetterType, - TemplateDTO, - VirusScanStatus, + $CreateTemplateSchema, + $EmailPropertiesWithType, + $LetterPropertiesWithType, + $NhsAppPropertiesWithType, + $SmsPropertiesWithType, + $TemplateDtoSchema, + TemplateDto, } from 'nhs-notify-backend-client'; -import { TemplateType, TemplateStatus } from './enum'; - -const $TemplateBase = z.object({ - id: z.string(), - templateType: z.nativeEnum(TemplateType), - templateStatus: z.nativeEnum(TemplateStatus), - name: z.string(), - createdAt: z.string().optional(), - updatedAt: z.string().optional(), -}); - -const $VirusScanStatus = z.nativeEnum(VirusScanStatus); - -const $File = z.object({ - fileName: z.string(), - currentVersion: z.string().optional(), - virusScanStatus: $VirusScanStatus, -}); - -const $Files = z.object({ - pdfTemplate: $File, - testDataCsv: $File.optional(), - proofs: z.array($File).optional(), -}); - -export const $EmailTemplate = $TemplateBase.extend({ - templateType: z.literal(TemplateType.EMAIL), - subject: z.string(), - message: z.string(), -}); -export const $SubmittedEmailTemplate = $EmailTemplate.extend({ - templateStatus: z.literal(TemplateStatus.SUBMITTED), -}); -export const $NonSubmittedEmailTemplate = $EmailTemplate.extend({ - templateStatus: z.literal(TemplateStatus.NOT_YET_SUBMITTED), -}); - -export const $NHSAppTemplate = $TemplateBase.extend({ - templateType: z.literal(TemplateType.NHS_APP), - message: z.string(), -}); -export const $SubmittedNHSAppTemplate = $NHSAppTemplate.extend({ - templateStatus: z.literal(TemplateStatus.SUBMITTED), -}); -export const $NonSubmittedNHSAppTemplate = $NHSAppTemplate.extend({ - templateStatus: z.literal(TemplateStatus.NOT_YET_SUBMITTED), -}); - -export const $SMSTemplate = $TemplateBase.extend({ - templateType: z.literal(TemplateType.SMS), - message: z.string(), -}); -export const $SubmittedSMSTemplate = $SMSTemplate.extend({ - templateStatus: z.literal(TemplateStatus.SUBMITTED), -}); -const $NonSubmittedSMSTemplate = $SMSTemplate.extend({ - templateStatus: z.literal(TemplateStatus.NOT_YET_SUBMITTED), -}); - -export const $LetterTemplate = $TemplateBase.extend({ - templateType: z.literal(TemplateType.LETTER), - letterType: z.nativeEnum(LetterType), - language: z.nativeEnum(Language), - files: $Files, -}); -const $SubmittedLetterTemplate = $LetterTemplate.extend({ - templateStatus: z.literal(TemplateStatus.SUBMITTED), -}); -const $NonSubmittedLetterTemplate = $LetterTemplate.extend({ - templateStatus: z.literal(TemplateStatus.NOT_YET_SUBMITTED), -}); - -export const $Template = z.discriminatedUnion('templateType', [ - $NHSAppTemplate, - $EmailTemplate, - $SMSTemplate, - $LetterTemplate, -]); - -export const $SubmittedTemplate = z.discriminatedUnion('templateType', [ - $SubmittedNHSAppTemplate, - $SubmittedEmailTemplate, - $SubmittedSMSTemplate, - $SubmittedLetterTemplate, -]); - -export const $NonSubmittedTemplate = z.discriminatedUnion('templateType', [ - $NonSubmittedNHSAppTemplate, - $NonSubmittedEmailTemplate, - $NonSubmittedSMSTemplate, - $NonSubmittedLetterTemplate, -]); - -export const isTemplateValid = (input: unknown): TemplateDTO | undefined => - $TemplateDTOSchema.safeParse(input).data; + +export const zodValidate = ( + schema: T, + obj: unknown +): z.infer | undefined => { + try { + return schema.parse(obj); + } catch { + return undefined; + } +}; + +export const $SubmittedTemplate = z.intersection( + $TemplateDtoSchema, + z.object({ + templateStatus: z.literal('SUBMITTED'), + }) +); + +export const $NonSubmittedTemplate = z.intersection( + $TemplateDtoSchema, + z.object({ + templateStatus: z.literal('NOT_YET_SUBMITTED'), + }) +); + +export const $CreateNHSAppTemplate = z.intersection( + $CreateTemplateSchema, + $NhsAppPropertiesWithType +); +export const $NHSAppTemplate = z.intersection( + $TemplateDtoSchema, + $NhsAppPropertiesWithType +); +export const $SubmittedNHSAppTemplate = z.intersection( + $SubmittedTemplate, + $NHSAppTemplate +); + +export const $CreateEmailTemplate = z.intersection( + $CreateTemplateSchema, + $EmailPropertiesWithType +); +export const $EmailTemplate = z.intersection( + $TemplateDtoSchema, + $EmailPropertiesWithType +); +export const $SubmittedEmailTemplate = z.intersection( + $SubmittedTemplate, + $EmailTemplate +); + +export const $CreateSMSTemplate = z.intersection( + $CreateTemplateSchema, + $SmsPropertiesWithType +); +export const $SMSTemplate = z.intersection( + $TemplateDtoSchema, + $SmsPropertiesWithType +); +export const $SubmittedSMSTemplate = z.intersection( + $SubmittedTemplate, + $SMSTemplate +); + +export const $CreateLetterTemplate = z.intersection( + $CreateTemplateSchema, + $LetterPropertiesWithType +); +export const $LetterTemplate = z.intersection( + $TemplateDtoSchema, + $LetterPropertiesWithType +); +export const $SubmittedLetterTemplate = z.intersection( + $SubmittedTemplate, + $LetterTemplate +); + +export const validateNHSAppTemplate = (template?: TemplateDto) => + zodValidate($NHSAppTemplate, template); + +export const validateSMSTemplate = (template?: TemplateDto) => + zodValidate($SMSTemplate, template); + +export const validateEmailTemplate = (template?: TemplateDto) => + zodValidate($EmailTemplate, template); + +export const validateLetterTemplate = (template?: TemplateDto) => + zodValidate($LetterTemplate, template); + +export const validateSubmittedEmailTemplate = (template?: TemplateDto) => + zodValidate($SubmittedEmailTemplate, template); + +export const validateSubmittedSMSTemplate = (template?: TemplateDto) => + zodValidate($SubmittedSMSTemplate, template); + +export const validateSubmittedNHSAppTemplate = (template?: TemplateDto) => + zodValidate($SubmittedNHSAppTemplate, template); + +export const validateTemplate = (template?: TemplateDto) => + zodValidate($TemplateDtoSchema, template); + +export const validateNonSubmittedTemplate = (template?: TemplateDto) => + zodValidate($NonSubmittedTemplate, template);